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 预览视觉一致)