✅ Completed
As a 系统管理员 I want 能够配置活动、路线等基础数据 so that 用户能够查询和使用出行服务
src/server/modules/routes/ 创建 route.entity.tssrc/server/modules/activities/ 创建 activity.entity.tssrc/share/ 创建相关类型定义src/server/modules/areas/ 创建 area.entity.tssrc/server/modules/locations/ 创建 location.entity.tssrc/share/ 创建省市区和地点相关类型定义routeType 计算字段,根据活动地点关系自动判断类型src/server/modules/routes/ 创建 route.schema.ts (创建、更新、获取、列表Schema)src/server/modules/activities/ 创建 activity.schema.ts (创建、更新、获取、列表Schema)src/server/modules/areas/ 创建 area.schema.ts (创建、更新、获取、列表Schema)src/server/modules/locations/ 创建 location.schema.ts (创建、更新、获取、列表Schema)scripts/generate-area-sql.mjs 生成省市区种子数据src/server/api/admin/activities/index.ts 使用 createCrudRoutes 创建活动管理APIsrc/server/api/admin/routes/index.ts 使用 createCrudRoutes 创建路线管理APIsrc/server/api/admin/areas/index.ts 使用 createCrudRoutes 创建省市区管理APIGET /api/v1/areas/provinces - 获取省份列表GET /api/v1/areas/cities?provinceId=1 - 获取城市列表GET /api/v1/areas/districts?cityId=34 - 获取区县列表src/server/api/admin/locations/index.ts 使用 createCrudRoutes 创建地点管理API[x] 实现用户端路线查询API (AC: 6, 7, 8)
src/server/api/routes/index.ts 中实现路线搜索API[x] 实现省市区管理页面 (AC: 5)
[x] 实现地点管理页面 (AC: 5)
[x] 编写地点管理测试 (AC: 5, 6, 7, 8)
tests/integration/server/)tests/integration/client/)tests/e2e/specs/admin/)[x] 实现地点选择组件 (AC: 5)
[x] 实现管理后台页面 (AC: 1, 2, 3, 4)
[x] 编写测试 (AC: 1, 2, 3, 4)
tests/integration/server/)tests/integration/client/)tests/e2e/specs/admin/)[x] 实现活动选择组件 (AC: 3)
[x] 修复表单时间格式问题 (AC: 1, 2, 3, 4)
基于 [docs/prd/epic-005-travel-service-core.md#后端数据模型] 和 [docs/architecture/data-model-schema-changes.md],需要实现以下实体:
Area实体 (遵循 通用CRUD实体设计规范):
id - 主键parentId - 关联父级区域,0表示顶级(省/直辖市)name - 区域名称level - 层级: 1:省/直辖市, 2:市, 3:区/县code - 行政区划代码createdAt 和 updatedAt 时间戳Location实体 (遵循 通用CRUD实体设计规范):
name - 地点名称province - 关联AreaEntity (level=1)city - 关联AreaEntity (level=2)district - 关联AreaEntity (level=3)address - 详细地址latitude - 纬度longitude - 经度createdAt 和 updatedAt 时间戳Activity实体 (遵循 通用CRUD实体设计规范):
name - 活动名称description - 活动描述venueLocation - 关联LocationEntity(举办地点)startDate - 开始时间endDate - 结束时间createdAt 和 updatedAt 时间戳Route实体 (遵循 通用CRUD实体设计规范):
startLocation - 关联LocationEntity(出发地)endLocation - 关联LocationEntity(目的地)pickupPoint - 上车点dropoffPoint - 下车点departureTime - 出发时间vehicleType - 车型price - 价格seatCount - 座位数activity - 关联ActivityEntitycreatedAt 和 updatedAt 时间戳locations 表,包含必要的字段和索引routes 表,包含必要的字段和索引activities 表,包含必要的字段和索引基于优化的数据模型,查询逻辑需要相应调整:
地点查询流程:
路线查询流程:
用户端路线和活动查询流程:
查询API设计:
GET /api/v1/routes/search?startLocationId=123&endLocationId=456&date=2025-10-15去程/返程动态判断逻辑:
业务逻辑实现位置:
src/server/modules/routes/route.service.ts 中实现 getRouteType 方法routeType,基于活动地点关系自动判断基于 [docs/prd/epic-005-travel-service-core.md#管理后台API],使用 通用CRUD规范 实现以下API端点:
地点管理API (使用 createCrudRoutes):
GET /api/v1/admin/locations - 地点管理列表(支持分页、搜索、筛选)GET /api/v1/admin/locations/:id - 地点详情POST /api/v1/admin/locations - 创建地点PUT /api/v1/admin/locations/:id - 更新地点DELETE /api/v1/admin/locations/:id - 删除地点地点管理API配置:
['name', 'province', 'city', 'district', 'address']province, city, districtname, province, city[authMiddleware]活动管理API (使用 createCrudRoutes):
GET /api/v1/admin/activities - 活动管理列表(支持分页、搜索、筛选)GET /api/v1/admin/activities/:id - 活动详情POST /api/v1/admin/activities - 创建活动PUT /api/v1/admin/activities/:id - 更新活动DELETE /api/v1/admin/activities/:id - 删除活动活动管理API配置:
['name', 'description']['routes', 'venueLocation']type (活动类型)[authMiddleware]路线管理API (使用 createCrudRoutes):
GET /api/v1/admin/routes - 路线管理列表(支持分页、搜索、筛选)GET /api/v1/admin/routes/:id - 路线详情POST /api/v1/admin/routes - 创建路线PUT /api/v1/admin/routes/:id - 更新路线DELETE /api/v1/admin/routes/:id - 删除路线路线管理API配置:
['vehicleType']['activity', 'startLocation', 'endLocation']vehicleType, price (范围查询), routeType (去程/返程)price, departureTime[authMiddleware]基于地点实体设计方案,需要实现地点选择组件来提升用户体验:
LocationSelect组件功能要求:
组件位置:
src/client/admin/components/LocationSelect.tsx集成要求:
基于用户体验改进需求,需要实现活动选择组件来替换原有的数字ID输入框:
ActivitySelect组件功能要求:
组件位置:
src/client/admin/components/ActivitySelect.tsx集成要求:
基于 [docs/prd/epic-005-travel-service-core.md#管理后台页面任务],需要实现以下页面:
地点管理页面:
严格遵循 RPC Client 使用规范:
客户端导入和类型定义:
// 从统一的API模块导入客户端
import { activityClient, routeClient } from '@/client/api';
import type { InferRequestType, InferResponseType } from 'hono/client';
// 类型提取规范
type ActivityResponse = InferResponseType<typeof activityClient.$get, 200>['data'][0];
type RouteResponse = InferResponseType<typeof routeClient.$get, 200>['data'][0];
type CreateActivityRequest = InferRequestType<typeof activityClient.$post>['json'];
type UpdateActivityRequest = InferRequestType<typeof activityClient[':id']['$put']>['json'];
数据获取规范:
// 使用React Query进行数据获取
const { data, isLoading, refetch } = useQuery({
queryKey: ['activities', searchParams],
queryFn: async () => {
const res = await activityClient.$get({
query: {
page: searchParams.page,
pageSize: searchParams.limit,
keyword: searchParams.keyword
}
});
if (res.status !== 200) throw new Error('获取数据失败');
return await res.json();
},
staleTime: 5 * 60 * 1000, // 5分钟缓存
cacheTime: 10 * 60 * 1000, // 10分钟缓存
});
统一错误处理:
// 统一操作处理函数
const handleOperation = async (operation: () => Promise<any>) => {
try {
await operation();
toast.success('操作成功');
} catch (error) {
console.error('操作失败:', error);
toast.error('操作失败,请重试');
}
};
// 创建活动示例
const handleCreateActivity = async (data: CreateActivityRequest) => {
await handleOperation(async () => {
const res = await activityClient.$post({ json: data });
if (res.status !== 201) throw new Error('创建失败');
});
};
防抖搜索实现:
// 防抖搜索函数
const debounce = (func: Function, delay: number) => {
let timeoutId: NodeJS.Timeout;
return (...args: any[]) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
};
const debouncedSearch = useCallback(
debounce((keyword: string) => {
setSearchParams(prev => ({ ...prev, keyword, page: 1 }));
}, 300),
[]
);
活动管理页面:
路线管理页面:
src/server/modules/locations/location.entity.tssrc/server/modules/routes/route.entity.tssrc/server/modules/activities/activity.entity.tssrc/server/modules/locations/location.schema.tssrc/server/modules/routes/route.schema.tssrc/server/modules/activities/activity.schema.tssrc/share/location.types.tssrc/share/route.types.tssrc/share/activity.types.tssrc/server/api/admin/locations/index.tssrc/server/api/admin/activities/index.tssrc/server/api/admin/routes/index.tsmini/src/pages/admin/locations/LocationManagementPage.tsxmini/src/pages/admin/activities/ActivityManagementPage.tsxmini/src/pages/admin/routes/RouteManagementPage.tsxsrc/client/admin/components/LocationSelect.tsxsrc/client/admin/components/ActivitySelect.tsxsrc/server/migrations/ 目录src/server/seeds/ 目录基于测试设计分析 (docs/qa/assessments/005.001-test-design-20251016.md),测试实施应遵循以下优先级:
P0 优先实施 (核心功能):
P1 其次实施 (重要功能):
P2 最后实施 (辅助功能):
测试文件位置参考:
tests/integration/server/admin/tests/integration/client/admin/tests/e2e/specs/admin/| Date | Version | Description | Author |
|---|---|---|---|
| 2025-10-18 | 6.0 | ✅ 完成地点管理功能测试覆盖:添加LocationSelect、ActivityForm、RouteForm完整测试套件,修复测试环境问题 | James (Dev Agent) |
| 2025-10-18 | 5.0 | 补充活动管理页中活动地点的相关任务,完善地点显示、筛选和测试覆盖 | John (PM) |
| 2025-10-17 | 4.0 | 添加省市区实体设计方案,支持省市区三级联动数据管理,完善地点管理任务 | James (Dev Agent) |
| 2025-10-17 | 3.0 | 添加地点实体设计方案,支持省市区结构化地址管理,优化活动实体设计 | John (PM) |
| 2025-10-16 | 2.0 | 修复TypeScript类型错误,提升代码质量:修复Schema定义、枚举类型、filters参数格式,移除所有any类型使用 | James (Dev Agent) |
| 2025-10-16 | 1.9 | 完成活动管理和路线管理E2E测试,实现完整的测试覆盖 | James (Dev Agent) |
| 2025-10-16 | 1.8 | 修复表单时间格式问题,补充日期时间处理规范 | Winston (Architect) |
| 2025-10-16 | 1.7 | 补充活动选择组件任务,提升用户体验 | Bob (Scrum Master) |
| 2025-10-16 | 1.6 | 完成管理后台页面所有功能:搜索筛选、创建编辑、启用/禁用 | James (Dev Agent) |
| 2025-10-16 | 1.5 | 添加前端RPC实现规范,确保符合管理后台RPC Client使用规范 | Bob (Scrum Master) |
| 2025-10-16 | 1.4 | 添加通用CRUD规范引用,完善API实现细节 | Bob (Scrum Master) |
| 2025-10-16 | 1.3 | 添加管理后台开发规范引用,确保符合标准 | Bob (Scrum Master) |
| 2025-10-16 | 1.2 | 修正故事,移除班次实体,与epic005和数据模型保持一致 | Bob (Scrum Master) |
| 2025-10-16 | 1.1 | 修正故事,添加管理后台功能,完全满足epic005 US005-01需求 | Bob (Scrum Master) |
| 2025-10-16 | 1.0 | 初始故事创建,从005.002迁移基础数据实体任务 | Bob (Scrum Master) |
此部分由开发代理在实施过程中填写
Claude Sonnet 4.5 (2025-09-29)
✅ 已完成的任务:
✅ 技术实现细节:
已创建/修改的文件:
地点管理功能测试相关文件:
省市区实体设计相关文件:
审查人: Quinn (Test Architect)
测试策略:
质量门控状态: ✅ 测试设计通过
实施建议: 开发团队应按P0→P1→P2优先级顺序实施测试