import type { LabelTemplateData, SystemLabelTemplate, SystemTemplateElementBase, } from '../print/types/printer' /** * 打印/预览 printInputJson 的 key:与接口文档一致优先 inputKey,否则 elementName,最后兜底元素 id。 * 兼容根字段与 config 内 InputKey(部分模板把键写在 config)。 */ export function printInputJsonKeyForElement(el: SystemTemplateElementBase): string { const cfg = el.config || {} const top = el.inputKey ?? (el as { InputKey?: string }).InputKey ?? cfg.inputKey ?? cfg.InputKey ?? el.elementName ?? (el as { ElementName?: string }).ElementName ?? cfg.elementName ?? cfg.ElementName const s = top != null ? String(top).trim() : '' if (s) return s return String(el.id ?? '').trim() } export function isPrintInputOptionsElement(el: SystemTemplateElementBase): boolean { const vst = String(el.valueSourceType || '').toUpperCase() if (vst !== 'PRINT_INPUT') return false const c = el.config || {} const it = String(c.inputType ?? c.InputType ?? '').toLowerCase() if (it === 'options') return true const mid = c.multipleOptionId ?? c.MultipleOptionId return typeof mid === 'string' && mid.trim() !== '' } /** PRINT_INPUT 且非多选项字典(无 effective multipleOptionId):需用户在页面上输入 */ export function isPrintInputFreeFieldElement(el: SystemTemplateElementBase): boolean { const vst = String(el.valueSourceType || '').toUpperCase() if (vst !== 'PRINT_INPUT') return false return !isPrintInputOptionsElement(el) } /** 从模板初始 config 读出已选(接口预览可能已带 selectedOptionValues) */ export function readSelectionsFromTemplate(template: SystemLabelTemplate): Record { const out: Record = {} for (const el of template.elements || []) { if (!isPrintInputOptionsElement(el)) continue const raw = el.config?.selectedOptionValues ?? el.config?.SelectedOptionValues if (Array.isArray(raw) && raw.length) { out[el.id] = raw.map((x: unknown) => String(x)) } } return out } /** * 将多选结果写回 config(画布与打印用 text 展示「字典名: 值」或 prefix+值) */ /** 从预览模板 config 初始化自由输入(如 WEIGHT 的 value、DATE 已算好的 text) */ export function readFreeFieldValuesFromTemplate(template: SystemLabelTemplate): Record { const out: Record = {} for (const el of template.elements || []) { if (!isPrintInputFreeFieldElement(el)) continue const c = el.config || {} const type = String(el.type || '').toUpperCase() let initial = '' if (type === 'WEIGHT') { const v = c.value ?? c.Value if (v != null && String(v).trim() !== '') initial = String(v).trim() } else { const fmt = String(c.format ?? c.Format ?? '').trim() const t = String(c.text ?? c.Text ?? '').trim() if (t && (!fmt || t !== fmt)) initial = t } out[el.id] = initial } return out } export function ensureFreeFieldKeys( template: SystemLabelTemplate, existing: Record ): Record { const out = { ...existing } for (const el of template.elements || []) { if (!isPrintInputFreeFieldElement(el)) continue if (!(el.id in out)) out[el.id] = '' } return out } /** * 将自由输入写回 config:画布用 text 展示;若有 unit 则拼在数值后(如 500g)。 */ export function mergePrintInputFreeFields( template: SystemLabelTemplate, values: Record ): SystemLabelTemplate { return { ...template, elements: (template.elements || []).map((el) => { if (!isPrintInputFreeFieldElement(el)) return el const cfg = { ...el.config } const raw = String(values[el.id] ?? '').trim() const unit = String(cfg.unit ?? cfg.Unit ?? '').trim() const type = String(el.type || '').toUpperCase() if (!raw) { if (type === 'DATE' || type === 'TIME') { const fmt = String(cfg.format ?? cfg.Format ?? '') return { ...el, config: { ...cfg, text: fmt } } } if (type === 'WEIGHT') { return { ...el, config: { ...cfg, text: '', value: '' } } } const ph = String( cfg.placeholder ?? cfg.Placeholder ?? cfg.defaultValue ?? cfg.DefaultValue ?? '' ).trim() return { ...el, config: { ...cfg, text: ph } } } const display = unit && !raw.endsWith(unit) ? `${raw}${unit}` : raw const next = { ...cfg, text: display } as Record if (type === 'WEIGHT') { next.value = raw } return { ...el, config: next } }), } } export function mergePrintOptionSelections( template: SystemLabelTemplate, selections: Record, dictNames: Record ): SystemLabelTemplate { return { ...template, elements: (template.elements || []).map((el) => { if (!isPrintInputOptionsElement(el)) return el const sel = selections[el.id] if (!sel || sel.length === 0) return el const cfg = { ...el.config } cfg.selectedOptionValues = sel const dictLabel = dictNames[el.id] || 'Options' const prefix = String(cfg.prefix ?? cfg.Prefix ?? '').trim() const answers = sel.join(', ') cfg.text = prefix ? `${prefix}${answers}` : `${dictLabel}: ${answers}` return { ...el, config: cfg } }), } } export function printInputJsonFromSelections( template: SystemLabelTemplate, selections: Record ): Record { const out: Record = {} for (const el of template.elements || []) { if (!isPrintInputOptionsElement(el)) continue const sel = selections[el.id] if (!sel || !sel.length) continue const key = printInputJsonKeyForElement(el) if (!key) continue out[key] = sel.length === 1 ? sel[0] : [...sel] } return out } export function printInputJsonFromFreeFields( template: SystemLabelTemplate, values: Record ): Record { const out: Record = {} for (const el of template.elements || []) { if (!isPrintInputFreeFieldElement(el)) continue const key = printInputJsonKeyForElement(el) if (!key) continue const v = String(values[el.id] ?? '').trim() if (v === '') continue out[key] = v } return out } export function buildPrintInputJson( template: SystemLabelTemplate, optionSelections: Record, freeFieldValues: Record ): Record { return { ...printInputJsonFromSelections(template, optionSelections), ...printInputJsonFromFreeFields(template, freeFieldValues), } } /** * 供接口 9 落库 `printInputJson`:在**纯 JSON 克隆**上再合并多选/自由输入,避免 Vue Proxy 嵌套 config * 在部分环境下 `JSON.stringify` 丢字段,导致服务端存下的 RenderDataJson 仍是设计器默认值(无日期、无多选)。 */ export function buildPrintPersistTemplateSnapshot( base: SystemLabelTemplate, optionSelections: Record, freeFieldValues: Record, dictNames: Record ): SystemLabelTemplate { const cloned = JSON.parse(JSON.stringify(base)) as SystemLabelTemplate let m = mergePrintOptionSelections(cloned, optionSelections, dictNames) m = mergePrintInputFreeFields(m, freeFieldValues) return m } /** 本地打印机 / dataJson:与 printInputJson 同键,供模板 {{key}} 或 native 层合并 */ export function printInputJsonToLabelTemplateData(pj: Record): LabelTemplateData { const out: LabelTemplateData = {} for (const k of Object.keys(pj)) { const v = pj[k] if (v == null) continue if (typeof v === 'string' || typeof v === 'number') { out[k] = v } else if (Array.isArray(v)) { out[k] = v.map((x) => String(x)).join(', ') } else { out[k] = JSON.stringify(v) } } return out } /** * PRINT_INPUT 且为多选项字典:未至少选一项则不可打印。 */ export function validatePrintInputOptionsBeforePrint( template: SystemLabelTemplate, selections: Record, dictLabels: Record ): string | null { for (const el of template.elements || []) { if (!isPrintInputOptionsElement(el)) continue const sel = selections[el.id] if (!sel || sel.length === 0) { const name = dictLabels[el.id] || el.elementName || el.inputKey || 'options' return `Please select “${name}” before printing.` } } return null } /** * PRINT_INPUT 自由字段:未填写则不可打印。 */ export function validatePrintInputFreeFieldsBeforePrint( template: SystemLabelTemplate, values: Record ): string | null { for (const el of template.elements || []) { if (!isPrintInputFreeFieldElement(el)) continue const raw = String(values[el.id] ?? '').trim() if (raw === '') { const name = el.elementName || el.inputKey || 'field' return `Please fill in “${name}” before printing.` } } return null }