@netang/quasar 0.2.19 → 0.2.21

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 (284) 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/dragger/index.vue +203 -203
  10. package/components/drawer/index.vue +303 -303
  11. package/components/editor-code/index.vue +325 -325
  12. package/components/empty/index.vue +82 -82
  13. package/components/field-date/index.vue +850 -850
  14. package/components/field-date/methods.js +100 -100
  15. package/components/field-table/index.vue +1482 -1482
  16. package/components/field-text/index.vue +165 -165
  17. package/components/field-tree/index.vue +754 -754
  18. package/components/img/index.vue +279 -279
  19. package/components/list-menu/index.vue +149 -149
  20. package/components/list-menu-item/index.vue +79 -79
  21. package/components/mixed-table/index.vue +532 -532
  22. package/components/mixed-table-splitter/index.vue +377 -377
  23. package/components/power-page/index.vue +96 -96
  24. package/components/price/index.vue +188 -188
  25. package/components/private/components/index.js +11 -11
  26. package/components/private/components/move-to-tree/index.vue +154 -154
  27. package/components/private/edit-power-data/index.vue +846 -846
  28. package/components/private/table-visible-columns-button/index.vue +114 -114
  29. package/components/render/index.vue +123 -123
  30. package/components/search/index.vue +231 -231
  31. package/components/search-item/index.vue +210 -210
  32. package/components/select/index.vue +177 -177
  33. package/components/splitter/index.vue +422 -422
  34. package/components/table/index.vue +513 -513
  35. package/components/table-column-fixed/index.vue +110 -110
  36. package/components/table-pagination/index.vue +192 -192
  37. package/components/table-summary/index.vue +107 -107
  38. package/components/thumbnail/index.vue +72 -72
  39. package/components/toolbar/index.vue +146 -146
  40. package/components/tree/index.vue +1728 -1728
  41. package/components/uploader/index.vue +195 -195
  42. package/components/uploader-query/index.vue +945 -945
  43. package/components/value-format/index.vue +274 -274
  44. package/configs/area3.js +1 -1
  45. package/docs/404.html +33 -33
  46. package/docs/assets/404.html-60b35caa.js +1 -1
  47. package/docs/assets/404.html-d1e63d77.js +1 -1
  48. package/docs/assets/alert.html-b2a2a72f.js +5 -5
  49. package/docs/assets/alert.html-ba46d137.js +1 -1
  50. package/docs/assets/app-9f30aa4b.js +6 -6
  51. package/docs/assets/area.html-01b9b58d.js +42 -42
  52. package/docs/assets/area.html-9a4fce6a.js +1 -1
  53. package/docs/assets/arr.html-145d27e7.js +1 -1
  54. package/docs/assets/arr.html-674e65ab.js +11 -11
  55. package/docs/assets/auth.html-579fa830.js +1 -1
  56. package/docs/assets/auth.html-8544ed95.js +8 -8
  57. package/docs/assets/bus.html-c71254aa.js +1 -1
  58. package/docs/assets/bus.html-dc7d3d19.js +6 -6
  59. package/docs/assets/column-title.html-c735cb5a.js +3 -3
  60. package/docs/assets/column-title.html-e9316762.js +1 -1
  61. package/docs/assets/confirm.html-ddfdc27f.js +10 -10
  62. package/docs/assets/confirm.html-ef3e2bef.js +1 -1
  63. package/docs/assets/copy.html-d20345b6.js +1 -1
  64. package/docs/assets/copy.html-ef8c8571.js +13 -13
  65. package/docs/assets/data.html-6432175d.js +30 -30
  66. package/docs/assets/data.html-a3b05d5b.js +1 -1
  67. package/docs/assets/dialog.html-1f698e5a.js +1 -1
  68. package/docs/assets/dialog.html-62902b83.js +68 -68
  69. package/docs/assets/dialog.html-baea77c9.js +1 -1
  70. package/docs/assets/dialog.html-bb082fc4.js +1 -1
  71. package/docs/assets/dict.html-1311da3d.js +23 -23
  72. package/docs/assets/dict.html-b96fbf0c.js +1 -1
  73. package/docs/assets/dictOptions.html-7c4f40a5.js +1 -1
  74. package/docs/assets/dictOptions.html-fb99d175.js +5 -5
  75. package/docs/assets/dragger.html-668d3efa.js +1 -1
  76. package/docs/assets/dragger.html-749d585a.js +1 -1
  77. package/docs/assets/editor-code.html-6ab26ea9.js +1 -1
  78. package/docs/assets/editor-code.html-d196205d.js +1 -1
  79. package/docs/assets/empty.html-1c139131.js +1 -1
  80. package/docs/assets/empty.html-1e9c441d.js +1 -1
  81. package/docs/assets/field-date.html-069fdb13.js +1 -1
  82. package/docs/assets/field-date.html-ad204aa9.js +1 -1
  83. package/docs/assets/field-table.html-ce480f03.js +1 -1
  84. package/docs/assets/field-table.html-d9236160.js +1 -1
  85. package/docs/assets/field-text.html-7277c62f.js +1 -1
  86. package/docs/assets/field-text.html-ccb4cecf.js +1 -1
  87. package/docs/assets/field-tree.html-519bfb45.js +1 -1
  88. package/docs/assets/field-tree.html-fdc748d6.js +1 -1
  89. package/docs/assets/form.html-2b562c37.js +2 -2
  90. package/docs/assets/form.html-75104cd5.js +1 -1
  91. package/docs/assets/framework-204010b2.js +5 -5
  92. package/docs/assets/getData.html-990e3787.js +1 -1
  93. package/docs/assets/getData.html-bb72025f.js +34 -34
  94. package/docs/assets/getFile.html-42368004.js +1 -1
  95. package/docs/assets/getFile.html-99abd054.js +3 -3
  96. package/docs/assets/getImage.html-3429c5a1.js +1 -1
  97. package/docs/assets/getImage.html-4d886d83.js +3 -3
  98. package/docs/assets/getTime.html-7435f922.js +1 -1
  99. package/docs/assets/getTime.html-b37f49eb.js +20 -20
  100. package/docs/assets/img.html-7d1da657.js +1 -1
  101. package/docs/assets/img.html-fbea1105.js +1 -1
  102. package/docs/assets/index.html-1695dd7c.js +1 -1
  103. package/docs/assets/index.html-65a4aa67.js +1 -1
  104. package/docs/assets/index.html-7b98d5bd.js +1 -1
  105. package/docs/assets/index.html-c01f2648.js +1 -1
  106. package/docs/assets/input-number.html-0b250d2a.js +1 -1
  107. package/docs/assets/input-number.html-a8eb0378.js +1 -1
  108. package/docs/assets/list-menu-item.html-7f1b4611.js +1 -1
  109. package/docs/assets/list-menu-item.html-84ed5ab8.js +1 -1
  110. package/docs/assets/list-menu.html-28b4163f.js +1 -1
  111. package/docs/assets/list-menu.html-cb6ba95b.js +1 -1
  112. package/docs/assets/loading.html-dae9e39d.js +6 -6
  113. package/docs/assets/loading.html-dc74c9e6.js +1 -1
  114. package/docs/assets/notify.html-e6c4c514.js +1 -1
  115. package/docs/assets/notify.html-f2c4d914.js +8 -8
  116. package/docs/assets/power-page.html-32e02f82.js +1 -1
  117. package/docs/assets/power-page.html-485e77da.js +1 -1
  118. package/docs/assets/power.html-d258cc19.js +93 -93
  119. package/docs/assets/power.html-e490bd32.js +1 -1
  120. package/docs/assets/previewImage.html-6a6b4245.js +1 -1
  121. package/docs/assets/previewImage.html-c5b7e945.js +2 -2
  122. package/docs/assets/price.html-1882c548.js +19 -19
  123. package/docs/assets/price.html-94d3f5be.js +1 -1
  124. package/docs/assets/price.html-d213df0f.js +1 -1
  125. package/docs/assets/price.html-deaf880f.js +1 -1
  126. package/docs/assets/render.html-8efcbdd4.js +1 -1
  127. package/docs/assets/render.html-df228e38.js +1 -1
  128. package/docs/assets/rule.html-2cd57fc2.js +13 -13
  129. package/docs/assets/rule.html-61662001.js +1 -1
  130. package/docs/assets/ruleValid.html-04fe2552.js +1 -1
  131. package/docs/assets/ruleValid.html-e0a776af.js +14 -14
  132. package/docs/assets/search-0782d0d1.svg +1 -1
  133. package/docs/assets/search-item.html-3f75394c.js +1 -1
  134. package/docs/assets/search-item.html-4e942ecd.js +1 -1
  135. package/docs/assets/search.html-2807043e.js +1 -1
  136. package/docs/assets/search.html-c24f8806.js +1 -1
  137. package/docs/assets/select.html-00d0607c.js +1 -1
  138. package/docs/assets/select.html-de7731f5.js +1 -1
  139. package/docs/assets/splitter.html-56f51a70.js +1 -1
  140. package/docs/assets/splitter.html-f5c836d7.js +1 -1
  141. package/docs/assets/style-161e43ab.css +1 -1
  142. package/docs/assets/symbols.html-a6aea4bf.js +1 -1
  143. package/docs/assets/symbols.html-b1f65bad.js +21 -21
  144. package/docs/assets/table-column-fixed.html-3a69e7b2.js +1 -1
  145. package/docs/assets/table-column-fixed.html-e763c38b.js +1 -1
  146. package/docs/assets/table-pagination.html-236934d3.js +1 -1
  147. package/docs/assets/table-pagination.html-c37ee2ac.js +1 -1
  148. package/docs/assets/table-splitter.html-07eab15c.js +1 -1
  149. package/docs/assets/table-splitter.html-7670ee65.js +1 -1
  150. package/docs/assets/table-summary.html-04db434f.js +1 -1
  151. package/docs/assets/table-summary.html-943c65a0.js +1 -1
  152. package/docs/assets/table.html-36253ad7.js +1 -1
  153. package/docs/assets/table.html-7f9c5d1b.js +38 -38
  154. package/docs/assets/table.html-93d53dc8.js +1 -1
  155. package/docs/assets/table.html-ac99b9cb.js +1 -1
  156. package/docs/assets/thumbnail.html-bab1976b.js +1 -1
  157. package/docs/assets/thumbnail.html-eb64e5e8.js +1 -1
  158. package/docs/assets/timestamp.html-4e54f79b.js +13 -13
  159. package/docs/assets/timestamp.html-d0e1b88a.js +1 -1
  160. package/docs/assets/toast.html-58ecbe21.js +1 -1
  161. package/docs/assets/toast.html-c9b9d36b.js +6 -6
  162. package/docs/assets/toolbar.html-83d9f97c.js +1 -1
  163. package/docs/assets/toolbar.html-ff7b8c92.js +1 -1
  164. package/docs/assets/tree.html-d07cbe79.js +23 -23
  165. package/docs/assets/tree.html-ea04193e.js +1 -1
  166. package/docs/assets/uploader-query.html-05590718.js +1 -1
  167. package/docs/assets/uploader-query.html-3175bac5.js +1 -1
  168. package/docs/assets/uploader.html-36da4394.js +2 -2
  169. package/docs/assets/uploader.html-6b5f3079.js +1 -1
  170. package/docs/assets/uploader.html-b9340b57.js +1 -1
  171. package/docs/assets/uploader.html-bc1c22e3.js +1 -1
  172. package/docs/assets/value-format.html-8ae3d47d.js +1 -1
  173. package/docs/assets/value-format.html-afa99b3d.js +1 -1
  174. package/docs/components/column-title.html +35 -35
  175. package/docs/components/data.html +62 -62
  176. package/docs/components/dialog.html +33 -33
  177. package/docs/components/dragger.html +33 -33
  178. package/docs/components/editor-code.html +33 -33
  179. package/docs/components/empty.html +33 -33
  180. package/docs/components/field-date.html +33 -33
  181. package/docs/components/field-table.html +33 -33
  182. package/docs/components/field-text.html +33 -33
  183. package/docs/components/field-tree.html +33 -33
  184. package/docs/components/img.html +33 -33
  185. package/docs/components/input-number.html +33 -33
  186. package/docs/components/list-menu-item.html +33 -33
  187. package/docs/components/list-menu.html +33 -33
  188. package/docs/components/power-page.html +33 -33
  189. package/docs/components/price.html +33 -33
  190. package/docs/components/render.html +33 -33
  191. package/docs/components/search-item.html +33 -33
  192. package/docs/components/search.html +33 -33
  193. package/docs/components/select.html +33 -33
  194. package/docs/components/splitter.html +33 -33
  195. package/docs/components/table-column-fixed.html +33 -33
  196. package/docs/components/table-pagination.html +33 -33
  197. package/docs/components/table-splitter.html +33 -33
  198. package/docs/components/table-summary.html +33 -33
  199. package/docs/components/table.html +33 -33
  200. package/docs/components/thumbnail.html +33 -33
  201. package/docs/components/toolbar.html +33 -33
  202. package/docs/components/uploader-query.html +33 -33
  203. package/docs/components/uploader.html +33 -33
  204. package/docs/components/value-format.html +33 -33
  205. package/docs/css/index.css +3 -3
  206. package/docs/index.html +33 -33
  207. package/docs/utils/alert.html +37 -37
  208. package/docs/utils/area.html +74 -74
  209. package/docs/utils/arr.html +43 -43
  210. package/docs/utils/auth.html +40 -40
  211. package/docs/utils/bus.html +38 -38
  212. package/docs/utils/confirm.html +42 -42
  213. package/docs/utils/copy.html +45 -45
  214. package/docs/utils/dialog.html +100 -100
  215. package/docs/utils/dict.html +55 -55
  216. package/docs/utils/dictOptions.html +37 -37
  217. package/docs/utils/form.html +34 -34
  218. package/docs/utils/getData.html +66 -66
  219. package/docs/utils/getFile.html +35 -35
  220. package/docs/utils/getImage.html +35 -35
  221. package/docs/utils/getTime.html +52 -52
  222. package/docs/utils/index.html +33 -33
  223. package/docs/utils/loading.html +38 -38
  224. package/docs/utils/notify.html +40 -40
  225. package/docs/utils/power.html +125 -125
  226. package/docs/utils/previewImage.html +34 -34
  227. package/docs/utils/price.html +51 -51
  228. package/docs/utils/rule.html +45 -45
  229. package/docs/utils/ruleValid.html +46 -46
  230. package/docs/utils/symbols.html +53 -53
  231. package/docs/utils/table.html +70 -70
  232. package/docs/utils/timestamp.html +45 -45
  233. package/docs/utils/toast.html +38 -38
  234. package/docs/utils/tree.html +55 -55
  235. package/docs/utils/uploader.html +34 -34
  236. package/package.json +25 -25
  237. package/sass/common.scss +184 -184
  238. package/sass/index.scss +12 -12
  239. package/sass/line.scss +39 -39
  240. package/sass/quasar/btn.scss +46 -46
  241. package/sass/quasar/common.scss +3 -3
  242. package/sass/quasar/drawer.scss +6 -6
  243. package/sass/quasar/field.scss +259 -259
  244. package/sass/quasar/loading.scss +6 -6
  245. package/sass/quasar/table.scss +168 -168
  246. package/sass/quasar/toolbar.scss +22 -22
  247. package/sass/variables.scss +140 -140
  248. package/store/index.js +29 -29
  249. package/utils/$auth.js +127 -127
  250. package/utils/$form.js +72 -72
  251. package/utils/$power.js +1486 -1486
  252. package/utils/$render.js +75 -75
  253. package/utils/$rule.js +13 -13
  254. package/utils/$ruleValid.js +10 -10
  255. package/utils/$search.js +416 -416
  256. package/utils/$table.js +1275 -1275
  257. package/utils/alert.js +12 -12
  258. package/utils/area.js +400 -400
  259. package/utils/arr.js +51 -51
  260. package/utils/bus.js +6 -6
  261. package/utils/config.js +64 -62
  262. package/utils/confirm.js +11 -11
  263. package/utils/copy.js +30 -30
  264. package/utils/dialog.js +36 -36
  265. package/utils/dict.js +21 -21
  266. package/utils/dictOptions.js +28 -28
  267. package/utils/getData.js +88 -88
  268. package/utils/getFile.js +67 -67
  269. package/utils/getImage.js +276 -236
  270. package/utils/getTime.js +113 -113
  271. package/utils/index.js +67 -67
  272. package/utils/loading.js +15 -15
  273. package/utils/notify.js +13 -13
  274. package/utils/play.js +40 -40
  275. package/utils/previewImage.js +14 -14
  276. package/utils/price.js +18 -18
  277. package/utils/symbols.js +18 -18
  278. package/utils/timestamp.js +18 -18
  279. package/utils/toast.js +13 -13
  280. package/utils/uploader.js +2114 -2099
  281. package/utils/useAuth.js +30 -30
  282. package/utils/useFileUrl.js +26 -26
  283. package/utils/useRouter.js +47 -47
  284. package/utils/useSearch.js +499 -499
@@ -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 += ':00'
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 += ':00'
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>