maooo-skyline-ui-system 0.1.1
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/README.md +157 -0
- package/miniprogram_dist/button/button.js +43 -0
- package/miniprogram_dist/button/button.json +5 -0
- package/miniprogram_dist/button/button.wxml +12 -0
- package/miniprogram_dist/button/button.wxs +23 -0
- package/miniprogram_dist/button/button.wxss +133 -0
- package/miniprogram_dist/calendar/calendar.js +549 -0
- package/miniprogram_dist/calendar/calendar.json +8 -0
- package/miniprogram_dist/calendar/calendar.wxml +79 -0
- package/miniprogram_dist/calendar/calendar.wxss +265 -0
- package/miniprogram_dist/card/card.js +22 -0
- package/miniprogram_dist/card/card.json +5 -0
- package/miniprogram_dist/card/card.wxml +9 -0
- package/miniprogram_dist/card/card.wxss +34 -0
- package/miniprogram_dist/countdown/countdown.js +213 -0
- package/miniprogram_dist/countdown/countdown.json +3 -0
- package/miniprogram_dist/countdown/countdown.wxml +9 -0
- package/miniprogram_dist/countdown/countdown.wxss +33 -0
- package/miniprogram_dist/form/form.js +12 -0
- package/miniprogram_dist/form/form.json +5 -0
- package/miniprogram_dist/form/form.wxml +12 -0
- package/miniprogram_dist/form/form.wxss +35 -0
- package/miniprogram_dist/form-group/form-group.js +53 -0
- package/miniprogram_dist/form-group/form-group.json +5 -0
- package/miniprogram_dist/form-group/form-group.wxml +11 -0
- package/miniprogram_dist/form-group/form-group.wxss +50 -0
- package/miniprogram_dist/form-input/form-input.js +48 -0
- package/miniprogram_dist/form-input/form-input.json +8 -0
- package/miniprogram_dist/form-input/form-input.wxml +28 -0
- package/miniprogram_dist/form-input/form-input.wxss +3 -0
- package/miniprogram_dist/form-textarea/form-textarea.js +34 -0
- package/miniprogram_dist/form-textarea/form-textarea.json +8 -0
- package/miniprogram_dist/form-textarea/form-textarea.wxml +20 -0
- package/miniprogram_dist/form-textarea/form-textarea.wxss +3 -0
- package/miniprogram_dist/icon/_iconfont/iconfont.js +63 -0
- package/miniprogram_dist/icon/_iconfont/iconfont.json +4 -0
- package/miniprogram_dist/icon/_iconfont/iconfont.wxml +8 -0
- package/miniprogram_dist/icon/_iconfont/iconfont.wxss +3 -0
- package/miniprogram_dist/icon/icon.js +41 -0
- package/miniprogram_dist/icon/icon.json +7 -0
- package/miniprogram_dist/icon/icon.wxml +3 -0
- package/miniprogram_dist/icon/icon.wxss +13 -0
- package/miniprogram_dist/image-cropper/image-cropper.js +703 -0
- package/miniprogram_dist/image-cropper/image-cropper.json +3 -0
- package/miniprogram_dist/image-cropper/image-cropper.wxml +58 -0
- package/miniprogram_dist/image-cropper/image-cropper.wxss +195 -0
- package/miniprogram_dist/index.js +4 -0
- package/miniprogram_dist/input/input.js +119 -0
- package/miniprogram_dist/input/input.json +7 -0
- package/miniprogram_dist/input/input.wxml +38 -0
- package/miniprogram_dist/input/input.wxss +52 -0
- package/miniprogram_dist/media-upload/media-upload.js +1108 -0
- package/miniprogram_dist/media-upload/media-upload.json +7 -0
- package/miniprogram_dist/media-upload/media-upload.wxml +98 -0
- package/miniprogram_dist/media-upload/media-upload.wxss +149 -0
- package/miniprogram_dist/navbar/navbar.js +191 -0
- package/miniprogram_dist/navbar/navbar.json +6 -0
- package/miniprogram_dist/navbar/navbar.wxml +25 -0
- package/miniprogram_dist/navbar/navbar.wxss +60 -0
- package/miniprogram_dist/notify/notify.js +342 -0
- package/miniprogram_dist/notify/notify.json +5 -0
- package/miniprogram_dist/notify/notify.wxml +27 -0
- package/miniprogram_dist/notify/notify.wxss +246 -0
- package/miniprogram_dist/notify/service.js +69 -0
- package/miniprogram_dist/oss-upload/oss-upload.js +505 -0
- package/miniprogram_dist/oss-upload/oss-upload.json +6 -0
- package/miniprogram_dist/oss-upload/oss-upload.wxml +20 -0
- package/miniprogram_dist/oss-upload/oss-upload.wxss +5 -0
- package/miniprogram_dist/popup/popup.js +36 -0
- package/miniprogram_dist/popup/popup.json +5 -0
- package/miniprogram_dist/popup/popup.wxml +14 -0
- package/miniprogram_dist/popup/popup.wxss +138 -0
- package/miniprogram_dist/popup-page/popup-page.js +341 -0
- package/miniprogram_dist/popup-page/popup-page.json +8 -0
- package/miniprogram_dist/popup-page/popup-page.wxml +65 -0
- package/miniprogram_dist/popup-page/popup-page.wxss +92 -0
- package/miniprogram_dist/progress/progress.js +161 -0
- package/miniprogram_dist/progress/progress.json +5 -0
- package/miniprogram_dist/progress/progress.wxml +16 -0
- package/miniprogram_dist/progress/progress.wxss +81 -0
- package/miniprogram_dist/rate/rate.js +127 -0
- package/miniprogram_dist/rate/rate.json +5 -0
- package/miniprogram_dist/rate/rate.wxml +32 -0
- package/miniprogram_dist/rate/rate.wxs +21 -0
- package/miniprogram_dist/rate/rate.wxss +126 -0
- package/miniprogram_dist/stepper/stepper.js +153 -0
- package/miniprogram_dist/stepper/stepper.json +5 -0
- package/miniprogram_dist/stepper/stepper.wxml +19 -0
- package/miniprogram_dist/stepper/stepper.wxss +66 -0
- package/miniprogram_dist/switch/switch.js +29 -0
- package/miniprogram_dist/switch/switch.json +3 -0
- package/miniprogram_dist/switch/switch.wxml +10 -0
- package/miniprogram_dist/switch/switch.wxss +71 -0
- package/miniprogram_dist/textarea/textarea.js +83 -0
- package/miniprogram_dist/textarea/textarea.json +5 -0
- package/miniprogram_dist/textarea/textarea.wxml +14 -0
- package/miniprogram_dist/textarea/textarea.wxss +33 -0
- package/miniprogram_dist/theme/theme.wxss +64 -0
- package/miniprogram_dist/toast/toast.js +51 -0
- package/miniprogram_dist/toast/toast.json +5 -0
- package/miniprogram_dist/toast/toast.wxml +13 -0
- package/miniprogram_dist/toast/toast.wxss +143 -0
- package/miniprogram_dist/upload/upload.js +276 -0
- package/miniprogram_dist/upload/upload.json +3 -0
- package/miniprogram_dist/upload/upload.wxml +36 -0
- package/miniprogram_dist/upload/upload.wxss +136 -0
- package/miniprogram_dist/utils/class.js +37 -0
- package/miniprogram_dist/utils/device.js +67 -0
- package/miniprogram_dist/utils/dom.js +51 -0
- package/miniprogram_dist/utils/event.js +28 -0
- package/miniprogram_dist/utils/form.js +39 -0
- package/miniprogram_dist/utils/function.js +63 -0
- package/miniprogram_dist/utils/index.js +21 -0
- package/miniprogram_dist/utils/props.js +51 -0
- package/miniprogram_dist/utils/style.js +52 -0
- package/miniprogram_dist/utils/theme.js +30 -0
- package/package.json +31 -0
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
2
|
+
const DEFAULT_MONTH_SPAN = 6;
|
|
3
|
+
|
|
4
|
+
const WEEKDAYS = {
|
|
5
|
+
monday: ["一", "二", "三", "四", "五", "六", "日"],
|
|
6
|
+
sunday: ["日", "一", "二", "三", "四", "五", "六"]
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function pad2(value) {
|
|
10
|
+
return value < 10 ? `0${value}` : `${value}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function startOfLocalDay(date) {
|
|
14
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function formatDate(date) {
|
|
18
|
+
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseLocalDate(value) {
|
|
22
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
23
|
+
const date = new Date(value);
|
|
24
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
25
|
+
return startOfLocalDay(date);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof value !== "string") return null;
|
|
29
|
+
if (!value) return null;
|
|
30
|
+
|
|
31
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
32
|
+
if (!match) return null;
|
|
33
|
+
|
|
34
|
+
const year = Number(match[1]);
|
|
35
|
+
const month = Number(match[2]);
|
|
36
|
+
const day = Number(match[3]);
|
|
37
|
+
const date = new Date(year, month - 1, day);
|
|
38
|
+
|
|
39
|
+
if (
|
|
40
|
+
date.getFullYear() !== year ||
|
|
41
|
+
date.getMonth() !== month - 1 ||
|
|
42
|
+
date.getDate() !== day
|
|
43
|
+
) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return date;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function addMonths(date, count) {
|
|
51
|
+
return new Date(date.getFullYear(), date.getMonth() + count, date.getDate());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getMonthStart(date) {
|
|
55
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getMonthEnd(date) {
|
|
59
|
+
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function compareMonth(a, b) {
|
|
63
|
+
const left = a.getFullYear() * 12 + a.getMonth();
|
|
64
|
+
const right = b.getFullYear() * 12 + b.getMonth();
|
|
65
|
+
return left === right ? 0 : left > right ? 1 : -1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeMode(mode) {
|
|
69
|
+
return mode === "multiple" ? "multiple" : "single";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function normalizeTagMode(mode) {
|
|
73
|
+
return mode === "single" ? "single" : "multiple";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeWeekStart(weekStart) {
|
|
77
|
+
return weekStart === "sunday" ? "sunday" : "monday";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function normalizeCount(value) {
|
|
81
|
+
const count = Number(value);
|
|
82
|
+
if (!Number.isFinite(count) || count <= 0) return 0;
|
|
83
|
+
return Math.floor(count);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizeValueArray(value) {
|
|
87
|
+
const source = Array.isArray(value) ? value : [];
|
|
88
|
+
const result = [];
|
|
89
|
+
const cache = {};
|
|
90
|
+
|
|
91
|
+
source.forEach((item) => {
|
|
92
|
+
const date = parseLocalDate(item);
|
|
93
|
+
if (!date) return;
|
|
94
|
+
|
|
95
|
+
const key = formatDate(date);
|
|
96
|
+
if (cache[key]) return;
|
|
97
|
+
|
|
98
|
+
cache[key] = true;
|
|
99
|
+
result.push(key);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function normalizeTagValue(value) {
|
|
106
|
+
const source = Array.isArray(value) ? value : [];
|
|
107
|
+
const result = [];
|
|
108
|
+
const cache = {};
|
|
109
|
+
|
|
110
|
+
source.forEach((item) => {
|
|
111
|
+
if (item === null || item === undefined) return;
|
|
112
|
+
|
|
113
|
+
const key = String(item);
|
|
114
|
+
if (cache[key]) return;
|
|
115
|
+
|
|
116
|
+
cache[key] = true;
|
|
117
|
+
result.push(key);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function toSet(values) {
|
|
124
|
+
const set = {};
|
|
125
|
+
values.forEach((value) => {
|
|
126
|
+
set[value] = true;
|
|
127
|
+
});
|
|
128
|
+
return set;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function formatPrice(price) {
|
|
132
|
+
const value = Number(price);
|
|
133
|
+
if (!Number.isFinite(value)) return "";
|
|
134
|
+
|
|
135
|
+
const yuan = value / 100;
|
|
136
|
+
if (value % 100 === 0) return `¥${yuan}`;
|
|
137
|
+
|
|
138
|
+
return `¥${yuan.toFixed(2).replace(/0+$/, "").replace(/\.$/, "")}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function hasValue(value) {
|
|
142
|
+
return value !== null && value !== undefined && value !== "";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getDateSubText(item) {
|
|
146
|
+
if (!item) return "";
|
|
147
|
+
if (hasValue(item.priceText)) return String(item.priceText);
|
|
148
|
+
if (hasValue(item.price)) return formatPrice(item.price);
|
|
149
|
+
if (hasValue(item.text)) return String(item.text);
|
|
150
|
+
return "";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getDateClassName(day) {
|
|
154
|
+
const classList = ["mo-calendar__day"];
|
|
155
|
+
|
|
156
|
+
if (day.empty) classList.push("is-empty");
|
|
157
|
+
if (day.disabled) classList.push("is-disabled");
|
|
158
|
+
if (day.selected) classList.push("is-selected");
|
|
159
|
+
if (day.today) classList.push("is-today");
|
|
160
|
+
|
|
161
|
+
return classList.join(" ");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function getDateContentClassName(day) {
|
|
165
|
+
const classList = ["mo-calendar__day-content"];
|
|
166
|
+
|
|
167
|
+
if (day.disabled) classList.push("is-disabled");
|
|
168
|
+
if (day.selected) classList.push("is-selected");
|
|
169
|
+
if (day.today) classList.push("is-today");
|
|
170
|
+
|
|
171
|
+
return classList.join(" ");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function getTagClassName(option) {
|
|
175
|
+
const classList = ["mo-calendar__tag"];
|
|
176
|
+
|
|
177
|
+
if (option.selected) classList.push("is-selected");
|
|
178
|
+
if (option.disabled) classList.push("is-disabled");
|
|
179
|
+
|
|
180
|
+
return classList.join(" ");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function getRangeDefaults(minDate, maxDate) {
|
|
184
|
+
const today = startOfLocalDay(new Date());
|
|
185
|
+
const parsedMin = parseLocalDate(minDate);
|
|
186
|
+
const parsedMax = parseLocalDate(maxDate);
|
|
187
|
+
|
|
188
|
+
const min = parsedMin || today;
|
|
189
|
+
let max = parsedMax || addMonths(today, DEFAULT_MONTH_SPAN);
|
|
190
|
+
|
|
191
|
+
if (max.getTime() < min.getTime()) {
|
|
192
|
+
max = min;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
min,
|
|
197
|
+
max,
|
|
198
|
+
invalidMin: hasValue(minDate) && !parsedMin,
|
|
199
|
+
invalidMax: hasValue(maxDate) && !parsedMax,
|
|
200
|
+
invalidRange: parsedMin && parsedMax && parsedMax.getTime() < parsedMin.getTime()
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
Component({
|
|
205
|
+
properties: {
|
|
206
|
+
show: {
|
|
207
|
+
type: Boolean,
|
|
208
|
+
value: false
|
|
209
|
+
},
|
|
210
|
+
title: {
|
|
211
|
+
type: String,
|
|
212
|
+
value: "选择服务日期"
|
|
213
|
+
},
|
|
214
|
+
value: {
|
|
215
|
+
type: Array,
|
|
216
|
+
value: [],
|
|
217
|
+
observer: "updateCalendarData"
|
|
218
|
+
},
|
|
219
|
+
mode: {
|
|
220
|
+
type: String,
|
|
221
|
+
value: "single",
|
|
222
|
+
observer: "updateCalendarData"
|
|
223
|
+
},
|
|
224
|
+
maxDateCount: {
|
|
225
|
+
type: Number,
|
|
226
|
+
value: 0
|
|
227
|
+
},
|
|
228
|
+
minDate: {
|
|
229
|
+
type: null,
|
|
230
|
+
value: "",
|
|
231
|
+
observer: "updateCalendarData"
|
|
232
|
+
},
|
|
233
|
+
maxDate: {
|
|
234
|
+
type: null,
|
|
235
|
+
value: "",
|
|
236
|
+
observer: "updateCalendarData"
|
|
237
|
+
},
|
|
238
|
+
weekStart: {
|
|
239
|
+
type: String,
|
|
240
|
+
value: "monday",
|
|
241
|
+
observer: "updateCalendarData"
|
|
242
|
+
},
|
|
243
|
+
dateItems: {
|
|
244
|
+
type: Array,
|
|
245
|
+
value: [],
|
|
246
|
+
observer: "updateCalendarData"
|
|
247
|
+
},
|
|
248
|
+
tagTitle: {
|
|
249
|
+
type: String,
|
|
250
|
+
value: "请选择服务时间(最多2次)"
|
|
251
|
+
},
|
|
252
|
+
tagOptions: {
|
|
253
|
+
type: Array,
|
|
254
|
+
value: [],
|
|
255
|
+
observer: "updateCalendarData"
|
|
256
|
+
},
|
|
257
|
+
tagValue: {
|
|
258
|
+
type: Array,
|
|
259
|
+
value: [],
|
|
260
|
+
observer: "updateCalendarData"
|
|
261
|
+
},
|
|
262
|
+
tagMode: {
|
|
263
|
+
type: String,
|
|
264
|
+
value: "multiple",
|
|
265
|
+
observer: "updateCalendarData"
|
|
266
|
+
},
|
|
267
|
+
tagMaxCount: {
|
|
268
|
+
type: Number,
|
|
269
|
+
value: 2
|
|
270
|
+
},
|
|
271
|
+
confirmText: {
|
|
272
|
+
type: String,
|
|
273
|
+
value: "确认"
|
|
274
|
+
},
|
|
275
|
+
closeOnMask: {
|
|
276
|
+
type: Boolean,
|
|
277
|
+
value: true
|
|
278
|
+
},
|
|
279
|
+
zIndex: {
|
|
280
|
+
type: Number,
|
|
281
|
+
value: 999
|
|
282
|
+
},
|
|
283
|
+
customClass: {
|
|
284
|
+
type: String,
|
|
285
|
+
value: ""
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
data: {
|
|
289
|
+
weekdays: WEEKDAYS.monday,
|
|
290
|
+
months: [],
|
|
291
|
+
normalizedValue: [],
|
|
292
|
+
normalizedTagValue: [],
|
|
293
|
+
normalizedTagOptions: [],
|
|
294
|
+
hasTags: false
|
|
295
|
+
},
|
|
296
|
+
lifetimes: {
|
|
297
|
+
attached() {
|
|
298
|
+
this.updateCalendarData();
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
methods: {
|
|
302
|
+
updateCalendarData() {
|
|
303
|
+
const range = getRangeDefaults(this.data.minDate, this.data.maxDate);
|
|
304
|
+
const weekStart = normalizeWeekStart(this.data.weekStart);
|
|
305
|
+
const value = normalizeValueArray(this.data.value);
|
|
306
|
+
const tagValue = normalizeTagValue(this.data.tagValue);
|
|
307
|
+
const dateItemMap = this.getDateItemMap();
|
|
308
|
+
const months = this.createMonths(range.min, range.max, weekStart, dateItemMap, value);
|
|
309
|
+
const normalizedTagOptions = this.createTagOptions(tagValue);
|
|
310
|
+
|
|
311
|
+
if (range.invalidMin) {
|
|
312
|
+
this.emitError("date", "minDate 必须是 YYYY-MM-DD 或毫秒时间戳");
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (range.invalidMax) {
|
|
316
|
+
this.emitError("date", "maxDate 必须是 YYYY-MM-DD 或毫秒时间戳");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (range.invalidRange) {
|
|
320
|
+
this.emitError("date", "maxDate 不能早于 minDate");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
this.setData({
|
|
324
|
+
weekdays: WEEKDAYS[weekStart],
|
|
325
|
+
months,
|
|
326
|
+
normalizedValue: value,
|
|
327
|
+
normalizedTagValue: tagValue,
|
|
328
|
+
normalizedTagOptions,
|
|
329
|
+
hasTags: normalizedTagOptions.length > 0
|
|
330
|
+
});
|
|
331
|
+
},
|
|
332
|
+
getDateItemMap() {
|
|
333
|
+
const source = Array.isArray(this.data.dateItems) ? this.data.dateItems : [];
|
|
334
|
+
const map = {};
|
|
335
|
+
|
|
336
|
+
source.forEach((item) => {
|
|
337
|
+
if (!item || !hasValue(item.date)) return;
|
|
338
|
+
|
|
339
|
+
const date = parseLocalDate(item.date);
|
|
340
|
+
if (!date) {
|
|
341
|
+
this.emitError("dateItems", "dateItems 中的 date 必须是 YYYY-MM-DD 或毫秒时间戳");
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
map[formatDate(date)] = item;
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
return map;
|
|
349
|
+
},
|
|
350
|
+
createMonths(minDate, maxDate, weekStart, dateItemMap, value) {
|
|
351
|
+
const months = [];
|
|
352
|
+
const selectedSet = toSet(value);
|
|
353
|
+
const todayKey = formatDate(new Date());
|
|
354
|
+
const minTime = minDate.getTime();
|
|
355
|
+
const maxTime = maxDate.getTime();
|
|
356
|
+
let cursor = getMonthStart(minDate);
|
|
357
|
+
const endMonth = getMonthStart(maxDate);
|
|
358
|
+
|
|
359
|
+
while (compareMonth(cursor, endMonth) <= 0) {
|
|
360
|
+
months.push(this.createMonth(cursor, minTime, maxTime, weekStart, dateItemMap, selectedSet, todayKey));
|
|
361
|
+
cursor = new Date(cursor.getFullYear(), cursor.getMonth() + 1, 1);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return months;
|
|
365
|
+
},
|
|
366
|
+
createMonth(monthDate, minTime, maxTime, weekStart, dateItemMap, selectedSet, todayKey) {
|
|
367
|
+
const days = [];
|
|
368
|
+
const firstDay = getMonthStart(monthDate);
|
|
369
|
+
const lastDay = getMonthEnd(monthDate);
|
|
370
|
+
const offset = weekStart === "monday" ? (firstDay.getDay() + 6) % 7 : firstDay.getDay();
|
|
371
|
+
const monthKey = `${monthDate.getFullYear()}-${pad2(monthDate.getMonth() + 1)}`;
|
|
372
|
+
|
|
373
|
+
for (let index = 0; index < offset; index += 1) {
|
|
374
|
+
days.push({
|
|
375
|
+
key: `${monthKey}-empty-before-${index}`,
|
|
376
|
+
empty: true,
|
|
377
|
+
className: "mo-calendar__day is-empty"
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
for (let day = 1; day <= lastDay.getDate(); day += 1) {
|
|
382
|
+
const date = new Date(monthDate.getFullYear(), monthDate.getMonth(), day);
|
|
383
|
+
const dateKey = formatDate(date);
|
|
384
|
+
const sourceItem = dateItemMap[dateKey] || {};
|
|
385
|
+
const disabled = date.getTime() < minTime || date.getTime() > maxTime || !!sourceItem.disabled;
|
|
386
|
+
const tagText = hasValue(sourceItem.tagText) ? String(sourceItem.tagText) : "";
|
|
387
|
+
const dayItem = {
|
|
388
|
+
...sourceItem,
|
|
389
|
+
key: dateKey,
|
|
390
|
+
date: dateKey,
|
|
391
|
+
day,
|
|
392
|
+
empty: false,
|
|
393
|
+
disabled,
|
|
394
|
+
selected: !!selectedSet[dateKey],
|
|
395
|
+
today: dateKey === todayKey,
|
|
396
|
+
tagText,
|
|
397
|
+
subText: getDateSubText(sourceItem)
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
dayItem.className = getDateClassName(dayItem);
|
|
401
|
+
dayItem.contentClassName = getDateContentClassName(dayItem);
|
|
402
|
+
days.push(dayItem);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
while (days.length % 7 !== 0) {
|
|
406
|
+
days.push({
|
|
407
|
+
key: `${monthKey}-empty-after-${days.length}`,
|
|
408
|
+
empty: true,
|
|
409
|
+
className: "mo-calendar__day is-empty"
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return {
|
|
414
|
+
key: monthKey,
|
|
415
|
+
title: `${monthDate.getFullYear()}年${monthDate.getMonth() + 1}月`,
|
|
416
|
+
days
|
|
417
|
+
};
|
|
418
|
+
},
|
|
419
|
+
createTagOptions(tagValue) {
|
|
420
|
+
const source = Array.isArray(this.data.tagOptions) ? this.data.tagOptions : [];
|
|
421
|
+
const selectedSet = toSet(tagValue);
|
|
422
|
+
|
|
423
|
+
return source
|
|
424
|
+
.filter((option) => option && (hasValue(option.value) || hasValue(option.label)))
|
|
425
|
+
.map((option) => {
|
|
426
|
+
const value = hasValue(option.value) ? String(option.value) : String(option.label);
|
|
427
|
+
const normalized = {
|
|
428
|
+
...option,
|
|
429
|
+
value,
|
|
430
|
+
label: hasValue(option.label) ? String(option.label) : value,
|
|
431
|
+
disabled: !!option.disabled,
|
|
432
|
+
selected: !!selectedSet[value]
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
normalized.className = getTagClassName(normalized);
|
|
436
|
+
return normalized;
|
|
437
|
+
});
|
|
438
|
+
},
|
|
439
|
+
getDayFromEvent(event) {
|
|
440
|
+
const monthIndex = Number(event.currentTarget.dataset.monthIndex);
|
|
441
|
+
const dayIndex = Number(event.currentTarget.dataset.dayIndex);
|
|
442
|
+
const month = this.data.months[monthIndex];
|
|
443
|
+
|
|
444
|
+
if (!month || !month.days) return null;
|
|
445
|
+
return month.days[dayIndex] || null;
|
|
446
|
+
},
|
|
447
|
+
handleDayTap(event) {
|
|
448
|
+
const day = this.getDayFromEvent(event);
|
|
449
|
+
if (!day || day.empty) return;
|
|
450
|
+
|
|
451
|
+
this.triggerEvent("click", {
|
|
452
|
+
date: day.date,
|
|
453
|
+
item: day,
|
|
454
|
+
disabled: !!day.disabled
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
if (day.disabled) return;
|
|
458
|
+
|
|
459
|
+
const mode = normalizeMode(this.data.mode);
|
|
460
|
+
const current = normalizeValueArray(this.data.value);
|
|
461
|
+
let nextValue = [];
|
|
462
|
+
|
|
463
|
+
if (mode === "single") {
|
|
464
|
+
nextValue = [day.date];
|
|
465
|
+
} else {
|
|
466
|
+
const exists = current.includes(day.date);
|
|
467
|
+
nextValue = exists ? current.filter((date) => date !== day.date) : current.concat(day.date);
|
|
468
|
+
|
|
469
|
+
const max = normalizeCount(this.data.maxDateCount);
|
|
470
|
+
if (!exists && max > 0 && current.length >= max) {
|
|
471
|
+
this.emitError("date-limit", `最多可选择${max}个日期`, null, true);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
this.triggerEvent("change", {
|
|
477
|
+
value: nextValue,
|
|
478
|
+
date: day.date,
|
|
479
|
+
item: day
|
|
480
|
+
});
|
|
481
|
+
},
|
|
482
|
+
handleTagTap(event) {
|
|
483
|
+
const index = Number(event.currentTarget.dataset.index);
|
|
484
|
+
const option = this.data.normalizedTagOptions[index];
|
|
485
|
+
if (!option || option.disabled) return;
|
|
486
|
+
|
|
487
|
+
const mode = normalizeTagMode(this.data.tagMode);
|
|
488
|
+
const current = normalizeTagValue(this.data.tagValue);
|
|
489
|
+
let nextValue = [];
|
|
490
|
+
|
|
491
|
+
if (mode === "single") {
|
|
492
|
+
nextValue = [option.value];
|
|
493
|
+
} else {
|
|
494
|
+
const exists = current.includes(option.value);
|
|
495
|
+
nextValue = exists ? current.filter((value) => value !== option.value) : current.concat(option.value);
|
|
496
|
+
|
|
497
|
+
const max = normalizeCount(this.data.tagMaxCount);
|
|
498
|
+
if (!exists && max > 0 && current.length >= max) {
|
|
499
|
+
this.emitError("tag-limit", `最多可选择${max}个选项`, null, true);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
this.triggerEvent("tagchange", {
|
|
505
|
+
value: nextValue,
|
|
506
|
+
option
|
|
507
|
+
});
|
|
508
|
+
},
|
|
509
|
+
handleConfirm() {
|
|
510
|
+
const value = normalizeValueArray(this.data.value);
|
|
511
|
+
const tagValue = normalizeTagValue(this.data.tagValue);
|
|
512
|
+
const dateItemMap = this.getDateItemMap();
|
|
513
|
+
const tagMap = {};
|
|
514
|
+
|
|
515
|
+
this.data.normalizedTagOptions.forEach((option) => {
|
|
516
|
+
tagMap[option.value] = option;
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
this.triggerEvent("confirm", {
|
|
520
|
+
value,
|
|
521
|
+
tagValue,
|
|
522
|
+
dates: value.map((date) => ({
|
|
523
|
+
...(dateItemMap[date] || {}),
|
|
524
|
+
date
|
|
525
|
+
})),
|
|
526
|
+
tags: tagValue.map((valueItem) => tagMap[valueItem]).filter(Boolean)
|
|
527
|
+
});
|
|
528
|
+
},
|
|
529
|
+
handleClose(event) {
|
|
530
|
+
this.triggerEvent("close", event.detail || {});
|
|
531
|
+
},
|
|
532
|
+
handleCloseTap() {
|
|
533
|
+
this.triggerEvent("close", {
|
|
534
|
+
source: "close"
|
|
535
|
+
});
|
|
536
|
+
},
|
|
537
|
+
emitError(source, message, error, force) {
|
|
538
|
+
const key = `${source}:${message}`;
|
|
539
|
+
if (!force && this._lastErrorKey === key) return;
|
|
540
|
+
|
|
541
|
+
this._lastErrorKey = key;
|
|
542
|
+
this.triggerEvent("error", {
|
|
543
|
+
source,
|
|
544
|
+
message,
|
|
545
|
+
error
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<mo-popup-page
|
|
2
|
+
show="{{show}}"
|
|
3
|
+
zIndex="{{zIndex}}"
|
|
4
|
+
closeOnMask="{{closeOnMask}}"
|
|
5
|
+
show-handle="{{false}}"
|
|
6
|
+
content-scrollable="{{false}}"
|
|
7
|
+
footer-mode="confirm"
|
|
8
|
+
confirmText="{{confirmText}}"
|
|
9
|
+
customClass="mo-calendar__popup mo-popup-page--content-flush"
|
|
10
|
+
bind:close="handleClose"
|
|
11
|
+
bind:confirm="handleConfirm"
|
|
12
|
+
>
|
|
13
|
+
<view class="mo-calendar {{customClass}}">
|
|
14
|
+
<view class="mo-calendar__header">
|
|
15
|
+
<view class="mo-calendar__header-side"></view>
|
|
16
|
+
<text class="mo-calendar__title">{{title}}</text>
|
|
17
|
+
<view class="mo-calendar__close" catchtap="handleCloseTap">
|
|
18
|
+
<mo-icon
|
|
19
|
+
name="close"
|
|
20
|
+
size="{{36}}"
|
|
21
|
+
color="#999999"
|
|
22
|
+
/>
|
|
23
|
+
</view>
|
|
24
|
+
</view>
|
|
25
|
+
|
|
26
|
+
<view class="mo-calendar__week">
|
|
27
|
+
<text wx:for="{{weekdays}}" wx:key="*this" class="mo-calendar__week-text">{{item}}</text>
|
|
28
|
+
</view>
|
|
29
|
+
|
|
30
|
+
<scroll-view class="mo-calendar__month-scroll" scroll-y type="list">
|
|
31
|
+
<view class="mo-calendar__months">
|
|
32
|
+
<block wx:for="{{months}}" wx:for-item="month" wx:for-index="monthIndex" wx:key="key">
|
|
33
|
+
<view class="mo-calendar__month">
|
|
34
|
+
<view class="mo-calendar__month-header">
|
|
35
|
+
<text class="mo-calendar__month-title">{{month.title}}</text>
|
|
36
|
+
</view>
|
|
37
|
+
<view class="mo-calendar__days">
|
|
38
|
+
<view
|
|
39
|
+
wx:for="{{month.days}}"
|
|
40
|
+
wx:for-item="day"
|
|
41
|
+
wx:for-index="dayIndex"
|
|
42
|
+
wx:key="key"
|
|
43
|
+
class="{{day.className}}"
|
|
44
|
+
data-month-index="{{monthIndex}}"
|
|
45
|
+
data-day-index="{{dayIndex}}"
|
|
46
|
+
bindtap="handleDayTap"
|
|
47
|
+
>
|
|
48
|
+
<block wx:if="{{!day.empty}}">
|
|
49
|
+
<view class="{{day.contentClassName}}">
|
|
50
|
+
<text class="mo-calendar__day-number">{{day.day}}</text>
|
|
51
|
+
<text wx:if="{{day.subText}}" class="mo-calendar__day-sub">{{day.subText}}</text>
|
|
52
|
+
</view>
|
|
53
|
+
<text wx:if="{{day.tagText}}" class="mo-calendar__day-badge">{{day.tagText}}</text>
|
|
54
|
+
</block>
|
|
55
|
+
</view>
|
|
56
|
+
</view>
|
|
57
|
+
</view>
|
|
58
|
+
</block>
|
|
59
|
+
</view>
|
|
60
|
+
</scroll-view>
|
|
61
|
+
|
|
62
|
+
<view wx:if="{{hasTags}}" class="mo-calendar__tags">
|
|
63
|
+
<text class="mo-calendar__tag-title">{{tagTitle}}</text>
|
|
64
|
+
<scroll-view class="mo-calendar__tag-scroll" type="list" scroll-x enable-flex style="flex-direction: row;">
|
|
65
|
+
<view class="mo-calendar__tag-list">
|
|
66
|
+
<view
|
|
67
|
+
wx:for="{{normalizedTagOptions}}"
|
|
68
|
+
wx:key="value"
|
|
69
|
+
class="{{item.className}}"
|
|
70
|
+
data-index="{{index}}"
|
|
71
|
+
bindtap="handleTagTap"
|
|
72
|
+
>
|
|
73
|
+
<text class="mo-calendar__tag-label">{{item.label}}</text>
|
|
74
|
+
</view>
|
|
75
|
+
</view>
|
|
76
|
+
</scroll-view>
|
|
77
|
+
</view>
|
|
78
|
+
</view>
|
|
79
|
+
</mo-popup-page>
|