feat(p89+p90): 复制表单链接 + 设计器整表预览
build / build (push) Failing after 32s

P89 复制填报链接(旧系统先例对齐:Cms AttachmentManage 的 copyToClipboard
+ 文案「链接已复制」;svc-hall 同款 execCommand 兜底):
- 新增 utils/fillLink.ts:buildFillLink 从当前地址推导部署根(生产
  /form-center/front/、本地 dev=/),hash 路由 query 进 hash(#/f/{code}?appCode=),
  中心表单不带 appCode;copyToClipboard=navigator.clipboard 优先 +
  临时 textarea+execCommand 兜底,双失败亮链接提示手动复制不静默。
- Forms.vue 行操作「复制链接」文字链(P51 形态,收「更多」逻辑不动);
  FormDesigner 头部「复制链接」按钮(草稿态可复制,发布后链接即生效)。

P90 设计器整表预览:
- 新增 components/designer/PreviewModal.vue:全屏 Modal 按填报视角渲染当前
  画布内容(含未保存改动);控件件与填报页同源(fieldWidget pc),选项解析
  与 DesignerCanvas.resolvedOptions 同规则(inline 直用/字典引用展开,字典
  缺域显式降级);必填红星/占位/约束 tip 同 Fill.vue 位;值容器本地可试填,
  不校验不提交;locked 只读态也可用;空分组/未知类型显式空态。
- FormDesigner 头部「预览」按钮。

验证:vue-tsc --noEmit 干净;vite build 通过。
This commit is contained in:
chenxing
2026-10-15 23:42:25 +08:00
parent 82a9801ac6
commit 79c98e4280
4 changed files with 259 additions and 0 deletions
+13
View File
@@ -20,11 +20,13 @@ import DesignerCanvas from "@/components/designer/DesignerCanvas.vue";
import FieldPropPanel from "@/components/designer/FieldPropPanel.vue";
import FormConfigModal from "@/components/form/FormConfigModal.vue";
import FormAdminModal from "@/components/admin/FormAdminModal.vue";
import PreviewModal from "@/components/designer/PreviewModal.vue";
import { formApi } from "@/api/module/form";
import { dictApi } from "@/api/module/dict";
import type { DictView, FormView, VersionView } from "@/types/form";
import type { DesignField, DesignGroup } from "@/types/formSchema";
import { MAX_CHANGE_LOG_LEN, MAX_NAME_LEN } from "@/types/formSchema";
import { copyFillLink } from "@/utils/fillLink";
import {
buildSchemaJson,
cloneField,
@@ -61,6 +63,8 @@ const baseline = ref("");
const configRef = ref<InstanceType<typeof FormConfigModal> | null>(null);
/** 单表单管理员弹窗(与设计器的「表单配置」并排,方案 §6.4:与表单列表行操作同一形态) */
const adminRef = ref<InstanceType<typeof FormAdminModal> | null>(null);
/** P90:整表预览弹层(含未保存改动,locked 只读态也可用) */
const previewRef = ref<InstanceType<typeof PreviewModal> | null>(null);
const publishModal = reactive({ visible: false, changeLog: "" });
const locked = computed(() => viewingPublished.value);
@@ -306,6 +310,12 @@ function onConfigSaved(res: FormView) {
form.value = res;
}
/** P89:复制当前表单的填报链接(草稿态也可复制——链接按 code 寻址,发布后即生效) */
function onCopyLink() {
if (!form.value) return;
copyFillLink(form.value);
}
async function boot() {
if (!uuid.value) {
Message.warning("请从表单列表进入设计器");
@@ -348,6 +358,8 @@ onMounted(boot);
</span>
</div>
<div class="head-right">
<Button icon="ios-link" @click="onCopyLink">复制链接</Button>
<Button icon="ios-eye" @click="previewRef?.open()">预览</Button>
<Button @click="configRef?.open()">表单配置</Button>
<Button @click="adminRef?.open(uuid, form?.name)">表单管理员</Button>
<Button @click="copyAs">另存为副本</Button>
@@ -399,6 +411,7 @@ onMounted(boot);
<FormConfigModal ref="configRef" :form="form" @saved="onConfigSaved" />
<FormAdminModal ref="adminRef" />
<PreviewModal ref="previewRef" :groups="groups" :dicts="dicts" />
<Modal v-model="publishModal.visible" title="发布新版本" :mask-closable="false">
<p class="publish-tip">
+2
View File
@@ -16,6 +16,7 @@ import { useRouter } from "vue-router";
import { Message, Modal } from "view-ui-plus";
import { formApi } from "@/api/module/form";
import { actionColumn } from "@/utils/tableActions";
import { copyFillLink } from "@/utils/fillLink";
import { useElementHeight } from "@/utils/hook/useElementHeight";
import FormConfigModal from "@/components/form/FormConfigModal.vue";
import FormAdminModal from "@/components/admin/FormAdminModal.vue";
@@ -105,6 +106,7 @@ const columns = computed(() => [
[
{ key: "design", label: "设计", on: (row: FormView) => goDesigner(row) },
{ key: "config", label: "配置", on: (row: FormView) => openConfig(row) },
{ key: "copyLink", label: "复制链接", on: (row: FormView) => copyFillLink(row) },
{
key: "publish",
label: "发布",