重构: P0-4 IdeaRecord.status union类型化(试点·类型安全)
- types.ts: 新增 IdeaStatus union(draft|pending_review|approved|rejected|promoted|archived, 对齐后端df-types IdeaStatus serde snake_case) + IdeaRecord.status string→IdeaStatus - Ideas.vue/IdeaDetail.vue/IdeasPanel.vue: statusOptions/statusLabelKey/onStatusChange/emit收窄 类型IdeaStatus(编译期校验拼写错) - stores/project.ts/state.ts: 比较 IdeaStatus 后端契约: union 6值=df-types IdeaStatus serde, IPC/DB不变零行为变更 P0-4试点跑通: 推广路径验证(union+父子类型传递+emit收窄); 剩余TaskRecord/AiToolCallInfo/WorkflowRecord/ProjectRecord status待推广
This commit is contained in:
@@ -4,11 +4,15 @@
|
|||||||
// 灵感
|
// 灵感
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
|
// IdeaRecord.status union 类型 — 值集对齐后端 IdeaStatus serde (df-types/src/types.rs:52)
|
||||||
|
// snake_case: draft | pending_review | approved | rejected | promoted | archived
|
||||||
|
export type IdeaStatus = 'draft' | 'pending_review' | 'approved' | 'rejected' | 'promoted' | 'archived'
|
||||||
|
|
||||||
export interface IdeaRecord {
|
export interface IdeaRecord {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
status: string // draft | pending_review | approved | rejected | promoted | archived
|
status: IdeaStatus
|
||||||
priority: number
|
priority: number
|
||||||
score: number | null
|
score: number | null
|
||||||
tags: string | null // JSON 数组字符串
|
tags: string | null // JSON 数组字符串
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ import { computed } from 'vue'
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { parseTags } from '../../stores/knowledge'
|
import { parseTags } from '../../stores/knowledge'
|
||||||
import { useRendered } from '../../composables/useMarkdown'
|
import { useRendered } from '../../composables/useMarkdown'
|
||||||
import type { IdeaRecord } from '../../api/types'
|
import type { IdeaRecord, IdeaStatus } from '../../api/types'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
idea: IdeaRecord
|
idea: IdeaRecord
|
||||||
@@ -138,20 +138,20 @@ const props = defineProps<{
|
|||||||
evalError: string
|
evalError: string
|
||||||
promoting: boolean
|
promoting: boolean
|
||||||
deleting: boolean
|
deleting: boolean
|
||||||
statusOptions: { value: string; labelKey: string }[]
|
statusOptions: { value: IdeaStatus; labelKey: string }[]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'evaluate'): void
|
(e: 'evaluate'): void
|
||||||
(e: 'promote'): void
|
(e: 'promote'): void
|
||||||
(e: 'delete'): void
|
(e: 'delete'): void
|
||||||
(e: 'status-change', value: string): void
|
(e: 'status-change', value: IdeaStatus): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 任意 status 字符串 → 对应 i18n key;未知状态回退到原值显示
|
// 任意 status 字符串 → 对应 i18n key;未知状态回退到原值显示
|
||||||
function statusLabelKey(status: string): string {
|
function statusLabelKey(status: IdeaStatus): string {
|
||||||
return props.statusOptions.find(s => s.value === status)?.labelKey ?? status
|
return props.statusOptions.find(s => s.value === status)?.labelKey ?? status
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ function sentimentClass(sentiment: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onStatusChange(e: Event) {
|
function onStatusChange(e: Event) {
|
||||||
emit('status-change', (e.target as HTMLSelectElement).value)
|
emit('status-change', (e.target as HTMLSelectElement).value as IdeaStatus)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ import { useRouter, useRoute } from 'vue-router'
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from '@arco-design/web-vue'
|
||||||
import { useProjectStore } from '../stores/project'
|
import { useProjectStore } from '../stores/project'
|
||||||
|
import type { IdeaStatus } from '../api/types'
|
||||||
import { parseTags } from '../stores/knowledge'
|
import { parseTags } from '../stores/knowledge'
|
||||||
import { formatDate } from '../utils/time'
|
import { formatDate } from '../utils/time'
|
||||||
import { stripMd } from '../utils/markdown'
|
import { stripMd } from '../utils/markdown'
|
||||||
@@ -150,7 +151,7 @@ const filters: { key: FilterKey; labelKey: string; icon: string }[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
// ── 状态映射(单一数据源,列表/详情/下拉共用) ──
|
// ── 状态映射(单一数据源,列表/详情/下拉共用) ──
|
||||||
const statusOptions: { value: string; labelKey: string }[] = [
|
const statusOptions: { value: IdeaStatus; labelKey: string }[] = [
|
||||||
{ value: 'draft', labelKey: 'ideas.status.draft' },
|
{ value: 'draft', labelKey: 'ideas.status.draft' },
|
||||||
{ value: 'pending_review', labelKey: 'ideas.status.pending_review' },
|
{ value: 'pending_review', labelKey: 'ideas.status.pending_review' },
|
||||||
{ value: 'approved', labelKey: 'ideas.status.approved' },
|
{ value: 'approved', labelKey: 'ideas.status.approved' },
|
||||||
@@ -159,7 +160,7 @@ const statusOptions: { value: string; labelKey: string }[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
// 任意 status 字符串 → 对应 i18n key;未知状态回退到原值显示
|
// 任意 status 字符串 → 对应 i18n key;未知状态回退到原值显示
|
||||||
function statusLabelKey(status: string): string {
|
function statusLabelKey(status: IdeaStatus): string {
|
||||||
return statusOptions.find(s => s.value === status)?.labelKey ?? status
|
return statusOptions.find(s => s.value === status)?.labelKey ?? status
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +273,7 @@ async function evaluateCurrentIdea() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onStatusChange(newStatus: string) {
|
async function onStatusChange(newStatus: IdeaStatus) {
|
||||||
if (!currentIdea.value) return
|
if (!currentIdea.value) return
|
||||||
await store.updateIdea(currentIdea.value.id, 'status', newStatus)
|
await store.updateIdea(currentIdea.value.id, 'status', newStatus)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user