Files
YschcmsFront/mock/data.ts
T
chenxing e5a9506228
build / build (push) Successful in 2m19s
chore(mock): 粉/紫两包下线后 mock 主题改指 academic-navy/campus-azure
后端删除 cherry-bloom/violet-iris,改以学院蓝为基座的学府藏蓝/青蓝校园两包接管;
mock 主题清单同步换名换标题换色(cssVar 用各皮肤私有前缀 --an-*/--cz-*),
院系子站种子站点 theme 一并改指,避免管理端主题选择器出现已不存在的皮肤。
2026-09-19 20:22:09 +08:00

511 lines
24 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Mock 内存数据库 + 种子数据(仅 dev mock 模式使用,vite.config 按需加载)。
* 数据形状与 com.yunhai.cms.model.vo 一一对应;时间串用 "yyyy-MM-dd HH:mm:ss"。
*/
/* ===== 行类型 ===== */
export interface MockSite {
id: number;
code: string;
/** 门户路径(W4:顶层=code;子站=父path/code) */
path: string;
/** 上级站点ID(0=顶层校站点;院系子站挂主站 id) */
parentSiteId: number;
schId: number;
schName: string;
name: string;
theme: string;
configJson: string;
status: number;
createTime: string;
}
export interface MockCategory {
id: number;
siteId: number;
parentId: number;
name: string;
type: number;
linkUrl?: string;
template?: string;
content?: string;
sortNo: number;
seoTitle?: string;
seoDescription?: string;
status: number;
}
export interface MockArticle {
id: number;
siteId: number;
categoryId: number;
title: string;
summary: string;
content: string;
coverImage?: string;
authorName: string;
source: string;
/** 0=草稿 1=已发布 2=已下架 */
status: number;
topmost: number;
publishTime?: string;
offlineTime?: string;
viewCount: number;
createTime: string;
createBy: string;
}
export interface MockAttachment {
id: number;
siteId: number;
articleId?: number;
/** 场景引用类型(B2):banner/link/site;空=未使用 */
refType?: string;
refId?: number;
fileName: string;
url: string;
fileSize: number;
mimeType: string;
createTime: string;
}
export interface MockBanner {
id: number;
siteId: number;
position: string;
title: string;
imageUrl: string;
linkType: number;
linkValue?: string;
sortNo: number;
startTime?: string;
endTime?: string;
status: number;
}
export interface MockLink {
id: number;
siteId: number;
groupName: string;
name: string;
logoUrl?: string;
linkUrl: string;
sortNo: number;
status: number;
}
export interface MockSvcDict {
id: number;
siteId: number;
dictType: "object" | "category";
dictKey: string;
dictName: string;
sortNo: number;
status: number;
}
export interface MockSvcItem {
id: number;
siteId: number;
itemCode: string;
title: string;
summary?: string;
objectKey?: string;
categoryKey?: string;
deptGroupId?: number;
deptName?: string;
handleMode: number;
onlineFlag: number;
handlePlace?: string;
handleTimeLimit?: string;
promiseTimeLimit?: string;
contactPhone?: string;
supervisePhone?: string;
processHtml?: string;
materialHtml?: string;
noticeHtml?: string;
faqCategoryId?: number;
noticeCategoryId?: number;
ruleCategoryId?: number;
coverImage?: string;
sortNo: number;
status: number;
publishTime?: string;
offlineTime?: string;
viewCount: number;
extJson?: string;
attachmentIds?: number[];
createTime: string;
}
export interface MockDb {
sites: MockSite[];
categories: MockCategory[];
articles: MockArticle[];
attachments: MockAttachment[];
banners: MockBanner[];
links: MockLink[];
svcItems: MockSvcItem[];
svcDicts: MockSvcDict[];
/** 上传文件缓存:url 尾段 → {buffer, mime} */
files: Map<string, { buffer: Buffer; mime: string; name: string }>;
}
/* ===== 工具 ===== */
function fmt(d: Date): string {
const p = (n: number) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
}
function daysAgo(n: number, h = 9, m = 30): string {
const d = new Date();
d.setDate(d.getDate() - n);
d.setHours(h, m, 0, 0);
return fmt(d);
}
/** 简单富文本正文(栏目/文章种子共用) */
function para(...ps: string[]): string {
return ps.map(t => `<p>${t}</p>`).join("");
}
/* ===== 种子数据 ===== */
export function seedDb(): MockDb {
const db: MockDb = {
sites: [],
categories: [],
articles: [],
attachments: [],
banners: [],
links: [],
svcItems: [],
svcDicts: [],
files: new Map(),
};
/* ---- 站点(demo 为主站 + jdx/xxgc 院系子站;fsz 独立顶层站无子站) ---- */
db.sites.push(
{
id: 1,
code: "demo",
path: "demo",
parentSiteId: 0,
schId: 1001,
schName: "云海大学",
name: "云海大学门户网站",
theme: "default",
configJson: JSON.stringify(
{
domain: "www.yunhai-demo.edu.cn",
public_base_url: "http://www.yunhai-demo.edu.cn",
logo: "/mock-img/logo-univ.svg",
copyright: "云海大学 · 版权所有 © 2026(Mock 数据)",
},
null,
2
),
status: 1,
createTime: daysAgo(90),
},
{
id: 2,
code: "fsz",
path: "fsz",
parentSiteId: 0,
schId: 1002,
schName: "云海大学附属中学",
name: "附中信息门户",
theme: "blue-white",
configJson: JSON.stringify({ copyright: "云大附中 · Mock 数据" }),
status: 1,
createTime: daysAgo(60),
},
{
id: 3,
code: "jdx",
path: "demo/jdx",
parentSiteId: 1,
schId: 1001,
schName: "云海大学",
name: "机电学院",
theme: "academic-navy",
configJson: JSON.stringify({
public_base_url: "http://www.yunhai-demo.edu.cn/college/jdx",
copyright: "机电学院 · Mock 数据",
}),
status: 1,
createTime: daysAgo(50),
},
{
id: 4,
code: "xxgc",
path: "demo/xxgc",
parentSiteId: 1,
schId: 1001,
schName: "云海大学",
name: "信息工程学院",
theme: "campus-azure",
configJson: JSON.stringify({
public_base_url: "http://www.yunhai-demo.edu.cn/college/xxgc",
copyright: "信息工程学院 · Mock 数据",
}),
status: 1,
createTime: daysAgo(45),
}
);
/* ---- 栏目(site1 大学门户) ---- */
const c1 = (o: Partial<MockCategory> & { id: number; name: string; type: number }) => ({
siteId: 1,
parentId: 0,
sortNo: 0,
status: 1,
...o,
} as MockCategory);
db.categories.push(
c1({ id: 1, name: "学校概况", type: 2, sortNo: 1, seoTitle: "云海大学简介", content: para("云海大学创建于 1958 年,是一所以工为主、多学科协调发展的综合性大学。", "学校现有全日制在校生 3.2 万余人,教职工 2800 余人,拥有两院院士 12 名。(此处为 Mock 演示数据)") }),
c1({ id: 2, name: "新闻中心", type: 1, sortNo: 2 }),
c1({ id: 3, name: "通知公告", type: 1, parentId: 2, sortNo: 1, seoTitle: "通知公告" }),
c1({ id: 4, name: "校园动态", type: 1, parentId: 2, sortNo: 2 }),
c1({ id: 5, name: "媒体报道", type: 1, parentId: 2, sortNo: 3 }),
c1({ id: 6, name: "教学科研", type: 1, sortNo: 3 }),
c1({ id: 7, name: "教学动态", type: 1, parentId: 6, sortNo: 1 }),
c1({ id: 8, name: "科研成果", type: 1, parentId: 6, sortNo: 2 }),
c1({ id: 9, name: "招生网", type: 3, sortNo: 4, linkUrl: "https://zs.example.edu.cn" }),
c1({ id: 10, name: "联系我们", type: 2, sortNo: 5, content: para("地址:云海市学府路 1 号", "邮编:100000", "电话:010-88888888(Mock)") })
);
/* ---- 栏目(site2 附中门户,验证站点数据隔离) ---- */
const c2 = (o: Partial<MockCategory> & { id: number; name: string; type: number }) => ({
siteId: 2,
parentId: 0,
sortNo: 0,
status: 1,
...o,
} as MockCategory);
db.categories.push(
c2({ id: 21, name: "附中新闻", type: 1, sortNo: 1 }),
c2({ id: 22, name: "校园风采", type: 2, sortNo: 2, content: para("附中校园风光介绍(Mock)。") })
);
/* ---- 栏目(site3/4 院系子站,门户 header 出"专业院系"下拉) ---- */
const c3 = (siteId: number) => (o: Partial<MockCategory> & { id: number; name: string; type: number }) => ({
siteId,
parentId: 0,
sortNo: 0,
status: 1,
...o,
} as MockCategory);
const c3j = c3(3);
const c3x = c3(4);
db.categories.push(
c3j({ id: 41, name: "学院概况", type: 2, sortNo: 1, seoTitle: "机电学院简介", content: para("机电学院设有机电一体化技术、电气自动化技术、机械制造及自动化、物联网应用技术等专业(Mock)。") }),
c3j({ id: 42, name: "学院新闻", type: 1, sortNo: 2 }),
c3j({ id: 43, name: "实习实训", type: 1, sortNo: 3 }),
c3x({ id: 44, name: "学院概况", type: 2, sortNo: 1, seoTitle: "信息工程学院简介", content: para("信息工程学院开设计算机应用技术、软件技术、大数据技术等专业(Mock)。") }),
c3x({ id: 45, name: "学院动态", type: 1, sortNo: 2 })
);
/* ---- 文章 ---- */
let aid = 0;
const a = (o: Partial<MockArticle> & { categoryId: number; title: string }) => ({
id: ++aid,
siteId: 1,
summary: "",
content: "",
authorName: "张老师",
source: "",
status: 1,
topmost: 0,
viewCount: Math.floor(Math.random() * 2000) + 100,
createTime: daysAgo(aid),
createBy: "admin",
...o,
} as MockArticle);
const body = (t: string) =>
para(
`${t}——本文为 Mock 演示数据,用于前端界面预览。`,
"云海大学始终坚持立德树人根本任务,深入推进教育教学改革,人才培养质量稳步提升。",
`正文第二段:近日,${t}相关活动在校园内顺利举行,广大师生积极参与,反响热烈。`,
`<p><img src="/mock-img/art-${aid}.svg" alt="配图" style="max-width:100%"/></p>`,
"正文第三段:学校相关负责人表示,将持续完善各项工作机制,以更高标准推动事业发展。"
);
db.articles.push(
a({ categoryId: 3, title: "关于 2026 年秋季学期开学注册安排的通知", topmost: 1, publishTime: daysAgo(1), content: body("关于 2026 年秋季学期开学注册安排的通知"), summary: "现将 2026 年秋季学期开学注册有关事项通知如下……" }),
a({ categoryId: 3, title: "图书馆国庆节期间开放时间调整公告", publishTime: daysAgo(3), content: body("图书馆开放时间调整") }),
a({ categoryId: 3, title: "关于开展 2026 级新生入学教育系列活动的通知", publishTime: daysAgo(6), content: body("新生入学教育活动") }),
a({ categoryId: 3, title: "校园网络升级维护通知(草稿)", status: 0, content: body("校园网络升级维护"), authorName: "李老师" }),
a({ categoryId: 4, title: "我校成功举办第 38 届田径运动会", topmost: 1, coverImage: "/mock-img/cover-1.svg", publishTime: daysAgo(2), content: body("第 38 届田径运动会"), summary: "为期三天的校运会圆满落幕,共有 16 个学院代表队参赛。" }),
a({ categoryId: 4, title: "2026 年迎新晚会精彩回顾", coverImage: "/mock-img/cover-2.svg", publishTime: daysAgo(5), content: body("迎新晚会") }),
a({ categoryId: 4, title: "大学生创新创业大赛校内选拔赛落幕", coverImage: "/mock-img/cover-3.svg", publishTime: daysAgo(9), content: body("创新创业大赛") }),
a({ categoryId: 4, title: "志愿服务月活动启动(草稿)", status: 0, content: body("志愿服务月") }),
a({ categoryId: 4, title: "2025 年优秀学生表彰大会报道(已下架)", status: 2, publishTime: daysAgo(40), offlineTime: daysAgo(10), content: body("表彰大会") }),
a({ categoryId: 5, title: "《云海日报》:云海大学深耕产教融合一线观察", publishTime: daysAgo(4), source: "云海日报", content: body("产教融合") }),
a({ categoryId: 5, title: "市电视台专访我校智能制造实验室", publishTime: daysAgo(12), source: "云海电视台", content: body("智能制造实验室") }),
a({ categoryId: 7, title: "我校 12 门课程获评省级一流本科课程", publishTime: daysAgo(7), content: body("省级一流课程") }),
a({ categoryId: 7, title: "关于组织申报 2027 年教改项目的预通知", publishTime: daysAgo(15), content: body("教改项目申报") }),
a({ categoryId: 8, title: "材料学院团队在《Nature》子刊发表最新成果", topmost: 1, publishTime: daysAgo(2), content: body("《Nature》子刊成果"), summary: "该研究首次揭示了新型钙钛矿材料的界面稳定性机制。" }),
a({ categoryId: 8, title: "我校获国家重点研发计划项目立项 3 项", publishTime: daysAgo(18), content: body("重点研发计划立项") }),
a({ categoryId: 8, title: "人工智能学院发布大模型教育应用白皮书(草稿)", status: 0, content: body("大模型教育白皮书") })
);
/* 附中站点少量文章 */
db.articles.push(
a({ siteId: 2, categoryId: 21, title: "附中举行新学期升旗仪式", publishTime: daysAgo(2), content: body("升旗仪式") }),
a({ siteId: 2, categoryId: 21, title: "附中啦啦操队获市级比赛一等奖", publishTime: daysAgo(8), content: body("啦啦操一等奖") }),
a({ siteId: 2, categoryId: 21, title: "高三年级家长会通知(草稿)", status: 0, content: body("家长会通知") })
);
/* 院系子站文章 */
db.articles.push(
a({ siteId: 3, categoryId: 42, title: "机电学院学生在省级技能大赛中斩获一等奖", topmost: 1, publishTime: daysAgo(1), content: body("省级技能大赛一等奖"), summary: "机电一体化专业学生团队获省级技能大赛一等奖。" }),
a({ siteId: 3, categoryId: 42, title: "机电学院召开 2026 届毕业生就业推进会", publishTime: daysAgo(4), content: body("就业推进会") }),
a({ siteId: 3, categoryId: 43, title: "工业机器人实训室投入使用", publishTime: daysAgo(7), content: body("实训室投用") }),
a({ siteId: 3, categoryId: 42, title: "实训设备采购论证会(草稿)", status: 0, content: body("设备采购论证") }),
a({ siteId: 4, categoryId: 45, title: "信息工程学院举办程序设计校内选拔赛", publishTime: daysAgo(3), content: body("程序设计选拔赛") }),
a({ siteId: 4, categoryId: 45, title: "软件技术专业开展企业导师课", publishTime: daysAgo(6), content: body("企业导师课") })
);
/* ---- 附件 ---- */
let atid = 0;
const at = (o: Partial<MockAttachment> & { fileName: string; url: string }) => ({
id: ++atid,
siteId: 1,
fileSize: Math.floor(Math.random() * 5 * 1024 * 1024) + 10240,
mimeType: "application/octet-stream",
createTime: daysAgo(atid * 2 + 1),
...o,
} as MockAttachment);
db.attachments.push(
at({ fileName: "2026秋季学期校历.pdf", url: "/mock-files/2026校历.pdf", mimeType: "application/pdf", articleId: 1 }),
at({ fileName: "运动会秩序册.pdf", url: "/mock-files/运动会秩序册.pdf", mimeType: "application/pdf", articleId: 5 }),
at({ fileName: "迎新晚会节目单.docx", url: "/mock-files/迎新晚会节目单.docx", articleId: 6 }),
// B2 场景引用:轮播图/友链 Logo 附件带 refType/refId(与真实后端形态一致)
at({ fileName: "banner-1.png", url: "/mock-img/banner-1.svg", mimeType: "image/png", refType: "banner", refId: 1 }),
at({ fileName: "banner-2.png", url: "/mock-img/banner-2.svg", mimeType: "image/png", refType: "banner", refId: 2 }),
at({ fileName: "banner-3.png", url: "/mock-img/banner-3.svg", mimeType: "image/png", refType: "banner", refId: 3 }),
at({ fileName: "logo-教育部.png", url: "/mock-img/logo-1.svg", mimeType: "image/png", refType: "link", refId: 1 }),
at({ fileName: "未使用旧banner.png", url: "/mock-img/banner-old.svg", mimeType: "image/png" }),
at({ fileName: "未使用配图.jpg", url: "/mock-img/orphan.svg", mimeType: "image/jpeg" })
);
/* ---- 轮播 ---- */
db.banners.push(
{ id: 1, siteId: 1, position: "home", title: "笃学慎思 明辨笃行", imageUrl: "/mock-img/banner-1.svg", linkType: 2, linkValue: "4", sortNo: 1, status: 1, startTime: daysAgo(30), endTime: undefined },
{ id: 2, siteId: 1, position: "home", title: "第 38 届田径运动会", imageUrl: "/mock-img/banner-2.svg", linkType: 1, linkValue: "5", sortNo: 2, status: 1, startTime: daysAgo(20) },
{ id: 3, siteId: 1, position: "home", title: "2026 年招生咨询", imageUrl: "/mock-img/banner-3.svg", linkType: 3, linkValue: "https://zs.example.edu.cn", sortNo: 3, status: 1, startTime: daysAgo(10) },
{ id: 4, siteId: 2, position: "home", title: "附中欢迎你", imageUrl: "/mock-img/banner-4.svg", linkType: 3, linkValue: "https://fsz.example.cn", sortNo: 1, status: 1 },
{ id: 5, siteId: 3, position: "home", title: "智能制造 匠心筑梦", imageUrl: "/mock-img/banner-2.svg", linkType: 2, linkValue: "42", sortNo: 1, status: 1 }
);
/* ---- 友情链接 ---- */
let lid = 0;
const l = (o: Partial<MockLink> & { name: string; linkUrl: string }) => ({
id: ++lid,
siteId: 1,
groupName: "常用服务",
sortNo: lid,
status: 1,
...o,
} as MockLink);
db.links.push(
l({ groupName: "上级部门", name: "教育部", linkUrl: "http://www.moe.gov.cn", logoUrl: "/mock-img/logo-1.svg" }),
l({ groupName: "上级部门", name: "省教育厅", linkUrl: "http://jyt.example.cn", logoUrl: "/mock-img/logo-2.svg" }),
l({ groupName: "兄弟院校", name: "云海理工大学", linkUrl: "https://www.yhlg.edu.cn", logoUrl: "/mock-img/logo-3.svg" }),
l({ groupName: "兄弟院校", name: "云海师范大学", linkUrl: "https://www.yhsf.edu.cn", logoUrl: "/mock-img/logo-4.svg" }),
l({ groupName: "兄弟院校", name: "云海医科大学", linkUrl: "https://www.yhyk.edu.cn", logoUrl: "/mock-img/logo-5.svg" }),
l({ name: "教务系统", linkUrl: "https://jw.yunhai-demo.edu.cn", logoUrl: "/mock-img/logo-6.svg" }),
l({ name: "图书馆", linkUrl: "https://lib.yunhai-demo.edu.cn", logoUrl: "/mock-img/logo-7.svg" }),
l({ name: "邮件系统", linkUrl: "https://mail.yunhai-demo.edu.cn", logoUrl: "/mock-img/logo-8.svg" }),
l({ siteId: 2, groupName: "附中链接", name: "教育云平台", linkUrl: "https://edu.example.cn" })
);
/* ---- 事项字典 + 办事事项(事项库 R2;demo 站为主,另给附中一条便于切换站点观察) ---- */
let sdid = 0;
const sd = (o: Partial<MockSvcDict> & { dictType: "object" | "category"; dictKey: string; dictName: string }) => ({
id: ++sdid,
siteId: 1,
sortNo: sdid,
status: 1,
...o,
} as MockSvcDict);
db.svcDicts.push(
sd({ dictType: "object", dictKey: "person", dictName: "个人" }),
sd({ dictType: "object", dictKey: "legal", dictName: "法人" }),
sd({ dictType: "object", dictKey: "other", dictName: "其他组织" }),
sd({ dictType: "category", dictKey: "jw", dictName: "教务服务" }),
sd({ dictType: "category", dictKey: "hq", dictName: "后勤服务" }),
sd({ dictType: "category", dictKey: "xs", dictName: "学生事务" }),
sd({ dictType: "category", dictKey: "stop", dictName: "已停用类别", status: 0 }),
sd({ siteId: 2, dictType: "object", dictKey: "person", dictName: "个人" }),
sd({ siteId: 2, dictType: "category", dictKey: "jw", dictName: "教务服务" })
);
let siid = 0;
const si = (o: Partial<MockSvcItem> & { itemCode: string; title: string }) => ({
id: ++siid,
siteId: 1,
handleMode: 1,
onlineFlag: 1,
sortNo: siid,
status: 1,
viewCount: Math.floor(Math.random() * 800),
processHtml: para("申请人携带材料到服务窗口提出申请。", "窗口受理后 1 个工作日内完成审核。"),
materialHtml: para("1. 申请表(现场领取)", "2. 本人身份证明", "3. 相关证明材料"),
noticeHtml: para("材料齐全当日办结;如需补正,以窗口告知为准。"),
extJson: JSON.stringify({ apply_url: "https://svhall.example.com/#/apply" }),
createTime: daysAgo(siid * 3),
...o,
} as MockSvcItem);
db.svcItems.push(
si({ itemCode: "BG-ZX-001", title: "转学办理", summary: "适用于在校学生转学申请", objectKey: "person", categoryKey: "jw", deptGroupId: 10, deptName: "教务处", handleMode: 1, handleTimeLimit: "3 个工作日", contactPhone: "0571-88888888", publishTime: daysAgo(12) }),
si({ itemCode: "BG-XJ-002", title: "休学办理", summary: "因病或其他原因申请休学", objectKey: "person", categoryKey: "jw", deptGroupId: 10, deptName: "教务处", handleMode: 3, handleTimeLimit: "5 个工作日", publishTime: daysAgo(10) }),
si({ itemCode: "BG-HQ-100", title: "宿舍报修", summary: "学生宿舍水电与设施报修", objectKey: "person", categoryKey: "hq", deptGroupId: 20, deptName: "后勤处", handleMode: 2, onlineFlag: 0, handlePlace: "后勤服务大厅", publishTime: daysAgo(8) }),
si({ itemCode: "BG-XS-210", title: "学生证补办", summary: "学生证遗失后的补办申请", objectKey: "person", categoryKey: "xs", deptGroupId: 30, deptName: "学生工作处", handleMode: 1, publishTime: daysAgo(6) }),
si({ itemCode: "BG-FR-300", title: "法人年检材料受理", summary: "面向法人单位的年检材料受理", objectKey: "legal", categoryKey: "jw", deptGroupId: 10, deptName: "教务处", handleMode: 2, coverImage: "/mock-img/banner-3.svg", publishTime: daysAgo(4) }),
si({ itemCode: "BG-DRAFT-001", title: "校园卡挂失(草稿)", objectKey: "person", categoryKey: "xs", status: 0, handleMode: 1 }),
si({ itemCode: "BG-OFF-001", title: "教室借用申请(已下架)", objectKey: "person", categoryKey: "hq", status: 2, handleMode: 2, publishTime: daysAgo(20), offlineTime: daysAgo(2) }),
si({ siteId: 2, itemCode: "FZ-001", title: "附中转学办理", objectKey: "person", categoryKey: "jw", deptName: "附中教务处", status: 1, publishTime: daysAgo(5) })
);
return db;
}
/* ===== 查询辅助 ===== */
/** 拍平表 → CategoryTreeNode 树 */
export function categoryTree(db: MockDb, siteId: number): any[] {
const list = db.categories
.filter(c => c.siteId === siteId)
.sort((x, y) => x.sortNo - y.sortNo);
const node = (parentId: number): any[] =>
list
.filter(c => c.parentId === parentId)
.map(c => ({
id: c.id,
parentId: c.parentId,
siteId: c.siteId,
name: c.name,
type: c.type,
linkUrl: c.linkUrl,
template: c.template,
content: c.content,
sortNo: c.sortNo,
seoTitle: c.seoTitle,
seoDescription: c.seoDescription,
status: c.status,
children: node(c.id),
}));
return node(0);
}
export function categoryName(db: MockDb, id: number): string {
return db.categories.find(c => c.id === id)?.name || "-";
}
/** 自增 id(各表统一走 999+,避免与种子 id 冲突混淆) */
export function nextId(rows: { id: number }[]): number {
return rows.reduce((m, r) => Math.max(m, r.id), 0) + 1;
}