docs: v1.5.1 - watermark fix, student_goals placeholder, cleanup duplicate checklist
This commit is contained in:
@@ -164,8 +164,8 @@ piano-plan/
|
||||
|
||||
---
|
||||
|
||||
> **版本**:v1.5.0
|
||||
> **版本**:v1.5.1
|
||||
> **创建时间**:2026-04-17
|
||||
> **最后更新**:2026-04-27
|
||||
> **最后更新**:2026-04-28
|
||||
>
|
||||
> **重要更新**:v1.5.0 - 数据统计页面(问题/级别分布可视化);PDF水印配置;编辑页按钮吸底;侧边栏调整
|
||||
> **重要更新**:v1.5.1 - PDF水印配置保存修复;{student_goals}占位符修复
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import sqlite3
|
||||
|
||||
def get_templates(db_path):
|
||||
conn = sqlite3.connect(db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT id, name, type, sort_order FROM templates ORDER BY type, sort_order")
|
||||
rows = c.fetchall()
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
dev_path = r"D:\F\NewI\opencode\daily-workspace\projects\青年钢琴集体课\练习方案系统\data\piano_plans.db"
|
||||
prod_path = r"D:\F\NewI\opencode\daily-workspace\projects\青年钢琴集体课\练习方案系统\temp_prod.db"
|
||||
|
||||
dev_rows = get_templates(dev_path)
|
||||
prod_rows = get_templates(prod_path)
|
||||
|
||||
with open("temp_templates_compare.txt", "w", encoding="utf-8") as f:
|
||||
f.write("=== DEV TEMPLATES ===\n")
|
||||
for r in dev_rows:
|
||||
f.write(f"ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}\n")
|
||||
|
||||
f.write("\n=== PROD TEMPLATES ===\n")
|
||||
for r in prod_rows:
|
||||
f.write(f"ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}\n")
|
||||
|
||||
f.write("\n=== COMPARISON ===\n")
|
||||
dev_ids = {r[0] for r in dev_rows}
|
||||
prod_ids = {r[0] for r in prod_rows}
|
||||
only_dev = dev_ids - prod_ids
|
||||
only_prod = prod_ids - dev_ids
|
||||
same_ids = dev_ids & prod_ids
|
||||
|
||||
if only_dev:
|
||||
f.write(f"ONLY IN DEV: IDs {only_dev}\n")
|
||||
for r in dev_rows:
|
||||
if r[0] in only_dev:
|
||||
f.write(f" ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}\n")
|
||||
if only_prod:
|
||||
f.write(f"ONLY IN PROD: IDs {only_prod}\n")
|
||||
for r in prod_rows:
|
||||
if r[0] in only_prod:
|
||||
f.write(f" ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}\n")
|
||||
if same_ids:
|
||||
dev_map = {r[0]: r for r in dev_rows}
|
||||
prod_map = {r[0]: r for r in prod_rows}
|
||||
for i in sorted(same_ids):
|
||||
d = dev_map[i]
|
||||
p = prod_map[i]
|
||||
if d != p:
|
||||
f.write(f"DIFF ID={i}:\n")
|
||||
f.write(f" DEV: name={d[1]} type={d[2]} sort={d[3]}\n")
|
||||
f.write(f" PROD: name={p[1]} type={p[2]} sort={p[3]}\n")
|
||||
else:
|
||||
f.write(f"ID={i}: IDENTICAL\n")
|
||||
|
||||
print("done")
|
||||
+8
-17
@@ -1,12 +1,12 @@
|
||||
# 钢琴练习方案系统 - 部署 SOP
|
||||
|
||||
> 版本:v1.5.0
|
||||
> 日期:2026-04-27
|
||||
> 版本:v1.5.1
|
||||
> 日期:2026-04-28
|
||||
> 核心原则:**不删除,只备份后新增/替换**
|
||||
|
||||
---
|
||||
|
||||
## 重要更新(v1.5.0)
|
||||
## 重要更新(v1.5.1)
|
||||
|
||||
### ⚠️ 问题文件已迁移到数据库
|
||||
|
||||
@@ -408,17 +408,7 @@ A: 检查是否执行了 migrate_goals_v3.py 迁移脚本,该脚本创建 stud
|
||||
[ ] 学员列表"暂无方案/问题"样式正常
|
||||
[ ] PDF 水印功能正常(配置后导出可见)
|
||||
[ ] 数据统计页面正常显示
|
||||
```
|
||||
[ ] 容器状态:running
|
||||
[ ] 服务响应:HTTP 200/302
|
||||
[ ] 数据库表完整:users, students, classes, student_problems, practice_plans, templates, problems, goals, goal_relations, student_goals, student_goal_evaluations
|
||||
[ ] practice_plans 表有新字段:created_by, updated_by, updated_at, template_id, is_typical
|
||||
[ ] 目标管理功能正常:创建目标、分配目标、评估目标
|
||||
[ ] 时间线正常显示阶段评估和最终评估
|
||||
[ ] API 配置正确
|
||||
[ ] 功能验证:能生成练习方案
|
||||
[ ] 方案列表支持删除
|
||||
[ ] 学员列表"暂无方案/问题"样式正常
|
||||
[ ] 导出PDF时 {student_goals} 正常显示学员目标
|
||||
```
|
||||
|
||||
---
|
||||
@@ -427,7 +417,8 @@ A: 检查是否执行了 migrate_goals_v3.py 迁移脚本,该脚本创建 stud
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| v1.5.0 | 2026-04-27 | 数据统计页面(问题/级别分布可视化);PDF水印配置(可自定义文本);编辑页按钮吸底;侧边栏顺序调整;MySQL字体问题修复(Linux) |
|
||||
| v1.5.1 | 2026-04-28 | PDF水印配置保存修复(3处漏改);{student_goals}占位符修复;移除目标导出时的"内容:"标签 |
|
||||
| v1.5.0 | 2026-04-27 | 数据统计页面(问题/级别分布可视化);PDF水印配置(可自定义文本);编辑页按钮吸底;侧边栏顺序调整;Linux中文字体路径修复 |
|
||||
| v1.4.0 | 2026-04-27 | 典型方案采纳;推荐方案列表;方案编辑/详情页导航优化(bfcache处理);审计字段完善(created_by/updated_by/updated_at);方案列表支持删除;学员列表"暂无方案/问题"样式统一 |
|
||||
| v1.3.6 | 2026-04-24 | 方案详情导航优化;典型方案开关移至方案详情;方案列表显示问题级别+严重程度 |
|
||||
| v1.3.5 | 2026-04-24 | 班级班主任字段;用户姓名name字段;班级/学员/方案增加"我的"筛选 |
|
||||
@@ -442,5 +433,5 @@ A: 检查是否执行了 migrate_goals_v3.py 迁移脚本,该脚本创建 stud
|
||||
|
||||
---
|
||||
|
||||
> **最后更新**:2026-04-27
|
||||
> **更新原因**:v1.5.0 发布;数据统计页面;PDF水印;编辑页吸底按钮;Linux中文字体路径
|
||||
> **最后更新**:2026-04-28
|
||||
> **更新原因**:v1.5.1 补丁;PDF水印保存漏改;{student_goals}占位符修复;清理重复检查清单
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import sqlite3, sys
|
||||
|
||||
def get_templates(db_path):
|
||||
conn = sqlite3.connect(db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT id, name, type, sort_order FROM templates ORDER BY type, sort_order")
|
||||
rows = c.fetchall()
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
dev_path = "D:/F/NewI/opencode/daily-workspace/projects/青年钢琴集体课/练习方案系统/data/piano_plans.db"
|
||||
prod_path = "D:/F/NewI/opencode/daily-workspace/projects/青年钢琴集体课/练习方案系统/temp_prod_piano.db"
|
||||
|
||||
import shutil
|
||||
shutil.copy("\\\\?\\UNC\\47.115.32.206\\ipc$\\tmp\\prod_piano.db", prod_path)
|
||||
|
||||
dev_rows = get_templates(dev_path)
|
||||
prod_rows = get_templates(prod_path)
|
||||
|
||||
print("=== DEV TEMPLATES ===")
|
||||
for r in dev_rows:
|
||||
print(f"ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
|
||||
print()
|
||||
print("=== PROD TEMPLATES ===")
|
||||
for r in prod_rows:
|
||||
print(f"ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
|
||||
print()
|
||||
dev_ids = {r[0] for r in dev_rows}
|
||||
prod_ids = {r[0] for r in prod_rows}
|
||||
only_dev = dev_ids - prod_ids
|
||||
only_prod = prod_ids - dev_ids
|
||||
same_ids = dev_ids & prod_ids
|
||||
|
||||
if only_dev:
|
||||
print(f"=== ONLY IN DEV: IDs {only_dev} ===")
|
||||
for r in dev_rows:
|
||||
if r[0] in only_dev:
|
||||
print(f" ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
if only_prod:
|
||||
print(f"=== ONLY IN PROD: IDs {only_prod} ===")
|
||||
for r in prod_rows:
|
||||
if r[0] in only_prod:
|
||||
print(f" ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
if same_ids:
|
||||
print(f"=== IN BOTH (comparing) ===")
|
||||
dev_map = {r[0]: r for r in dev_rows}
|
||||
prod_map = {r[0]: r for r in prod_rows}
|
||||
for i in sorted(same_ids):
|
||||
d = dev_map[i]
|
||||
p = prod_map[i]
|
||||
if d != p:
|
||||
print(f" ID={i}:")
|
||||
print(f" DEV: name={d[1]} type={d[2]} sort={d[3]}")
|
||||
print(f" PROD: name={p[1]} type={p[2]} sort={p[3]}")
|
||||
else:
|
||||
print(f" ID={i}: IDENTICAL")
|
||||
@@ -0,0 +1,55 @@
|
||||
import sqlite3
|
||||
|
||||
def get_templates(db_path):
|
||||
conn = sqlite3.connect(db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT id, name, type, sort_order FROM templates ORDER BY type, sort_order")
|
||||
rows = c.fetchall()
|
||||
conn.close()
|
||||
return rows
|
||||
|
||||
dev_path = r"D:\F\NewI\opencode\daily-workspace\projects\青年钢琴集体课\练习方案系统\data\piano_plans.db"
|
||||
prod_path = r"D:\F\NewI\opencode\daily-workspace\projects\青年钢琴集体课\练习方案系统\temp_prod.db"
|
||||
|
||||
dev_rows = get_templates(dev_path)
|
||||
prod_rows = get_templates(prod_path)
|
||||
|
||||
print("=== DEV TEMPLATES ===")
|
||||
for r in dev_rows:
|
||||
print(f"ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
|
||||
print()
|
||||
print("=== PROD TEMPLATES ===")
|
||||
for r in prod_rows:
|
||||
print(f"ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
|
||||
print()
|
||||
dev_ids = {r[0] for r in dev_rows}
|
||||
prod_ids = {r[0] for r in prod_rows}
|
||||
only_dev = dev_ids - prod_ids
|
||||
only_prod = prod_ids - dev_ids
|
||||
same_ids = dev_ids & prod_ids
|
||||
|
||||
if only_dev:
|
||||
print(f"=== ONLY IN DEV: IDs {only_dev} ===")
|
||||
for r in dev_rows:
|
||||
if r[0] in only_dev:
|
||||
print(f" ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
if only_prod:
|
||||
print(f"=== ONLY IN PROD: IDs {only_prod} ===")
|
||||
for r in prod_rows:
|
||||
if r[0] in only_prod:
|
||||
print(f" ID={r[0]} | {r[1]} | type={r[2]} | sort={r[3]}")
|
||||
if same_ids:
|
||||
print(f"=== IN BOTH (comparing) ===")
|
||||
dev_map = {r[0]: r for r in dev_rows}
|
||||
prod_map = {r[0]: r for r in prod_rows}
|
||||
for i in sorted(same_ids):
|
||||
d = dev_map[i]
|
||||
p = prod_map[i]
|
||||
if d != p:
|
||||
print(f" ID={i}:")
|
||||
print(f" DEV: name={d[1]} type={d[2]} sort={d[3]}")
|
||||
print(f" PROD: name={p[1]} type={p[2]} sort={p[3]}")
|
||||
else:
|
||||
print(f" ID={i}: IDENTICAL")
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
=== DEV TEMPLATES ===
|
||||
ID=3 | 简单文字版 | type=ai_prompt | sort=0
|
||||
ID=1 | 正式报告版 | type=ai_prompt | sort=1
|
||||
ID=4 | 报告导出模板(简洁版) | type=report | sort=0
|
||||
ID=2 | 报告导出模板 | type=report | sort=1
|
||||
|
||||
=== PROD TEMPLATES ===
|
||||
ID=1 | 正式报告版 | type=ai_prompt | sort=0
|
||||
ID=3 | 简单文字版 | type=ai_prompt | sort=1
|
||||
ID=4 | 报告导出模板(简洁版) | type=report | sort=0
|
||||
ID=2 | 报告导出模板(备份,勿用) | type=report | sort=1
|
||||
|
||||
=== COMPARISON ===
|
||||
DIFF ID=1:
|
||||
DEV: name=正式报告版 type=ai_prompt sort=1
|
||||
PROD: name=正式报告版 type=ai_prompt sort=0
|
||||
DIFF ID=2:
|
||||
DEV: name=报告导出模板 type=report sort=1
|
||||
PROD: name=报告导出模板(备份,勿用) type=report sort=1
|
||||
DIFF ID=3:
|
||||
DEV: name=简单文字版 type=ai_prompt sort=0
|
||||
PROD: name=简单文字版 type=ai_prompt sort=1
|
||||
ID=4: IDENTICAL
|
||||
Reference in New Issue
Block a user