import dayjs from "dayjs";
|
|
/** 新闻分类:统一信息出口 */
|
export const NEWS_TYPE_OPTIONS = [
|
{ value: "announcement", label: "企业公告", color: "#409eff" },
|
{ value: "policy", label: "政策解读", color: "#e6a23c" },
|
{ value: "industry", label: "行业动态", color: "#909399" },
|
{ value: "culture", label: "文化活动", color: "#67c23a" },
|
];
|
|
/** 发布状态 */
|
export const PUBLISH_STATUS_OPTIONS = [
|
{ value: "draft", label: "草稿", tag: "info" },
|
{ value: "pending_review", label: "待审核", tag: "warning" },
|
{ value: "published", label: "已发布", tag: "success" },
|
{ value: "archived", label: "已归档", tag: "" },
|
];
|
|
/** 排版模板 */
|
export const LAYOUT_TEMPLATE_OPTIONS = [
|
{ value: "standard", label: "标准图文" },
|
{ value: "policy", label: "政策条文" },
|
{ value: "gallery", label: "图集相册" },
|
{ value: "briefing", label: "简报摘要" },
|
];
|
|
/** 阅读可见范围 */
|
export const READ_SCOPE_OPTIONS = [
|
{ value: "all", label: "全员可见" },
|
{ value: "management", label: "管理层" },
|
{ value: "department", label: "指定部门" },
|
{ value: "custom", label: "自定义名单" },
|
];
|
|
/** 编辑/审核角色(发布权限) */
|
export const PUBLISH_ROLE_OPTIONS = [
|
{ value: "hr", label: "HR(人事政策)" },
|
{ value: "admin", label: "管理员(外部新闻审核)" },
|
{ value: "dept_manager", label: "部门负责人" },
|
{ value: "editor", label: "内容编辑" },
|
];
|
|
export const STORAGE_KEY = "oa_enterprise_news_v1";
|
|
/** 演示用目标受众(后期对接组织架构) */
|
export const MOCK_AUDIENCE = [
|
{ userId: "u1", employeeNo: "zhangsan", name: "张三", deptName: "研发部", isManagement: false },
|
{ userId: "u2", employeeNo: "lisi", name: "李四", deptName: "研发部", isManagement: false },
|
{ userId: "u3", employeeNo: "wangwu", name: "王五", deptName: "行政部", isManagement: false },
|
{ userId: "u4", employeeNo: "zhaoliu", name: "赵六", deptName: "销售部", isManagement: false },
|
{ userId: "u5", employeeNo: "sunqi", name: "孙七", deptName: "财务部", isManagement: false },
|
{ userId: "u6", employeeNo: "zhouba", name: "周八", deptName: "总经办", isManagement: true },
|
{ userId: "u7", employeeNo: "wujiu", name: "吴九", deptName: "总经办", isManagement: true },
|
{ userId: "u8", employeeNo: "zhengshi", name: "郑十", deptName: "人力资源部", isManagement: false },
|
];
|
|
const DEPT_OPTIONS = [
|
{ value: "101", label: "研发部" },
|
{ value: "102", label: "销售部" },
|
{ value: "103", label: "行政部" },
|
{ value: "104", label: "财务部" },
|
{ value: "105", label: "总经办" },
|
{ value: "106", label: "人力资源部" },
|
];
|
|
export { DEPT_OPTIONS };
|
|
export function newsTypeLabel(v) {
|
return NEWS_TYPE_OPTIONS.find((x) => x.value === v)?.label || v || "—";
|
}
|
|
export function newsTypeColor(v) {
|
return NEWS_TYPE_OPTIONS.find((x) => x.value === v)?.color || "#909399";
|
}
|
|
export function publishStatusLabel(v) {
|
return PUBLISH_STATUS_OPTIONS.find((x) => x.value === v)?.label || v || "—";
|
}
|
|
export function publishStatusTag(v) {
|
return PUBLISH_STATUS_OPTIONS.find((x) => x.value === v)?.tag || "info";
|
}
|
|
export function layoutTemplateLabel(v) {
|
return LAYOUT_TEMPLATE_OPTIONS.find((x) => x.value === v)?.label || v || "—";
|
}
|
|
export function readScopeLabel(v) {
|
return READ_SCOPE_OPTIONS.find((x) => x.value === v)?.label || v || "—";
|
}
|
|
export function publishRoleLabel(v) {
|
return PUBLISH_ROLE_OPTIONS.find((x) => x.value === v)?.label || v || "—";
|
}
|
|
export function createEmptyForm() {
|
return {
|
id: "",
|
newsNo: "",
|
title: "",
|
summary: "",
|
newsType: "announcement",
|
layoutTemplate: "standard",
|
contentHtml: "",
|
coverImage: "",
|
mediaList: [],
|
attachmentList: [],
|
editorRole: "hr",
|
reviewerRole: "admin",
|
readScope: "all",
|
targetDeptIds: [],
|
targetUserIds: [],
|
publishStatus: "draft",
|
publisherName: "",
|
publishTime: "",
|
readRecords: [],
|
remindLogs: [],
|
likes: [],
|
comments: [],
|
versions: [],
|
versionNo: 1,
|
requireReadConfirm: false,
|
};
|
}
|
|
function buildReadRecords(readUserIds = []) {
|
const set = new Set(readUserIds);
|
return MOCK_AUDIENCE.map((u) => ({
|
userId: u.userId,
|
employeeNo: u.employeeNo,
|
name: u.name,
|
deptName: u.deptName,
|
readAt: set.has(u.userId) ? dayjs().subtract(2, "day").format("YYYY-MM-DD HH:mm:ss") : "",
|
lastRemindAt: "",
|
}));
|
}
|
|
function createVersionSnapshot(row, changeNote = "发布") {
|
return {
|
versionNo: row.versionNo || 1,
|
title: row.title,
|
summary: row.summary,
|
contentHtml: row.contentHtml,
|
newsType: row.newsType,
|
publishTime: row.publishTime || dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
archivedAt: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
changeNote,
|
publisherName: row.publisherName || "系统",
|
};
|
}
|
|
export function createInitialMockNews() {
|
const policyContent =
|
"<p><strong>2026 年考勤管理制度(试行)</strong></p><p>一、上班时间 9:00,弹性打卡窗口 8:30–9:30。</p><p>二、请假须提前在 OA 提交审批。</p><p>三、本制度自 2026-06-01 起执行。</p>";
|
const cultureContent =
|
"<p>2026 企业年会圆满落幕!感谢每一位同事的参与,以下为精彩瞬间图集。</p>";
|
const strategyContent =
|
"<p><strong>2026 下半年战略方向(内部)</strong></p><p>聚焦核心产品线升级与海外市场拓展,具体指标见附件。</p>";
|
|
const policyRow = {
|
id: "news_1",
|
newsNo: "EN202605150001",
|
title: "关于发布新考勤制度的通知",
|
summary: "请全体员工认真阅读并确认知悉,自 2026-06-01 起执行。",
|
newsType: "policy",
|
layoutTemplate: "policy",
|
contentHtml: policyContent,
|
coverImage: "",
|
mediaList: [],
|
attachmentList: [{ name: "考勤制度2026.pdf", url: "/mock/attendance-policy.pdf" }],
|
editorRole: "hr",
|
reviewerRole: "admin",
|
readScope: "all",
|
targetDeptIds: [],
|
targetUserIds: [],
|
publishStatus: "published",
|
publisherName: "人力资源部",
|
publishTime: "2026-05-15 10:00:00",
|
readRecords: buildReadRecords(["u6", "u7", "u8"]),
|
remindLogs: [],
|
likes: [],
|
comments: [],
|
versions: [
|
{
|
versionNo: 1,
|
title: "关于发布新考勤制度的通知(征求意见稿)",
|
summary: "征求意见稿",
|
contentHtml: "<p>征求意见稿:上班时间 9:00……</p>",
|
newsType: "policy",
|
publishTime: "2026-05-10 09:00:00",
|
archivedAt: "2026-05-15 09:55:00",
|
changeNote: "定稿发布",
|
publisherName: "人力资源部",
|
},
|
],
|
versionNo: 2,
|
requireReadConfirm: true,
|
createTime: "2026-05-10 09:00:00",
|
updateTime: "2026-05-15 10:00:00",
|
};
|
|
const cultureRow = {
|
id: "news_2",
|
newsNo: "EN202605200002",
|
title: "2026 企业年会精彩瞬间",
|
summary: "年会图集上线,欢迎点赞留言,共建企业文化。",
|
newsType: "culture",
|
layoutTemplate: "gallery",
|
contentHtml: cultureContent,
|
coverImage: "/mock/annual-cover.jpg",
|
mediaList: [
|
{ type: "image", name: "开场.jpg", url: "/mock/annual-1.jpg" },
|
{ type: "image", name: "颁奖.jpg", url: "/mock/annual-2.jpg" },
|
{ type: "video", name: "年会花絮.mp4", url: "/mock/annual.mp4" },
|
],
|
attachmentList: [],
|
editorRole: "dept_manager",
|
reviewerRole: "admin",
|
readScope: "all",
|
targetDeptIds: [],
|
targetUserIds: [],
|
publishStatus: "published",
|
publisherName: "行政部",
|
publishTime: "2026-05-20 14:30:00",
|
readRecords: buildReadRecords(["u1", "u2", "u3", "u4", "u5", "u6", "u7"]),
|
remindLogs: [],
|
likes: [
|
{ userId: "u1", name: "张三", time: "2026-05-20 15:01:00" },
|
{ userId: "u2", name: "李四", time: "2026-05-20 15:05:00" },
|
{ userId: "u4", name: "赵六", time: "2026-05-20 16:20:00" },
|
],
|
comments: [
|
{ id: "c1", userId: "u1", name: "张三", content: "节目太精彩了!", time: "2026-05-20 15:10:00" },
|
{ id: "c2", userId: "u3", name: "王五", content: "期待明年再聚!", time: "2026-05-20 17:00:00" },
|
],
|
versions: [],
|
versionNo: 1,
|
requireReadConfirm: false,
|
createTime: "2026-05-20 14:00:00",
|
updateTime: "2026-05-20 14:30:00",
|
};
|
|
const strategyRow = {
|
id: "news_3",
|
newsNo: "EN202605220003",
|
title: "2026 下半年战略规划要点",
|
summary: "仅限管理层阅读,请勿对外传播。",
|
newsType: "announcement",
|
layoutTemplate: "briefing",
|
contentHtml: strategyContent,
|
coverImage: "",
|
mediaList: [],
|
attachmentList: [{ name: "战略指标.pdf", url: "/mock/strategy.pdf" }],
|
editorRole: "admin",
|
reviewerRole: "admin",
|
readScope: "management",
|
targetDeptIds: [],
|
targetUserIds: [],
|
publishStatus: "published",
|
publisherName: "总经办",
|
publishTime: "2026-05-22 09:00:00",
|
readRecords: buildReadRecords(["u6", "u7"]),
|
remindLogs: [],
|
likes: [],
|
comments: [],
|
versions: [],
|
versionNo: 1,
|
requireReadConfirm: false,
|
createTime: "2026-05-22 08:30:00",
|
updateTime: "2026-05-22 09:00:00",
|
};
|
|
const industryDraft = {
|
id: "news_4",
|
newsNo: "EN202605250004",
|
title: "制造业数字化转型趋势简报",
|
summary: "行业动态草稿,待管理员审核后发布。",
|
newsType: "industry",
|
layoutTemplate: "standard",
|
contentHtml: "<p>本期简报梳理工业互联网与 AI 质检应用案例……</p>",
|
coverImage: "",
|
mediaList: [],
|
attachmentList: [],
|
editorRole: "editor",
|
reviewerRole: "admin",
|
readScope: "all",
|
targetDeptIds: [],
|
targetUserIds: [],
|
publishStatus: "pending_review",
|
publisherName: "市场部",
|
publishTime: "",
|
readRecords: [],
|
remindLogs: [],
|
likes: [],
|
comments: [],
|
versions: [],
|
versionNo: 1,
|
requireReadConfirm: false,
|
createTime: "2026-05-25 11:00:00",
|
updateTime: "2026-05-25 11:00:00",
|
};
|
|
return [policyRow, cultureRow, strategyRow, industryDraft];
|
}
|
|
export function loadStoredNews() {
|
try {
|
const raw = localStorage.getItem(STORAGE_KEY);
|
if (!raw) return null;
|
const data = JSON.parse(raw);
|
return Array.isArray(data) ? data : null;
|
} catch {
|
return null;
|
}
|
}
|
|
export function saveStoredNews(rows) {
|
try {
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(rows));
|
} catch {
|
/* ignore */
|
}
|
}
|
|
/** 按阅读范围解析目标受众 */
|
export function resolveTargetAudience(row) {
|
const scope = row.readScope || "all";
|
if (scope === "management") {
|
return MOCK_AUDIENCE.filter((u) => u.isManagement);
|
}
|
if (scope === "department" && row.targetDeptIds?.length) {
|
const names = DEPT_OPTIONS.filter((d) => row.targetDeptIds.includes(d.value)).map((d) => d.label);
|
return MOCK_AUDIENCE.filter((u) => names.includes(u.deptName));
|
}
|
if (scope === "custom" && row.targetUserIds?.length) {
|
return MOCK_AUDIENCE.filter((u) => row.targetUserIds.includes(u.userId));
|
}
|
return [...MOCK_AUDIENCE];
|
}
|
|
export function getUnreadEmployees(row) {
|
const audience = resolveTargetAudience(row);
|
const readSet = new Set(
|
(row.readRecords || []).filter((r) => r.readAt).map((r) => r.userId)
|
);
|
return audience.filter((u) => !readSet.has(u.userId));
|
}
|
|
export function readRate(row) {
|
const audience = resolveTargetAudience(row);
|
if (!audience.length) return 0;
|
const readCount = (row.readRecords || []).filter((r) => r.readAt).length;
|
return Math.round((readCount / audience.length) * 100);
|
}
|
|
export function nextNewsNo() {
|
return `EN${dayjs().format("YYYYMMDD")}${String(Math.floor(Math.random() * 9000) + 1000)}`;
|
}
|
|
export function pushVersionBeforeUpdate(row, changeNote) {
|
const versions = row.versions || [];
|
versions.unshift(createVersionSnapshot(row, changeNote));
|
row.versions = versions;
|
row.versionNo = (row.versionNo || 1) + 1;
|
}
|
|
export function validateNewsForm(form) {
|
const title = (form.title || "").trim();
|
if (!title) return { ok: false, message: "请填写新闻标题" };
|
if (!form.newsType) return { ok: false, message: "请选择新闻分类" };
|
if (form.readScope === "department" && !(form.targetDeptIds || []).length) {
|
return { ok: false, message: "请选择可见部门" };
|
}
|
return { ok: true, title };
|
}
|