build / build (push) Successful in 10m17s
- 同步仓库 CI 配置 .gitea/workflows/build.yml - 纳入 src/public/config/scripts 等工程文件 - .gitignore 增加 .scratch/.backup/.trash,排除本地临时产物
238 lines
8.2 KiB
Vue
238 lines
8.2 KiB
Vue
<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>
|