diff --git a/DESIGN.md b/DESIGN.md index fa03d61..1aa5bcd 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -9,7 +9,7 @@ - Home 首页路径为 `/`,用于聚合公开 Wiki 入口;Logo 导航回到 Home,用户可从 Home 进入核心资料、每日 CheckList、Life 和正在准备中的分区。 - 桌面端使用侧边栏导航,侧边栏可折叠为图标栏;移动端继续使用抽屉式侧边栏。 - 全局顶部导航栏承载语言切换、通知、User Profile 和登录 / 退出等账号操作;除 User Profile 可展示用户名外,顶部操作以图标按钮呈现。 -- 全局顶部导航栏提供全站搜索。搜索结果按内容类型分组展示,覆盖 Pokemon、Habitats、Items、Ancient Artifacts、Recipes、Daily CheckList 和公开可见的 Life Post;结果跳转到对应公开详情页或页面锚点。 +- 全局顶部导航栏提供全站搜索。搜索结果按内容类型分组展示,覆盖 Pokemon、Habitats、Items、Ancient Artifacts、Recipes、Daily CheckList、公开可见的 Life Post 和公开用户 Profile;结果跳转到对应公开详情页、页面锚点或 `/profile/:id`。 - 管理入口用于维护全局配置、语言、系统文案、列表排序和每日 CheckList。 ## 技术栈 @@ -24,7 +24,7 @@ - `DESIGN.md` 是产品行为、数据结构和 API 暴露边界的单一事实来源。 - API 只返回业务需要的字段,不返回密码、token hash、验证 token、内部调试字段或不必要的元数据。 -- 全局搜索 API 只返回公开浏览所需的最小结果字段:结果类型、ID、展示标题、目标 URL、可选摘要和可选图片;不返回编辑审计、权限、审核原因、内部字段或调试信息。 +- 全局搜索 API 只返回公开浏览所需的最小结果字段:结果类型、ID、展示标题、目标 URL、可选摘要和可选图片;用户搜索结果只使用公开 Profile 所需的 `id`、`displayName` 和目标 URL,不返回邮箱、角色、权限、Referral、编辑审计、审核原因、token/hash、内部字段或调试信息。 - 用户界面只展示业务数据和设计内的文案,不展示提示词、计划、调试信息、字段内部名或修改说明。 - 可编辑 Wiki 内容必须记录创建者、最后编辑者、创建时间、最后编辑时间和编辑历史。 - 列表顺序由 `sort_order` 控制,默认按创建时间旧到新初始化,排序值按 10 递增以便后续插入和拖拽排序。 diff --git a/backend/src/queries.ts b/backend/src/queries.ts index 245fa38..f0148be 100644 --- a/backend/src/queries.ts +++ b/backend/src/queries.ts @@ -43,7 +43,8 @@ type GlobalSearchGroupType = | 'ancient-artifacts' | 'recipes' | 'daily-checklist' - | 'life'; + | 'life' + | 'users'; type GlobalSearchItem = { id: number; type: GlobalSearchGroupType; @@ -2466,7 +2467,7 @@ export async function globalSearch(paramsQuery: QueryParams = {}, locale = defau const checklistTitle = localizedField('daily-checklist-items', 'c.id', 'c.title', 'title', locale); const lifeCategoryName = localizedName('life-tags', 'lc', locale); - const [pokemon, habitats, items, artifacts, recipes, checklist, life] = await Promise.all([ + const [pokemon, habitats, items, artifacts, recipes, checklist, life, users] = await Promise.all([ query( ` SELECT @@ -2604,6 +2605,23 @@ export async function globalSearch(paramsQuery: QueryParams = {}, locale = defau LIMIT $2 `, [pattern, limit] + ), + query( + ` + SELECT + u.id, + 'users' AS type, + u.display_name AS title, + '/profile/' || u.id AS url, + NULL AS summary, + NULL AS meta, + NULL AS image + FROM users u + WHERE u.display_name ILIKE $1 + ORDER BY lower(u.display_name), u.id + LIMIT $2 + `, + [pattern, limit] ) ]); @@ -2614,7 +2632,8 @@ export async function globalSearch(paramsQuery: QueryParams = {}, locale = defau { type: 'ancient-artifacts', items: artifacts }, { type: 'recipes', items: recipes }, { type: 'daily-checklist', items: checklist }, - { type: 'life', items: life } + { type: 'life', items: life }, + { type: 'users', items: users } ]; return { query: search, groups: groups.filter((group) => group.items.length > 0) }; diff --git a/frontend/src/components/GlobalSearch.vue b/frontend/src/components/GlobalSearch.vue index f46056c..9afc6ec 100644 --- a/frontend/src/components/GlobalSearch.vue +++ b/frontend/src/components/GlobalSearch.vue @@ -36,7 +36,8 @@ const groupLabels: Record = { 'ancient-artifacts': 'search.groups.ancientArtifacts', recipes: 'search.groups.recipes', 'daily-checklist': 'search.groups.dailyChecklist', - life: 'search.groups.life' + life: 'search.groups.life', + users: 'search.groups.users' }; function clearSearchTimeout() { diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index 7a5cebd..53d88ef 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -325,7 +325,8 @@ export type GlobalSearchGroupType = | 'ancient-artifacts' | 'recipes' | 'daily-checklist' - | 'life'; + | 'life' + | 'users'; export interface GlobalSearchItem { id: number; diff --git a/system-wordings.ts b/system-wordings.ts index 1976853..38b4102 100644 --- a/system-wordings.ts +++ b/system-wordings.ts @@ -90,7 +90,8 @@ export const systemWordingMessages = { ancientArtifacts: 'Ancient Artifacts', recipes: 'Recipes', dailyChecklist: 'Daily CheckList', - life: 'Life' + life: 'Life', + users: 'Users' } }, notifications: { @@ -1409,7 +1410,8 @@ export const systemWordingMessages = { ancientArtifacts: 'Ancient Artifacts', recipes: '材料单', dailyChecklist: '每日 CheckList', - life: 'Life' + life: 'Life', + users: '用户' } }, notifications: {