图谱四视图切换(全景/技术栈聚类/职级演进/动态时序)+ 标签按需显示 + NEW 脉动标记(CSS/Canvas 实现,无 emoji)+ 时点对比 Git Style Diff 与证据关键词高亮 + 简历加分项改琥珀色 + 学习路径甘特图
This commit is contained in:
@@ -93,5 +93,48 @@ eq(weak.distinctness, 0, "技能完全重合时差异度为 0");
|
||||
eq(stageEffortText(2), "2 周 / 约 16 小时", "阶段投入文案");
|
||||
eq(stageEffortText(1), "1 周 / 约 8 小时", "单周投入文案");
|
||||
|
||||
/* ganttBars:甘特图横条位置(左偏移/宽度百分比) */
|
||||
const ganttBars = loadFn("ganttBars");
|
||||
const gb = ganttBars([2, 2, 4]);
|
||||
eq(gb.length, 3, "甘特条数");
|
||||
eq(gb[0].left + "," + gb[0].width, "0,25", "甘特首条位置");
|
||||
eq(gb[2].left + "," + gb[2].width, "50,50", "甘特末条位置");
|
||||
eq(ganttBars([4, 4])[1].left, 50, "等长两阶段第二条起点");
|
||||
|
||||
/* diffSkillRows:时点画像 Git 风格差集 */
|
||||
const diffSkillRows = loadFn("diffSkillRows");
|
||||
const d = diffSkillRows(
|
||||
[{ skill: "Java", importance: "required" }, { skill: "JSP", importance: "preferred" }],
|
||||
[{ skill: "Java", importance: "preferred" }, { skill: "Kubernetes", importance: "required" }]);
|
||||
eq(d.add.map((r) => r.skill).join(","), "Kubernetes", "diff 新增");
|
||||
eq(d.del.map((r) => r.skill).join(","), "JSP", "diff 退出");
|
||||
eq(d.keep.length, 1, "diff 保留数");
|
||||
eq(d.keep[0].up, true, "加分升级必备标记");
|
||||
|
||||
/* graph.js 纯逻辑:时序边生效判定 / 职级带归属(函数在 IIFE 内,按两空格缩进闭合提取) */
|
||||
const gsrc = fs.readFileSync(path.join(__dirname, "..", "webui", "graph.js"), "utf-8");
|
||||
function loadGraphFns(names) {
|
||||
const code = names.map((n) => {
|
||||
const m = gsrc.match(new RegExp(`function ${n}\\([\\s\\S]*?\\n \\}`));
|
||||
if (!m) throw new Error(`graph.js 未找到函数 ${n}`);
|
||||
return m[0];
|
||||
}).join("\n");
|
||||
return new Function(`${code}; return { ${names.join(", ")} };`)();
|
||||
}
|
||||
const gf = loadGraphFns(["jobLevel", "levelBandOf", "edgeActiveAt"]);
|
||||
eq(gf.edgeActiveAt({ intervals: [] }, "2026Q1"), true, "无区间边始终生效");
|
||||
eq(gf.edgeActiveAt({ intervals: [["2025Q1", "2025Q3"]] }, "2025Q2"), true, "区间内生效");
|
||||
eq(gf.edgeActiveAt({ intervals: [["2025Q1", "2025Q3"]] }, "2025Q3"), false, "结束边界半开不生效");
|
||||
eq(gf.edgeActiveAt({ intervals: [["2025Q1", "2025Q3"]] }, "2024Q4"), false, "起点前不生效");
|
||||
eq(gf.edgeActiveAt({ intervals: [["2025Q1", null]] }, "2026Q4"), true, "开放区间持续生效");
|
||||
eq(gf.jobLevel({ expected_years: 1 }), "初级", "≤2年初级");
|
||||
eq(gf.jobLevel({ expected_years: 4 }), "中级", "3-5年中级");
|
||||
eq(gf.jobLevel({ expected_years: 8 }), "高级", ">5年高级");
|
||||
eq(gf.levelBandOf({ type: "Job", expected_years: 1 }), 0, "初级岗位入带0");
|
||||
eq(gf.levelBandOf({ type: "Job", expected_years: 8 }), 2, "高级岗位入带2");
|
||||
eq(gf.levelBandOf({ type: "Skill", level: "L1" }), 0, "L1技能入带0");
|
||||
eq(gf.levelBandOf({ type: "Skill", level: "L3" }), 2, "L3技能入带2");
|
||||
eq(gf.levelBandOf({ type: "Skill" }), 1, "无级别技能默认中级带");
|
||||
|
||||
console.log(`\n${pass} passed, ${fail} failed`);
|
||||
process.exit(fail ? 1 : 0);
|
||||
|
||||
Reference in New Issue
Block a user