面向 AI 代理的工作者: 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(
- [ ])语法来跟踪进度。
目标: 修复个人 OKR 页面周期与接口数据链路,并按 Open Design 参考图交付可更新、可追溯的 Objective/KR 进度可视化。
架构: 以 workspace store 的当前周期为唯一周期来源,由路由 query 持久化;个人页面监听有效周期并加载本人全部 Objective。抽取一个 ObjectiveProgressCard 组件复用在“我的 OKR”和“执行进度”,后端 execution-timeline 收窄为本人数据并补齐单位字段。
技术栈: Vue 3、Pinia、Vue Router、Element Plus、Vitest、Spring Boot、MyBatis-Plus、JUnit 5、Mockito
frontend/src/components/okr/ObjectiveProgressCard.vue — Objective/KR 主进度卡片。frontend/src/composables/useCurrentPeriodId.js — URL 与 workspace 当前周期归一化。frontend/src/components/shell/CohereSidebar.vue — 周期相关链接携带 query。frontend/src/views/okr/MyOkrView.vue — 使用统一周期并渲染进度卡片。frontend/src/views/okr/OkrExecutionView.vue — 加载多 Objective、渲染主进度卡和时间线。frontend/src/api/index.js — 作为两个页面唯一 OKR API 客户端。backend/src/main/java/com/yimeng/okr/dto/OkrExecutionTimelineDto.java — 时间线增加 KR 单位。backend/src/main/java/com/yimeng/okr/service/OkrService.java — 时间线仅聚合当前用户。frontend/src/__tests__/workspace-navigation-contract.test.js — 周期继承契约。frontend/src/__tests__/open-design-page-contract.test.js — 进度可视化契约。backend/src/test/java/com/yimeng/okr/service/OkrServiceTest.java — 本人时间线边界测试。文件:
frontend/src/__tests__/workspace-navigation-contract.test.js修改:frontend/src/__tests__/open-design-page-contract.test.js
[ ] 步骤 1:编写失败的周期继承测试
it('keeps the selected period on personal OKR navigation', () => {
const sidebar = readFileSync(resolve(process.cwd(), 'src/components/shell/CohereSidebar.vue'), 'utf8')
expect(sidebar).toContain('periodAwareTarget')
expect(sidebar).toContain('workspace.periodId')
})
[ ] 步骤 2:编写失败的执行页数据契约测试
it('loads all personal objectives and the personal execution timeline', () => {
const page = source('okr/OkrExecutionView.vue')
expect(page).toContain('okrApi.getMyOkrSet(periodId)')
expect(page).toContain('okrApi.getExecutionTimeline(periodId)')
expect(page).toContain('ObjectiveProgressCard')
expect(page).toContain('watch(effectivePeriodId')
})
[ ] 步骤 3:运行测试验证失败
运行:cd frontend && npm test -- --run src/__tests__/workspace-navigation-contract.test.js src/__tests__/open-design-page-contract.test.js
预期:FAIL,侧边栏仍使用固定字符串路径,执行页仍依赖单个 myOkr 与 onMounted。
文件:
frontend/src/composables/useCurrentPeriodId.jsfrontend/src/components/shell/CohereSidebar.vuefrontend/src/views/okr/MyOkrView.vue修改:frontend/src/views/okr/OkrExecutionView.vue
[ ] 步骤 1:实现有效周期 composable
import { computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useWorkspaceStore } from '@/stores/workspace'
export function useCurrentPeriodId() {
const route = useRoute()
const router = useRouter()
const workspace = useWorkspaceStore()
const effectivePeriodId = computed(() => {
const queryId = Number(route.query.periodId)
return Number.isFinite(queryId) && queryId > 0 ? queryId : workspace.periodId
})
watch(() => workspace.periodId, id => {
if (id && !route.query.periodId) router.replace({ query: { ...route.query, periodId: id } })
}, { immediate: true })
return { effectivePeriodId }
}
[ ] 步骤 2:让侧边栏周期页面继承当前 query
function periodAwareTarget(item) {
if (!item.periodAware || !workspace.periodId) return item.to
return { path: item.to, query: { periodId: workspace.periodId } }
}
将“我的 OKR”“团队 OKR”“OKR 对齐”“执行进度”和绩效周期页面标记为 periodAware: true,并把 <router-link :to="item.to"> 改为 <router-link :to="periodAwareTarget(item)">。
[ ] 步骤 3:让两个个人页面监听有效周期
const { effectivePeriodId } = useCurrentPeriodId()
watch(effectivePeriodId, periodId => {
if (periodId) fetchData(periodId)
}, { immediate: true })
“我的 OKR”保留自身周期切换 UI,但切换时同步 query;执行页不再使用只执行一次的 onMounted(fetchData)。
运行:cd frontend && npm test -- --run src/__tests__/workspace-navigation-contract.test.js
预期:PASS。
文件:
backend/src/main/java/com/yimeng/okr/dto/OkrExecutionTimelineDto.javabackend/src/main/java/com/yimeng/okr/service/OkrService.java修改:backend/src/test/java/com/yimeng/okr/service/OkrServiceTest.java
[ ] 步骤 1:编写失败的本人范围测试
构造当前用户 Objective 和直属下属 Objective,调用 getExecutionTimeline(periodId, actorId),断言结果只包含当前用户 KR:
assertEquals(List.of(100L), dto.getItems().stream()
.map(OkrExecutionTimelineDto.KrTimelineItem::getKrId).toList());
verify(userMapper, never()).selectList(any());
运行:cd backend && mvn -Dtest=OkrServiceTest#getExecutionTimelineOnlyReturnsCurrentUsersObjectives test
预期:FAIL,现有实现会调用 getSubordinateOkrs 并合并下属。
[ ] 步骤 3:实现最小后端修复
List<OkrDetailDto> myOkrList = new ArrayList<>(getMyOkrSet(periodId, actorId));
删除下属合并逻辑;在 KrTimelineItem 增加 private String unit;,映射时执行 item.setUnit(kr.getUnit())。
运行:cd backend && mvn -Dtest=OkrServiceTest test
预期:全部 OkrServiceTest 通过。
文件:
frontend/src/components/okr/ObjectiveProgressCard.vuefrontend/src/views/okr/MyOkrView.vuefrontend/src/views/okr/OkrExecutionView.vue修改:frontend/src/__tests__/open-design-page-contract.test.js
[ ] 步骤 1:扩展失败的视觉契约
expect(page).toContain('objective-progress-card')
expect(page).toContain('objective-progress-card__kr')
expect(page).toContain('objective-progress-card__track')
expect(page).toContain('objective-progress-card__fill')
expect(page).toContain('update-progress')
[ ] 步骤 2:实现共享进度卡组件
组件 props 为 objective、objectiveIndex、interactive;emit 为 update-progress。进度计算使用 baseline-aware 公式:
const progressOf = kr => {
const baseline = Number(kr.baselineValue || 0)
const current = Number(kr.currentValue || 0)
const target = Number(kr.targetValue || 0)
if (target === baseline) return current === target ? 100 : 0
return Math.max(0, Math.min(100, Math.round((current - baseline) / (target - baseline) * 100)))
}
模板按参考图渲染 O 编号、标题、权重、描述,以及每条 KR 的编号、标题、当前值、目标值、单位、状态标签和横向进度条。阻塞/延期为 danger,正常执行在深紫与浅青之间交替。
用 ObjectiveProgressCard 替换现有 Objective 表格区,点击更新事件继续调用现有 openKrDrawer(kr),不修改创建与审核表单。
[ ] 步骤 4:重构执行页为多 Objective 主视图
const myOkrs = ref([])
const [objectives, timeline] = await Promise.all([
okrApi.getMyOkrSet(periodId),
okrApi.getExecutionTimeline(periodId)
])
myOkrs.value = objectives || []
timelineItems.value = timeline?.items || []
主区域先渲染全部 ObjectiveProgressCard,再渲染计划时间线。即使没有 progressHistory,只要 KR 有计划日期就必须显示轨道。
请求失败设置 error;请求成功但无 Objective 设置 empty。空态文案明确提示“当前账号在该周期没有个人 OKR”,不显示“网络错误”。
运行:cd frontend && npm test -- --run src/__tests__/open-design-page-contract.test.js src/__tests__/workspace-navigation-contract.test.js
预期:PASS。
文件:
design-qa.mddocs/audit/open-design-2026-07-14/execution-*.png同步:backend/src/main/resources/static/**
[ ] 步骤 1:运行前端完整验证
运行:
cd frontend
npm test -- --run
npm run verify:theme
npm run verify:scoring
npm run build
预期:全部测试、契约检查和 Vite 构建通过。
运行:cd backend && mvn clean test
预期:0 failures、0 errors。
使用有个人 OKR 的账号打开 /okr/my?periodId=1 和 /okr/execution?periodId=1,捕获桌面与移动端截图。将用户参考图和实现截图横向合成后检查:Objective 边界、KR 行密度、进度条宽度、当前/目标值、状态色、更新入口及移动端溢出。
design-qa.md 必须记录参考图、实现图、已修复差异,并包含 final result: passed;存在 P0/P1/P2 时继续修改和重新截图。
[ ] 步骤 5:同步和重新打包
rm -rf backend/src/main/resources/static/assets
cp -R frontend/dist/. backend/src/main/resources/static/
cmp frontend/dist/index.html backend/src/main/resources/static/index.html
cd backend && mvn package -DskipTests
预期:cmp 退出码 0,JAR 中包含最新 ObjectiveProgressCard 与 OkrExecutionView 产物。