From fae1d77ba5894c6af4ac9c8edf6b13654e1ece19 Mon Sep 17 00:00:00 2001
From: ZF sun <34314687@qq.com>
Date: Thu, 11 Jun 2026 09:45:09 +0800
Subject: [PATCH] =?UTF-8?q?refactor(diy-form&ns-newform):=20=E9=87=8D?=
=?UTF-8?q?=E6=9E=84=E8=A1=A8=E5=8D=95=E7=BB=84=E4=BB=B6=E6=A0=B7=E5=BC=8F?=
=?UTF-8?q?=E4=B8=8E=E9=85=8D=E7=BD=AE=E4=BD=93=E7=B3=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 统一表单样式配置为中心化CSS变量方案,替换原有硬编码样式
2. 新增表单配置合并逻辑,兼容新旧数据格式与平台差异化配置
3. 拆分提交按钮与提示语样式,实现完全可配置化
4. 优化ns-newform组件的样式复用与响应式布局逻辑
5. 修复多端适配与占位符默认值问题
---
components-diy/diy-form.vue | 210 ++++++++-
components/ns-newform/ns-newform.vue | 661 +++++++++++++++++++--------
2 files changed, 667 insertions(+), 204 deletions(-)
diff --git a/components-diy/diy-form.vue b/components-diy/diy-form.vue
index cc7b6c7..3b293a7 100644
--- a/components-diy/diy-form.vue
+++ b/components-diy/diy-form.vue
@@ -1,25 +1,23 @@
-
+
-
+
- {{ value.form_tip }}
+ {{ value.form_tip }}
-
- 提交信息
+
+
+ {{ submitText }}
+
@@ -65,8 +63,148 @@ export default {
}
return css;
},
+ // 兼容旧 style 别名(部分页面用 :style="style" 引用)
+ diyFormStyle() {
+ return this.style;
+ },
+ // 将后端 formConfig 写入 CSS 变量:与后端 design.css :root 对齐,
+ // 让 banner / tip / submit 与 ns-newform 子组件共享同一套样式变量
+ cssVars() {
+ const cfg = this.mergedFormConfig || {};
+ const rpx = (v) => {
+ if (v === '' || v === null || v === undefined) return '';
+ return typeof v === 'number' ? `${v}rpx` : `${v}`;
+ };
+ const showDivider = this._coerceBool(cfg.showRowDivider);
+ return {
+ '--form-padding-x': rpx(cfg.formPaddingX || 14),
+ '--banner-padding-x': rpx(cfg.bannerPaddingX || 0),
+ '--tip-padding-x': rpx(cfg.tipPaddingX || 14),
+ '--tip-font-size': rpx(cfg.tipFontSize || 24),
+ '--tip-color': cfg.tipColor || '#666666',
+ '--tip-bg-color': cfg.tipBgColor || '#ffffff',
+ '--row-padding-y': rpx(cfg.rowPaddingY || 4),
+ '--row-min-height': rpx(cfg.rowMinHeight || 60),
+ '--label-gap': rpx(cfg.labelGap || 16),
+ '--form-bg-color': cfg.formBgColor || '#ffffff',
+ '--row-divider-color': cfg.rowDividerColor || '#f0f0f0',
+ '--input-height': rpx(cfg.inputHeight || 60),
+ '--input-radius': rpx(cfg.inputRadius || 10),
+ '--label-fixed-width': rpx(cfg.labelFixedWidth || 180),
+ '--label-font-size': rpx(cfg.labelFontSize || 28),
+ '--label-color': cfg.labelColor || '#1f2937',
+ '--required-color': cfg.requiredColor || '#ef4444',
+ '--checked-color': cfg.checkedColor || '#ff4544',
+ '--submit-color': cfg.submitColor || '#ffffff',
+ '--submit-bg-color': cfg.submitBgColor || '#ff4544',
+ '--placeholder-color': '#ddd',
+ '--show-row-divider': showDivider ? '1' : '0'
+ };
+ },
+ // Banner 容器左右内边距(与后端 .form-preview-banner padding-x 对齐)
+ bannerStyle() {
+ return {
+ padding: `0 ${this._num(this.mergedFormConfig && this.mergedFormConfig.bannerPaddingX, 0)}rpx`
+ };
+ },
+ // 提示语样式:padding-x、font-size、color、bg-color(与后端 .form-preview-tip 对齐)
+ tipStyle() {
+ const cfg = this.mergedFormConfig || {};
+ return {
+ padding: `${this._num(cfg.rowPaddingY, 4)}rpx ${this._num(cfg.tipPaddingX, 14)}rpx`,
+ 'font-size': `${this._num(cfg.tipFontSize, 24)}rpx`,
+ 'color': cfg.tipColor || '#666666',
+ 'background-color': cfg.tipBgColor || 'transparent'
+ };
+ },
+ // 提交按钮外层:与后端 .form-preview-submit 对齐(padding: row-padding-y form-padding-x;background: form-bg-color)
+ submitWrapStyle() {
+ const cfg = this.mergedFormConfig || {};
+ return {
+ padding: `${this._num(cfg.rowPaddingY, 4)}rpx ${this._num(cfg.formPaddingX, 14)}rpx`,
+ 'background-color': cfg.formBgColor || '#ffffff'
+ };
+ },
+ // 提交按钮样式:颜色 / 背景色 / 高度 / 圆角 / 字号(与后端 .form-preview-submit button 对齐)
+ submitStyle() {
+ const cfg = this.mergedFormConfig || {};
+ return {
+ color: cfg.submitColor || '#ffffff',
+ 'background-color': cfg.submitBgColor || '#ff4544',
+ 'line-height': `${this._num(cfg.inputHeight, 60)}rpx`,
+ 'border-radius': `${this._num(cfg.inputRadius, 10)}rpx`,
+ 'font-size': `${this._num(cfg.labelFontSize, 28)}rpx`
+ };
+ },
+ // 提交按钮文字:与后端 design.html 默认对齐,开放给 formConfig 覆盖
+ submitText() {
+ return this.formCfg.submit_text || '提交';
+ },
formLayoutClass() {
- return this.value.form_layout === 'vertical' ? 'form-vertical' : 'form-horizontal';
+ return this.formCfg.form_layout === 'vertical' ? 'form-vertical' : 'form-horizontal';
+ },
+ // 后端把表单样式配置统一存放在 data.formConfig 子对象中(与后端 design.js getDefaultFormData().formConfig 字段名一致)。
+ // 这里做一次归一化:优先取 formConfig;如果历史数据是扁平结构(直接挂在 value 上),也做兼容。
+ formCfg() {
+ const v = this.value || {};
+ if (v.formConfig && typeof v.formConfig === 'object') {
+ return v.formConfig;
+ }
+ return v;
+ },
+ // 合并后的表单配置(支持平台差异化)
+ mergedFormConfig() {
+ const v = this.value || {};
+ const fc = this.formCfg;
+ // 通用全局配置(与后端 design.js getDefaultFormData().formConfig 字段名一致)
+ const base = {
+ formPaddingX: fc.form_padding_x,
+ bannerPaddingX: fc.banner_padding_x,
+ tipPaddingX: fc.tip_padding_x,
+ rowPaddingY: fc.row_padding_y,
+ rowMinHeight: fc.row_min_height,
+ labelGap: fc.label_gap,
+ formBgColor: fc.form_bg_color,
+ rowDividerColor: fc.row_divider_color,
+ showRowDivider: this._coerceBool(fc.show_row_divider),
+ inputHeight: fc.input_height,
+ inputRadius: fc.input_radius,
+ labelWidthMode: fc.label_width_mode,
+ labelFixedWidth: fc.label_fixed_width,
+ labelFontSize: fc.label_font_size,
+ labelColor: fc.label_color,
+ requiredColor: fc.required_color,
+ checkedColor: fc.checked_color,
+ submitColor: fc.submit_color,
+ submitBgColor: fc.submit_bg_color,
+ tipFontSize: fc.tip_font_size,
+ tipColor: fc.tip_color,
+ tipBgColor: fc.tip_bg_color
+ };
+ // 移除 undefined / 空字符串(保留 0/false)
+ Object.keys(base).forEach(function(k) {
+ if (base[k] === undefined || base[k] === null || base[k] === '') {
+ delete base[k];
+ }
+ });
+ // 平台差异化配置(与后端 formConfig.terminal 字段名对齐)
+ // 优先级:value.form_config_terminal > value.terminal > value.form_config_platform
+ const result = Object.assign({}, base);
+ const termBlock = v.form_config_terminal || v.terminal || v.form_config_platform;
+ if (termBlock && typeof termBlock === 'object') {
+ Object.keys(termBlock).forEach(function(platform) {
+ var src = termBlock[platform];
+ if (!src) return;
+ // 嵌套值若为 snake_case(部分序列化路径),在此统一转 camelCase
+ var translated = {};
+ Object.keys(src).forEach(function(k) {
+ var camel = k.replace(/_([a-z])/g, function(_, c) { return c.toUpperCase(); });
+ translated[camel] = src[k];
+ });
+ result[platform] = translated;
+ });
+ }
+ return result;
}
},
methods: {
@@ -87,6 +225,20 @@ export default {
});
},
+ // 数字保底:undefined/空串/非数字时返回兜底值
+ _num(v, fb) {
+ if (v === '' || v === null || v === undefined) return fb;
+ var n = parseInt(v);
+ return isNaN(n) ? fb : n;
+ },
+ // 布尔保底:0/false/'0'/'false' → false;其它有值 → true
+ _coerceBool(v) {
+ if (v === false || v === 0 || v === '0' || v === 'false' || v === null || v === undefined) {
+ return false;
+ }
+ return true;
+ },
+
// 提交表单
submitForm() {
var self = this;
@@ -141,13 +293,14 @@ export default {
diff --git a/components/ns-newform/ns-newform.vue b/components/ns-newform/ns-newform.vue
index c9fa13d..13a0014 100644
--- a/components/ns-newform/ns-newform.vue
+++ b/components/ns-newform/ns-newform.vue
@@ -1,17 +1,17 @@
-
+
-
-
-
+
+
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
-
+
@@ -20,15 +20,15 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
-
+
@@ -37,20 +37,20 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
{{ item.val }}
- 请选择
+ {{ item.value.placeholder || '请选择' }}
@@ -58,9 +58,9 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
@@ -73,8 +73,9 @@
:class="[
'iconfont',
!v.checked ? 'icon-fuxuankuang2' : '',
- v.checked ? 'icon-fuxuankuang1 color-base-text' : ''
+ v.checked ? 'icon-fuxuankuang1' : ''
]"
+ :style="{ color: v.checked ? checkedColor : '' }"
>
{{ v.value }}
@@ -85,9 +86,9 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
@@ -100,8 +101,9 @@
:class="[
'iconfont',
item.val != v.value ? 'icon-yuan_checkbox' : '',
- item.val == v.value ? 'icon-yuan_checked color-base-text' : ''
+ item.val == v.value ? 'icon-yuan_checked' : ''
]"
+ :style="{ color: item.val == v.value ? checkedColor : '' }"
>
{{ v.value }}
@@ -112,13 +114,13 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
-
+
@@ -131,9 +133,9 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
@@ -144,7 +146,7 @@
@change="bindDateChange($event, index)"
>
- {{ item.val ? item.val : item.value.placeholder }}
+ {{ item.val ? item.val : (item.value.placeholder || '请选择日期') }}
@@ -153,13 +155,13 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
-
+
- {{ item.start_date ? item.start_date : item.value.placeholder_start }}
-
+ {{ item.start_date ? item.start_date : (item.value.placeholder_start || '开始日期') }}
+
@@ -182,8 +184,8 @@
>
- {{ item.end_date ? item.end_date : item.value.placeholder_end }}
-
+ {{ item.end_date ? item.end_date : (item.value.placeholder_end || '结束日期') }}
+
@@ -192,9 +194,9 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
@@ -205,7 +207,7 @@
@change="bindTimeChange($event, index)"
>
- {{ item.val ? item.val : item.value.placeholder }}
+ {{ item.val ? item.val : (item.value.placeholder || '请选择时间') }}
@@ -214,13 +216,13 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
-
+
- {{ item.start_time ? item.start_time : item.value.placeholder_start }}
-
+ {{ item.start_time ? item.start_time : (item.value.placeholder_start || '开始时间') }}
+
@@ -243,8 +245,8 @@
>
- {{ item.end_time ? item.end_time : item.value.placeholder_end }}
-
+ {{ item.end_time ? item.end_time : (item.value.placeholder_end || '结束时间') }}
+
@@ -253,9 +255,9 @@
-
+
-
+
{{ item.value.title }}
{{ item.value.required ? '*' : '' }}
@@ -266,7 +268,7 @@
@getRegions="handleGetRegions($event, index)"
>
- {{ item.val ? item.val : (item.select_arr == '2' ? '请选择省市' : '请选择省市区/县') }}
+ {{ item.val ? item.val : (item.value.placeholder || '请选择城市') }}
@@ -294,26 +296,16 @@ export default {
default: 'horizontal',
validator: (value) => !value || ['horizontal', 'vertical'].includes(value)
},
- labelWidthMode: {
- type: String,
- default: 'auto',
- validator: (value) => !value || ['auto', 'fixed'].includes(value)
- },
- labelFixedWidth: {
- type: [String, Number],
- default: 180
- },
- labelFontSize: {
- type: [String, Number],
- default: 26
- },
- labelColor: {
- type: String,
- default: '#303133'
- },
- requiredColor: {
- type: String,
- default: '#F56C6C'
+ // 表单配置(按平台差异化)
+ // 格式:{
+ // form_padding_x: 14, // 全局默认值
+ // mp: { form_padding_x: 10 }, // 微信小程序平台覆盖
+ // h5: { row_padding_y: 8 }, // H5 平台覆盖
+ // harmony: { ... } // 鸿蒙元服务覆盖
+ // }
+ formConfig: {
+ type: Object,
+ default: () => ({})
}
},
data() {
@@ -340,69 +332,289 @@ export default {
});
},
deep: true
+ },
+ // 配置变化(如字号 / 模式切换)时,重新计算 maxLabelWidth
+ formConfig: {
+ handler() {
+ this.$nextTick(() => {
+ this.calculateMaxLabelWidth();
+ });
+ },
+ deep: true
+ },
+ mode() {
+ this.$nextTick(() => {
+ this.calculateMaxLabelWidth();
+ });
}
},
computed: {
- nameWidthStyle() {
+ // 当前运行平台标识(与后端 formConfig.terminal 键名对齐:h5 / wechat / weapp / harmony)
+ platform() {
+ // 优先使用后端在 formConfig.terminal 中使用的键名
+ // #ifdef H5
+ return 'h5';
+ // #endif
+ // #ifdef MP-WEIXIN
+ return 'weapp';
+ // #endif
+ // #ifdef MP-ALIPAY
+ return 'mp-alipay';
+ // #endif
+ // #ifdef MP-BAIDU
+ return 'mp-baidu';
+ // #endif
+ // #ifdef MP-TOUTIAO
+ return 'mp-toutiao';
+ // #endif
+ // #ifdef APP-PLUS
+ return 'app';
+ // #endif
+ // #ifdef APP-HARMONY
+ return 'harmony';
+ // #endif
+ // #ifdef QUICKAPP-WEBVIEW
+ return 'quickapp';
+ // #endif
+ return 'h5';
+ },
+ // 平台配置兼容层:后端键名(h5/wechat/weapp/harmony)→ 内部 platform 名
+ platformAliases() {
+ return {
+ 'h5': 'h5',
+ 'weapp': 'weapp',
+ 'mp-weixin': 'weapp',
+ 'wechat': 'wechat',
+ 'harmony': 'harmony',
+ 'app': 'app',
+ 'app-plus': 'app'
+ };
+ },
+ // 当前平台的有效配置键集合(用于 config() 中查找 platformCfg)
+ platformConfigKeys() {
+ const cur = this.platform;
+ const aliases = this.platformAliases;
+ // 找出所有映射到当前平台的后端键名
+ const keys = [];
+ Object.keys(aliases).forEach(k => {
+ if (aliases[k] === cur) keys.push(k);
+ });
+ // 加入当前平台名(兼容 formConfig[platform] 这种写法)
+ if (keys.indexOf(cur) === -1) keys.push(cur);
+ return keys;
+ },
+ // 合并配置:内置默认 < 全局 < 当前平台
+ config() {
+ // 内置默认值(最低优先级)- 与后端 D:\projects\shop-projects\backend\src\app\component\view\form\js\design.js getDefaultFormData().formConfig 对齐
+ const defaults = {
+ formPaddingX: 14,
+ bannerPaddingX: 0,
+ tipPaddingX: 14,
+ rowPaddingY: 4,
+ rowMinHeight: 60,
+ labelGap: 16,
+ formBgColor: '#ffffff',
+ rowDividerColor: '#f0f0f0',
+ showRowDivider: true,
+ inputHeight: 60,
+ inputRadius: 10,
+ labelWidthMode: 'auto',
+ labelFixedWidth: 180,
+ labelFontSize: 28,
+ labelColor: '#1f2937',
+ requiredColor: '#ef4444',
+ checkedColor: '#ff4544',
+ // 提交按钮
+ submitColor: '#ffffff',
+ submitBgColor: '#ff4544',
+ // 提示语
+ tipFontSize: 24,
+ tipColor: '#666666',
+ tipBgColor: '#ffffff'
+ };
+ // 全局配置(中间优先级)
+ const globalCfg = this.formConfig || {};
+ // 当前平台配置(最高优先级):从 formConfig.terminal 多个别名中按顺序合并
+ const formConfigRoot = this.formConfig || {};
+ // 兼容两种结构:
+ // 1) 后端格式:formConfig.terminal = { h5: {...}, weapp: {...}, harmony: {...} }
+ // 2) 旧式扁平:formConfig[platformKey] = { ... }
+ const terminalBlock = formConfigRoot.terminal || {};
+ const platformKeys = this.platformConfigKeys || [];
+ const platformCfg = Object.assign(
+ {},
+ ...platformKeys.map(k => (terminalBlock[k] || formConfigRoot[k] || {}))
+ );
+ // 合并:defaults <- globalCfg <- platformCfg
+ return Object.assign({}, defaults, globalCfg, platformCfg);
+ },
+ nameWidthStyle() {
+ if (this.mode === 'vertical') {
+ return {};
+ }
+ let width;
+ if (this.config.labelWidthMode === 'fixed') {
+ width = `${this.config.labelFixedWidth}rpx`;
+ } else {
+ width = this.maxLabelWidth ? `${this.maxLabelWidth}rpx` : 'auto';
+ }
+ return {
+ width: width
+ };
+ },
+ // 容器样式(与后端 form-preview-content 对齐:通过 CSS 变量驱动子元素样式)
+ formWrapStyle() {
+ const cfg = this.config;
+ const num = (v, fb) => (typeof v === 'number' ? v : parseInt(v) || fb);
+ return {
+ // 仅保留左右内边距 = form-padding-x;上下由每行 row-padding-y 承担
+ padding: `0 ${cfg.formPaddingX}rpx`,
+ background: cfg.formBgColor,
+ // 通过 CSS 变量传递:与后端 design.css 的 :root 变量一一对应
+ '--form-padding-x': `${cfg.formPaddingX}rpx`,
+ '--banner-padding-x': `${cfg.bannerPaddingX}rpx`,
+ '--tip-padding-x': `${cfg.tipPaddingX}rpx`,
+ '--tip-font-size': `${cfg.tipFontSize}rpx`,
+ '--tip-color': cfg.tipColor,
+ '--tip-bg-color': cfg.tipBgColor,
+ '--row-padding-y': `${cfg.rowPaddingY}rpx`,
+ '--row-min-height': `${cfg.rowMinHeight}rpx`,
+ '--label-gap': `${cfg.labelGap}rpx`,
+ '--form-bg-color': cfg.formBgColor,
+ '--row-divider-color': cfg.rowDividerColor,
+ '--input-height': `${cfg.inputHeight}rpx`,
+ '--input-radius': `${cfg.inputRadius}rpx`,
+ '--label-fixed-width': `${cfg.labelFixedWidth}rpx`,
+ '--label-font-size': `${num(cfg.labelFontSize, 28)}rpx`,
+ '--label-color': cfg.labelColor,
+ '--required-color': cfg.requiredColor,
+ '--checked-color': cfg.checkedColor,
+ '--submit-color': cfg.submitColor,
+ '--submit-bg-color': cfg.submitBgColor,
+ // 分割线显隐
+ '--show-row-divider': cfg.showRowDivider === false ? '0' : '1'
+ };
+ },
+ // 行间距样式:仅上下内边距,水平由外层 form-wrap 控制(与后端 form-gorup 对齐)
+ rowWrapStyle() {
+ return {
+ padding: `${this.config.rowPaddingY}rpx 0`
+ };
+ },
+ // 行容器 class:用于控制分割线显隐
+ rowWrapClass() {
+ return this.config.showRowDivider === false ? 'order-wrap no-divider' : 'order-wrap';
+ },
+ // 行最小高度
+ rowCellStyle() {
+ return {
+ 'min-height': `${this.config.rowMinHeight}rpx`
+ };
+ },
+ // 标签与输入框间距
+ nameStyle() {
if (this.mode === 'vertical') {
return {};
}
- let width;
- if (this.labelWidthMode === 'fixed') {
- width = `${this.labelFixedWidth}rpx`;
- } else {
- width = this.maxLabelWidth ? `${this.maxLabelWidth}rpx` : 'auto';
- }
return {
- width: width
+ 'margin-right': `${this.config.labelGap}rpx`
+ };
+ },
+ // 输入框样式(全局,未指定 item 时使用)
+ inputStyle() {
+ return {
+ 'min-height': `${this.config.inputHeight}rpx`,
+ 'border-radius': `${this.config.inputRadius}rpx`
};
},
labelStyle() {
let style = {};
- let fontSize = this.labelFontSize;
+ let fontSize = this.config.labelFontSize;
if (typeof fontSize === 'number') {
fontSize = `${fontSize}rpx`;
} else if (typeof fontSize === 'string' && !fontSize.endsWith('rpx') && !fontSize.endsWith('px')) {
fontSize = `${fontSize}rpx`;
}
style.fontSize = fontSize;
- style.color = this.labelColor;
+ style.color = this.config.labelColor;
+ return style;
+ },
+ requiredColor() {
+ return this.config.requiredColor;
+ },
+ checkedColor() {
+ return this.config.checkedColor;
+ },
+ rowDividerStyle() {
+ const style = {};
+ if (this.config.showRowDivider === false) {
+ style.display = 'none';
+ } else {
+ style.background = this.config.rowDividerColor;
+ }
return style;
}
},
methods: {
+ // 处理 rpx 字号:与后端 label_font_size 字段语义对齐
+ _resolveFontSize(value, fallback) {
+ let v = value;
+ if (v === '' || v === null || v === undefined) {
+ v = fallback;
+ }
+ if (typeof v === 'number') {
+ return `${v}rpx`;
+ }
+ if (typeof v === 'string') {
+ if (v.endsWith('rpx') || v.endsWith('px')) return v;
+ return `${v}rpx`;
+ }
+ return v;
+ },
+ // 组件级 label 样式:通过 CSS 变量覆盖,驱动子元素 .tit / .required
+ getItemLabelStyle(item) {
+ const override = (item && item.value) || {};
+ const style = {};
+ if (override.label_font_size !== undefined && override.label_font_size !== null && override.label_font_size !== '') {
+ let fs = override.label_font_size;
+ if (typeof fs === 'number') fs = `${fs}rpx`;
+ else if (typeof fs === 'string' && !fs.endsWith('rpx') && !fs.endsWith('px')) fs = `${fs}rpx`;
+ style['--item-label-font-size'] = fs;
+ }
+ if (override.label_color) {
+ style['--item-label-color'] = override.label_color;
+ }
+ return style;
+ },
+ // 组件级输入框对齐方式:left / center / right
+ getItemBoxAlignStyle(item) {
+ const align = item && item.value && item.value.input_align;
+ if (!align) return {};
+ return { 'text-align': align };
+ },
+ // 容器样式(提供给外部 diy-form 使用)
+ getFormWrapStyle() {
+ return this.formWrapStyle;
+ },
calculateMaxLabelWidth() {
if (this.mode === 'vertical' || !this.formData || this.formData.length === 0) {
+ this.maxLabelWidth = 0;
return;
}
-
- let maxWidth = 0;
-
+ // 与后端 design.js calculateMaxLabelWidth 算法对齐:
+ // 取所有 title 中最长字符数(必填 +1),按 fontSize(rpx)近似换算宽度
+ // 后端在 H5 中按 1rpx = 0.5px 计算宽度,再加 12 边距
+ const fontSize = parseInt(this.config.labelFontSize) || 28;
+ let maxChars = 0;
this.formData.forEach((item) => {
- if (item.value && item.value.title) {
- let text = item.value.title;
- if (item.value.required) {
- text += '*';
- }
- let width = 0;
- for (let i = 0; i < text.length; i++) {
- const char = text[i];
- if (/[\u4e00-\u9fa5]/.test(char)) {
- width += 1;
- } else {
- width += 0.5;
- }
- }
- const fontSize = parseInt(this.labelFontSize) || 30;
- width = width * fontSize * 0.85 + 30;
- maxWidth = Math.max(maxWidth, width);
- }
+ if (!item.value || !item.value.title) return;
+ let len = (item.value.title || '').length;
+ if (item.value.required) len += 1;
+ if (len > maxChars) maxChars = len;
});
-
- maxWidth = Math.max(maxWidth, 60);
- maxWidth = Math.min(maxWidth, 160);
-
- this.maxLabelWidth = maxWidth;
+ // 与后端公式一致:chars * (fontSize/2) * 1.1 + 12,单位 px → 转 rpx(×2)
+ const widthPx = Math.max(40, maxChars * (fontSize / 2) * 1.1 + 12);
+ this.maxLabelWidth = Math.round(widthPx * 2);
},
initFormData() {
@@ -768,48 +980,91 @@ export default {