- ServiceFormManage:被绑定列显示"已绑定 N 个事项",弹窗列明细(站点/编码/名称/状态)可直达事项编辑(跨站点先切站点);发布未绑定时 confirm 引导前往办事事项;保存文案带下一步;编辑弹窗"预览效果"复用 DynamicForm 渲染 schemaJson - ServiceItemEdit:选中草稿/停用表单时红字提示"发布后才能在发起页实际填写",下拉选项标注状态 - types/svc.ts:SvcFormVo +refItems、新增 SvcFormItemBrief
This commit is contained in:
@@ -152,6 +152,16 @@ export interface SvcFormVo {
|
||||
schemaJson: string;
|
||||
publishTime?: string;
|
||||
referenced?: boolean;
|
||||
/** 绑定本表单的事项明细(表单页反查使用位置;sch 级共享,可能跨站点) */
|
||||
refItems?: SvcFormItemBrief[];
|
||||
}
|
||||
|
||||
export interface SvcFormItemBrief {
|
||||
id: number;
|
||||
itemCode: string;
|
||||
title: string;
|
||||
siteCode: string;
|
||||
status: number;
|
||||
}
|
||||
|
||||
export interface SvcFormSaveRequest {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
/** 表单管理(modId 25):列表/JSON 编辑(发布版保存=自动升版本)/发布/删除/版本轨迹。 */
|
||||
/** 表单管理(modId 25):列表/JSON 编辑(发布版保存=自动升版本)/发布/删除/版本轨迹/绑定明细/schema 预览。 */
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { Message, Modal } from "view-ui-plus";
|
||||
import { svcFormApi } from "@/api/module/svc";
|
||||
import type { SvcFormVo } from "@/types/svc";
|
||||
import type { SvcFormItemBrief, SvcFormVo } from "@/types/svc";
|
||||
import { useSite } from "@/utils/site";
|
||||
import DynamicForm from "@/components/DynamicForm.vue";
|
||||
|
||||
const router = useRouter();
|
||||
const { currentSiteCode, sites, loadSites, setSite } = useSite();
|
||||
const loading = ref(false);
|
||||
const list = ref<SvcFormVo[]>([]);
|
||||
@@ -14,9 +17,15 @@ const versionsModal = ref(false);
|
||||
const saving = ref(false);
|
||||
const form = ref<any>({ schemaJson: '{\n "groups": [\n { "title": "基本信息", "fields": [\n { "key": "reason", "label": "申请事由", "type": "textarea", "required": true }\n ] }\n ]\n}' });
|
||||
const versionRows = ref<SvcFormVo[]>([]);
|
||||
const refsModal = ref(false);
|
||||
const refRows = ref<SvcFormItemBrief[]>([]);
|
||||
const refFormName = ref("");
|
||||
const previewModal = ref(false);
|
||||
const previewData = ref<Record<string, any>>({});
|
||||
|
||||
const statusName = (s: number) => (s === 1 ? "已发布" : s === 2 ? "停用" : "草稿");
|
||||
const statusColor = (s: number) => (s === 1 ? "success" : "default");
|
||||
const itemStatusName = (s: number) => (s === 1 ? "已发布" : s === 2 ? "已下线" : "草稿");
|
||||
|
||||
async function load() {
|
||||
if (!currentSiteCode.value) return;
|
||||
@@ -48,7 +57,7 @@ async function save() {
|
||||
saving.value = true;
|
||||
try {
|
||||
await svcFormApi.save(currentSiteCode.value, form.value).send();
|
||||
Message.success("已保存(已发布版本会自动生成新草稿版本)");
|
||||
Message.success("已保存为草稿。下一步:发布表单,并在「办事事项」中绑定使用");
|
||||
modal.value = false;
|
||||
load();
|
||||
} finally {
|
||||
@@ -58,8 +67,18 @@ async function save() {
|
||||
|
||||
async function publish(row: SvcFormVo) {
|
||||
await svcFormApi.publish(currentSiteCode.value, row.id).send();
|
||||
Message.success("已发布");
|
||||
load();
|
||||
if (!row.referenced) {
|
||||
// 使用场景引导:发布后唯一消费入口是事项绑定,未绑定的直接带过去
|
||||
Modal.confirm({
|
||||
title: "发布成功,下一步去绑定事项",
|
||||
content: `表单「${row.name}」尚未绑定任何事项。绑定后用户在事项发起页才能填写此表单,是否前往办事事项?`,
|
||||
okText: "前往办事事项",
|
||||
onOk: () => router.push("/svc/item"),
|
||||
});
|
||||
} else {
|
||||
Message.success("已发布");
|
||||
}
|
||||
}
|
||||
|
||||
function remove(row: SvcFormVo) {
|
||||
@@ -79,6 +98,31 @@ async function showVersions(row: SvcFormVo) {
|
||||
versionsModal.value = true;
|
||||
}
|
||||
|
||||
/** 绑定明细:这张表单用在了哪些事项上(可跨站点),并可直达事项编辑 */
|
||||
function showRefs(row: SvcFormVo) {
|
||||
refFormName.value = row.name;
|
||||
refRows.value = row.refItems || [];
|
||||
refsModal.value = true;
|
||||
}
|
||||
|
||||
/** 跨站点明细先切站点再跳编辑,保证事项编辑页站点上下文一致 */
|
||||
function editRefItem(item: SvcFormItemBrief) {
|
||||
setSite(item.siteCode);
|
||||
router.push(`/svc/item/edit?id=${item.id}`);
|
||||
}
|
||||
|
||||
/** schema 预览:发布前即可看到表单长相(复用发起页 DynamicForm 渲染器) */
|
||||
function openPreview() {
|
||||
try {
|
||||
JSON.parse(form.value.schemaJson);
|
||||
} catch {
|
||||
Message.error("表单结构不是合法 JSON,无法预览");
|
||||
return;
|
||||
}
|
||||
previewData.value = {};
|
||||
previewModal.value = true;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadSites();
|
||||
load();
|
||||
@@ -89,9 +133,9 @@ const cols = [
|
||||
{ title: "名称", key: "name", minWidth: 140 },
|
||||
{ title: "最新版本", key: "version", width: 90 },
|
||||
{ title: "状态", slot: "status", width: 90 },
|
||||
{ title: "被绑定", slot: "referenced", width: 90 },
|
||||
{ title: "被绑定", slot: "referenced", width: 110 },
|
||||
{ title: "发布时间", key: "publishTime", width: 160 },
|
||||
{ title: "操作", slot: "action", width: 220 },
|
||||
{ title: "操作", slot: "action", width: 260 },
|
||||
];
|
||||
</script>
|
||||
|
||||
@@ -109,12 +153,13 @@ const cols = [
|
||||
<Tag :color="statusColor(row.status)">{{ statusName(row.status) }}</Tag>
|
||||
</template>
|
||||
<template #referenced="{ row }">
|
||||
<Tag v-if="row.referenced" color="blue">已绑定事项</Tag>
|
||||
<span v-else>—</span>
|
||||
<a v-if="row.referenced" @click="showRefs(row)">已绑定 {{ (row.refItems || []).length }} 个事项</a>
|
||||
<span v-else style="color: #999">未绑定</span>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Button size="small" type="text" @click="open(row)">编辑</Button>
|
||||
<Button v-if="row.status === 0" size="small" type="text" @click="publish(row)">发布</Button>
|
||||
<Button v-if="!row.referenced" size="small" type="text" @click="router.push('/svc/item')">去绑定</Button>
|
||||
<Button size="small" type="text" @click="showVersions(row)">版本</Button>
|
||||
<Button size="small" type="text" style="color: #ed4014" @click="remove(row)">删除</Button>
|
||||
</template>
|
||||
@@ -135,6 +180,7 @@ const cols = [
|
||||
契约:{"groups":[{title, fields:[{key,label,type,required,pattern,min,max,maxLength,options,accept,maxSize,maxFiles,…}]}]}
|
||||
;一期控件:text/textarea/number/date/select/radio/upload
|
||||
</div>
|
||||
<Button size="small" type="text" @click="openPreview">预览效果</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<template #footer>
|
||||
@@ -143,6 +189,37 @@ const cols = [
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="previewModal" width="640" title="表单预览(发起页渲染效果)">
|
||||
<DynamicForm :schema-json="form.schemaJson" v-model:form-data="previewData" />
|
||||
<template #footer>
|
||||
<Button @click="previewModal = false">关闭</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="refsModal" width="720" :title="`「${refFormName}」被以下事项使用`">
|
||||
<Table size="small" :columns="[
|
||||
{ title: '站点', key: 'siteCode', width: 100 },
|
||||
{ title: '事项编码', key: 'itemCode', width: 140 },
|
||||
{ title: '事项名称', key: 'title', minWidth: 140 },
|
||||
{ title: '状态', slot: 'refStatus', width: 90 },
|
||||
{ title: '操作', slot: 'refAction', width: 80 },
|
||||
]" :data="refRows">
|
||||
<template #refStatus="{ row }">
|
||||
<Tag :color="row.status === 1 ? 'success' : 'default'">{{ itemStatusName(row.status) }}</Tag>
|
||||
</template>
|
||||
<template #refAction="{ row }">
|
||||
<Button size="small" type="text" @click="editRefItem(row)">编辑</Button>
|
||||
</template>
|
||||
</Table>
|
||||
<div class="tip" style="margin-top: 8px">
|
||||
用户在绑定此表单的事项发起页填写该表单;草稿表单发布后才会实际下发给发起页。
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button @click="refsModal = false">关闭</Button>
|
||||
<Button type="primary" @click="refsModal = false; router.push('/svc/item')">去办事事项</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="versionsModal" title="版本轨迹">
|
||||
<Table size="small" :columns="[
|
||||
{ title: '版本', key: 'version', width: 80 },
|
||||
|
||||
@@ -40,6 +40,13 @@ const uploadingCover = ref(false);
|
||||
const editing = computed(() => !!route.query.id);
|
||||
const pageTitle = computed(() => (editing.value ? "编辑事项" : "新建事项"));
|
||||
|
||||
/** 选中表单的最新版本是否为草稿/停用(草稿可先绑,但发起页要等发布才生效) */
|
||||
const selectedFormDraft = computed(() => {
|
||||
if (!form.value.formCode) return false;
|
||||
const f = forms.value.find((x) => x.code === form.value.formCode);
|
||||
return !!f && f.status !== 1;
|
||||
});
|
||||
|
||||
/** 部门树扁平化(缩进展示,承袭 CMS flattenDepts) */
|
||||
const deptOptions = computed(() => {
|
||||
const out: { id: number; label: string }[] = [];
|
||||
@@ -233,8 +240,14 @@ onMounted(loadAll);
|
||||
<Col span="12">
|
||||
<FormItem label="办理表单">
|
||||
<Select v-model="form.formCode" clearable placeholder="该事项发起时填写的自定义表单">
|
||||
<Option v-for="f in forms" :key="f.code" :value="f.code">{{ f.name }}</Option>
|
||||
<Option v-for="f in forms" :key="f.code" :value="f.code">
|
||||
{{ f.name }}{{ f.status !== 1 ? `(${f.status === 2 ? "已停用" : "草稿"})` : "" }}
|
||||
</Option>
|
||||
</Select>
|
||||
<div v-if="selectedFormDraft" class="tip" style="color: #ed4014">
|
||||
该表单尚未发布,发布后才能在发起页实际填写;请到「表单管理」发布。
|
||||
</div>
|
||||
<div v-else class="tip">发起页按表单编码取最新已发布版本渲染</div>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="24">
|
||||
|
||||
Reference in New Issue
Block a user