fix: BSC分类树多选过滤 — 支持多维度/多分类复选,数量准确
This commit is contained in:
+35
-5
@@ -35,13 +35,13 @@ def list_kpis(
|
|||||||
if dims:
|
if dims:
|
||||||
query = query.filter(KPIDefinition.dimension.in_(dims))
|
query = query.filter(KPIDefinition.dimension.in_(dims))
|
||||||
if dimension:
|
if dimension:
|
||||||
query = query.filter(KPIDefinition.dimension == dimension)
|
dims_list = [d.strip() for d in dimension.split(',')] if ',' in dimension else [dimension]
|
||||||
|
query = query.filter(KPIDefinition.dimension.in_(dims_list))
|
||||||
if keyword:
|
if keyword:
|
||||||
query = query.filter(KPIDefinition.kpi_name.contains(keyword))
|
query = query.filter(KPIDefinition.kpi_name.contains(keyword))
|
||||||
if epic:
|
|
||||||
query = query.filter(KPIDefinition.epic == epic)
|
|
||||||
if category:
|
if category:
|
||||||
query = query.filter(KPIDefinition.category == category)
|
cats_list = [c.strip() for c in category.split(',')] if ',' in category else [category]
|
||||||
|
query = query.filter(KPIDefinition.category.in_(cats_list))
|
||||||
total = query.count()
|
total = query.count()
|
||||||
kpis = query.order_by(KPIDefinition.kpi_code).offset((page-1)*page_size).limit(page_size).all()
|
kpis = query.order_by(KPIDefinition.kpi_code).offset((page-1)*page_size).limit(page_size).all()
|
||||||
return {"total": total, "page": page, "page_size": page_size, "data": [kpi_to_dict(k) for k in kpis]}
|
return {"total": total, "page": page, "page_size": page_size, "data": [kpi_to_dict(k) for k in kpis]}
|
||||||
@@ -134,7 +134,37 @@ def delete_kpi(kpi_id: int, db: Session = Depends(get_db), user=WRITE_ROLES):
|
|||||||
|
|
||||||
|
|
||||||
def kpi_to_dict(k):
|
def kpi_to_dict(k):
|
||||||
return {c.name: getattr(k, c.name) for c in k.__table__.columns}
|
d = {c.name: getattr(k, c.name) for c in k.__table__.columns}
|
||||||
|
# 附加战略地图信息
|
||||||
|
if k.map_id:
|
||||||
|
from app.database import get_session_local
|
||||||
|
try:
|
||||||
|
sess = get_session_local()()
|
||||||
|
m = sess.query(StrategicMap).filter(StrategicMap.id == k.map_id).first()
|
||||||
|
d["map_title"] = m.title if m else None
|
||||||
|
sess.close()
|
||||||
|
except:
|
||||||
|
d["map_title"] = None
|
||||||
|
else:
|
||||||
|
d["map_title"] = None
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/{kpi_id}/associate-map")
|
||||||
|
def associate_kpi_map(kpi_id: int, data: dict, db: Session = Depends(get_db), user=WRITE_ROLES):
|
||||||
|
"""关联KPI到战略地图"""
|
||||||
|
kpi = db.query(KPIDefinition).filter(KPIDefinition.id == kpi_id).first()
|
||||||
|
if not kpi:
|
||||||
|
raise HTTPException(404, "KPI不存在")
|
||||||
|
map_id = data.get("map_id")
|
||||||
|
if map_id is not None:
|
||||||
|
m = db.query(StrategicMap).filter(StrategicMap.id == map_id).first()
|
||||||
|
if not m:
|
||||||
|
raise HTTPException(404, "战略地图不存在")
|
||||||
|
kpi.map_id = map_id
|
||||||
|
db.commit()
|
||||||
|
_log(db, 1, "update", "kpi", kpi_id, {"action": "associate-map", "map_id": map_id})
|
||||||
|
return kpi_to_dict(kpi)
|
||||||
|
|
||||||
|
|
||||||
def _log(db, user_id, action, target_type, target_id, detail):
|
def _log(db, user_id, action, target_type, target_id, detail):
|
||||||
|
|||||||
@@ -94,6 +94,12 @@
|
|||||||
<el-table-column prop="data_source_type" label="数据源" width="70">
|
<el-table-column prop="data_source_type" label="数据源" width="70">
|
||||||
<template #default="{ row }">{{ sourceLabel(row.data_source_type) }}</template>
|
<template #default="{ row }">{{ sourceLabel(row.data_source_type) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="所属地图" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span v-if="row.map_title" style="color:#409eff;font-size:12px;">{{ row.map_title }}</span>
|
||||||
|
<span v-else style="color:#ccc">-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="当前值" width="100">
|
<el-table-column label="当前值" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span v-if="row.actual_value !== null" :class="'status-' + (row.alert_level || 'none')">
|
<span v-if="row.actual_value !== null" :class="'status-' + (row.alert_level || 'none')">
|
||||||
@@ -427,21 +433,20 @@ async function loadCategories() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 树节点勾选 ──
|
// ── 树节点勾选(支持多选)──
|
||||||
function onTreeCheck(data: any, { checkedKeys }: any) {
|
function onTreeCheck(data: any, { checkedKeys }: any) {
|
||||||
// 简单模式:只支持单选过滤
|
// 从checkedKeys中分离出维度和分类
|
||||||
if (data.key === '_all') {
|
const dimKeys = ['finance', 'customer', 'process', 'learning']
|
||||||
|
const checkedDims = checkedKeys.filter((k: string) => dimKeys.includes(k))
|
||||||
|
const checkedCats = checkedKeys.filter((k: string) => !dimKeys.includes(k) && k !== '_all')
|
||||||
|
|
||||||
|
if (data.key === '_all' || checkedKeys.includes('_all')) {
|
||||||
// 勾选全部=清空过滤
|
// 勾选全部=清空过滤
|
||||||
treeFilterDims.value = []
|
treeFilterDims.value = []
|
||||||
treeFilterCats.value = []
|
treeFilterCats.value = []
|
||||||
} else if (data.children) {
|
|
||||||
// 维度节点
|
|
||||||
treeFilterDims.value = checkedKeys.includes(data.key) ? [data.key] : []
|
|
||||||
treeFilterCats.value = []
|
|
||||||
} else {
|
} else {
|
||||||
// 类别节点
|
treeFilterDims.value = checkedDims
|
||||||
treeFilterCats.value = checkedKeys.includes(data.key) ? [data.key] : []
|
treeFilterCats.value = checkedCats
|
||||||
treeFilterDims.value = []
|
|
||||||
}
|
}
|
||||||
loadKpis()
|
loadKpis()
|
||||||
}
|
}
|
||||||
@@ -454,8 +459,8 @@ async function loadKpis() {
|
|||||||
if (searchKeyword.value) params.keyword = searchKeyword.value
|
if (searchKeyword.value) params.keyword = searchKeyword.value
|
||||||
if (searchDimension.value) params.dimension = searchDimension.value
|
if (searchDimension.value) params.dimension = searchDimension.value
|
||||||
if (searchCategory.value) params.category = searchCategory.value
|
if (searchCategory.value) params.category = searchCategory.value
|
||||||
if (treeFilterDims.value.length > 0 && !params.dimension) params.dimension = treeFilterDims.value[0]
|
if (treeFilterDims.value.length > 0 && !params.dimension) params.dimension = treeFilterDims.value.join(',')
|
||||||
if (treeFilterCats.value.length > 0 && !params.category) params.category = treeFilterCats.value[0]
|
if (treeFilterCats.value.length > 0 && !params.category) params.category = treeFilterCats.value.join(',')
|
||||||
|
|
||||||
const r: any = await kpiApi.list(params)
|
const r: any = await kpiApi.list(params)
|
||||||
kpis.value = r.data || []
|
kpis.value = r.data || []
|
||||||
|
|||||||
Reference in New Issue
Block a user