feat: expand and secure mentor library

This commit is contained in:
leefer
2026-07-23 17:56:52 +08:00
parent d85529dce5
commit 771882ebf0
134 changed files with 4148 additions and 38 deletions
+102 -1
View File
@@ -47,6 +47,65 @@ function session(role = "admin", subscribed = true) {
};
}
function mentorDirectory(role = "admin") {
const mentors = [
{
id: "source-a",
name: "原帖老师",
description: "依据长期实盘原帖提炼",
tagline: "先看周期,再看机会。",
focus: ["情绪周期", "仓位纪律"],
evidence: { grade: "A", label: "实盘原帖", note: "长期原始实盘记录" },
quality: { score: 6, total: 6, status: "pass" },
private: false,
},
{
id: "source-b",
name: "多源老师",
description: "依据公开访谈与多源资料整理",
tagline: "确认之后再行动。",
focus: ["主线确认", "风险管理"],
evidence: { grade: "B", label: "多源整理", note: "公开访谈与多源材料" },
quality: { score: 6, total: 6, status: "pass" },
private: false,
},
{
id: "source-c",
name: "推演老师",
description: "公开语录较少,以行为推演为主",
tagline: "只讨论可验证的行为。",
focus: ["行为推演", "诚实边界"],
evidence: { grade: "C", label: "行为推演", note: "公开语录较少" },
quality: { score: 5, total: 6, status: "conditional" },
private: false,
},
];
for (let index = 1; index <= 18; index += 1) {
const grade = ["A", "B", "C"][(index - 1) % 3];
mentors.push({
id: `extra-${index}`,
name: `扩展模型${String(index).padStart(2, "0")}`,
description: `用于验证完整目录密度的${grade}级思维模型`,
tagline: "保持证据边界。",
focus: ["市场结构", "条件预案"],
evidence: { grade, label: { A: "原始语料", B: "多源整理", C: "行为材料" }[grade], note: `${grade}级测试素材` },
quality: { score: 6, total: 6, status: "pass" },
private: false,
});
}
if (role === "admin") mentors.unshift({
id: "private-owner",
name: "私有老师",
description: "依据个人复盘记录提炼",
tagline: "只对自己开放。",
focus: ["个人复盘", "交易纪律"],
evidence: { grade: "A", label: "私有原始语料", note: "仅限管理员本人使用" },
quality: { score: null, total: null, status: "private" },
private: true,
});
return mentors;
}
async function mockApplication(page, authSession = session()) {
await page.route("**/api/**", async (route) => {
const url = new URL(route.request().url());
@@ -157,7 +216,9 @@ async function mockApplication(page, authSession = session()) {
created_at: "2026-07-23T09:12:00+08:00",
}],
};
} else if (url.pathname === "/api/mentors/setup") payload = { trade_date: "20260722", mentors: [] };
} else if (url.pathname === "/api/mentors/setup") {
payload = { trade_date: "20260722", mentors: mentorDirectory(authSession.user.role) };
}
else if (url.pathname === "/api/heaven/setup") {
await route.fulfill({ status: 503, contentType: "application/json", body: JSON.stringify({ error: "测试环境不加载问天数据" }) });
return;
@@ -430,3 +491,43 @@ test("heaven workspace controls fit a narrow viewport", async ({ page }) => {
expect(heartControls.x + heartControls.width).toBeLessThanOrEqual(375);
expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBeLessThanOrEqual(1);
});
test("mentor directory exposes evidence filters and private owner metadata", async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 900 });
await mockApplication(page, session("admin", true));
await page.goto("/index.html");
await page.locator('[data-view="mentorView"]').first().click();
await expect(page.locator("#mentorList .mentor-option")).toHaveCount(22);
await expect(page.locator('#mentorList [data-mentor-id="private-owner"] .mentor-badge.private')).toContainText("仅自己");
await expect(page.locator('#mentorList [data-mentor-id="source-a"] .mentor-badge.grade-a')).toHaveText("A");
await expect(page.locator('#mentorList [data-mentor-id="source-c"] .mentor-badge.quality')).toHaveText("5/6");
await page.locator("#mentorSearchInput").fill("行为推演");
await expect(page.locator("#mentorList .mentor-option")).toHaveCount(1);
await expect(page.locator("#mentorCount")).toHaveText("1 / 22 位");
await page.locator("#mentorSearchInput").fill("");
await page.locator('[data-mentor-grade="B"]').click();
await expect(page.locator("#mentorList .mentor-option")).toHaveCount(7);
await page.locator('#mentorList [data-mentor-id="source-b"]').click();
await expect(page.locator("#activeMentorName")).toHaveText("多源老师");
await expect(page.locator("#activeMentorBadges")).toContainText("B · 多源整理");
await expect(page.locator("#activeMentorEvidence")).toHaveText("公开访谈与多源材料");
});
test("mobile mentor directory opens as a searchable selector and hides private mentors", async ({ page }) => {
await page.setViewportSize({ width: 375, height: 812 });
await mockApplication(page, session("user", true));
await page.goto("/index.html");
await page.locator('[data-view="mentorView"]').first().click();
await expect(page.locator("#mentorDirectoryToggle")).toBeVisible();
await page.locator("#mentorDirectoryToggle").click();
await expect(page.locator("#mentorView .mentor-sidebar")).toHaveClass(/is-open/);
await expect(page.locator("#mentorList .mentor-option")).toHaveCount(21);
await expect(page.locator('#mentorList [data-mentor-id="private-owner"]')).toHaveCount(0);
await page.locator('#mentorList [data-mentor-id="source-c"]').click();
await expect(page.locator("#mentorView .mentor-sidebar")).not.toHaveClass(/is-open/);
await expect(page.locator("#mobileActiveMentorName")).toHaveText("推演老师");
expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBeLessThanOrEqual(1);
});