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 @@
取消
- {{ editMode ? '保存' : '创建' }}
+ {{ editMode ? '保存' : '创建' }}
@@ -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
}
}