From 957dacd248ec543ef8ea572fb94620020dba3356 Mon Sep 17 00:00:00 2001 From: Hermes CI Fix Date: Mon, 13 Jul 2026 09:52:06 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8D5=E4=B8=AA=E8=A2=ABCI?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E7=9A=84=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6?= =?UTF-8?q?+=E6=88=90=E6=9C=AC=E6=95=B0=E6=8D=AE+=E9=A2=84=E8=AD=A6?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E5=99=A8=20-=20=E4=BB=8E.bak=E6=81=A2?= =?UTF-8?q?=E5=A4=8D:=20BudgetManagement(72%=E4=BB=A3=E7=A0=81=E4=B8=A2?= =?UTF-8?q?=E5=A4=B1)/KPIList/DeviationDashboard/MapReview/NodeEditDialog?= =?UTF-8?q?=20-=20=E6=B3=A8=E5=86=8C4=E4=B8=AA=E7=BC=BA=E5=A4=B1=E5=90=8E?= =?UTF-8?q?=E7=AB=AFAPI=E6=A8=A1=E5=9D=97=E5=88=B0main.py=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E3=E4=B8=AA=E5=89=8D=E7=AB=AF=E8=B7=AF=E7=94=B1(?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=8A=A5=E8=A1=A8/=E6=88=98=E7=95=A5?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E7=9C=8B=E6=9D=BF/=E6=9D=9C=E9=82=A6?= =?UTF-8?q?=E5=88=86=E6=9E=90)=20-=20=E4=BF=AE=E5=A4=8D=E6=94=B9=E5=96=84?= =?UTF-8?q?=E8=A1=8C=E5=8A=A8=E8=B7=AF=E7=94=B1=E6=8C=87=E5=90=91ActionPla?= =?UTF-8?q?nLibrary(=E5=8E=9F=E6=8C=87=E5=90=91AlertList)=20-=20deploy.sh?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0git=20pull=E6=AD=A5=E9=AA=A4=20-=20=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=88=90=E6=9C=AC=E7=A7=8D=E5=AD=90=E6=95=B0=E6=8D=AE?= =?UTF-8?q?:=2029=E6=A0=87=E5=87=86=E6=88=90=E6=9C=AC+31=E5=AE=9E=E9=99=85?= =?UTF-8?q?=E6=88=90=E6=9C=AC+10ABC+25=E5=88=86=E9=85=8D=20-=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E9=9D=9E=E8=B4=A2=E5=8A=A1KPI=E9=A2=84=E7=AE=97:=2072?= =?UTF-8?q?=E6=9D=A1(=E5=AE=A2=E6=88=B7/=E6=B5=81=E7=A8=8B/=E5=AD=A6?= =?UTF-8?q?=E4=B9=A0=E7=BB=B4=E5=BA=A6)=20-=20=E9=85=8D=E7=BD=AE=E9=A2=84?= =?UTF-8?q?=E8=AD=A6cron:=20=E6=AF=8F30=E5=88=86=E9=92=9F=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/__pycache__/main.cpython-312.pyc | Bin 7481 -> 7894 bytes backend/scripts/seed_nonfinance_budget.py | 51 ++ deploy.sh | 8 +- frontend/components.d.ts | 2 + .../strategy-map/NodeEditDialog.vue | 242 +++---- frontend/src/views/BudgetManagement.vue | 668 +++++++++++------- frontend/src/views/DeviationDashboard.vue | 335 +++++---- frontend/src/views/KPIList.vue | 185 ++++- frontend/src/views/MapReview.vue | 10 +- 9 files changed, 994 insertions(+), 507 deletions(-) create mode 100644 backend/scripts/seed_nonfinance_budget.py diff --git a/backend/app/__pycache__/main.cpython-312.pyc b/backend/app/__pycache__/main.cpython-312.pyc index 1ab30f568396d028e3c9ce172d2d542b963ec7c5..e531c0e93b5826019c062473625834ac177cc835 100644 GIT binary patch delta 2200 zcmah~O>7%Q6yCAdj`L^7cH*D3uJhY?ogb4zq}ELn3W&?VnMN5bYO%MewDJHd1aTIV0P+HY7 zZCsqtQsN`F-=m_Mjg6im&2(j@U!kE+*?|vH>O=WU}22)=7HCUCtiB z>M_Ku6lSs!CL3k4y-fBHlReyE?fJgs+4CJ?R*Ey(J|^4GWCxh+Ad?+xu=adqH+#OL z%t|9nHo;^CCYxlkqYd_Cx_I?JZq4leEmOjfS0ZqBg;$~*{Qlh)A1Al&8a~q^xSk-^ zoA{NM{^6-+j$_54#NZskBO9(}&OA}Rjqg50*>^zslwFhe2qzb)^U~{d6GGwnb zd>}t#uax%);0%7(a~;HRr1jT~706W#v!p>JDYB7YF3Cu-yb8Qhkj+9#m&z3*Z~2xh z$|Yz@m!J-jY(gt=Sud@skOU+CnGrWXCzz95H9{^^SV~X<}J? zL0>7|=6<1lqbDiM@54O4+8G0x>ieCefHe1&chWsgxl{O0Zy3zrkncDNpY!#`X`bbk z6|JC45S1lkP0t~b1kaM!Si!gbvFb;@bujug@fWk`8S;ac2vmFo_C9@Y?~Bd74{rSQ z$&H`i+C=vkS@QR$XQ=R53Ks|%Jb^y)*o|7De=jI0XiY*D9lc0Y7pfon7aT#lhUG@k zsHo?i`2Fi z4rLj=OuZKf7%l>|v-_Fn3v!RftRjK_Zc>A9t?;u!Q5G^BpTRk^VuDB>Z|P z>?#twjBkaeK?c`D>1>Mlg2QqfrfgOWG)Y{v(1Z-N?45V#p{$yDq?5>N_dp3e-*eJXw6XWSI6Q+ULS@l5=Z+ zD0^EFo!oA}F<*1EKRnY~NvWuC25k@t-7Le&bKE^A0N^`r;Cs&d12s<1;=){@ozb2oeR{sz~)Rnn5YF4JDl)O ZY_=X0YC&O#OEzN%ldD6A{eY(v{0$K%%mx4e delta 1968 zcmai!O>7%Q6vsX5UE?J6N1ZxrJGl93(z>B>gQ!)Uq$DCC1(h@{E~?xHv+<6xm-Pp; zYofxTMrtLHDwK2tXSg7>k=lbLBrYJ%?V%hfXir?Ia^MDtiVM6MH+CwpW~Kf6y_w&8 zJO9}oKb-p}?Z4;q^}66n&1Z~Hf?NKGWO%oZe49Zo9qB#hk#Zt?v^<%8j_1ARvGPTorczHTIja-ro_ieKlaPbTodMn$j7#Rin8ag~w+&kKe^}sf2McET{6NQx&P8n5t z8zrMD2Yl!yRHK zWz_%Ygv{)oC|$*}9>FsOS&v?mch6~d7EaiQ^m%VWIR(*G`nGpue7apD6(l{5=Rpr% zQ`$8PKwhU`bs>lMkT3I|zd`p!9>sb_!mQi)9%hMmTkT1pSLg>l*HQFl?;p*%z9Gr; z0{9^(=(_K$G7sSl{o41_$Q(qDT&fhRw_LwN>>@8QS=f~YddD9}OU?WKNdz4q2c|tI z+1!gX8B|f4E(cG-a3dHSVs(yR)61nw4wG8Wx>CuLH(_uYZmU3@P`vpt*g%t~Az#Um zSK)`80jUQ-cJ6+*^WEmomp6XBbK}v+o8-wuJ_^OsX$HQ|ZZNh_jp)US>Kg}*V(7lYE!yqYwMbYNtV79j;~!} zHA>#B!pJJb;j0TfUuQ4Sz4&Iw0sfg-_2CLvEqj>ob!yKa$Vkdno=EU}31 zyr+mY(=HMNMmFHKd>{?iF9WeJHh$t_wLx?RkbOS*324UJ$jLH~)4qB%Mm zTP*PXn`fxE3ZKUNxMK6~%aLnU%jTQPzZ1v(4z~G=8-D mqyY%qJZsxc@5ja_mgT=-pu7IbXPbkA8L9bwd_R&|(|-X(5RZod diff --git a/backend/scripts/seed_nonfinance_budget.py b/backend/scripts/seed_nonfinance_budget.py new file mode 100644 index 00000000..1c7a58da --- /dev/null +++ b/backend/scripts/seed_nonfinance_budget.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +"""补充非财务KPI预算数据 — 客户/流程/学习维度 +运行: python3 scripts/seed_nonfinance_budget.py +""" +import sys, os +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from app.database import get_session_local +from app.models import KPIDefinition, BudgetPlan +import logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s') +logger = logging.getLogger("seed_nonfinance") + +def seed(): + db = get_session_local()() + try: + kpi_map = {k.kpi_code: k.id for k in db.query(KPIDefinition).all()} + codes = ["C_SATISFACTION", "C_NEW_CLIENTS", "P_DELIVERY", "P_BUG_RATE", "L_TRAINING", "L_EMPLOYEE_SAT"] + # 年度预算值 + annual_budget = { + "C_SATISFACTION": 92, "C_NEW_CLIENTS": 120, + "P_DELIVERY": 95, "P_BUG_RATE": 2, + "L_TRAINING": 90, "L_EMPLOYEE_SAT": 85, + } + cnt = 0 + existing = set((r.kpi_id, r.period) for r in db.query(BudgetPlan).all()) + for code in codes: + kid = kpi_map.get(code) + if not kid: continue + annual = annual_budget[code] + for month in range(1, 13): + if (kid, f"2026-{month:02d}") in existing: + continue + db.add(BudgetPlan( + kpi_id=kid, period=f"2026-{month:02d}", + budget_value=annual if code != "C_NEW_CLIENTS" else annual / 12, + budget_year=2026, budget_month=month, + version="v1.0", status="active", + )) + cnt += 1 + db.commit() + logger.info(f"✅ 补充非财务预算: {cnt}条") + logger.info(f"📊 预算总数: {db.query(BudgetPlan).count()}条") + except Exception as e: + db.rollback() + logger.error(f"❌ 失败: {e}") + finally: + db.close() + +if __name__ == "__main__": + seed() diff --git a/deploy.sh b/deploy.sh index c9965b52..9f7fda77 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,5 +1,5 @@ #!/bin/bash -# 管理会计OS — 一键构建并部署到生产 +# 管理会计OS — 一键拉取、构建并部署到生产 set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" @@ -7,6 +7,12 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" echo "===== 管理会计OS 生产部署 =====" echo "" +# 0. 拉取最新代码 +echo "[0/4] 拉取最新代码..." +cd "$SCRIPT_DIR" +git pull origin main +echo " ✓ 代码已更新" + # 1. 构建前端 echo "[1/4] 构建前端..." cd "$SCRIPT_DIR/frontend" diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 339f87d7..1352c6b3 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -47,6 +47,7 @@ declare module 'vue' { ElRow: typeof import('element-plus/es')['ElRow'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElSkeleton: typeof import('element-plus/es')['ElSkeleton'] + ElSlider: typeof import('element-plus/es')['ElSlider'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElTable: typeof import('element-plus/es')['ElTable'] @@ -54,6 +55,7 @@ declare module 'vue' { ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabs: typeof import('element-plus/es')['ElTabs'] ElTag: typeof import('element-plus/es')['ElTag'] + ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTree: typeof import('element-plus/es')['ElTree'] ElUpload: typeof import('element-plus/es')['ElUpload'] GaugeChart: typeof import('./src/components/charts/GaugeChart.vue')['default'] diff --git a/frontend/src/components/strategy-map/NodeEditDialog.vue b/frontend/src/components/strategy-map/NodeEditDialog.vue index 7f598b66..8220f69d 100644 --- a/frontend/src/components/strategy-map/NodeEditDialog.vue +++ b/frontend/src/components/strategy-map/NodeEditDialog.vue @@ -1,64 +1,56 @@ + + diff --git a/frontend/src/views/DeviationDashboard.vue b/frontend/src/views/DeviationDashboard.vue index 2dda9c50..0208a46c 100644 --- a/frontend/src/views/DeviationDashboard.vue +++ b/frontend/src/views/DeviationDashboard.vue @@ -10,13 +10,13 @@ - + - + @@ -26,37 +26,26 @@ 导出CSV - +
已录预算KPI
-
{{ stats.total_budget || 0 }}
+
{{ stats.total_kpis || 0 }}
- - + +
-
超预算(红色)
-
{{ stats.red_count || 0 }}
-
-
-
- - -
-
接近阈值(黄色)
-
{{ stats.yellow_count || 0 }}
-
-
-
- - -
-
正常达标
-
{{ stats.normal_count || 0 }}
+
{{ dim.icon }} {{ dim.name }}
+
+ {{ dim.summary.deviation_rate != null ? dim.summary.deviation_rate.toFixed(1) + '%' : '-' }} +
+
+ {{ dim.summary.has_budget }}/{{ dim.summary.count }} KPI有预算 +
@@ -97,71 +86,110 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - +