@cloudbase/weda-ui-mp 3.30.0 → 3.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@
4
4
  "usingComponents": {
5
5
  "mp-cells": "weui-miniprogram/cells/cells",
6
6
  "mp-cell": "weui-miniprogram/cell/cell",
7
- "mp-actionSheet": "weui-miniprogram/actionsheet/actionsheet"
7
+ "mp-actionSheet": "weui-miniprogram/actionsheet/actionsheet",
8
+ "wd-button": "../../wd-button/index"
8
9
  }
9
10
  }
@@ -6,8 +6,7 @@
6
6
  {{label}}
7
7
  </view>
8
8
  <view class="weda-uploader-files__btn-contain">
9
- <button class="weui-btn weda-uploader-files__btn" bindtap="onButtonTap" disabled="{{disabled}}">{{uploadButtonText}}</button>
10
-
9
+ <wd-button size="sm" disabled="{{disabled}}" variant="outline" text="{{uploadButtonText}}" bindtap="onButtonTap"> </wd-button>
11
10
  <view wx:if="{{maxCount!=1}}" class="weda-uploader-files__tips">{{uploadTipText}}</view>
12
11
  <view wx:else>
13
12
  <slot name="tips"></slot>
@@ -41,6 +41,12 @@ Component({
41
41
  value: true,
42
42
  type: Boolean,
43
43
  },
44
+ // 新增统一字段:circularEnabled 一旦显式有值(true/false),优先级高于历史 circular 字段。
45
+ // 仅当用户在编辑器主动开启/关闭时才有值;缺省时(null)保持旧 circular 字段语义。
46
+ circularEnabled: {
47
+ type: null,
48
+ value: null,
49
+ },
44
50
  vertical: {
45
51
  value: false,
46
52
  type: Boolean,
@@ -82,4 +88,13 @@ Component({
82
88
  },
83
89
  ]),
84
90
  },
91
+ observers: {
92
+ // 当 circularEnabled 显式设置时(非 null/undefined),用其值覆盖 circular,
93
+ // 让 wxml 中的 circular="{{circular}}" 直接反映新字段语义,无需改动模板。
94
+ circularEnabled: function (circularEnabled) {
95
+ if (circularEnabled === null || circularEnabled === undefined) return;
96
+ if (this.data.circular === circularEnabled) return;
97
+ this.setData({ circular: circularEnabled });
98
+ },
99
+ },
85
100
  });
@@ -1,4 +1,5 @@
1
1
  import { WdCompError } from '../../utils/error';
2
+ import { convertDayjs } from '../../utils/getFormLegacy.js';
2
3
 
3
4
  // father-son 是老的,新的叫many-one
4
5
  const SINGLE_SELECT_FORMATS = [
@@ -14,22 +15,86 @@ const SINGLE_SELECT_FORMATS = [
14
15
 
15
16
  const MULTI_SELECT_FORMATS = ['many-many', 'one-many'];
16
17
 
18
+ // 判断关联关系字段是否有有效值(排除 null, undefined, '', {}, [])
19
+ function isValidRelationValue(value) {
20
+ if (value === null || value === undefined || value === '') {
21
+ return false;
22
+ }
23
+ // 排除空对象 {}
24
+ if (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
25
+ return false;
26
+ }
27
+ // 排除空数组 []
28
+ if (Array.isArray(value) && value.length === 0) {
29
+ return false;
30
+ }
31
+ return true;
32
+ }
33
+
34
+ // 单选关联字段值规范化:对象提取 _id,空对象置 undefined,原始值(字符串/null)透传
35
+ // 用于 father-son / related / many-one / one-one / one-one-r
36
+ function normalizeSingleRelationValue(v, fallback) {
37
+ if (v && typeof v === 'object' && !Array.isArray(v)) {
38
+ return isValidRelationValue(v) ? v._id : undefined;
39
+ }
40
+ // 字符串/null/undefined 等原始值,透传 fallback(即原始字段值)
41
+ return fallback;
42
+ }
43
+
44
+ // 多选关联字段值规范化:过滤无效项后提取每个 _id,空结果置 undefined
45
+ // 用于 one-many / many-many
46
+ function normalizeMultiRelationValue(v) {
47
+ if (Array.isArray(v)) {
48
+ const ids = v
49
+ .map((item) => (isValidRelationValue(item) ? item?.['_id'] : undefined))
50
+ .filter((id) => id !== undefined && id !== null && id !== '');
51
+ return ids.length > 0 ? ids : undefined;
52
+ }
53
+ if (!isValidRelationValue(v)) {
54
+ return undefined;
55
+ }
56
+ return v;
57
+ }
58
+
59
+ // 日期字段格式化:将后端 $date 对象 / 'date'/'datetime' format 转为时间戳
60
+ function normalizeDateValue(fieldValue, format, type) {
61
+ if (type !== 'number') return undefined;
62
+ if (fieldValue && Object.prototype.hasOwnProperty.call(fieldValue, '$date')) {
63
+ return convertDayjs(fieldValue)?.valueOf() ?? null;
64
+ }
65
+ if (['date', 'datetime'].includes(format)) {
66
+ return convertDayjs(fieldValue)?.valueOf() ?? null;
67
+ }
68
+ return undefined;
69
+ }
70
+
17
71
  export function convertRemoteValueToFormData(dataSourceType, dataSourceProfile, fetchedInitialValues) {
18
- if (dataSourceType === 'experssion') {
72
+ // 修正历史拼写错误 'experssion',但保留兼容
73
+ if (dataSourceType === 'expression' || dataSourceType === 'experssion') {
19
74
  return fetchedInitialValues;
20
75
  }
21
- const result = Object.keys(fetchedInitialValues).reduce((acc, field) => {
76
+ return Object.keys(fetchedInitialValues).reduce((acc, field) => {
22
77
  const format = dataSourceProfile?.schema?.properties?.[field]?.format;
23
- acc[field] = fetchedInitialValues[field];
24
- if ([...SINGLE_SELECT_FORMATS, 'father-son'].includes(format) && fetchedInitialValues[field]['_id']) {
25
- acc[field] = fetchedInitialValues[field]['_id'];
78
+ const type = dataSourceProfile?.schema?.properties?.[field]?.type;
79
+ const fieldValue = fetchedInitialValues[field];
80
+ acc[field] = fieldValue;
81
+
82
+ // 关联关系字段:father-son / related / many-one / one-one / one-one-r
83
+ if (['father-son', 'related', ...SINGLE_SELECT_FORMATS].includes(format)) {
84
+ acc[field] = normalizeSingleRelationValue(fieldValue, fieldValue);
85
+ } else if (MULTI_SELECT_FORMATS.includes(format)) {
86
+ // 多选关联:one-many / many-many
87
+ acc[field] = normalizeMultiRelationValue(fieldValue);
26
88
  }
27
- if (MULTI_SELECT_FORMATS.includes(format)) {
28
- acc[field] = fetchedInitialValues[field].map((item) => item['_id']);
89
+
90
+ // 日期字段:转时间戳(覆盖关联字段处理结果,因为日期字段不会同时是关联字段)
91
+ const dateValue = normalizeDateValue(fieldValue, format, type);
92
+ if (dateValue !== undefined) {
93
+ acc[field] = dateValue;
29
94
  }
95
+
30
96
  return acc;
31
97
  }, {});
32
- return result;
33
98
  }
34
99
 
35
100
  export function convertFormDataToSubmitParams(dataSourceProfile, formData, formType, _id, fields) {
@@ -38,10 +103,12 @@ export function convertFormDataToSubmitParams(dataSourceProfile, formData, formT
38
103
  const format = dataSourceProfile.schema?.properties?.[cur]?.format;
39
104
  acc[cur] = formData[cur];
40
105
  if (SINGLE_SELECT_FORMATS.includes(format)) {
41
- acc[cur] = { _id: formData[cur] };
106
+ // 空值(null/undefined/''/{})时不转换,保持 null,避免提交 { _id: null } 或 { _id: {} }
107
+ acc[cur] = isValidRelationValue(formData[cur]) ? { _id: formData[cur] } : null;
42
108
  }
43
109
  if (MULTI_SELECT_FORMATS.includes(format)) {
44
- acc[cur] = acc[cur]?.map((_id) => ({ _id }));
110
+ // 空值时返回 null,有值时转换为 [{ _id: 'xxx' }] 格式
111
+ acc[cur] = isValidRelationValue(formData[cur]) ? formData[cur].map((_id) => ({ _id })) : null;
45
112
  }
46
113
  if ('x-json' === format && typeof formData[cur] === 'string') {
47
114
  try {
@@ -105,6 +105,10 @@ Component({
105
105
  },
106
106
  min: {},
107
107
  max: {},
108
+ inputValue: {
109
+ type: Number,
110
+ value: null,
111
+ },
108
112
  },
109
113
  data: {
110
114
  isInit: true,
@@ -181,21 +185,20 @@ Component({
181
185
  const toReal = getRealValue({ value: toShow, format });
182
186
  const detail = { ...e.detail, value: toReal };
183
187
 
184
- if (needSetData) {
185
- this.changeForm(detail);
186
- this.triggerEvent('change', detail);
187
- } else {
188
- this.triggerEvent('input', detail);
189
- }
190
-
191
188
  const upDownState = this.getStepDisabled(null, toReal);
192
189
 
193
- needSetData &&
190
+ // 先更新 realValue,避免 value 观察者触发时 realValue 还是旧值导致重复处理
191
+ if (needSetData) {
194
192
  this.setData({
195
193
  realValue: toReal,
196
194
  showValue: toShow,
197
195
  ...upDownState,
198
196
  });
197
+ this.changeForm(detail);
198
+ this.triggerEvent('change', detail);
199
+ } else {
200
+ this.triggerEvent('input', detail);
201
+ }
199
202
 
200
203
  return toReal;
201
204
  },
@@ -288,7 +291,7 @@ Component({
288
291
  ...{ ...this.properties, ...props },
289
292
  type: format,
290
293
  });
291
- const toReal = getRealValue({ value: toShow });
294
+ const toReal = getRealValue({ value: toShow, format });
292
295
 
293
296
  const { stepPlusDisabled, stepMinusDisabled } = this.getStepDisabled(
294
297
  { readOnly, disabled, status, max, min, format },
@@ -447,24 +450,17 @@ Component({
447
450
  },
448
451
  // 监听非输入引起的value变化,比如调用 setValue, clearValue
449
452
  value: function (value) {
453
+ if (equal(value, this.data.realValue)) return;
450
454
  const { format } = this.properties;
451
455
 
452
- let toReal = this.data.realValue;
453
- let toShow = this.data.showValue;
456
+ // value 是真实值,不需要做百分比转换,只需要格式化显示
457
+ const toReal = isNumber(value) ? value : null;
454
458
 
455
- if (!this.data.isInit) {
456
- toReal = isNumber(value) ? value : null;
457
- toShow = this.getShowValue({
458
- ...this.properties,
459
- value: `${isNumber(value) ? value : ''}`,
460
- type: format,
461
- });
462
- }
463
-
464
- // 初始化时同步真实值到表单
465
- if (isNumber(toReal) && this.data.isInit) {
466
- this.changeForm({ value: toReal });
467
- }
459
+ const toShow = this.getShowValue({
460
+ ...this.properties,
461
+ value: `${isNumber(value) ? value : ''}`,
462
+ type: format,
463
+ });
468
464
 
469
465
  const readValue = `${toShow}${getPercentUnit(format)}`;
470
466
 
@@ -482,22 +478,6 @@ Component({
482
478
  });
483
479
  }, 0);
484
480
  },
485
- inputValue: function (inputValue) {
486
- if (equal(inputValue, this.data._oldInputValue)) return;
487
- const { toReal, toShow, stepPlusDisabled, stepMinusDisabled, readValue } = this.getRealAndShowData({
488
- value: inputValue,
489
- });
490
-
491
- this.setData({
492
- readValue,
493
- realValue: toReal,
494
- showValue: this.data.readOnly ? readValue : toShow,
495
- stepPlusDisabled,
496
- stepMinusDisabled,
497
- });
498
- this.changeForm({ value: toReal });
499
- this.data._oldInputValue = inputValue;
500
- },
501
481
  },
502
482
  lifetimes: {
503
483
  attached: function () {
@@ -53,4 +53,5 @@
53
53
  readOnly="{{readOnly}}"
54
54
  value="{{value}}"
55
55
  cursorSpacing="{{cursorSpacing}}"
56
+ type="{{type}}"
56
57
  ></inner-input>
@@ -712,6 +712,10 @@
712
712
  align-items: center;
713
713
  }
714
714
 
715
+ .wd-menulayout-menu__list.wedatea2td-list {
716
+ padding: calc(var(--wd-space-base) * 2);
717
+ }
718
+
715
719
  .wd-menulayout-h5__drawer {
716
720
  position: fixed;
717
721
  }
@@ -710,4 +710,8 @@
710
710
  width: 100%;
711
711
  display: flex;
712
712
  align-items: center;
713
+ }
714
+
715
+ .wd-menulayout-menu__list.wedatea2td-list {
716
+ padding: calc(var(--wd-space-base) * 2);
713
717
  }
@@ -299,6 +299,14 @@ Component({
299
299
  if (Array.isArray(values) && Array.isArray(options)) {
300
300
  const rm = arrayToMap(options, 'value');
301
301
  labels = values.map((d) => {
302
+ // 兜底:value 元素可能是关联字段对象({ _id } / {} 空对象等)
303
+ // 对象一律提取 _id 当 key;提取不到说明是空值,直接返回空串避免渲染 [object Object]
304
+ if (d && typeof d === 'object' && !Array.isArray(d)) {
305
+ if (d._id === undefined || d._id === null || d._id === '') {
306
+ return '';
307
+ }
308
+ d = d._id;
309
+ }
302
310
  const obj = rm[d];
303
311
  let item = lodashGet(obj, 'text') ?? lodashGet(obj, 'label') ?? d;
304
312
  return textToString(item);
@@ -1,7 +1,13 @@
1
1
  <wd-form-item-read-only version="{{version}}" readOnly="{{readOnly}}" readValue="{{displayValue}}">
2
2
  <view class="wd-select">
3
3
  <view class="wd-select-input-group" bindchange="onChange" bindtap="onOpenPicker" data-show="true">
4
- <label class="wd-select-input {{displayValue ? '' : 'weui-input__placeholder'}}">{{displayValue || placeholder}}</label>
4
+ <input
5
+ class="wd-select-input"
6
+ placeholder-class="weui-input__placeholder"
7
+ placeholder="{{placeholder}}"
8
+ value="{{displayValue}}"
9
+ disabled="true"
10
+ />
5
11
  </view>
6
12
  <block wx:if="{{allPickerShow}}">
7
13
  <dropdownSelect
@@ -1,6 +1,7 @@
1
1
  /* 标准化样式适配 start */
2
2
  .wd-form-item .wd-form-input-wrap .wd-select {
3
3
  width: 100%;
4
+ height: 100%;
4
5
  }
5
6
  .wd-form-item .wd-form-input-wrap .wd-select .wd-select-input-group {
6
7
  height: 100%;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "miniprogram": "./",
4
4
  "packageManager": "yarn@3.0.2",
5
5
  "dependencies": {},
6
- "version": "3.30.0",
6
+ "version": "3.31.0",
7
7
  "main": "./",
8
8
  "publishConfig": {
9
9
  "access": "public"