|
@@ -0,0 +1,258 @@
|
|
|
|
|
+# Story 007.005: 首页目的地默认值配置
|
|
|
|
|
+
|
|
|
|
|
+## Status
|
|
|
|
|
+Draft
|
|
|
|
|
+
|
|
|
|
|
+## Story
|
|
|
|
|
+**As a** 小程序用户,
|
|
|
|
|
+**I want** 首页自动使用配置的默认省市区名称作为出发地和目的地,
|
|
|
|
|
+**so that** 能够快速开始查询路线,无需手动选择地区。
|
|
|
|
|
+
|
|
|
|
|
+## Acceptance Criteria
|
|
|
|
|
+1. 在环境变量中添加默认目的地配置
|
|
|
|
|
+2. 首页自动使用配置的默认省市区名称
|
|
|
|
|
+3. 支持开发环境和正式环境不同配置
|
|
|
|
|
+4. 验证默认目的地功能正常工作
|
|
|
|
|
+
|
|
|
|
|
+## Tasks / Subtasks
|
|
|
|
|
+- [ ] 在环境变量中添加默认目的地配置 (AC: 1)
|
|
|
|
|
+ - [ ] 在 `mini/.env.development` 中添加开发环境默认目的地配置
|
|
|
|
|
+ - [ ] 在 `mini/.env.production` 中添加生产环境默认目的地配置
|
|
|
|
|
+ - [ ] 配置默认省市区ID的环境变量(只需要配置ID,名称通过API获取)
|
|
|
|
|
+- [ ] 更新全局类型定义 (AC: 1)
|
|
|
|
|
+ - [ ] 更新 `mini/types/global.d.ts` 文件,添加新的环境变量类型定义
|
|
|
|
|
+ - [ ] 确保TypeScript类型检查能够识别新的环境变量
|
|
|
|
|
+- [ ] 修改首页组件使用默认目的地 (AC: 2)
|
|
|
|
|
+ - [ ] 修改 `mini/src/pages/home/index.tsx` 中的初始状态设置
|
|
|
|
|
+ - [ ] 实现从环境变量读取默认目的地配置的逻辑
|
|
|
|
|
+ - [ ] 确保默认目的地正确显示在出发地和目的地选择按钮上
|
|
|
|
|
+- [ ] 实现环境变量配置验证 (AC: 3)
|
|
|
|
|
+ - [ ] 添加配置验证逻辑,确保环境变量格式正确
|
|
|
|
|
+ - [ ] 实现开发环境和生产环境配置分离
|
|
|
|
|
+ - [ ] 添加配置缺失时的降级处理
|
|
|
|
|
+- [ ] 编写和更新相关测试 (AC: 4)
|
|
|
|
|
+ - [ ] 更新首页测试文件 `mini/tests/pages/home.test.tsx`
|
|
|
|
|
+ - [ ] 添加默认目的地配置的测试场景
|
|
|
|
|
+ - [ ] 验证默认目的地功能在各种环境下的正确性
|
|
|
|
|
+ - [ ] 确保现有功能无回归
|
|
|
|
|
+
|
|
|
|
|
+## Dev Notes
|
|
|
|
|
+
|
|
|
|
|
+### 技术栈要求
|
|
|
|
|
+- **前端框架**: Taro 4.x + React [Source: architecture/tech-stack.md#现有技术栈维护]
|
|
|
|
|
+- **小程序平台**: 微信小程序 [Source: architecture/tech-stack.md#现有技术栈维护]
|
|
|
|
|
+- **状态管理**: React Query (TanStack Query) [Source: architecture/tech-stack.md#现有技术栈维护]
|
|
|
|
|
+- **UI组件**: 自定义组件 + Heroicons [Source: architecture/tech-stack.md#现有技术栈维护]
|
|
|
|
|
+
|
|
|
|
|
+### 项目结构
|
|
|
|
|
+- **首页位置**: `mini/src/pages/home/index.tsx` [Source: architecture/source-tree.md#实际项目结构]
|
|
|
|
|
+- **环境变量文件**: `mini/.env.development`, `mini/.env.production` [Source: architecture/source-tree.md#实际项目结构]
|
|
|
|
|
+- **全局类型定义**: `mini/types/global.d.ts` [Source: architecture/source-tree.md#实际项目结构]
|
|
|
|
|
+- **测试文件位置**: `mini/tests/pages/home.test.tsx` [Source: architecture/testing-strategy.md#taro小程序测试体系]
|
|
|
|
|
+- **地区选择组件**: `mini/src/components/AreaPicker.tsx` [Source: architecture/source-tree.md#实际项目结构]
|
|
|
|
|
+
|
|
|
|
|
+### 现有实现分析
|
|
|
|
|
+基于对 `mini/src/pages/home/index.tsx` 的分析:
|
|
|
|
|
+- 当前首页使用空的初始状态:`startAreaIds` 和 `endAreaIds` 为 undefined
|
|
|
|
|
+- 地区选择通过 `AreaPicker` 组件实现,支持省市区三级选择
|
|
|
|
|
+- 地区数据通过 React Query 从后端 API 获取
|
|
|
|
|
+- 地区显示文本通过 `getAreaDisplayText` 函数生成
|
|
|
|
|
+
|
|
|
|
|
+### 环境变量配置方案
|
|
|
|
|
+只需要配置地区ID,地区名称可以通过ID从后端API动态获取:
|
|
|
|
|
+- `TARO_APP_DEFAULT_START_PROVINCE_ID` - 默认出发省份ID
|
|
|
|
|
+- `TARO_APP_DEFAULT_START_CITY_ID` - 默认出发城市ID
|
|
|
|
|
+- `TARO_APP_DEFAULT_START_DISTRICT_ID` - 默认出发区县ID
|
|
|
|
|
+- `TARO_APP_DEFAULT_END_PROVINCE_ID` - 默认目的省份ID
|
|
|
|
|
+- `TARO_APP_DEFAULT_END_CITY_ID` - 默认目的城市ID
|
|
|
|
|
+- `TARO_APP_DEFAULT_END_DISTRICT_ID` - 默认目的区县ID
|
|
|
|
|
+
|
|
|
|
|
+**理由**:
|
|
|
|
|
+- 地区名称可以通过ID从后端API动态获取,确保名称始终最新
|
|
|
|
|
+- 减少环境变量的配置复杂度
|
|
|
|
|
+- 符合现有代码的实现模式(通过ID查找名称)
|
|
|
|
|
+
|
|
|
|
|
+### 全局类型定义更新
|
|
|
|
|
+需要在 `mini/types/global.d.ts` 文件的 `ProcessEnv` 接口中添加新的环境变量类型定义:
|
|
|
|
|
+```typescript
|
|
|
|
|
+declare namespace NodeJS {
|
|
|
|
|
+ interface ProcessEnv {
|
|
|
|
|
+ // 现有环境变量...
|
|
|
|
|
+
|
|
|
|
|
+ // 默认目的地配置(只需要配置ID)
|
|
|
|
|
+ TARO_APP_DEFAULT_START_PROVINCE_ID?: string
|
|
|
|
|
+ TARO_APP_DEFAULT_START_CITY_ID?: string
|
|
|
|
|
+ TARO_APP_DEFAULT_START_DISTRICT_ID?: string
|
|
|
|
|
+ TARO_APP_DEFAULT_END_PROVINCE_ID?: string
|
|
|
|
|
+ TARO_APP_DEFAULT_END_CITY_ID?: string
|
|
|
|
|
+ TARO_APP_DEFAULT_END_DISTRICT_ID?: string
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+注意:使用可选属性(`?`)表示这些环境变量可能未配置。
|
|
|
|
|
+
|
|
|
|
|
+### 实现细节
|
|
|
|
|
+
|
|
|
|
|
+#### 初始状态设置
|
|
|
|
|
+需要修改首页第27-31行的初始状态设置:
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 当前代码
|
|
|
|
|
+const [searchParams, setSearchParams] = useState<SearchParams>({
|
|
|
|
|
+ date: new Date().toISOString().split('T')[0],
|
|
|
|
|
+ vehicleType: 'bus',
|
|
|
|
|
+ travelMode: 'carpool'
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 修改后逻辑
|
|
|
|
|
+const [searchParams, setSearchParams] = useState<SearchParams>(() => {
|
|
|
|
|
+ const defaultStartIds = process.env.TARO_APP_DEFAULT_START_PROVINCE_ID ? [
|
|
|
|
|
+ Number(process.env.TARO_APP_DEFAULT_START_PROVINCE_ID),
|
|
|
|
|
+ Number(process.env.TARO_APP_DEFAULT_START_CITY_ID),
|
|
|
|
|
+ Number(process.env.TARO_APP_DEFAULT_START_DISTRICT_ID)
|
|
|
|
|
+ ].filter(id => id) : undefined
|
|
|
|
|
+
|
|
|
|
|
+ const defaultEndIds = process.env.TARO_APP_DEFAULT_END_PROVINCE_ID ? [
|
|
|
|
|
+ Number(process.env.TARO_APP_DEFAULT_END_PROVINCE_ID),
|
|
|
|
|
+ Number(process.env.TARO_APP_DEFAULT_END_CITY_ID),
|
|
|
|
|
+ Number(process.env.TARO_APP_DEFAULT_END_DISTRICT_ID)
|
|
|
|
|
+ ].filter(id => id) : undefined
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ date: new Date().toISOString().split('T')[0],
|
|
|
|
|
+ vehicleType: 'bus',
|
|
|
|
|
+ travelMode: 'carpool',
|
|
|
|
|
+ startAreaIds: defaultStartIds,
|
|
|
|
|
+ endAreaIds: defaultEndIds
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 地区显示文本优化
|
|
|
|
|
+需要修改 `getAreaDisplayText` 函数以支持默认配置:
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 修改后的 getAreaDisplayText 函数
|
|
|
|
|
+const getAreaDisplayText = (areaIds?: number[], defaultText?: string) => {
|
|
|
|
|
+ if (!areaIds || areaIds.length === 0) {
|
|
|
|
|
+ return defaultText || '请选择地区'
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 根据areaIds获取地区名称
|
|
|
|
|
+ const areaNames = areaIds.map(id => {
|
|
|
|
|
+ const area = areaData.find(a => a.id === id)
|
|
|
|
|
+ return area ? area.name : '未知地区'
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return areaNames.join(' ') || (defaultText || '请选择地区')
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 错误处理
|
|
|
|
|
+- **配置缺失**: 如果环境变量未配置,保持原有行为(空选择)
|
|
|
|
|
+- **配置格式错误**: 验证数字格式,使用默认值作为备选
|
|
|
|
|
+- **地区数据不匹配**: 如果配置的地区ID在地区数据中不存在,显示配置的地区名称
|
|
|
|
|
+
|
|
|
|
|
+### 用户体验
|
|
|
|
|
+- **加载状态**: 使用现有加载指示器
|
|
|
|
|
+- **配置验证**: 在开发阶段验证环境变量配置
|
|
|
|
|
+- **一致性**: 确保默认显示与现有设计风格一致
|
|
|
|
|
+
|
|
|
|
|
+### 项目结构对齐
|
|
|
|
|
+- **文件命名**: 保持现有kebab-case命名约定 [Source: architecture/source-tree.md#集成指南]
|
|
|
|
|
+- **导入导出**: 使用ES模块和现有别名系统 [Source: architecture/source-tree.md#集成指南]
|
|
|
|
|
+- **组件位置**: 符合现有的页面组织模式 [Source: architecture/source-tree.md#实际项目结构]
|
|
|
|
|
+
|
|
|
|
|
+## Testing
|
|
|
|
|
+
|
|
|
|
|
+### 测试标准
|
|
|
|
|
+- **测试文件位置**: `mini/tests/pages/home.test.tsx` [Source: architecture/testing-strategy.md#taro小程序测试体系]
|
|
|
|
|
+- **测试框架**: Jest + @testing-library/react + React Query + Taro API mock [Source: architecture/testing-strategy.md#taro小程序测试体系]
|
|
|
|
|
+- **覆盖率要求**: 页面级测试 ≥ 60% [Source: architecture/testing-strategy.md#taro小程序测试体系]
|
|
|
|
|
+
|
|
|
|
|
+### 关键测试场景
|
|
|
|
|
+- 首页加载时自动使用环境变量配置的默认目的地
|
|
|
|
|
+- 默认目的地正确显示在出发地和目的地选择按钮上
|
|
|
|
|
+- 环境变量配置缺失时的降级处理
|
|
|
|
|
+- 配置格式错误的错误处理
|
|
|
|
|
+- TypeScript类型检查正确识别新的环境变量
|
|
|
|
|
+- 现有功能无回归
|
|
|
|
|
+
|
|
|
|
|
+### 测试数据管理
|
|
|
|
|
+- **模拟环境变量**: 测试环境配置不同的默认目的地
|
|
|
|
|
+- **API模拟**: 模拟地区数据获取成功和失败场景
|
|
|
|
|
+- **边界测试**: 测试配置缺失、格式错误等边界情况
|
|
|
|
|
+
|
|
|
|
|
+### 测试模式
|
|
|
|
|
+基于最新的测试文件模式 [Source: architecture/testing-strategy.md#最新测试模式和最佳实践]:
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 测试环境设置
|
|
|
|
|
+const createTestQueryClient = () => new QueryClient({
|
|
|
|
|
+ defaultOptions: {
|
|
|
|
|
+ queries: { retry: false },
|
|
|
|
|
+ },
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 组件包装器
|
|
|
|
|
+const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
|
|
+ <QueryClientProvider client={createTestQueryClient()}>
|
|
|
|
|
+ {children}
|
|
|
|
|
+ </QueryClientProvider>
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// 环境变量mock
|
|
|
|
|
+const originalEnv = process.env
|
|
|
|
|
+beforeEach(() => {
|
|
|
|
|
+ process.env = {
|
|
|
|
|
+ ...originalEnv,
|
|
|
|
|
+ TARO_APP_DEFAULT_START_PROVINCE_ID: '1',
|
|
|
|
|
+ TARO_APP_DEFAULT_START_PROVINCE_NAME: '北京市',
|
|
|
|
|
+ TARO_APP_DEFAULT_START_CITY_ID: '2',
|
|
|
|
|
+ TARO_APP_DEFAULT_START_CITY_NAME: '北京市',
|
|
|
|
|
+ TARO_APP_DEFAULT_END_PROVINCE_ID: '3',
|
|
|
|
|
+ TARO_APP_DEFAULT_END_PROVINCE_NAME: '上海市',
|
|
|
|
|
+ TARO_APP_DEFAULT_END_CITY_ID: '4',
|
|
|
|
|
+ TARO_APP_DEFAULT_END_CITY_NAME: '上海市'
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+afterEach(() => {
|
|
|
|
|
+ process.env = originalEnv
|
|
|
|
|
+})
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Risk and Compatibility Check
|
|
|
|
|
+
|
|
|
|
|
+### 风险评估
|
|
|
|
|
+- **主要风险**: 环境变量配置可能在不同环境不一致
|
|
|
|
|
+- **缓解措施**: 确保开发环境和正式环境都正确配置,添加配置验证
|
|
|
|
|
+- **回滚方案**: 恢复原有的空初始状态设置
|
|
|
|
|
+
|
|
|
|
|
+### 兼容性验证
|
|
|
|
|
+- [ ] 对现有API无破坏性变更
|
|
|
|
|
+- [ ] 无数据库变更
|
|
|
|
|
+- [ ] UI变更遵循现有设计模式
|
|
|
|
|
+- [ ] 性能影响可忽略
|
|
|
|
|
+- [ ] 现有功能无回归
|
|
|
|
|
+
|
|
|
|
|
+## Change Log
|
|
|
|
|
+| Date | Version | Description | Author |
|
|
|
|
|
+|------|---------|-------------|--------|
|
|
|
|
|
+| 2025-10-31 | 1.0 | 初始故事创建 | Bob (Scrum Master) |
|
|
|
|
|
+| 2025-10-31 | 1.1 | 添加全局类型定义更新任务 | Bob (Scrum Master) |
|
|
|
|
|
+| 2025-10-31 | 1.2 | 优化环境变量配置:只配置ID,名称通过API获取 | Bob (Scrum Master) |
|
|
|
|
|
+
|
|
|
|
|
+## Dev Agent Record
|
|
|
|
|
+
|
|
|
|
|
+### Agent Model Used
|
|
|
|
|
+*此部分将由开发代理在实现过程中填写*
|
|
|
|
|
+
|
|
|
|
|
+### Debug Log References
|
|
|
|
|
+*此部分将由开发代理在实现过程中填写*
|
|
|
|
|
+
|
|
|
|
|
+### Completion Notes List
|
|
|
|
|
+*此部分将由开发代理在实现过程中填写*
|
|
|
|
|
+
|
|
|
|
|
+### File List
|
|
|
|
|
+*此部分将由开发代理在实现过程中填写*
|
|
|
|
|
+
|
|
|
|
|
+## QA Results
|
|
|
|
|
+*此部分将由QA代理在质量保证过程中填写*
|