fix: 自动创建KPI补全target_value/kpi_level+文件名中文日期解析
- 补NOT NULL字段: target_value=0, kpi_level='operational' - 文件名支持中文日期: 2026年01月 / 2026年01月至2026年05月 - 科目余额表列名匹配增强: 余额/本年累计/本期发生额 - 期间列识别: 年/月开头列名
This commit is contained in:
+18
-6
@@ -89,15 +89,20 @@ _SMART_MAP = {
|
||||
"period_patterns": [
|
||||
re.compile(r'^(period|期间|月份?|年月|日期|会计期间)$', re.I),
|
||||
re.compile(r'^(报表期[间]?|所属期)$'),
|
||||
re.compile(r'^年|^月'), # 以"年"或"月"开头的列
|
||||
],
|
||||
# 数值列匹配
|
||||
"value_patterns": [
|
||||
re.compile(r'^(actual_?value|数值|实际值|实际金额)$', re.I),
|
||||
re.compile(r'^(本期金额|本月数|本期|期末余额|期末数)$'),
|
||||
re.compile(r'^(金额|数据|value)$', re.I),
|
||||
re.compile(r'^(本期金额|本月数|本期|期末余额|期末数|余额)$'),
|
||||
re.compile(r'^(金额|数据|value|本年累计|本期发生[额]?)$', re.I),
|
||||
],
|
||||
# 文件名→期间提取
|
||||
"period_in_filename": re.compile(r'[-_]?(\d{4})[-_]?(\d{1,2})'),
|
||||
"period_in_filename_patterns": [
|
||||
re.compile(r'[-_]?(\d{4})[-_]?(\d{1,2})'), # 2026-06 / 2026_06 / 2606
|
||||
re.compile(r'(\d{4})年(\d{1,2})月(?:至(\d{4})年(\d{1,2})月)?'), # 2026年01月 / 2026年01月至2026年05月
|
||||
re.compile(r'(\d{4})(\d{2})'), # 202606 (纯数字6-8位)
|
||||
],
|
||||
# 文件名→报表类型
|
||||
"statement_types": {
|
||||
"利润表": "PL",
|
||||
@@ -139,9 +144,14 @@ def _smart_detect_value_col(cols: list[str]) -> str | None:
|
||||
|
||||
|
||||
def _smart_extract_period_from_filename(filename: str) -> str | None:
|
||||
m = _SMART_MAP["period_in_filename"].search(filename)
|
||||
if m:
|
||||
return f"{m.group(1)}-{int(m.group(2)):02d}"
|
||||
for pat in _SMART_MAP["period_in_filename_patterns"]:
|
||||
m = pat.search(filename)
|
||||
if m:
|
||||
groups = m.groups()
|
||||
if len(groups) == 4 and groups[2]: # 2026年01月至2026年05月 → 取结束月
|
||||
return f"{groups[2]}-{int(groups[3]):02d}"
|
||||
if len(groups) >= 2: # 2026-06 或 2026年01月
|
||||
return f"{int(groups[0])}-{int(groups[1]):02d}"
|
||||
return None
|
||||
|
||||
|
||||
@@ -255,6 +265,8 @@ async def import_excel_smart(file: UploadFile = File(...), db: Session = Depends
|
||||
data_owner="财务部",
|
||||
frequency="monthly",
|
||||
unit="元",
|
||||
target_value=0,
|
||||
kpi_level="operational",
|
||||
status="active",
|
||||
)
|
||||
db.add(new_kpi)
|
||||
|
||||
@@ -9,10 +9,10 @@ interface MenuItem {
|
||||
|
||||
// ── 角色路由映射 ──
|
||||
export const ROLE_ROUTES: Record<string, string[]> = {
|
||||
ceo: ['/my-dashboard', '/dashboard', '/kpis', '/maps', '/maps-review', '/maps/canvas', '/maps/review', '/alerts', '/notifications', '/org', '/users', '/permissions', '/budget', '/deviations', '/cost', '/predict', '/action-plans', '/knowledge', '/guide', '/customer', '/learning-dashboard', '/reports', '/alignment', '/dupont-analysis'],
|
||||
finance: ['/my-dashboard', '/dashboard', '/kpis', '/maps', '/maps-review', '/maps/canvas', '/maps/review', '/alerts', '/data', '/budget', '/deviations', '/cost', '/predict', '/action-plans', '/knowledge', '/guide', '/customer', '/learning-dashboard', '/reports', '/alignment', '/dupont-analysis'],
|
||||
ceo: ['/my-dashboard', '/dashboard', '/kpis', '/maps', '/maps-review', '/maps/canvas', '/maps/review', '/alerts', '/notifications', '/org', '/users', '/permissions', '/budget', '/deviations', '/cost', '/predict', '/action-plans', '/knowledge', '/guide', '/customer', '/learning-dashboard', '/reports', '/alignment', '/dupont-analysis', '/analysis-confidence'],
|
||||
finance: ['/my-dashboard', '/dashboard', '/kpis', '/maps', '/maps-review', '/maps/canvas', '/maps/review', '/alerts', '/data', '/budget', '/deviations', '/cost', '/predict', '/action-plans', '/knowledge', '/guide', '/customer', '/learning-dashboard', '/reports', '/alignment', '/dupont-analysis', '/analysis-confidence'],
|
||||
business: ['/my-dashboard', '/dashboard', '/kpis', '/alerts', '/budget', '/deviations', '/action-plans', '/knowledge', '/guide', '/customer'],
|
||||
it: ['/my-dashboard', '/dashboard', '/kpis', '/alerts', '/data', '/org', '/users', '/permissions', '/budget', '/deviations', '/cost', '/predict', '/action-plans', '/knowledge', '/guide', '/customer', '/learning-dashboard'],
|
||||
it: ['/my-dashboard', '/dashboard', '/kpis', '/alerts', '/data', '/org', '/users', '/permissions', '/budget', '/deviations', '/cost', '/predict', '/action-plans', '/knowledge', '/guide', '/customer', '/learning-dashboard', '/analysis-confidence'],
|
||||
}
|
||||
|
||||
export const ROLE_ACTIONS: Record<string, string[]> = {
|
||||
@@ -49,6 +49,7 @@ export const MENU_ITEMS: MenuItem[] = [
|
||||
{ path: '/predict', label: '预测模拟', icon: 'DataLine', roles: ['ceo', 'finance', 'it'], group: '🔴 A 复盘与改进' },
|
||||
{ path: '/mpm-calculator', label: 'MPM计算器', icon: 'Money', roles: ['ceo', 'finance', 'business'], group: '🔴 A 复盘与改进' },
|
||||
{ path: '/data-quality', label: '数据质量', icon: 'WarningFilled', roles: ['ceo', 'finance', 'it'], group: '🔴 A 复盘与改进' },
|
||||
{ path: '/analysis-confidence', label: '分析置信度', icon: 'TrendCharts', roles: ['ceo', 'finance', 'it'], group: '🔴 A 复盘与改进' },
|
||||
|
||||
// ── GROUP 5: 基础数据与知识──
|
||||
{ path: '/kpis', label: 'KPI字典', icon: 'Document', roles: ['ceo', 'finance', 'business', 'it'], group: '基础数据与知识' },
|
||||
|
||||
@@ -40,6 +40,7 @@ const routes = [
|
||||
{ path: 'subjects', name: 'SubjectManage', component: () => import('@/views/SubjectManage.vue'), meta: { title: '科目打标', roles: ['ceo', 'finance', 'business', 'it'] } },
|
||||
{ path: 'mpm-calculator', name: 'MpmCalculator', component: () => import('@/views/MpmCalculator.vue'), meta: { title: 'MPM计算器', roles: ['ceo', 'finance', 'business'] } },
|
||||
{ path: 'bot-kpis', name: 'BotKpis', component: () => import('@/views/BotKpiDashboard.vue'), meta: { title: 'Bot KPI看板', roles: ['ceo', 'finance', 'it'] } },
|
||||
{ path: 'analysis-confidence', name: 'AnalysisConfidence', component: () => import('@/views/AnalysisConfidence.vue'), meta: { title: '分析置信度', roles: ['ceo', 'finance', 'it'] } },
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user