# 清道夫 App 5 项修复与排班新增实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking. **Goal:** 修复 tab 页 TopBar 返回按钮、任务页胶囊遮挡、tabBar 高亮同步、退出登录卡顿问题,并实现排班页新增排班功能。 **Architecture:** 前端基于 uni-app Vue 3 + TypeScript + Pinia,通过修改通用组件与页面生命周期解决问题;后端 Spring Boot 补全 `/vehicle/simple-list` 下拉接口;排班新增采用弹窗表单,严格映射后端 `DispatchSchedule` 字段。 **Tech Stack:** uni-app Vue 3, TypeScript, Tailwind, Pinia, Spring Boot, MyBatis-Plus ## Global Constraints - 所有 API 以后端接口为准;缺失则后端补全。 - 排班类型映射:月计划 ↔ `month_plan`,应急 ↔ `emergency`。 - 保持 `npm run type-check` 与 `npm run build:mp-weixin` 通过。 - 每个任务完成后提交一次 git commit。 --- ## Task 1: 后端补全 `/vehicle/simple-list` 接口 **Files:** - Modify: `D:/work/绿水青山/java/aquagreen-server/aquagreen-business/src/main/java/com/aquagreen/business/service/VehicleService.java` - Modify: `D:/work/绿水青山/java/aquagreen-server/aquagreen-business/src/main/java/com/aquagreen/business/controller/VehicleController.java` **Interfaces:** - Produces: `GET /vehicle/simple-list` → `R>>` with `{ value: vehicleId, label: plateNo }` - [x] **Step 1.1: 在 VehicleService 添加 simpleList 方法** 在 `VehicleService.java` 中 `assignToTask` 方法之后新增: ```java public List> simpleList() { List list = list( new LambdaQueryWrapper() .orderByAsc(BizVehicle::getPlateNo)); List> result = new ArrayList<>(); for (BizVehicle vehicle : list) { Map item = new HashMap<>(); item.put("value", vehicle.getVehicleId()); item.put("label", vehicle.getPlateNo()); result.add(item); } return result; } ``` 并在文件顶部添加 `import java.util.ArrayList;` 和 `import java.util.HashMap;`(如不存在)。 - [x] **Step 1.2: 在 VehicleController 添加 /vehicle/simple-list 端点** 在 `VehicleController.java` 中 `/vehicle/{vehicleId}` 之前新增: ```java @GetMapping("/simple-list") @Operation(summary = "车辆下拉列表", description = "返回车辆ID与车牌号,用于下拉选择") public R>> simpleList() { return R.ok(vehicleService.simpleList()); } ``` 并在文件顶部添加 `import java.util.List;`、`import java.util.Map;`、`import java.util.HashMap;`、`import java.util.ArrayList;`(如不存在)。 - [x] **Step 1.3: 后端编译验证** Run: `cd D:/work/绿水青山/java/aquagreen-server && mvn compile -pl aquagreen-business -am` Expected: BUILD SUCCESS - [x] **Step 1.4: Commit** ```bash git add aquagreen-business/src/main/java/com/aquagreen/business/service/VehicleService.java aquagreen-business/src/main/java/com/aquagreen/business/controller/VehicleController.java git commit -m "feat(vehicle): add /vehicle/simple-list endpoint" ``` --- ## Task 2: 修复 TopBar 默认返回按钮与 tab 页面返回按钮 **Files:** - Modify: `D:/work/绿水青山/清道夫App/src/components/common/TopBar.vue` - Modify: `D:/work/绿水青山/清道夫App/src/components/dispatch/ScheduleView.vue`(可选,确认 showBack 传递) **Interfaces:** - Consumes: `TopBar.showBack` prop(Boolean,默认 false) - Produces: tab 页面不再显示返回按钮 - [x] **Step 2.1: 修改 TopBar 默认值** 在 `TopBar.vue` 中,将 `showBack` 默认值从 `true` 改为 `false`: ```typescript const props = withDefaults( defineProps<{ title: string showBack?: boolean }>(), { showBack: false } ) ``` - [x] **Step 2.2: 全局搜索确认非 tab 页面已显式开启返回(如需要)** Run: `grep -rn " ``` - [x] **Step 3.2: 验证构建无 TS/模板错误** Run: `npm run type-check` Expected: 无错误 - [x] **Step 3.3: Commit** ```bash git add src/components/task/TaskListView.vue git commit -m "fix(task): ensure publish button stays clear of WeChat capsule" ``` --- ## Task 4: 修复自定义 tabBar 高亮同步 **Files:** - Modify: `D:/work/绿水青山/清道夫App/src/pages/home/home.vue` - Modify: `D:/work/绿水青山/清道夫App/src/pages/task/task.vue` - Modify: `D:/work/绿水青山/清道夫App/src/pages/schedule/schedule.vue` - Modify: `D:/work/绿水青山/清道夫App/src/pages/my/my.vue` - Modify: `D:/work/绿水青山/清道夫App/src/custom-tab-bar/index.js` **Interfaces:** - Consumes: `getTabBar()` API from custom tabBar component - Produces: 切换 tab 后高亮即时同步 - [x] **Step 4.1: 在 custom-tab-bar/index.js 中暴露 setSelected 方法** 在 `custom-tab-bar/index.js` 的 `methods` 对象中新增: ```javascript setSelected(index) { this.setData({ selected: index }) } ``` - [x] **Step 4.2: 在 tab 页面 onShow 中同步高亮** 在每个 tab 页面的 `onShow` 中添加(需从 `@dcloudio/uni-app` 导入 `onShow`): **src/pages/home/home.vue**(索引 0): ```typescript import { onShow } from '@dcloudio/uni-app' onShow(() => { const tabBar = getTabBar ? getTabBar() : null tabBar?.setSelected?.(0) }) ``` **src/pages/task/task.vue**(索引 1,commonTabs)或 2(dispatchTabs): ```typescript onShow(() => { taskStore.fetchTasks() const tabBar = getTabBar ? getTabBar() : null const role = authStore.userRole const index = role === 'dispatch' ? 2 : 1 tabBar?.setSelected?.(index) }) ``` **src/pages/schedule/schedule.vue**(索引 1,仅 dispatch): ```vue ``` **src/pages/my/my.vue**(commonTabs 索引 2,dispatchTabs 索引 3): ```vue ``` - [x] **Step 4.3: 验证 type-check** Run: `npm run type-check` Expected: 无错误(`getTabBar` 为 uni-app 全局 API,TypeScript 可能需要 `declare const getTabBar: any` 或忽略) - [x] **Step 4.4: Commit** ```bash git add src/pages/home/home.vue src/pages/task/task.vue src/pages/schedule/schedule.vue src/pages/my/my.vue src/custom-tab-bar/index.js git commit -m "fix(tabbar): sync highlight on tab page onShow" ``` --- ## Task 5: 修复退出登录卡顿 **Files:** - Modify: `D:/work/绿水青山/清道夫App/src/components/my/ProfileView.vue` **Interfaces:** - Consumes: `uni.reLaunch`, `authStore.doLogout` - Produces: 登出动画流畅 - [x] **Step 5.1: 调整 handleLogout 顺序** 将 `ProfileView.vue` 中 `handleLogout` 函数替换为: ```typescript async function handleLogout() { const res = await uni.showModal({ title: '确认退出', content: '确定要退出登录吗?', }) if (res.confirm) { uni.reLaunch({ url: '/pages/login/login', complete: () => { authStore.doLogout() }, }) } } ``` - [x] **Step 5.2: Commit** ```bash git add src/components/my/ProfileView.vue git commit -m "fix(logout): reLaunch first then clear auth state to avoid hang" ``` --- ## Task 6: 更新排班与车辆 API 类型 **Files:** - Modify: `D:/work/绿水青山/清道夫App/src/api/schedule.ts` - Modify: `D:/work/绿水青山/清道夫App/src/api/vehicle.ts` - Create: `D:/work/绿水青山/清道夫App/src/api/team.ts` **Interfaces:** - Produces: `createSchedule(data: DispatchSchedule)` → `post('/schedule', data)` - Produces: `getVehicleSimpleList()` → `get('/vehicle/simple-list')` - Produces: `getTeamSimpleList()` → `get('/team/simple-list')` - [x] **Step 6.1: 定义 DispatchSchedule 类型** 在 `src/api/schedule.ts` 顶部新增类型: ```typescript export interface DispatchSchedule { scheduleId?: number teamId?: number teamName?: string workDate?: string shiftType?: 'month_plan' | 'emergency' | string vehicleIds?: string staffIds?: string status?: string remark?: string } ``` - [x] **Step 6.2: 更新 createSchedule 签名** 将 `createSchedule` 改为: ```typescript export function createSchedule(data: DispatchSchedule) { return post('/schedule', data) } ``` - [x] **Step 6.3: 更新 getScheduleList 返回字段兼容** 当前 `getScheduleList` 按 `year/month` 查询,后端 `/schedule/list` 是分页。需要改为按日期 `/schedule/date/{workDate}` 查询日排班。保留原函数用于月视图标记,新增: ```typescript export function getSchedulesByDate(workDate: string) { return get(`/schedule/date/${workDate}`) } ``` - [x] **Step 6.4: 更新 vehicle API** 将 `src/api/vehicle.ts` 中 `getAvailableVehicles` 改为: ```typescript export function getVehicleSimpleList() { return get>('/vehicle/simple-list') } ``` - [x] **Step 6.5: 创建 team API** 创建 `src/api/team.ts`: ```typescript import { get } from './request' export interface SimpleOption { value: number label: string } export function getTeamSimpleList() { return get('/team/simple-list') } export function getTeamMembers(teamId: number) { return get>(`/team/${teamId}/members`) } ``` - [x] **Step 6.6: Commit** ```bash git add src/api/schedule.ts src/api/vehicle.ts src/api/team.ts git commit -m "feat(api): align schedule/vehicle/team APIs with backend" ``` --- ## Task 7: 实现排班页新增排班弹窗 **Files:** - Modify: `D:/work/绿水青山/清道夫App/src/components/dispatch/ScheduleView.vue` **Interfaces:** - Consumes: `getTeamSimpleList`, `getVehicleSimpleList`, `getTeamMembers`, `createSchedule`, `getSchedulesByDate` - Produces: 新增排班弹窗,提交后刷新列表 - [x] **Step 7.1: 导入 API 与工具** 在 `ScheduleView.vue` 的 `