From cc468027cac21e54825d0d851fd611868ba30db7 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 16 Oct 2026 20:02:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20actually=20commit=20app/server/db.mjs=20?= =?UTF-8?q?with=20demo=5Fseed=20+=20DEMO=20data=20(was=20never=20staged=20?= =?UTF-8?q?-=20root=20cause=20of=20=E6=9C=AA=E7=9F=A5=E5=91=BD=E4=BB=A4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/server/db.mjs | 103 ++++++++++++++++++++++++++++++++++++++++++++ app/server/seed.mjs | 80 +++------------------------------- 2 files changed, 110 insertions(+), 73 deletions(-) diff --git a/app/server/db.mjs b/app/server/db.mjs index 1604cdf..5ed63ba 100644 --- a/app/server/db.mjs +++ b/app/server/db.mjs @@ -342,6 +342,79 @@ function openDb(dbPath) { } // 按数据库路径创建一套应用命令(多用户/服务器模式:每个用户一个独立档案库) + +// ---------- 演示数据(demo 账号播种 / 本地 seed 共用) ---------- +// 行格式: [类型, 标题, 角色, 级别, 获奖等级, 主办方, 开始, 结束, 状态, 描述, 结果, 标签, 维度, extras, metrics] +export const DEMO_ROWS = [ + ['竞赛', '2025 全国大学生数学建模竞赛', '主导', '国家级', '省市级二等奖', '中国工业与应用数学学会', '2025-09-05', '2025-09-08', 'finished', + '担任队长,负责模型建立与论文主笔;协调三人分工与时间安排', '重庆赛区二等奖', ['建模', '团队协作'], ['学业深造'], + { my_work: '模型建立与论文主笔', deliverable: '参赛论文《基于优化模型的共享单车调度研究》', team_members: '张三、李四、王五' }, {}], + ['竞赛', '第十六届蓝桥杯程序设计大赛', '参加', '省市级', '省市级二等奖', '工业和信息化部人才交流中心', '2025-04-12', '2025-06-20', 'finished', + '备战算法与数据结构,完成省赛', '重庆赛区 C/C++ B 组二等奖', ['算法'], ['职业发展', '学业深造'], + { my_work: '独立参赛', deliverable: '省赛获奖证书' }, {}], + ['竞赛', '全国大学生信息安全竞赛', '核心', '国家级', null, '教育部高等学校网络空间安全专业教学指导委员会', '2025-05-01', '2025-08-15', 'submitted', + '负责 Web 漏洞挖掘与利用脚本编写,参与作品报告撰写', '已提交作品,等待国赛评审', ['安全', 'CTF'], ['职业发展'], + { my_work: 'Web 漏洞挖掘与利用脚本编写', deliverable: '参赛作品与报告' }, {}], + ['志愿公益', '校图书馆迎新志愿服务', '参加', '校级', null, '校图书馆', '2025-09-01', '2025-09-05', 'finished', + '新生入馆引导与借阅咨询,共服务 5 天', '获馆方感谢信', ['志愿'], ['综合素养'], + { hours: 24, contact: '李老师' }, { volunteer_hours: 24 }], + ['志愿公益', '社区敬老院慰问活动', '参加', '区县级', null, '所在社区居委会', '2025-03-15', '2025-03-15', 'finished', + '陪伴老人、协助整理活动室', '', ['志愿', '公益'], ['综合素养'], + { hours: 6 }, { volunteer_hours: 6 }], + ['学生工作', '院学生会宣传部干事', '参加', '院级', null, '院学生会', '2024-09-01', '2025-06-30', 'finished', + '负责活动推文撰写与排版,全年产出推文 20 篇', '获优秀干事', ['宣传'], ['综合素养'], + { duties: '推文撰写与排版、活动现场摄影', term: '2024.09 - 2025.06' }, {}], + ['学生工作', '院学生会宣传部副部长', '主导', '院级', null, '院学生会', '2025-09-01', null, 'ongoing', + '统筹部门工作,管理 8 名干事,主导院级活动宣传方案', '', ['管理'], ['综合素养', '职业发展'], + { duties: '部门统筹、活动宣传方案设计', term: '2025.09 - 至今' }, {}], + ['荣誉惩处', '校级二等奖学金', '参加', '校级', null, '重庆城市科技学院', '2025-10-15', '2025-10-15', 'finished', + '2024-2025 学年综合测评前列', '二等奖学金', ['奖学金'], ['学业深造'], + { issued_by: '重庆城市科技学院' }, {}], + ['荣誉惩处', '优秀共青团员', '参加', '校级', null, '校团委', '2025-05-04', '2025-05-04', 'finished', + '五四表彰', '优秀共青团员', ['表彰'], ['综合素养'], + { issued_by: '共青团重庆城市科技学院委员会' }, {}], + ['证书技能', '大学英语六级', '参加', '国家级', null, '教育部教育考试院', '2025-06-14', '2025-08-20', 'finished', + '笔试 528 分', 'CET-6 528 分', ['英语'], ['学业深造', '职业发展'], + { cert_no: '510001251200123', score: '528' }, {}], + ['证书技能', '计算机技术与软件专业技术资格(中级)', '参加', '国家级', null, '工业和信息化部', '2025-11-08', null, 'ongoing', + '备考软件设计师', '', ['软考'], ['职业发展'], + { score: '' }, {}], + ['学业', '2024-2025 学年秋季学期', '参加', null, null, null, '2024-09-01', '2025-01-15', 'finished', + '学期绩点 3.72,专业排名 12/156', '', ['绩点'], ['学业深造'], + { semester_label: '2024-2025-1' }, {}], + ['学业', '2024-2025 学年春季学期', '参加', null, null, null, '2025-02-24', '2025-07-05', 'finished', + '学期绩点 3.85,专业排名 9/156', '', ['绩点'], ['学业深造'], + { semester_label: '2024-2025-2' }, {}], + ['文体活动', '校运动会开幕式方阵', '参加', '校级', null, '校体育运动委员会', '2025-04-18', '2025-04-20', 'finished', + '学院方阵队员,参与排练与开幕式表演', '', ['文体'], ['兴趣生活'], + { participation: '方阵队员' }, {}], + ['科研', '大学生创新创业训练计划项目', '主导', '校级', null, '校创新创业学院', '2025-03-01', null, 'ongoing', + '主持校级大创项目「基于流量特征的入侵检测研究」,带 2 名成员', '中期检查通过', ['科研', '安全'], ['学业深造', '职业发展'], + { authors: '主持人', outcome: '研究报告' }, {}], + ['实习实践', '某安全公司渗透测试实习生', '参加', null, null, '某网络安全科技有限公司', '2025-07-01', '2025-08-25', 'finished', + '参与企业授权渗透测试项目 3 个,编写测试报告', '获实习优秀评价', ['实习', '安全'], ['职业发展'], + { position: '渗透测试实习生', mentor: '陈工' }, {}] +]; +// 学期: { term, gpa, rank, total, courses: [课程名, 学分, 分数, 绩点][] } +export const DEMO_SEMESTERS = [ + { term: '2023-2024-1', gpa: 3.42, rank: 38, total: 156, courses: [ + ['高等数学(上)', 5, 78, 3.0], ['大学英语(一)', 3, 85, 3.7], ['程序设计基础', 4, 91, 4.0], + ['思想道德与法治', 2, 88, 3.9], ['体育(一)', 1, 82, 3.5] + ]}, + { term: '2023-2024-2', gpa: 3.61, rank: 29, total: 156, courses: [ + ['高等数学(下)', 5, 84, 3.7], ['线性代数', 3, 76, 2.9], ['数据结构', 4, 90, 4.0], + ['大学英语(二)', 3, 87, 3.8], ['中国近现代史纲要', 2, 84, 3.5], ['体育(二)', 1, 86, 3.8] + ]}, + { term: '2024-2025-1', gpa: 3.78, rank: 18, total: 156, courses: [ + ['概率论与数理统计', 3, 88, 3.9], ['操作系统', 4, 92, 4.0], ['计算机网络', 4, 86, 3.8], + ['数据库原理', 3, 94, 4.0], ['马克思主义基本原理', 2, 81, 3.3] + ]}, + { term: '2024-2025-2', gpa: 3.85, rank: 12, total: 156, courses: [ + ['软件工程', 3, 90, 4.0], ['信息安全导论', 3, 95, 4.0], ['密码学基础', 3, 89, 3.9], + ['Web 应用开发', 2, 96, 4.0], ['数字逻辑', 3, 79, 3.1], ['体育(四)', 1, 90, 4.0] + ]} +]; + export function createAppCommands(dbPath) { const db = openDb(dbPath); const DATA_DIR = path.dirname(dbPath); // 工厂内遮蔽顶层默认值:附件按用户目录 @@ -1006,6 +1079,36 @@ function listFootprints(d, query) { return { ok: true }; } + case 'demo_seed': { + // 演示数据播种(仅当档案库为空时;走真实命令层,附带同步元数据与 oplog) + const fpCnt = d.prepare('SELECT COUNT(*) AS c FROM footprint WHERE deleted_at IS NULL').get().c; + const semCnt = d.prepare('SELECT COUNT(*) AS c FROM semester WHERE deleted_at IS NULL').get().c; + if (fpCnt > 0 || semCnt > 0) return { seeded: false, footprints: fpCnt, semesters: semCnt }; + const typeIds = Object.fromEntries(d.prepare('SELECT id, name FROM footprint_type').all().map((r) => [r.name, r.id])); + const dimIds = Object.fromEntries(d.prepare('SELECT id, name FROM dimension').all().map((r) => [r.name, r.id])); + let n = 0; + for (const [t, title, role, level, grade, organizer, start, end, status, desc, result, tags, dimNames, extras, metrics] of DEMO_ROWS) { + const typeId = typeIds[t]; + if (!typeId) continue; + handleCommand('footprint_upsert', { item: { + type_id: typeId, title, role, level, award_grade: grade, organizer, + start_date: start, end_date: end, status, description: desc, result, + tags, metrics, extras, + dimension_ids: (dimNames || []).map((nm) => dimIds[nm]).filter(Boolean), + }}); + n++; + } + let sems = 0; + for (const s of DEMO_SEMESTERS) { + const r = handleCommand('semester_upsert', { term: s.term, gpa: s.gpa, rank: s.rank, total_students: s.total }); + const sid = r.item.id; + for (const [name, credit, score, gp] of s.courses) { + handleCommand('course_upsert', { semester_id: sid, course_name: name, credit, score, grade_point: gp }); + } + sems++; + } + return { seeded: true, footprints: n, semesters: sems }; + } case 'sync_apply_wire': return applyWireBatch(payload.changes || []); diff --git a/app/server/seed.mjs b/app/server/seed.mjs index b4cc07e..545516f 100644 --- a/app/server/seed.mjs +++ b/app/server/seed.mjs @@ -1,5 +1,5 @@ // 演示数据:仅当足迹表为空时写入,用于界面验收 -import { getDb, buildSearchText, migrateSync, uuidv7, hlcNext } from './db.mjs'; +import { getDb, buildSearchText, migrateSync, uuidv7, hlcNext, DEMO_ROWS, DEMO_SEMESTERS } from './db.mjs'; const db = getDb(); const count = db.prepare('SELECT COUNT(*) AS c FROM footprint').get().c; @@ -16,63 +16,14 @@ const dims = Object.fromEntries( ); // [type, title, role, level, grade, organizer, start, end, status, desc, result, tags, dims, extras, metrics] -const rows = [ - ['竞赛', '2025 全国大学生数学建模竞赛', '主导', '国家级', '省市级二等奖', '中国工业与应用数学学会', '2025-09-05', '2025-09-08', 'finished', - '担任队长,负责模型建立与论文主笔;协调三人分工与时间安排', '重庆赛区二等奖', ['建模', '团队协作'], ['学业深造'], - { my_work: '模型建立与论文主笔', deliverable: '参赛论文《基于优化模型的共享单车调度研究》', team_members: '张三、李四、王五' }, {}], - ['竞赛', '第十六届蓝桥杯程序设计大赛', '参加', '省市级', '省市级二等奖', '工业和信息化部人才交流中心', '2025-04-12', '2025-06-20', 'finished', - '备战算法与数据结构,完成省赛', '重庆赛区 C/C++ B 组二等奖', ['算法'], ['职业发展', '学业深造'], - { my_work: '独立参赛', deliverable: '省赛获奖证书' }, {}], - ['竞赛', '全国大学生信息安全竞赛', '核心', '国家级', null, '教育部高等学校网络空间安全专业教学指导委员会', '2025-05-01', '2025-08-15', 'submitted', - '负责 Web 漏洞挖掘与利用脚本编写,参与作品报告撰写', '已提交作品,等待国赛评审', ['安全', 'CTF'], ['职业发展'], - { my_work: 'Web 漏洞挖掘与利用脚本编写', deliverable: '参赛作品与报告' }, {}], - ['志愿公益', '校图书馆迎新志愿服务', '参加', '校级', null, '校图书馆', '2025-09-01', '2025-09-05', 'finished', - '新生入馆引导与借阅咨询,共服务 5 天', '获馆方感谢信', ['志愿'], ['综合素养'], - { hours: 24, contact: '李老师' }, { volunteer_hours: 24 }], - ['志愿公益', '社区敬老院慰问活动', '参加', '区县级', null, '所在社区居委会', '2025-03-15', '2025-03-15', 'finished', - '陪伴老人、协助整理活动室', '', ['志愿', '公益'], ['综合素养'], - { hours: 6 }, { volunteer_hours: 6 }], - ['学生工作', '院学生会宣传部干事', '参加', '院级', null, '院学生会', '2024-09-01', '2025-06-30', 'finished', - '负责活动推文撰写与排版,全年产出推文 20 篇', '获优秀干事', ['宣传'], ['综合素养'], - { duties: '推文撰写与排版、活动现场摄影', term: '2024.09 - 2025.06' }, {}], - ['学生工作', '院学生会宣传部副部长', '主导', '院级', null, '院学生会', '2025-09-01', null, 'ongoing', - '统筹部门工作,管理 8 名干事,主导院级活动宣传方案', '', ['管理'], ['综合素养', '职业发展'], - { duties: '部门统筹、活动宣传方案设计', term: '2025.09 - 至今' }, {}], - ['荣誉惩处', '校级二等奖学金', '参加', '校级', null, '重庆城市科技学院', '2025-10-15', '2025-10-15', 'finished', - '2024-2025 学年综合测评前列', '二等奖学金', ['奖学金'], ['学业深造'], - { issued_by: '重庆城市科技学院' }, {}], - ['荣誉惩处', '优秀共青团员', '参加', '校级', null, '校团委', '2025-05-04', '2025-05-04', 'finished', - '五四表彰', '优秀共青团员', ['表彰'], ['综合素养'], - { issued_by: '共青团重庆城市科技学院委员会' }, {}], - ['证书技能', '大学英语六级', '参加', '国家级', null, '教育部教育考试院', '2025-06-14', '2025-08-20', 'finished', - '笔试 528 分', 'CET-6 528 分', ['英语'], ['学业深造', '职业发展'], - { cert_no: '510001251200123', score: '528' }, {}], - ['证书技能', '计算机技术与软件专业技术资格(中级)', '参加', '国家级', null, '工业和信息化部', '2025-11-08', null, 'ongoing', - '备考软件设计师', '', ['软考'], ['职业发展'], - { score: '' }, {}], - ['学业', '2024-2025 学年秋季学期', '参加', null, null, null, '2024-09-01', '2025-01-15', 'finished', - '学期绩点 3.72,专业排名 12/156', '', ['绩点'], ['学业深造'], - { semester_label: '2024-2025-1' }, {}], - ['学业', '2024-2025 学年春季学期', '参加', null, null, null, '2025-02-24', '2025-07-05', 'finished', - '学期绩点 3.85,专业排名 9/156', '', ['绩点'], ['学业深造'], - { semester_label: '2024-2025-2' }, {}], - ['文体活动', '校运动会开幕式方阵', '参加', '校级', null, '校体育运动委员会', '2025-04-18', '2025-04-20', 'finished', - '学院方阵队员,参与排练与开幕式表演', '', ['文体'], ['兴趣生活'], - { participation: '方阵队员' }, {}], - ['科研', '大学生创新创业训练计划项目', '主导', '校级', null, '校创新创业学院', '2025-03-01', null, 'ongoing', - '主持校级大创项目「基于流量特征的入侵检测研究」,带 2 名成员', '中期检查通过', ['科研', '安全'], ['学业深造', '职业发展'], - { authors: '主持人', outcome: '研究报告' }, {}], - ['实习实践', '某安全公司渗透测试实习生', '参加', null, null, '某网络安全科技有限公司', '2025-07-01', '2025-08-25', 'finished', - '参与企业授权渗透测试项目 3 个,编写测试报告', '获实习优秀评价', ['实习', '安全'], ['职业发展'], - { position: '渗透测试实习生', mentor: '陈工' }, {}] -]; +// 数据统一维护在 ./db.mjs(DEMO_ROWS / DEMO_SEMESTERS) const ins = db.prepare(`INSERT INTO footprint (type_id, title, role, level, award_grade, organizer, start_date, end_date, status, description, result, tags, search_text, extras, metrics) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`); const setDim = db.prepare('INSERT OR IGNORE INTO footprint_dimension (footprint_id, dimension_id) VALUES (?,?)'); -for (const [t, title, role, level, grade, organizer, start, end, status, desc, result, tags, dimNames, extras, metrics] of rows) { +for (const [t, title, role, level, grade, organizer, start, end, status, desc, result, tags, dimNames, extras, metrics] of DEMO_ROWS) { const search = buildSearchText(title, desc, result, tags, extras); const r = ins.run(types[t], title, role, level, grade, organizer, start, end, status, desc, result, JSON.stringify(tags), search, JSON.stringify(extras), JSON.stringify(metrics)); @@ -82,39 +33,22 @@ for (const [t, title, role, level, grade, organizer, start, end, status, desc, r } } -console.log('已写入 ' + rows.length + ' 条演示记录'); +console.log('已写入 ' + DEMO_ROWS.length + ' 条演示记录'); // ---------- 学年学科成绩演示 ---------- const semIns = db.prepare('INSERT INTO semester (term, gpa, rank, total_students, uuid, hlc, origin) VALUES (?,?,?,?,?,?,?)'); const couIns = db.prepare('INSERT INTO course_grade (semester_id, course_name, credit, score, grade_point, uuid, hlc, origin) VALUES (?,?,?,?,?,?,?,?)'); -const semData = [ - { term: '2023-2024-1', gpa: 3.42, rank: 38, total: 156, courses: [ - ['高等数学(上)', 5, 78, 3.0], ['大学英语(一)', 3, 85, 3.7], ['程序设计基础', 4, 91, 4.0], - ['思想道德与法治', 2, 88, 3.9], ['体育(一)', 1, 82, 3.5] - ]}, - { term: '2023-2024-2', gpa: 3.61, rank: 29, total: 156, courses: [ - ['高等数学(下)', 5, 84, 3.7], ['线性代数', 3, 76, 2.9], ['数据结构', 4, 90, 4.0], - ['大学英语(二)', 3, 87, 3.8], ['中国近现代史纲要', 2, 84, 3.5], ['体育(二)', 1, 86, 3.8] - ]}, - { term: '2024-2025-1', gpa: 3.78, rank: 18, total: 156, courses: [ - ['概率论与数理统计', 3, 88, 3.9], ['操作系统', 4, 92, 4.0], ['计算机网络', 4, 86, 3.8], - ['数据库原理', 3, 94, 4.0], ['马克思主义基本原理', 2, 81, 3.3] - ]}, - { term: '2024-2025-2', gpa: 3.85, rank: 12, total: 156, courses: [ - ['软件工程', 3, 90, 4.0], ['信息安全导论', 3, 95, 4.0], ['密码学基础', 3, 89, 3.9], - ['Web 应用开发', 2, 96, 4.0], ['数字逻辑', 3, 79, 3.1], ['体育(四)', 1, 90, 4.0] - ]} -]; -for (const s of semData) { + +for (const s of DEMO_SEMESTERS) { const h1 = hlcNext(db); const sid = Number(semIns.run(s.term, s.gpa, s.rank, s.total, uuidv7(), h1, 'seed').lastInsertRowid); for (const [name, credit, score, gp] of s.courses) { couIns.run(sid, name, credit, score, gp, uuidv7(), hlcNext(db), 'seed'); } } -console.log('已写入 ' + semData.length + ' 个学期、' + semData.reduce((a, s) => a + s.courses.length, 0) + ' 门课程成绩'); +console.log('已写入 ' + DEMO_SEMESTERS.length + ' 个学期、' + DEMO_SEMESTERS.reduce((a, s) => a + s.courses.length, 0) + ' 门课程成绩'); migrateSync(getDb()); console.log('同步元数据(uuid/hlc/origin)已回填');