form-driver 0.4.24 → 0.4.26

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.
package/es/m3.js CHANGED
@@ -22970,7 +22970,10 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
22970
22970
  if (dom) {
22971
22971
  // @ts-ignore
22972
22972
  var r = dom.querySelector(":nth-child(3)");
22973
- r.innerHTML = "<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
22973
+
22974
+ if (r) {
22975
+ r.innerHTML = "<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
22976
+ }
22974
22977
  }
22975
22978
  }
22976
22979
  }
@@ -23015,7 +23018,7 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23015
23018
  var rangePickerData = this._data2rangePicker((_this$getValue = this.getValue()) != null ? _this$getValue : []);
23016
23019
 
23017
23020
  if (MUtil.phoneLike()) {
23018
- var _this$props$schema$da3, _this$props$schema$da4;
23021
+ var _this$props$schema$da3;
23019
23022
 
23020
23023
  var show = MDateRangeType.toReadableN(assembly, this.props.schema, _Viewer.prototype.getValue.call(this)); // 根据 precision 配置确定移动端 DatePicker 精度(使用扁平化属性 dateRangePrecision)
23021
23024
 
@@ -23060,7 +23063,7 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23060
23063
  visible: this.state.mobileDlg && this.state.mobileStep === 'end',
23061
23064
  precision: mobilePrecision,
23062
23065
  title: // 如果允许"至今"且开始时间不在未来,在标题区域展示"至今"按钮
23063
- !((_this$props$schema$da3 = this.props.schema.dateRange) != null && _this$props$schema$da3.hideTillNow) && !((_this$props$schema$da4 = this.props.schema.dateRange) != null && _this$props$schema$da4.showTime) && !(this.state.mobileStartDate && this.state.mobileStartDate > new Date()) ? jsxs("div", {
23066
+ !((_this$props$schema$da3 = this.props.schema.dateRange) != null && _this$props$schema$da3.hideTillNow) && !(this.state.mobileStartDate && this.state.mobileStartDate > new Date()) ? jsxs("div", {
23064
23067
  style: {
23065
23068
  display: 'flex',
23066
23069
  alignItems: 'center',
@@ -23111,12 +23114,12 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23111
23114
  }, "end_" + mobilePrecision)]
23112
23115
  });
23113
23116
  } else {
23114
- var _this$props$schema$da5, _this$props$schema$da6, _this$props$schema$da7;
23117
+ var _this$props$schema$da4, _this$props$schema$da5, _this$props$schema$da6;
23115
23118
 
23116
23119
  // 根据 precision 配置确定 PC 端 picker 模式和 showTime(使用扁平化属性 dateRangePrecision)
23117
23120
  var precision = this.props.schema.dateRangePrecision;
23118
- var pcShowTime = precision === 'minute' || ((_this$props$schema$da5 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da5.showTime);
23119
- var hideFooter = ((_this$props$schema$da6 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da6.hideTillNow) || pcShowTime; // 动态构建额外属性,避免 showTime 和 picker 同时传入导致类型冲突
23121
+ var pcShowTime = precision === 'minute' || ((_this$props$schema$da4 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da4.showTime);
23122
+ var hideFooter = (_this$props$schema$da5 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da5.hideTillNow; // 动态构建额外属性,避免 showTime 和 picker 同时传入导致类型冲突
23120
23123
 
23121
23124
  var extraProps = {};
23122
23125
 
@@ -23133,18 +23136,94 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23133
23136
  if (precision === 'minute') {
23134
23137
  extraProps.format = 'YYYY-MM-DD HH:mm';
23135
23138
  }
23136
- } // 构造元素
23139
+ } // "至今"按钮的点击处理函数
23140
+
23141
+
23142
+ var handleTillNow = function handleTillNow() {
23143
+ var _this2$_onCalendarCha, _ref, _ref2;
23144
+
23145
+ // 优先级:onCalendarChange 记录的值 > 面板点击捕获的日期 > 已有默认值 > 当前时间
23146
+ var fromCalendarChange = (_this2$_onCalendarCha = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha[0];
23147
+ var fromPanelClick = _this2._panelClickedDate;
23148
+ var startMoment = (_ref = (_ref2 = fromCalendarChange != null ? fromCalendarChange : fromPanelClick) != null ? _ref2 : rangePickerData == null ? void 0 : rangePickerData[0]) != null ? _ref : moment(); // 如果开始时间来自面板点击(只有日期没有时间),将当前时刻的时分附加上去
23149
+
23150
+ if (!fromCalendarChange && fromPanelClick) {
23151
+ var now = moment();
23152
+ startMoment = startMoment.clone().hour(now.hour()).minute(now.minute()).second(0);
23153
+ }
23154
+
23155
+ _Viewer.prototype.changeValueEx.call(_this2, _this2._rangePicker2Data([startMoment, moment()], true), true, true);
23156
+ }; // 判断是否应展示"至今"按钮
23157
+
23137
23158
 
23159
+ var showTillNow = !hideFooter; // 构造元素
23138
23160
 
23139
23161
  return jsx(DatePicker$1.RangePicker, _objectSpread$8({
23140
23162
  ref: this._pickerRef,
23141
- renderExtraFooter: hideFooter ? undefined : function (mode) {
23142
- var _this2$_onCalendarCha;
23163
+ panelRender: pcShowTime && showTillNow ? function (panelNode) {
23164
+ // showTime 模式下:通过事件委托捕获面板上日期单元格的点击
23165
+ // 同时在 footer 的"确定"按钮同一行注入"至今"按钮
23166
+ return jsx("div", {
23167
+ onClick: function onClick(e) {
23168
+ var target = e.target;
23169
+ var cell = target.closest == null ? void 0 : target.closest('.ant-picker-cell');
23170
+
23171
+ if (cell) {
23172
+ // 排除 disabled 状态的日期单元格
23173
+ if (cell.classList.contains('ant-picker-cell-disabled')) return;
23174
+ var title = cell.getAttribute('title');
23175
+
23176
+ if (title) {
23177
+ var parsed = moment(title, 'YYYY-MM-DD'); // 校验 moment 解析有效性,无效日期不记录
23178
+
23179
+ if (parsed.isValid()) {
23180
+ _this2._panelClickedDate = parsed;
23181
+ }
23182
+ }
23183
+ }
23184
+ },
23185
+ ref: function ref(el) {
23186
+ var _ref3, _this2$_onCalendarCha2, _this2$_onCalendarCha3;
23143
23187
 
23144
- // 如果开始时间超过当前时间(未来时间),不展示"至今"按钮
23145
- var startMoment = (_this2$_onCalendarCha = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha[0];
23188
+ // 面板渲染后,将"至今"按钮注入到 .ant-picker-ok 内部,确定按钮之后
23189
+ // 这样两者在同一个 flex item 中,确定在左、至今在右
23190
+ if (!el) return;
23191
+ var okLi = el.querySelector('.ant-picker-ok');
23192
+ if (!okLi) return; // 开始时间在未来时,移除已有的至今按钮并不再注入
23146
23193
 
23147
- if (startMoment && startMoment.isAfter(moment())) {
23194
+ var previewStart = (_ref3 = (_this2$_onCalendarCha2 = (_this2$_onCalendarCha3 = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha3[0]) != null ? _this2$_onCalendarCha2 : _this2._panelClickedDate) != null ? _ref3 : rangePickerData == null ? void 0 : rangePickerData[0];
23195
+
23196
+ if (previewStart && previewStart.isAfter(moment())) {
23197
+ var existingBtn = okLi.querySelector('.till-now-btn');
23198
+ if (existingBtn) existingBtn.remove();
23199
+ return;
23200
+ }
23201
+
23202
+ if (!okLi.querySelector('.till-now-btn')) {
23203
+ var tillNowBtn = document.createElement('button');
23204
+ tillNowBtn.className = 'ant-btn ant-btn-sm till-now-btn';
23205
+ tillNowBtn.textContent = '至今';
23206
+ tillNowBtn.style.cssText = 'margin-left: 8px;'; // 使用具名函数以便于清理;先移除可能的旧监听再添加,防止重复绑定
23207
+
23208
+ var onTillNowClick = function onTillNowClick(e) {
23209
+ e.stopPropagation();
23210
+ handleTillNow();
23211
+ };
23212
+
23213
+ tillNowBtn.addEventListener('click', onTillNowClick);
23214
+ okLi.appendChild(tillNowBtn);
23215
+ }
23216
+ },
23217
+ children: panelNode
23218
+ });
23219
+ } : undefined,
23220
+ renderExtraFooter: !pcShowTime && showTillNow ? function (mode) {
23221
+ var _this2$_onCalendarCha4, _this2$_onCalendarCha5;
23222
+
23223
+ // 非 showTime 模式:使用 renderExtraFooter 展示"至今"按钮
23224
+ var previewStart = (_this2$_onCalendarCha4 = (_this2$_onCalendarCha5 = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha5[0]) != null ? _this2$_onCalendarCha4 : rangePickerData == null ? void 0 : rangePickerData[0];
23225
+
23226
+ if (previewStart && previewStart.isAfter(moment())) {
23148
23227
  return null;
23149
23228
  }
23150
23229
 
@@ -23159,13 +23238,11 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23159
23238
  display: "inline-block",
23160
23239
  marginTop: "5px"
23161
23240
  },
23162
- onClick: function onClick() {
23163
- _Viewer.prototype.changeValueEx.call(_this2, _this2._rangePicker2Data(_this2._onCalendarChangeValue, true), true, true);
23164
- },
23241
+ onClick: handleTillNow,
23165
23242
  children: "\u81F3\u4ECA"
23166
23243
  })
23167
23244
  });
23168
- },
23245
+ } : undefined,
23169
23246
  bordered: this.props.hideBorder ? false : true,
23170
23247
  style: {
23171
23248
  width: "300px"
@@ -23173,7 +23250,14 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23173
23250
  locale: zhCN$1,
23174
23251
  defaultValue: rangePickerData,
23175
23252
  onCalendarChange: function onCalendarChange(d) {
23176
- _this2._onCalendarChangeValue = d;
23253
+ _this2._onCalendarChangeValue = d; // 用户开始新一轮选择时清理面板点击缓存,避免上一轮过时数据污染
23254
+
23255
+ _this2._panelClickedDate = null;
23256
+ },
23257
+ onOpenChange: function onOpenChange(open) {
23258
+ if (!open) {
23259
+ _this2._panelClickedDate = null;
23260
+ }
23177
23261
  },
23178
23262
  onChange: function onChange(vv) {
23179
23263
  // 用户清空日期范围时,直接置空
@@ -23191,7 +23275,7 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23191
23275
 
23192
23276
  _Viewer.prototype.changeValueEx.call(_this2, _this2._rangePicker2Data(vv, newTillNow), true, true);
23193
23277
  }
23194
- }, extraProps), this.state.ctrlVersion + "_" + ((_this$props$schema$da7 = this.props.schema.dateRangePrecision) != null ? _this$props$schema$da7 : 'day'));
23278
+ }, extraProps), this.state.ctrlVersion + "_" + ((_this$props$schema$da6 = this.props.schema.dateRangePrecision) != null ? _this$props$schema$da6 : 'day'));
23195
23279
  }
23196
23280
  };
23197
23281
 
package/lib/m3.js CHANGED
@@ -22995,7 +22995,10 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
22995
22995
  if (dom) {
22996
22996
  // @ts-ignore
22997
22997
  var r = dom.querySelector(":nth-child(3)");
22998
- r.innerHTML = "<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
22998
+
22999
+ if (r) {
23000
+ r.innerHTML = "<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
23001
+ }
22999
23002
  }
23000
23003
  }
23001
23004
  }
@@ -23040,7 +23043,7 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23040
23043
  var rangePickerData = this._data2rangePicker((_this$getValue = this.getValue()) != null ? _this$getValue : []);
23041
23044
 
23042
23045
  if (MUtil.phoneLike()) {
23043
- var _this$props$schema$da3, _this$props$schema$da4;
23046
+ var _this$props$schema$da3;
23044
23047
 
23045
23048
  var show = MDateRangeType.toReadableN(assembly, this.props.schema, _Viewer.prototype.getValue.call(this)); // 根据 precision 配置确定移动端 DatePicker 精度(使用扁平化属性 dateRangePrecision)
23046
23049
 
@@ -23085,7 +23088,7 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23085
23088
  visible: this.state.mobileDlg && this.state.mobileStep === 'end',
23086
23089
  precision: mobilePrecision,
23087
23090
  title: // 如果允许"至今"且开始时间不在未来,在标题区域展示"至今"按钮
23088
- !((_this$props$schema$da3 = this.props.schema.dateRange) != null && _this$props$schema$da3.hideTillNow) && !((_this$props$schema$da4 = this.props.schema.dateRange) != null && _this$props$schema$da4.showTime) && !(this.state.mobileStartDate && this.state.mobileStartDate > new Date()) ? jsxRuntime.jsxs("div", {
23091
+ !((_this$props$schema$da3 = this.props.schema.dateRange) != null && _this$props$schema$da3.hideTillNow) && !(this.state.mobileStartDate && this.state.mobileStartDate > new Date()) ? jsxRuntime.jsxs("div", {
23089
23092
  style: {
23090
23093
  display: 'flex',
23091
23094
  alignItems: 'center',
@@ -23136,12 +23139,12 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23136
23139
  }, "end_" + mobilePrecision)]
23137
23140
  });
23138
23141
  } else {
23139
- var _this$props$schema$da5, _this$props$schema$da6, _this$props$schema$da7;
23142
+ var _this$props$schema$da4, _this$props$schema$da5, _this$props$schema$da6;
23140
23143
 
23141
23144
  // 根据 precision 配置确定 PC 端 picker 模式和 showTime(使用扁平化属性 dateRangePrecision)
23142
23145
  var precision = this.props.schema.dateRangePrecision;
23143
- var pcShowTime = precision === 'minute' || ((_this$props$schema$da5 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da5.showTime);
23144
- var hideFooter = ((_this$props$schema$da6 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da6.hideTillNow) || pcShowTime; // 动态构建额外属性,避免 showTime 和 picker 同时传入导致类型冲突
23146
+ var pcShowTime = precision === 'minute' || ((_this$props$schema$da4 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da4.showTime);
23147
+ var hideFooter = (_this$props$schema$da5 = this.props.schema.dateRange) == null ? void 0 : _this$props$schema$da5.hideTillNow; // 动态构建额外属性,避免 showTime 和 picker 同时传入导致类型冲突
23145
23148
 
23146
23149
  var extraProps = {};
23147
23150
 
@@ -23158,18 +23161,94 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23158
23161
  if (precision === 'minute') {
23159
23162
  extraProps.format = 'YYYY-MM-DD HH:mm';
23160
23163
  }
23161
- } // 构造元素
23164
+ } // "至今"按钮的点击处理函数
23165
+
23166
+
23167
+ var handleTillNow = function handleTillNow() {
23168
+ var _this2$_onCalendarCha, _ref, _ref2;
23169
+
23170
+ // 优先级:onCalendarChange 记录的值 > 面板点击捕获的日期 > 已有默认值 > 当前时间
23171
+ var fromCalendarChange = (_this2$_onCalendarCha = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha[0];
23172
+ var fromPanelClick = _this2._panelClickedDate;
23173
+ var startMoment = (_ref = (_ref2 = fromCalendarChange != null ? fromCalendarChange : fromPanelClick) != null ? _ref2 : rangePickerData == null ? void 0 : rangePickerData[0]) != null ? _ref : moment__default["default"](); // 如果开始时间来自面板点击(只有日期没有时间),将当前时刻的时分附加上去
23174
+
23175
+ if (!fromCalendarChange && fromPanelClick) {
23176
+ var now = moment__default["default"]();
23177
+ startMoment = startMoment.clone().hour(now.hour()).minute(now.minute()).second(0);
23178
+ }
23179
+
23180
+ _Viewer.prototype.changeValueEx.call(_this2, _this2._rangePicker2Data([startMoment, moment__default["default"]()], true), true, true);
23181
+ }; // 判断是否应展示"至今"按钮
23182
+
23162
23183
 
23184
+ var showTillNow = !hideFooter; // 构造元素
23163
23185
 
23164
23186
  return jsxRuntime.jsx(antd.DatePicker.RangePicker, _objectSpread$8({
23165
23187
  ref: this._pickerRef,
23166
- renderExtraFooter: hideFooter ? undefined : function (mode) {
23167
- var _this2$_onCalendarCha;
23188
+ panelRender: pcShowTime && showTillNow ? function (panelNode) {
23189
+ // showTime 模式下:通过事件委托捕获面板上日期单元格的点击
23190
+ // 同时在 footer 的"确定"按钮同一行注入"至今"按钮
23191
+ return jsxRuntime.jsx("div", {
23192
+ onClick: function onClick(e) {
23193
+ var target = e.target;
23194
+ var cell = target.closest == null ? void 0 : target.closest('.ant-picker-cell');
23195
+
23196
+ if (cell) {
23197
+ // 排除 disabled 状态的日期单元格
23198
+ if (cell.classList.contains('ant-picker-cell-disabled')) return;
23199
+ var title = cell.getAttribute('title');
23200
+
23201
+ if (title) {
23202
+ var parsed = moment__default["default"](title, 'YYYY-MM-DD'); // 校验 moment 解析有效性,无效日期不记录
23203
+
23204
+ if (parsed.isValid()) {
23205
+ _this2._panelClickedDate = parsed;
23206
+ }
23207
+ }
23208
+ }
23209
+ },
23210
+ ref: function ref(el) {
23211
+ var _ref3, _this2$_onCalendarCha2, _this2$_onCalendarCha3;
23168
23212
 
23169
- // 如果开始时间超过当前时间(未来时间),不展示"至今"按钮
23170
- var startMoment = (_this2$_onCalendarCha = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha[0];
23213
+ // 面板渲染后,将"至今"按钮注入到 .ant-picker-ok 内部,确定按钮之后
23214
+ // 这样两者在同一个 flex item 中,确定在左、至今在右
23215
+ if (!el) return;
23216
+ var okLi = el.querySelector('.ant-picker-ok');
23217
+ if (!okLi) return; // 开始时间在未来时,移除已有的至今按钮并不再注入
23171
23218
 
23172
- if (startMoment && startMoment.isAfter(moment__default["default"]())) {
23219
+ var previewStart = (_ref3 = (_this2$_onCalendarCha2 = (_this2$_onCalendarCha3 = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha3[0]) != null ? _this2$_onCalendarCha2 : _this2._panelClickedDate) != null ? _ref3 : rangePickerData == null ? void 0 : rangePickerData[0];
23220
+
23221
+ if (previewStart && previewStart.isAfter(moment__default["default"]())) {
23222
+ var existingBtn = okLi.querySelector('.till-now-btn');
23223
+ if (existingBtn) existingBtn.remove();
23224
+ return;
23225
+ }
23226
+
23227
+ if (!okLi.querySelector('.till-now-btn')) {
23228
+ var tillNowBtn = document.createElement('button');
23229
+ tillNowBtn.className = 'ant-btn ant-btn-sm till-now-btn';
23230
+ tillNowBtn.textContent = '至今';
23231
+ tillNowBtn.style.cssText = 'margin-left: 8px;'; // 使用具名函数以便于清理;先移除可能的旧监听再添加,防止重复绑定
23232
+
23233
+ var onTillNowClick = function onTillNowClick(e) {
23234
+ e.stopPropagation();
23235
+ handleTillNow();
23236
+ };
23237
+
23238
+ tillNowBtn.addEventListener('click', onTillNowClick);
23239
+ okLi.appendChild(tillNowBtn);
23240
+ }
23241
+ },
23242
+ children: panelNode
23243
+ });
23244
+ } : undefined,
23245
+ renderExtraFooter: !pcShowTime && showTillNow ? function (mode) {
23246
+ var _this2$_onCalendarCha4, _this2$_onCalendarCha5;
23247
+
23248
+ // 非 showTime 模式:使用 renderExtraFooter 展示"至今"按钮
23249
+ var previewStart = (_this2$_onCalendarCha4 = (_this2$_onCalendarCha5 = _this2._onCalendarChangeValue) == null ? void 0 : _this2$_onCalendarCha5[0]) != null ? _this2$_onCalendarCha4 : rangePickerData == null ? void 0 : rangePickerData[0];
23250
+
23251
+ if (previewStart && previewStart.isAfter(moment__default["default"]())) {
23173
23252
  return null;
23174
23253
  }
23175
23254
 
@@ -23184,13 +23263,11 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23184
23263
  display: "inline-block",
23185
23264
  marginTop: "5px"
23186
23265
  },
23187
- onClick: function onClick() {
23188
- _Viewer.prototype.changeValueEx.call(_this2, _this2._rangePicker2Data(_this2._onCalendarChangeValue, true), true, true);
23189
- },
23266
+ onClick: handleTillNow,
23190
23267
  children: "\u81F3\u4ECA"
23191
23268
  })
23192
23269
  });
23193
- },
23270
+ } : undefined,
23194
23271
  bordered: this.props.hideBorder ? false : true,
23195
23272
  style: {
23196
23273
  width: "300px"
@@ -23198,7 +23275,14 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23198
23275
  locale: zhCN__default$1["default"],
23199
23276
  defaultValue: rangePickerData,
23200
23277
  onCalendarChange: function onCalendarChange(d) {
23201
- _this2._onCalendarChangeValue = d;
23278
+ _this2._onCalendarChangeValue = d; // 用户开始新一轮选择时清理面板点击缓存,避免上一轮过时数据污染
23279
+
23280
+ _this2._panelClickedDate = null;
23281
+ },
23282
+ onOpenChange: function onOpenChange(open) {
23283
+ if (!open) {
23284
+ _this2._panelClickedDate = null;
23285
+ }
23202
23286
  },
23203
23287
  onChange: function onChange(vv) {
23204
23288
  // 用户清空日期范围时,直接置空
@@ -23216,7 +23300,7 @@ var ARangePicker = /*#__PURE__*/function (_Viewer) {
23216
23300
 
23217
23301
  _Viewer.prototype.changeValueEx.call(_this2, _this2._rangePicker2Data(vv, newTillNow), true, true);
23218
23302
  }
23219
- }, extraProps), this.state.ctrlVersion + "_" + ((_this$props$schema$da7 = this.props.schema.dateRangePrecision) != null ? _this$props$schema$da7 : 'day'));
23303
+ }, extraProps), this.state.ctrlVersion + "_" + ((_this$props$schema$da6 = this.props.schema.dateRangePrecision) != null ? _this$props$schema$da6 : 'day'));
23220
23304
  }
23221
23305
  };
23222
23306
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-driver",
3
- "version": "0.4.24",
3
+ "version": "0.4.26",
4
4
  "description": "An efficient framework for creating forms.",
5
5
  "license": "MIT",
6
6
  "authors": [
@@ -63,7 +63,7 @@
63
63
  "@dnd-kit/utilities": "^3.2.2",
64
64
  "@babel/runtime": "^7.9.2",
65
65
  "ali-oss": "^6.17.1",
66
- "antd": "4.18.7",
66
+ "antd": "^4.18.7",
67
67
  "antd-mobile": "^5.37.1",
68
68
  "clsx": "^2.1.1",
69
69
  "lodash": "^4.17.20",
@@ -33,6 +33,7 @@ interface State extends ViewerState {
33
33
  export class ARangePicker extends Viewer<State> {
34
34
  _pickerRef: RefObject<any> = React.createRef();
35
35
  _onCalendarChangeValue?: AntData | null;
36
+ _panelClickedDate?: moment.Moment | null; // showTime 模式下通过面板点击事件捕获的日期
36
37
  _startConfirmed = false; // 标记开始日期是否已确认,用于区分 onClose 是取消还是确认后的自动触发
37
38
 
38
39
  constructor(p: MProp) {
@@ -55,7 +56,9 @@ export class ARangePicker extends Viewer<State> {
55
56
  if (dom) {
56
57
  // @ts-ignore
57
58
  let r = dom.querySelector(":nth-child(3)");
58
- r.innerHTML = "<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
59
+ if (r) {
60
+ r.innerHTML = "<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
61
+ }
59
62
  }
60
63
  }
61
64
  }
@@ -123,7 +126,6 @@ export class ARangePicker extends Viewer<State> {
123
126
  title={
124
127
  // 如果允许"至今"且开始时间不在未来,在标题区域展示"至今"按钮
125
128
  !this.props.schema.dateRange?.hideTillNow
126
- && !this.props.schema.dateRange?.showTime
127
129
  && !(this.state.mobileStartDate && this.state.mobileStartDate > new Date())
128
130
  ? <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 12 }}>
129
131
  <span>选择结束日期</span>
@@ -165,7 +167,7 @@ export class ARangePicker extends Viewer<State> {
165
167
  // 根据 precision 配置确定 PC 端 picker 模式和 showTime(使用扁平化属性 dateRangePrecision)
166
168
  const precision = this.props.schema.dateRangePrecision;
167
169
  const pcShowTime = precision === 'minute' || this.props.schema.dateRange?.showTime;
168
- const hideFooter = this.props.schema.dateRange?.hideTillNow || pcShowTime;
170
+ const hideFooter = this.props.schema.dateRange?.hideTillNow;
169
171
 
170
172
  // 动态构建额外属性,避免 showTime 和 picker 同时传入导致类型冲突
171
173
  const extraProps: any = {};
@@ -182,26 +184,100 @@ export class ARangePicker extends Viewer<State> {
182
184
  }
183
185
  }
184
186
 
187
+ // "至今"按钮的点击处理函数
188
+ const handleTillNow = () => {
189
+ // 优先级:onCalendarChange 记录的值 > 面板点击捕获的日期 > 已有默认值 > 当前时间
190
+ const fromCalendarChange = this._onCalendarChangeValue?.[0];
191
+ const fromPanelClick = this._panelClickedDate;
192
+ let startMoment = fromCalendarChange ?? fromPanelClick ?? rangePickerData?.[0] ?? moment();
193
+
194
+ // 如果开始时间来自面板点击(只有日期没有时间),将当前时刻的时分附加上去
195
+ if (!fromCalendarChange && fromPanelClick) {
196
+ const now = moment();
197
+ startMoment = startMoment.clone().hour(now.hour()).minute(now.minute()).second(0);
198
+ }
199
+
200
+ super.changeValueEx(
201
+ this._rangePicker2Data([startMoment, moment()], true),
202
+ true, true
203
+ );
204
+ };
205
+
206
+ // 判断是否应展示"至今"按钮
207
+ const showTillNow = !hideFooter;
208
+
185
209
  // 构造元素
186
210
  return <DatePicker.RangePicker
187
211
  ref={this._pickerRef}
188
212
  key={`${this.state.ctrlVersion}_${this.props.schema.dateRangePrecision ?? 'day'}`}
189
- renderExtraFooter={hideFooter
190
- ? undefined
191
- : (mode) => {
192
- // 如果开始时间超过当前时间(未来时间),不展示"至今"按钮
193
- const startMoment = this._onCalendarChangeValue?.[0];
194
- if (startMoment && startMoment.isAfter(moment())) {
213
+ panelRender={pcShowTime && showTillNow
214
+ ? (panelNode) => {
215
+ // showTime 模式下:通过事件委托捕获面板上日期单元格的点击
216
+ // 同时在 footer 的"确定"按钮同一行注入"至今"按钮
217
+ return <div onClick={(e) => {
218
+ const target = e.target as HTMLElement;
219
+ const cell = target.closest?.('.ant-picker-cell');
220
+ if (cell) {
221
+ // 排除 disabled 状态的日期单元格
222
+ if (cell.classList.contains('ant-picker-cell-disabled')) return;
223
+ const title = cell.getAttribute('title');
224
+ if (title) {
225
+ const parsed = moment(title, 'YYYY-MM-DD');
226
+ // 校验 moment 解析有效性,无效日期不记录
227
+ if (parsed.isValid()) {
228
+ this._panelClickedDate = parsed;
229
+ }
230
+ }
231
+ }
232
+ }}
233
+ ref={(el) => {
234
+ // 面板渲染后,将"至今"按钮注入到 .ant-picker-ok 内部,确定按钮之后
235
+ // 这样两者在同一个 flex item 中,确定在左、至今在右
236
+ if (!el) return;
237
+ const okLi = el.querySelector('.ant-picker-ok');
238
+ if (!okLi) return;
239
+
240
+ // 开始时间在未来时,移除已有的至今按钮并不再注入
241
+ const previewStart = this._onCalendarChangeValue?.[0] ?? this._panelClickedDate ?? rangePickerData?.[0];
242
+ if (previewStart && previewStart.isAfter(moment())) {
243
+ const existingBtn = okLi.querySelector('.till-now-btn');
244
+ if (existingBtn) existingBtn.remove();
245
+ return;
246
+ }
247
+
248
+ if (!okLi.querySelector('.till-now-btn')) {
249
+ const tillNowBtn = document.createElement('button');
250
+ tillNowBtn.className = 'ant-btn ant-btn-sm till-now-btn';
251
+ tillNowBtn.textContent = '至今';
252
+ tillNowBtn.style.cssText = 'margin-left: 8px;';
253
+ // 使用具名函数以便于清理;先移除可能的旧监听再添加,防止重复绑定
254
+ const onTillNowClick = (e: Event) => {
255
+ e.stopPropagation();
256
+ handleTillNow();
257
+ };
258
+ tillNowBtn.addEventListener('click', onTillNowClick);
259
+ okLi.appendChild(tillNowBtn);
260
+ }
261
+ }}>
262
+ {panelNode}
263
+ </div>;
264
+ }
265
+ : undefined
266
+ }
267
+ renderExtraFooter={!pcShowTime && showTillNow
268
+ ? (mode) => {
269
+ // 非 showTime 模式:使用 renderExtraFooter 展示"至今"按钮
270
+ const previewStart = this._onCalendarChangeValue?.[0] ?? rangePickerData?.[0];
271
+ if (previewStart && previewStart.isAfter(moment())) {
195
272
  return null;
196
273
  }
197
274
  return <div style={{ textAlign: "right" }}>
198
275
  <AntButton
199
276
  size="small" style={{ width: "100px", display: "inline-block", marginTop: "5px" }}
200
- onClick={() => {
201
- super.changeValueEx(this._rangePicker2Data(this._onCalendarChangeValue, true), true, true);
202
- }}>至今</AntButton>
277
+ onClick={handleTillNow}>至今</AntButton>
203
278
  </div>;
204
279
  }
280
+ : undefined
205
281
  }
206
282
  bordered={this.props.hideBorder ? false : true}
207
283
  style={{ width: "300px" }}
@@ -209,6 +285,13 @@ export class ARangePicker extends Viewer<State> {
209
285
  defaultValue={rangePickerData}
210
286
  onCalendarChange={(d) => {
211
287
  this._onCalendarChangeValue = d;
288
+ // 用户开始新一轮选择时清理面板点击缓存,避免上一轮过时数据污染
289
+ this._panelClickedDate = null;
290
+ }}
291
+ onOpenChange={(open) => {
292
+ if (!open) {
293
+ this._panelClickedDate = null;
294
+ }
212
295
  }}
213
296
  onChange={(vv) => {
214
297
  // 用户清空日期范围时,直接置空
@@ -2,12 +2,13 @@
2
2
 
3
3
  import { Select } from "antd";
4
4
  import { Picker } from "antd-mobile";
5
+ import type { PickerColumnItem, PickerValue } from "antd-mobile/es/components/picker-view";
5
6
  import _ from "lodash";
6
7
  import React from "react";
7
8
  import { MUtil } from '../../framework/MUtil';
8
9
 
9
- interface PickerOption {
10
- label: string | React.ReactNode;
10
+ interface PickerOption extends PickerColumnItem {
11
+ label: React.ReactNode;
11
12
  value: string;
12
13
  }
13
14
 
@@ -16,6 +16,7 @@ interface State extends ViewerState {
16
16
  export declare class ARangePicker extends Viewer<State> {
17
17
  _pickerRef: RefObject<any>;
18
18
  _onCalendarChangeValue?: AntData | null;
19
+ _panelClickedDate?: moment.Moment | null;
19
20
  _startConfirmed: boolean;
20
21
  constructor(p: MProp);
21
22
  componentDidUpdate(): void;
@@ -1,6 +1,7 @@
1
+ import type { PickerColumnItem } from "antd-mobile/es/components/picker-view";
1
2
  import React from "react";
2
- interface PickerOption {
3
- label: string | React.ReactNode;
3
+ interface PickerOption extends PickerColumnItem {
4
+ label: React.ReactNode;
4
5
  value: string;
5
6
  }
6
7
  interface Prop {