diff --git a/frontend/src/views/KPIDetail.vue b/frontend/src/views/KPIDetail.vue index 41bacbfb..e62ad893 100644 --- a/frontend/src/views/KPIDetail.vue +++ b/frontend/src/views/KPIDetail.vue @@ -85,7 +85,7 @@ - 保存 + 保存 @@ -305,6 +305,7 @@ const fullNetworkLoading = ref(false) // 编辑未保存离开确认(统一守卫 composable) const isDirty = ref(false) useFormGuard(isDirty) +const saving = ref(false) let kpiSnapshot: string = '' let watchInitialized = false @@ -539,6 +540,8 @@ const fullNetworkChartOption = computed(() => { }) async function save() { + if (saving.value) return + saving.value = true try { await kpiApi.update(kpi.value.id, kpi.value) ElMessage.success('保存成功') @@ -549,6 +552,8 @@ async function save() { kpiSnapshot = JSON.stringify(kpi.value) } catch (e) { ElMessage.error('保存失败') + } finally { + saving.value = false } } diff --git a/frontend/src/views/KPIList.vue b/frontend/src/views/KPIList.vue index 2f6b338e..64dd81e4 100644 --- a/frontend/src/views/KPIList.vue +++ b/frontend/src/views/KPIList.vue @@ -140,9 +140,10 @@ - - + @@ -260,7 +261,7 @@ @@ -417,6 +418,31 @@ async function loadUsers() { const showForm = ref(false) const editMode = ref(false) const form = ref({}) +const saving = ref(false) + +// ── 编辑入口:列表行 → 弹窗编辑(与新建一致)── +function openEdit(row: any) { + editMode.value = true + form.value = { + id: row.id, + kpi_code: row.kpi_code, + kpi_name: row.kpi_name, + dimension: row.dimension, + category: row.category, + target_value: row.target_value, + unit: row.unit, + frequency: row.frequency, + data_source_type: row.data_source_type, + responsible_dept: row.responsible_dept, + responsible_user: row.responsible_user, + formula: row.formula, + threshold_green: row.threshold_green, + threshold_yellow: row.threshold_yellow, + threshold_red: row.threshold_red, + epic: row.epic, + } + showForm.value = true +} // ── 未保存离开守卫 ── const isDirty = ref(false) @@ -610,6 +636,8 @@ function onDimensionChange(val: string) { } async function saveKPI() { + if (saving.value) return + saving.value = true try { if (editMode.value) { await kpiApi.update(form.value.id, form.value) @@ -624,6 +652,8 @@ async function saveKPI() { loadCategories() } catch (e) { ElMessage.error(editMode.value ? '保存失败' : '创建失败') + } finally { + saving.value = false } } diff --git a/frontend/src/views/UserManage.vue b/frontend/src/views/UserManage.vue index 0ce976b1..13bc3ed0 100644 --- a/frontend/src/views/UserManage.vue +++ b/frontend/src/views/UserManage.vue @@ -49,7 +49,7 @@ @@ -66,6 +66,7 @@ const loading = ref(false) const showForm = ref(false) const isEdit = ref(false) const form = ref({}) +const saving = ref(false) function roleLabel(role: string) { const map: Record = { ceo: 'CEO', finance: '财务', business: '业务', it: 'IT管理' } @@ -94,6 +95,8 @@ function openForm(row: any) { } async function saveUser() { + if (saving.value) return + saving.value = true try { if (isEdit.value) { const payload: any = {} @@ -106,6 +109,7 @@ async function saveUser() { } else { if (!form.value.username || !form.value.password) { ElMessage.warning('用户名和密码必填') + saving.value = false return } await userApi.create(form.value) @@ -115,6 +119,8 @@ async function saveUser() { load() } catch (e) { ElMessage.error('操作失败') + } finally { + saving.value = false } }