refactor(formdata.vue): update default styles and config merging logic
- Adjusted the merging order of form configuration to prioritize frontend defaults when backend configurations are absent. - Clarified comments regarding the purpose of new visual styles and their application. - Modified the hideInnerBanner logic to ensure consistent behavior with the updated form styles.
This commit is contained in:
@@ -7,31 +7,41 @@
|
||||
r=function(){var o=this.value.show_banner...this.$mp.data...})
|
||||
报 "Cannot read properties of undefined (reading 'show_banner')"。 -->
|
||||
<view v-if="value && value.show_banner && value.form_banner" class="form-banner is-card-overlap" :style="bannerStyle + bannerBleedStyle">
|
||||
<!-- 固定高度容器:默认 180rpx ≈ 页面 1/8,由 formConfig.bannerHeight 控制。
|
||||
图片用 mode="aspectFill" 居中裁剪填充,使横幅只占页面八分之一(与设计图一致)。 -->
|
||||
<view class="banner-img-wrap" :style="bannerImgWrapStyle">
|
||||
<image :src="$util.img(value.form_banner)" mode="aspectFill" class="banner-img" />
|
||||
<!-- Banner 图片高度策略(与商家端预览 .preview-banner height:auto 对齐):
|
||||
默认 mode="widthFix":宽度撑满、高度按图片原始比例自适应,图片完整显示不裁剪;
|
||||
仅显式配置 formConfig.bannerHeight / banner_height 时才固定高度 + aspectFill 居中裁剪。 -->
|
||||
<view class="banner-img-wrap" :class="{ 'is-fixed-height': hasBannerHeight }" :style="bannerImgWrapStyle">
|
||||
<image :src="$util.img(value.form_banner)" :mode="bannerImgMode" class="banner-img" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 卡片容器:仅在后台配置了 banner 图片时启用,让表单浮在 banner 之上(参考左图布局)。
|
||||
无 banner 时不渲染 .form-card,保持原有平铺行为,零外溢。 -->
|
||||
<view v-if="hasBannerMode" class="form-card" :style="cardWrapStyle">
|
||||
<!-- 提示语 -->
|
||||
<view v-if="value && value.show_tip && value.form_tip" class="form-tip" :style="tipStyle">{{ value && value.form_tip }}</view>
|
||||
<!-- 表单组件 -->
|
||||
<ns-newform
|
||||
:data="formComponents"
|
||||
:customAttr="value"
|
||||
:mode="mergedFormConfig.formLayout || 'vertical'"
|
||||
:formConfig="mergedFormConfig"
|
||||
ref="nsNewform"
|
||||
></ns-newform>
|
||||
<!-- 提交按钮(外层 = form-bg + form-padding-x;按钮 = submit-bg + submit-color + input-height + input-radius)。
|
||||
showSubmit=false 时由父级页面渲染自己的提交按钮并通过 ref 调用本组件的 verify()/getFormData()。 -->
|
||||
<view v-if="showSubmit" class="form-submit-wrap" :style="submitWrapStyle">
|
||||
<!-- 卡片浮起模式:tip / 提交按钮位置可配(仅 card 风格生效)
|
||||
- tip_position: outside(默认)= 独立白卡负 margin 压住 banner 底部;inside = 内容卡内
|
||||
- submit_position: inside(默认)= 提交按钮在内容卡内;outside = 卡片下方独立区域 -->
|
||||
<template v-if="hasBannerMode">
|
||||
<!-- tip 独立卡(outside,默认):负 margin 压 banner + 白底 + 圆角 + 阴影,视觉参照商家端预览 .preview-tip -->
|
||||
<view v-if="value && value.show_tip && value.form_tip && tipPosition === 'outside'" class="form-tip-card" :style="tipCardStyle">{{ value.form_tip }}</view>
|
||||
<!-- 内容卡:tipPosition !== 'outside'(tip 关闭或 tip 在卡内)时由本卡接管负 margin 浮起 -->
|
||||
<view class="form-card" :style="cardWrapStyle">
|
||||
<!-- tip 卡内(inside):无独立卡视觉,用户配置的 bg/border/shadow 仍生效 -->
|
||||
<view v-if="value && value.show_tip && value.form_tip && tipPosition !== 'outside'" class="form-tip" :style="tipStyle">{{ value.form_tip }}</view>
|
||||
<!-- 表单组件 -->
|
||||
<ns-newform
|
||||
:data="formComponents"
|
||||
:customAttr="value"
|
||||
:mode="mergedFormConfig.formLayout || 'vertical'"
|
||||
:formConfig="mergedFormConfig"
|
||||
ref="nsNewform"
|
||||
></ns-newform>
|
||||
<!-- 提交按钮(inside,默认):在内容卡内 -->
|
||||
<view v-if="showSubmit && submitPosition !== 'outside'" class="form-submit-wrap" :style="submitWrapStyle">
|
||||
<view @click.stop="handleSubmit" class="form-submit" :style="submitStyle">{{ submitText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 提交按钮独立区(outside):卡片下方,无卡背景 -->
|
||||
<view v-if="showSubmit && submitPosition === 'outside'" class="form-submit-wrap" :style="submitWrapStyle">
|
||||
<view @click.stop="handleSubmit" class="form-submit" :style="submitStyle">{{ submitText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 无 banner 时仍按旧布局直接渲染 tip / ns-newform / submit,避免影响其他使用方(diy-group / diy-article 等) -->
|
||||
<template v-else>
|
||||
<!-- 提示语 -->
|
||||
@@ -140,13 +150,27 @@ export default {
|
||||
padding: `0 ${this._num(this.mergedFormConfig && this.mergedFormConfig.bannerPaddingX, 0)}rpx`
|
||||
});
|
||||
},
|
||||
// Banner 图片包裹层高度(rpx)。固定高度使图片用 mode="aspectFill" 居中裁剪填充,
|
||||
// 保证横幅只占页面 1/8 左右(默认 180rpx ≈ 1334rpx 屏高的 13.5%,接近 1/8)。
|
||||
// 后台可配 formConfig.bannerHeight(camelCase)/ banner_height(snake_case)。
|
||||
// Banner 图片高度模式(2026-09-03 对齐商家端预览):
|
||||
// 商家端预览 .preview-banner 是 max-width:100%; height:auto —— 按图片原始比例完整显示。
|
||||
// 此前 H5 固定 180rpx + aspectFill 居中裁剪,导致横幅高度不一/图片内容被裁缺失。
|
||||
// 现在:无显式配置 → widthFix 自适应(与后端 height:auto 等价);
|
||||
// 显式配置 bannerHeight / banner_height → 固定高度 + aspectFill 裁剪(用户主动选择)。
|
||||
hasBannerHeight() {
|
||||
const cfg = this.mergedFormConfig || {};
|
||||
const raw = cfg.bannerHeight !== undefined ? cfg.bannerHeight : cfg.banner_height;
|
||||
const n = parseInt(raw);
|
||||
return !isNaN(n) && n > 0;
|
||||
},
|
||||
bannerImgMode() {
|
||||
return this.hasBannerHeight ? 'aspectFill' : 'widthFix';
|
||||
},
|
||||
// Banner 图片包裹层高度:仅显式配置 bannerHeight(rpx,clamp 40-1200)时输出;否则为空由图片自适应。
|
||||
bannerImgWrapStyle() {
|
||||
return this.$util.objToStyle({
|
||||
height: `${this._num(this.mergedFormConfig && this.mergedFormConfig.bannerHeight, 180)}rpx`
|
||||
});
|
||||
if (!this.hasBannerHeight) return '';
|
||||
let h = parseInt(this.mergedFormConfig.bannerHeight !== undefined ? this.mergedFormConfig.bannerHeight : this.mergedFormConfig.banner_height);
|
||||
if (h < 40) h = 40;
|
||||
if (h > 1200) h = 1200;
|
||||
return this.$util.objToStyle({ height: h + 'rpx' });
|
||||
},
|
||||
// 表单风格:优先读显式 form_style(classic / card),未设置时回退到隐式判定(看 show_banner && form_banner)
|
||||
// - classic:经典风格,平铺无 banner 卡片
|
||||
@@ -162,33 +186,104 @@ export default {
|
||||
if (style === 'classic') return false;
|
||||
return !!(v.show_banner && v.form_banner);
|
||||
},
|
||||
// 卡片容器内联样式:maring-top(负偏移让卡片向上压住 banner 底部)+ border-radius + padding-x + box-shadow + background。
|
||||
// 数值由 formConfig 走 camelCase/snake_case 双读,缺省走默认值,使后端零配置时也能看到卡片浮起效果。
|
||||
// 关键:卡片必须自带白底 + z-index(见 SCSS .form-card)—— 只有卡片自己的背景才能"盖住"banner 图片底部,
|
||||
// 父级容器(如 formdata.vue 的 .system-form-wrap)是 banner 的祖先,其背景会被 banner 覆盖,无法形成浮起效果。
|
||||
// tip 提示语位置(仅 card 风格消费;classic 恒 'outside' 维持原结构)
|
||||
// outside=独立白卡浮起压 banner(默认);inside=内容卡内(无独立卡视觉)
|
||||
tipPosition() {
|
||||
if (!this.hasBannerMode) return 'outside';
|
||||
return this.mergedFormConfig.tipPosition === 'inside' ? 'inside' : 'outside';
|
||||
},
|
||||
// 提交按钮位置(仅 card 风格消费;classic 恒 'outside' 维持原结构)
|
||||
// inside=内容卡内(默认);outside=卡片下方独立区域
|
||||
submitPosition() {
|
||||
if (!this.hasBannerMode) return 'outside';
|
||||
return this.mergedFormConfig.submitPosition === 'outside' ? 'outside' : 'inside';
|
||||
},
|
||||
// 卡片容器内联样式:margin-top(负偏移+下移补偿)+ 左右外缩 + border-radius + box-shadow + background + border。
|
||||
// clamp 与默认值对齐后端 form.js syncFormConfigToCSS:overlap 0-200(默认48) / radius 0-40(默认24) / sidePad 0-60(默认30);
|
||||
// margin-top = -overlap + overlap_top(后端 --card-overlap 公式 (-overlap+overlapTop)/2 为 px,rpx 不除 2)
|
||||
// tip 独立卡(outside + showTip)带队浮起时,本卡只留正常间距(后端预览 draggable margin 10px=20rpx)
|
||||
// sidePad 语义(2026-09-03 与后端统一):卡片距屏幕左右距离(对齐后端 --card-side-pad,默认 30rpx=15px)。
|
||||
// formdata 链路(containerInset>0)容器已有 padding,卡片负 margin 破壳后再缩 sidePad(与 banner bleed 同思路);
|
||||
// DIY 链路(无 containerInset)直接 margin = sidePad。
|
||||
// 卡内内容缩进由 ns-newform .form-wrap 的 formPaddingX 承担(与后端 .draggable-wrap padding: form-padding-x 同构)。
|
||||
cardWrapStyle() {
|
||||
const cfg = this.mergedFormConfig || {};
|
||||
// 父级传了 containerInset(即 formdata.vue 场景),外层 system-form-wrap 已给左右 padding-x,这里默认 0 不重复
|
||||
// 其他场景(diy-group / diy-article 等未传 containerInset),回退到 bannerPaddingX 或 28rpx 保证卡片模式视觉正常
|
||||
const parentInset = this._num(this.containerInset, 0);
|
||||
const defaultSidePad = parentInset > 0 ? 0 : this._num(cfg.bannerPaddingX, 28);
|
||||
const sidePad = this._num(cfg.cardSidePad, defaultSidePad);
|
||||
// overlap:负值,让卡片向上"压"住 banner 底部(与设计图一致)
|
||||
const overlap = -Math.abs(this._num(cfg.cardOverlap, 48));
|
||||
let sidePad = this._num(cfg.cardSidePad, 30);
|
||||
if (sidePad < 0) sidePad = 0;
|
||||
if (sidePad > 60) sidePad = 60;
|
||||
const sideMargin = parentInset > 0 ? (sidePad - parentInset) : sidePad;
|
||||
// overlap:负值向上压住 banner 底部;overlap_top 为下移补偿(可正可负,叠加生效)
|
||||
let overlap = Math.abs(this._num(cfg.cardOverlap, 48));
|
||||
if (overlap > 200) overlap = 200;
|
||||
const overlapTop = this._num(cfg.cardOverlapTop, 0);
|
||||
// banner 实际渲染时才用负 margin 压住它;banner 被隐藏(如 hideInnerBanner / 配置缺失)时
|
||||
// 负 margin 会把卡片(含 tip)整体推出屏幕顶部,必须收回 0
|
||||
const bannerVisible = !!(this.value && this.value.show_banner && this.value.form_banner);
|
||||
// tip 独立卡存在时由 tip 卡带队压 banner,内容卡只留正常间距(20rpx ≈ 后端预览 10px)
|
||||
const tipLeads = this.tipPosition === 'outside' && !!(this.value && this.value.show_tip && this.value.form_tip);
|
||||
// 卡片圆角:缺省 24rpx(浮起卡片的圆角,比外层卡片的 16rpx 更明显,突出浮起感)
|
||||
const radius = this._num(cfg.cardRadius, 24);
|
||||
let radius = this._num(cfg.cardRadius, 24);
|
||||
if (radius < 0) radius = 0;
|
||||
if (radius > 40) radius = 40;
|
||||
// 阴影:缺省中等阴影(与设计方案一致)—— 由本容器承担浮起感
|
||||
const shadow = cfg.cardShadow || '0 8rpx 24rpx rgba(0,0,0,0.08)';
|
||||
// 卡片底色:纯白,与设计方案一致;可由后台 formConfig.cardBgColor 覆盖
|
||||
const bgColor = cfg.cardBgColor || '#ffffff';
|
||||
return this.$util.objToStyle({
|
||||
marginTop: overlap + 'rpx',
|
||||
paddingLeft: sidePad + 'rpx',
|
||||
paddingRight: sidePad + 'rpx',
|
||||
// 边框:宽度 rpx(0-20),留空/0 = 无边框
|
||||
let borderWidth = this._num(cfg.cardBorderWidth, 0);
|
||||
if (borderWidth < 0) borderWidth = 0;
|
||||
if (borderWidth > 20) borderWidth = 20;
|
||||
const style = {
|
||||
marginTop: (bannerVisible ? (tipLeads ? 20 : (-overlap + overlapTop)) : 0) + 'rpx',
|
||||
marginLeft: sideMargin + 'rpx',
|
||||
marginRight: sideMargin + 'rpx',
|
||||
borderRadius: radius + 'rpx',
|
||||
boxShadow: shadow,
|
||||
backgroundColor: bgColor
|
||||
});
|
||||
};
|
||||
if (borderWidth > 0) {
|
||||
style['border'] = borderWidth + 'rpx ' + (cfg.cardBorderStyle || 'solid') + ' ' + (cfg.cardBorderColor || 'transparent');
|
||||
}
|
||||
return this.$util.objToStyle(style);
|
||||
},
|
||||
// tip 独立卡样式(card + outside):负 margin 压 banner + 左右外缩 + 白底 + 圆角 + 阴影 + 细边框。
|
||||
// 视觉参照后端预览 .form-style-card .preview-tip(margin: var(--card-overlap) var(--card-side-pad) 0;白底 12px 圆角 柔和阴影 左对齐)
|
||||
// 用户配置的 tip 四态属性(bg/border/radius/shadow/padding/align)在此全部生效,仅默认值不同(独立卡默认白底卡视觉)
|
||||
// sidePad 语义与 cardWrapStyle 一致:卡片距屏幕左右距离(默认 30rpx;formdata 链路破壳 sidePad-parentInset)
|
||||
tipCardStyle() {
|
||||
const cfg = this.mergedFormConfig || {};
|
||||
const bannerVisible = !!(this.value && this.value.show_banner && this.value.form_banner);
|
||||
let overlap = Math.abs(this._num(cfg.cardOverlap, 48));
|
||||
if (overlap > 200) overlap = 200;
|
||||
const overlapTop = this._num(cfg.cardOverlapTop, 0);
|
||||
const parentInset = this._num(this.containerInset, 0);
|
||||
let sidePad = this._num(cfg.cardSidePad, 30);
|
||||
if (sidePad < 0) sidePad = 0;
|
||||
if (sidePad > 60) sidePad = 60;
|
||||
const sideMargin = parentInset > 0 ? (sidePad - parentInset) : sidePad;
|
||||
const padT = this._num(cfg.tipPaddingTop, 32);
|
||||
const padR = this._num(cfg.tipPaddingRight, 32);
|
||||
const padB = this._num(cfg.tipPaddingBottom, 32);
|
||||
const padL = this._num(cfg.tipPaddingLeft, 32);
|
||||
const style = {
|
||||
marginTop: (bannerVisible ? (-overlap + overlapTop) : 0) + 'rpx',
|
||||
marginLeft: sideMargin + 'rpx',
|
||||
marginRight: sideMargin + 'rpx',
|
||||
padding: `${padT}rpx ${padR}rpx ${padB}rpx ${padL}rpx`,
|
||||
'font-size': `${this._num(cfg.tipFontSize, 32)}rpx`,
|
||||
'color': cfg.tipColor || '#1f2937',
|
||||
'background-color': cfg.tipBgColor || '#ffffff',
|
||||
'border-radius': `${this._num(cfg.tipRadius, 24)}rpx`,
|
||||
'box-shadow': cfg.tipShadow || '0 8rpx 24rpx rgba(0,0,0,0.08)',
|
||||
'text-align': cfg.tipAlign || 'left'
|
||||
};
|
||||
// 边框:独立卡默认细边框(2rpx ≈ 后端预览 1px);配置 0 = 无边框
|
||||
const bw = this._num(cfg.tipBorderWidth, 2);
|
||||
if (bw > 0) {
|
||||
style['border'] = `${bw}rpx ${cfg.tipBorderStyle || 'solid'} ${cfg.tipBorderColor || 'rgba(0,0,0,0.06)'}`;
|
||||
}
|
||||
return this.$util.objToStyle(style);
|
||||
},
|
||||
// Banner 容器破壳样式:仅在卡片模式下 + 父级传了 containerInset>0 时启用,让 banner 突破父容器 padding 跨越屏幕宽度。
|
||||
// 计算逻辑:负 margin-left/right + 等量扩宽 width,使 banner 元素左/右边界对齐到屏幕边缘。
|
||||
@@ -203,24 +298,76 @@ export default {
|
||||
width: 'calc(100% + ' + expand + 'rpx)'
|
||||
});
|
||||
},
|
||||
// 提示语样式:padding-x、font-size、color、bg-color、border-bottom(与后端 .form-preview-tip 对齐)
|
||||
// 提示语样式(classic 平铺 / card+inside 卡内共用):与后端 edit.html 内联 .preview-tip 对齐
|
||||
// - 四边内边距:未配置时经典态 上/下=rowPaddingY(4) 左右=tipPaddingX(14);卡片态统一 32rpx
|
||||
// - 边框:classic 用 border-bottom(宽度默认 0;旧数据仅配 color → 2rpx 底边);
|
||||
// card 用全边框(配置宽度才输出)
|
||||
// - 圆角 / 阴影(rpx 字符串) / 对齐(card 态默认左对齐,经典态居中)
|
||||
// - 背景色:''=未配置 → 透明(独立卡白底兜底已挪到 tipCardStyle,卡内 tip 无独立卡视觉)
|
||||
tipStyle() {
|
||||
const cfg = this.mergedFormConfig || {};
|
||||
const card = this.hasBannerMode;
|
||||
const padT = this._num(cfg.tipPaddingTop, card ? 32 : this._num(cfg.rowPaddingY, 4));
|
||||
const padR = this._num(cfg.tipPaddingRight, card ? 32 : this._num(cfg.tipPaddingX, 14));
|
||||
const padB = this._num(cfg.tipPaddingBottom, card ? 32 : this._num(cfg.rowPaddingY, 4));
|
||||
const padL = this._num(cfg.tipPaddingLeft, card ? 32 : this._num(cfg.tipPaddingX, 14));
|
||||
const style = {
|
||||
padding: `${this._num(cfg.rowPaddingY, 4)}rpx ${this._num(cfg.tipPaddingX, 14)}rpx`,
|
||||
padding: `${padT}rpx ${padR}rpx ${padB}rpx ${padL}rpx`,
|
||||
'font-size': `${this._num(cfg.tipFontSize, 32)}rpx`,
|
||||
'color': cfg.tipColor || '#000000',
|
||||
'background-color': cfg.tipBgColor || 'transparent'
|
||||
'color': cfg.tipColor || (card ? '#1f2937' : '#000000'),
|
||||
'background-color': cfg.tipBgColor || 'transparent',
|
||||
'text-align': cfg.tipAlign || (card ? 'left' : 'center')
|
||||
};
|
||||
// 仅在配置了 tipBorderColor 时添加底线,避免 transparent 占位仍增加 2rpx 高度
|
||||
if (cfg.tipBorderColor) {
|
||||
// 边框:配置了宽度(>0)输出;未配宽度但配了颜色 → 旧数据兼容,2rpx 底边(仅经典态)
|
||||
const bw = this._num(cfg.tipBorderWidth, 0);
|
||||
if (bw > 0) {
|
||||
const bs = cfg.tipBorderStyle || 'solid';
|
||||
const bc = cfg.tipBorderColor || 'rgba(0,0,0,0.06)';
|
||||
if (card) {
|
||||
style['border'] = `${bw}rpx ${bs} ${bc}`;
|
||||
} else {
|
||||
style['border-bottom'] = `${bw}rpx ${bs} ${bc}`;
|
||||
}
|
||||
} else if (!card && cfg.tipBorderColor) {
|
||||
style['border-bottom'] = `2rpx solid ${cfg.tipBorderColor}`;
|
||||
}
|
||||
// 圆角(rpx)
|
||||
if (cfg.tipRadius !== undefined && cfg.tipRadius !== null && cfg.tipRadius !== '') {
|
||||
style['border-radius'] = `${this._num(cfg.tipRadius, 0)}rpx`;
|
||||
}
|
||||
// 阴影:后端存 rpx 单位字符串(如 '0 4rpx 12rpx rgba(...)'),uniapp H5/MP 运行时支持 rpx
|
||||
if (cfg.tipShadow) {
|
||||
style['box-shadow'] = cfg.tipShadow;
|
||||
}
|
||||
return this.$util.objToStyle(style);
|
||||
},
|
||||
// 提交按钮外层:与后端 .form-preview-submit 对齐(margin-top + padding: row-padding-y form-padding-x;background: form-bg-color)
|
||||
// card + inside(默认)时按钮已在内容卡内:padding 收窄为卡内边距(≈后端预览 14px 12px 20px),不设独立背景(继承卡白底)
|
||||
submitWrapStyle() {
|
||||
const cfg = this.mergedFormConfig || {};
|
||||
if (this.hasBannerMode && this.submitPosition !== 'outside') {
|
||||
return this.$util.objToStyle({
|
||||
marginTop: `${this._num(cfg.submitMarginTop, 0)}rpx`,
|
||||
padding: `24rpx 24rpx 40rpx`
|
||||
});
|
||||
}
|
||||
if (this.hasBannerMode) {
|
||||
// card + outside:卡片下方独立区域 —— 与后端 .preview-submit-wrap(card 模式)同构:
|
||||
// 左右破壳对齐卡片缩进(sidePad - parentInset),水平内缩 formPaddingX,
|
||||
// 上下 padding 36rpx/48rpx(后端 18px/24px),背景白底(后端 .preview-submit-wrap 亦为白底)
|
||||
const parentInset = this._num(this.containerInset, 0);
|
||||
let sidePad = this._num(cfg.cardSidePad, 30);
|
||||
if (sidePad < 0) sidePad = 0;
|
||||
if (sidePad > 60) sidePad = 60;
|
||||
const sideMargin = parentInset > 0 ? (sidePad - parentInset) : 0;
|
||||
return this.$util.objToStyle({
|
||||
marginTop: `${this._num(cfg.submitMarginTop, 0)}rpx`,
|
||||
marginLeft: sideMargin + 'rpx',
|
||||
marginRight: sideMargin + 'rpx',
|
||||
padding: `36rpx ${this._num(cfg.formPaddingX, 14)}rpx 48rpx`,
|
||||
'background-color': cfg.formBgColor || '#ffffff'
|
||||
});
|
||||
}
|
||||
return this.$util.objToStyle({
|
||||
marginTop: `${this._num(cfg.submitMarginTop, 0)}rpx`,
|
||||
padding: `${this._num(cfg.rowPaddingY, 4)}rpx ${this._num(cfg.formPaddingX, 14)}rpx`,
|
||||
@@ -303,6 +450,8 @@ export default {
|
||||
labelFontWeight: pick('labelFontWeight', 'label_font_weight'),
|
||||
labelAutoMaxWidth: pick('labelAutoMaxWidth', 'label_auto_max_width'),
|
||||
requiredColor: pick('requiredColor', 'required_color'),
|
||||
// 必填星号位置:before=标签前(默认)/ after=标签后(终端无关,存 base 层)
|
||||
requiredPosition: pick('requiredPosition', 'required_position'),
|
||||
checkedColor: pick('checkedColor', 'checked_color'),
|
||||
// 占位符:遗漏会被 ns-newform SCSS 默认值回退覆盖
|
||||
placeholderColor: pick('placeholderColor', 'placeholder_color'),
|
||||
@@ -323,27 +472,47 @@ export default {
|
||||
submitWidthPercent: pick('submitWidthPercent', 'submit_width_percent'),
|
||||
submitSize: pick('submitSize', 'submit_size'),
|
||||
submitMarginTop: pick('submitMarginTop', 'submit_margin_top'),
|
||||
// 提示语
|
||||
tipFontSize: pick('tipFontSize', 'tip_font_size'),
|
||||
tipColor: pick('tipColor', 'tip_color'),
|
||||
tipBgColor: pick('tipBgColor', 'tip_bg_color'),
|
||||
tipBorderColor: pick('tipBorderColor', 'tip_border_color'),
|
||||
// 卡片浮起(仅 show_banner && form_banner 启用)
|
||||
cardOverlap: pick('cardOverlap', 'card_overlap'),
|
||||
cardRadius: pick('cardRadius', 'card_radius'),
|
||||
cardShadow: pick('cardShadow', 'card_shadow'),
|
||||
cardSidePad: pick('cardSidePad', 'card_side_pad'),
|
||||
cardBgColor: pick('cardBgColor', 'card_bg_color')
|
||||
};
|
||||
// 提示语(与后端 form.js syncFormConfigToCSS 的 --tip-* 变量一一对应)
|
||||
tipFontSize: pick('tipFontSize', 'tip_font_size'),
|
||||
tipColor: pick('tipColor', 'tip_color'),
|
||||
tipBgColor: pick('tipBgColor', 'tip_bg_color'),
|
||||
tipBorderColor: pick('tipBorderColor', 'tip_border_color'),
|
||||
// 边框:宽度(rpx)/线型;未配置宽度时保留旧逻辑(仅 color 配置 → 底边 2rpx)
|
||||
tipBorderWidth: pick('tipBorderWidth', 'tip_border_width'),
|
||||
tipBorderStyle: pick('tipBorderStyle', 'tip_border_style'),
|
||||
// 独立样式:圆角 / 四边内边距 / 阴影 / 对齐('' 与 null 均走 delete → 用各自态的兜底默认)
|
||||
tipRadius: pick('tipRadius', 'tip_radius'),
|
||||
tipPaddingTop: pick('tipPaddingTop', 'tip_padding_top'),
|
||||
tipPaddingRight: pick('tipPaddingRight', 'tip_padding_right'),
|
||||
tipPaddingBottom: pick('tipPaddingBottom', 'tip_padding_bottom'),
|
||||
tipPaddingLeft: pick('tipPaddingLeft', 'tip_padding_left'),
|
||||
tipShadow: pick('tipShadow', 'tip_shadow'),
|
||||
tipAlign: pick('tipAlign', 'tip_align'),
|
||||
// 卡片浮起(仅 show_banner && form_banner 启用)
|
||||
cardOverlap: pick('cardOverlap', 'card_overlap'),
|
||||
// 额外下移补偿(rpx,可正可负,与 overlap 叠加:margin-top = -overlap + overlap_top)
|
||||
cardOverlapTop: pick('cardOverlapTop', 'card_overlap_top'),
|
||||
cardRadius: pick('cardRadius', 'card_radius'),
|
||||
cardShadow: pick('cardShadow', 'card_shadow'),
|
||||
cardSidePad: pick('cardSidePad', 'card_side_pad'),
|
||||
cardBgColor: pick('cardBgColor', 'card_bg_color'),
|
||||
// 卡片边框(宽度 rpx / CSS 线型 / 颜色;留空 = 无边框)
|
||||
cardBorderWidth: pick('cardBorderWidth', 'card_border_width'),
|
||||
cardBorderStyle: pick('cardBorderStyle', 'card_border_style'),
|
||||
cardBorderColor: pick('cardBorderColor', 'card_border_color'),
|
||||
// 位置控制(仅 card 风格生效;outside/inside 见 tipPosition/submitPosition computed)
|
||||
tipPosition: pick('tipPosition', 'tip_position'),
|
||||
submitPosition: pick('submitPosition', 'submit_position')
|
||||
};
|
||||
// 移除 undefined / 空字符串(保留 0/false)
|
||||
Object.keys(base).forEach(function(k) {
|
||||
if (base[k] === undefined || base[k] === null || base[k] === '') {
|
||||
delete base[k];
|
||||
}
|
||||
});
|
||||
// 前端视觉默认:强制覆盖后端 formConfig 中可能存在的旧默认(horizontal / 红按钮 / 灰背景等),
|
||||
// 与 formdata.vue 的 styleDefaults 保持一致,使所有 diy-form(含 diy-group 内的表单)统一呈现新设计稿样式。
|
||||
// 后端仍保留行为/文案类配置(behavior / submitText / banner / tip 等),本合并仅覆盖视觉字段。
|
||||
// 前端视觉默认:仅作兜底(后端未配置的字段才生效)。
|
||||
// 注意合并顺序:base 在后 —— 后台 formConfig 显式配置的值(如 submit_bg_color / input_radius)
|
||||
// 必须覆盖前端默认,否则商家端样式配置完全不生效(曾因此导致提交按钮恒为蓝色)。
|
||||
const styleDefaults = {
|
||||
formLayout: 'vertical',
|
||||
formPaddingX: 28,
|
||||
@@ -367,7 +536,7 @@ export default {
|
||||
};
|
||||
// 平台差异化配置(terminal 块在 formConfig 子对象内)
|
||||
// 优先级:v.formConfig.terminal > v.form_config_terminal > v.terminal > v.form_config_platform
|
||||
const result = Object.assign({}, base, styleDefaults);
|
||||
const result = Object.assign({}, styleDefaults, base);
|
||||
const termBlock = (v.formConfig && v.formConfig.terminal) || v.form_config_terminal || v.terminal || v.form_config_platform;
|
||||
if (termBlock && typeof termBlock === 'object') {
|
||||
Object.keys(termBlock).forEach(function(platform) {
|
||||
@@ -503,19 +672,23 @@ export default {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
// 横幅图片固定高度容器:默认 180rpx ≈ 页面 1/8,与 bannerImgWrapStyle 默认值一致。
|
||||
// 后台可通过 formConfig.bannerHeight / banner_height 覆盖。
|
||||
// 配合 mode="aspectFill" 使图片居中裁剪填充,跨端一致呈现"只占页面八分之一"的视觉效果。
|
||||
// 横幅图片容器:默认高度由 image widthFix 按图片比例自适应(与商家端预览 height:auto 对齐);
|
||||
// .is-fixed-height(显式配置 bannerHeight)时高度由 bannerImgWrapStyle 内联写入,
|
||||
// 配合 mode="aspectFill" 居中裁剪填充。
|
||||
.banner-img-wrap {
|
||||
width: 100%;
|
||||
height: 180rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&.is-fixed-height {
|
||||
.banner-img {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@@ -526,18 +699,34 @@ export default {
|
||||
// 关键:卡片必须自带白底并 z-index 高于 banner,才能真正"盖住"banner 图片底部形成浮起;
|
||||
// 父级容器(formdata.vue 的 .system-form-wrap)虽也是白底,但它是 banner 的祖先、背景会被 banner 覆盖,
|
||||
// 因此本容器的白底不可省略(与 .system-form-wrap 同色,视觉上从卡片向下自然延续到页面底部)。
|
||||
.form-card {
|
||||
// 定位上下文 + 高于 banner 的层级:让卡片盖住 banner 底部(banner z-index:1)
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
// 兜底白底 / 圆角 / 阴影:与后端未配置时内联写入的默认值一致;后台配置时由内联 cardWrapStyle 覆盖
|
||||
background-color: #ffffff;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
|
||||
.form-card {
|
||||
// 定位上下文 + 高于 banner 的层级:让卡片盖住 banner 底部(banner z-index:1)
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
// 兜底白底 / 圆角 / 阴影:与后端未配置时内联写入的默认值一致;后台配置时由内联 cardWrapStyle 覆盖
|
||||
background-color: #ffffff;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
|
||||
// 关键:裁剪卡内子元素(ns-newform 白底 / submit 区)到圆角内。
|
||||
// tip 关闭时本卡带队负 margin 压 banner,若无 overflow:hidden,
|
||||
// 卡内第一个子元素的方形背景会盖住卡片上圆角(banner 图片在圆角外的部分被遮)。
|
||||
// 商家端预览 .draggable-wrap 同样有 overflow:hidden(form.css 两处同步)。
|
||||
overflow: hidden;
|
||||
// 兜底 padding-bottom:让卡片与后面内容(如推荐码、其它 diy 组件)有间距
|
||||
padding-bottom: 24rpx;
|
||||
}
|
||||
|
||||
// tip 独立卡(card + tip_position=outside):浮在 banner 上方的独立白卡。
|
||||
// margin/padding/白底/圆角/阴影/边框 全部由 tipCardStyle 内联写入;
|
||||
// 必须自带 z-index 高于 banner(z-index:1)才能真正"盖住"banner 底部形成浮起。
|
||||
.form-tip-card {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
box-sizing: border-box;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.form-tip {
|
||||
// 提示语:上下内边距 / 左右内边距 / 字号 / 颜色 / 背景 全部由 tipStyle 内联写入
|
||||
padding: 0;
|
||||
|
||||
Reference in New Issue
Block a user