diff --git a/backend/app/api/kpis.py b/backend/app/api/kpis.py
index 58303c18..0c21d3f8 100644
--- a/backend/app/api/kpis.py
+++ b/backend/app/api/kpis.py
@@ -425,6 +425,15 @@ def delete_kpi(kpi_id: int, db: Session = Depends(get_db), user=WRITE_ROLES):
return {"message": "已删除"}
+@router.put("/{kpi_id}/restore")
+def restore_kpi(kpi_id: int, db: Session = Depends(get_db), user=WRITE_ROLES):
+ kpi = db.query(KPIDefinition).filter(KPIDefinition.id == kpi_id).first()
+ if kpi:
+ kpi.status = "active"
+ db.commit()
+ return {"message": "已恢复"}
+
+
def kpi_to_dict(k):
d = {c.name: getattr(k, c.name) for c in k.__table__.columns}
# 附加战略地图信息
diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts
index 0dafd47b..3efe72ce 100644
--- a/frontend/src/api/index.ts
+++ b/frontend/src/api/index.ts
@@ -34,6 +34,7 @@ export const kpiApi = {
create: (data: any) => api.post('/kpis', data),
update: (id: number, data: any) => api.put(`/kpis/${id}`, data),
delete: (id: number) => api.delete(`/kpis/${id}`),
+ restore: (id: number) => api.put(`/kpis/${id}/restore`),
listCategories: () => api.get('/kpis/categories'),
associateMap: (id: number, data: any) => api.put(`/kpis/${id}/associate-map`, data),
// KPI-5: 五档评分
diff --git a/frontend/src/views/KPIList.vue b/frontend/src/views/KPIList.vue
index dbd90bd3..2c60f536 100644
--- a/frontend/src/views/KPIList.vue
+++ b/frontend/src/views/KPIList.vue
@@ -59,7 +59,11 @@
-
+
+
+
+
+
查询
重置
@@ -139,7 +143,8 @@
编辑
- 删除
+ 归档
+ 恢复
@@ -365,6 +370,7 @@ const pageSize = 20
const searchKeyword = ref('')
const searchDimension = ref('')
const searchCategory = ref('')
+const searchStatus = ref('active')
// ── 企业选择 ──
const entities = ref([])
@@ -484,6 +490,7 @@ async function loadKpis() {
if (searchKeyword.value) params.keyword = searchKeyword.value
if (searchDimension.value) params.dimension = searchDimension.value
if (searchCategory.value) params.category = searchCategory.value
+ if (searchStatus.value) params.status = searchStatus.value
if (treeFilterDims.value.length > 0 && !params.dimension) params.dimension = treeFilterDims.value.join(',')
if (treeFilterCats.value.length > 0 && !params.category) params.category = treeFilterCats.value.join(',')
@@ -533,7 +540,7 @@ function onSelectionChange(rows: any[]) {
}
function batchDelete() {
- ElMessageBox.confirm(`确定删除选中的 ${selectedIds.value.length} 条KPI?`, '提示').then(async () => {
+ ElMessageBox.confirm(`确定归档选中的 ${selectedIds.value.length} 条KPI?`, '提示').then(async () => {
for (const id of selectedIds.value) {
try { await kpiApi.delete(id) } catch (e) {}
}
@@ -544,6 +551,14 @@ function batchDelete() {
}).catch(() => {})
}
+function doRestore(id: number) {
+ ElMessageBox.confirm('确定恢复此KPI?', '提示').then(async () => {
+ await kpiApi.restore(id)
+ ElMessage.success('已恢复')
+ loadKpis()
+ }).catch(() => {})
+}
+
function batchExport() {
const header = '编码,名称,维度,二级类别,目标值,频率,数据源,负责人,计算公式'
const rows = kpis.value.map((k: any) =>