From acab1971ab8a085b536360a5e389ede17a34fdf4 Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Fri, 4 Sep 2026 13:48:00 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ns-newform.vue):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=A0=B7=E5=BC=8F=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E7=BA=A7=E6=8E=A7=E4=BB=B6=E5=B0=BA=E5=AF=B8?= =?UTF-8?q?=E5=92=8C=E6=A0=B7=E5=BC=8F=E5=8A=A8=E6=80=81=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ns-newform/ns-newform.vue | 60 ++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/components/ns-newform/ns-newform.vue b/components/ns-newform/ns-newform.vue index b299257..8842c21 100644 --- a/components/ns-newform/ns-newform.vue +++ b/components/ns-newform/ns-newform.vue @@ -36,7 +36,7 @@ :placeholder="item.value.placeholder" placeholder-class="placeholder color-tip" v-model="item.val" - :style="textareaStyle" + :style="item._textareaStyle" > @@ -54,7 +54,7 @@ {{ item.value.required ? '*' : '' }} {{ item.value.title }}{{ item.value.required ? '*' : '' }} - + {{ item.val }} {{ item.value.placeholder || $lang('components.ns-newform.selectPlaceholder') }} @@ -70,7 +70,7 @@ {{ item.value.required ? '*' : '' }} {{ item.value.title }}{{ item.value.required ? '*' : '' }} - + - + - + {{ item.value.required ? '*' : '' }} {{ item.value.title }}{{ item.value.required ? '*' : '' }} - + {{ item.value.required ? '*' : '' }} {{ item.value.title }}{{ item.value.required ? '*' : '' }} - + 0 ? n : 44; }, - // textarea 专用 inline style(所有平台统一使用,见 template 中 textarea 节点) - // 高度 = rows × lineHeight + padding + border,由 formConfig 动态控制,与 ns-form 同公式 - textareaStyle() { + // textarea 基础 inline style 对象(供 textareaStyle 与字段级尺寸合并复用) + textareaBaseStyle() { const lh = this.$util.rpx(this.textareaLineHeightValue); const rows = this.textareaRowsValue; const paddings = this.$util.rpx(24) + this.$util.rpx(2); // padding 12rpx 上下 + border 1rpx 上下 const h = (this.$util.rpx(this.textareaLineHeightValue * (rows - 1)) + lh) + paddings; - return this.$util.objToStyle({ + return { 'height': h, 'min-height': h, 'line-height': lh, 'border-radius': this.$util.rpx(this.config.inputRadius) - }); + }; + }, + // textarea 专用 inline style(所有平台统一使用,见 template 中 textarea 节点) + // 高度 = rows × lineHeight + padding + border,由 formConfig 动态控制,与 ns-form 同公式 + textareaStyle() { + return this.$util.objToStyle(this.textareaBaseStyle); }, labelStyle() { const style = { @@ -596,10 +600,28 @@ export default { // 行容器基础上下内边距(原 rowWrapStyle 语义:全局行间距 rowPaddingY;左右恒 0) const rowPadY = this.$util.rpx(this.config.rowPaddingY); const clampRpx = (n, min, max) => this.$util.rpx(Math.max(min, Math.min(max, n))); + // 字段级控件尺寸(宽度 / 高度 / 选项间距):'' / null / undefined = 未设置,沿用全局(宽度默认占满 100%) + // clamp 与后端 fieldSizeStyleMixin 一致(width 0..750 / height 0..400 / gap 0..200 rpx) + const sizeRpx = (x, min, max) => { + if (x === undefined || x === null || x === '') return null; + const n = parseFloat(x); + return isNaN(n) ? null : this.$util.rpx(Math.max(min, Math.min(max, n))); + }; this.formData.forEach((item) => { const itemValue = (item && item.value) || {}; + // ---- 字段级控件尺寸 ---- + const cW = sizeRpx(itemValue.field_width, 0, 750); + const cH = sizeRpx(itemValue.field_height, 0, 400); + const oG = sizeRpx(itemValue.option_gap, 0, 200); + // 宽度:.box 基础规则是 flex:1,需 flex:none 解除伸缩,否则 inline width 不生效 + const ctrlWidthStyle = cW !== null ? { width: cW, 'flex': 'none', 'max-width': '100%' } : {}; + // 高度:单行控件(input / picker .uni-input)的 height 与 line-height 均由 --input-height 驱动, + // 在 .box 上覆盖该 CSS 变量即可同时命中 H5(::v-deep input)与小程序的原生元素规则 + const ctrlHeightStyle = cH !== null ? { '--input-height': cH } : {}; + const ctrlBoxStyle = Object.assign({}, ctrlWidthStyle, ctrlHeightStyle); + // ---- 字段级间距(每个组件独立):外边距直出(允许负值上移贴近相邻组件)---- // clamp 与后端 fieldSpacingStyle 一致(margin -100..400 / padding 0..400 rpx) const mTop = spNum(itemValue.margin_top), mBottom = spNum(itemValue.margin_bottom), @@ -638,8 +660,9 @@ export default { this.$set(item, '_labelStyle', style); // item 级别 box 对齐方式(与原 getItemBoxAlignStyle 逻辑一致) + // 并入字段级宽度 / 高度(.box 是 flex:1,width 需配合 flex:none 才生效,见 ctrlWidthStyle) const align = itemValue.input_align; - this.$set(item, '_boxAlignStyle', align ? { 'text-align': align } : {}); + this.$set(item, '_boxAlignStyle', Object.assign(align ? { 'text-align': align } : {}, ctrlBoxStyle)); // 必填星号样式:颜色/字号/间距全部预计算 inline(微信小程序/鸿蒙元服务对 // 嵌套 var() fallback 与 .required-after 类 margin 翻转支持不全,动态值不走 CSS 变量链)。 @@ -674,8 +697,19 @@ export default { optStyle['align-items'] = 'flex-start'; optStyle['gap'] = '20rpx'; } + // 字段级选项间距(option_gap):覆盖默认 gap(wrap 12rpx / vertical 20rpx) + if (oG !== null) optStyle['gap'] = oG; this.$set(item, '_optionLayoutStyle', optStyle); + // 单行 / 多选行控件(Select、Date、Time、City 的 .box 无 _boxAlignStyle 绑定; + // Checkbox / Radio 只需要宽度,高度无意义)单独落 key,供模板直接绑定 + this.$set(item, '_controlBoxStyle', ctrlBoxStyle); + this.$set(item, '_controlWidthStyle', ctrlWidthStyle); + // textarea:字段级高度直出(宽度走 .box 的 _boxAlignStyle;行高沿用 formConfig), + // 同步 min-height 防止被基础规则的 min-height 顶住不缩 + this.$set(item, '_textareaStyle', Object.assign({}, this.textareaBaseStyle, + cH !== null ? { 'height': cH, 'min-height': cH } : {})); + // 信息卡片:容器底色 + 空白判定 + 分割线样式(与后台 design.js 的 // getInfoCardContainerStyle / getInfoCardDividerStyle 对齐;数值单位为 px 直出, // 与编辑器输入单位一致,375 宽屏上与后台 PC 预览视觉一致)