浏览代码

docs(story): 创建故事017.006 - 设置与帮助功能实现

- 创建rencai-settings-ui包的设置页和帮助功能
- 实现个人信息摘要、功能入口列表、退出登录功能
- 集成登录日志查询API(账号与安全页)
- 使用React Query管理服务端状态
- TabBar页面使用Navbar无返回按钮
- 包含完整的测试策略和代码示例

状态: Approved (清晰度评分: 9/10)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 3 周之前
父节点
当前提交
eca2c4084b
共有 1 个文件被更改,包括 979 次插入0 次删除
  1. 979 0
      docs/stories/017.006.story.md

+ 979 - 0
docs/stories/017.006.story.md

@@ -0,0 +1,979 @@
+# 故事017.006: 设置与帮助功能实现
+
+## 元信息
+- **史诗**: 017 - 人才小程序功能实现
+- **优先级**: P1 - 核心功能
+- **状态**: Approved
+- **创建日期**: 2025-12-28
+- **负责人**: 开发团队
+
+## 故事描述
+
+**作为** 人才小程序开发者,
+**我想要** 实现设置页和帮助功能,
+**以便** 人才用户能够管理个人信息、查看帮助文档、修改账号设置和退出登录。
+
+### 背景
+
+**现有系统状态:**
+- 故事017.001已完成rencai mini ui包基础框架搭建
+- 故事017.002已完成登录与首页实现
+- 故事017.003已完成个人信息功能实现
+- 故事017.004已完成考勤记录功能实现
+- 故事017.005已完成就业信息功能实现
+- `@d8d/rencai-settings-ui`包基础框架已就绪
+- API客户端文件已创建(`src/api/index.ts`)
+- mini-talent项目路由结构已配置完成(设置页在底部TabBar中)
+
+**原型设计参考:**
+- `docs/小程序原型/rencai.html` 提供了设置页的完整原型设计
+- 设置页 (原型行770-906): 个人信息摘要、功能入口、帮助与支持、退出登录
+
+**技术集成模式:**
+- 参照`yongren-settings-ui`的实现模式(如果存在)
+- 设置页使用`@d8d/rencai-settings-ui`包
+- API调用逻辑封装在页面组件内部
+- **TabBar页面**:使用Navbar无返回按钮(参照故事017.012规范)
+
+**依赖API (史诗015):**
+- ✅ 退出登录API (POST /api/v1/rencai/auth/logout) - 已完成
+- ✅ 登录日志查询API (GET /api/v1/rencai/auth/login-logs) - 已完成
+- 📋 帮助与支持API - P2优先级,当前使用静态内容
+- 📋 用户协议API - P2优先级,当前使用静态内容
+- 📋 隐私政策API - P2优先级,当前使用静态内容
+- 📋 前端可直接使用退出登录和登录日志API,帮助内容使用静态展示
+
+**依赖故事完成状态:**
+- ✅ 故事017.001: rencai mini ui包基础框架搭建完成
+- ✅ 故事017.002: 登录与首页实现完成
+- ✅ 故事017.003: 个人信息功能实现完成
+- ✅ 故事017.004: 考勤记录功能实现完成
+- ✅ 故事017.005: 就业信息功能实现完成
+- ✅ 故事017.012: 统一Navbar导航栏组件规范完成
+
+## 验收标准
+
+### 个人信息摘要展示
+- [ ] 设置页顶部展示个人信息摘要(姓名、残疾类型)
+- [ ] 显示3列统计数据:本月出勤、累计出勤、本月薪资
+- [ ] 圆形头像显示用户姓名首字
+- [ ] 头像样式:蓝色背景 + 白色文字
+
+### 功能入口列表
+- [ ] 修改个人信息入口可用(带图标和右箭头)
+- [ ] 账号与安全入口可用(带图标和右箭头)
+- [ ] 消息通知设置入口可用(带图标和右箭头)
+- [ ] 每个入口使用圆形图标背景(蓝色、绿色、紫色)
+
+### 帮助与支持入口
+- [ ] 帮助中心入口可用(带图标和右箭头)
+- [ ] 用户协议入口可用(带图标和右箭头)
+- [ ] 隐私政策入口可用(带图标和右箭头)
+- [ ] 每个入口使用圆形图标背景(黄色、靛蓝、粉色)
+
+### 退出登录功能
+- [ ] 退出登录按钮可用(红色背景图标)
+- [ ] 点击退出登录调用退出登录API
+- [ ] 退出成功后清除本地token和用户状态
+- [ ] 退出成功后跳转到登录页
+
+### 登录日志查询
+- [ ] 登录日志查询接口返回个人的登录日志记录
+- [ ] 在账号与安全页展示登录日志(时间、设备、IP地址)
+- [ ] 日志按时间倒序排列
+
+### 页面设计与布局
+- [ ] 页面设计符合原型标准,移动端体验良好
+- [ ] 已集成Navbar导航栏组件(**TabBar页面**,无返回按钮)
+- [ ] 所有功能入口列表项使用统一的hover样式
+
+## 任务列表
+
+### 任务1: 创建设置页主页面组件 (AC: 个人信息摘要展示, 页面设计与布局)
+- [ ] 1.1 在`@d8d/rencai-settings-ui`中实现`SettingsPage`页面组件 (`src/pages/SettingsPage/SettingsPage.tsx`)
+- [ ] 1.2 创建个人信息摘要组件 (`src/components/UserProfileSummary.tsx`)
+  - 显示圆形头像(用户姓名首字,蓝色背景)
+  - 显示用户姓名和残疾类型
+  - 显示3列统计:本月出勤、累计出勤、本月薪资
+- [ ] 1.3 集成Navbar导航栏组件(TabBar页面,无返回按钮)
+- [ ] 1.4 实现数据加载状态(Loading状态)
+- [ ] 1.5 实现错误处理(数据加载失败时显示错误提示)
+
+### 任务2: 实现功能入口列表 (AC: 功能入口列表)
+- [ ] 2.1 创建功能入口组件 (`src/components/MenuItem.tsx`)
+  - 圆形图标背景(支持不同颜色)
+  - 图标使用Heroicons
+  - 标题文本
+  - 右箭头指示器
+- [ ] 2.2 创建功能入口列表组件 (`src/components/MenuSection.tsx`)
+  - 修改个人信息:蓝色背景,user图标
+  - 账号与安全:绿色背景,shield图标
+  - 消息通知设置:紫色背景,bell图标
+- [ ] 2.3 实现入口点击事件处理(预留导航接口)
+
+### 任务3: 实现帮助与支持入口 (AC: 帮助与支持入口)
+- [ ] 3.1 使用MenuSection组件创建帮助与支持入口列表
+  - 帮助中心:黄色背景,question-circle图标
+  - 用户协议:靛蓝背景,document-text图标
+  - 隐私政策:粉色背景,lock-closed图标
+- [ ] 3.2 实现入口点击事件处理(预留导航接口)
+
+### 任务4: 实现退出登录功能 (AC: 退出登录功能)
+- [ ] 4.1 创建退出登录按钮组件 (`src/components/LogoutButton.tsx`)
+  - 红色背景图标
+  - "退出登录"文本
+- [ ] 4.2 集成退出登录API(使用React Query的useMutation)
+  - 调用`POST /api/v1/rencai/auth/logout`
+  - 成功后清除本地token
+  - 成功后清除用户状态
+  - 成功后跳转到登录页
+- [ ] 4.3 实现退出确认对话框(可选,提升用户体验)
+
+### 任务5: 实现账号与安全页(登录日志) (AC: 登录日志查询)
+- [ ] 5.1 创建账号与安全页组件 (`src/pages/AccountSecurityPage/AccountSecurityPage.tsx`)
+- [ ] 5.2 创建登录日志列表组件 (`src/components/LoginLogsList.tsx`)
+  - 显示登录时间
+  - 显示设备信息
+  - 显示IP地址
+  - 按时间倒序排列
+- [ ] 5.3 集成登录日志查询API(使用React Query的useQuery)
+  - 调用`GET /api/v1/rencai/auth/login-logs`
+  - 使用分页加载(可选)
+- [ ] 5.4 添加Navbar导航栏(非TabBar页面,带返回按钮)
+
+### 任务6: 更新mini-talent页面集成 (AC: 集成与兼容性)
+- [ ] 6.1 更新`mini-talent/src/pages/settings/index.tsx`:
+  - 从`@d8d/rencai-settings-ui/pages/SettingsPage/SettingsPage`导入SettingsPage组件
+  - 用AuthProvider包装页面
+  - 添加认证检查(未登录跳转到登录页)
+  - 导出SettingsPage组件
+- [ ] 6.2 添加账号与安全页路由(如果需要)
+- [ ] 6.3 验证底部TabBar"更多"入口能正确跳转到设置页
+
+### 任务7: 实现页面样式和移动端适配 (AC: 页面设计与布局)
+- [ ] 7.1 参照原型设计实现设置页样式(原型行770-906)
+  - 个人信息摘要样式(圆形头像、3列统计)
+  - 功能入口列表样式(圆形图标背景、右箭头)
+  - 退出登录按钮样式(红色图标)
+- [ ] 7.2 确保页面设计符合移动端规范:
+  - 宽度参考: 375px
+  - 圆角规范: 12px (列表项)
+  - 颜色主题: 蓝色为主色
+  - 字体规范: 标题18-24px, 正文14px, 小字12px
+  - 图标背景色: 蓝/绿/紫/黄/靛蓝/粉/红
+- [ ] 7.3 使用正确的组件:设置页使用**TabBar页面**(无返回按钮的Navbar)
+
+### 任务8: 编写测试 (AC: 集成与兼容性)
+- [ ] 8.1 为SettingsPage编写组件测试 (`tests/pages/SettingsPage/SettingsPage.test.tsx`)
+  - 测试组件渲染
+  - 测试个人信息摘要展示(Mock数据)
+  - 测试功能入口列表显示
+  - 测试退出登录功能
+- [ ] 8.2 为子组件编写单元测试:
+  - UserProfileSummary.test.tsx
+  - MenuItem.test.tsx
+  - LogoutButton.test.tsx
+  - LoginLogsList.test.tsx(如果实现)
+- [ ] 8.3 编写集成测试验证现有功能不受影响
+- [ ] 8.4 运行`pnpm typecheck`确保类型检查通过
+
+## 开发者笔记
+
+### 前置故事见解
+
+**故事017.001完成状态:**
+- ✅ rencai系列7个UI包基础结构已创建
+- ✅ `@d8d/rencai-settings-ui`包基础框架已就绪
+- ✅ API客户端文件已创建(`src/api/index.ts`)
+- ✅ mini-talent项目路由结构已配置完成
+- ✅ package.json的exports字段已配置
+- ✅ Jest测试框架已配置(`jest.config.cjs`)
+
+**故事017.002完成状态:**
+- ✅ 登录页面功能完整,支持人才用户身份证号/残疾证号/手机号密码登录
+- ✅ 首页/个人主页页面展示个人概览数据
+- ✅ 认证状态管理正常,token存储和验证可靠
+- ✅ AuthContext提供登录状态、用户信息和登出方法
+
+**故事017.003完成状态:**
+- ✅ 个人信息页面功能完整
+- ✅ 数据脱敏工具函数实现(`maskUtils.ts`)
+- ✅ 证件照片预览功能实现
+- ✅ 测试框架选择确认:**mini项目使用Jest**(不是Vitest)
+
+**故事017.004完成状态:**
+- ✅ 考勤记录页面功能完整
+- ✅ 前端模拟数据规范实现
+- ✅ Taro布局规范确认(使用`flex flex-col`实现垂直布局)
+- ✅ Navbar导航栏集成规范确认
+
+**故事017.005完成状态:**
+- ✅ 就业信息页面功能完整
+- ✅ 使用React Query (useQuery) 管理服务端状态
+- ✅ 使用React Query (useMutation) 处理数据修改操作
+- ✅ 测试使用真实的QueryClientProvider
+
+**故事017.012完成状态:**
+- ✅ 统一Navbar导航栏组件规范
+- ✅ TabBar页面使用Navbar无返回按钮(leftIcon="" leftText="")
+- ✅ **本故事是TabBar页面**:使用Navbar无返回按钮
+
+**关键实现经验:**
+1. API客户端导入路径修正:从相应的后端模块包导入,而不是`@d8d/server`
+2. 页面文件简化设计:采用"薄包装层",仅导入并导出组件
+3. 复用现有共享组件:StatusBar、PageContainer、Navbar使用`@d8d/mini-shared-ui-components`中的实现
+4. 测试框架选择:**mini项目使用Jest**(不是Vitest)
+5. **使用React Query管理服务端状态**,不要使用useState + useEffect手动管理
+6. **本故事是TabBar页面**:需要使用Navbar无返回按钮
+
+### 技术栈要求
+
+**来源**: [architecture/tech-stack.md](../architecture/tech-stack.md)
+
+**运行时和框架:**
+- **Node.js**: 20.18.3
+- **Hono**: 4.8.5 (RPC客户端)
+- **React**: 19.1.0 (UI组件)
+- **Taro**: 4.1.4 (小程序框架)
+- **Tailwind CSS**: 4.1.11 (样式)
+- **React Query**: 5.83.0 (服务端状态管理)
+
+**测试框架:**
+- **Jest**: 30.2.0 (mini项目使用Jest,不是Vitest!)
+- **ts-jest**: 29.4.5 (TypeScript预处理器)
+- **@testing-library/react**: 16.3.0 (React组件测试)
+- **@d8d/mini-testing-utils**: workspace包 (Taro小程序测试工具)
+
+**重要**: **mini项目使用Jest测试框架**,与web应用使用的Vitest不同。
+
+### UI包开发规范
+
+**来源**:
+- [architecture/mini-ui-package-standards.md](../architecture/mini-ui-package-standards.md) - **Mini UI包专用规范(本文档必须遵循)**
+
+**关键规范要求:**
+
+#### 1. UI包内部导入规范
+**重要**: UI包内部导入必须使用相对路径,不要使用别名。
+
+**正确示例**:
+```typescript
+// ✅ 正确: 使用相对路径导入同一包内的模块
+import { UserProfileSummary } from '../../components/UserProfileSummary'
+import { MenuItem } from '../components/MenuItem'
+```
+
+**错误示例**:
+```typescript
+// ❌ 错误: 不要使用别名导入UI包内部的模块
+import { UserProfileSummary } from '@/components/UserProfileSummary'
+import { MenuItem } from '@/components/MenuItem'
+```
+
+#### 2. package.json exports配置规范
+```json
+{
+  "exports": {
+    ".": {
+      "types": "./dist/src/index.d.ts",
+      "import": "./dist/src/index.js",
+      "require": "./dist/src/index.js"
+    },
+    "./api": {
+      "types": "./src/api/index.ts",
+      "import": "./src/api/index.ts",
+      "require": "./src/api/index.ts"
+    },
+    "./pages/SettingsPage/SettingsPage": {
+      "types": "./src/pages/SettingsPage/SettingsPage.tsx",
+      "import": "./dist/src/pages/SettingsPage/SettingsPage.js",
+      "require": "./dist/src/pages/SettingsPage/SettingsPage.js"
+    }
+  }
+}
+```
+
+#### 3. React Query数据获取规范
+**重要**: Mini UI包必须使用React Query (`@tanstack/react-query`) 管理服务端状态。
+
+**数据查询 (useQuery)**:
+```typescript
+import { useQuery } from '@tanstack/react-query'
+import { apiClient } from '../../api'
+
+const MyPage: React.FC = () => {
+  // ✅ 正确: 使用React Query
+  const { data, isLoading, error } = useQuery({
+    queryKey: ['login-logs'],
+    queryFn: async () => {
+      const res = await apiClient.auth['login-logs'].$get()
+      if (!res.ok) {
+        throw new Error('获取登录日志失败')
+      }
+      return await res.json()
+    }
+  })
+
+  if (isLoading) return <div>加载中...</div>
+  if (error) return <div>加载失败</div>
+
+  return <div>{/* 渲染数据 */}</div>
+}
+```
+
+**数据修改 (useMutation)**:
+```typescript
+import { useMutation, useQueryClient } from '@tanstack/react-query'
+import { apiClient } from '../../api'
+
+const SettingsPage: React.FC = () => {
+  const queryClient = useQueryClient()
+  const navigate = useNavigate()
+
+  // 退出登录mutation
+  const logoutMutation = useMutation({
+    mutationFn: async () => {
+      const res = await apiClient.auth.logout.$post()
+      if (!res.ok) {
+        throw new Error('退出登录失败')
+      }
+      return await res.json()
+    },
+    onSuccess: () => {
+      // 清除查询缓存
+      queryClient.clear()
+      // 清除本地存储
+      localStorage.removeItem('token')
+      localStorage.removeItem('user')
+      // 跳转到登录页
+      Taro.reLaunch({ url: '/pages/login/index' })
+    },
+    onError: (error) => {
+      Taro.showToast({
+        title: error.message,
+        icon: 'none'
+      })
+    }
+  })
+
+  const handleLogout = () => {
+    Taro.showModal({
+      title: '提示',
+      content: '确定要退出登录吗?',
+      success: (res) => {
+        if (res.confirm) {
+          logoutMutation.mutate()
+        }
+      }
+    })
+  }
+
+  return (
+    <View onClick={handleLogout}>
+      <Text>{logoutMutation.isPending ? '退出中...' : '退出登录'}</Text>
+    </View>
+  )
+}
+```
+
+#### 4. Jest配置规范
+每个UI包必须创建`jest.config.cjs`配置文件,参照`rencai-personal-info-ui/jest.config.cjs`:
+
+```javascript
+module.exports = {
+  preset: 'ts-jest',
+  testEnvironment: 'jsdom',
+  setupFilesAfterEnv: ['@d8d/mini-testing-utils/setup'],
+  moduleNameMapper: {
+    '^@/(.*)$': '<rootDir>/src/$1',
+    '^~/(.*)$': '<rootDir>/tests/$1',
+    '^@tarojs/taro$': '@d8d/mini-testing-utils/testing/taro-api-mock.ts',
+    '\\.(css|less|scss|sass)$': '@d8d/mini-testing-utils/testing/style-mock.js',
+    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
+      '@d8d/mini-testing-utils/testing/file-mock.js'
+  },
+  testMatch: [
+    '<rootDir>/tests/**/*.spec.{ts,tsx}',
+    '<rootDir>/tests/**/*.test.{ts,tsx}'
+  ],
+  collectCoverageFrom: [
+    'src/**/*.{ts,tsx}',
+    '!src/**/*.d.ts',
+    '!src/**/index.{ts,tsx}',
+    '!src/**/*.stories.{ts,tsx}'
+  ],
+  coverageDirectory: 'coverage',
+  coverageReporters: ['text', 'lcov', 'html'],
+  testPathIgnorePatterns: [
+    '/node_modules/',
+    '/dist/',
+    '/coverage/'
+  ],
+  transform: {
+    '^.+\\.(ts|tsx)$': 'ts-jest',
+    '^.+\\.(js|jsx)$': 'babel-jest'
+  },
+  transformIgnorePatterns: [
+    '/node_modules/(?!(swiper|@tarojs)/)'
+  ],
+  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json']
+}
+```
+
+### 原型设计参考
+
+**来源**: [docs/小程序原型/rencai.html](../小程序原型/rencai.html)
+
+**设置页** (原型行770-906):
+
+#### 1. 个人信息摘要
+```html
+<!-- 个人信息 -->
+<div class="p-4 border-b border-gray-200">
+  <div class="flex items-center mb-4">
+    <div class="w-16 h-16 rounded-full mr-4 bg-blue-500 flex items-center justify-center text-white text-xl font-bold">
+      张
+    </div>
+    <div>
+      <h3 class="font-semibold text-gray-800">张明</h3>
+      <p class="text-sm text-gray-500">肢体残疾 · 三级</p>
+    </div>
+  </div>
+  <div class="grid grid-cols-3 gap-3 text-center">
+    <div>
+      <p class="text-xl font-bold text-gray-800">28</p>
+      <p class="text-xs text-gray-500">本月出勤</p>
+    </div>
+    <div>
+      <p class="text-xl font-bold text-gray-800">156</p>
+      <p class="text-xs text-gray-500">累计出勤</p>
+    </div>
+    <div>
+      <p class="text-xl font-bold text-gray-800">¥4,800</p>
+      <p class="text-xs text-gray-500">本月薪资</p>
+    </div>
+  </div>
+</div>
+```
+
+**移动端设计规范**:
+- 圆形头像:64x64px (`w-16 h-16`),蓝色背景 (`bg-blue-500`)
+- 头像文字:白色,大号字体 (`text-xl font-bold`)
+- 3列统计:等宽网格 (`grid grid-cols-3 gap-3`)
+- 统计数字:大号加粗 (`text-xl font-bold`)
+- 统计标签:小号灰色 (`text-xs text-gray-500`)
+
+#### 2. 功能入口列表
+```html
+<!-- 功能列表 -->
+<div class="space-y-1 mb-6">
+  <div class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50">
+    <div class="flex items-center">
+      <div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
+        <i class="fas fa-user-edit text-blue-500"></i>
+      </div>
+      <span class="text-gray-700">修改个人信息</span>
+    </div>
+    <i class="fas fa-chevron-right text-gray-400"></i>
+  </div>
+  <div class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50">
+    <div class="flex items-center">
+      <div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center mr-3">
+        <i class="fas fa-shield-alt text-green-500"></i>
+      </div>
+      <span class="text-gray-700">账号与安全</span>
+    </div>
+    <i class="fas fa-chevron-right text-gray-400"></i>
+  </div>
+  <div class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50">
+    <div class="flex items-center">
+      <div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center mr-3">
+        <i class="fas fa-bell text-purple-500"></i>
+      </div>
+      <span class="text-gray-700">消息通知设置</span>
+    </div>
+    <i class="fas fa-chevron-right text-gray-400"></i>
+  </div>
+</div>
+```
+
+**移动端设计规范**:
+- 列表项间距:4px (`space-y-1`)
+- 列表项内边距:12px (`p-3`)
+- 圆角:8px (`rounded-lg`)
+- 圆形图标:40x40px (`w-10 h-10`)
+- 图标背景色:蓝/绿/紫
+- 右箭头:灰色 (`text-gray-400`)
+
+#### 3. 帮助与支持入口
+```html
+<!-- 帮助与支持 -->
+<div class="space-y-1 mb-6">
+  <div class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50">
+    <div class="flex items-center">
+      <div class="w-10 h-10 rounded-full bg-yellow-100 flex items-center justify-center mr-3">
+        <i class="fas fa-question-circle text-yellow-500"></i>
+      </div>
+      <span class="text-gray-700">帮助中心</span>
+    </div>
+    <i class="fas fa-chevron-right text-gray-400"></i>
+  </div>
+  <div class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50">
+    <div class="flex items-center">
+      <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center mr-3">
+        <i class="fas fa-file-alt text-indigo-500"></i>
+      </div>
+      <span class="text-gray-700">用户协议</span>
+    </div>
+    <i class="fas fa-chevron-right text-gray-400"></i>
+  </div>
+  <div class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50">
+    <div class="flex items-center">
+      <div class="w-10 h-10 rounded-full bg-pink-100 flex items-center justify-center mr-3">
+        <i class="fas fa-lock text-pink-500"></i>
+      </div>
+      <span class="text-gray-700">隐私政策</span>
+    </div>
+    <i class="fas fa-chevron-right text-gray-400"></i>
+  </div>
+</div>
+```
+
+**图标背景色**:
+- 帮助中心:黄色 (`bg-yellow-100 text-yellow-500`)
+- 用户协议:靛蓝 (`bg-indigo-100 text-indigo-500`)
+- 隐私政策:粉色 (`bg-pink-100 text-pink-500`)
+
+#### 4. 退出登录按钮
+```html
+<!-- 退出登录 -->
+<div class="space-y-1">
+  <div class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50">
+    <div class="flex items-center">
+      <div class="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center mr-3">
+        <i class="fas fa-sign-out-alt text-red-500"></i>
+      </div>
+      <span class="text-gray-700">退出登录</span>
+    </div>
+  </div>
+</div>
+```
+
+**退出登录样式**:
+- 图标背景:红色 (`bg-red-100 text-red-500`)
+
+### Navbar导航栏集成规范
+
+**来源**: [docs/stories/017.012.story.md](../stories/017.012.story.md)
+
+**TabBar页面规范(设置页属于此类):**
+- 使用`leftIcon=""`和`leftText=""`隐藏返回按钮
+- 参照yongren-dashboard-ui:139-148
+- Navbar组件来源: `@d8d/mini-shared-ui-components/components/navbar`
+
+**Navbar集成示例**:
+```typescript
+import { Navbar } from '@d8d/mini-shared-ui-components/components/navbar'
+import { View, ScrollView } from '@tarojs/components'
+
+export function SettingsPage() {
+  return (
+    <View className="h-screen bg-gray-100">
+      {/* Navbar导航栏 - TabBar页面无返回按钮 */}
+      <Navbar
+        title="设置"
+        leftIcon=""
+        leftText=""
+        onClickLeft={() => {}}
+        placeholder
+        fixed
+      />
+
+      {/* 页面内容 */}
+      <ScrollView scrollY className="h-full">
+        {/* 页面内容 */}
+      </ScrollView>
+    </View>
+  )
+}
+```
+
+**关键配置**:
+- `leftIcon=""`: 隐藏返回按钮图标
+- `leftText=""`: 隐藏返回按钮文字
+- `placeholder`: 添加占位空间,避免内容被Navbar遮挡
+- `fixed`: 固定在顶部
+
+### Taro小程序布局规范
+
+**重要**: 在Taro小程序中,`<View>` 组件内的子元素默认是**横向布局**(`flex-row`),需要显式添加 `flex flex-col` 类才能实现**垂直布局**。
+
+**正确示例**:
+```typescript
+// ✅ 正确: 使用 flex flex-col 实现垂直布局
+<View className="flex flex-col">
+  <Text>姓名: 张三</Text>
+  <Text>残疾类型: 肢体残疾 · 三级</Text>
+</View>
+
+// ❌ 错误: 缺少 flex flex-col,子元素会横向排列
+<View>
+  <Text>姓名: 张三</Text>
+  <Text>残疾类型: 肢体残疾 · 三级</Text>
+</View>
+```
+
+### 图标使用规范
+
+**来源**: [architecture/mini-ui-package-standards.md](../architecture/mini-ui-package-standards.md#图标使用规范)
+
+**重要**: **不要使用emoji**,必须使用Heroicons图标类。
+
+**图标类命名格式**: `i-heroicons-{图标名称}-{尺寸}-{样式}`
+
+**本故事需要的图标**:
+- `user-20-solid` - 修改个人信息(替代fas fa-user-edit)
+- `shield-check-20-solid` - 账号与安全(替代fas fa-shield-alt)
+- `bell-20-solid` - 消息通知设置
+- `question-mark-circle-20-solid` - 帮助中心(替代fas fa-question-circle)
+- `document-text-20-solid` - 用户协议(替代fas fa-file-alt)
+- `lock-closed-20-solid` - 隐私政策
+- `arrow-right-on-rectangle-20-solid` - 退出登录(替代fas fa-sign-out-alt)
+- `chevron-right-20-solid` - 右箭头
+
+**正确示例**:
+```typescript
+// ✅ 正确: 使用Heroicons图标类
+<View className="i-heroicons-user-20-solid w-5 h-5 text-blue-500" />
+
+// ❌ 错误: 使用emoji
+<Text>👤</Text>
+```
+
+**功能入口图标示例**:
+```typescript
+import { View } from '@tarojs/components'
+
+// 修改个人信息 - 蓝色
+<View className="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
+  <View className="i-heroicons-user-20-solid text-blue-500 w-5 h-5" />
+</View>
+
+// 账号与安全 - 绿色
+<View className="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center mr-3">
+  <View className="i-heroicons-shield-check-20-solid text-green-500 w-5 h-5" />
+</View>
+
+// 消息通知设置 - 紫色
+<View className="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center mr-3">
+  <View className="i-heroicons-bell-20-solid text-purple-500 w-5 h-5" />
+</View>
+```
+
+### 项目结构指南
+
+**来源**: [architecture/source-tree.md](../architecture/source-tree.md)
+
+**mini-talent项目结构**:
+```
+mini-talent/                   # 人才小程序项目
+├── src/
+│   ├── app.tsx                # 小程序入口
+│   ├── app.config.ts          # 小程序配置
+│   ├── app.css                # 全局样式
+│   ├── pages/                 # 页面目录
+│   │   ├── login/             # 登录页
+│   │   ├── index/             # 首页/个人主页
+│   │   ├── attendance/        # 考勤记录页
+│   │   ├── personal-info/     # 个人信息页
+│   │   ├── employment/        # 就业信息页
+│   │   └── settings/          # 设置页 (TabBar) - 本故事
+│   │       └── index.tsx
+├── package.json
+├── jest.config.js
+└── tsconfig.json
+```
+
+**mini-ui-packages目录结构**:
+```
+mini-ui-packages/
+├── rencai-settings-ui/        # 人才设置UI包
+│   ├── src/
+│   │   ├── api/
+│   │   │   ├── settingsClient.ts
+│   │   │   └── index.ts
+│   │   ├── pages/
+│   │   │   └── SettingsPage/
+│   │   │       ├── SettingsPage.tsx
+│   │   │       └── index.ts (可选)
+│   │   ├── components/        # UI组件
+│   │   │   ├── UserProfileSummary.tsx      # 个人信息摘要
+│   │   │   ├── MenuItem.tsx                 # 菜单项
+│   │   │   ├── MenuSection.tsx             # 菜单分组
+│   │   │   ├── LogoutButton.tsx            # 退出登录按钮
+│   │   │   └── LoginLogsList.tsx           # 登录日志列表(可选)
+│   │   ├── types/
+│   │   │   └── settings.ts     # 类型定义
+│   │   └── index.ts
+│   ├── tests/                 # 测试文件
+│   │   ├── pages/
+│   │   │   └── SettingsPage/
+│   │   │       └── SettingsPage.test.tsx
+│   │   └── components/
+│   │       ├── UserProfileSummary.test.tsx
+│   │       ├── MenuItem.test.tsx
+│   │       ├── LogoutButton.test.tsx
+│   │       └── LoginLogsList.test.tsx
+│   ├── package.json
+│   ├── jest.config.cjs
+│   └── tsconfig.json
+└── mini-shared-ui-components/ # 通用小程序UI组件
+    ├── src/
+    │   └── components/
+    │       ├── status-bar.tsx
+    │       ├── page-container.tsx
+    │       ├── navbar.tsx
+    │       └── tab-bar.tsx
+    └── ...
+```
+
+**mini-talent页面导入方式**:
+```typescript
+// mini-talent/src/pages/settings/index.tsx
+import SettingsPage from '@d8d/rencai-settings-ui/pages/SettingsPage/SettingsPage'
+import { AuthContextProvider, useAuth } from '@d8d/rencai-auth-ui/utils'
+
+function Settings() {
+  const { isLoggedIn } = useAuth()
+
+  // 未登录跳转到登录页
+  if (!isLoggedIn) {
+    Taro.navigateTo({ url: '/pages/login/index' })
+    return null
+  }
+
+  return <SettingsPage />
+}
+
+export default function SettingsIndex() {
+  return (
+    <AuthContextProvider>
+      <Settings />
+    </AuthContextProvider>
+  )
+}
+```
+
+### 测试策略
+
+**来源**: [architecture/testing-strategy.md](../architecture/testing-strategy.md)
+
+**测试框架:**
+- **Jest**: 30.2.0 (mini项目使用Jest,不是Vitest!)
+- **ts-jest**: 29.4.5 (TypeScript预处理器)
+- **@testing-library/react**: 16.3.0 (React组件测试)
+- **@d8d/mini-testing-utils**: workspace包 (Taro小程序测试工具)
+
+**测试文件位置**:
+```
+mini-ui-packages/<package-name>/
+└── tests/
+    ├── components/              # 组件测试
+    │   ├── UserProfileSummary.test.tsx
+    │   ├── MenuItem.test.tsx
+    │   ├── LogoutButton.test.tsx
+    │   └── LoginLogsList.test.tsx
+    └── pages/                   # 页面组件测试
+        └── SettingsPage/
+            └── SettingsPage.test.tsx
+```
+
+**测试要求:**
+1. 为每个页面组件编写Jest测试
+2. 测试React Query数据加载(使用真实的QueryClientProvider)
+3. 测试退出登录功能(使用useMutation)
+4. 测试个人信息摘要展示
+5. 测试功能入口列表显示
+6. 测试登录日志列表显示(如果实现)
+7. 验证mini-talent项目现有功能不受影响
+8. 运行`pnpm typecheck`确保类型检查通过
+
+**页面集成测试示例(使用真实React Query)**:
+```typescript
+import React from 'react'
+import { render, screen, waitFor } from '@testing-library/react'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import SettingsPage from '../pages/SettingsPage/SettingsPage'
+
+// Mock API client
+jest.mock('../../api', () => ({
+  apiClient: {
+    auth: {
+      logout: {
+        $post: jest.fn()
+      },
+      'login-logs': {
+        $get: jest.fn()
+      }
+    }
+  }
+}))
+
+const { apiClient } = require('../../api')
+
+const createTestQueryClient = () => new QueryClient({
+  defaultOptions: {
+    queries: { retry: false, staleTime: Infinity },
+    mutations: { retry: false }
+  }
+})
+
+const renderWithQueryClient = (component: React.ReactElement) => {
+  const queryClient = createTestQueryClient()
+  return render(
+    <QueryClientProvider client={queryClient}>
+      {component}
+    </QueryClientProvider>
+  )
+}
+
+describe('SettingsPage', () => {
+  beforeEach(() => {
+    jest.clearAllMocks()
+  })
+
+  it('应该显示个人信息摘要', async () => {
+    renderWithQueryClient(<SettingsPage />)
+
+    await waitFor(() => {
+      expect(screen.getByText('张明')).toBeInTheDocument()
+      expect(screen.getByText('肢体残疾 · 三级')).toBeInTheDocument()
+    })
+  })
+
+  it('应该显示功能入口列表', async () => {
+    renderWithQueryClient(<SettingsPage />)
+
+    expect(screen.getByText('修改个人信息')).toBeInTheDocument()
+    expect(screen.getByText('账号与安全')).toBeInTheDocument()
+    expect(screen.getByText('消息通知设置')).toBeInTheDocument()
+  })
+
+  it('应该成功退出登录', async () => {
+    apiClient.auth.logout.$post.mockResolvedValue({
+      ok: true,
+      json: async () => ({ message: '退出成功' })
+    })
+
+    renderWithQueryClient(<SettingsPage />)
+
+    const logoutButton = screen.getByText('退出登录')
+    logoutButton.click()
+
+    await waitFor(() => {
+      expect(apiClient.auth.logout.$post).toHaveBeenCalled()
+    })
+  })
+})
+```
+
+### 编码标准
+
+**来源**: [architecture/coding-standards.md](../architecture/coding-standards.md)
+
+**关键编码规范:**
+
+#### 1. 必须遵循Mini UI包开发规范
+开发Mini UI包时,**必须**参考并遵循[Mini UI包开发规范](../architecture/mini-ui-package-standards.md),该规范基于史诗011和017的经验总结。
+
+#### 2. 关键检查点 (基于史诗011和017经验)
+- **Taro布局规范**: View容器默认横向布局,必须添加`flex flex-col`实现垂直布局
+- **图标使用规范**: 必须使用Heroicons图标类,不要使用emoji
+- **测试框架选择**: **mini项目使用Jest**(不是Vitest)
+- **Navbar集成**: TabBar页面使用Navbar无返回按钮
+- **React Query**: 使用React Query管理服务端状态,不要使用useState + useEffect
+
+#### 3. 常见错误避免
+- ❌ 不要忘记添加 `flex flex-col` 实现垂直布局
+- ❌ 不要使用emoji代替Heroicons图标
+- ❌ 不要忘记为图标添加尺寸类(`w-5 h-5`、`text-lg`等)
+- ❌ 不要在Mini UI包内部导入中使用别名 (`@/`、`~/`等),必须使用相对路径
+- ❌ 不要忘记为TabBar页面隐藏返回按钮
+- ❌ 不要使用Vitest作为Mini项目的测试框架(应使用Jest)
+- ❌ 不要使用useState + useEffect手动管理服务端状态(应使用React Query)
+
+**路径使用示例**:
+```typescript
+// ✅ 正确: UI包内部使用相对路径
+import { UserProfileSummary } from '../../components/UserProfileSummary'
+import { MenuItem } from '../components/MenuItem'
+
+// ✅ 正确: 跨包导入使用workspace包名
+import { SharedComponent } from '@d8d/mini-shared-ui-components'
+
+// ❌ 错误: UI包内部使用别名
+import { UserProfileSummary } from '@/components/UserProfileSummary'
+import { MenuItem } from '@/components/MenuItem'
+```
+
+#### 4. 参考实现
+- **用人方设置UI包**: `mini-ui-packages/yongren-settings-ui` (如果存在)
+- **人才个人信息UI包**: `mini-ui-packages/rencai-personal-info-ui`
+  - 组件结构和测试参考
+  - Navbar集成参考
+
+### 技术约束
+
+1. **向后兼容**: 不影响现有mini-talent项目功能
+2. **类型安全**: 使用TypeScript严格模式,所有数据结构必须有类型定义
+3. **模块独立性**: 每个UI包独立管理自己的类型定义
+4. **测试覆盖**: 所有新增代码必须有测试覆盖
+5. **代码规范**: 遵循项目编码标准和Mini UI包开发规范
+6. **React Query**: 必须使用React Query管理服务端状态
+
+### 风险和缓解措施
+
+**主要风险:**
+1. **API延期风险**: 史诗015的帮助与支持API为P2延期功能,使用静态内容展示
+2. **退出登录状态同步**: 退出后需要确保所有相关状态被清除
+3. **UI组件复用风险**: rencai系列UI包可能与现有yongren系列UI包存在差异
+4. **登录日志分页**: 登录日志数据量可能较大,需要考虑分页加载
+
+**缓解措施:**
+1. **静态内容展示**: 帮助中心、用户协议、隐私政策使用静态内容展示,便于后续替换为API
+2. **完整状态清理**: 退出登录时清除React Query缓存、本地存储、用户状态
+3. **参考现有模式**: 参照yongren系列UI包的实现模式和架构
+4. **类型安全**: 使用TypeScript接口定义数据结构,确保类型一致性
+5. **测试驱动**: 编写完整的测试,确保功能正确性
+6. **React Query缓存**: 使用queryClient.clear()清除所有缓存
+
+## 变更日志
+
+| 日期 | 版本 | 描述 | 作者 |
+|------|------|------|------|
+| 2025-12-28 | 1.0 | 创建故事文档 | Bob (Scrum Master) |
+| 2025-12-28 | 1.1 | 状态更新为Approved | Bob (Scrum Master) |
+
+## 开发者记录
+
+*此部分由开发代理在实施过程中填写*
+
+### 使用的代理模型
+
+待填写
+
+### 调试日志引用
+
+待填写
+
+### 完成说明列表
+
+待填写
+
+### 文件列表
+
+待填写
+
+## QA结果
+
+*此部分由QA代理在审查完成后填写*