工作台改版: - 学会→学术, 总工作台→总览(数据库迁移+session清理) - 侧边栏工作台从下拉菜单改为竖向平铺+独立图标 - 5个工作台去除部门模块, 只有总览显示 - 工作台顺序: 总览→学术→MCN→科普→医患→科研 经营月报+季度月报: - 月度/季度总览改名(月度总览→经营月报, 季度总览→季度月报) - 财务概览增加回款/项目现金流行(7行) - 新增业务线经营情况卡片(毛利/平台费用/利润) - 新增业务线现金流卡片(项目现金流/平台费用已付/业务线现金流) - 季度月报完善为三卡片结构, 与经营月报一致 - 计划模块总览独立数据源(computePlanMonthly) UI优化: - 汇总卡片单行显示+5x2网格+去外层卡片 - 项目表格行高压缩(py-px+line-height:0.95) - 表头不压缩, 只压缩tbody - 加权/项目类型内联下拉去原生箭头+自定义箭头 - 加权/项目类型表头去除排序箭头 - 实际模块已付→支出, 已回款→回款, 成本→成本(不含平台费用) - 现金流注释(回款-支出) - 卡片间距/筛选区/tip高度压缩 - 实际模块增加执行提示tip 修复: - routes.py planFinances client_name列去重 - plan_expense.js savePlanExpense改用api()+load() - plan.js createPlanFinance拆分try-catch - 版本号 v1.0.0.35
160 lines
5.7 KiB
Python
160 lines
5.7 KiB
Python
"""migrations/data_fixes.py — 数据修正迁移(修复脏数据、变更枚举值)"""
|
||
|
||
|
||
def migrate_fix_task_status():
|
||
"""修正 project_tasks 中非法的 status 值"""
|
||
from db import db, _exec, mysql, logger
|
||
|
||
conn = db()
|
||
try:
|
||
fixes = [
|
||
"UPDATE project_tasks SET status='未开始' WHERE status='' OR status IS NULL",
|
||
"UPDATE project_tasks SET status='已结束' WHERE status='done'",
|
||
"UPDATE project_tasks SET status='进行中' WHERE status='验收中'",
|
||
]
|
||
for sql in fixes:
|
||
try:
|
||
cur = _exec(conn, sql)
|
||
affected = cur.rowcount
|
||
cur.close()
|
||
if affected:
|
||
print(f"[migrate] 修正 {affected} 条任务状态")
|
||
except mysql.connector.Error as e:
|
||
logger.warning(f"task status fix skipped: {e}")
|
||
conn.commit()
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def migrate_rename_tenant():
|
||
"""工作台重命名:无界·无界 → 学会·无界"""
|
||
from db import db, _exec, mysql
|
||
|
||
conn = db()
|
||
try:
|
||
tables = ["user_tenants", "sales_leads", "follow_up_records", "business_proposals",
|
||
"operation_projects", "product_versions", "finance_records", "project_tasks",
|
||
"project_finances"]
|
||
for table in tables:
|
||
try:
|
||
cur = _exec(conn, f"UPDATE {table} SET tenant='学会·无界' WHERE tenant='无界·无界'")
|
||
affected = cur.rowcount
|
||
cur.close()
|
||
if affected:
|
||
print(f"[migrate] {table}: {affected} 条记录 tenant 改为 '学会·无界'")
|
||
except mysql.connector.Error:
|
||
pass
|
||
conn.commit()
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def migrate_drop_product_fields():
|
||
"""删除 product_versions 表的 owner / platform / feature_list 字段"""
|
||
from db import db, mysql
|
||
|
||
conn = db()
|
||
try:
|
||
for col in ["owner", "platform", "feature_list"]:
|
||
cur = conn.cursor(dictionary=True)
|
||
cur.execute("SHOW COLUMNS FROM product_versions LIKE %s", (col,))
|
||
exists = cur.fetchone()
|
||
cur.close()
|
||
if exists:
|
||
try:
|
||
cur = conn.cursor()
|
||
cur.execute(f"ALTER TABLE product_versions DROP COLUMN {col}")
|
||
cur.close()
|
||
conn.commit()
|
||
print(f"[migrate] product_versions.{col} 列已删除")
|
||
except mysql.connector.Error as e:
|
||
print(f"[migrate] 删除 {col} 失败: {e}")
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def migrate_fix_service_fee_standard():
|
||
"""修正 project_finances.service_fee_standard 旧数据为默认值 5(5%)"""
|
||
from db import db
|
||
|
||
conn = db()
|
||
try:
|
||
cur = conn.cursor()
|
||
cur.execute(
|
||
"UPDATE project_finances SET service_fee_standard = 5 "
|
||
"WHERE service_fee_standard = 0 OR service_fee_standard IS NULL "
|
||
"OR service_fee_standard NOT IN (5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25)"
|
||
)
|
||
affected = cur.rowcount
|
||
cur.close()
|
||
if affected:
|
||
conn.commit()
|
||
print(f"[migrate] project_finances: {affected} 条记录 service_fee_standard 修正为 5")
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def migrate_fix_expense_status():
|
||
"""修正 expense_records 中空的 status 为默认值「计入费用」"""
|
||
from db import db
|
||
|
||
conn = db()
|
||
try:
|
||
cur = conn.cursor()
|
||
cur.execute(
|
||
"UPDATE expense_records SET status='计入费用' "
|
||
"WHERE status IS NULL OR status='' OR status='待审批'"
|
||
)
|
||
affected = cur.rowcount
|
||
cur.close()
|
||
if affected:
|
||
conn.commit()
|
||
print(f"[migrate] expense_records: {affected} 条记录 status 修正为 '计入费用'")
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
|
||
def migrate_rename_xuehui_to_xueshu():
|
||
"""工作台重命名:学会·无界 → 学术·无界"""
|
||
from db import db, _exec, mysql
|
||
conn = db()
|
||
try:
|
||
tables = ["project_finances", "plan_finances", "expense_records", "plan_expense_records",
|
||
"sales_leads", "business_proposals", "product_versions", "operation_projects",
|
||
"follow_up_records", "project_tasks", "finance_records", "users", "user_tenants"]
|
||
for table in tables:
|
||
try:
|
||
cur = _exec(conn, f"UPDATE {table} SET tenant='学术·无界' WHERE tenant='学会·无界'")
|
||
affected = cur.rowcount
|
||
cur.close()
|
||
if affected:
|
||
conn.commit()
|
||
print(f"[migrate] {table}: {affected} 条记录 tenant 改为 '学术·无界'")
|
||
except mysql.connector.Error:
|
||
pass
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def migrate_rename_zong_to_overview():
|
||
"""工作台重命名:总工作台 → 总览"""
|
||
from db import db, _exec, mysql
|
||
conn = db()
|
||
try:
|
||
tables = ["project_finances", "plan_finances", "expense_records", "plan_expense_records",
|
||
"sales_leads", "business_proposals", "product_versions", "operation_projects",
|
||
"follow_up_records", "project_tasks", "finance_records", "users", "user_tenants"]
|
||
for table in tables:
|
||
try:
|
||
cur = _exec(conn, f"UPDATE {table} SET tenant='总览' WHERE tenant='总工作台'")
|
||
affected = cur.rowcount
|
||
cur.close()
|
||
if affected:
|
||
conn.commit()
|
||
print(f"[migrate] {table}: {affected} 条记录 tenant 改为 '总览'")
|
||
except mysql.connector.Error:
|
||
pass
|
||
finally:
|
||
conn.close()
|