form-driver 0.4.26 → 0.4.28
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/dist/m3.css +11 -3
- package/dist/m3.js +1 -1
- package/es/m3.css +11 -3
- package/es/m3.js +118 -118
- package/lib/m3.css +11 -3
- package/lib/m3.js +118 -119
- package/package.json +1 -1
- package/src/framework/MViewer.less +11 -3
- package/src/ui/editor/basic/ADatetimePicker.tsx +1 -1
- package/src/ui/editor/basic/ARangePicker.tsx +295 -179
- package/types/ui/editor/basic/ARangePicker.d.ts +3 -3
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import React, { Component, RefObject } from "react";
|
|
2
2
|
import { DatePicker } from "antd";
|
|
3
|
-
import zhCN from
|
|
3
|
+
import zhCN from "antd/lib/date-picker/locale/zh_CN";
|
|
4
4
|
import moment from "moment";
|
|
5
5
|
import { DatePicker as DatePickerM } from "antd-mobile";
|
|
6
6
|
import { Button as AntButton } from "antd";
|
|
7
|
-
import ReactDOM from "react-dom";
|
|
8
7
|
import { RangePickerProps } from "antd/lib/date-picker";
|
|
9
8
|
import _ from "lodash";
|
|
10
|
-
import { Viewer, ViewerState } from
|
|
11
|
-
import { MUtil } from
|
|
9
|
+
import { Viewer, ViewerState } from "../../BaseViewer";
|
|
10
|
+
import { MUtil } from "../../../framework/MUtil";
|
|
12
11
|
import { MProp } from "../../../framework/Schema";
|
|
13
|
-
import { MDateRangeType } from
|
|
14
|
-
import { assembly } from
|
|
12
|
+
import { MDateRangeType } from "../../../types/MDateRangeType";
|
|
13
|
+
import { assembly } from "../../../framework/Assembly";
|
|
15
14
|
|
|
16
15
|
export type ARangePickerData = [
|
|
17
16
|
// 开始时间
|
|
@@ -19,26 +18,31 @@ export type ARangePickerData = [
|
|
|
19
18
|
// 结束时间
|
|
20
19
|
string | null | undefined,
|
|
21
20
|
// 是否至今,如果true,结束时间是无效的
|
|
22
|
-
boolean | null | undefined
|
|
21
|
+
boolean | null | undefined,
|
|
23
22
|
];
|
|
24
23
|
|
|
25
24
|
type AntData = [moment.Moment | null, moment.Moment | null];
|
|
26
25
|
|
|
27
26
|
interface State extends ViewerState {
|
|
28
27
|
mobileDlg: boolean;
|
|
29
|
-
mobileStep:
|
|
28
|
+
mobileStep: "start" | "end";
|
|
30
29
|
mobileStartDate?: Date;
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
export class ARangePicker extends Viewer<State> {
|
|
34
|
-
_pickerRef: RefObject<
|
|
33
|
+
_pickerRef: RefObject<HTMLDivElement> = React.createRef();
|
|
35
34
|
_onCalendarChangeValue?: AntData | null;
|
|
36
35
|
_panelClickedDate?: moment.Moment | null; // showTime 模式下通过面板点击事件捕获的日期
|
|
37
36
|
_startConfirmed = false; // 标记开始日期是否已确认,用于区分 onClose 是取消还是确认后的自动触发
|
|
38
37
|
|
|
39
38
|
constructor(p: MProp) {
|
|
40
39
|
super(p);
|
|
41
|
-
this.state = {
|
|
40
|
+
this.state = {
|
|
41
|
+
ctrlVersion: 1,
|
|
42
|
+
noValidate: false,
|
|
43
|
+
mobileDlg: false,
|
|
44
|
+
mobileStep: "start",
|
|
45
|
+
};
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
componentDidUpdate() {
|
|
@@ -51,13 +55,14 @@ export class ARangePicker extends Viewer<State> {
|
|
|
51
55
|
|
|
52
56
|
_patchTillnow() {
|
|
53
57
|
const v = super.getValue();
|
|
54
|
-
if (_.get(v, "[2]")) {
|
|
55
|
-
|
|
58
|
+
if (_.get(v, "[2]")) {
|
|
59
|
+
// tillnow
|
|
60
|
+
const dom = this._pickerRef.current;
|
|
56
61
|
if (dom) {
|
|
57
|
-
// @ts-ignore
|
|
58
62
|
let r = dom.querySelector(":nth-child(3)");
|
|
59
63
|
if (r) {
|
|
60
|
-
r.innerHTML =
|
|
64
|
+
r.innerHTML =
|
|
65
|
+
"<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
}
|
|
@@ -65,9 +70,12 @@ export class ARangePicker extends Viewer<State> {
|
|
|
65
70
|
|
|
66
71
|
/**
|
|
67
72
|
* RangePicker的数据转换成json上的数据类型
|
|
68
|
-
* @param r
|
|
73
|
+
* @param r
|
|
69
74
|
*/
|
|
70
|
-
_rangePicker2Data(
|
|
75
|
+
_rangePicker2Data(
|
|
76
|
+
v: AntData | null | undefined,
|
|
77
|
+
tillNow: boolean,
|
|
78
|
+
): ARangePickerData | undefined {
|
|
71
79
|
if (!v) {
|
|
72
80
|
return undefined;
|
|
73
81
|
}
|
|
@@ -77,12 +85,13 @@ export class ARangePicker extends Viewer<State> {
|
|
|
77
85
|
|
|
78
86
|
/**
|
|
79
87
|
* json上的数据转换成RangePicker的数据
|
|
80
|
-
* @param d
|
|
88
|
+
* @param d
|
|
81
89
|
*/
|
|
82
90
|
_data2rangePicker(d: ARangePickerData): AntData {
|
|
83
91
|
const dataFormat = this.props.schema.dataFormat ?? "x";
|
|
84
92
|
// 若 tillNow=true,结束时间传 null,避免 RangePicker 缓存旧结束时间
|
|
85
|
-
const endTime =
|
|
93
|
+
const endTime =
|
|
94
|
+
d[2] === true ? null : d[1] ? moment(d[1], dataFormat) : null;
|
|
86
95
|
return [d[0] ? moment(d[0], dataFormat) : null, endTime];
|
|
87
96
|
}
|
|
88
97
|
|
|
@@ -90,44 +99,76 @@ export class ARangePicker extends Viewer<State> {
|
|
|
90
99
|
const p = this.props.schema.props ?? {};
|
|
91
100
|
let rangePickerData = this._data2rangePicker(this.getValue() ?? []);
|
|
92
101
|
if (MUtil.phoneLike()) {
|
|
93
|
-
let show = MDateRangeType.toReadableN(
|
|
102
|
+
let show = MDateRangeType.toReadableN(
|
|
103
|
+
assembly,
|
|
104
|
+
this.props.schema,
|
|
105
|
+
super.getValue(),
|
|
106
|
+
);
|
|
94
107
|
|
|
95
108
|
// 根据 precision 配置确定移动端 DatePicker 精度(使用扁平化属性 dateRangePrecision)
|
|
96
|
-
const mobilePrecision = (this.props.schema.dateRangePrecision ||
|
|
109
|
+
const mobilePrecision = (this.props.schema.dateRangePrecision ||
|
|
110
|
+
"day") as "year" | "month" | "day" | "hour" | "minute" | "second";
|
|
97
111
|
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
precision={mobilePrecision}
|
|
105
|
-
title="选择开始日期"
|
|
106
|
-
min={this.props.schema.min ? new Date(this.props.schema.min) : undefined}
|
|
107
|
-
max={this.props.schema.max ? new Date(this.props.schema.max) : undefined}
|
|
108
|
-
onConfirm={(val) => {
|
|
109
|
-
this._startConfirmed = true;
|
|
110
|
-
this.setState({ mobileStartDate: val, mobileStep: 'end' });
|
|
111
|
-
}}
|
|
112
|
-
onClose={() => {
|
|
113
|
-
// antd-mobile v5 确认时会同时触发 onConfirm 和 onClose
|
|
114
|
-
// 用实例变量同步判断:确认后的 onClose 应忽略,仅用户主动取消时才关闭
|
|
115
|
-
if (this._startConfirmed) {
|
|
116
|
-
this._startConfirmed = false;
|
|
117
|
-
return;
|
|
112
|
+
return (
|
|
113
|
+
<>
|
|
114
|
+
<div
|
|
115
|
+
className="backfill"
|
|
116
|
+
onClick={() =>
|
|
117
|
+
this.setState({ mobileDlg: true, mobileStep: "start" })
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
119
|
+
>
|
|
120
|
+
{" "}
|
|
121
|
+
{show ?? "请点击选择"}{" "}
|
|
122
|
+
</div>
|
|
123
|
+
{/* 移动端:使用两步 DatePickerM 选择开始和结束日期 */}
|
|
124
|
+
<DatePickerM
|
|
125
|
+
key={`start_${mobilePrecision}`}
|
|
126
|
+
visible={this.state.mobileDlg && this.state.mobileStep === "start"}
|
|
127
|
+
precision={mobilePrecision}
|
|
128
|
+
title="选择开始日期"
|
|
129
|
+
min={
|
|
130
|
+
this.props.schema.min
|
|
131
|
+
? new Date(this.props.schema.min)
|
|
132
|
+
: undefined
|
|
133
|
+
}
|
|
134
|
+
max={
|
|
135
|
+
this.props.schema.max
|
|
136
|
+
? new Date(this.props.schema.max)
|
|
137
|
+
: undefined
|
|
138
|
+
}
|
|
139
|
+
onConfirm={(val) => {
|
|
140
|
+
this._startConfirmed = true;
|
|
141
|
+
this.setState({ mobileStartDate: val, mobileStep: "end" });
|
|
142
|
+
}}
|
|
143
|
+
onClose={() => {
|
|
144
|
+
// antd-mobile v5 确认时会同时触发 onConfirm 和 onClose
|
|
145
|
+
// 用实例变量同步判断:确认后的 onClose 应忽略,仅用户主动取消时才关闭
|
|
146
|
+
if (this._startConfirmed) {
|
|
147
|
+
this._startConfirmed = false;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
this.setState({ mobileDlg: false });
|
|
151
|
+
}}
|
|
152
|
+
/>
|
|
153
|
+
<DatePickerM
|
|
154
|
+
key={`end_${mobilePrecision}`}
|
|
155
|
+
visible={this.state.mobileDlg && this.state.mobileStep === "end"}
|
|
156
|
+
precision={mobilePrecision}
|
|
157
|
+
title={
|
|
158
|
+
// 如果允许"至今"且开始时间不在未来,在标题区域展示"至今"按钮
|
|
159
|
+
!this.props.schema.dateRange?.hideTillNow &&
|
|
160
|
+
!(
|
|
161
|
+
this.state.mobileStartDate &&
|
|
162
|
+
this.state.mobileStartDate > new Date()
|
|
163
|
+
) ? (
|
|
164
|
+
<div
|
|
165
|
+
style={{
|
|
166
|
+
display: "flex",
|
|
167
|
+
alignItems: "center",
|
|
168
|
+
justifyContent: "center",
|
|
169
|
+
gap: 12,
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
131
172
|
<span>选择结束日期</span>
|
|
132
173
|
<AntButton
|
|
133
174
|
size="small"
|
|
@@ -136,51 +177,78 @@ export class ARangePicker extends Viewer<State> {
|
|
|
136
177
|
const startDate = this.state.mobileStartDate;
|
|
137
178
|
if (startDate) {
|
|
138
179
|
super.changeValueEx(
|
|
139
|
-
this._rangePicker2Data(
|
|
140
|
-
|
|
180
|
+
this._rangePicker2Data(
|
|
181
|
+
[moment(startDate), moment()],
|
|
182
|
+
true,
|
|
183
|
+
),
|
|
184
|
+
true,
|
|
185
|
+
true,
|
|
141
186
|
);
|
|
142
187
|
}
|
|
143
188
|
this.setState({ mobileDlg: false });
|
|
144
189
|
}}
|
|
145
|
-
|
|
190
|
+
>
|
|
191
|
+
至今
|
|
192
|
+
</AntButton>
|
|
146
193
|
</div>
|
|
147
|
-
:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
max={this.props.schema.max ? new Date(this.props.schema.max) : undefined}
|
|
151
|
-
onConfirm={(val: any) => {
|
|
152
|
-
const startDate = this.state.mobileStartDate;
|
|
153
|
-
if (startDate) {
|
|
154
|
-
// 防御:结束日期不能早于开始日期
|
|
155
|
-
const finalEnd = val < startDate ? startDate : val;
|
|
156
|
-
super.changeValueEx(this._rangePicker2Data([moment(startDate), moment(finalEnd)], false), true, true);
|
|
194
|
+
) : (
|
|
195
|
+
"选择结束日期"
|
|
196
|
+
)
|
|
157
197
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
198
|
+
min={
|
|
199
|
+
this.state.mobileStartDate ||
|
|
200
|
+
(this.props.schema.min
|
|
201
|
+
? new Date(this.props.schema.min)
|
|
202
|
+
: undefined)
|
|
203
|
+
}
|
|
204
|
+
max={
|
|
205
|
+
this.props.schema.max
|
|
206
|
+
? new Date(this.props.schema.max)
|
|
207
|
+
: undefined
|
|
208
|
+
}
|
|
209
|
+
onConfirm={(val: any) => {
|
|
210
|
+
const startDate = this.state.mobileStartDate;
|
|
211
|
+
if (startDate) {
|
|
212
|
+
// 防御:结束日期不能早于开始日期
|
|
213
|
+
const finalEnd = val < startDate ? startDate : val;
|
|
214
|
+
super.changeValueEx(
|
|
215
|
+
this._rangePicker2Data(
|
|
216
|
+
[moment(startDate), moment(finalEnd)],
|
|
217
|
+
false,
|
|
218
|
+
),
|
|
219
|
+
true,
|
|
220
|
+
true,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
this.setState({ mobileDlg: false });
|
|
224
|
+
}}
|
|
225
|
+
onClose={() => {
|
|
226
|
+
// 回退到第一步,让用户可以重新选择开始日期
|
|
227
|
+
this.setState({ mobileStep: "start" });
|
|
228
|
+
}}
|
|
229
|
+
/>
|
|
230
|
+
</>
|
|
231
|
+
);
|
|
166
232
|
} else {
|
|
167
233
|
// 根据 precision 配置确定 PC 端 picker 模式和 showTime(使用扁平化属性 dateRangePrecision)
|
|
168
234
|
const precision = this.props.schema.dateRangePrecision;
|
|
169
|
-
const pcShowTime =
|
|
235
|
+
const pcShowTime =
|
|
236
|
+
precision === "minute" || this.props.schema.dateRange?.showTime;
|
|
170
237
|
const hideFooter = this.props.schema.dateRange?.hideTillNow;
|
|
171
238
|
|
|
172
239
|
// 动态构建额外属性,避免 showTime 和 picker 同时传入导致类型冲突
|
|
173
240
|
const extraProps: any = {};
|
|
174
|
-
if (precision ===
|
|
175
|
-
extraProps.picker =
|
|
176
|
-
} else if (precision ===
|
|
177
|
-
extraProps.picker =
|
|
241
|
+
if (precision === "year") {
|
|
242
|
+
extraProps.picker = "year";
|
|
243
|
+
} else if (precision === "month") {
|
|
244
|
+
extraProps.picker = "month";
|
|
178
245
|
} else if (pcShowTime) {
|
|
179
246
|
// precision 为 minute 时只展示时分,不展示秒
|
|
180
|
-
extraProps.showTime =
|
|
247
|
+
extraProps.showTime =
|
|
248
|
+
precision === "minute" ? { format: "HH:mm" } : true;
|
|
181
249
|
// 同步设置输入框的显示格式,避免 showTime.format 只影响面板列而输入框仍显示秒
|
|
182
|
-
if (precision ===
|
|
183
|
-
extraProps.format =
|
|
250
|
+
if (precision === "minute") {
|
|
251
|
+
extraProps.format = "YYYY-MM-DD HH:mm";
|
|
184
252
|
}
|
|
185
253
|
}
|
|
186
254
|
|
|
@@ -189,17 +257,26 @@ export class ARangePicker extends Viewer<State> {
|
|
|
189
257
|
// 优先级:onCalendarChange 记录的值 > 面板点击捕获的日期 > 已有默认值 > 当前时间
|
|
190
258
|
const fromCalendarChange = this._onCalendarChangeValue?.[0];
|
|
191
259
|
const fromPanelClick = this._panelClickedDate;
|
|
192
|
-
let startMoment =
|
|
260
|
+
let startMoment =
|
|
261
|
+
fromCalendarChange ??
|
|
262
|
+
fromPanelClick ??
|
|
263
|
+
rangePickerData?.[0] ??
|
|
264
|
+
moment();
|
|
193
265
|
|
|
194
266
|
// 如果开始时间来自面板点击(只有日期没有时间),将当前时刻的时分附加上去
|
|
195
267
|
if (!fromCalendarChange && fromPanelClick) {
|
|
196
268
|
const now = moment();
|
|
197
|
-
startMoment = startMoment
|
|
269
|
+
startMoment = startMoment
|
|
270
|
+
.clone()
|
|
271
|
+
.hour(now.hour())
|
|
272
|
+
.minute(now.minute())
|
|
273
|
+
.second(0);
|
|
198
274
|
}
|
|
199
275
|
|
|
200
276
|
super.changeValueEx(
|
|
201
277
|
this._rangePicker2Data([startMoment, moment()], true),
|
|
202
|
-
true,
|
|
278
|
+
true,
|
|
279
|
+
true,
|
|
203
280
|
);
|
|
204
281
|
};
|
|
205
282
|
|
|
@@ -207,106 +284,145 @@ export class ARangePicker extends Viewer<State> {
|
|
|
207
284
|
const showTillNow = !hideFooter;
|
|
208
285
|
|
|
209
286
|
// 构造元素
|
|
210
|
-
return
|
|
211
|
-
ref={this._pickerRef}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
287
|
+
return (
|
|
288
|
+
<div ref={this._pickerRef}>
|
|
289
|
+
<DatePicker.RangePicker
|
|
290
|
+
key={`${this.state.ctrlVersion}_${
|
|
291
|
+
this.props.schema.dateRangePrecision ?? "day"
|
|
292
|
+
}`}
|
|
293
|
+
panelRender={
|
|
294
|
+
pcShowTime && showTillNow
|
|
295
|
+
? (panelNode) => {
|
|
296
|
+
// showTime 模式下:通过事件委托捕获面板上日期单元格的点击
|
|
297
|
+
// 同时在 footer 的"确定"按钮同一行注入"至今"按钮
|
|
298
|
+
return (
|
|
299
|
+
<div
|
|
300
|
+
onClick={(e) => {
|
|
301
|
+
const target = e.target as HTMLElement;
|
|
302
|
+
const cell = target.closest?.(".ant-picker-cell");
|
|
303
|
+
if (cell) {
|
|
304
|
+
// 排除 disabled 状态的日期单元格
|
|
305
|
+
if (
|
|
306
|
+
cell.classList.contains(
|
|
307
|
+
"ant-picker-cell-disabled",
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
return;
|
|
311
|
+
const title = cell.getAttribute("title");
|
|
312
|
+
if (title) {
|
|
313
|
+
const parsed = moment(title, "YYYY-MM-DD");
|
|
314
|
+
// 校验 moment 解析有效性,无效日期不记录
|
|
315
|
+
if (parsed.isValid()) {
|
|
316
|
+
this._panelClickedDate = parsed;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}}
|
|
321
|
+
ref={(el) => {
|
|
322
|
+
// 面板渲染后,将"至今"按钮注入到 .ant-picker-ok 内部,确定按钮之后
|
|
323
|
+
// 这样两者在同一个 flex item 中,确定在左、至今在右
|
|
324
|
+
if (!el) return;
|
|
325
|
+
const okLi = el.querySelector(".ant-picker-ok");
|
|
326
|
+
if (!okLi) return;
|
|
327
|
+
|
|
328
|
+
// 开始时间在未来时,移除已有的至今按钮并不再注入
|
|
329
|
+
const previewStart =
|
|
330
|
+
this._onCalendarChangeValue?.[0] ??
|
|
331
|
+
this._panelClickedDate ??
|
|
332
|
+
rangePickerData?.[0];
|
|
333
|
+
if (previewStart && previewStart.isAfter(moment())) {
|
|
334
|
+
const existingBtn =
|
|
335
|
+
okLi.querySelector(".till-now-btn");
|
|
336
|
+
if (existingBtn) existingBtn.remove();
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (!okLi.querySelector(".till-now-btn")) {
|
|
341
|
+
const tillNowBtn = document.createElement("button");
|
|
342
|
+
tillNowBtn.className =
|
|
343
|
+
"ant-btn ant-btn-sm till-now-btn";
|
|
344
|
+
tillNowBtn.textContent = "至今";
|
|
345
|
+
tillNowBtn.style.cssText = "margin-left: 8px;";
|
|
346
|
+
// 使用具名函数以便于清理;先移除可能的旧监听再添加,防止重复绑定
|
|
347
|
+
const onTillNowClick = (e: Event) => {
|
|
348
|
+
e.stopPropagation();
|
|
349
|
+
handleTillNow();
|
|
350
|
+
};
|
|
351
|
+
tillNowBtn.addEventListener(
|
|
352
|
+
"click",
|
|
353
|
+
onTillNowClick,
|
|
354
|
+
);
|
|
355
|
+
okLi.appendChild(tillNowBtn);
|
|
356
|
+
}
|
|
357
|
+
}}
|
|
358
|
+
>
|
|
359
|
+
{panelNode}
|
|
360
|
+
</div>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
: undefined
|
|
364
|
+
}
|
|
365
|
+
renderExtraFooter={
|
|
366
|
+
!pcShowTime && showTillNow
|
|
367
|
+
? (mode) => {
|
|
368
|
+
// 非 showTime 模式:使用 renderExtraFooter 展示"至今"按钮
|
|
369
|
+
const previewStart =
|
|
370
|
+
this._onCalendarChangeValue?.[0] ?? rangePickerData?.[0];
|
|
371
|
+
if (previewStart && previewStart.isAfter(moment())) {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
return (
|
|
375
|
+
<div style={{ textAlign: "right" }}>
|
|
376
|
+
<AntButton
|
|
377
|
+
size="small"
|
|
378
|
+
style={{
|
|
379
|
+
width: "100px",
|
|
380
|
+
display: "inline-block",
|
|
381
|
+
marginTop: "5px",
|
|
382
|
+
}}
|
|
383
|
+
onClick={handleTillNow}
|
|
384
|
+
>
|
|
385
|
+
至今
|
|
386
|
+
</AntButton>
|
|
387
|
+
</div>
|
|
388
|
+
);
|
|
229
389
|
}
|
|
230
|
-
|
|
390
|
+
: undefined
|
|
391
|
+
}
|
|
392
|
+
bordered={this.props.hideBorder ? false : true}
|
|
393
|
+
style={{ width: "100%" }}
|
|
394
|
+
locale={zhCN}
|
|
395
|
+
defaultValue={rangePickerData}
|
|
396
|
+
onCalendarChange={(d) => {
|
|
397
|
+
this._onCalendarChangeValue = d;
|
|
398
|
+
// 用户开始新一轮选择时清理面板点击缓存,避免上一轮过时数据污染
|
|
399
|
+
this._panelClickedDate = null;
|
|
400
|
+
}}
|
|
401
|
+
onOpenChange={(open) => {
|
|
402
|
+
if (!open) {
|
|
403
|
+
this._panelClickedDate = null;
|
|
231
404
|
}
|
|
232
405
|
}}
|
|
233
|
-
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
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();
|
|
406
|
+
onChange={(vv) => {
|
|
407
|
+
// 用户清空日期范围时,直接置空
|
|
408
|
+
if (!vv) {
|
|
409
|
+
super.changeValueEx(undefined, true, true);
|
|
245
410
|
return;
|
|
246
411
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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())) {
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
return <div style={{ textAlign: "right" }}>
|
|
275
|
-
<AntButton
|
|
276
|
-
size="small" style={{ width: "100px", display: "inline-block", marginTop: "5px" }}
|
|
277
|
-
onClick={handleTillNow}>至今</AntButton>
|
|
278
|
-
</div>;
|
|
279
|
-
}
|
|
280
|
-
: undefined
|
|
281
|
-
}
|
|
282
|
-
bordered={this.props.hideBorder ? false : true}
|
|
283
|
-
style={{ width: "300px" }}
|
|
284
|
-
locale={zhCN}
|
|
285
|
-
defaultValue={rangePickerData}
|
|
286
|
-
onCalendarChange={(d) => {
|
|
287
|
-
this._onCalendarChangeValue = d;
|
|
288
|
-
// 用户开始新一轮选择时清理面板点击缓存,避免上一轮过时数据污染
|
|
289
|
-
this._panelClickedDate = null;
|
|
290
|
-
}}
|
|
291
|
-
onOpenChange={(open) => {
|
|
292
|
-
if (!open) {
|
|
293
|
-
this._panelClickedDate = null;
|
|
294
|
-
}
|
|
295
|
-
}}
|
|
296
|
-
onChange={(vv) => {
|
|
297
|
-
// 用户清空日期范围时,直接置空
|
|
298
|
-
if (!vv) {
|
|
299
|
-
super.changeValueEx(undefined, true, true);
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
const currentData = super.getValue();
|
|
303
|
-
const isTillNow = _.get(currentData, '[2]') === true;
|
|
304
|
-
// 若当前是"至今"且用户只改了开始时间(结束时间仍为 null),保留 tillNow
|
|
305
|
-
const newTillNow = isTillNow && vv[1] == null;
|
|
306
|
-
super.changeValueEx(this._rangePicker2Data(vv, newTillNow), true, true);
|
|
307
|
-
}}
|
|
308
|
-
{...extraProps}
|
|
309
|
-
/>;
|
|
412
|
+
const currentData = super.getValue();
|
|
413
|
+
const isTillNow = _.get(currentData, "[2]") === true;
|
|
414
|
+
// 若当前是"至今"且用户只改了开始时间(结束时间仍为 null),保留 tillNow
|
|
415
|
+
const newTillNow = isTillNow && vv[1] == null;
|
|
416
|
+
super.changeValueEx(
|
|
417
|
+
this._rangePicker2Data(vv, newTillNow),
|
|
418
|
+
true,
|
|
419
|
+
true,
|
|
420
|
+
);
|
|
421
|
+
}}
|
|
422
|
+
{...extraProps}
|
|
423
|
+
/>
|
|
424
|
+
</div>
|
|
425
|
+
);
|
|
310
426
|
}
|
|
311
427
|
}
|
|
312
428
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RefObject } from "react";
|
|
2
2
|
import moment from "moment";
|
|
3
|
-
import { Viewer, ViewerState } from
|
|
3
|
+
import { Viewer, ViewerState } from "../../BaseViewer";
|
|
4
4
|
import { MProp } from "../../../framework/Schema";
|
|
5
5
|
export type ARangePickerData = [
|
|
6
6
|
string | null | undefined,
|
|
@@ -10,11 +10,11 @@ export type ARangePickerData = [
|
|
|
10
10
|
type AntData = [moment.Moment | null, moment.Moment | null];
|
|
11
11
|
interface State extends ViewerState {
|
|
12
12
|
mobileDlg: boolean;
|
|
13
|
-
mobileStep:
|
|
13
|
+
mobileStep: "start" | "end";
|
|
14
14
|
mobileStartDate?: Date;
|
|
15
15
|
}
|
|
16
16
|
export declare class ARangePicker extends Viewer<State> {
|
|
17
|
-
_pickerRef: RefObject<
|
|
17
|
+
_pickerRef: RefObject<HTMLDivElement>;
|
|
18
18
|
_onCalendarChangeValue?: AntData | null;
|
|
19
19
|
_panelClickedDate?: moment.Moment | null;
|
|
20
20
|
_startConfirmed: boolean;
|