feat: 表单保存交互规范P1+P2+P3 — 保存按钮loading防重复(KPIList/UserManage/KPIDetail)+KPIList编辑弹窗化(详情跳页并存)+保存反馈全面核查
This commit is contained in:
@@ -85,7 +85,7 @@
|
|||||||
<el-form-item label="计算公式"><el-input v-model="kpi.formula" type="textarea" :rows="2" /></el-form-item>
|
<el-form-item label="计算公式"><el-input v-model="kpi.formula" type="textarea" :rows="2" /></el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-form-item><el-button type="primary" @click="save">保存</el-button></el-form-item>
|
<el-form-item><el-button type="primary" :loading="saving" @click="save">保存</el-button></el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- 元数据卡片 -->
|
<!-- 元数据卡片 -->
|
||||||
@@ -305,6 +305,7 @@ const fullNetworkLoading = ref(false)
|
|||||||
// 编辑未保存离开确认(统一守卫 composable)
|
// 编辑未保存离开确认(统一守卫 composable)
|
||||||
const isDirty = ref(false)
|
const isDirty = ref(false)
|
||||||
useFormGuard(isDirty)
|
useFormGuard(isDirty)
|
||||||
|
const saving = ref(false)
|
||||||
let kpiSnapshot: string = ''
|
let kpiSnapshot: string = ''
|
||||||
|
|
||||||
let watchInitialized = false
|
let watchInitialized = false
|
||||||
@@ -539,6 +540,8 @@ const fullNetworkChartOption = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
|
if (saving.value) return
|
||||||
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
await kpiApi.update(kpi.value.id, kpi.value)
|
await kpiApi.update(kpi.value.id, kpi.value)
|
||||||
ElMessage.success('保存成功')
|
ElMessage.success('保存成功')
|
||||||
@@ -549,6 +552,8 @@ async function save() {
|
|||||||
kpiSnapshot = JSON.stringify(kpi.value)
|
kpiSnapshot = JSON.stringify(kpi.value)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ElMessage.error('保存失败')
|
ElMessage.error('保存失败')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,9 +140,10 @@
|
|||||||
<span v-else style="color:#ccc">-</span>
|
<span v-else style="color:#ccc">-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="100" fixed="right">
|
<el-table-column label="操作" width="130" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button size="small" text type="primary" @click.stop="$router.push('/kpis/' + row.id)">编辑</el-button>
|
<el-button size="small" text type="primary" @click.stop="$router.push('/kpis/' + row.id)">详情</el-button>
|
||||||
|
<el-button size="small" text type="primary" @click.stop="openEdit(row)">编辑</el-button>
|
||||||
<el-button v-if="row.status === 'active'" size="small" text type="danger" @click.stop="doDelete(row.id)">归档</el-button>
|
<el-button v-if="row.status === 'active'" size="small" text type="danger" @click.stop="doDelete(row.id)">归档</el-button>
|
||||||
<el-button v-else size="small" text type="success" @click.stop="doRestore(row.id)">恢复</el-button>
|
<el-button v-else size="small" text type="success" @click.stop="doRestore(row.id)">恢复</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -260,7 +261,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="showForm=false">取消</el-button>
|
<el-button @click="showForm=false">取消</el-button>
|
||||||
<el-button type="primary" @click="saveKPI">{{ editMode ? '保存' : '创建' }}</el-button>
|
<el-button type="primary" :loading="saving" @click="saveKPI">{{ editMode ? '保存' : '创建' }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
</MyDialog>
|
</MyDialog>
|
||||||
|
|
||||||
@@ -417,6 +418,31 @@ async function loadUsers() {
|
|||||||
const showForm = ref(false)
|
const showForm = ref(false)
|
||||||
const editMode = ref(false)
|
const editMode = ref(false)
|
||||||
const form = ref<any>({})
|
const form = ref<any>({})
|
||||||
|
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)
|
const isDirty = ref(false)
|
||||||
@@ -610,6 +636,8 @@ function onDimensionChange(val: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function saveKPI() {
|
async function saveKPI() {
|
||||||
|
if (saving.value) return
|
||||||
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
if (editMode.value) {
|
if (editMode.value) {
|
||||||
await kpiApi.update(form.value.id, form.value)
|
await kpiApi.update(form.value.id, form.value)
|
||||||
@@ -624,6 +652,8 @@ async function saveKPI() {
|
|||||||
loadCategories()
|
loadCategories()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ElMessage.error(editMode.value ? '保存失败' : '创建失败')
|
ElMessage.error(editMode.value ? '保存失败' : '创建失败')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="showForm=false">取消</el-button>
|
<el-button @click="showForm=false">取消</el-button>
|
||||||
<el-button type="primary" @click="saveUser">保存</el-button>
|
<el-button type="primary" :loading="saving" @click="saveUser">保存</el-button>
|
||||||
</template>
|
</template>
|
||||||
</MyDialog>
|
</MyDialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,6 +66,7 @@ const loading = ref(false)
|
|||||||
const showForm = ref(false)
|
const showForm = ref(false)
|
||||||
const isEdit = ref(false)
|
const isEdit = ref(false)
|
||||||
const form = ref<any>({})
|
const form = ref<any>({})
|
||||||
|
const saving = ref(false)
|
||||||
|
|
||||||
function roleLabel(role: string) {
|
function roleLabel(role: string) {
|
||||||
const map: Record<string, string> = { ceo: 'CEO', finance: '财务', business: '业务', it: 'IT管理' }
|
const map: Record<string, string> = { ceo: 'CEO', finance: '财务', business: '业务', it: 'IT管理' }
|
||||||
@@ -94,6 +95,8 @@ function openForm(row: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function saveUser() {
|
async function saveUser() {
|
||||||
|
if (saving.value) return
|
||||||
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
if (isEdit.value) {
|
if (isEdit.value) {
|
||||||
const payload: any = {}
|
const payload: any = {}
|
||||||
@@ -106,6 +109,7 @@ async function saveUser() {
|
|||||||
} else {
|
} else {
|
||||||
if (!form.value.username || !form.value.password) {
|
if (!form.value.username || !form.value.password) {
|
||||||
ElMessage.warning('用户名和密码必填')
|
ElMessage.warning('用户名和密码必填')
|
||||||
|
saving.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await userApi.create(form.value)
|
await userApi.create(form.value)
|
||||||
@@ -115,6 +119,8 @@ async function saveUser() {
|
|||||||
load()
|
load()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ElMessage.error('操作失败')
|
ElMessage.error('操作失败')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user