@netang/quasar 0.2.30 → 0.2.32

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