feat: 办事大厅前端源码首次入库(事项列表/详情/申报/管理端)
build / build (push) Successful in 1m55s

This commit is contained in:
chenxing
2026-09-15 11:00:57 +08:00
parent 7a2ea27f1e
commit 22dfb70377
328 changed files with 26089 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
<script setup lang="ts">
/** 办事事项列表(modId 23):筛选/发布/下架/删除/同步部门名。 */
import { h, onMounted, ref } from "vue";
import { useRouter } from "vue-router";
import { Message, Modal } from "view-ui-plus";
import { svcItemApi } from "@/api/module/svc";
import type { SvcItemPageItem } from "@/types/svc";
import { useSite } from "@/utils/site";
const router = useRouter();
const { currentSiteCode, sites, loadSites, setSite } = useSite();
const loading = ref(false);
const list = ref<SvcItemPageItem[]>([]);
const total = ref(0);
const page = ref(1);
const pageSize = ref(10);
const status = ref<number | undefined>(undefined);
const keyword = ref("");
const statusName = (s: number) => (s === 1 ? "已发布" : s === 2 ? "已下架" : "草稿");
const statusColor = (s: number) => (s === 1 ? "success" : s === 2 ? "warning" : "default");
const handleModeName = (m: number) => (m === 1 ? "线上" : m === 2 ? "线下" : "线上线下");
const columns = [
{ title: "编码", key: "itemCode", width: 140 },
{ title: "名称", key: "title", minWidth: 200 },
{ title: "类别", key: "categoryName", width: 110 },
{ title: "部门", key: "deptName", width: 130 },
{
title: "办理方式",
width: 90,
render: (h: any, p: any) => h("span", handleModeName(p.row.handleMode)),
},
{ title: "在线办理", slot: "online", width: 110 },
{ title: "状态", slot: "status", width: 90 },
{ title: "浏览量", key: "viewCount", width: 80 },
{ title: "操作", slot: "action", width: 200 },
];
async function load() {
if (!currentSiteCode.value) return;
loading.value = true;
try {
const res: any = await svcItemApi
.page({
siteCode: currentSiteCode.value,
status: status.value,
keyword: keyword.value,
page: page.value,
pageSize: pageSize.value,
})
.send();
total.value = res.total || 0;
list.value = res.list || [];
} finally {
loading.value = false;
}
}
function onSiteChange(code: string) {
setSite(code);
page.value = 1;
load();
}
function edit(row?: SvcItemPageItem) {
router.push({ path: "/svc/item/edit", query: { id: row?.id ? String(row.id) : undefined } });
}
async function publish(row: SvcItemPageItem) {
await svcItemApi.publish(currentSiteCode.value, row.id).send();
Message.success("已发布");
load();
}
async function offline(row: SvcItemPageItem) {
await svcItemApi.offline(currentSiteCode.value, row.id).send();
Message.success("已下架");
load();
}
function remove(row: SvcItemPageItem) {
Modal.confirm({
title: "删除确认",
content: `确定删除事项「${row.title}」吗?删除后不可恢复。`,
onOk: async () => {
await svcItemApi.delete(currentSiteCode.value, row.id).send();
Message.success("已删除");
load();
},
});
}
async function syncDept() {
const res: any = await svcItemApi.syncDeptName(currentSiteCode.value).send();
Message.success(`已同步 ${res.updated} 条部门名快照`);
load();
}
onMounted(async () => {
await loadSites();
load();
});
</script>
<template>
<div class="page">
<Card :bordered="false" dis-hover>
<div class="bar">
<Select :model-value="currentSiteCode" style="width: 240px" @on-change="onSiteChange">
<Option v-for="s in sites" :key="s.siteCode" :value="s.siteCode">
{{ s.name }}({{ s.siteCode }})
</Option>
</Select>
<Select v-model="status" clearable placeholder="状态" style="width: 120px" @on-change="load">
<Option :value="0">草稿</Option>
<Option :value="1">已发布</Option>
<Option :value="2">已下架</Option>
</Select>
<Input
v-model="keyword"
search
enter-button
placeholder="名称/编码"
style="width: 240px"
@on-search="load"
/>
<Button type="primary" @click="edit()">新建事项</Button>
<Button @click="syncDept">同步部门名</Button>
</div>
<Table :loading="loading" :columns="columns" :data="list">
<template #status="{ row }">
<Tag :color="statusColor(row.status)">{{ statusName(row.status) }}</Tag>
</template>
<template #online="{ row }">
<Tag v-if="row.onlineFlag === 1" color="green">可在线办理</Tag>
<span v-else>—</span>
</template>
<template #action="{ row }">
<Button size="small" type="text" @click="edit(row)">编辑</Button>
<Button v-if="row.status !== 1" size="small" type="text" @click="publish(row)">发布</Button>
<Button v-if="row.status === 1" size="small" type="text" @click="offline(row)">下架</Button>
<Button size="small" type="text" style="color: #ed4014" @click="remove(row)">删除</Button>
</template>
</Table>
<Page
class="pager"
:total="total"
:current="page"
:page-size="pageSize"
show-total
@on-change="(p: number) => { page = p; load(); }"
/>
</Card>
</div>
</template>
<style scoped>
.bar {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.pager {
margin-top: 12px;
text-align: right;
}
</style>