import { Search } from "@element-plus/icons-vue"; import dayjs from "dayjs"; import { ElMessageBox } from "element-plus"; import { computed, reactive, ref, watch } from "vue"; import { NOTICE_TYPE_OPTIONS, PRIORITY_OPTIONS, PUBLISH_STATUS_OPTIONS, READ_SCOPE_OPTIONS, DEPT_OPTIONS, createEmptyForm, createInitialMockNotices, loadStoredNotices, saveStoredNotices, nextNoticeNo, validateNoticeForm, noticeTypeLabel, priorityLabel, publishStatusLabel, isExpired, } from "./noticeAnnouncementUtils.js"; export function useNoticeAnnouncement() { const stored = loadStoredNotices(); const allRows = ref(stored?.length ? stored : createInitialMockNotices()); const searchForm = reactive({ keyword: "", noticeType: "", priority: "", publishStatus: "", publishDateRange: [], }); const tableLoading = ref(false); const page = reactive({ current: 1, size: 10, total: 0 }); const formDialog = reactive({ visible: false, title: "", mode: "add", readonly: false }); const form = reactive(createEmptyForm()); const formRef = ref(); const detailDialog = reactive({ visible: false }); const detailRow = ref({}); const filteredList = computed(() => { let list = [...allRows.value]; const kw = (searchForm.keyword || "").trim().toLowerCase(); if (kw) { list = list.filter((r) => (r.title || "").toLowerCase().includes(kw) || (r.noticeNo || "").toLowerCase().includes(kw)); } if (searchForm.noticeType) list = list.filter((r) => r.noticeType === searchForm.noticeType); if (searchForm.priority) list = list.filter((r) => r.priority === searchForm.priority); if (searchForm.publishStatus) list = list.filter((r) => r.publishStatus === searchForm.publishStatus); const range = searchForm.publishDateRange; if (range?.length === 2 && range[0] && range[1]) { const start = dayjs(range[0]).startOf("day"); const end = dayjs(range[1]).endOf("day"); list = list.filter((r) => { if (!r.publishDate) return false; const t = dayjs(r.publishDate); return !t.isBefore(start) && !t.isAfter(end); }); } return list.sort((a, b) => (String(a.updateTime) < String(b.updateTime) ? 1 : -1)); }); watch( filteredList, (list) => { page.total = list.length; const maxPage = Math.max(1, Math.ceil(list.length / page.size) || 1); if (page.current > maxPage) page.current = maxPage; }, { immediate: true } ); const tableData = computed(() => { const start = (page.current - 1) * page.size; return filteredList.value.slice(start, start + page.size); }); const formRules = { title: [{ required: true, message: "请输入公告标题", trigger: "blur" }], publishDate: [{ required: true, message: "请选择发布日期", trigger: "change" }], noticeType: [{ required: true, message: "请选择公告类型", trigger: "change" }], }; const tableColumn = ref([ { label: "编号", prop: "noticeNo", width: 150 }, { label: "标题", prop: "title", minWidth: 200, showOverflowTooltip: true }, { label: "类型", prop: "noticeType", width: 100, dataType: "slot", slot: "noticeType", }, { label: "优先级", prop: "priority", width: 90, dataType: "tag", formatData: (v) => priorityLabel(v), formatType: (v) => { const hit = PRIORITY_OPTIONS.find((x) => x.value === v); return hit?.tag || "info"; }, }, { label: "状态", prop: "publishStatus", width: 90, dataType: "tag", formatData: (v, row) => (isExpired(row) && v === "published" ? "已过期" : publishStatusLabel(v)), formatType: (v, row) => { if (isExpired(row) && v === "published") return ""; const hit = PUBLISH_STATUS_OPTIONS.find((x) => x.value === v); return hit?.tag || "info"; }, }, { label: "发布日期", prop: "publishDate", width: 120 }, { label: "发布人", prop: "publisherName", width: 110 }, { label: "阅读量", prop: "readCount", width: 80, align: "center" }, { dataType: "action", label: "操作", align: "center", fixed: "right", width: 220, operation: [ { name: "详情", type: "text", clickFun: (row) => openDetail(row) }, { name: "修改", type: "text", disabled: (row) => row.publishStatus === "withdrawn", clickFun: (row) => openFormDialog("edit", row), }, { name: "发布", type: "text", disabled: (row) => row.publishStatus === "published", clickFun: (row) => publishNotice(row), }, { name: "撤回", type: "text", disabled: (row) => row.publishStatus !== "published", clickFun: (row) => withdrawNotice(row), }, { name: "删除", type: "text", clickFun: (row) => deleteNotice(row) }, ], }, ]); function persist() { saveStoredNotices(allRows.value); } function handleQuery() { tableLoading.value = true; page.current = 1; setTimeout(() => { tableLoading.value = false; }, 200); } function resetSearch() { searchForm.keyword = ""; searchForm.noticeType = ""; searchForm.priority = ""; searchForm.publishStatus = ""; searchForm.publishDateRange = []; handleQuery(); } function pagination({ page: p, limit }) { page.current = p; page.size = limit; } function resetForm(target = createEmptyForm()) { Object.assign(form, createEmptyForm(), target); } function openFormDialog(mode, row) { formDialog.mode = mode; formDialog.readonly = mode === "view"; formDialog.title = mode === "add" ? "添加公告" : mode === "edit" ? "修改公告" : "查看公告"; if (mode === "add") { resetForm({ publisherName: "当前用户", priority: "normal" }); } else { resetForm({ ...JSON.parse(JSON.stringify(row)), targetDeptIds: [...(row.targetDeptIds || [])], }); } formDialog.visible = true; } function openDetail(row) { detailRow.value = { ...row }; detailDialog.visible = true; } function saveForm(publish = false) { const v = validateNoticeForm(form); if (!v.ok) return { ok: false, message: v.message }; const now = dayjs().format("YYYY-MM-DD HH:mm:ss"); const payload = { ...JSON.parse(JSON.stringify(form)), title: v.title, updateTime: now, }; if (form.noticeType === "emergency" && payload.priority === "normal") { payload.priority = "urgent"; } if (formDialog.mode === "add") { payload.id = `notice_${Date.now()}`; payload.noticeNo = nextNoticeNo(); payload.createTime = now; payload.readCount = 0; if (publish) { payload.publishStatus = "published"; payload.publishTime = now; } else { payload.publishStatus = "draft"; } allRows.value.unshift(payload); } else { const idx = allRows.value.findIndex((r) => r.id === form.id); if (idx < 0) return { ok: false, message: "记录不存在" }; const prev = allRows.value[idx]; if (publish) { payload.publishStatus = "published"; payload.publishTime = payload.publishTime || now; } allRows.value[idx] = { ...prev, ...payload }; } persist(); formDialog.visible = false; return { ok: true }; } async function publishNotice(row) { try { await ElMessageBox.confirm(`确认发布「${row.title}」?`, "发布公告", { type: "warning", confirmButtonText: "发布", cancelButtonText: "取消", }); const hit = allRows.value.find((r) => r.id === row.id); if (!hit) return; const now = dayjs().format("YYYY-MM-DD HH:mm:ss"); hit.publishStatus = "published"; hit.publishTime = now; hit.updateTime = now; if (hit.noticeType === "emergency") hit.priority = "urgent"; persist(); return true; } catch { return false; } } async function withdrawNotice(row) { try { await ElMessageBox.confirm(`确认撤回「${row.title}」?撤回后员工端将不再展示。`, "撤回公告", { type: "warning", confirmButtonText: "撤回", cancelButtonText: "取消", }); const hit = allRows.value.find((r) => r.id === row.id); if (!hit) return; hit.publishStatus = "withdrawn"; hit.updateTime = dayjs().format("YYYY-MM-DD HH:mm:ss"); persist(); return true; } catch { return false; } } async function deleteNotice(row) { try { await ElMessageBox.confirm(`确认删除「${row.title}」?此操作不可恢复。`, "删除公告", { type: "warning", confirmButtonText: "删除", cancelButtonText: "取消", }); allRows.value = allRows.value.filter((r) => r.id !== row.id); persist(); return true; } catch { return false; } } return { Search, NOTICE_TYPE_OPTIONS, PRIORITY_OPTIONS, PUBLISH_STATUS_OPTIONS, READ_SCOPE_OPTIONS, DEPT_OPTIONS, noticeTypeLabel, searchForm, tableLoading, page, tableData, tableColumn, formDialog, form, formRef, formRules, detailDialog, detailRow, isExpired, handleQuery, resetSearch, pagination, openFormDialog, openDetail, saveForm, publishNotice, withdrawNotice, deleteNotice, }; }