feat: 提交校园公告前端工程源码(Vue3 + Vite + view-ui-plus)
build / build (push) Successful in 10m17s

- 同步仓库 CI 配置 .gitea/workflows/build.yml
- 纳入 src/public/config/scripts 等工程文件
- .gitignore 增加 .scratch/.backup/.trash,排除本地临时产物
This commit is contained in:
lijing
2026-09-15 11:15:03 +08:00
parent 36f921450c
commit ec1f94eaa8
344 changed files with 40001 additions and 2 deletions
+237
View File
@@ -0,0 +1,237 @@
<script setup lang="ts">
import { ref, computed, onMounted, nextTick, h } from "vue";
import { useRouter } from "vue-router";
import { useRequest } from "alova/client";
import { Message } from "view-ui-plus";
import { noticeApi } from "@/api/module/notice";
import type { NoticeVo, NoticeQuery } from "@/types/notice";
import ApprovalFlowEditor, { type FlowModel } from "@/components/ApprovalFlowEditor.vue";
import MyConfirm from "@/components/MyConfirm";
import Utils from "@/utils";
/**
* 草稿箱:未发送的通知草稿(status=0 本人)。
* 操作:继续编辑(带参进写通知)、提交审批(选审批人后 Submit,空选复用草稿已存流程定义)、删除。
*/
const router = useRouter();
const keyword = ref("");
const pageNum = ref(1);
const pageSize = ref(parseInt(localStorage.getItem("customPageCount") || "10"));
const { data: page, loading, send: reload } = useRequest(
(params: NoticeQuery) => noticeApi.draftList(params),
{ immediate: false, initialData: { content: [], total: 0, pageIndex: 1, pageSize: 10, totalPages: 0, hasNext: false } }
);
async function run() {
try {
await reload({ keyword: keyword.value || "", pageIndex: pageNum.value, pageSize: pageSize.value, orderByTime: "2" });
} catch (e: any) {
Message.error(e.message || "获取草稿列表失败");
}
}
function doSearch() {
pageNum.value = 1;
run();
}
function pageUpdate(p: number) {
pageNum.value = p;
run();
}
function pageSizeUpdate(size: number) {
pageNum.value = 1;
pageSize.value = size;
localStorage.setItem("customPageCount", String(size));
run();
}
onMounted(run);
/* ---------- 继续编辑 ---------- */
function edit(row: NoticeVo) {
router.push({ path: "/list/new", query: { serid: row.id } });
}
/* ---------- 删除 ---------- */
function del(row: NoticeVo) {
MyConfirm({
title: "删除草稿",
msg: `确定删除“ ${row.title} ”这份草稿吗?`,
info: "删除后不可恢复",
async onOk() {
try {
await noticeApi.deleteNotice(String(row.id)).send();
Message.success("操作成功!");
if ((page.value?.content?.length || 0) <= 1 && pageNum.value > 1) pageNum.value -= 1;
run();
} catch (e: any) {
Message.error(e.message || "删除失败");
}
},
});
}
/* ---------- 提交审批(弹窗选审批人 → Submit) ---------- */
const submitModal = ref(false);
const submitRow = ref<NoticeVo | null>(null);
const flowModel = ref<FlowModel>({ enabled: false, flow: [] });
const flowEditorRef = ref();
const submitting = ref(false);
function openSubmit(row: NoticeVo) {
submitRow.value = row;
flowModel.value = { enabled: false, flow: [] };
submitModal.value = true;
// 弹窗复用同一编辑器实例,打开时重置内部勾选与步骤
nextTick(() => flowEditorRef.value?.setFlow(null));
}
async function doSubmit() {
if (!submitRow.value) return;
// 勾了审批但一步都没选人 → 拦截;未勾选(不重选人)则沿用草稿已存流程定义
if (flowEditorRef.value && !flowEditorRef.value.validate()) {
Message.info("请为审批流程选择审批人,或取消勾选");
return;
}
const flow = flowModel.value.flow || [];
submitting.value = true;
try {
const steps = flow.length
? flow.map((s, i) => ({ name: `第${i + 1}步`, vote: s.vote, approverTeaIds: [...s.approverTeaIds] }))
: undefined;
await noticeApi.submit({ serid: submitRow.value.id, steps }).send();
Message.success("已提交审批,可在「已发管理」查看进度");
submitModal.value = false;
run();
} catch (e: any) {
Message.error(e.message || "提交审批失败");
} finally {
submitting.value = false;
}
}
/* ---------- 表格 ---------- */
const columns = [
{ title: "序号", type: "index", width: 90, align: "center" },
{
title: "标题",
key: "title",
align: "left",
tooltip: true,
render: (h: any, p: any) => {
const row: any = p.row;
const children = [h("span", {}, row.title)];
if (row.timingSendTime) {
children.push(h("Tag", { style: "margin-left:6px" }, () => "定时"));
}
return h("div", {}, children);
},
},
{
title: "类型",
width: 100,
align: "center",
render: (h: any, p: any) =>
h("Tag", { color: p.row.type == 2 ? "error" : "default" }, () => p.row.typeDesc || (p.row.type == 2 ? "重要" : "普通")),
},
{
title: "定时发送",
width: 170,
align: "left",
render: (h: any, p: any) => h("span", {}, p.row.timingSendTime ? String(p.row.timingSendTime).replace("T", " ").slice(0, 16) : "—"),
},
{
title: "最后修改",
width: 170,
align: "left",
render: (h: any, p: any) => h("span", {}, String(p.row.updateTime || p.row.createTime || "").replace("T", " ").slice(0, 16)),
},
{
title: "操作",
width: 220,
align: "center",
fixed: "right",
render: (h: any, p: any) => {
const row: any = p.row;
return [
Utils.operatingHandle(h, "继续编辑", "icon-xiugaijl", () => edit(row)),
Utils.operatingHandle(h, "提交审批", "icon-shenpi", () => openSubmit(row)),
Utils.operatingHandle(h, "删除草稿", "icon-ashbin", () => del(row)),
];
},
},
];
const tableHeight = computed(() => Utils.useTableHeight({ isSearch: true, isOperat: true, isPage: true }));
</script>
<template>
<div class="page-wrapper">
<div class="main-container">
<!-- 搜索区 -->
<div class="search-wrap fix">
<Button class="fl" type="primary" size="large" @click="router.push('/list/new')">写公告</Button>
<Input
class="fr"
style="width: 220px"
search
suffix="ios-search"
placeholder="输入标题关键字搜索"
v-model="keyword"
@on-search="doSearch"
@on-clear="doSearch"
/>
</div>
<!-- 表格 + 分页 -->
<Table
:columns="columns"
:data="page.content"
class="link-table table-bottom-box"
:height="tableHeight"
:loading="loading"
no-data-text="草稿箱是空的"
></Table>
<div class="page-panel">
<div class="fl ml-15 align-middle"></div>
<Page
class="page-box fr"
:total="page.total"
:current="pageNum"
:page-size="pageSize"
:page-size-opts="[10, 20, 30, 40]"
@on-page-size-change="pageSizeUpdate"
@on-change="pageUpdate"
placement="top"
show-total
show-sizer
></Page>
</div>
<!-- 提交审批弹窗 -->
<Modal v-model="submitModal" title="提交审批" :mask-closable="false" width="620px">
<p class="submit-tip">公告:{{ submitRow?.title }}</p>
<ApprovalFlowEditor ref="flowEditorRef" v-model="flowModel" unchecked-text="(不勾选=沿用草稿已存流程)"></ApprovalFlowEditor>
<p class="submit-hint">不重选审批人时,将沿用草稿保存时配置的审批流程。</p>
<template #footer>
<Button type="warning" :loading="submitting" @click="doSubmit">提交审批</Button>
<Button @click="submitModal = false" style="margin-left: 8px">取消</Button>
</template>
</Modal>
</div>
</div>
</template>
<style scoped>
.submit-tip {
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
}
.submit-hint {
color: #808695;
font-size: 12px;
margin-top: 8px;
}
</style>