/** * Mock 内存数据库 + 种子数据(仅 dev mock 模式使用,vite.config 按需加载)。 * 数据形状与 com.yunhai.cms.model.vo 一一对应;时间串用 "yyyy-MM-dd HH:mm:ss"。 */ /* ===== 行类型 ===== */ export interface MockSite { id: number; code: 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 MockDb { sites: MockSite[]; categories: MockCategory[]; articles: MockArticle[]; attachments: MockAttachment[]; banners: MockBanner[]; links: MockLink[]; /** 上传文件缓存:url 尾段 → {buffer, mime} */ files: Map; } /* ===== 工具 ===== */ 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 => `

${t}

`).join(""); } /* ===== 种子数据 ===== */ export function seedDb(): MockDb { const db: MockDb = { sites: [], categories: [], articles: [], attachments: [], banners: [], links: [], files: new Map(), }; /* ---- 站点(demo 为主站 + jdx/xxgc 院系子站;fsz 独立顶层站无子站) ---- */ db.sites.push( { id: 1, code: "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", parentSiteId: 0, schId: 1002, schName: "云海大学附属中学", name: "附中信息门户", theme: "blue-white", configJson: JSON.stringify({ copyright: "云大附中 · Mock 数据" }), status: 1, createTime: daysAgo(60), }, { id: 3, code: "jdx", parentSiteId: 1, schId: 1001, schName: "云海大学", name: "机电学院", theme: "default", 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", parentSiteId: 1, schId: 1001, schName: "云海大学", name: "信息工程学院", theme: "default", 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 & { 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 & { 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 & { 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 & { 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}相关活动在校园内顺利举行,广大师生积极参与,反响热烈。`, `

配图

`, "正文第三段:学校相关负责人表示,将持续完善各项工作机制,以更高标准推动事业发展。" ); 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 & { 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 & { 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" }) ); 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; }