统一状态流转为前端状态机

This commit is contained in:
Cheng Zhou
2025-12-17 20:52:55 +08:00
parent c074c2b5bc
commit c2328594b0
15 changed files with 361 additions and 188 deletions
+28 -21
View File
@@ -6,18 +6,28 @@
<h3>AE不良事件</h3>
<p>{{ ae.term }}</p>
</div>
<PermissionAction action="ae.close">
<el-button :type="ae.status === 'CLOSED' ? 'primary' : 'danger'" size="small" @click="toggleClose">
{{ ae.status === "CLOSED" ? "重新打开" : "关闭" }}
</el-button>
</PermissionAction>
<div class="action-buttons">
<template v-for="action in availableActions" :key="action.key">
<PermissionAction action="ae.close">
<el-button
size="small"
:type="action.danger ? 'danger' : 'primary'"
@click="onAction(action)"
>
{{ action.label }}
</el-button>
</PermissionAction>
</template>
</div>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="受试者ID">{{ ae.subject_id }}</el-descriptions-item>
<el-descriptions-item label="严重性">{{ ae.seriousness }}</el-descriptions-item>
<el-descriptions-item label="严重程度">{{ ae.severity }}</el-descriptions-item>
<el-descriptions-item label="发生日期">{{ ae.onset_date }}</el-descriptions-item>
<el-descriptions-item label="状态">{{ statusLabel(ae.status) }}</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="stateColor(aeState)">{{ stateLabel(aeState) }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="描述">{{ ae.description }}</el-descriptions-item>
</el-descriptions>
</el-card>
@@ -52,6 +62,8 @@ import CommentList from "../components/CommentList.vue";
import AttachmentList from "../components/attachments/AttachmentList.vue";
import PermissionAction from "../components/PermissionAction.vue";
import { usePermission } from "../utils/permission";
import { aeMachine, getAvailableActions, getStateColor, getStateLabel } from "../state-machine";
import type { ActionConfig } from "../state-machine";
const route = useRoute();
const study = useStudyStore();
@@ -61,7 +73,10 @@ const ae = ref<any | null>(null);
const studyId = computed(() => study.currentStudy?.id || "");
const { can } = usePermission();
const canClose = computed(() => can("ae.close"));
const aeState = computed(() => (ae.value?.status as string) || "NEW");
const availableActions = computed(() => getAvailableActions(aeMachine, aeState.value));
const stateLabel = (v?: string | null) => getStateLabel(aeMachine, v);
const stateColor = (v?: string | null) => getStateColor(aeMachine, v) || "info";
const enrichOverdue = (item: any) => {
if (!item) return item;
@@ -84,15 +99,14 @@ const load = async () => {
}
};
const toggleClose = async () => {
const onAction = async (action: ActionConfig) => {
if (!study.currentStudy || !ae.value) return;
const targetStatus = ae.value.status === "CLOSED" ? "FOLLOW_UP" : "CLOSED";
await ElMessageBox.confirm(
`确定将该 AE 状态设置为 ${targetStatus === "CLOSED" ? "已关闭" : "随访中"}?该操作不可撤销,请谨慎确认。`,
"提示"
);
if (action.confirm) {
const ok = await ElMessageBox.confirm(action.confirmText || "确认执行该操作?", "提示").catch(() => null);
if (!ok) return;
}
try {
const resp = await updateAe(study.currentStudy.id, ae.value.id, { status: targetStatus });
const resp = await updateAe(study.currentStudy.id, ae.value.id, { status: action.to });
ElMessage.success("状态已更新");
ae.value = enrichOverdue(resp.data);
await load();
@@ -101,13 +115,6 @@ const toggleClose = async () => {
}
};
const statusLabel = (v: string) =>
({
NEW: "新增",
FOLLOW_UP: "随访中",
CLOSED: "已关闭",
}[v] || v);
onMounted(async () => {
if (!auth.user && auth.token) {
await auth.fetchMe().catch(() => {});