添加字典

This commit is contained in:
2026-06-10 15:21:47 +08:00
parent c7ac4c50e0
commit fd257f027b
5 changed files with 310 additions and 220 deletions
+13
View File
@@ -0,0 +1,13 @@
import request from "@/utils/request";
export function getDictDataByType(dictType) {
return request({
url: "/admin/dict/getDictDataByType",
method: "post",
data: {
params: {
dictType,
},
},
}).then((res) => res?.result || []);
}
@@ -193,6 +193,10 @@ import {
queryPublishedManifestList,
} from "@/api/manifest.js";
import { uploadLaunchFile } from "@/api/launch.js";
import {
buildTemplateFieldLabelMap,
loadTemplateFieldList,
} from "../../shared/templateFieldDict.js";
import {
contractSourceOptions,
contractTypeOptions,
@@ -218,32 +222,6 @@ const contractCreateModeOptions = [
{ label: "手动创建", value: "manual" },
];
// ========== 可绑定业务字段列表(用于映射下拉和展示) ==========
const templateFieldList = [
{ value: "contractName", label: "合同名称" },
{ value: "contractCode", label: "合同编码" },
{ value: "contractType", label: "合同类型" },
{ value: "contractAmountDisplay", label: "合同金额" },
{ value: "effectiveStart", label: "有效期起" },
{ value: "effectiveEnd", label: "有效期止" },
{ value: "effectivePeriod", label: "有效期区间" },
{ value: "paymentMethod", label: "付款方式" },
{ value: "primaryContent", label: "合同标的说明" },
{ value: "amountExplain", label: "金额说明" },
{ value: "partyAName", label: "甲方名称" },
{ value: "partyBName", label: "乙方名称" },
{ value: "partyCName", label: "丙方名称" },
{ value: "partyDName", label: "丁方名称" },
{ value: "partyEName", label: "戊方名称" },
{ value: "partyFName", label: "己方名称" },
{ value: "counterpartySummary", label: "合同方摘要" },
{ value: "attachmentSummary", label: "附件情况" },
{ value: "templateLabel", label: "模板名称" },
{ value: "signDate", label: "签署日期" },
{ value: "businessRemark", label: "业务备注" },
{ value: "contractSubject", label: "合同标的说明" },
];
// ========== 格式化合同金额(如 368,000.00 元) ==========
function formatContractAmount(value) {
if (value === undefined || value === null || value === "") return "";
@@ -763,63 +741,12 @@ function copyContractFormData(data = {}) {
// ========== 模板变量预览数据构建 ==========
/** 将合同表单数据转换为模板变量字典(用于 docxtemplater 渲染) */
function buildTemplatePreviewData(
formData,
templateLabel = "",
creationMode = "template",
) {
const form = copyContractFormData(formData);
const parties = getPartyList(form);
const templateValues = form.templateFieldValues || {};
function pick(fieldKey, fallback = "") {
if (
templateValues[fieldKey] !== undefined &&
templateValues[fieldKey] !== null &&
templateValues[fieldKey] !== ""
) {
return templateValues[fieldKey];
}
return fallback;
}
return {
contractName: pick("contractName", form.contractName || ""),
contractCode: pick("contractCode", form.contractCode || ""),
contractType: pick("contractType", form.contractType || ""),
contractAmountDisplay: pick(
"contractAmountDisplay",
formatContractAmount(form.contractAmount),
),
effectiveStart: pick("effectiveStart", form.effectiveStart || ""),
effectiveEnd: pick("effectiveEnd", form.effectiveEnd || ""),
effectivePeriod: pick(
"effectivePeriod",
[form.effectiveStart, form.effectiveEnd].filter(Boolean).join(" 至 "),
),
paymentMethod: pick("paymentMethod", form.paymentMethod || ""),
primaryContent: pick("primaryContent", form.primaryContent || ""),
amountExplain: pick("amountExplain", form.amountExplain || ""),
partyAName: pick("partyAName", parties[0]?.companyName || ""),
partyBName: pick("partyBName", parties[1]?.companyName || ""),
partyCName: pick("partyCName", parties[2]?.companyName || ""),
partyDName: pick("partyDName", parties[3]?.companyName || ""),
partyEName: pick("partyEName", parties[4]?.companyName || ""),
partyFName: pick("partyFName", parties[5]?.companyName || ""),
counterpartySummary: pick("counterpartySummary", getPartySummary(form)),
attachmentSummary: pick(
"attachmentSummary",
formatFileSummary(form.otherAttachmentList),
),
templateLabel: pick(
"templateLabel",
templateLabel || (creationMode === "manual" ? "手动创建" : ""),
),
signDate: pick("signDate", form.signDate || dayjs().format("YYYY-MM-DD")),
businessRemark: pick("businessRemark", ""),
contractSubject: pick("contractSubject", ""),
templateFieldValuesJson: JSON.stringify(form.templateFieldValues || {}),
};
function buildTemplateRenderData(templateFieldValues = {}) {
const data = {};
(templateFieldList.value || []).forEach((item) => {
data[item.value] = templateFieldValues?.[item.value] ?? "";
});
return data;
}
// ========== 提交报文构建 ==========
@@ -925,6 +852,7 @@ const previewError = ref("");
const previewBlob = ref(null);
const manualBodyFileList = ref([]);
const publishedTemplates = ref([]);
const templateFieldList = ref([]);
const templateBufferCache = new Map();
let previewTimer = null;
@@ -945,13 +873,9 @@ const isViewMode = computed(() => modalMode.value === "view");
const modalTitle = computed(() => "合同正文配置");
const templateFieldLabelMap = computed(() => {
const map = {};
templateFieldList.forEach((item) => {
map[item.value] = item.label;
});
return map;
});
const templateFieldLabelMap = computed(() =>
buildTemplateFieldLabelMap(templateFieldList.value),
);
const launchFieldList = computed(() => {
if (creationMode.value === "manual") return [];
@@ -970,67 +894,8 @@ const launchFieldList = computed(() => {
}));
});
/** 模板字段中与合同主信息同名的直接映射字段 */
const CONTRACT_DIRECT_FIELDS = [
"contractName",
"contractCode",
"contractType",
"effectiveStart",
"effectiveEnd",
"paymentMethod",
"primaryContent",
"amountExplain",
"businessRemark",
"contractSubject",
];
function getLaunchFieldValue(fieldKey) {
// 1. 优先返回用户在"模板信息录入"中自定义的值
const templateVal = contractDetailState.value.templateFieldValues?.[fieldKey];
if (templateVal !== undefined && templateVal !== null && templateVal !== "") {
return templateVal;
}
// 2. 若字段与合同主信息直接同名,自动带入主信息的值
if (CONTRACT_DIRECT_FIELDS.includes(fieldKey)) {
return contractDetailState.value[fieldKey] ?? "";
}
// 3. 特殊计算字段
if (fieldKey === "contractAmountDisplay") {
return formatContractAmount(contractDetailState.value.contractAmount);
}
if (fieldKey === "effectivePeriod") {
return [
contractDetailState.value.effectiveStart,
contractDetailState.value.effectiveEnd,
]
.filter(Boolean)
.join(" 至 ");
}
if (fieldKey === "templateLabel") {
return activeTemplate.value?.templateName || "";
}
if (fieldKey === "signDate") {
return contractDetailState.value.signDate || dayjs().format("YYYY-MM-DD");
}
if (fieldKey === "counterpartySummary") {
return getPartySummary(contractDetailState.value.partyState);
}
if (fieldKey === "attachmentSummary") {
return formatFileSummary(contractDetailState.value.otherAttachmentList);
}
// 4. 合同方名称字段
if (/^party[A-F]Name$/.test(fieldKey)) {
const fieldIndex = PARTY_NAME_KEYS.indexOf(fieldKey);
return (
getPartyList(contractDetailState.value.partyState)[fieldIndex]
?.companyName ?? ""
);
}
return "";
return contractDetailState.value.templateFieldValues?.[fieldKey] ?? "";
}
function setLaunchFieldValue(fieldKey, value) {
@@ -1044,11 +909,7 @@ function setLaunchFieldValue(fieldKey, value) {
}
const templateVariables = computed(() =>
buildTemplatePreviewData(
contractDetailState.value,
activeTemplate.value?.templateName || "",
creationMode.value,
),
buildTemplateRenderData(contractDetailState.value.templateFieldValues || {}),
);
const hasPreviewSource = computed(() => {
@@ -1137,12 +998,17 @@ function syncManualBodyFileList() {
}
function loadPublishedTemplates() {
// TODO: 这里后续替换为“已发布模板列表接口”
return queryPublishedManifestList().then((list) => {
publishedTemplates.value = list;
});
}
function loadTemplateFields() {
return loadTemplateFieldList().then((list) => {
templateFieldList.value = list || [];
});
}
function getManifestDetailLocal(templateId) {
return (
publishedTemplates.value.find((item) => item.id === templateId) || null
@@ -1234,22 +1100,16 @@ async function buildFilledDocumentBlob() {
},
});
//这里是生成的测试数据
const sourceValues = buildTemplatePreviewData(
contractDetailState.value,
activeTemplate.value?.templateName || "",
creationMode.value,
const sourceValues = buildTemplateRenderData(
contractDetailState.value.templateFieldValues || {},
);
const mappings = activeTemplate.value.variableMappings || [];
const renderData = {};
//这部分是匹配的关键
if (mappings.length) {
mappings.forEach((item) => {
if (!item.variableKey) return;
renderData[item.variableKey] =
sourceValues[item.bindField] ??
contractDetailState.value[item.bindField] ??
"";
renderData[item.variableKey] = sourceValues[item.bindField] ?? "";
});
} else {
Object.assign(renderData, sourceValues);
@@ -1460,7 +1320,7 @@ function resetForm() {
async function showModal(initialValues = {}, mode = "create") {
modalMode.value = mode || "create";
const isCreate = modalMode.value === "create";
await loadPublishedTemplates();
await Promise.all([loadPublishedTemplates(), loadTemplateFields()]);
creationMode.value = isCreate
? "template"
@@ -16,8 +16,8 @@
<section class="template-config-panel">
<div class="panel-header">
<div>
<h3>合同范本维护</h3>
<p>支持模板分类Word 文件上传变量自动识别与业务字段匹配</p>
<h3>合同模板配置中心</h3>
<p>在线维护模板配置与变量映射推荐在本地 Word 编辑正文后回传系统</p>
</div>
</div>
@@ -97,7 +97,14 @@
</div>
</a-card>
<a-card size="small" title="模板件与正文预览" class="panel-card">
<a-card size="small" title="模板件与配置预览" class="panel-card">
<a-alert
type="info"
show-icon
class="workflow-alert"
message="推荐维护方式"
description="下载当前模板到本地 Word 编辑正文与占位符,保存后重新上传回传;平台负责变量识别、映射、预览与发布。"
/>
<div class="upload-meta">
<div>
<div class="meta-label">当前模板文件</div>
@@ -105,7 +112,12 @@
{{ formState.templateFileName || '尚未上传 .docx 模板文件' }}
</div>
</div>
<a-space v-if="!isViewMode">
<a-button @click="handleDownloadCurrentTemplate" :disabled="!hasTemplateFile">
<DownloadOutlined />
下载当前模板
</a-button>
<a-button @click="handleReDetectVariables">
<ReloadOutlined />
重新识别变量
@@ -134,33 +146,58 @@
<p class="ant-upload-hint">
上传后会自动识别花括号变量 `{contractName}``{partyAName}`并生成变量匹配清单
</p>
<p class="ant-upload-hint">
如需修改正文内容建议先下载模板到本地 Word 编辑后再重新上传回传
</p>
</a-upload-dragger>
</a-card>
<a-card size="small" title="变量匹配" class="panel-card">
<a-card size="small" title="占位符工具栏与变量映射" class="panel-card">
<div class="variable-header">
<div>
<div class="meta-label">已识别变量</div>
<div class="meta-value">{{ detectedVariableKeys.length ? detectedVariableKeys.join('、') : '暂未识别到变量' }}</div>
<div class="catalog-help">
点击下方字段标签可直接复制占位符点击加入映射可快速补充变量绑定
</div>
</div>
<a-space>
<a-button @click="handleDownloadVariableGuide">
<DownloadOutlined />
下载变量说明
</a-button>
<a-button v-if="!isViewMode" type="primary" ghost @click="handleAddManualVariable">
<PlusOutlined />
手动新增变量
</a-button>
</a-space>
</div>
<div class="catalog-wrap">
<div class="catalog-title">可绑定业务字段</div>
<div class="catalog-title">占位符工具栏</div>
<div class="catalog-list">
<a-tag
<div
v-for="item in templateFieldList"
:key="item.value"
class="catalog-item"
>
<a-tag
color="blue"
class="catalog-tag"
@click="handleQuickAddCatalogField(item.value)"
@click="handleCopyPlaceholder(item.value)"
>
{{ item.label }}
</a-tag>
<a-button
v-if="!isViewMode"
type="link"
size="small"
class="catalog-action"
@click.stop="handleQuickAddCatalogField(item.value)"
>
加入映射
</a-button>
</div>
</div>
</div>
@@ -242,7 +279,7 @@
<div class="panel-header">
<div>
<h3>模板预览</h3>
<p>右侧基于当前变量匹配渲染 Word 模板效果便于检查变量位置是否正确</p>
<p>右侧基于当前变量映射渲染模板效果于检查占位符位置与展示结果本页不直接在线修改 Word 正文</p>
</div>
<a-space size="small">
<a-tag color="geekblue">{{ formState.source || '未分类' }}</a-tag>
@@ -253,7 +290,7 @@
<div class="preview-shell">
<div v-if="!templateArrayBuffer" class="preview-state">
<FileWordOutlined style="font-size: 42px; color: #94a3b8" />
<p>上传 `.docx` 模板文件后这里会显示填充后的预览</p>
<p>上传 `.docx` 模板文件后这里会显示填充后的预览正文修改建议在本地 Word 完成后回传</p>
</div>
<div v-else ref="previewRef" class="preview-stage"></div>
<div v-if="rendering" class="preview-state preview-mask">
@@ -274,7 +311,13 @@
import { computed, nextTick, onBeforeUnmount, reactive, ref, watch } from 'vue'
import dayjs from 'dayjs'
import Docxtemplater from 'docxtemplater'
import { DeleteOutlined, FileWordOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons-vue'
import {
DeleteOutlined,
DownloadOutlined,
FileWordOutlined,
PlusOutlined,
ReloadOutlined,
} from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import PizZip from 'pizzip'
import { renderAsync } from 'docx-preview'
@@ -284,6 +327,11 @@ import {
uploadTemplateFile,
} from '@/api/manifest.js'
import { contractTypeTreeOptions } from '../contractTypeOptions.js'
import {
buildTemplateFieldLabelMap,
buildTemplateFieldOptions,
loadTemplateFieldList,
} from '../../shared/templateFieldDict.js'
// ========== 模板管理字典(后续可由后端接口替换) ==========
@@ -298,35 +346,6 @@ const templateSourceOptions = [
{ label: '对方文本', value: '对方文本' },
]
// 可绑定业务字段列表
const templateFieldList = [
{ value: 'contractName', label: '合同名称' },
{ value: 'contractCode', label: '合同编码' },
{ value: 'contractType', label: '合同类型' },
{ value: 'contractAmountDisplay', label: '合同金额' },
{ value: 'effectiveStart', label: '有效期起' },
{ value: 'effectiveEnd', label: '有效期止' },
{ value: 'effectivePeriod', label: '有效期区间' },
{ value: 'paymentMethod', label: '付款方式' },
{ value: 'primaryContent', label: '合同标的说明' },
{ value: 'amountExplain', label: '业务备注' },
{ value: 'partyAName', label: '甲方名称' },
{ value: 'partyBName', label: '乙方名称' },
{ value: 'partyCName', label: '丙方名称' },
{ value: 'counterpartySummary', label: '合同方摘要' },
{ value: 'contractSubject', label: '合同标的说明' },
{ value: 'businessRemark', label: '业务备注' },
{ value: 'attachmentSummary', label: '附件情况' },
{ value: 'templateLabel', label: '模板名称' },
{ value: 'signDate', label: '签署日期' },
]
// 业务字段下拉选项(由 templateFieldList 生成)
const templateFieldOptions = templateFieldList.map((item) => ({
label: `${item.label}${item.value}`,
value: item.value,
}))
// 批量创建变量映射
function createSimpleVariableList(list = []) {
return list.map((item, index) => ({
@@ -349,15 +368,23 @@ const templateUploadList = ref([])
const variableMappings = ref([])
const detectedVariableKeys = ref([])
const orgOptions = ref([])
const templateFieldList = ref([])
let previewTimer = null
let renderTaskId = 0
const templateFieldOptions = computed(() =>
buildTemplateFieldOptions(templateFieldList.value),
)
const templateFieldLabelMap = computed(() =>
buildTemplateFieldLabelMap(templateFieldList.value),
)
const formRules = {
templateName: [{ required: true, message: '请输入范本名称', trigger: 'blur' }],
source: [{ required: true, message: '请选择范本类型', trigger: 'change' }],
contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
selfPartyRole: [{ required: true, message: '请选择我方地位', trigger: 'change' }],
version: [{ required: true, message: '请输入版本号', trigger: 'blur' }],
publishOrgIds: [{ required: true, type: 'array', min: 1, message: '请选择发布范围', trigger: 'change' }],
}
@@ -369,7 +396,6 @@ function createDefaultFormState() {
templateCode: '',
source: '标准模板',
contractType: 'MM',
selfPartyRole: '甲方',
version: 'V1.0',
status: 'draft',
description: '',
@@ -387,10 +413,14 @@ const formState = reactive(createDefaultFormState())
const isViewMode = computed(() => modalMode.value === 'view')
const hasTemplateFile = computed(
() => !!(formState.templateFilePath || formState.templateFileName || templateArrayBuffer.value),
)
const modalTitle = computed(() => {
if (modalMode.value === 'view') return '查看合同范本'
if (modalMode.value === 'edit') return '编辑合同范本'
return '新增合同范本'
if (modalMode.value === 'view') return '查看模板配置'
if (modalMode.value === 'edit') return '编辑模板配置'
return '新增模板配置'
})
watch(
@@ -431,6 +461,13 @@ function resetState() {
}
}
async function ensureTemplateFieldListLoaded() {
if (templateFieldList.value.length) {
return
}
templateFieldList.value = await loadTemplateFieldList()
}
function schedulePreview() {
clearPreviewTimer()
previewTimer = window.setTimeout(() => {
@@ -635,6 +672,37 @@ function handleQuickAddCatalogField(fieldKey) {
)
}
function buildPlaceholderText(fieldKey) {
return `{${fieldKey}}`
}
async function copyTextToClipboard(text) {
if (navigator?.clipboard?.writeText) {
await navigator.clipboard.writeText(text)
return
}
const textarea = document.createElement('textarea')
textarea.value = text
textarea.setAttribute('readonly', 'readonly')
textarea.style.position = 'fixed'
textarea.style.left = '-9999px'
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
}
async function handleCopyPlaceholder(fieldKey) {
const placeholder = buildPlaceholderText(fieldKey)
try {
await copyTextToClipboard(placeholder)
message.success(`已复制占位符:${placeholder}`)
} catch (error) {
message.warning(`复制失败,请手动使用占位符:${placeholder}`)
}
}
function removeVariable(id) {
variableMappings.value = variableMappings.value.filter((item) => item.id !== id)
}
@@ -643,7 +711,10 @@ function buildPreviewData() {
const data = {}
variableMappings.value.forEach((item) => {
if (!item.variableKey) return
data[item.variableKey] = item.bindField || `[${item.variableKey}]`
data[item.variableKey] =
templateFieldLabelMap.value[item.bindField] ||
item.bindField ||
`[${item.variableKey}]`
})
return data
}
@@ -717,7 +788,6 @@ function buildRecord(status) {
version: formState.version,
status,
variableCount: variableMappings.value.filter((item) => item.variableKey).length,
selfPartyRole: formState.selfPartyRole,
publishOrgIds: [...(formState.publishOrgIds || [])],
publishOrgNames,
updatedBy: formState.updatedBy || '当前用户',
@@ -805,9 +875,81 @@ async function loadTemplateBufferFromRecord(record) {
}
}
function triggerBlobDownload(blob, fileName) {
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
}
function buildVariableGuideText() {
const lines = [
'合同模板变量说明',
'',
'推荐维护方式:',
'1. 下载当前模板到本地 Word 编辑正文内容。',
'2. 在正文中插入占位符,例如 {contractName}、{partyAName}。',
'3. 保存后重新上传 .docx 文件回传系统。',
'4. 在平台内完成变量识别、字段映射、预览和发布。',
'',
'可用占位符清单:',
...templateFieldList.value.map(
(item) => `- ${item.label}: ${buildPlaceholderText(item.value)}`,
),
]
return lines.join('\r\n')
}
function handleDownloadVariableGuide() {
const blob = new Blob([buildVariableGuideText()], {
type: 'text/plain;charset=utf-8',
})
const fileName = `合同模板变量说明-${dayjs().format('YYYYMMDDHHmmss')}.txt`
triggerBlobDownload(blob, fileName)
message.success('变量说明已开始下载')
}
async function handleDownloadCurrentTemplate() {
if (!hasTemplateFile.value) {
message.warning('当前暂无可下载的模板文件')
return
}
try {
let arrayBuffer = templateArrayBuffer.value
if (!arrayBuffer && formState.templateFilePath) {
const response = await downloadTemplateFile(formState.templateFilePath)
const downloaded = response?.data ?? response
arrayBuffer =
downloaded instanceof ArrayBuffer ? downloaded : downloaded?.buffer
}
if (!arrayBuffer) {
message.warning('模板文件尚未加载完成,请稍后重试')
return
}
const blob = new Blob([arrayBuffer], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
})
const fileName =
formState.templateFileName || `${formState.templateName || '合同模板'}.docx`
triggerBlobDownload(blob, fileName)
message.success('模板文件已开始下载,可在本地 Word 编辑后重新上传')
} catch (error) {
message.error('模板文件下载失败')
}
}
async function showModal(record = {}, mode = 'create') {
resetState()
modalMode.value = mode || 'create'
await ensureTemplateFieldListLoaded()
if (!orgOptions.value.length) {
const orgList = await queryManifestOrgOptions()
orgOptions.value = (orgList || []).map((item) => ({
@@ -910,6 +1052,10 @@ defineExpose({
box-shadow: 0 6px 20px rgba(15, 23, 42, 0.04);
}
.workflow-alert {
margin-bottom: 14px;
}
.panel-footer {
display: flex;
justify-content: flex-end;
@@ -940,6 +1086,7 @@ defineExpose({
display: flex;
align-items: flex-start;
justify-content: space-between;
flex-direction: column;
gap: 16px;
margin-bottom: 14px;
}
@@ -972,17 +1119,37 @@ defineExpose({
margin-bottom: 10px;
}
.catalog-help {
margin-top: 6px;
font-size: 12px;
color: #64748b;
line-height: 1.7;
}
.catalog-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.catalog-item {
display: inline-flex;
align-items: center;
gap: 2px;
padding: 2px 4px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.72);
}
.catalog-tag {
cursor: pointer;
user-select: none;
}
.catalog-action {
padding-inline: 4px;
}
.mapping-list {
display: flex;
flex-direction: column;
@@ -0,0 +1,46 @@
import { getDictDataByType } from "@/api/dict.js";
export const TEMPLATE_FIELD_DICT_TYPE = "CONTRACT_TEMPLATE_FIELDS";
let cachedTemplateFieldList = null;
function cloneTemplateFieldList(list = []) {
return list.map((item) => ({
...item,
}));
}
function normalizeTemplateFieldList(list = []) {
return list
.map((item) => ({
label: item?.k || item?.label || "",
value: item?.v || item?.value || "",
remark: item?.remark || "",
}))
.filter((item) => item.label && item.value);
}
export async function loadTemplateFieldList() {
if (cachedTemplateFieldList?.length) {
return cloneTemplateFieldList(cachedTemplateFieldList);
}
const result = await getDictDataByType(TEMPLATE_FIELD_DICT_TYPE);
cachedTemplateFieldList = normalizeTemplateFieldList(result);
return cloneTemplateFieldList(cachedTemplateFieldList);
}
export function buildTemplateFieldOptions(list = []) {
return list.map((item) => ({
label: `${item.label}${item.value}`,
value: item.value,
}));
}
export function buildTemplateFieldLabelMap(list = []) {
const map = {};
list.forEach((item) => {
map[item.value] = item.label;
});
return map;
}
+4
View File
@@ -31,6 +31,10 @@ export default defineConfig({
target: 'http://127.0.0.1:8899',
changeOrigin: true,
},
'/admin': {
target: 'http://127.0.0.1:8899',
changeOrigin: true,
},
'/trans': {
target: 'http://127.0.0.1:8899',
changeOrigin: true,