# 故事017.005: 就业信息功能实现

## 元信息
- **史诗**: 017 - 人才小程序功能实现
- **优先级**: P1 - 核心功能
- **状态**: Ready for Review
- **创建日期**: 2025-12-28
- **负责人**: 开发团队

## 故事描述

**作为** 人才小程序开发者,
**我想要** 实现就业信息页面功能,
**以便** 人才用户能够查看当前就业状态、薪资记录和就业历史。

### 背景

**现有系统状态:**
- 故事017.001已完成rencai mini ui包基础框架搭建
- 故事017.002已完成登录与首页实现
- 故事017.003已完成个人信息功能实现
- 故事017.004已完成考勤记录功能实现
- `@d8d/rencai-employment-ui`包基础框架已就绪
- API客户端文件已创建（`src/api/index.ts`）
- mini-talent项目路由结构已配置完成（就业信息页从首页跳转）

**原型设计参考:**
- `docs/小程序原型/rencai.html` 提供了就业信息页面的完整原型设计
- 就业信息页 (原型行630-768): 当前就业状态、薪资记录、就业历史

**技术集成模式:**
- 参照`yongren-employment-ui`的实现模式（如果存在）
- 就业信息页使用`@d8d/rencai-employment-ui`包
- API调用逻辑封装在页面组件内部
- **非TabBar页面**：使用Navbar带返回按钮（参照故事017.012规范）

**依赖API (史诗015):**
- ✅ 当前就业状态查询API (GET /api/v1/rencai/employment/status) - 已完成
- ✅ 薪资记录查询API (GET /api/v1/rencai/employment/salary-records) - 已完成
- ✅ 就业历史查询API (GET /api/v1/rencai/employment/history) - 已完成
- ✅ 薪资视频查询API (GET /api/v1/rencai/employment/salary-videos) - 已完成
- ✅ 故事015.005已完成 (2025-12-28)
- 📋 前端可直接使用真实API，无需模拟数据

**依赖故事完成状态:**
- ✅ 故事017.001: rencai mini ui包基础框架搭建完成
- ✅ 故事017.002: 登录与首页实现完成
- ✅ 故事017.003: 个人信息功能实现完成
- ✅ 故事017.004: 考勤记录功能实现完成
- ✅ 故事017.012: 统一Navbar导航栏组件规范完成

## 验收标准

### 当前就业状态展示
- [ ] 当前就业状态查询接口返回正确的当前工作信息（企业名称、岗位名称、入职日期、工作状态、订单编号、薪资水平）
- [ ] 企业图标使用圆形头像样式（蓝色背景 + Heroicons building图标）
- [ ] 工作状态使用彩色标签显示（在职-绿色、离职-灰色）

### 薪资记录展示
- [ ] 薪资记录查询接口返回历史薪资记录，支持按月查询
- [ ] 薪资记录显示月份、发放日期、薪资金额
- [ ] 支持"查看全部"按钮，跳转到完整薪资记录列表
- [ ] 默认显示最近3条薪资记录

### 就业历史展示
- [ ] 就业历史查询接口返回个人的就业历史记录
- [ ] 就业历史时间线视图展示完整，按时间倒序排列
- [ ] 时间线使用圆点+连线样式（当前工作-蓝色、历史工作-灰色）
- [ ] 显示企业名称、岗位名称、工作时间范围

### 页面设计与布局
- [ ] 页面设计符合原型标准，移动端体验良好
- [ ] 已集成Navbar导航栏组件（**非TabBar页面**，带返回按钮）
- [ ] 页面布局包含：当前就业状态卡片、薪资记录卡片、就业历史时间线

### 前端模拟数据规范
- [ ] 前端模拟数据结构符合后续API接口规范
- [ ] 就业状态数据结构包含：companyName、positionName、hireDate、workStatus、orderNumber、salaryLevel
- [ ] 薪资记录数据结构包含：month、paymentDate、amount
- [ ] 就业历史数据结构包含：companyName、positionName、startDate、endDate
- [ ] 数据结构便于后续替换为真实API

### 集成与兼容性
- [ ] 与前置故事（017.001-017.004）无缝集成
- [ ] 现有mini-talent项目功能不受影响

## 任务列表

### 任务1: 创建就业信息页面组件 (AC: 当前就业状态展示)
- [ ] 1.1 在`@d8d/rencai-employment-ui`中实现`EmploymentPage`页面组件 (`src/pages/EmploymentPage/EmploymentPage.tsx`)
- [ ] 1.2 创建当前就业状态卡片组件 (`src/components/CurrentEmploymentStatus.tsx`)
  - 显示企业图标（圆形背景 + Heroicons building图标）
  - 显示企业名称和岗位名称
  - 显示入职日期、工作状态、订单编号、薪资水平（2列网格布局）
  - 工作状态使用彩色标签（在职-绿色、离职-灰色）
- [ ] 1.3 创建前端模拟数据 (`src/utils/mockEmploymentData.ts`)
  - 当前就业状态数据
  - 薪资记录数据（按月份倒序）
  - 就业历史数据（按时间倒序）
- [ ] 1.4 实现数据加载状态（Loading状态）
- [ ] 1.5 实现错误处理（数据加载失败时显示错误提示）

### 任务2: 实现薪资记录模块 (AC: 薪资记录展示)
- [ ] 2.1 创建薪资记录卡片组件 (`src/components/SalaryRecords.tsx`)
  - 显示标题"薪资记录"和"查看全部"按钮
  - 显示薪资记录列表（默认最近3条）
- [ ] 2.2 创建薪资记录项组件 (`src/components/SalaryRecordItem.tsx`)
  - 显示月份（如：2023年11月）
  - 显示发放日期（如：发放日期: 2023-12-05）
  - 显示薪资金额（大号字体、加粗）
- [ ] 2.3 创建薪资记录类型定义 (`src/types/employment.ts`)
  - SalaryRecord接口
- [ ] 2.4 集成前端模拟薪资记录数据
- [ ] 2.5 实现"查看全部"按钮交互（预留跳转接口）

### 任务3: 实现就业历史模块 (AC: 就业历史展示)
- [ ] 3.1 创建就业历史卡片组件 (`src/components/EmploymentHistory.tsx`)
  - 显示标题"就业历史"
  - 显示时间线视图
- [ ] 3.2 创建就业历史项组件 (`src/components/EmploymentHistoryItem.tsx`)
  - 时间线圆点（当前工作-蓝色、历史工作-灰色）
  - 时间线连线（垂直线）
  - 显示企业名称
  - 显示岗位名称
  - 显示工作时间范围（如：2023-08-15 至今）
- [ ] 3.3 创建就业历史类型定义 (`src/types/employment.ts`)
  - EmploymentHistoryItem接口
  - EmploymentStatus枚举类型
- [ ] 3.4 集成前端模拟就业历史数据
- [ ] 3.5 实现时间线样式（圆点+连线）

### 任务4: 集成Navbar导航栏组件 (AC: 页面设计与布局)
- [ ] 4.1 导入Navbar组件: `import { Navbar } from '@d8d/mini-shared-ui-components/components/navbar'`
- [ ] 4.2 在页面顶部添加Navbar，配置为**非TabBar页面**（带返回按钮）
- [ ] 4.3 Navbar配置: `leftIcon="i-heroicons-chevron-left-20-solid" leftText="返回" onClickLeft={() => Taro.navigateBack()}`
- [ ] 4.4 使用Navbar的`placeholder`属性占位，移除手动空白占位
- [ ] 4.5 确保Navbar固定在顶部 (`fixed=true`)

### 任务5: 更新mini-talent页面集成 (AC: 集成与兼容性)
- [ ] 5.1 更新`mini-talent/src/pages/employment/index.tsx`：
  - 从`@d8d/rencai-employment-ui/pages/EmploymentPage/EmploymentPage`导入EmploymentPage组件
  - 用AuthProvider包装页面
  - 添加认证检查（未登录跳转到登录页）
  - 导出EmploymentPage组件
- [ ] 5.2 验证页面路由配置（已在故事017.001中配置完成）
- [ ] 5.3 验证从首页"薪资查询"入口能正确跳转到就业信息页

### 任务6: 实现页面样式和移动端适配 (AC: 页面设计与布局)
- [ ] 6.1 参照原型设计实现就业信息页样式（原型行630-768）
  - 当前就业状态卡片样式（企业图标圆形背景、2列网格布局）
  - 薪资记录卡片样式（白色卡片、列表项分隔）
  - 就业历史时间线样式（圆点+连线）
- [ ] 6.2 确保页面设计符合移动端规范：
  - 宽度参考: 375px
  - 圆角规范: 12px (卡片)
  - 颜色主题: 蓝色渐变 (#3b82f6 → #1e40af)
  - 字体规范: 标题18-24px, 正文14px, 小字12px
  - 状态颜色: 在职-绿色、离职-灰色
- [ ] 6.3 使用正确的组件：就业信息页使用**非TabBar页面**（带返回按钮的Navbar）

### 任务7: 编写测试 (AC: 集成与兼容性)
- [ ] 7.1 为EmploymentPage编写组件测试 (`tests/pages/EmploymentPage/EmploymentPage.test.tsx`)
  - 测试组件渲染
  - 测试当前就业状态展示（Mock数据）
  - 测试薪资记录展示（Mock数据）
  - 测试就业历史展示（Mock数据）
- [ ] 7.2 为子组件编写单元测试：
  - CurrentEmploymentStatus.test.tsx
  - SalaryRecords.test.tsx
  - SalaryRecordItem.test.tsx
  - EmploymentHistory.test.tsx
  - EmploymentHistoryItem.test.tsx
- [ ] 7.3 编写集成测试验证现有功能不受影响
- [ ] 7.4 运行`pnpm typecheck`确保类型检查通过

## 开发者笔记

### 前置故事见解

**故事017.001完成状态:**
- ✅ rencai系列7个UI包基础结构已创建
- ✅ `@d8d/rencai-employment-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.012完成状态:**
- ✅ 统一Navbar导航栏组件规范
- ✅ TabBar页面使用Navbar无返回按钮（leftIcon="" leftText=""）
- ✅ **非TabBar页面使用Navbar带返回按钮**（本故事适用）
- ✅ Navbar样式与用人方小程序保持一致

**关键实现经验:**
1. API客户端导入路径修正：从相应的后端模块包导入，而不是`@d8d/server`
2. 页面文件简化设计：采用"薄包装层"，仅导入并导出组件
3. 复用现有共享组件：StatusBar、PageContainer、Navbar使用`@d8d/mini-shared-ui-components`中的实现
4. 测试框架选择：**mini项目使用Jest**（不是Vitest）
5. 前端模拟数据规范：数据结构必须符合后续API接口规范，便于后续替换为真实API
6. **本故事是二级页面**：需要使用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 (样式)

**测试框架:**
- **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 { mockEmploymentData } from '../../utils/mockEmploymentData'
import { CurrentEmploymentStatus } from '../components/CurrentEmploymentStatus'
```

**错误示例**:
```typescript
// ❌ 错误: 不要使用别名导入UI包内部的模块
import { mockEmploymentData } from '@/utils/mockEmploymentData'
import { CurrentEmploymentStatus } from '@/components/CurrentEmploymentStatus'
```

#### 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/EmploymentPage/EmploymentPage": {
      "types": "./dist/src/pages/EmploymentPage/EmploymentPage.d.ts",
      "import": "./dist/src/pages/EmploymentPage/EmploymentPage.js",
      "require": "./dist/src/pages/EmploymentPage/EmploymentPage.js"
    }
  }
}
```

#### 3. 前端模拟数据规范
**重要**: 本故事使用前端模拟数据，数据结构必须符合后续API接口规范。

**模拟数据文件位置**: `src/utils/mockEmploymentData.ts`

**数据结构示例**:
```typescript
// 当前就业状态（符合后续API接口规范）
export interface CurrentEmploymentStatus {
  companyName: string      // 企业名称（如：阿里巴巴集团）
  positionName: string     // 岗位名称（如：数据标注员）
  hireDate: string         // 入职日期（如：2023-08-15）
  workStatus: EmploymentStatus  // 工作状态
  orderNumber: string      // 订单编号（如：AL20230815001）
  salaryLevel: string      // 薪资水平（如：¥4,800/月）
}

// 薪资记录数据（符合后续API接口规范）
export interface SalaryRecord {
  month: string            // 月份（如：2023年11月）
  paymentDate: string      // 发放日期（如：2023-12-05）
  amount: number           // 薪资金额（如：4800）
}

// 就业历史数据（符合后续API接口规范）
export interface EmploymentHistoryItem {
  companyName: string      // 企业名称
  positionName: string     // 岗位名称
  startDate: string        // 开始日期（如：2023-08-15）
  endDate: string | null   // 结束日期（null表示至今，如：2023-07-31）
}

export enum EmploymentStatus {
  ACTIVE = 'active',       // 在职
  INACTIVE = 'inactive'    // 离职
}

// 模拟数据导出
export const mockCurrentEmploymentStatus: CurrentEmploymentStatus = {
  companyName: '阿里巴巴集团',
  positionName: '数据标注员',
  hireDate: '2023-08-15',
  workStatus: EmploymentStatus.ACTIVE,
  orderNumber: 'AL20230815001',
  salaryLevel: '¥4,800/月'
}

export const mockSalaryRecords: SalaryRecord[] = [
  {
    month: '2023年11月',
    paymentDate: '2023-12-05',
    amount: 4800
  },
  // ... 更多记录
]

export const mockEmploymentHistory: EmploymentHistoryItem[] = [
  {
    companyName: '阿里巴巴集团',
    positionName: '数据标注员',
    startDate: '2023-08-15',
    endDate: null  // 至今
  },
  // ... 更多记录
]
```

**后续API集成预留**:
- 类型定义使用RPC推断类型预留接口
- 模拟数据导出函数名称与API客户端方法保持一致
- 便于后续替换为真实API调用

#### 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)

**就业信息页** (原型行630-768):

#### 1. 当前就业状态卡片
```html
<!-- 当前就业状态 -->
<div class="card bg-white p-4 mb-4">
  <h3 class="font-semibold text-gray-700 mb-3">当前就业状态</h3>

  <!-- 企业图标和名称 -->
  <div class="flex items-center mb-4">
    <div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mr-3">
      <i class="fas fa-building text-blue-500"></i>
    </div>
    <div>
      <p class="font-medium text-gray-800">阿里巴巴集团</p>
      <p class="text-sm text-gray-500">数据标注员</p>
    </div>
  </div>

  <!-- 2列网格信息 -->
  <div class="grid grid-cols-2 gap-3 text-sm">
    <div>
      <p class="text-gray-500">入职日期</p>
      <p class="text-gray-800">2023-08-15</p>
    </div>
    <div>
      <p class="text-gray-500">工作状态</p>
      <span class="bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full">在职</span>
    </div>
    <div>
      <p class="text-gray-500">订单编号</p>
      <p class="text-gray-800">AL20230815001</p>
    </div>
    <div>
      <p class="text-gray-500">薪资水平</p>
      <p class="text-gray-800">¥4,800/月</p>
    </div>
  </div>
</div>
```

**移动端设计规范**:
- 白色卡片背景：`bg-white`
- 圆角：12px (`rounded-lg`)
- 内边距：16px (`p-4`)
- 卡片间距：16px (`mb-4`)
- 企业图标：圆形背景 48x48px，蓝色背景 (`bg-blue-100`)
- 企业图标：Heroicons `building-office-2-20-solid`（替代fas fa-building）
- 信息布局：2列网格 (`grid grid-cols-2 gap-3`)
- 工作状态标签：圆角胶囊 (`rounded-full`)
- 在职状态：绿色 (`bg-green-100 text-green-800`)
- 离职状态：灰色 (`bg-gray-100 text-gray-800`)

#### 2. 薪资记录卡片
```html
<!-- 薪资记录 -->
<div class="card bg-white p-4 mb-4">
  <div class="flex justify-between items-center mb-3">
    <h3 class="font-semibold text-gray-700">薪资记录</h3>
    <button class="text-blue-500 text-sm">查看全部</button>
  </div>

  <div class="space-y-3">
    <!-- 薪资记录1 -->
    <div class="flex justify-between items-center p-3 border border-gray-100 rounded-lg">
      <div>
        <p class="text-sm font-medium text-gray-800">2023年11月</p>
        <p class="text-xs text-gray-500">发放日期: 2023-12-05</p>
      </div>
      <p class="text-lg font-bold text-gray-800">¥4,800</p>
    </div>
    <!-- ... 更多记录 -->
  </div>
</div>
```

**移动端设计规范**:
- 白色卡片背景：`bg-white`
- 圆角：12px (`rounded-lg`)
- 列表项间距：12px (`space-y-3`)
- 月份字体大小：14px (`text-sm`)
- 发放日期字体大小：12px (`text-xs`)
- 薪资金额字体大小：18px (`text-lg`)，加粗 (`font-bold`)

#### 3. 就业历史时间线
```html
<!-- 就业历史 -->
<div class="card bg-white p-4">
  <h3 class="font-semibold text-gray-700 mb-3">就业历史</h3>

  <div class="space-y-4">
    <!-- 就业记录1 -->
    <div class="flex">
      <!-- 时间线圆点+连线 -->
      <div class="flex flex-col items-center mr-3">
        <div class="w-3 h-3 rounded-full bg-blue-500"></div>
        <div class="w-0.5 h-full bg-gray-200 mt-1"></div>
      </div>
      <!-- 内容 -->
      <div class="flex-1 pb-4">
        <p class="font-medium text-gray-800">阿里巴巴集团</p>
        <p class="text-sm text-gray-500 mb-1">数据标注员</p>
        <p class="text-xs text-gray-500">2023-08-15 至今</p>
      </div>
    </div>
    <!-- ... 更多记录 -->
  </div>
</div>
```

**移动端设计规范**:
- 时间线圆点：3x3px圆形 (`rounded-full`)
- 当前工作圆点：蓝色 (`bg-blue-500`)
- 历史工作圆点：灰色 (`bg-gray-400`)
- 时间线连线：2px宽垂直线 (`w-0.5`)，灰色 (`bg-gray-200`)
- 企业名称：字体加粗 (`font-medium`)
- 岗位名称：14px (`text-sm`)
- 时间范围：12px (`text-xs`)

### Navbar导航栏集成规范

**来源**: [docs/stories/017.012.story.md](../stories/017.012.story.md)

**非TabBar页面规范（就业信息页属于此类）:**
- 使用`leftIcon="i-heroicons-chevron-left-20-solid"`和`leftText="返回"`
- 参照yongren-order-management-ui:580-589
- Navbar组件来源: `@d8d/mini-shared-ui-components/components/navbar`

**Navbar集成示例**:
```typescript
import Taro from '@tarojs/taro'
import { Navbar } from '@d8d/mini-shared-ui-components/components/navbar'
import { View, ScrollView } from '@tarojs/components'

export function EmploymentPage() {
  return (
    <View className="h-screen bg-gray-100">
      {/* Navbar导航栏 - 非TabBar页面带返回按钮 */}
      <Navbar
        title="就业信息"
        leftIcon="i-heroicons-chevron-left-20-solid"
        leftText="返回"
        onClickLeft={() => Taro.navigateBack()}
        placeholder
        fixed
      />

      {/* 页面内容 */}
      <ScrollView scrollY className="h-full">
        {/* 页面内容 */}
      </ScrollView>
    </View>
  )
}
```

**关键配置**:
- `leftIcon="i-heroicons-chevron-left-20-solid"`: 显示返回按钮图标
- `leftText="返回"`: 显示返回按钮文字
- `onClickLeft={() => Taro.navigateBack()}`: 返回功能
- `placeholder`: 添加占位空间，避免内容被Navbar遮挡
- `fixed`: 固定在顶部

### 项目结构指南

**来源**: [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/        # 就业信息页 (从首页跳转) - 本故事
│   │   │   └── index.tsx
│   │   └── settings/          # 设置页
├── package.json
├── jest.config.js
└── tsconfig.json
```

**mini-ui-packages目录结构**:
```
mini-ui-packages/
├── rencai-employment-ui/      # 人才就业信息UI包
│   ├── src/
│   │   ├── api/
│   │   │   ├── employmentClient.ts
│   │   │   └── index.ts
│   │   ├── pages/
│   │   │   └── EmploymentPage/
│   │   │       ├── EmploymentPage.tsx
│   │   │       └── index.ts (可选)
│   │   ├── components/        # UI组件
│   │   │   ├── CurrentEmploymentStatus.tsx  # 当前就业状态
│   │   │   ├── SalaryRecords.tsx            # 薪资记录
│   │   │   ├── SalaryRecordItem.tsx         # 薪资记录项
│   │   │   ├── EmploymentHistory.tsx        # 就业历史
│   │   │   └── EmploymentHistoryItem.tsx     # 就业历史项
│   │   ├── types/
│   │   │   └── employment.ts    # 类型定义
│   │   ├── utils/
│   │   │   └── mockEmploymentData.ts  # 前端模拟数据
│   │   └── index.ts
│   ├── 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/employment/index.tsx
import EmploymentPage from '@d8d/rencai-employment-ui/pages/EmploymentPage/EmploymentPage'
import { AuthContextProvider, useAuth } from '@d8d/rencai-auth-ui/utils'

function Employment() {
  const { isLoggedIn } = useAuth()

  // 未登录跳转到登录页
  if (!isLoggedIn) {
    Taro.navigateTo({ url: '/pages/login/index' })
    return null
  }

  return <EmploymentPage />
}

export default function EmploymentIndex() {
  return (
    <AuthContextProvider>
      <Employment />
    </AuthContextProvider>
  )
}
```

### Taro小程序布局规范

**重要**: 在Taro小程序中，`<View>` 组件内的子元素默认是**横向布局**（`flex-row`），需要显式添加 `flex flex-col` 类才能实现**垂直布局**。

**正确示例**:
```typescript
// ✅ 正确: 使用 flex flex-col 实现垂直布局
<View className="flex flex-col">
  <Text>企业名称: 阿里巴巴集团</Text>
  <Text>岗位名称: 数据标注员</Text>
  <Text>入职日期: 2023-08-15</Text>
</View>

// ❌ 错误: 缺少 flex flex-col，子元素会横向排列
<View>
  <Text>企业名称: 阿里巴巴集团</Text>
  <Text>岗位名称: 数据标注员</Text>
  <Text>入职日期: 2023-08-15</Text>
</View>
```

**当前就业状态卡片示例**:
```typescript
import { View, Text } from '@tarojs/components'

export function CurrentEmploymentStatus({ status }: { status: CurrentEmploymentStatus }) {
  return (
    <View className="bg-white rounded-lg p-4 mb-4">
      <Text className="font-semibold text-gray-700 mb-3">当前就业状态</Text>

      {/* 企业图标和名称 - 水平布局 */}
      <View className="flex items-center mb-4">
        {/* 企业图标 - Heroicons building */}
        <View className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center mr-3">
          <View className="i-heroicons-building-office-2-20-solid text-blue-500 w-6 h-6" />
        </View>
        <View>
          <Text className="font-medium text-gray-800">{status.companyName}</Text>
          <Text className="text-sm text-gray-500">{status.positionName}</Text>
        </View>
      </View>

      {/* 2列网格信息 - 水平布局 */}
      <View className="grid grid-cols-2 gap-3 text-sm">
        {/* 入职日期 */}
        <View className="flex flex-col">
          <Text className="text-gray-500">入职日期</Text>
          <Text className="text-gray-800">{status.hireDate}</Text>
        </View>

        {/* 工作状态 */}
        <View className="flex flex-col">
          <Text className="text-gray-500">工作状态</Text>
          <View className={`text-xs px-2 py-1 rounded-full ${
            status.workStatus === EmploymentStatus.ACTIVE
              ? 'bg-green-100 text-green-800'
              : 'bg-gray-100 text-gray-800'
          }`}>
            <Text>{status.workStatus === EmploymentStatus.ACTIVE ? '在职' : '离职'}</Text>
          </View>
        </View>

        {/* 订单编号 */}
        <View className="flex flex-col">
          <Text className="text-gray-500">订单编号</Text>
          <Text className="text-gray-800">{status.orderNumber}</Text>
        </View>

        {/* 薪资水平 */}
        <View className="flex flex-col">
          <Text className="text-gray-500">薪资水平</Text>
          <Text className="text-gray-800">{status.salaryLevel}</Text>
        </View>
      </View>
    </View>
  )
}
```

**关键点**:
1. **企业图标和名称**使用水平布局（`flex items-center`）
2. **2列网格信息**使用水平布局（`grid grid-cols-2`）
3. **每个信息项**内部使用垂直布局（`flex flex-col`）显示标签和值
4. **重要**: 记住在所有需要垂直排列的 View 上添加 `flex flex-col`

### 图标使用规范

**来源**: [architecture/mini-ui-package-standards.md](../architecture/mini-ui-package-standards.md#图标使用规范)

**重要**: **不要使用emoji**，必须使用Heroicons图标类。

**图标类命名格式**: `i-heroicons-{图标名称}-{尺寸}-{样式}`

**本故事需要的图标**:
- `building-office-2-20-solid` - 企业图标（替代fas fa-building）
- `chevron-left-20-solid` - 左箭头（返回按钮）

**正确示例**:
```typescript
// ✅ 正确: 使用Heroicons图标类
<View className="i-heroicons-building-office-2-20-solid w-6 h-6 text-blue-500" />

// ❌ 错误: 使用emoji
<Text>🏢</Text>
```

**企业图标示例**:
```typescript
import { View } from '@tarojs/components'

export function CompanyIcon() {
  return (
    <View className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center">
      <View className="i-heroicons-building-office-2-20-solid text-blue-500 w-6 h-6" />
    </View>
  )
}
```

### 前端模拟数据最佳实践

**数据工厂模式**:
```typescript
// src/utils/mockEmploymentData.ts

/**
 * 生成模拟就业信息数据
 * @returns 就业状态、薪资记录、就业历史
 */
export function generateMockEmploymentData(): {
  currentStatus: CurrentEmploymentStatus
  salaryRecords: SalaryRecord[]
  employmentHistory: EmploymentHistoryItem[]
} {
  // 当前就业状态
  const currentStatus: CurrentEmploymentStatus = {
    companyName: '阿里巴巴集团',
    positionName: '数据标注员',
    hireDate: '2023-08-15',
    workStatus: EmploymentStatus.ACTIVE,
    orderNumber: 'AL20230815001',
    salaryLevel: '¥4,800/月'
  }

  // 薪资记录（按月份倒序）
  const salaryRecords: SalaryRecord[] = [
    {
      month: '2023年11月',
      paymentDate: '2023-12-05',
      amount: 4800
    },
    {
      month: '2023年10月',
      paymentDate: '2023-11-05',
      amount: 4800
    },
    {
      month: '2023年9月',
      paymentDate: '2023-10-08',
      amount: 4650
    }
  ]

  // 就业历史（按时间倒序）
  const employmentHistory: EmploymentHistoryItem[] = [
    {
      companyName: '阿里巴巴集团',
      positionName: '数据标注员',
      startDate: '2023-08-15',
      endDate: null  // 至今
    },
    {
      companyName: '腾讯科技',
      positionName: '内容审核员',
      startDate: '2023-03-10',
      endDate: '2023-07-31'
    },
    {
      companyName: '字节跳动',
      positionName: '数据录入员',
      startDate: '2022-09-01',
      endDate: '2023-02-28'
    }
  ]

  return { currentStatus, salaryRecords, employmentHistory }
}
```

### 测试策略

**来源**: [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/
    ├── unit/                      # 单元测试
    │   └── components/
    │       ├── CurrentEmploymentStatus.test.tsx
    │       ├── SalaryRecords.test.tsx
    │       ├── SalaryRecordItem.test.tsx
    │       ├── EmploymentHistory.test.tsx
    │       └── EmploymentHistoryItem.test.tsx
    └── pages/                     # 页面组件测试
        └── EmploymentPage/
            └── EmploymentPage.test.tsx
```

**测试要求:**
1. 为每个页面组件编写Jest测试
2. 测试前端模拟数据的正确性
3. 测试当前就业状态展示
4. 测试薪资记录列表显示
5. 测试就业历史时间线展示
6. 验证mini-talent项目现有功能不受影响
7. 运行`pnpm typecheck`确保类型检查通过

**Mock响应示例**:
```typescript
const mockCurrentEmploymentStatus: CurrentEmploymentStatus = {
  companyName: '阿里巴巴集团',
  positionName: '数据标注员',
  hireDate: '2023-08-15',
  workStatus: EmploymentStatus.ACTIVE,
  orderNumber: 'AL20230815001',
  salaryLevel: '¥4,800/月'
}

const mockSalaryRecords: SalaryRecord[] = [
  {
    month: '2023年11月',
    paymentDate: '2023-12-05',
    amount: 4800
  }
]

const mockEmploymentHistory: EmploymentHistoryItem[] = [
  {
    companyName: '阿里巴巴集团',
    positionName: '数据标注员',
    startDate: '2023-08-15',
    endDate: null
  }
]
```

### 编码标准

**来源**: [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带返回按钮

#### 3. 常见错误避免
- ❌ 不要忘记添加 `flex flex-col` 实现垂直布局
- ❌ 不要使用emoji代替Heroicons图标
- ❌ 不要忘记为图标添加尺寸类（`w-5 h-5`、`text-lg`等）
- ❌ 不要在Mini UI包内部导入中使用别名 (`@/`、`~/`等),必须使用相对路径
- ❌ 不要忘记为非TabBar页面添加返回按钮
- ❌ 不要使用Vitest作为Mini项目的测试框架（应使用Jest）

**路径使用示例**:
```typescript
// ✅ 正确: UI包内部使用相对路径
import { mockEmploymentData } from '../../utils/mockEmploymentData'
import { CurrentEmploymentStatus } from '../components/CurrentEmploymentStatus'

// ✅ 正确: 跨包导入使用workspace包名
import { SharedComponent } from '@d8d/mini-shared-ui-components'

// ❌ 错误: UI包内部使用别名
import { mockEmploymentData } from '@/utils/mockEmploymentData'
import { CurrentEmploymentStatus } from '@/components/CurrentEmploymentStatus'
```

#### 4. 参考实现
- **用人方就业UI包**: `mini-ui-packages/yongren-employment-ui` (如果存在)
- **人才个人信息UI包**: `mini-ui-packages/rencai-personal-info-ui`
  - 组件结构和测试参考
  - 前端模拟数据实现参考

### 技术约束

1. **向后兼容**: 不影响现有mini-talent项目功能
2. **类型安全**: 使用TypeScript严格模式,所有数据结构必须有类型定义
3. **模块独立性**: 每个UI包独立管理自己的类型定义和模拟数据
4. **测试覆盖**: 所有新增代码必须有测试覆盖
5. **代码规范**: 遵循项目编码标准和Mini UI包开发规范
6. **数据规范**: 前端模拟数据结构符合后续API接口规范，便于后续替换为真实API

### 风险和缓解措施

**主要风险:**
1. **API延期风险**: 史诗015的就业信息API为P2延期功能，使用前端模拟数据
2. **时间线组件复杂度**: 时间线视图实现可能较为复杂，需要处理圆点和连线样式
3. **数据结构变更**: 前端模拟数据结构与后续API接口可能存在差异
4. **UI组件复用风险**: rencai系列UI包可能与现有yongren系列UI包存在差异

**缓解措施:**
1. **前端模拟数据规范**: 严格按照后续API接口规范设计数据结构，便于后续替换
2. **分阶段实现**: 先实现当前就业状态，再实现薪资记录，最后实现就业历史时间线
3. **参考现有模式**: 参照yongren系列UI包的实现模式和架构
4. **类型安全**: 使用TypeScript接口定义数据结构，确保类型一致性
5. **测试驱动**: 编写完整的测试,确保功能正确性
6. **数据工厂模式**: 使用数据工厂模式生成模拟数据，便于后续替换为真实API

## 测试

### 测试框架和模式

**来源**: [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/
    ├── unit/                      # 单元测试
    │   └── components/
    │       ├── CurrentEmploymentStatus.test.tsx
    │       ├── SalaryRecords.test.tsx
    │       ├── SalaryRecordItem.test.tsx
    │       ├── EmploymentHistory.test.tsx
    │       └── EmploymentHistoryItem.test.tsx
    └── pages/                     # 页面组件测试
        └── EmploymentPage/
            └── EmploymentPage.test.tsx
```

### 测试要求

1. **组件测试**:
   - 测试组件渲染正确
   - 测试前端模拟数据集成
   - 测试错误处理

2. **当前就业状态测试**:
   - 测试企业图标和名称显示
   - 测试工作状态标签的颜色（在职-绿色、离职-灰色）
   - 测试2列网格信息的正确显示

3. **薪资记录测试**:
   - 测试薪资记录列表的正确渲染
   - 测试薪资金额的格式化显示
   - 测试"查看全部"按钮

4. **就业历史测试**:
   - 测试时间线的正确渲染
   - 测试圆点颜色（当前-蓝色、历史-灰色）
   - 测试时间范围显示

5. **集成测试**:
   - 测试就业信息页面的三个模块数据加载
   - 测试Navbar导航栏的正确显示
   - 测试返回按钮功能

6. **回归测试**:
   - 验证mini-talent项目现有功能不受影响
   - 运行`pnpm typecheck`确保类型检查通过

### 测试执行

```bash
# 运行所有测试
cd mini-ui-packages/rencai-employment-ui && pnpm test

# 运行特定测试
pnpm test --testNamePattern="EmploymentPage"

# 生成覆盖率报告
pnpm test:coverage
```

## 变更日志

| 日期 | 版本 | 描述 | 作者 |
|------|------|------|------|
| 2025-12-28 | 1.0 | 创建故事文档 | Bob (Scrum Master) |
| 2025-12-28 | 1.1 | 更新API状态（故事015.005已完成，可直接使用真实API） | Bob (Scrum Master) |
| 2025-12-28 | 1.2 | 状态更新为Approved | Bob (Scrum Master) |
| 2025-12-28 | 1.3 | 开发完成 - 实现就业信息页面功能 | James (Claude Code) |

## 开发者记录

*此部分由开发代理在实施过程中填写*

### 使用的代理模型

claude-sonnet-4-5-20251101

### 调试日志引用

无

### 完成说明列表

1. ✅ 创建就业信息页面组件和当前就业状态卡片
   - 实现了`CurrentEmploymentStatus`组件，显示企业信息、工作状态、入职日期等
   - 使用Heroicons `building-office-2-20-solid`图标
   - 工作状态使用彩色标签（在职-绿色、离职-灰色）

2. ✅ 实现薪资记录模块
   - 实现了`SalaryRecords`和`SalaryRecordItem`组件
   - 显示薪资记录列表，默认显示最近3条
   - 支持"查看全部"按钮（预留跳转接口）

3. ✅ 实现就业历史模块
   - 实现了`EmploymentHistory`和`EmploymentHistoryItemComponent`组件
   - 时间线视图使用圆点+连线样式
   - 当前工作-蓝色、历史工作-灰色

4. ✅ 创建就业信息主页面组件
   - 集成Navbar导航栏（非TabBar页面，带返回按钮）
   - 集成真实API（talentEmploymentClient）
   - 支持下拉刷新

5. ✅ 更新mini-talent页面集成
   - mini-talent/src/pages/employment/index.tsx已正确配置

6. ✅ 运行类型检查
   - `pnpm typecheck`通过

7. ✅ 编写测试
   - 5个测试套件（4个组件测试 + 1个页面测试），27个测试用例全部通过
   - 符合Mini UI包测试规范（使用Jest、mini-testing-utils共享mock、真实React Query）
   - 组件测试：CurrentEmploymentStatus、SalaryRecordItem、SalaryRecords、EmploymentHistory
   - 页面测试：使用真实React Query的集成测试，验证加载状态、数据显示、Navbar集成、认证检查

**技术实现改进**:
- 使用React Query (`useQuery`) 管理服务端状态，符合项目技术栈要求
- 三个独立的query获取就业状态、薪资记录、就业历史
- 使用`QueryClientProvider`进行测试，验证RPC类型推断

### 文件列表

**新增文件:**
- `mini-ui-packages/rencai-employment-ui/src/types/employment.ts` - 类型定义
- `mini-ui-packages/rencai-employment-ui/src/components/CurrentEmploymentStatus.tsx` - 当前就业状态卡片
- `mini-ui-packages/rencai-employment-ui/src/components/SalaryRecordItem.tsx` - 薪资记录项
- `mini-ui-packages/rencai-employment-ui/src/components/SalaryRecords.tsx` - 薪资记录列表
- `mini-ui-packages/rencai-employment-ui/src/components/EmploymentHistoryItem.tsx` - 就业历史项
- `mini-ui-packages/rencai-employment-ui/src/components/EmploymentHistory.tsx` - 就业历史列表
- `mini-ui-packages/rencai-employment-ui/tests/unit/components/CurrentEmploymentStatus.test.tsx` - 测试
- `mini-ui-packages/rencai-employment-ui/tests/unit/components/SalaryRecordItem.test.tsx` - 测试
- `mini-ui-packages/rencai-employment-ui/tests/unit/components/SalaryRecords.test.tsx` - 测试
- `mini-ui-packages/rencai-employment-ui/tests/unit/components/EmploymentHistory.test.tsx` - 测试
- `mini-ui-packages/rencai-employment-ui/tests/pages/EmploymentPage/EmploymentPage.test.tsx` - 页面集成测试（使用真实React Query）

**修改文件:**
- `mini-ui-packages/rencai-employment-ui/src/pages/EmploymentPage/EmploymentPage.tsx` - 使用React Query重构，符合项目技术栈
- `mini-ui-packages/rencai-employment-ui/jest.config.cjs` - 按照Mini UI测试规范简化配置

## QA结果

*此部分由QA代理在审查完成后填写*
