diff --git a/backend/app/agendas/outcome_tags.py b/backend/app/agendas/outcome_tags.py index bb37855..68926ac 100644 --- a/backend/app/agendas/outcome_tags.py +++ b/backend/app/agendas/outcome_tags.py @@ -66,13 +66,13 @@ def parse_action_metadata( due_date_val = date.fromisoformat(token) except ValueError: break - elif token_lower in ("todo", "open"): + elif token_lower in ("todo", "open", "待办", "待开始"): status = ActionStatus.open - elif token_lower in ("in_progress", "doing", "progress"): + elif token_lower in ("in_progress", "doing", "progress", "进行中"): status = ActionStatus.in_progress - elif token_lower in ("done", "completed", "finish", "finished"): + elif token_lower in ("done", "completed", "finish", "finished", "已完成", "完成"): status = ActionStatus.done - elif token_lower in ("canceled", "cancelled"): + elif token_lower in ("canceled", "cancelled", "已取消", "取消"): status = ActionStatus.canceled else: break diff --git a/backend/tests/domain/test_bidirectional_actions.py b/backend/tests/domain/test_bidirectional_actions.py index 5cc054b..1a3312e 100644 --- a/backend/tests/domain/test_bidirectional_actions.py +++ b/backend/tests/domain/test_bidirectional_actions.py @@ -84,6 +84,40 @@ def test_parse_outcome_tags_extended_syntax(): assert actions[3].content == "传统无括号待办" +def test_parse_outcome_tags_chinese_status_tokens(): + md = """ +@行动:[待办][@林宇][2026-10-01] 整理压测报告 +@行动:[待开始][@乔安] 准备回滚预案 +@行动:[进行中][@林宇] 推进网关限流改造 +@行动:[已完成][@乔安][2026-09-30] 完成发布清单核验 +@行动:[已取消] 旧版接口迁移计划 +""" + tags = parse_outcome_tags(md) + assert len(tags) == 5 + + assert tags[0].status == ActionStatus.open + assert tags[0].owner_name == "林宇" + assert tags[0].due_date == date(2026, 10, 1) + assert tags[0].content == "整理压测报告" + + assert tags[1].status == ActionStatus.open + assert tags[1].owner_name == "乔安" + assert tags[1].content == "准备回滚预案" + + assert tags[2].status == ActionStatus.in_progress + assert tags[2].owner_name == "林宇" + assert tags[2].content == "推进网关限流改造" + + assert tags[3].status == ActionStatus.done + assert tags[3].owner_name == "乔安" + assert tags[3].due_date == date(2026, 9, 30) + assert tags[3].content == "完成发布清单核验" + + assert tags[4].status == ActionStatus.canceled + assert tags[4].owner_name is None + assert tags[4].content == "旧版接口迁移计划" + + def test_rewrite_action_in_notes(): notes = """# Notes - List item diff --git a/docs/assets/demo_meetflow.gif b/docs/assets/demo_meetflow.gif index 163dd25..7e294af 100644 Binary files a/docs/assets/demo_meetflow.gif and b/docs/assets/demo_meetflow.gif differ diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 1b02524..9c3acec 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -1,4 +1,5 @@ import { locale } from '../i18n' +import { translateBackendError } from '../utils/errors' export class ApiError extends Error { constructor( @@ -25,7 +26,12 @@ export function apiErrorMessage( && 'message' in payload.error && typeof payload.error.message === 'string' ) { - return payload.error.message + const code = 'code' in payload.error && typeof payload.error.code === 'string' ? payload.error.code : null + const translated = translateBackendError(payload.error.message, code) + if (locale.value === 'en' && /[\u4e00-\u9fff]/.test(translated) && !/[\u4e00-\u9fff]/.test(fallback)) { + return fallback + } + return translated } return fallback } diff --git a/frontend/src/api/plugin-stream.ts b/frontend/src/api/plugin-stream.ts index 1c279e2..540f8c6 100644 --- a/frontend/src/api/plugin-stream.ts +++ b/frontend/src/api/plugin-stream.ts @@ -1,4 +1,5 @@ import { locale } from '../i18n' +import { translateBackendError } from '../utils/errors' import { apiErrorMessage, dispatchAuthExpired } from './client' function consumeEvent(block: string, onDelta: (text: string) => void): boolean { @@ -24,7 +25,8 @@ function consumeEvent(block: string, onDelta: (text: string) => void): boolean { } if (event === 'error') { if (payload && typeof payload === 'object' && 'message' in payload && typeof payload.message === 'string') { - throw new Error(payload.message) + const code = 'code' in payload && typeof payload.code === 'string' ? payload.code : null + throw new Error(translateBackendError(payload.message, code)) } throw new Error(locale.value === 'en' ? 'Failed to generate AI work brief, please try again later' : 'AI 工作简报生成失败,请稍后重试') } diff --git a/frontend/src/components/AgendaDetail.vue b/frontend/src/components/AgendaDetail.vue index 06c74f7..6e34abb 100644 --- a/frontend/src/components/AgendaDetail.vue +++ b/frontend/src/components/AgendaDetail.vue @@ -479,7 +479,7 @@ const noteActionTags = computed(() => {