@netang/quasar 0.0.101 → 0.0.102

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.
Files changed (164) hide show
  1. package/.editorconfig +12 -0
  2. package/LICENSE +21 -21
  3. package/README.md +11 -11
  4. package/_docs/docs/.vuepress/client.js +8 -8
  5. package/_docs/docs/.vuepress/config.js +40 -40
  6. package/_docs/docs/.vuepress/configs/index.js +2 -2
  7. package/_docs/docs/.vuepress/configs/navbar/index.js +1 -1
  8. package/_docs/docs/.vuepress/configs/navbar/zh.js +16 -16
  9. package/_docs/docs/.vuepress/configs/sidebar/index.js +1 -1
  10. package/_docs/docs/.vuepress/configs/sidebar/zh.js +75 -75
  11. package/_docs/docs/.vuepress/public/css/index.css +3 -3
  12. package/_docs/docs/.vuepress/styles/index.scss +3 -3
  13. package/_docs/docs/components/column-title.md +25 -25
  14. package/_docs/docs/components/data.md +66 -66
  15. package/_docs/docs/components/dialog.md +59 -59
  16. package/_docs/docs/components/dragger.md +26 -26
  17. package/_docs/docs/components/editor-code.md +16 -16
  18. package/_docs/docs/components/empty.md +13 -13
  19. package/_docs/docs/components/field-date.md +16 -16
  20. package/_docs/docs/components/field-text.md +57 -57
  21. package/_docs/docs/components/field-tree.md +21 -21
  22. package/_docs/docs/components/img.md +25 -25
  23. package/_docs/docs/components/input-number.md +21 -21
  24. package/_docs/docs/components/list-menu-item.md +21 -21
  25. package/_docs/docs/components/list-menu.md +21 -21
  26. package/_docs/docs/components/power-page.md +21 -21
  27. package/_docs/docs/components/price.md +21 -21
  28. package/_docs/docs/components/render.md +12 -12
  29. package/_docs/docs/components/search-item.md +10 -10
  30. package/_docs/docs/components/search.md +12 -12
  31. package/_docs/docs/components/select.md +11 -11
  32. package/_docs/docs/components/splitter.md +15 -15
  33. package/_docs/docs/components/table-column-fixed.md +20 -20
  34. package/_docs/docs/components/table-pagination.md +20 -20
  35. package/_docs/docs/components/table-splitter.md +20 -20
  36. package/_docs/docs/components/table-summary.md +20 -20
  37. package/_docs/docs/components/table.md +25 -25
  38. package/_docs/docs/components/thumbnail.md +18 -18
  39. package/_docs/docs/components/toolbar.md +9 -9
  40. package/_docs/docs/components/uploader-query.md +19 -19
  41. package/_docs/docs/components/uploader.md +16 -16
  42. package/_docs/docs/components/value-format.md +26 -26
  43. package/_docs/docs/index.md +1 -1
  44. package/_docs/docs/utils/alert.md +26 -26
  45. package/_docs/docs/utils/area.md +112 -112
  46. package/_docs/docs/utils/arr.md +80 -80
  47. package/_docs/docs/utils/auth.md +101 -101
  48. package/_docs/docs/utils/bus.md +18 -18
  49. package/_docs/docs/utils/confirm.md +31 -31
  50. package/_docs/docs/utils/copy.md +22 -22
  51. package/_docs/docs/utils/dialog.md +98 -98
  52. package/_docs/docs/utils/dict.md +50 -50
  53. package/_docs/docs/utils/dictOptions.md +27 -27
  54. package/_docs/docs/utils/form.md +33 -33
  55. package/_docs/docs/utils/getData.md +60 -60
  56. package/_docs/docs/utils/getFile.md +21 -21
  57. package/_docs/docs/utils/getImage.md +33 -33
  58. package/_docs/docs/utils/getTime.md +51 -51
  59. package/_docs/docs/utils/index.md +1 -1
  60. package/_docs/docs/utils/loading.md +18 -18
  61. package/_docs/docs/utils/notify.md +29 -29
  62. package/_docs/docs/utils/power.md +353 -353
  63. package/_docs/docs/utils/previewImage.md +11 -11
  64. package/_docs/docs/utils/price.md +45 -45
  65. package/_docs/docs/utils/rule.md +30 -30
  66. package/_docs/docs/utils/ruleValid.md +31 -31
  67. package/_docs/docs/utils/symbols.md +30 -30
  68. package/_docs/docs/utils/table.md +194 -194
  69. package/_docs/docs/utils/timestamp.md +27 -27
  70. package/_docs/docs/utils/toast.md +27 -27
  71. package/_docs/docs/utils/tree.md +174 -174
  72. package/_docs/docs/utils/uploader.md +29 -29
  73. package/_docs/package.json +11 -11
  74. package/components/column-title/index.vue +37 -37
  75. package/components/data/index.vue +20 -20
  76. package/components/dialog/index.vue +372 -372
  77. package/components/dragger/index.vue +203 -203
  78. package/components/drawer/index.vue +303 -303
  79. package/components/editor-code/index.vue +289 -289
  80. package/components/empty/index.vue +71 -71
  81. package/components/field-date/index.vue +850 -850
  82. package/components/field-date/methods.js +100 -100
  83. package/components/field-table/index.vue +1222 -1222
  84. package/components/field-text/index.vue +165 -165
  85. package/components/field-tree/index.vue +739 -659
  86. package/components/img/index.vue +202 -202
  87. package/components/input-number/index.vue +546 -546
  88. package/components/list-menu/index.vue +149 -149
  89. package/components/list-menu-item/index.vue +79 -79
  90. package/components/power-page/index.vue +92 -92
  91. package/components/price/index.vue +188 -188
  92. package/components/private/components/index.js +11 -11
  93. package/components/private/components/move-to-tree/index.vue +154 -154
  94. package/components/private/edit-power-data/index.vue +816 -816
  95. package/components/private/table-visible-columns-button/index.vue +109 -109
  96. package/components/render/index.vue +150 -150
  97. package/components/search/index.vue +222 -222
  98. package/components/search-item/index.vue +210 -210
  99. package/components/select/index.vue +177 -177
  100. package/components/splitter/index.vue +415 -415
  101. package/components/table/index.vue +456 -456
  102. package/components/table-column-fixed/index.vue +112 -112
  103. package/components/table-pagination/index.vue +192 -192
  104. package/components/table-splitter/index.vue +360 -360
  105. package/components/table-summary/index.vue +110 -110
  106. package/components/thumbnail/index.vue +72 -72
  107. package/components/toolbar/container.vue +31 -31
  108. package/components/toolbar/index.vue +136 -136
  109. package/components/uploader/index.vue +158 -158
  110. package/components/uploader-query/index.vue +758 -758
  111. package/components/value-format/index.vue +274 -274
  112. package/configs/area3.js +1 -1
  113. package/docs/css/index.css +3 -3
  114. package/package.json +24 -24
  115. package/sass/common.scss +174 -174
  116. package/sass/index.scss +14 -14
  117. package/sass/line.scss +39 -39
  118. package/sass/quasar/btn.scss +46 -46
  119. package/sass/quasar/common.scss +3 -3
  120. package/sass/quasar/dialog.scss +7 -7
  121. package/sass/quasar/drawer.scss +6 -6
  122. package/sass/quasar/field.scss +243 -243
  123. package/sass/quasar/loading.scss +6 -6
  124. package/sass/quasar/menu.scss +8 -8
  125. package/sass/quasar/table.scss +150 -150
  126. package/sass/quasar/toolbar.scss +22 -22
  127. package/store/index.js +29 -29
  128. package/utils/$auth.js +127 -127
  129. package/utils/$form.js +56 -56
  130. package/utils/$power.js +1215 -1215
  131. package/utils/$rule.js +13 -13
  132. package/utils/$ruleValid.js +10 -10
  133. package/utils/$table.js +999 -999
  134. package/utils/$tree.js +713 -713
  135. package/utils/alert.js +12 -12
  136. package/utils/area.js +400 -400
  137. package/utils/arr.js +51 -51
  138. package/utils/bus.js +6 -6
  139. package/utils/config.js +52 -52
  140. package/utils/confirm.js +11 -11
  141. package/utils/copy.js +30 -30
  142. package/utils/dialog.js +36 -36
  143. package/utils/dict.js +21 -21
  144. package/utils/dictOptions.js +28 -28
  145. package/utils/getData.js +73 -73
  146. package/utils/getFile.js +40 -40
  147. package/utils/getImage.js +153 -153
  148. package/utils/getTime.js +106 -106
  149. package/utils/index.js +61 -61
  150. package/utils/loading.js +15 -15
  151. package/utils/notify.js +13 -13
  152. package/utils/previewImage.js +10 -10
  153. package/utils/price.js +18 -18
  154. package/utils/symbols.js +18 -18
  155. package/utils/timestamp.js +18 -18
  156. package/utils/toast.js +13 -13
  157. package/utils/uploader/aliyun.js +6 -6
  158. package/utils/uploader/local.js +8 -8
  159. package/utils/uploader/qiniu.js +321 -321
  160. package/utils/uploader.js +1059 -1059
  161. package/utils/useAuth.js +30 -30
  162. package/utils/useRouter.js +47 -47
  163. package/utils/useSearch.js +496 -496
  164. package/utils/useUploader.js +53 -53
@@ -1,850 +1,850 @@
1
- <template>
2
- <q-field
3
- :model-value="modelValue"
4
- :readonly="readonly"
5
- @clear="onClear"
6
- v-bind="$attrs"
7
- >
8
- <template v-slot:control>
9
-
10
- <!-- 显示值 -->
11
- <div v-if="showValue">{{showValue}}</div>
12
-
13
- <!-- 显示占位符 -->
14
- <div class="n-placeholder" v-else-if="placeholder">{{placeholder}}</div>
15
- </template>
16
-
17
- <template v-slot:before v-if="$slots.before">
18
- <slot name="before" />
19
- </template>
20
- <template v-slot:prepend v-if="$slots.prepend">
21
- <slot name="prepend" />
22
- </template>
23
- <template v-slot:append v-if="$slots.append">
24
- <slot name="append" />
25
- </template>
26
- <template v-slot:after v-if="$slots.after">
27
- <slot name="after" />
28
- </template>
29
-
30
- <q-popup-proxy
31
- ref="popupRef"
32
- no-refocus
33
- no-focus
34
- @before-show="onPopupBeforeShow"
35
- @hide="onPopupHide"
36
- v-if="! readonly"
37
- >
38
- <!-- 单选 -->
39
- <template v-if="isSelect">
40
- <div class="date__select">
41
- <div class="row flex">
42
- <q-scroll-area
43
- ref="scrollRef"
44
- :style="{
45
- width: selectLists.length === 1 ? '136px' : '80px',
46
- height: '300px'
47
- }"
48
- v-for="(selectItem, selectItemIndex) in selectLists"
49
- :key="`list-${selectItemIndex}`"
50
- >
51
- <q-list>
52
- <q-item
53
- v-for="(item, itemIndex) in selectItem.lists"
54
- :key="`item-${selectItemIndex}-${itemIndex}`"
55
- :active="dateValue[selectItem.type] !== '' && dateValue[selectItem.type] == item[0]"
56
- :active-class="$q.dark.isActive ? 'bg-grey-14 text-white' : 'bg-grey-3 text-dark'"
57
- @click="onSelect(selectItem.type, item[0])"
58
- dense
59
- clickable
60
- >
61
- <q-item-section>{{item[1]}}</q-item-section>
62
- </q-item>
63
- </q-list>
64
- </q-scroll-area>
65
- </div>
66
-
67
- <!-- 底部按钮 -->
68
- <div class="date__footer row items-center justify-end q-pa-sm" v-if="type !== 'year'">
69
- <q-btn label="取消" color="primary" flat @click="onCancel" v-close-popup />
70
- <q-btn label="确定" color="primary" flat v-close-popup />
71
- </div>
72
- </div>
73
- </template>
74
-
75
- <!-- 选择日期范围 -->
76
- <q-date
77
- :model-value="dateValue"
78
- :range="isRange"
79
- @update:model-value="onUpdateDateValue"
80
- minimal
81
- v-else
82
- >
83
- <div class="date__time row q-gutter-sm" v-if="isDatetime">
84
- <q-input
85
- class="n-field-fieldset n-flex-1"
86
- :model-value="timeValue.from"
87
- @update:model-value="onUpdateTimeValueFrom"
88
- outlined
89
- :label="type === 'datetimerange' ? `时间 起` : '选择时间'"
90
- stack-label
91
- type="time"
92
- :step="showSecond ? '1' : '0'"
93
- dense
94
- />
95
- <q-input
96
- class="n-field-fieldset n-flex-1"
97
- :model-value="timeValue.to"
98
- @update:model-value="onUpdateTimeValueTo"
99
- outlined
100
- label="时间 止"
101
- stack-label
102
- :step="showSecond ? '1' : '0'"
103
- type="time"
104
- dense
105
- v-if="type === 'datetimerange'"
106
- />
107
- </div>
108
-
109
- <!-- 操作 -->
110
- <div class="date__settings" v-if="isRange">
111
- <q-scroll-area style="height:40px;">
112
- <div class="row no-wrap">
113
- <q-chip
114
- v-for="(item, index) in quickRange"
115
- :key="`quick-${index}`"
116
- size="sm"
117
- :ripple="false"
118
- clickable
119
- @click="onQuickRange(index)"
120
- flat
121
- >{{item}}</q-chip>
122
- </div>
123
- </q-scroll-area>
124
- </div>
125
-
126
- <!-- 底部按钮 -->
127
- <div class="date__settings row items-center justify-end" v-if="isDatetime || type === 'daterange'">
128
- <q-btn label="取消" color="primary" flat @click="onCancel" v-close-popup />
129
- <q-btn label="确定" color="primary" flat v-close-popup />
130
- </div>
131
- </q-date>
132
-
133
- </q-popup-proxy>
134
- </q-field>
135
- </template>
136
-
137
- <script>
138
- import { ref, reactive, computed, watch, nextTick } from 'vue'
139
- import { date as quasarDate } from 'quasar'
140
-
141
- import $n_padStart from 'lodash/padStart'
142
- import $n_isNil from 'lodash/isNil'
143
-
144
- import $n_forEach from '@netang/utils/forEach'
145
- import $n_indexOf from '@netang/utils/indexOf'
146
- import $n_isRequired from '@netang/utils/isRequired'
147
- import $n_isValidValue from '@netang/utils/isValidValue'
148
- import $n_numberDeep from '@netang/utils/numberDeep'
149
- import $n_isDate from '@netang/utils/isDate'
150
- import $n_dateObject from '@netang/utils/dateObject'
151
- import $n_ymd from '@netang/utils/ymd'
152
-
153
- import { quickRange, getQuickRange } from './methods'
154
-
155
- export default {
156
-
157
- /**
158
- * 标识
159
- */
160
- name: 'NFieldDate',
161
-
162
- /**
163
- * 声明属性
164
- */
165
- props: {
166
- // 值 v-model
167
- modelValue: {
168
- required: true,
169
- },
170
- // 结束值
171
- end: [String, Number],
172
- // 类型, 可选值 year month day time datetime daterange datetimerange
173
- type: {
174
- type: String,
175
- default: 'day',
176
- },
177
- // 是否截止日期
178
- isEndDate: Boolean,
179
- // 是否显示秒
180
- showSecond: Boolean,
181
- // 显示在输入框中的格式
182
- format: String,
183
- // 绑定值的格式(默认:秒时间戳)
184
- // 格式 YYYY-MM-DD HH:mm:ss
185
- valueFormat: {
186
- type: String,
187
- default: 'X',
188
- },
189
- // 占位符
190
- placeholder: String,
191
- // 是否只读
192
- readonly: Boolean,
193
- },
194
-
195
- /**
196
- * 声明事件
197
- */
198
- emits: [
199
- 'update:modelValue',
200
- 'update:end',
201
- ],
202
-
203
- /**
204
- * 组合式
205
- */
206
- setup(props, { emit }) {
207
-
208
- // ==========【计算属性】=========================================================================================
209
-
210
- // 是否为选择
211
- const isSelect = computed(function() {
212
- return $n_indexOf(['year', 'month', 'time'], props.type) > -1
213
- })
214
-
215
- // 是否为范围
216
- const isRange = computed(function() {
217
- return $n_indexOf(['daterange', 'datetimerange'], props.type) > -1
218
- })
219
-
220
- // 是否为选择时间
221
- const isDatetime = computed(function() {
222
- return $n_indexOf(['datetime', 'datetimerange'], props.type) > -1
223
- })
224
-
225
- // 选择数据列表
226
- const selectLists = computed(function () {
227
-
228
- const arr = []
229
-
230
- // 如果是选择时间
231
- if (props.type === 'time') {
232
- const hh = {
233
- type: 'hh',
234
- lists: []
235
- }
236
- for (let i = 0; i <= 23; i++) {
237
- hh.lists.push([i, $n_padStart(String(i), 2, '0')])
238
- }
239
- const ii = {
240
- type: 'ii',
241
- lists: []
242
- }
243
- for (let i = 0; i <= 59; i++) {
244
- ii.lists.push([i, $n_padStart(String(i), 2, '0')])
245
- }
246
- arr.push(hh, ii)
247
- if (props.showSecond) {
248
- const ss = {
249
- type: 'ss',
250
- lists: []
251
- }
252
- for (let i = 0; i <= 59; i++) {
253
- ss.lists.push([i, $n_padStart(String(i), 2, '0')])
254
- }
255
- arr.push(ss)
256
- }
257
-
258
- return arr
259
- }
260
-
261
- // 如果是选择年
262
- const year = new Date().getFullYear()
263
-
264
- const y = {
265
- type: 'y',
266
- lists: []
267
- }
268
- for (let j = year + 10; j >= year - 80; j--) {
269
- y.lists.push([j, j])
270
- }
271
- arr.push(y)
272
-
273
- if (props.type === 'year') {
274
- return arr
275
- }
276
-
277
- const mm = {
278
- type: 'mm',
279
- lists: []
280
- }
281
- for (let i = 1; i <= 12; i++) {
282
- mm.lists.push([i, $n_padStart(String(i), 2, '0')])
283
- }
284
-
285
- arr.push(mm)
286
-
287
- return arr
288
- })
289
-
290
- // ==========【数据】============================================================================================
291
-
292
- // 弹出层节点
293
- const popupRef = ref(null)
294
-
295
- // 滚动层节点
296
- const scrollRef = ref(null)
297
-
298
- // 日期值
299
- const dateValue = ref(formatDateValue())
300
-
301
- // 时间值
302
- const timeValue = reactive(formatTimeValue())
303
-
304
- // 显示值
305
- const showValue = ref(updateValue(dateValue.value, timeValue, false))
306
-
307
- // 记录原始值
308
- let oldModelValue = props.modelValue
309
- let oldEnd = props.end
310
-
311
- // ==========【监听数据】=========================================================================================
312
-
313
- /**
314
- * 监听声明值
315
- */
316
- watch([()=>props.modelValue, ()=>props.end, ()=>props.type], function() {
317
- dateValue.value = formatDateValue()
318
- Object.assign(timeValue, formatTimeValue())
319
-
320
- showValue.value = updateValue(dateValue.value, timeValue, false)
321
- })
322
-
323
- // ==========【方法】=============================================================================================
324
-
325
- /**
326
- * 格式化日期值
327
- */
328
- function formatDateValue() {
329
-
330
- let val = props.modelValue
331
- if (val === null) {
332
- return null
333
- }
334
-
335
- // 如果是选择数据
336
- if (isSelect.value) {
337
-
338
- const obj = {}
339
-
340
- // 如果是选择时间
341
- if (props.type === 'time') {
342
-
343
- // 初始化时间数据
344
- Object.assign(obj, {
345
- hh: '',
346
- ii: '',
347
- })
348
-
349
- // 如果是这种格式 06:59 的时间
350
- if (
351
- ! $n_isDate(val)
352
- && $n_indexOf(val, ':') > -1
353
- ) {
354
- val = quasarDate.formatDate(Date.now(), `YYYY-MM-DD ${val}`)
355
- }
356
-
357
- if ($n_isDate(val)) {
358
-
359
- const { hh, ii, ss } = $n_dateObject(val)
360
-
361
- // 设置时间数据
362
- Object.assign(obj, {
363
- hh,
364
- ii,
365
- })
366
-
367
- // 设置秒数据
368
- if (props.showSecond) {
369
- obj.ss = ss
370
- }
371
-
372
- } else if (props.showSecond) {
373
- obj.ss = ''
374
- }
375
-
376
- // 否则是选择年月
377
- } else {
378
-
379
- obj.y = ''
380
-
381
- // 如果是选择年
382
- if (props.type === 'year') {
383
-
384
- // 如果有值
385
- if (val) {
386
-
387
- // 如果值长度为 4
388
- if (String(val).length === 4) {
389
- obj.y = val
390
-
391
- // 否则如果是日期格式
392
- } else if ($n_isDate(val)) {
393
- const { y } = $n_dateObject(val)
394
- obj.y = y
395
- }
396
- }
397
-
398
- return obj
399
- }
400
-
401
- // 否则是选择月
402
-
403
- // 如果是这样的格式 202207, 则转换为 2022-07
404
- const newVal = $n_ymd.toString(val)
405
- if (newVal) {
406
- val = newVal
407
- }
408
-
409
- if ($n_isDate(val)) {
410
- const { y, mm } = $n_dateObject(val)
411
- Object.assign(obj, {
412
- y,
413
- mm,
414
- })
415
- } else {
416
- obj.mm = ''
417
- }
418
- }
419
-
420
- return obj
421
- }
422
-
423
- // 否则是日期选择
424
- let from = ''
425
- let to = ''
426
-
427
- // 如果是这样的格式 20220708, 则转换为 2022-07-08
428
- const newVal = $n_ymd.toString(val)
429
- if (newVal) {
430
- val = newVal
431
- }
432
-
433
- if ($n_isDate(val)) {
434
- const { y, mm, dd } = $n_dateObject(val)
435
- from = `${y}/${mm}/${dd}`
436
-
437
- // 如果不是日期选择范围, 则返回单个日期
438
- if (! isRange.value) {
439
- return from
440
- }
441
- }
442
-
443
- // 如果是日期选择范围
444
- if (isRange.value && $n_isDate(props.end)) {
445
- const { y, mm, dd } = $n_dateObject(props.end)
446
- to = `${y}/${mm}/${dd}`
447
- }
448
-
449
- return {
450
- from,
451
- to,
452
- }
453
- }
454
-
455
- /**
456
- * 格式化时间值
457
- */
458
- function formatTimeValue() {
459
-
460
- const obj = {
461
- from: '',
462
- to: '',
463
- }
464
-
465
- if ($n_isDate(props.modelValue)) {
466
- const { hh, ii, ss } = $n_dateObject(props.modelValue)
467
- obj.from = `${hh}:${ii}`
468
- if (props.showSecond) {
469
- obj.from += `:${ss}`
470
- }
471
-
472
- // 如果不是范围日期 && 是结束日期
473
- } else if (! isRange.value && props.isEndDate) {
474
- obj.from = props.showSecond ? '23:59:59' : '23:59'
475
- } else {
476
- obj.from = props.showSecond ? '00:00:00' : '00:00'
477
- }
478
-
479
- if (isRange.value && $n_isDate(props.end)) {
480
- const { hh, ii, ss } = $n_dateObject(props.end)
481
- obj.to = `${hh}:${ii}`
482
- if (props.showSecond) {
483
- obj.to += `:${ss}`
484
- }
485
- } else {
486
- obj.to = props.showSecond ? '23:59:59' : '23:59'
487
- }
488
-
489
- return obj
490
- }
491
-
492
- /**
493
- * 更新值
494
- */
495
- function updateValue(dateValue, timeValue, isEmit = true) {
496
-
497
- let format = ''
498
-
499
- if (isSelect.value) {
500
-
501
- let val = ''
502
-
503
- // 如果是选择时间
504
- if (props.type === 'time') {
505
-
506
- if (! $n_isValidValue(dateValue.hh) && ! $n_isValidValue(dateValue.ii)) {
507
- return ''
508
- }
509
-
510
- format = 'HH:mm'
511
- if (props.showSecond) {
512
- format += ':ss'
513
- }
514
- val = quasarDate.formatDate(Date.now(), `YYYY-MM-DD ${dateValue.hh !== '' ? dateValue.hh : '00'}:${dateValue.ii !== '' ? dateValue.ii : '00'}${props.showSecond && dateValue.ss !== '' ? dateValue.ss : (props.isEndDate ? ':59' : ':00')}`)
515
-
516
- // 否则是选择年月
517
- } else {
518
- if (! $n_isValidValue(dateValue.y)) {
519
- return ''
520
- }
521
-
522
- const isMonth = props.type === 'month'
523
- if (isMonth) {
524
- if (! $n_isValidValue(dateValue.mm)) {
525
- return ''
526
- }
527
-
528
- format = 'YYYY-MM'
529
- val = quasarDate[props.isEndDate ? 'endOfDate' : 'startOfDate'](new Date(`${dateValue.y}-${dateValue.mm}`), 'month')
530
-
531
- } else {
532
- format = 'YYYY'
533
- val = quasarDate[props.isEndDate ? 'endOfDate' : 'startOfDate'](new Date(`${dateValue.y}-01`), 'year')
534
- }
535
- }
536
-
537
- if (props.format) {
538
- format = props.format
539
- }
540
-
541
- if (isEmit) {
542
- onEmit('update:modelValue', quasarDate.formatDate(val, props.valueFormat))
543
- } else {
544
- return quasarDate.formatDate(val, format)
545
- }
546
- return ''
547
- }
548
-
549
- if (! $n_isRequired(dateValue)) {
550
- return ''
551
- }
552
-
553
- if (isRange.value) {
554
-
555
- let {
556
- from,
557
- to,
558
- } = dateValue
559
-
560
- if (
561
- ! $n_isValidValue(from)
562
- || ! $n_isValidValue(to)
563
- ) {
564
- return ''
565
- }
566
-
567
- from += ' '
568
- to += ' '
569
- format = 'YYYY-MM-DD'
570
-
571
- if (props.type === 'datetimerange') {
572
- from += `${timeValue.from}`
573
- to += `${timeValue.to}`
574
- format += ' HH:mm'
575
- if (props.showSecond) {
576
- format += ':ss'
577
- } else {
578
- from += ':59'
579
- to += ':59'
580
- }
581
-
582
- } else {
583
- from += `00:00`
584
- to += `23:59`
585
- if (! props.showSecond) {
586
- from += ':00'
587
- to += ':59'
588
- }
589
- }
590
- if (props.format) {
591
- format = props.format
592
- }
593
-
594
- if (isEmit) {
595
- onEmit('update:modelValue', quasarDate.formatDate(from, props.valueFormat))
596
- onEmit('update:end', quasarDate.formatDate(to, props.valueFormat))
597
- } else {
598
- return quasarDate.formatDate(from, format) + ' - ' + quasarDate.formatDate(to, format)
599
- }
600
- return ''
601
- }
602
-
603
- let from = `${dateValue} `
604
- format = 'YYYY-MM-DD'
605
-
606
- if (props.type === 'datetime') {
607
- from += `${timeValue.from}`
608
- format += ' HH:mm'
609
- if (props.showSecond) {
610
- format += ':ss'
611
- } else {
612
- from += (props.isEndDate ? ':59' : ':00')
613
- }
614
- } else {
615
- from += (props.isEndDate ? '23:59' : '00:00')
616
- if (! props.showSecond) {
617
- from += (props.isEndDate ? ':59' : ':00')
618
- }
619
- }
620
- if (props.format) {
621
- format = props.format
622
- }
623
-
624
- if (isEmit) {
625
- onEmit('update:modelValue', quasarDate.formatDate(from, props.valueFormat))
626
- } else {
627
- return quasarDate.formatDate(from, format)
628
- }
629
-
630
- return ''
631
- }
632
-
633
- /**
634
- * 更新日期后回调
635
- */
636
- function onUpdateDateValue(val) {
637
-
638
- // 如果为 null, 则清空数据
639
- if ($n_isNil(val)) {
640
- emit('update:modelValue', null)
641
- if (isRange.value) {
642
- emit('update:end', null)
643
- }
644
-
645
- } else {
646
- updateValue(val, timeValue)
647
- }
648
-
649
- // 如是类型是天
650
- if (props.type === 'day') {
651
- // 则关闭弹出层
652
- popupRef.value.hide()
653
- }
654
- }
655
-
656
- /**
657
- * 更新日期时间起回调
658
- */
659
- function onUpdateTimeValueFrom(from) {
660
- updateValue(dateValue.value, Object.assign({}, timeValue, {
661
- from,
662
- }))
663
- }
664
-
665
- /**
666
- * 更新日期时间止回调
667
- */
668
- function onUpdateTimeValueTo(to) {
669
- updateValue(dateValue.value, Object.assign({}, timeValue, {
670
- to,
671
- }))
672
- }
673
-
674
- /**
675
- * 选择
676
- */
677
- function onSelect(type, value) {
678
-
679
- // 更新值
680
- const newValue = {}
681
- newValue[type] = value
682
-
683
- updateValue(Object.assign({}, dateValue.value, newValue), timeValue)
684
-
685
- // 如是类型是年
686
- if (props.type === 'year') {
687
- // 则关闭弹出层
688
- popupRef.value.hide()
689
- }
690
- }
691
-
692
- /**
693
- * 快捷范围
694
- */
695
- function onQuickRange(index) {
696
-
697
- const {
698
- date,
699
- time,
700
- } = getQuickRange(index, props.showSecond)
701
-
702
- if (date) {
703
- updateValue(date, time)
704
- }
705
- }
706
-
707
- /**
708
- * 取消
709
- */
710
- function onCancel() {
711
- // 还原原始值
712
- onEmit('update:modelValue', oldModelValue)
713
- if (isRange.value) {
714
- onEmit('update:end', oldEnd)
715
- }
716
- }
717
-
718
- /**
719
- * 提交
720
- */
721
- function onEmit(key, value) {
722
- emit(key, $n_numberDeep(value))
723
- }
724
-
725
- /**
726
- * 弹出层显示前回调
727
- */
728
- function onPopupBeforeShow() {
729
-
730
- // 如果为选择
731
- if (isSelect.value) {
732
- // 下次 DOM 更新
733
- nextTick(function() {
734
-
735
- // 遍历选择列表
736
- $n_forEach(selectLists.value, function(selectItem, selectItemIndex) {
737
- // 遍历选单个列表
738
- $n_forEach(selectItem.lists, function(item, itemIndex) {
739
- if (dateValue.value[selectItem.type] !== '' && dateValue.value[selectItem.type] == item[0]) {
740
- scrollRef.value[selectItemIndex].setScrollPosition('vertical', 32 * itemIndex, 0)
741
- return true
742
- }
743
- })
744
- })
745
-
746
- })
747
- }
748
- }
749
-
750
- /**
751
- * 弹出层隐藏后回调
752
- */
753
- function onPopupHide() {
754
-
755
- // 更新原始值
756
- oldModelValue = props.modelValue
757
- if (isRange.value) {
758
- oldEnd = props.end
759
- }
760
- }
761
-
762
- /**
763
- * 清空
764
- */
765
- function onClear() {
766
- emit('update:modelValue', null)
767
- if (isRange.value) {
768
- emit('update:end', null)
769
- }
770
- popupRef.value.hide()
771
- }
772
-
773
- // ==========【返回】=============================================================================================
774
-
775
- return {
776
- // 是否为选择
777
- isSelect,
778
- // 是否为范围
779
- isRange,
780
- // 是否为选择时间
781
- isDatetime,
782
- // 选择数据列表
783
- selectLists,
784
-
785
- // 弹出层节点
786
- popupRef,
787
- // 滚动层节点
788
- scrollRef,
789
- // 日期值
790
- dateValue,
791
- // 时间值
792
- timeValue,
793
- // 显示值
794
- showValue,
795
- // 快捷范围
796
- quickRange,
797
-
798
- // 更新日期后回调
799
- onUpdateDateValue,
800
- // 更新日期时间起回调
801
- onUpdateTimeValueFrom,
802
- // 更新日期时间止回调
803
- onUpdateTimeValueTo,
804
-
805
- // 选择
806
- onSelect,
807
- // 快捷范围
808
- onQuickRange,
809
- // 取消
810
- onCancel,
811
-
812
- // 弹出层显示前回调
813
- onPopupBeforeShow,
814
- // 弹出层隐藏后回调
815
- onPopupHide,
816
- // 清空
817
- onClear,
818
- }
819
- },
820
- }
821
- </script>
822
-
823
- <style lang="scss" scoped>
824
- @import "@/assets/sass/variables.scss";
825
-
826
- .date {
827
-
828
- // 选择容器
829
- &__select {
830
- background-color: #ffffff;
831
- }
832
-
833
- // 时间容器
834
- &__time {
835
- + .date__settings {
836
- // 等同 q-pt-sm
837
- padding-top: map-get($space-sm, 'y');
838
- }
839
- }
840
- }
841
-
842
- /**
843
- * 暗色
844
- */
845
- .body--dark {
846
- .date__select {
847
- background-color: $color-gray-86;
848
- }
849
- }
850
- </style>
1
+ <template>
2
+ <q-field
3
+ :model-value="modelValue"
4
+ :readonly="readonly"
5
+ @clear="onClear"
6
+ v-bind="$attrs"
7
+ >
8
+ <template v-slot:control>
9
+
10
+ <!-- 显示值 -->
11
+ <div v-if="showValue">{{showValue}}</div>
12
+
13
+ <!-- 显示占位符 -->
14
+ <div class="n-placeholder" v-else-if="placeholder">{{placeholder}}</div>
15
+ </template>
16
+
17
+ <template v-slot:before v-if="$slots.before">
18
+ <slot name="before" />
19
+ </template>
20
+ <template v-slot:prepend v-if="$slots.prepend">
21
+ <slot name="prepend" />
22
+ </template>
23
+ <template v-slot:append v-if="$slots.append">
24
+ <slot name="append" />
25
+ </template>
26
+ <template v-slot:after v-if="$slots.after">
27
+ <slot name="after" />
28
+ </template>
29
+
30
+ <q-popup-proxy
31
+ ref="popupRef"
32
+ no-refocus
33
+ no-focus
34
+ @before-show="onPopupBeforeShow"
35
+ @hide="onPopupHide"
36
+ v-if="! readonly"
37
+ >
38
+ <!-- 单选 -->
39
+ <template v-if="isSelect">
40
+ <div class="date__select">
41
+ <div class="row flex">
42
+ <q-scroll-area
43
+ ref="scrollRef"
44
+ :style="{
45
+ width: selectLists.length === 1 ? '136px' : '80px',
46
+ height: '300px'
47
+ }"
48
+ v-for="(selectItem, selectItemIndex) in selectLists"
49
+ :key="`list-${selectItemIndex}`"
50
+ >
51
+ <q-list>
52
+ <q-item
53
+ v-for="(item, itemIndex) in selectItem.lists"
54
+ :key="`item-${selectItemIndex}-${itemIndex}`"
55
+ :active="dateValue[selectItem.type] !== '' && dateValue[selectItem.type] == item[0]"
56
+ :active-class="$q.dark.isActive ? 'bg-grey-14 text-white' : 'bg-grey-3 text-dark'"
57
+ @click="onSelect(selectItem.type, item[0])"
58
+ dense
59
+ clickable
60
+ >
61
+ <q-item-section>{{item[1]}}</q-item-section>
62
+ </q-item>
63
+ </q-list>
64
+ </q-scroll-area>
65
+ </div>
66
+
67
+ <!-- 底部按钮 -->
68
+ <div class="date__footer row items-center justify-end q-pa-sm" v-if="type !== 'year'">
69
+ <q-btn label="取消" color="primary" flat @click="onCancel" v-close-popup />
70
+ <q-btn label="确定" color="primary" flat v-close-popup />
71
+ </div>
72
+ </div>
73
+ </template>
74
+
75
+ <!-- 选择日期范围 -->
76
+ <q-date
77
+ :model-value="dateValue"
78
+ :range="isRange"
79
+ @update:model-value="onUpdateDateValue"
80
+ minimal
81
+ v-else
82
+ >
83
+ <div class="date__time row q-gutter-sm" v-if="isDatetime">
84
+ <q-input
85
+ class="n-field-fieldset n-flex-1"
86
+ :model-value="timeValue.from"
87
+ @update:model-value="onUpdateTimeValueFrom"
88
+ outlined
89
+ :label="type === 'datetimerange' ? `时间 起` : '选择时间'"
90
+ stack-label
91
+ type="time"
92
+ :step="showSecond ? '1' : '0'"
93
+ dense
94
+ />
95
+ <q-input
96
+ class="n-field-fieldset n-flex-1"
97
+ :model-value="timeValue.to"
98
+ @update:model-value="onUpdateTimeValueTo"
99
+ outlined
100
+ label="时间 止"
101
+ stack-label
102
+ :step="showSecond ? '1' : '0'"
103
+ type="time"
104
+ dense
105
+ v-if="type === 'datetimerange'"
106
+ />
107
+ </div>
108
+
109
+ <!-- 操作 -->
110
+ <div class="date__settings" v-if="isRange">
111
+ <q-scroll-area style="height:40px;">
112
+ <div class="row no-wrap">
113
+ <q-chip
114
+ v-for="(item, index) in quickRange"
115
+ :key="`quick-${index}`"
116
+ size="sm"
117
+ :ripple="false"
118
+ clickable
119
+ @click="onQuickRange(index)"
120
+ flat
121
+ >{{item}}</q-chip>
122
+ </div>
123
+ </q-scroll-area>
124
+ </div>
125
+
126
+ <!-- 底部按钮 -->
127
+ <div class="date__settings row items-center justify-end" v-if="isDatetime || type === 'daterange'">
128
+ <q-btn label="取消" color="primary" flat @click="onCancel" v-close-popup />
129
+ <q-btn label="确定" color="primary" flat v-close-popup />
130
+ </div>
131
+ </q-date>
132
+
133
+ </q-popup-proxy>
134
+ </q-field>
135
+ </template>
136
+
137
+ <script>
138
+ import { ref, reactive, computed, watch, nextTick } from 'vue'
139
+ import { date as quasarDate } from 'quasar'
140
+
141
+ import $n_padStart from 'lodash/padStart'
142
+ import $n_isNil from 'lodash/isNil'
143
+
144
+ import $n_forEach from '@netang/utils/forEach'
145
+ import $n_indexOf from '@netang/utils/indexOf'
146
+ import $n_isRequired from '@netang/utils/isRequired'
147
+ import $n_isValidValue from '@netang/utils/isValidValue'
148
+ import $n_numberDeep from '@netang/utils/numberDeep'
149
+ import $n_isDate from '@netang/utils/isDate'
150
+ import $n_dateObject from '@netang/utils/dateObject'
151
+ import $n_ymd from '@netang/utils/ymd'
152
+
153
+ import { quickRange, getQuickRange } from './methods'
154
+
155
+ export default {
156
+
157
+ /**
158
+ * 标识
159
+ */
160
+ name: 'NFieldDate',
161
+
162
+ /**
163
+ * 声明属性
164
+ */
165
+ props: {
166
+ // 值 v-model
167
+ modelValue: {
168
+ required: true,
169
+ },
170
+ // 结束值
171
+ end: [String, Number],
172
+ // 类型, 可选值 year month day time datetime daterange datetimerange
173
+ type: {
174
+ type: String,
175
+ default: 'day',
176
+ },
177
+ // 是否截止日期
178
+ isEndDate: Boolean,
179
+ // 是否显示秒
180
+ showSecond: Boolean,
181
+ // 显示在输入框中的格式
182
+ format: String,
183
+ // 绑定值的格式(默认:秒时间戳)
184
+ // 格式 YYYY-MM-DD HH:mm:ss
185
+ valueFormat: {
186
+ type: String,
187
+ default: 'X',
188
+ },
189
+ // 占位符
190
+ placeholder: String,
191
+ // 是否只读
192
+ readonly: Boolean,
193
+ },
194
+
195
+ /**
196
+ * 声明事件
197
+ */
198
+ emits: [
199
+ 'update:modelValue',
200
+ 'update:end',
201
+ ],
202
+
203
+ /**
204
+ * 组合式
205
+ */
206
+ setup(props, { emit }) {
207
+
208
+ // ==========【计算属性】=========================================================================================
209
+
210
+ // 是否为选择
211
+ const isSelect = computed(function() {
212
+ return $n_indexOf(['year', 'month', 'time'], props.type) > -1
213
+ })
214
+
215
+ // 是否为范围
216
+ const isRange = computed(function() {
217
+ return $n_indexOf(['daterange', 'datetimerange'], props.type) > -1
218
+ })
219
+
220
+ // 是否为选择时间
221
+ const isDatetime = computed(function() {
222
+ return $n_indexOf(['datetime', 'datetimerange'], props.type) > -1
223
+ })
224
+
225
+ // 选择数据列表
226
+ const selectLists = computed(function () {
227
+
228
+ const arr = []
229
+
230
+ // 如果是选择时间
231
+ if (props.type === 'time') {
232
+ const hh = {
233
+ type: 'hh',
234
+ lists: []
235
+ }
236
+ for (let i = 0; i <= 23; i++) {
237
+ hh.lists.push([i, $n_padStart(String(i), 2, '0')])
238
+ }
239
+ const ii = {
240
+ type: 'ii',
241
+ lists: []
242
+ }
243
+ for (let i = 0; i <= 59; i++) {
244
+ ii.lists.push([i, $n_padStart(String(i), 2, '0')])
245
+ }
246
+ arr.push(hh, ii)
247
+ if (props.showSecond) {
248
+ const ss = {
249
+ type: 'ss',
250
+ lists: []
251
+ }
252
+ for (let i = 0; i <= 59; i++) {
253
+ ss.lists.push([i, $n_padStart(String(i), 2, '0')])
254
+ }
255
+ arr.push(ss)
256
+ }
257
+
258
+ return arr
259
+ }
260
+
261
+ // 如果是选择年
262
+ const year = new Date().getFullYear()
263
+
264
+ const y = {
265
+ type: 'y',
266
+ lists: []
267
+ }
268
+ for (let j = year + 10; j >= year - 80; j--) {
269
+ y.lists.push([j, j])
270
+ }
271
+ arr.push(y)
272
+
273
+ if (props.type === 'year') {
274
+ return arr
275
+ }
276
+
277
+ const mm = {
278
+ type: 'mm',
279
+ lists: []
280
+ }
281
+ for (let i = 1; i <= 12; i++) {
282
+ mm.lists.push([i, $n_padStart(String(i), 2, '0')])
283
+ }
284
+
285
+ arr.push(mm)
286
+
287
+ return arr
288
+ })
289
+
290
+ // ==========【数据】============================================================================================
291
+
292
+ // 弹出层节点
293
+ const popupRef = ref(null)
294
+
295
+ // 滚动层节点
296
+ const scrollRef = ref(null)
297
+
298
+ // 日期值
299
+ const dateValue = ref(formatDateValue())
300
+
301
+ // 时间值
302
+ const timeValue = reactive(formatTimeValue())
303
+
304
+ // 显示值
305
+ const showValue = ref(updateValue(dateValue.value, timeValue, false))
306
+
307
+ // 记录原始值
308
+ let oldModelValue = props.modelValue
309
+ let oldEnd = props.end
310
+
311
+ // ==========【监听数据】=========================================================================================
312
+
313
+ /**
314
+ * 监听声明值
315
+ */
316
+ watch([()=>props.modelValue, ()=>props.end, ()=>props.type], function() {
317
+ dateValue.value = formatDateValue()
318
+ Object.assign(timeValue, formatTimeValue())
319
+
320
+ showValue.value = updateValue(dateValue.value, timeValue, false)
321
+ })
322
+
323
+ // ==========【方法】=============================================================================================
324
+
325
+ /**
326
+ * 格式化日期值
327
+ */
328
+ function formatDateValue() {
329
+
330
+ let val = props.modelValue
331
+ if (val === null) {
332
+ return null
333
+ }
334
+
335
+ // 如果是选择数据
336
+ if (isSelect.value) {
337
+
338
+ const obj = {}
339
+
340
+ // 如果是选择时间
341
+ if (props.type === 'time') {
342
+
343
+ // 初始化时间数据
344
+ Object.assign(obj, {
345
+ hh: '',
346
+ ii: '',
347
+ })
348
+
349
+ // 如果是这种格式 06:59 的时间
350
+ if (
351
+ ! $n_isDate(val)
352
+ && $n_indexOf(val, ':') > -1
353
+ ) {
354
+ val = quasarDate.formatDate(Date.now(), `YYYY-MM-DD ${val}`)
355
+ }
356
+
357
+ if ($n_isDate(val)) {
358
+
359
+ const { hh, ii, ss } = $n_dateObject(val)
360
+
361
+ // 设置时间数据
362
+ Object.assign(obj, {
363
+ hh,
364
+ ii,
365
+ })
366
+
367
+ // 设置秒数据
368
+ if (props.showSecond) {
369
+ obj.ss = ss
370
+ }
371
+
372
+ } else if (props.showSecond) {
373
+ obj.ss = ''
374
+ }
375
+
376
+ // 否则是选择年月
377
+ } else {
378
+
379
+ obj.y = ''
380
+
381
+ // 如果是选择年
382
+ if (props.type === 'year') {
383
+
384
+ // 如果有值
385
+ if (val) {
386
+
387
+ // 如果值长度为 4
388
+ if (String(val).length === 4) {
389
+ obj.y = val
390
+
391
+ // 否则如果是日期格式
392
+ } else if ($n_isDate(val)) {
393
+ const { y } = $n_dateObject(val)
394
+ obj.y = y
395
+ }
396
+ }
397
+
398
+ return obj
399
+ }
400
+
401
+ // 否则是选择月
402
+
403
+ // 如果是这样的格式 202207, 则转换为 2022-07
404
+ const newVal = $n_ymd.toString(val)
405
+ if (newVal) {
406
+ val = newVal
407
+ }
408
+
409
+ if ($n_isDate(val)) {
410
+ const { y, mm } = $n_dateObject(val)
411
+ Object.assign(obj, {
412
+ y,
413
+ mm,
414
+ })
415
+ } else {
416
+ obj.mm = ''
417
+ }
418
+ }
419
+
420
+ return obj
421
+ }
422
+
423
+ // 否则是日期选择
424
+ let from = ''
425
+ let to = ''
426
+
427
+ // 如果是这样的格式 20220708, 则转换为 2022-07-08
428
+ const newVal = $n_ymd.toString(val)
429
+ if (newVal) {
430
+ val = newVal
431
+ }
432
+
433
+ if ($n_isDate(val)) {
434
+ const { y, mm, dd } = $n_dateObject(val)
435
+ from = `${y}/${mm}/${dd}`
436
+
437
+ // 如果不是日期选择范围, 则返回单个日期
438
+ if (! isRange.value) {
439
+ return from
440
+ }
441
+ }
442
+
443
+ // 如果是日期选择范围
444
+ if (isRange.value && $n_isDate(props.end)) {
445
+ const { y, mm, dd } = $n_dateObject(props.end)
446
+ to = `${y}/${mm}/${dd}`
447
+ }
448
+
449
+ return {
450
+ from,
451
+ to,
452
+ }
453
+ }
454
+
455
+ /**
456
+ * 格式化时间值
457
+ */
458
+ function formatTimeValue() {
459
+
460
+ const obj = {
461
+ from: '',
462
+ to: '',
463
+ }
464
+
465
+ if ($n_isDate(props.modelValue)) {
466
+ const { hh, ii, ss } = $n_dateObject(props.modelValue)
467
+ obj.from = `${hh}:${ii}`
468
+ if (props.showSecond) {
469
+ obj.from += `:${ss}`
470
+ }
471
+
472
+ // 如果不是范围日期 && 是结束日期
473
+ } else if (! isRange.value && props.isEndDate) {
474
+ obj.from = props.showSecond ? '23:59:59' : '23:59'
475
+ } else {
476
+ obj.from = props.showSecond ? '00:00:00' : '00:00'
477
+ }
478
+
479
+ if (isRange.value && $n_isDate(props.end)) {
480
+ const { hh, ii, ss } = $n_dateObject(props.end)
481
+ obj.to = `${hh}:${ii}`
482
+ if (props.showSecond) {
483
+ obj.to += `:${ss}`
484
+ }
485
+ } else {
486
+ obj.to = props.showSecond ? '23:59:59' : '23:59'
487
+ }
488
+
489
+ return obj
490
+ }
491
+
492
+ /**
493
+ * 更新值
494
+ */
495
+ function updateValue(dateValue, timeValue, isEmit = true) {
496
+
497
+ let format = ''
498
+
499
+ if (isSelect.value) {
500
+
501
+ let val = ''
502
+
503
+ // 如果是选择时间
504
+ if (props.type === 'time') {
505
+
506
+ if (! $n_isValidValue(dateValue.hh) && ! $n_isValidValue(dateValue.ii)) {
507
+ return ''
508
+ }
509
+
510
+ format = 'HH:mm'
511
+ if (props.showSecond) {
512
+ format += ':ss'
513
+ }
514
+ val = quasarDate.formatDate(Date.now(), `YYYY-MM-DD ${dateValue.hh !== '' ? dateValue.hh : '00'}:${dateValue.ii !== '' ? dateValue.ii : '00'}${props.showSecond && dateValue.ss !== '' ? dateValue.ss : (props.isEndDate ? ':59' : ':00')}`)
515
+
516
+ // 否则是选择年月
517
+ } else {
518
+ if (! $n_isValidValue(dateValue.y)) {
519
+ return ''
520
+ }
521
+
522
+ const isMonth = props.type === 'month'
523
+ if (isMonth) {
524
+ if (! $n_isValidValue(dateValue.mm)) {
525
+ return ''
526
+ }
527
+
528
+ format = 'YYYY-MM'
529
+ val = quasarDate[props.isEndDate ? 'endOfDate' : 'startOfDate'](new Date(`${dateValue.y}-${dateValue.mm}`), 'month')
530
+
531
+ } else {
532
+ format = 'YYYY'
533
+ val = quasarDate[props.isEndDate ? 'endOfDate' : 'startOfDate'](new Date(`${dateValue.y}-01`), 'year')
534
+ }
535
+ }
536
+
537
+ if (props.format) {
538
+ format = props.format
539
+ }
540
+
541
+ if (isEmit) {
542
+ onEmit('update:modelValue', quasarDate.formatDate(val, props.valueFormat))
543
+ } else {
544
+ return quasarDate.formatDate(val, format)
545
+ }
546
+ return ''
547
+ }
548
+
549
+ if (! $n_isRequired(dateValue)) {
550
+ return ''
551
+ }
552
+
553
+ if (isRange.value) {
554
+
555
+ let {
556
+ from,
557
+ to,
558
+ } = dateValue
559
+
560
+ if (
561
+ ! $n_isValidValue(from)
562
+ || ! $n_isValidValue(to)
563
+ ) {
564
+ return ''
565
+ }
566
+
567
+ from += ' '
568
+ to += ' '
569
+ format = 'YYYY-MM-DD'
570
+
571
+ if (props.type === 'datetimerange') {
572
+ from += `${timeValue.from}`
573
+ to += `${timeValue.to}`
574
+ format += ' HH:mm'
575
+ if (props.showSecond) {
576
+ format += ':ss'
577
+ } else {
578
+ from += ':59'
579
+ to += ':59'
580
+ }
581
+
582
+ } else {
583
+ from += `00:00`
584
+ to += `23:59`
585
+ if (! props.showSecond) {
586
+ from += ':00'
587
+ to += ':59'
588
+ }
589
+ }
590
+ if (props.format) {
591
+ format = props.format
592
+ }
593
+
594
+ if (isEmit) {
595
+ onEmit('update:modelValue', quasarDate.formatDate(from, props.valueFormat))
596
+ onEmit('update:end', quasarDate.formatDate(to, props.valueFormat))
597
+ } else {
598
+ return quasarDate.formatDate(from, format) + ' - ' + quasarDate.formatDate(to, format)
599
+ }
600
+ return ''
601
+ }
602
+
603
+ let from = `${dateValue} `
604
+ format = 'YYYY-MM-DD'
605
+
606
+ if (props.type === 'datetime') {
607
+ from += `${timeValue.from}`
608
+ format += ' HH:mm'
609
+ if (props.showSecond) {
610
+ format += ':ss'
611
+ } else {
612
+ from += (props.isEndDate ? ':59' : ':00')
613
+ }
614
+ } else {
615
+ from += (props.isEndDate ? '23:59' : '00:00')
616
+ if (! props.showSecond) {
617
+ from += (props.isEndDate ? ':59' : ':00')
618
+ }
619
+ }
620
+ if (props.format) {
621
+ format = props.format
622
+ }
623
+
624
+ if (isEmit) {
625
+ onEmit('update:modelValue', quasarDate.formatDate(from, props.valueFormat))
626
+ } else {
627
+ return quasarDate.formatDate(from, format)
628
+ }
629
+
630
+ return ''
631
+ }
632
+
633
+ /**
634
+ * 更新日期后回调
635
+ */
636
+ function onUpdateDateValue(val) {
637
+
638
+ // 如果为 null, 则清空数据
639
+ if ($n_isNil(val)) {
640
+ emit('update:modelValue', null)
641
+ if (isRange.value) {
642
+ emit('update:end', null)
643
+ }
644
+
645
+ } else {
646
+ updateValue(val, timeValue)
647
+ }
648
+
649
+ // 如是类型是天
650
+ if (props.type === 'day') {
651
+ // 则关闭弹出层
652
+ popupRef.value.hide()
653
+ }
654
+ }
655
+
656
+ /**
657
+ * 更新日期时间起回调
658
+ */
659
+ function onUpdateTimeValueFrom(from) {
660
+ updateValue(dateValue.value, Object.assign({}, timeValue, {
661
+ from,
662
+ }))
663
+ }
664
+
665
+ /**
666
+ * 更新日期时间止回调
667
+ */
668
+ function onUpdateTimeValueTo(to) {
669
+ updateValue(dateValue.value, Object.assign({}, timeValue, {
670
+ to,
671
+ }))
672
+ }
673
+
674
+ /**
675
+ * 选择
676
+ */
677
+ function onSelect(type, value) {
678
+
679
+ // 更新值
680
+ const newValue = {}
681
+ newValue[type] = value
682
+
683
+ updateValue(Object.assign({}, dateValue.value, newValue), timeValue)
684
+
685
+ // 如是类型是年
686
+ if (props.type === 'year') {
687
+ // 则关闭弹出层
688
+ popupRef.value.hide()
689
+ }
690
+ }
691
+
692
+ /**
693
+ * 快捷范围
694
+ */
695
+ function onQuickRange(index) {
696
+
697
+ const {
698
+ date,
699
+ time,
700
+ } = getQuickRange(index, props.showSecond)
701
+
702
+ if (date) {
703
+ updateValue(date, time)
704
+ }
705
+ }
706
+
707
+ /**
708
+ * 取消
709
+ */
710
+ function onCancel() {
711
+ // 还原原始值
712
+ onEmit('update:modelValue', oldModelValue)
713
+ if (isRange.value) {
714
+ onEmit('update:end', oldEnd)
715
+ }
716
+ }
717
+
718
+ /**
719
+ * 提交
720
+ */
721
+ function onEmit(key, value) {
722
+ emit(key, $n_numberDeep(value))
723
+ }
724
+
725
+ /**
726
+ * 弹出层显示前回调
727
+ */
728
+ function onPopupBeforeShow() {
729
+
730
+ // 如果为选择
731
+ if (isSelect.value) {
732
+ // 下次 DOM 更新
733
+ nextTick(function() {
734
+
735
+ // 遍历选择列表
736
+ $n_forEach(selectLists.value, function(selectItem, selectItemIndex) {
737
+ // 遍历选单个列表
738
+ $n_forEach(selectItem.lists, function(item, itemIndex) {
739
+ if (dateValue.value[selectItem.type] !== '' && dateValue.value[selectItem.type] == item[0]) {
740
+ scrollRef.value[selectItemIndex].setScrollPosition('vertical', 32 * itemIndex, 0)
741
+ return true
742
+ }
743
+ })
744
+ })
745
+
746
+ })
747
+ }
748
+ }
749
+
750
+ /**
751
+ * 弹出层隐藏后回调
752
+ */
753
+ function onPopupHide() {
754
+
755
+ // 更新原始值
756
+ oldModelValue = props.modelValue
757
+ if (isRange.value) {
758
+ oldEnd = props.end
759
+ }
760
+ }
761
+
762
+ /**
763
+ * 清空
764
+ */
765
+ function onClear() {
766
+ emit('update:modelValue', null)
767
+ if (isRange.value) {
768
+ emit('update:end', null)
769
+ }
770
+ popupRef.value.hide()
771
+ }
772
+
773
+ // ==========【返回】=============================================================================================
774
+
775
+ return {
776
+ // 是否为选择
777
+ isSelect,
778
+ // 是否为范围
779
+ isRange,
780
+ // 是否为选择时间
781
+ isDatetime,
782
+ // 选择数据列表
783
+ selectLists,
784
+
785
+ // 弹出层节点
786
+ popupRef,
787
+ // 滚动层节点
788
+ scrollRef,
789
+ // 日期值
790
+ dateValue,
791
+ // 时间值
792
+ timeValue,
793
+ // 显示值
794
+ showValue,
795
+ // 快捷范围
796
+ quickRange,
797
+
798
+ // 更新日期后回调
799
+ onUpdateDateValue,
800
+ // 更新日期时间起回调
801
+ onUpdateTimeValueFrom,
802
+ // 更新日期时间止回调
803
+ onUpdateTimeValueTo,
804
+
805
+ // 选择
806
+ onSelect,
807
+ // 快捷范围
808
+ onQuickRange,
809
+ // 取消
810
+ onCancel,
811
+
812
+ // 弹出层显示前回调
813
+ onPopupBeforeShow,
814
+ // 弹出层隐藏后回调
815
+ onPopupHide,
816
+ // 清空
817
+ onClear,
818
+ }
819
+ },
820
+ }
821
+ </script>
822
+
823
+ <style lang="scss" scoped>
824
+ @import "@/assets/sass/variables.scss";
825
+
826
+ .date {
827
+
828
+ // 选择容器
829
+ &__select {
830
+ background-color: #ffffff;
831
+ }
832
+
833
+ // 时间容器
834
+ &__time {
835
+ + .date__settings {
836
+ // 等同 q-pt-sm
837
+ padding-top: map-get($space-sm, 'y');
838
+ }
839
+ }
840
+ }
841
+
842
+ /**
843
+ * 暗色
844
+ */
845
+ .body--dark {
846
+ .date__select {
847
+ background-color: $color-gray-86;
848
+ }
849
+ }
850
+ </style>