refactor(diy-form): 兼容前后端命名格式,优化表单配置处理
1. 重构mergedFormConfig逻辑,同时支持camelCase和snake_case格式的配置项,camelCase优先读取 2. 调整ns-newform的mode参数读取mergedFormConfig的formLayout 3. 优化提示语样式,新增tipBorderColor支持显示底部边框 4. 修复submitText读取逻辑,改为从mergedFormConfig获取 5. 移除多余的console日志,更新注释说明
This commit is contained in:
@@ -7,10 +7,10 @@
|
|||||||
<!-- 提示语 -->
|
<!-- 提示语 -->
|
||||||
<view v-if="value.show_tip && value.form_tip" class="form-tip" :style="tipStyle">{{ value.form_tip }}</view>
|
<view v-if="value.show_tip && value.form_tip" class="form-tip" :style="tipStyle">{{ value.form_tip }}</view>
|
||||||
<!-- 表单组件 -->
|
<!-- 表单组件 -->
|
||||||
<ns-newform
|
<ns-newform
|
||||||
:data="formComponents"
|
:data="formComponents"
|
||||||
:customAttr="value"
|
:customAttr="value"
|
||||||
:mode="formCfg.form_layout === 'vertical' ? 'vertical' : 'horizontal'"
|
:mode="mergedFormConfig.formLayout || 'horizontal'"
|
||||||
:formConfig="mergedFormConfig"
|
:formConfig="mergedFormConfig"
|
||||||
ref="nsNewform"
|
ref="nsNewform"
|
||||||
></ns-newform>
|
></ns-newform>
|
||||||
@@ -90,15 +90,20 @@ export default {
|
|||||||
padding: `0 ${this._num(this.mergedFormConfig && this.mergedFormConfig.bannerPaddingX, 0)}rpx`
|
padding: `0 ${this._num(this.mergedFormConfig && this.mergedFormConfig.bannerPaddingX, 0)}rpx`
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 提示语样式:padding-x、font-size、color、bg-color(与后端 .form-preview-tip 对齐)
|
// 提示语样式:padding-x、font-size、color、bg-color、border-bottom(与后端 .form-preview-tip 对齐)
|
||||||
tipStyle() {
|
tipStyle() {
|
||||||
const cfg = this.mergedFormConfig || {};
|
const cfg = this.mergedFormConfig || {};
|
||||||
return this.$util.objToStyle({
|
const style = {
|
||||||
padding: `${this._num(cfg.rowPaddingY, 4)}rpx ${this._num(cfg.tipPaddingX, 14)}rpx`,
|
padding: `${this._num(cfg.rowPaddingY, 4)}rpx ${this._num(cfg.tipPaddingX, 14)}rpx`,
|
||||||
'font-size': `${this._num(cfg.tipFontSize, 24)}rpx`,
|
'font-size': `${this._num(cfg.tipFontSize, 24)}rpx`,
|
||||||
'color': cfg.tipColor || '#666666',
|
'color': cfg.tipColor || '#666666',
|
||||||
'background-color': cfg.tipBgColor || 'transparent'
|
'background-color': cfg.tipBgColor || 'transparent'
|
||||||
});
|
};
|
||||||
|
// 仅在配置了 tipBorderColor 时添加底线,避免 transparent 占位仍增加 2rpx 高度
|
||||||
|
if (cfg.tipBorderColor) {
|
||||||
|
style['border-bottom'] = `2rpx solid ${cfg.tipBorderColor}`;
|
||||||
|
}
|
||||||
|
return this.$util.objToStyle(style);
|
||||||
},
|
},
|
||||||
// 提交按钮外层:与后端 .form-preview-submit 对齐(padding: row-padding-y form-padding-x;background: form-bg-color)
|
// 提交按钮外层:与后端 .form-preview-submit 对齐(padding: row-padding-y form-padding-x;background: form-bg-color)
|
||||||
submitWrapStyle() {
|
submitWrapStyle() {
|
||||||
@@ -131,8 +136,9 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 提交按钮文字:与后端 design.html <button>提交</button> 默认对齐,开放给 formConfig 覆盖
|
// 提交按钮文字:与后端 design.html <button>提交</button> 默认对齐,开放给 formConfig 覆盖
|
||||||
|
// 走 mergedFormConfig(兼容 camelCase / snake_case),让 formConfig.submitText 能正确覆盖
|
||||||
submitText() {
|
submitText() {
|
||||||
return this.formCfg.submit_text || '提交';
|
return this.mergedFormConfig.submitText || '提交';
|
||||||
},
|
},
|
||||||
// 后端把表单样式配置统一存放在 data.formConfig 子对象中(与后端 design.js getDefaultFormData().formConfig 字段名一致)。
|
// 后端把表单样式配置统一存放在 data.formConfig 子对象中(与后端 design.js getDefaultFormData().formConfig 字段名一致)。
|
||||||
// 这里做一次归一化:优先取 formConfig;如果历史数据是扁平结构(直接挂在 value 上),也做兼容。
|
// 这里做一次归一化:优先取 formConfig;如果历史数据是扁平结构(直接挂在 value 上),也做兼容。
|
||||||
@@ -147,34 +153,45 @@ export default {
|
|||||||
mergedFormConfig() {
|
mergedFormConfig() {
|
||||||
const v = this.value || {};
|
const v = this.value || {};
|
||||||
const fc = this.formCfg;
|
const fc = this.formCfg;
|
||||||
|
// 后端实际返回 camelCase(如 formPaddingX / formBgColor / labelFontSize),
|
||||||
|
// 但旧版 design.js / 部分序列化路径可能用 snake_case(form_padding_x)。这里同时读两种写法,camelCase 优先
|
||||||
|
const self = this;
|
||||||
|
const pick = function(camel, snake) {
|
||||||
|
var v1 = fc[camel];
|
||||||
|
if (v1 !== undefined && v1 !== null && v1 !== '') return v1;
|
||||||
|
return fc[snake];
|
||||||
|
};
|
||||||
// 通用全局配置(与后端 design.js getDefaultFormData().formConfig 字段名一致)
|
// 通用全局配置(与后端 design.js getDefaultFormData().formConfig 字段名一致)
|
||||||
const base = {
|
const base = {
|
||||||
formPaddingX: fc.form_padding_x,
|
formPaddingX: pick('formPaddingX', 'form_padding_x'),
|
||||||
bannerPaddingX: fc.banner_padding_x,
|
bannerPaddingX: pick('bannerPaddingX', 'banner_padding_x'),
|
||||||
tipPaddingX: fc.tip_padding_x,
|
tipPaddingX: pick('tipPaddingX', 'tip_padding_x'),
|
||||||
rowPaddingY: fc.row_padding_y,
|
rowPaddingY: pick('rowPaddingY', 'row_padding_y'),
|
||||||
rowMinHeight: fc.row_min_height,
|
rowMinHeight: pick('rowMinHeight', 'row_min_height'),
|
||||||
labelGap: fc.label_gap,
|
labelGap: pick('labelGap', 'label_gap'),
|
||||||
formBgColor: fc.form_bg_color,
|
formBgColor: pick('formBgColor', 'form_bg_color'),
|
||||||
rowDividerColor: fc.row_divider_color,
|
rowDividerColor: pick('rowDividerColor', 'row_divider_color'),
|
||||||
showRowDivider: this._coerceBool(fc.show_row_divider),
|
showRowDivider: self._coerceBool(pick('showRowDivider', 'show_row_divider')),
|
||||||
inputHeight: fc.input_height,
|
inputHeight: pick('inputHeight', 'input_height'),
|
||||||
inputRadius: fc.input_radius,
|
inputRadius: pick('inputRadius', 'input_radius'),
|
||||||
labelWidthMode: fc.label_width_mode,
|
formLayout: pick('formLayout', 'form_layout'),
|
||||||
labelFixedWidth: fc.label_fixed_width,
|
labelWidthMode: pick('labelWidthMode', 'label_width_mode'),
|
||||||
labelFontSize: fc.label_font_size,
|
labelFixedWidth: pick('labelFixedWidth', 'label_fixed_width'),
|
||||||
labelColor: fc.label_color,
|
labelFontSize: pick('labelFontSize', 'label_font_size'),
|
||||||
requiredColor: fc.required_color,
|
labelColor: pick('labelColor', 'label_color'),
|
||||||
checkedColor: fc.checked_color,
|
requiredColor: pick('requiredColor', 'required_color'),
|
||||||
submitColor: fc.submit_color,
|
checkedColor: pick('checkedColor', 'checked_color'),
|
||||||
submitBgColor: fc.submit_bg_color,
|
submitText: pick('submitText', 'submit_text'),
|
||||||
|
submitColor: pick('submitColor', 'submit_color'),
|
||||||
|
submitBgColor: pick('submitBgColor', 'submit_bg_color'),
|
||||||
// 提交按钮尺寸:宽度百分比 + 尺寸预设(与后端 design.js 对齐)
|
// 提交按钮尺寸:宽度百分比 + 尺寸预设(与后端 design.js 对齐)
|
||||||
submitWidthPercent: fc.submit_width_percent,
|
submitWidthPercent: pick('submitWidthPercent', 'submit_width_percent'),
|
||||||
submitSize: fc.submit_size,
|
submitSize: pick('submitSize', 'submit_size'),
|
||||||
// 提示语
|
// 提示语
|
||||||
tipFontSize: fc.tip_font_size,
|
tipFontSize: pick('tipFontSize', 'tip_font_size'),
|
||||||
tipColor: fc.tip_color,
|
tipColor: pick('tipColor', 'tip_color'),
|
||||||
tipBgColor: fc.tip_bg_color
|
tipBgColor: pick('tipBgColor', 'tip_bg_color'),
|
||||||
|
tipBorderColor: pick('tipBorderColor', 'tip_border_color')
|
||||||
};
|
};
|
||||||
// 移除 undefined / 空字符串(保留 0/false)
|
// 移除 undefined / 空字符串(保留 0/false)
|
||||||
Object.keys(base).forEach(function(k) {
|
Object.keys(base).forEach(function(k) {
|
||||||
@@ -182,10 +199,10 @@ export default {
|
|||||||
delete base[k];
|
delete base[k];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 平台差异化配置(与后端 formConfig.terminal 字段名对齐)
|
// 平台差异化配置(terminal 块在 formConfig 子对象内)
|
||||||
// 优先级:value.form_config_terminal > value.terminal > value.form_config_platform
|
// 优先级:v.formConfig.terminal > v.form_config_terminal > v.terminal > v.form_config_platform
|
||||||
const result = Object.assign({}, base);
|
const result = Object.assign({}, base);
|
||||||
const termBlock = v.form_config_terminal || v.terminal || v.form_config_platform;
|
const termBlock = (v.formConfig && v.formConfig.terminal) || v.form_config_terminal || v.terminal || v.form_config_platform;
|
||||||
if (termBlock && typeof termBlock === 'object') {
|
if (termBlock && typeof termBlock === 'object') {
|
||||||
Object.keys(termBlock).forEach(function(platform) {
|
Object.keys(termBlock).forEach(function(platform) {
|
||||||
var src = termBlock[platform];
|
var src = termBlock[platform];
|
||||||
@@ -193,8 +210,7 @@ export default {
|
|||||||
// 嵌套值若为 snake_case(部分序列化路径),在此统一转 camelCase
|
// 嵌套值若为 snake_case(部分序列化路径),在此统一转 camelCase
|
||||||
var translated = {};
|
var translated = {};
|
||||||
Object.keys(src).forEach(function(k) {
|
Object.keys(src).forEach(function(k) {
|
||||||
var camel = k.replace(/_([a-z])/g, function(_, c) { return c.toUpperCase(); });
|
translated[self.$util.snakeToCamel(k)] = src[k];
|
||||||
translated[camel] = src[k];
|
|
||||||
});
|
});
|
||||||
result[platform] = translated;
|
result[platform] = translated;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -60,12 +60,12 @@ export default {
|
|||||||
},
|
},
|
||||||
formTip() {
|
formTip() {
|
||||||
const tip = this.detail?.form_tip
|
const tip = this.detail?.form_tip
|
||||||
console.log('formTip computed, tip value:', tip, 'truthy:', !!tip)
|
|
||||||
return tip ? tip : '请填写表单所需信息'
|
return tip ? tip : '请填写表单所需信息'
|
||||||
},
|
},
|
||||||
// 构造 diy-form raw 模式期望的 value 形态:
|
// 构造 diy-form raw 模式期望的 value 形态:
|
||||||
// - jsonData:透传给 ns-newform(已是 ns-newform 期望的 [{ controller, value, val }])
|
// - jsonData:透传给 ns-newform(已是 ns-newform 期望的 [{ controller, value, val }])
|
||||||
// - formConfig:snake_case 表单配置,diy-form 内部 mergedFormConfig 会做 camelCase 转换
|
// - formConfig:后端返回 camelCase(如 formPaddingX / formBgColor / labelFontSize),
|
||||||
|
// diy-form 内部 mergedFormConfig 同时兼容 snake_case 后再交给 ns-newform
|
||||||
// - 不传 show_banner / show_tip:让 diy-form 自带的 banner/tip 不渲染(页面已自渲染)
|
// - 不传 show_banner / show_tip:让 diy-form 自带的 banner/tip 不渲染(页面已自渲染)
|
||||||
// 注:本 computed 只在 <block v-if="detail"> 内被消费,无需 null 守卫
|
// 注:本 computed 只在 <block v-if="detail"> 内被消费,无需 null 守卫
|
||||||
diyValue() {
|
diyValue() {
|
||||||
@@ -138,7 +138,6 @@ export default {
|
|||||||
success: res => {
|
success: res => {
|
||||||
if (res.code == 0 && res.data) {
|
if (res.code == 0 && res.data) {
|
||||||
this.detail = res.data
|
this.detail = res.data
|
||||||
console.log(`form data =>`, this.detail)
|
|
||||||
this.updateNavbarTitle();
|
this.updateNavbarTitle();
|
||||||
}
|
}
|
||||||
this.$refs.loadingCover && this.$refs.loadingCover.hide()
|
this.$refs.loadingCover && this.$refs.loadingCover.hide()
|
||||||
|
|||||||
Reference in New Issue
Block a user