From 9c21f3f9315a5d5ecdf2ea2a98dc8841fdd14299 Mon Sep 17 00:00:00 2001 From: xiaomakuaiz Date: Fri, 26 Sep 2025 10:45:10 +0000 Subject: [PATCH 1/3] feat: add landing page settings --- backend/docs/docs.go | 177 ++++++++++++++++++++++++++++++++++++++ backend/docs/swagger.json | 177 ++++++++++++++++++++++++++++++++++++++ backend/docs/swagger.yaml | 112 ++++++++++++++++++++++++ backend/domain/app.go | 54 ++++++++++++ backend/usecase/app.go | 4 + 5 files changed, 524 insertions(+) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 7976c58a..002a9003 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -5113,6 +5113,14 @@ const docTemplate = `{ } ] }, + "web_app_landing_settings": { + "description": "WebAppLandingSettings", + "allOf": [ + { + "$ref": "#/definitions/domain.WebAppLandingSettings" + } + ] + }, "wechat_app_agent_id": { "type": "string" }, @@ -5333,6 +5341,14 @@ const docTemplate = `{ } ] }, + "web_app_landing_settings": { + "description": "WebApp Landing Settings", + "allOf": [ + { + "$ref": "#/definitions/domain.WebAppLandingSettings" + } + ] + }, "wechat_app_agent_id": { "type": "string" }, @@ -7366,6 +7382,167 @@ const docTemplate = `{ } } }, + "domain.WebAppLandingSettings": { + "type": "object", + "properties": { + "banner_config": { + "type": "object", + "properties": { + "bg_url": { + "type": "string" + }, + "btns": { + "type": "array", + "items": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "id": { + "type": "string" + }, + "text": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + }, + "hot_search": { + "type": "array", + "items": { + "type": "string" + } + }, + "placeholder": { + "type": "string" + }, + "sub_title": { + "type": "string" + }, + "subtitle_color": { + "type": "string" + }, + "subtitle_font_size": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "title_color": { + "type": "string" + }, + "title_font_size": { + "type": "integer" + } + } + }, + "basic_doc_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + } + } + }, + "carousel_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "desc": { + "type": "string" + }, + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + } + } + }, + "title": { + "type": "string" + } + } + }, + "com_config_order": { + "type": "array", + "items": { + "type": "string" + } + }, + "dir_doc_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + } + } + }, + "faq_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "link": { + "type": "string" + }, + "question": { + "type": "string" + } + } + } + }, + "title": { + "type": "string" + } + } + }, + "simple_doc_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + } + } + } + } + }, "domain.WidgetBotSettings": { "type": "object", "properties": { diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 8eb7b758..e18036ff 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -5106,6 +5106,14 @@ } ] }, + "web_app_landing_settings": { + "description": "WebAppLandingSettings", + "allOf": [ + { + "$ref": "#/definitions/domain.WebAppLandingSettings" + } + ] + }, "wechat_app_agent_id": { "type": "string" }, @@ -5326,6 +5334,14 @@ } ] }, + "web_app_landing_settings": { + "description": "WebApp Landing Settings", + "allOf": [ + { + "$ref": "#/definitions/domain.WebAppLandingSettings" + } + ] + }, "wechat_app_agent_id": { "type": "string" }, @@ -7359,6 +7375,167 @@ } } }, + "domain.WebAppLandingSettings": { + "type": "object", + "properties": { + "banner_config": { + "type": "object", + "properties": { + "bg_url": { + "type": "string" + }, + "btns": { + "type": "array", + "items": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "id": { + "type": "string" + }, + "text": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + }, + "hot_search": { + "type": "array", + "items": { + "type": "string" + } + }, + "placeholder": { + "type": "string" + }, + "sub_title": { + "type": "string" + }, + "subtitle_color": { + "type": "string" + }, + "subtitle_font_size": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "title_color": { + "type": "string" + }, + "title_font_size": { + "type": "integer" + } + } + }, + "basic_doc_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + } + } + }, + "carousel_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "desc": { + "type": "string" + }, + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + } + } + } + }, + "title": { + "type": "string" + } + } + }, + "com_config_order": { + "type": "array", + "items": { + "type": "string" + } + }, + "dir_doc_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + } + } + }, + "faq_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "link": { + "type": "string" + }, + "question": { + "type": "string" + } + } + } + }, + "title": { + "type": "string" + } + } + }, + "simple_doc_config": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "type": "string" + } + }, + "title": { + "type": "string" + } + } + } + } + }, "domain.WidgetBotSettings": { "type": "object", "properties": { diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 2e570ed4..39e8bbea 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -399,6 +399,10 @@ definitions: allOf: - $ref: '#/definitions/domain.WebAppCustomSettings' description: WebAppCustomStyle + web_app_landing_settings: + allOf: + - $ref: '#/definitions/domain.WebAppLandingSettings' + description: WebAppLandingSettings wechat_app_agent_id: type: string wechat_app_corpid: @@ -539,6 +543,10 @@ definitions: allOf: - $ref: '#/definitions/domain.WebAppCustomSettings' description: WebAppCustomStyle + web_app_landing_settings: + allOf: + - $ref: '#/definitions/domain.WebAppLandingSettings' + description: WebApp Landing Settings wechat_app_agent_id: type: string wechat_app_corpid: @@ -1870,6 +1878,110 @@ definitions: $ref: '#/definitions/domain.SocialMediaAccount' type: array type: object + domain.WebAppLandingSettings: + properties: + banner_config: + properties: + bg_url: + type: string + btns: + items: + properties: + href: + type: string + id: + type: string + text: + type: string + type: + type: string + type: object + type: array + hot_search: + items: + type: string + type: array + placeholder: + type: string + sub_title: + type: string + subtitle_color: + type: string + subtitle_font_size: + type: integer + title: + type: string + title_color: + type: string + title_font_size: + type: integer + type: object + basic_doc_config: + properties: + list: + items: + type: string + type: array + title: + type: string + type: object + carousel_config: + properties: + list: + items: + properties: + desc: + type: string + id: + type: string + title: + type: string + url: + type: string + type: object + type: array + title: + type: string + type: object + com_config_order: + items: + type: string + type: array + dir_doc_config: + properties: + list: + items: + type: string + type: array + title: + type: string + type: object + faq_config: + properties: + list: + items: + properties: + id: + type: string + link: + type: string + question: + type: string + type: object + type: array + title: + type: string + type: object + simple_doc_config: + properties: + list: + items: + type: string + type: array + title: + type: string + type: object + type: object domain.WidgetBotSettings: properties: btn_logo: diff --git a/backend/domain/app.go b/backend/domain/app.go index 21cb3586..6ad16719 100644 --- a/backend/domain/app.go +++ b/backend/domain/app.go @@ -143,6 +143,8 @@ type AppSettings struct { OpenAIAPIBotSettings OpenAIAPIBotSettings `json:"openai_api_bot_settings"` // Disclaimer Settings DisclaimerSettings DisclaimerSettings `json:"disclaimer_settings"` + // WebAppLandingSettings + WebAppLandingSettings *WebAppLandingSettings `json:"web_app_landing_settings,omitempty"` WatermarkContent string `json:"watermark_content"` WatermarkSetting consts.WatermarkSetting `json:"watermark_setting" validate:"omitempty,oneof='' hidden visible"` @@ -150,6 +152,56 @@ type AppSettings struct { ContributeSettings ContributeSettings `json:"contribute_settings"` } +type WebAppLandingSettings struct { + BannerConfig struct { + Title string `json:"title"` + TitleColor string `json:"title_color"` + TitleFontSize int `json:"title_font_size"` + Subtitle string `json:"sub_title"` + Placeholder string `json:"placeholder"` + SubtitleColor string `json:"subtitle_color"` + SubtitleFontSize int `json:"subtitle_font_size"` + BgURL string `json:"bg_url"` + HotSearch []string `json:"hot_search"` + Btns []struct { + ID string `json:"id"` + Text string `json:"text"` + Type string `json:"type"` + Href string `json:"href"` + } `json:"btns"` + } `json:"banner_config"` + BasicDocConfig struct { + Title string `json:"title"` + List []string `json:"list"` + } `json:"basic_doc_config"` + DirDocConfig struct { + Title string `json:"title"` + List []string `json:"list"` + } `json:"dir_doc_config"` + SimpleDocConfig struct { + Title string `json:"title"` + List []string `json:"list"` + } `json:"simple_doc_config"` + CarouselConfig struct { + Title string `json:"title"` + List []struct { + ID string `json:"id"` + Title string `json:"title"` + URL string `json:"url"` + Desc string `json:"desc"` + } `json:"list"` + } `json:"carousel_config"` + FaqConfig struct { + Title string `json:"title"` + List []struct { + ID string `json:"id"` + Question string `json:"question"` + Link string `json:"link"` + } `json:"list"` + } `json:"faq_config"` + ComConfigOrder []string `json:"com_config_order"` +} + type DisclaimerSettings struct { Content *string `json:"content"` } @@ -326,6 +378,8 @@ type AppSettingsResp struct { OpenAIAPIBotSettings OpenAIAPIBotSettings `json:"openai_api_bot_settings"` // Disclaimer Settings DisclaimerSettings DisclaimerSettings `json:"disclaimer_settings"` + // WebApp Landing Settings + WebAppLandingSettings *WebAppLandingSettings `json:"web_app_landing_settings,omitempty"` } func (s *AppSettingsResp) Scan(value any) error { diff --git a/backend/usecase/app.go b/backend/usecase/app.go index f202f40f..54d172eb 100644 --- a/backend/usecase/app.go +++ b/backend/usecase/app.go @@ -394,6 +394,8 @@ func (u *AppUsecase) GetAppDetailByKBIDAndAppType(ctx context.Context, kbID stri OpenAIAPIBotSettings: app.Settings.OpenAIAPIBotSettings, // disclaimer settings DisclaimerSettings: app.Settings.DisclaimerSettings, + // webapp landing settings + WebAppLandingSettings: app.Settings.WebAppLandingSettings, WatermarkContent: app.Settings.WatermarkContent, WatermarkSetting: app.Settings.WatermarkSetting, @@ -456,6 +458,8 @@ func (u *AppUsecase) GetWebAppInfo(ctx context.Context, kbID string) (*domain.Ap WebAppCustomSettings: app.Settings.WebAppCustomSettings, // Disclaimer Settings DisclaimerSettings: app.Settings.DisclaimerSettings, + // WebApp Landing Settings + WebAppLandingSettings: app.Settings.WebAppLandingSettings, WatermarkContent: app.Settings.WatermarkContent, WatermarkSetting: app.Settings.WatermarkSetting, From 93484ff3ec20f7e326a660e602b7632fddd5efbe Mon Sep 17 00:00:00 2001 From: coltea Date: Sun, 28 Sep 2025 17:10:33 +0800 Subject: [PATCH 2/3] fix subtitle --- backend/docs/docs.go | 2 +- backend/docs/swagger.json | 2 +- backend/docs/swagger.yaml | 2 +- backend/domain/app.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 002a9003..56ad4c7c 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -7420,7 +7420,7 @@ const docTemplate = `{ "placeholder": { "type": "string" }, - "sub_title": { + "subtitle": { "type": "string" }, "subtitle_color": { diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index e18036ff..441b55e6 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -7413,7 +7413,7 @@ "placeholder": { "type": "string" }, - "sub_title": { + "subtitle": { "type": "string" }, "subtitle_color": { diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 39e8bbea..43ddc07a 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -1903,7 +1903,7 @@ definitions: type: array placeholder: type: string - sub_title: + subtitle: type: string subtitle_color: type: string diff --git a/backend/domain/app.go b/backend/domain/app.go index 6ad16719..fbb4c71d 100644 --- a/backend/domain/app.go +++ b/backend/domain/app.go @@ -157,7 +157,7 @@ type WebAppLandingSettings struct { Title string `json:"title"` TitleColor string `json:"title_color"` TitleFontSize int `json:"title_font_size"` - Subtitle string `json:"sub_title"` + Subtitle string `json:"subtitle"` Placeholder string `json:"placeholder"` SubtitleColor string `json:"subtitle_color"` SubtitleFontSize int `json:"subtitle_font_size"` From c32c77f2c247a78df2517bf6116a953319245799 Mon Sep 17 00:00:00 2001 From: coltea Date: Mon, 29 Sep 2025 11:33:01 +0800 Subject: [PATCH 3/3] feat recommend list add landing --- backend/api/share/v1/node.go | 13 ++- backend/cmd/api/wire_gen.go | 2 +- backend/docs/docs.go | 122 +++++++++++++++++++--------- backend/docs/swagger.json | 122 +++++++++++++++++++--------- backend/docs/swagger.yaml | 81 +++++++++++++------ backend/domain/app.go | 24 ++++-- backend/handler/share/node.go | 15 ++-- backend/pro | 2 +- backend/usecase/app.go | 3 + backend/usecase/node.go | 144 ++++++++++++++++++++++++---------- 10 files changed, 370 insertions(+), 158 deletions(-) diff --git a/backend/api/share/v1/node.go b/backend/api/share/v1/node.go index a692199f..ef1a75c4 100644 --- a/backend/api/share/v1/node.go +++ b/backend/api/share/v1/node.go @@ -19,7 +19,18 @@ type ShareNodeListItemResp struct { UpdatedAt time.Time `json:"updated_at"` } -type RecommendNodeListItem struct { +type NodeRecommendListReq struct { + KbID string `json:"kb_id"` +} + +type NodeRecommendListResp struct { + NodeRecommend []NodeItem `json:"node_recommends"` + BasicDocs []NodeItem `json:"basic_docs"` + DirDocs []NodeItem `json:"dir_docs"` + SimpleDocs []NodeItem `json:"simple_docs"` +} + +type NodeItem struct { ID string `json:"id"` Name string `json:"name"` Type domain.NodeType `json:"type"` diff --git a/backend/cmd/api/wire_gen.go b/backend/cmd/api/wire_gen.go index e2d7b68e..53d50fe6 100644 --- a/backend/cmd/api/wire_gen.go +++ b/backend/cmd/api/wire_gen.go @@ -111,7 +111,7 @@ func createApp() (*App, error) { if err != nil { return nil, err } - appUsecase := usecase.NewAppUsecase(appRepository, authRepo, nodeUsecase, logger, configConfig, chatUsecase, cacheCache) + appUsecase := usecase.NewAppUsecase(appRepository, authRepo, nodeRepository, nodeUsecase, logger, configConfig, chatUsecase, cacheCache) appHandler := v1.NewAppHandler(echo, baseHandler, logger, authMiddleware, appUsecase, modelUsecase, conversationUsecase, configConfig) fileUsecase := usecase.NewFileUsecase(logger, minioClient, configConfig) fileHandler := v1.NewFileHandler(echo, baseHandler, logger, authMiddleware, minioClient, configConfig, fileUsecase) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index 56ad4c7c..54cb43ae 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -4452,10 +4452,7 @@ const docTemplate = `{ "type": "object", "properties": { "data": { - "type": "array", - "items": { - "$ref": "#/definitions/v1.RecommendNodeListItem" - } + "$ref": "#/definitions/v1.NodeRecommendListResp" } } } @@ -7443,6 +7440,9 @@ const docTemplate = `{ "basic_doc_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7451,6 +7451,9 @@ const docTemplate = `{ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } }, @@ -7491,6 +7494,9 @@ const docTemplate = `{ "dir_doc_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7499,12 +7505,18 @@ const docTemplate = `{ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } }, "faq_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7524,12 +7536,18 @@ const docTemplate = `{ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } }, "simple_doc_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7538,6 +7556,9 @@ const docTemplate = `{ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } } @@ -8363,6 +8384,38 @@ const docTemplate = `{ } } }, + "v1.NodeItem": { + "type": "object", + "properties": { + "emoji": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parent_id": { + "type": "string" + }, + "position": { + "type": "number" + }, + "recommend_nodes": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.RecommendNodeListResp" + } + }, + "summary": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/domain.NodeType" + } + } + }, "v1.NodePermissionEditReq": { "type": "object", "required": [ @@ -8440,6 +8493,35 @@ const docTemplate = `{ } } }, + "v1.NodeRecommendListResp": { + "type": "object", + "properties": { + "basic_docs": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + }, + "dir_docs": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + }, + "node_recommends": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + }, + "simple_docs": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + } + } + }, "v1.NotionParseItem": { "type": "object", "properties": { @@ -8503,38 +8585,6 @@ const docTemplate = `{ } } }, - "v1.RecommendNodeListItem": { - "type": "object", - "properties": { - "emoji": { - "type": "string" - }, - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "parent_id": { - "type": "string" - }, - "position": { - "type": "number" - }, - "recommend_nodes": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.RecommendNodeListResp" - } - }, - "summary": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/domain.NodeType" - } - } - }, "v1.ResetPasswordReq": { "type": "object", "required": [ diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 441b55e6..a7b3d744 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -4445,10 +4445,7 @@ "type": "object", "properties": { "data": { - "type": "array", - "items": { - "$ref": "#/definitions/v1.RecommendNodeListItem" - } + "$ref": "#/definitions/v1.NodeRecommendListResp" } } } @@ -7436,6 +7433,9 @@ "basic_doc_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7444,6 +7444,9 @@ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } }, @@ -7484,6 +7487,9 @@ "dir_doc_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7492,12 +7498,18 @@ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } }, "faq_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7517,12 +7529,18 @@ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } }, "simple_doc_config": { "type": "object", "properties": { + "bg_color": { + "type": "string" + }, "list": { "type": "array", "items": { @@ -7531,6 +7549,9 @@ }, "title": { "type": "string" + }, + "title_color": { + "type": "string" } } } @@ -8356,6 +8377,38 @@ } } }, + "v1.NodeItem": { + "type": "object", + "properties": { + "emoji": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "parent_id": { + "type": "string" + }, + "position": { + "type": "number" + }, + "recommend_nodes": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.RecommendNodeListResp" + } + }, + "summary": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/domain.NodeType" + } + } + }, "v1.NodePermissionEditReq": { "type": "object", "required": [ @@ -8433,6 +8486,35 @@ } } }, + "v1.NodeRecommendListResp": { + "type": "object", + "properties": { + "basic_docs": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + }, + "dir_docs": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + }, + "node_recommends": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + }, + "simple_docs": { + "type": "array", + "items": { + "$ref": "#/definitions/v1.NodeItem" + } + } + } + }, "v1.NotionParseItem": { "type": "object", "properties": { @@ -8496,38 +8578,6 @@ } } }, - "v1.RecommendNodeListItem": { - "type": "object", - "properties": { - "emoji": { - "type": "string" - }, - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "parent_id": { - "type": "string" - }, - "position": { - "type": "number" - }, - "recommend_nodes": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.RecommendNodeListResp" - } - }, - "summary": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/domain.NodeType" - } - } - }, "v1.ResetPasswordReq": { "type": "object", "required": [ diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 43ddc07a..3bea8f35 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -1918,12 +1918,16 @@ definitions: type: object basic_doc_config: properties: + bg_color: + type: string list: items: type: string type: array title: type: string + title_color: + type: string type: object carousel_config: properties: @@ -1949,15 +1953,21 @@ definitions: type: array dir_doc_config: properties: + bg_color: + type: string list: items: type: string type: array title: type: string + title_color: + type: string type: object faq_config: properties: + bg_color: + type: string list: items: properties: @@ -1971,15 +1981,21 @@ definitions: type: array title: type: string + title_color: + type: string type: object simple_doc_config: properties: + bg_color: + type: string list: items: type: string type: array title: type: string + title_color: + type: string type: object type: object domain.WidgetBotSettings: @@ -2522,6 +2538,27 @@ definitions: updated_at: type: string type: object + v1.NodeItem: + properties: + emoji: + type: string + id: + type: string + name: + type: string + parent_id: + type: string + position: + type: number + recommend_nodes: + items: + $ref: '#/definitions/domain.RecommendNodeListResp' + type: array + summary: + type: string + type: + $ref: '#/definitions/domain.NodeType' + type: object v1.NodePermissionEditReq: properties: answerable_groups: @@ -2575,6 +2612,25 @@ definitions: $ref: '#/definitions/domain.NodeGroupDetail' type: array type: object + v1.NodeRecommendListResp: + properties: + basic_docs: + items: + $ref: '#/definitions/v1.NodeItem' + type: array + dir_docs: + items: + $ref: '#/definitions/v1.NodeItem' + type: array + node_recommends: + items: + $ref: '#/definitions/v1.NodeItem' + type: array + simple_docs: + items: + $ref: '#/definitions/v1.NodeItem' + type: array + type: object v1.NotionParseItem: properties: id: @@ -2616,27 +2672,6 @@ definitions: content: type: string type: object - v1.RecommendNodeListItem: - properties: - emoji: - type: string - id: - type: string - name: - type: string - parent_id: - type: string - position: - type: number - recommend_nodes: - items: - $ref: '#/definitions/domain.RecommendNodeListResp' - type: array - summary: - type: string - type: - $ref: '#/definitions/domain.NodeType' - type: object v1.ResetPasswordReq: properties: id: @@ -5590,9 +5625,7 @@ paths: - $ref: '#/definitions/domain.Response' - properties: data: - items: - $ref: '#/definitions/v1.RecommendNodeListItem' - type: array + $ref: '#/definitions/v1.NodeRecommendListResp' type: object summary: 推荐卡片列表 tags: diff --git a/backend/domain/app.go b/backend/domain/app.go index fbb4c71d..9a58f34f 100644 --- a/backend/domain/app.go +++ b/backend/domain/app.go @@ -171,16 +171,22 @@ type WebAppLandingSettings struct { } `json:"btns"` } `json:"banner_config"` BasicDocConfig struct { - Title string `json:"title"` - List []string `json:"list"` + Title string `json:"title"` + TitleColor string `json:"title_color"` + BgColor string `json:"bg_color"` + List []string `json:"list"` } `json:"basic_doc_config"` DirDocConfig struct { - Title string `json:"title"` - List []string `json:"list"` + Title string `json:"title"` + TitleColor string `json:"title_color"` + BgColor string `json:"bg_color"` + List []string `json:"list"` } `json:"dir_doc_config"` SimpleDocConfig struct { - Title string `json:"title"` - List []string `json:"list"` + Title string `json:"title"` + TitleColor string `json:"title_color"` + BgColor string `json:"bg_color"` + List []string `json:"list"` } `json:"simple_doc_config"` CarouselConfig struct { Title string `json:"title"` @@ -192,8 +198,10 @@ type WebAppLandingSettings struct { } `json:"list"` } `json:"carousel_config"` FaqConfig struct { - Title string `json:"title"` - List []struct { + Title string `json:"title"` + TitleColor string `json:"title_color"` + BgColor string `json:"bg_color"` + List []struct { ID string `json:"id"` Question string `json:"question"` Link string `json:"link"` diff --git a/backend/handler/share/node.go b/backend/handler/share/node.go index 24a3a2e1..2e908b3b 100644 --- a/backend/handler/share/node.go +++ b/backend/handler/share/node.go @@ -1,7 +1,6 @@ package share import ( - "github.com/jinzhu/copier" "github.com/labstack/echo/v4" v1 "github.com/chaitin/panda-wiki/api/share/v1" @@ -71,24 +70,24 @@ func (h *ShareNodeHandler) GetNodeList(c echo.Context) error { // @Accept json // @Produce json // @Param X-KB-ID header string true "kb id" -// @Success 200 {object} domain.Response{data=[]v1.RecommendNodeListItem} +// @Success 200 {object} domain.Response{data=v1.NodeRecommendListResp} // @Router /share/v1/node/recommend/list [get] func (h *ShareNodeHandler) NodeRecommendList(c echo.Context) error { + var req v1.NodeRecommendListReq + if err := c.Bind(&req); err != nil { + return h.NewResponseWithError(c, "bind request", err) + } + kbID := c.Request().Header.Get("X-KB-ID") if kbID == "" { return h.NewResponseWithError(c, "kb_id is required", nil) } - nodes, err := h.usecase.GetNodeRecommendListByKBID(c.Request().Context(), kbID, domain.GetAuthID(c)) + resp, err := h.usecase.GetNodeRecommendListByKBID(c.Request().Context(), kbID, domain.GetAuthID(c)) if err != nil { return h.NewResponseWithError(c, "failed to get node list", err) } - var resp []v1.RecommendNodeListItem - if err := copier.Copy(&resp, &nodes); err != nil { - return h.NewResponseWithError(c, "failed to get node list", err) - } - return h.NewResponseWithData(c, resp) } diff --git a/backend/pro b/backend/pro index 5080087c..78c3784c 160000 --- a/backend/pro +++ b/backend/pro @@ -1 +1 @@ -Subproject commit 5080087c22e62c14215ac467b668920d24edd100 +Subproject commit 78c3784ce805d8fbdd1798c4e1b71e11105e1a32 diff --git a/backend/usecase/app.go b/backend/usecase/app.go index 54d172eb..511066f0 100644 --- a/backend/usecase/app.go +++ b/backend/usecase/app.go @@ -21,6 +21,7 @@ import ( type AppUsecase struct { repo *pg.AppRepository authRepo *pg.AuthRepo + nodeRepo *pg.NodeRepository nodeUsecase *NodeUsecase chatUsecase *ChatUsecase logger *log.Logger @@ -37,6 +38,7 @@ type AppUsecase struct { func NewAppUsecase( repo *pg.AppRepository, authRepo *pg.AuthRepo, + nodeRepo *pg.NodeRepository, nodeUsecase *NodeUsecase, logger *log.Logger, config *config.Config, @@ -48,6 +50,7 @@ func NewAppUsecase( nodeUsecase: nodeUsecase, chatUsecase: chatUsecase, authRepo: authRepo, + nodeRepo: nodeRepo, logger: logger.WithModule("usecase.app"), config: config, cache: cache, diff --git a/backend/usecase/node.go b/backend/usecase/node.go index 90ae94dd..20404554 100644 --- a/backend/usecase/node.go +++ b/backend/usecase/node.go @@ -15,6 +15,7 @@ import ( "gorm.io/gorm" v1 "github.com/chaitin/panda-wiki/api/node/v1" + shareV1 "github.com/chaitin/panda-wiki/api/share/v1" "github.com/chaitin/panda-wiki/consts" "github.com/chaitin/panda-wiki/domain" "github.com/chaitin/panda-wiki/log" @@ -305,72 +306,129 @@ func (u *NodeUsecase) GetNodeReleaseListByKBID(ctx context.Context, kbID string, return items, nil } -func (u *NodeUsecase) GetNodeRecommendListByKBID(ctx context.Context, kbID string, authId uint) ([]*domain.RecommendNodeListResp, error) { +func (u *NodeUsecase) GetNodeRecommendListByKBID(ctx context.Context, kbID string, authId uint) (*shareV1.NodeRecommendListResp, error) { app, err := u.appRepo.GetOrCreateAppByKBIDAndType(ctx, kbID, domain.AppTypeWeb) if err != nil { return nil, err } - recommendNodes := make([]*domain.RecommendNodeListResp, 0) + resp := &shareV1.NodeRecommendListResp{ + NodeRecommend: make([]shareV1.NodeItem, 0), + BasicDocs: make([]shareV1.NodeItem, 0), + DirDocs: make([]shareV1.NodeItem, 0), + SimpleDocs: make([]shareV1.NodeItem, 0), + } - if len(app.Settings.RecommendNodeIDs) > 0 { - nodes, err := u.GetRecommendNodeList(ctx, &domain.GetRecommendNodeListReq{ - KBID: kbID, - NodeIDs: app.Settings.RecommendNodeIDs, - }) - if err != nil { - return nil, err - } + nodeIds := make([]string, 0) + nodeIds = append(nodeIds, app.Settings.RecommendNodeIDs...) + if app.Settings.WebAppLandingSettings != nil { + nodeIds = append(nodeIds, lo.Union( + app.Settings.WebAppLandingSettings.BasicDocConfig.List, + app.Settings.WebAppLandingSettings.DirDocConfig.List, + app.Settings.WebAppLandingSettings.SimpleDocConfig.List, + )...) + } - nodeVisibleGroupIds, err := u.GetNodeIdsByAuthId(ctx, authId, consts.NodePermNameVisible) - if err != nil { - return nil, err - } + if len(nodeIds) == 0 { + return resp, nil + } - nodeVisitableGroupIds, err := u.GetNodeIdsByAuthId(ctx, authId, consts.NodePermNameVisitable) - if err != nil { - return nil, err - } + recommendNodes := make([]*domain.RecommendNodeListResp, 0) + nodes, err := u.GetRecommendNodeList(ctx, &domain.GetRecommendNodeListReq{ + KBID: kbID, + NodeIDs: nodeIds, + }) + if err != nil { + return nil, err + } + + nodeVisibleGroupIds, err := u.GetNodeIdsByAuthId(ctx, authId, consts.NodePermNameVisible) + if err != nil { + return nil, err + } + + nodeVisitableGroupIds, err := u.GetNodeIdsByAuthId(ctx, authId, consts.NodePermNameVisitable) + if err != nil { + return nil, err + } - for i, node := range nodes { - switch node.Permissions.Visitable { - case consts.NodeAccessPermClosed: + for i, node := range nodes { + switch node.Permissions.Visitable { + case consts.NodeAccessPermClosed: + nodes[i].Summary = "" + case consts.NodeAccessPermPartial: + if !slices.Contains(nodeVisitableGroupIds, node.ID) { nodes[i].Summary = "" - case consts.NodeAccessPermPartial: - if !slices.Contains(nodeVisitableGroupIds, node.ID) { - nodes[i].Summary = "" - } } + } - switch node.Permissions.Visible { - case consts.NodeAccessPermOpen: + switch node.Permissions.Visible { + case consts.NodeAccessPermOpen: + recommendNodes = append(recommendNodes, nodes[i]) + case consts.NodeAccessPermPartial: + if slices.Contains(nodeVisibleGroupIds, node.ID) { recommendNodes = append(recommendNodes, nodes[i]) - case consts.NodeAccessPermPartial: - if slices.Contains(nodeVisibleGroupIds, node.ID) { - recommendNodes = append(recommendNodes, nodes[i]) - } } + } - if node.Type == domain.NodeTypeFolder { - newFileNodes := make([]*domain.RecommendNodeListResp, 0) + if node.Type == domain.NodeTypeFolder { + newFileNodes := make([]*domain.RecommendNodeListResp, 0) - for i2, recommendNode := range node.RecommendNodes { - node.RecommendNodes[i2].Summary = "" - switch recommendNode.Permissions.Visible { - case consts.NodeAccessPermOpen: + for i2, recommendNode := range node.RecommendNodes { + node.RecommendNodes[i2].Summary = "" + switch recommendNode.Permissions.Visible { + case consts.NodeAccessPermOpen: + newFileNodes = append(newFileNodes, node.RecommendNodes[i2]) + case consts.NodeAccessPermPartial: + if slices.Contains(nodeVisibleGroupIds, node.RecommendNodes[i2].ID) { newFileNodes = append(newFileNodes, node.RecommendNodes[i2]) - case consts.NodeAccessPermPartial: - if slices.Contains(nodeVisibleGroupIds, node.RecommendNodes[i2].ID) { - newFileNodes = append(newFileNodes, node.RecommendNodes[i2]) - } } } - node.RecommendNodes = newFileNodes + } + node.RecommendNodes = newFileNodes + } + } + + nodeMap := lo.SliceToMap(recommendNodes, func(node *domain.RecommendNodeListResp) (string, *shareV1.NodeItem) { + return node.ID, &shareV1.NodeItem{ + ID: node.ID, + Name: node.Name, + Type: node.Type, + Summary: node.Summary, + ParentID: node.Summary, + Position: node.Position, + Emoji: node.Emoji, + RecommendNodes: node.RecommendNodes, + } + }) + + for _, id := range app.Settings.RecommendNodeIDs { + if node, ok := nodeMap[id]; ok { + resp.NodeRecommend = append(resp.NodeRecommend, *node) + } + } + if app.Settings.WebAppLandingSettings != nil { + for _, id := range app.Settings.WebAppLandingSettings.BasicDocConfig.List { + if node, ok := nodeMap[id]; ok { + resp.BasicDocs = append(resp.BasicDocs, *node) + } + } + + for _, id := range app.Settings.WebAppLandingSettings.DirDocConfig.List { + if node, ok := nodeMap[id]; ok { + resp.DirDocs = append(resp.DirDocs, *node) + } + } + + for _, id := range app.Settings.WebAppLandingSettings.SimpleDocConfig.List { + if node, ok := nodeMap[id]; ok { + resp.SimpleDocs = append(resp.SimpleDocs, *node) } } } - return recommendNodes, nil + + return resp, nil } func (u *NodeUsecase) GetNodeIdsByAuthId(ctx context.Context, authId uint, PermName consts.NodePermName) ([]string, error) {