foucui 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +43 -0
  2. package/components/QiuAffix/index.vue +186 -0
  3. package/components/QiuAlert/index.vue +208 -0
  4. package/components/QiuAnchor/context.ts +18 -0
  5. package/components/QiuAnchor/index.vue +180 -0
  6. package/components/QiuAnchorLink/index.vue +67 -0
  7. package/components/QiuApp/index.vue +9 -0
  8. package/components/QiuAutocomplete/index.vue +408 -0
  9. package/components/QiuAvatar/index.vue +140 -0
  10. package/components/QiuBacktop/index.vue +121 -0
  11. package/components/QiuBadge/api/index.ts +389 -0
  12. package/components/QiuBadge/components/BadgeImagePickerDialog.vue +243 -0
  13. package/components/QiuBadge/components/BadgeLibraryManagerDialog.vue +30 -0
  14. package/components/QiuBadge/components/BadgeLibraryPanel.vue +182 -0
  15. package/components/QiuBadge/composables/useTableHostHeight.ts +53 -0
  16. package/components/QiuBadge/index.ts +18 -0
  17. package/components/QiuBadge/shared/BadgeTemplateRenderer.vue +32 -0
  18. package/components/QiuBadge/shared/assetUrl.ts +26 -0
  19. package/components/QiuBadge/shared/badgeTemplate.ts +309 -0
  20. package/components/QiuBadge/utils/chinaAreaData.ts +44 -0
  21. package/components/QiuBadge/utils/hostRegion.ts +22 -0
  22. package/components/QiuBadge/utils/pca-code.json +1 -0
  23. package/components/QiuBadge/utils/pdfFromElement.ts +348 -0
  24. package/components/QiuBadge/views/BadgeLibraryView.vue +32 -0
  25. package/components/QiuBadge/views/BadgeManageView.vue +1364 -0
  26. package/components/QiuBadge/views/BadgeTemplateEditorView.vue +10 -0
  27. package/components/QiuBadge/views/BadgeTemplateListView.vue +229 -0
  28. package/components/QiuBadge/views/DeskLabelTemplateListView.vue +227 -0
  29. package/components/QiuBadge/views/DeskLabelView.vue +683 -0
  30. package/components/QiuBadgeDot/index.vue +87 -0
  31. package/components/QiuButton/index.vue +247 -0
  32. package/components/QiuButtonGroup/index.vue +63 -0
  33. package/components/QiuCanvasKit/QiuCanvasEditor.vue +5503 -0
  34. package/components/QiuCanvasKit/QiuCanvasRenderer.vue +348 -0
  35. package/components/QiuCanvasKit/assetUrl.ts +11 -0
  36. package/components/QiuCanvasKit/components/DataModulesPanel.vue +352 -0
  37. package/components/QiuCanvasKit/export/html.ts +132 -0
  38. package/components/QiuCanvasKit/export/pdf.ts +48 -0
  39. package/components/QiuCanvasKit/export/png.ts +50 -0
  40. package/components/QiuCanvasKit/index.ts +20 -0
  41. package/components/QiuCanvasKit/modules/badgeCompat.ts +84 -0
  42. package/components/QiuCanvasKit/modules/dataRegistry.ts +207 -0
  43. package/components/QiuCanvasKit/modules/merge.ts +71 -0
  44. package/components/QiuCanvasKit/presets/badge.ts +67 -0
  45. package/components/QiuCanvasKit/presets/banner.ts +79 -0
  46. package/components/QiuCanvasKit/types.ts +138 -0
  47. package/components/QiuCard/index.vue +104 -0
  48. package/components/QiuCarousel/context.ts +16 -0
  49. package/components/QiuCarousel/index.vue +343 -0
  50. package/components/QiuCarouselItem/index.vue +47 -0
  51. package/components/QiuCascader/index.vue +879 -0
  52. package/components/QiuCascader/types.ts +48 -0
  53. package/components/QiuCheckbox/QiuCheckboxGroup.vue +78 -0
  54. package/components/QiuCheckbox/index.vue +231 -0
  55. package/components/QiuCheckbox/types.ts +8 -0
  56. package/components/QiuCode/index.vue +64 -0
  57. package/components/QiuCol/col.scss +55 -0
  58. package/components/QiuCol/index.vue +64 -0
  59. package/components/QiuCollapse/context.ts +10 -0
  60. package/components/QiuCollapse/index.vue +70 -0
  61. package/components/QiuCollapseItem/index.vue +167 -0
  62. package/components/QiuColorField/index.vue +296 -0
  63. package/components/QiuColorPicker/README.md +118 -0
  64. package/components/QiuColorPicker/index.vue +60 -0
  65. package/components/QiuColorfulCard/index.vue +101 -0
  66. package/components/QiuCombobox/index.vue +277 -0
  67. package/components/QiuConfigProvider/index.vue +31 -0
  68. package/components/QiuContextMenu/index.vue +209 -0
  69. package/components/QiuDate/index.vue +1134 -0
  70. package/components/QiuDescriptions/context.ts +20 -0
  71. package/components/QiuDescriptions/index.vue +115 -0
  72. package/components/QiuDescriptionsItem/index.vue +103 -0
  73. package/components/QiuDialog/index.vue +828 -0
  74. package/components/QiuDigitalCard/index.vue +159 -0
  75. package/components/QiuDivider/index.vue +185 -0
  76. package/components/QiuDot/index.vue +83 -0
  77. package/components/QiuDrawer/index.vue +350 -0
  78. package/components/QiuDropdown/QiuDropdownItem.vue +74 -0
  79. package/components/QiuDropdown/QiuDropdownMenu.vue +22 -0
  80. package/components/QiuDropdown/context.ts +9 -0
  81. package/components/QiuDropdown/index.vue +189 -0
  82. package/components/QiuEmpty/index.vue +73 -0
  83. package/components/QiuForm/index.vue +172 -0
  84. package/components/QiuForm/types.ts +39 -0
  85. package/components/QiuFormItem/index.vue +276 -0
  86. package/components/QiuFullscreen/index.vue +11 -0
  87. package/components/QiuGrid/index.vue +408 -0
  88. package/components/QiuHoverCard/index.vue +192 -0
  89. package/components/QiuIcon/index.vue +117 -0
  90. package/components/QiuIconPicker/iconify.libraries.ts +182 -0
  91. package/components/QiuIconPicker/icons.catalog.ts +3072 -0
  92. package/components/QiuIconPicker/index.vue +488 -0
  93. package/components/QiuImage/index.vue +177 -0
  94. package/components/QiuInput/index.vue +328 -0
  95. package/components/QiuInputNumber/index.vue +295 -0
  96. package/components/QiuInputOtp/index.vue +190 -0
  97. package/components/QiuKbd/index.vue +57 -0
  98. package/components/QiuLayoutContainer/index.vue +50 -0
  99. package/components/QiuLinkPreview/index.vue +224 -0
  100. package/components/QiuLoading/index.ts +176 -0
  101. package/components/QiuLoading/spinner.vue +820 -0
  102. package/components/QiuLoading/types.ts +44 -0
  103. package/components/QiuMention/index.vue +299 -0
  104. package/components/QiuMenu/QiuMenuRoot.vue +241 -0
  105. package/components/QiuMenu/components/QiuMenuItem.vue +340 -0
  106. package/components/QiuMenu/components/QiuSubMenu.vue +504 -0
  107. package/components/QiuMenu/context.ts +21 -0
  108. package/components/QiuMenu/index.vue +43 -0
  109. package/components/QiuMenuNav/QiuMenuNavItem.vue +100 -0
  110. package/components/QiuMenuNav/QiuMenuNavSub.vue +120 -0
  111. package/components/QiuMenuNav/context.ts +14 -0
  112. package/components/QiuMenuNav/index.vue +148 -0
  113. package/components/QiuMsg/QiuMsgItem.vue +180 -0
  114. package/components/QiuMsg/index.ts +158 -0
  115. package/components/QiuMsg/types.ts +23 -0
  116. package/components/QiuMsgBox/index.ts +147 -0
  117. package/components/QiuNotification/QiuNotificationItem.vue +168 -0
  118. package/components/QiuNotification/index.ts +155 -0
  119. package/components/QiuNotification/types.ts +14 -0
  120. package/components/QiuPage/index.vue +12 -0
  121. package/components/QiuPageHeader/index.vue +115 -0
  122. package/components/QiuPageMain/index.vue +78 -0
  123. package/components/QiuPagination/index.vue +421 -0
  124. package/components/QiuPasswordStrength/index.vue +101 -0
  125. package/components/QiuPopconfirm/index.vue +196 -0
  126. package/components/QiuPopover/index.vue +277 -0
  127. package/components/QiuProgress/index.vue +235 -0
  128. package/components/QiuQrcode/index.vue +302 -0
  129. package/components/QiuQueryForm/components/QiuQueryFormBottomPanel.vue +13 -0
  130. package/components/QiuQueryForm/components/QiuQueryFormLeftPanel.vue +37 -0
  131. package/components/QiuQueryForm/components/QiuQueryFormRightPanel.vue +37 -0
  132. package/components/QiuQueryForm/components/QiuQueryFormTopPanel.vue +13 -0
  133. package/components/QiuQueryForm/index.vue +117 -0
  134. package/components/QiuRadio/QiuRadioGroup.vue +75 -0
  135. package/components/QiuRadio/index.vue +191 -0
  136. package/components/QiuRadio/types.ts +9 -0
  137. package/components/QiuRate/index.vue +184 -0
  138. package/components/QiuRefresh/index.vue +32 -0
  139. package/components/QiuResult/index.vue +103 -0
  140. package/components/QiuRow/index.vue +60 -0
  141. package/components/QiuRow/types.ts +5 -0
  142. package/components/QiuScrollbar/index.vue +107 -0
  143. package/components/QiuSearchBar/index.vue +154 -0
  144. package/components/QiuSegmented/index.vue +120 -0
  145. package/components/QiuSelect/QiuOption.vue +93 -0
  146. package/components/QiuSelect/index.vue +452 -0
  147. package/components/QiuSelect/types.ts +15 -0
  148. package/components/QiuSkeleton/index.vue +78 -0
  149. package/components/QiuSlider/index.vue +266 -0
  150. package/components/QiuSpace/index.vue +95 -0
  151. package/components/QiuSparkline/index.vue +92 -0
  152. package/components/QiuStatistic/index.vue +4 -0
  153. package/components/QiuStatistics/index.vue +123 -0
  154. package/components/QiuStep/index.vue +220 -0
  155. package/components/QiuSteps/context.ts +25 -0
  156. package/components/QiuSteps/index.vue +84 -0
  157. package/components/QiuSwitch/index.vue +145 -0
  158. package/components/QiuTabBar/index.vue +218 -0
  159. package/components/QiuTabBar/types.ts +19 -0
  160. package/components/QiuTabPane/index.vue +82 -0
  161. package/components/QiuTable/columns.ts +16 -0
  162. package/components/QiuTable/export.ts +102 -0
  163. package/components/QiuTable/index.ts +24 -0
  164. package/components/QiuTable/index.vue +3503 -0
  165. package/components/QiuTable/registry.ts +75 -0
  166. package/components/QiuTable/styles/table.scss +1230 -0
  167. package/components/QiuTable/types.ts +413 -0
  168. package/components/QiuTable/useArea.ts +202 -0
  169. package/components/QiuTable/useColumns.ts +325 -0
  170. package/components/QiuTable/useEdit.ts +136 -0
  171. package/components/QiuTable/useExtras.ts +115 -0
  172. package/components/QiuTable/useHistory.ts +77 -0
  173. package/components/QiuTable/useMerge.ts +105 -0
  174. package/components/QiuTable/useResize.ts +86 -0
  175. package/components/QiuTable/useScrollSync.ts +152 -0
  176. package/components/QiuTable/useVirtual.ts +97 -0
  177. package/components/QiuTable/utils.ts +165 -0
  178. package/components/QiuTableColumn/index.vue +101 -0
  179. package/components/QiuTag/index.vue +143 -0
  180. package/components/QiuText/index.vue +99 -0
  181. package/components/QiuTime/index.vue +548 -0
  182. package/components/QiuTimeAgo/index.vue +103 -0
  183. package/components/QiuTimeline/index.vue +54 -0
  184. package/components/QiuTimelineItem/index.vue +140 -0
  185. package/components/QiuTips/index.vue +323 -0
  186. package/components/QiuTooltip/index.vue +237 -0
  187. package/components/QiuTransfer/index.vue +277 -0
  188. package/components/QiuTree/QiuTreeNode.vue +146 -0
  189. package/components/QiuTree/index.vue +143 -0
  190. package/components/QiuTree/types.ts +30 -0
  191. package/components/QiuTreeSelect/index.vue +259 -0
  192. package/components/QiuTrend/index.vue +92 -0
  193. package/components/QiuUpload/index.vue +628 -0
  194. package/components/QiuUploadCrop/index.vue +1267 -0
  195. package/components/QiuWatermark/index.vue +121 -0
  196. package/components/useBodyScrollLock.ts +28 -0
  197. package/dist/components/QiuAnchor/context.d.ts +15 -0
  198. package/dist/components/QiuAnchorLink/index.vue.d.ts +23 -0
  199. package/dist/components/QiuBadge/api/index.d.ts +110 -0
  200. package/dist/components/QiuBadge/components/BadgeImagePickerDialog.vue.d.ts +16 -0
  201. package/dist/components/QiuBadge/components/BadgeLibraryManagerDialog.vue.d.ts +9 -0
  202. package/dist/components/QiuBadge/components/BadgeLibraryPanel.vue.d.ts +5 -0
  203. package/dist/components/QiuBadge/composables/useTableHostHeight.d.ts +7 -0
  204. package/dist/components/QiuBadge/index.d.ts +18 -0
  205. package/dist/components/QiuBadge/shared/BadgeTemplateRenderer.vue.d.ts +14 -0
  206. package/dist/components/QiuBadge/shared/assetUrl.d.ts +1 -0
  207. package/dist/components/QiuBadge/shared/badgeTemplate.d.ts +132 -0
  208. package/dist/components/QiuBadge/utils/chinaAreaData.d.ts +9 -0
  209. package/dist/components/QiuBadge/utils/hostRegion.d.ts +3 -0
  210. package/dist/components/QiuBadge/utils/pca-code.json.d.ts +3 -0
  211. package/dist/components/QiuBadge/utils/pdfFromElement.d.ts +14 -0
  212. package/dist/components/QiuBadge/views/BadgeLibraryView.vue.d.ts +2 -0
  213. package/dist/components/QiuBadge/views/BadgeManageView.vue.d.ts +7 -0
  214. package/dist/components/QiuBadge/views/BadgeTemplateListView.vue.d.ts +4 -0
  215. package/dist/components/QiuBadge/views/DeskLabelTemplateListView.vue.d.ts +4 -0
  216. package/dist/components/QiuBadge/views/DeskLabelView.vue.d.ts +4 -0
  217. package/dist/components/QiuButton/index.vue.d.ts +52 -0
  218. package/dist/components/QiuCanvasKit/QiuCanvasEditor.vue.d.ts +24 -0
  219. package/dist/components/QiuCanvasKit/QiuCanvasRenderer.vue.d.ts +13 -0
  220. package/dist/components/QiuCanvasKit/assetUrl.d.ts +7 -0
  221. package/dist/components/QiuCanvasKit/components/DataModulesPanel.vue.d.ts +23 -0
  222. package/dist/components/QiuCanvasKit/export/html.d.ts +12 -0
  223. package/dist/components/QiuCanvasKit/export/pdf.d.ts +9 -0
  224. package/dist/components/QiuCanvasKit/export/png.d.ts +8 -0
  225. package/dist/components/QiuCanvasKit/index.d.ts +19 -0
  226. package/dist/components/QiuCanvasKit/modules/badgeCompat.d.ts +8 -0
  227. package/dist/components/QiuCanvasKit/modules/dataRegistry.d.ts +23 -0
  228. package/dist/components/QiuCanvasKit/modules/merge.d.ts +12 -0
  229. package/dist/components/QiuCanvasKit/presets/badge.d.ts +12 -0
  230. package/dist/components/QiuCanvasKit/presets/banner.d.ts +4 -0
  231. package/dist/components/QiuCanvasKit/types.d.ts +119 -0
  232. package/dist/components/QiuCarousel/context.d.ts +13 -0
  233. package/dist/components/QiuCarouselItem/index.vue.d.ts +20 -0
  234. package/dist/components/QiuCascader/types.d.ts +25 -0
  235. package/dist/components/QiuCheckbox/QiuCheckboxGroup.vue.d.ts +33 -0
  236. package/dist/components/QiuCheckbox/index.vue.d.ts +38 -0
  237. package/dist/components/QiuCheckbox/types.d.ts +7 -0
  238. package/dist/components/QiuCode/index.vue.d.ts +15 -0
  239. package/dist/components/QiuCollapse/context.d.ts +8 -0
  240. package/dist/components/QiuCollapseItem/index.vue.d.ts +30 -0
  241. package/dist/components/QiuColorField/index.vue.d.ts +23 -0
  242. package/dist/components/QiuColorPicker/index.vue.d.ts +21 -0
  243. package/dist/components/QiuCombobox/index.vue.d.ts +54 -0
  244. package/dist/components/QiuContextMenu/index.vue.d.ts +46 -0
  245. package/dist/components/QiuDescriptions/context.d.ts +16 -0
  246. package/dist/components/QiuDescriptionsItem/index.vue.d.ts +25 -0
  247. package/dist/components/QiuDigitalCard/index.vue.d.ts +45 -0
  248. package/dist/components/QiuDropdown/QiuDropdownItem.vue.d.ts +30 -0
  249. package/dist/components/QiuDropdown/QiuDropdownMenu.vue.d.ts +17 -0
  250. package/dist/components/QiuDropdown/context.d.ts +7 -0
  251. package/dist/components/QiuDropdown/index.vue.d.ts +46 -0
  252. package/dist/components/QiuForm/types.d.ts +31 -0
  253. package/dist/components/QiuHoverCard/index.vue.d.ts +44 -0
  254. package/dist/components/QiuIcon/index.vue.d.ts +18 -0
  255. package/dist/components/QiuIconPicker/iconify.libraries.d.ts +18 -0
  256. package/dist/components/QiuIconPicker/icons.catalog.d.ts +12 -0
  257. package/dist/components/QiuInput/index.vue.d.ts +71 -0
  258. package/dist/components/QiuInputNumber/index.vue.d.ts +38 -0
  259. package/dist/components/QiuInputOtp/index.vue.d.ts +28 -0
  260. package/dist/components/QiuKbd/index.vue.d.ts +22 -0
  261. package/dist/components/QiuLayoutContainer/index.vue.d.ts +29 -0
  262. package/dist/components/QiuLinkPreview/index.vue.d.ts +43 -0
  263. package/dist/components/QiuLoading/index.d.ts +26 -0
  264. package/dist/components/QiuLoading/spinner.vue.d.ts +14 -0
  265. package/dist/components/QiuLoading/types.d.ts +2 -0
  266. package/dist/components/QiuMention/index.vue.d.ts +35 -0
  267. package/dist/components/QiuMenu/QiuMenuRoot.vue.d.ts +36 -0
  268. package/dist/components/QiuMenu/context.d.ts +19 -0
  269. package/dist/components/QiuMenuNav/QiuMenuNavItem.vue.d.ts +26 -0
  270. package/dist/components/QiuMenuNav/QiuMenuNavSub.vue.d.ts +25 -0
  271. package/dist/components/QiuMenuNav/context.d.ts +12 -0
  272. package/dist/components/QiuMenuNav/index.vue.d.ts +35 -0
  273. package/dist/components/QiuMsg/QiuMsgItem.vue.d.ts +15 -0
  274. package/dist/components/QiuMsg/index.d.ts +30 -0
  275. package/dist/components/QiuMsg/types.d.ts +12 -0
  276. package/dist/components/QiuMsgBox/index.d.ts +14 -0
  277. package/dist/components/QiuNotification/QiuNotificationItem.vue.d.ts +16 -0
  278. package/dist/components/QiuNotification/index.d.ts +30 -0
  279. package/dist/components/QiuNotification/types.d.ts +12 -0
  280. package/dist/components/QiuPageMain/index.vue.d.ts +27 -0
  281. package/dist/components/QiuPagination/index.vue.d.ts +44 -0
  282. package/dist/components/QiuPasswordStrength/index.vue.d.ts +9 -0
  283. package/dist/components/QiuQrcode/index.vue.d.ts +20 -0
  284. package/dist/components/QiuRadio/QiuRadioGroup.vue.d.ts +33 -0
  285. package/dist/components/QiuRadio/types.d.ts +8 -0
  286. package/dist/components/QiuRow/types.d.ts +4 -0
  287. package/dist/components/QiuSearchBar/index.vue.d.ts +38 -0
  288. package/dist/components/QiuSelect/QiuOption.vue.d.ts +24 -0
  289. package/dist/components/QiuSelect/index.vue.d.ts +52 -0
  290. package/dist/components/QiuSelect/types.d.ts +13 -0
  291. package/dist/components/QiuSparkline/index.vue.d.ts +18 -0
  292. package/dist/components/QiuStep/index.vue.d.ts +31 -0
  293. package/dist/components/QiuSteps/context.d.ts +21 -0
  294. package/dist/components/QiuSwitch/index.vue.d.ts +25 -0
  295. package/dist/components/QiuTabBar/index.vue.d.ts +32 -0
  296. package/dist/components/QiuTabBar/types.d.ts +16 -0
  297. package/dist/components/QiuTabPane/index.vue.d.ts +25 -0
  298. package/dist/components/QiuTable/columns.d.ts +1 -0
  299. package/dist/components/QiuTable/export.d.ts +18 -0
  300. package/dist/components/QiuTable/index.d.ts +3 -0
  301. package/dist/components/QiuTable/index.vue.d.ts +322 -0
  302. package/dist/components/QiuTable/registry.d.ts +39 -0
  303. package/dist/components/QiuTable/types.d.ts +353 -0
  304. package/dist/components/QiuTable/useArea.d.ts +51 -0
  305. package/dist/components/QiuTable/useColumns.d.ts +67 -0
  306. package/dist/components/QiuTable/useEdit.d.ts +36 -0
  307. package/dist/components/QiuTable/useExtras.d.ts +38 -0
  308. package/dist/components/QiuTable/useHistory.d.ts +44 -0
  309. package/dist/components/QiuTable/useMerge.d.ts +28 -0
  310. package/dist/components/QiuTable/useResize.d.ts +19 -0
  311. package/dist/components/QiuTable/useScrollSync.d.ts +25 -0
  312. package/dist/components/QiuTable/useVirtual.d.ts +30 -0
  313. package/dist/components/QiuTable/utils.d.ts +54 -0
  314. package/dist/components/QiuTime/index.vue.d.ts +43 -0
  315. package/dist/components/QiuTimeAgo/index.vue.d.ts +35 -0
  316. package/dist/components/QiuTimelineItem/index.vue.d.ts +35 -0
  317. package/dist/components/QiuTooltip/index.vue.d.ts +38 -0
  318. package/dist/components/QiuTree/types.d.ts +13 -0
  319. package/dist/components/QiuTrend/index.vue.d.ts +34 -0
  320. package/dist/components/QiuUpload/index.vue.d.ts +86 -0
  321. package/dist/components/QiuUploadCrop/index.vue.d.ts +136 -0
  322. package/dist/components/useBodyScrollLock.d.ts +4 -0
  323. package/dist/foucui.css +1 -0
  324. package/dist/foucui.js +26509 -0
  325. package/dist/foucui.umd.cjs +125 -0
  326. package/dist/index.d.ts +46 -0
  327. package/dist/src/bridge/@/api/media.d.ts +7 -0
  328. package/dist/src/bridge/@/api/notice.d.ts +5 -0
  329. package/dist/src/bridge/@/config/index.d.ts +29 -0
  330. package/dist/src/bridge/@/config/media.config.d.ts +15 -0
  331. package/dist/src/bridge/@/config/security.config.d.ts +7 -0
  332. package/dist/src/bridge/@/i18n/index.d.ts +7 -0
  333. package/dist/src/bridge/@/store/modules/bing.d.ts +3 -0
  334. package/dist/src/bridge/@/store/modules/errorLog.d.ts +3 -0
  335. package/dist/src/bridge/@/store/modules/media.d.ts +4 -0
  336. package/dist/src/bridge/@/store/modules/routes.d.ts +3 -0
  337. package/dist/src/bridge/@/store/modules/settings.d.ts +3 -0
  338. package/dist/src/bridge/@/store/modules/tabs.d.ts +3 -0
  339. package/dist/src/bridge/@/store/modules/user.d.ts +3 -0
  340. package/dist/src/bridge/@/utils/convertToCamelCase.d.ts +2 -0
  341. package/dist/src/bridge/@/utils/index.d.ts +5 -0
  342. package/dist/src/bridge/@/utils/pageTitle.d.ts +1 -0
  343. package/dist/src/bridge/@/utils/routes.d.ts +11 -0
  344. package/dist/src/bridge/@/utils/validate.d.ts +13 -0
  345. package/dist/src/bridge/@qiu/plugins/shortcuts.d.ts +2 -0
  346. package/dist/src/i18n.d.ts +2 -0
  347. package/package.json +83 -0
  348. package/plugins/qiu.ts +83 -0
  349. package/plugins/shortcuts.ts +69 -0
  350. package/src/bridge/@/api/media.ts +8 -0
  351. package/src/bridge/@/api/notice.ts +5 -0
  352. package/src/bridge/@/config/index.ts +38 -0
  353. package/src/bridge/@/config/media.config.ts +37 -0
  354. package/src/bridge/@/config/security.config.ts +8 -0
  355. package/src/bridge/@/i18n/index.ts +6 -0
  356. package/src/bridge/@/store/modules/bing.ts +9 -0
  357. package/src/bridge/@/store/modules/errorLog.ts +9 -0
  358. package/src/bridge/@/store/modules/media.ts +10 -0
  359. package/src/bridge/@/store/modules/routes.ts +10 -0
  360. package/src/bridge/@/store/modules/settings.ts +9 -0
  361. package/src/bridge/@/store/modules/tabs.ts +9 -0
  362. package/src/bridge/@/store/modules/user.ts +9 -0
  363. package/src/bridge/@/utils/convertToCamelCase.ts +11 -0
  364. package/src/bridge/@/utils/index.ts +9 -0
  365. package/src/bridge/@/utils/pageTitle.ts +4 -0
  366. package/src/bridge/@/utils/routes.ts +14 -0
  367. package/src/bridge/@/utils/validate.ts +17 -0
  368. package/src/bridge/@qiu/plugins/shortcuts.ts +3 -0
  369. package/src/i18n.ts +8 -0
  370. package/src/icons/qiu-logo.svg +1 -0
  371. package/styles/dark.scss +194 -0
  372. package/styles/normalize.css +349 -0
  373. package/styles/plain.scss +423 -0
  374. package/styles/qiu-tokens.scss +40 -0
  375. package/styles/qiu.scss +1149 -0
  376. package/styles/technology.scss +452 -0
  377. package/styles/var.scss +382 -0
  378. package/styles/variables.scss +77 -0
@@ -0,0 +1,1134 @@
1
+ <template>
2
+ <div
3
+ ref="rootRef"
4
+ class="qiu-date"
5
+ :class="[
6
+ `qiu-date--${type}`,
7
+ { 'is-disabled': disabled, 'is-focused': panelVisible },
8
+ ]"
9
+ >
10
+ <div class="qiu-date__editor" @click="togglePanel">
11
+ <template v-if="isRange">
12
+ <input
13
+ class="qiu-date__input"
14
+ :value="displayStartText"
15
+ :placeholder="startPlaceholder || startPlaceholderFallback"
16
+ readonly
17
+ :disabled="disabled"
18
+ />
19
+ <span class="qiu-date__separator">{{ rangeSeparator }}</span>
20
+ <input
21
+ class="qiu-date__input"
22
+ :value="displayEndText"
23
+ :placeholder="endPlaceholder || endPlaceholderFallback"
24
+ readonly
25
+ :disabled="disabled"
26
+ />
27
+ </template>
28
+ <input
29
+ v-else
30
+ class="qiu-date__input qiu-date__input--single"
31
+ :value="singleText"
32
+ :placeholder="placeholder || singlePlaceholderFallback"
33
+ readonly
34
+ :disabled="disabled"
35
+ />
36
+ <button
37
+ v-if="clearable && hasValue && !disabled"
38
+ type="button"
39
+ class="qiu-date__clear"
40
+ @click.stop="clearValue"
41
+ >
42
+ ×
43
+ </button>
44
+ <qiu-icon icon="calendar-line" class="qiu-date__icon" />
45
+ </div>
46
+
47
+ <Teleport to="body">
48
+ <Transition name="qiu-date-fade">
49
+ <div
50
+ v-if="panelVisible"
51
+ ref="panelRef"
52
+ class="qiu-date-panel"
53
+ :class="[
54
+ popperClass,
55
+ {
56
+ 'qiu-date-panel--lunar': showLunar && panelUnit === 'date',
57
+ 'qiu-date-panel--range': isRange,
58
+ [`qiu-date-panel--${panelUnit}`]: true,
59
+ },
60
+ ]"
61
+ :style="panelStyle"
62
+ @mousedown.prevent
63
+ >
64
+ <div class="qiu-date-panel__body" :class="{ 'is-range': isRange }">
65
+ <!-- 左面板 / 单面板 -->
66
+ <div class="qiu-date-panel__side">
67
+ <div class="qiu-date-panel__header">
68
+ <button type="button" class="qiu-date-panel__nav" @click="navLeft(-1)">‹</button>
69
+ <span class="qiu-date-panel__title">{{ leftTitle }}</span>
70
+ <button type="button" class="qiu-date-panel__nav" @click="navLeft(1)">›</button>
71
+ </div>
72
+
73
+ <template v-if="panelUnit === 'date'">
74
+ <div class="qiu-date-panel__weeks">
75
+ <span v-for="w in weekLabels" :key="w" class="qiu-date-panel__week">{{ w }}</span>
76
+ </div>
77
+ <div class="qiu-date-panel__grid qiu-date-panel__grid--day">
78
+ <button
79
+ v-for="cell in leftDayCells"
80
+ :key="`l-${cell.key}`"
81
+ type="button"
82
+ class="qiu-date-panel__cell"
83
+ :class="cellClass(cell)"
84
+ :disabled="cell.disabled"
85
+ @click="pickOnSide('start', cell)"
86
+ >
87
+ <div
88
+ class="qiu-date__cell"
89
+ :class="{ 'is-selected': cell.selected, 'is-today': cell.isToday }"
90
+ >
91
+ <span class="qiu-date__solar">{{ cell.day }}</span>
92
+ <span
93
+ v-if="showLunar"
94
+ class="qiu-date__lunar"
95
+ :class="{ 'is-festival': cell.lunar.festival }"
96
+ >
97
+ {{ cell.lunar.label }}
98
+ </span>
99
+ </div>
100
+ </button>
101
+ </div>
102
+ </template>
103
+
104
+ <div v-else-if="panelUnit === 'month'" class="qiu-date-panel__grid qiu-date-panel__grid--month">
105
+ <button
106
+ v-for="cell in leftMonthCells"
107
+ :key="`lm-${cell.key}`"
108
+ type="button"
109
+ class="qiu-date-panel__cell qiu-date-panel__cell--month"
110
+ :class="cellClass(cell)"
111
+ :disabled="cell.disabled"
112
+ @click="pickOnSide('start', cell)"
113
+ >
114
+ <div class="qiu-date__cell" :class="{ 'is-selected': cell.selected }">
115
+ <span class="qiu-date__solar">{{ cell.label }}</span>
116
+ </div>
117
+ </button>
118
+ </div>
119
+
120
+ <div v-else class="qiu-date-panel__grid qiu-date-panel__grid--year">
121
+ <button
122
+ v-for="cell in leftYearCells"
123
+ :key="`ly-${cell.key}`"
124
+ type="button"
125
+ class="qiu-date-panel__cell qiu-date-panel__cell--year"
126
+ :class="cellClass(cell)"
127
+ :disabled="cell.disabled"
128
+ @click="pickOnSide('start', cell)"
129
+ >
130
+ <div class="qiu-date__cell" :class="{ 'is-selected': cell.selected }">
131
+ <span class="qiu-date__solar">{{ cell.label }}</span>
132
+ </div>
133
+ </button>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- 右面板(区间) -->
138
+ <div v-if="isRange" class="qiu-date-panel__side">
139
+ <div class="qiu-date-panel__header">
140
+ <button type="button" class="qiu-date-panel__nav" @click="navRight(-1)">‹</button>
141
+ <span class="qiu-date-panel__title">{{ rightTitle }}</span>
142
+ <button type="button" class="qiu-date-panel__nav" @click="navRight(1)">›</button>
143
+ </div>
144
+
145
+ <template v-if="panelUnit === 'date'">
146
+ <div class="qiu-date-panel__weeks">
147
+ <span v-for="w in weekLabels" :key="`r-${w}`" class="qiu-date-panel__week">{{ w }}</span>
148
+ </div>
149
+ <div class="qiu-date-panel__grid qiu-date-panel__grid--day">
150
+ <button
151
+ v-for="cell in rightDayCells"
152
+ :key="`r-${cell.key}`"
153
+ type="button"
154
+ class="qiu-date-panel__cell"
155
+ :class="cellClass(cell)"
156
+ :disabled="cell.disabled"
157
+ @click="pickOnSide('end', cell)"
158
+ >
159
+ <div
160
+ class="qiu-date__cell"
161
+ :class="{ 'is-selected': cell.selected, 'is-today': cell.isToday }"
162
+ >
163
+ <span class="qiu-date__solar">{{ cell.day }}</span>
164
+ <span
165
+ v-if="showLunar"
166
+ class="qiu-date__lunar"
167
+ :class="{ 'is-festival': cell.lunar.festival }"
168
+ >
169
+ {{ cell.lunar.label }}
170
+ </span>
171
+ </div>
172
+ </button>
173
+ </div>
174
+ </template>
175
+
176
+ <div v-else-if="panelUnit === 'month'" class="qiu-date-panel__grid qiu-date-panel__grid--month">
177
+ <button
178
+ v-for="cell in rightMonthCells"
179
+ :key="`rm-${cell.key}`"
180
+ type="button"
181
+ class="qiu-date-panel__cell qiu-date-panel__cell--month"
182
+ :class="cellClass(cell)"
183
+ :disabled="cell.disabled"
184
+ @click="pickOnSide('end', cell)"
185
+ >
186
+ <div class="qiu-date__cell" :class="{ 'is-selected': cell.selected }">
187
+ <span class="qiu-date__solar">{{ cell.label }}</span>
188
+ </div>
189
+ </button>
190
+ </div>
191
+
192
+ <div v-else class="qiu-date-panel__grid qiu-date-panel__grid--year">
193
+ <button
194
+ v-for="cell in rightYearCells"
195
+ :key="`ry-${cell.key}`"
196
+ type="button"
197
+ class="qiu-date-panel__cell qiu-date-panel__cell--year"
198
+ :class="cellClass(cell)"
199
+ :disabled="cell.disabled"
200
+ @click="pickOnSide('end', cell)"
201
+ >
202
+ <div class="qiu-date__cell" :class="{ 'is-selected': cell.selected }">
203
+ <span class="qiu-date__solar">{{ cell.label }}</span>
204
+ </div>
205
+ </button>
206
+ </div>
207
+ </div>
208
+ </div>
209
+
210
+ <div v-if="isRange" class="qiu-date-panel__footer">
211
+ <button type="button" class="qiu-date-panel__btn qiu-date-panel__btn--text" @click="onCancel">
212
+ 取消
213
+ </button>
214
+ <button
215
+ type="button"
216
+ class="qiu-date-panel__btn qiu-date-panel__btn--primary"
217
+ :disabled="!canConfirm"
218
+ @click="onConfirm"
219
+ >
220
+ 确定
221
+ </button>
222
+ </div>
223
+ </div>
224
+ </Transition>
225
+ </Teleport>
226
+ </div>
227
+ </template>
228
+
229
+ <script lang="ts" setup>
230
+ /**
231
+ * QiuDate — 纯自研日历面板 + 中国农历
232
+ * 区间模式:左右双面板 + 联动纠偏 + 确定/取消(参考 el-date-picker)
233
+ */
234
+ import { Solar } from 'lunar-javascript'
235
+
236
+ defineOptions({ name: 'QiuDate' })
237
+
238
+ type PanelUnit = 'date' | 'month' | 'year'
239
+ type Side = 'start' | 'end'
240
+
241
+ const props = withDefaults(
242
+ defineProps<{
243
+ modelValue?: any
244
+ showLunar?: boolean
245
+ type?: string
246
+ placeholder?: string
247
+ startPlaceholder?: string
248
+ endPlaceholder?: string
249
+ format?: string
250
+ valueFormat?: string
251
+ disabled?: boolean
252
+ clearable?: boolean
253
+ size?: 'large' | 'default' | 'small'
254
+ editable?: boolean
255
+ readonly?: boolean
256
+ rangeSeparator?: string
257
+ disabledDate?: (date: Date) => boolean
258
+ shortcuts?: any[]
259
+ teleported?: boolean
260
+ popperClass?: string
261
+ }>(),
262
+ {
263
+ showLunar: true,
264
+ type: 'date',
265
+ clearable: true,
266
+ editable: true,
267
+ rangeSeparator: '至',
268
+ }
269
+ )
270
+
271
+ const emit = defineEmits<{
272
+ 'update:modelValue': [any]
273
+ change: [any]
274
+ 'calendar-change': [any]
275
+ 'visible-change': [boolean]
276
+ 'panel-change': [any]
277
+ }>()
278
+
279
+ const rootRef = ref<HTMLElement | null>(null)
280
+ const panelRef = ref<HTMLElement | null>(null)
281
+ const panelVisible = ref(false)
282
+ const panelStyle = ref<Record<string, string>>({})
283
+
284
+ const leftYear = ref(new Date().getFullYear())
285
+ const leftMonth = ref(new Date().getMonth())
286
+ const rightYear = ref(new Date().getFullYear())
287
+ const rightMonth = ref(new Date().getMonth())
288
+ /** 年份面板十年起点 */
289
+ const leftDecade = ref(Math.floor(new Date().getFullYear() / 10) * 10)
290
+ const rightDecade = ref(Math.floor(new Date().getFullYear() / 10) * 10 + 10)
291
+
292
+ const draftStart = ref<Date | null>(null)
293
+ const draftEnd = ref<Date | null>(null)
294
+
295
+ const weekLabels = ['日', '一', '二', '三', '四', '五', '六']
296
+ const monthLabels = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
297
+
298
+ const panelUnit = computed<PanelUnit>(() => {
299
+ const t = props.type || 'date'
300
+ if (t === 'year' || t === 'yearrange') return 'year'
301
+ if (t === 'month' || t === 'monthrange') return 'month'
302
+ return 'date'
303
+ })
304
+
305
+ const isRange = computed(() =>
306
+ ['daterange', 'datetimerange', 'monthrange', 'yearrange'].includes(props.type || '')
307
+ )
308
+
309
+ const resolveDateFormats = (type: string) => {
310
+ switch (type) {
311
+ case 'datetime':
312
+ case 'datetimerange':
313
+ return { format: 'YYYY-MM-DD HH:mm:ss', valueFormat: 'YYYY-MM-DD HH:mm:ss' }
314
+ case 'month':
315
+ case 'monthrange':
316
+ return { format: 'YYYY-MM', valueFormat: 'YYYY-MM' }
317
+ case 'year':
318
+ case 'yearrange':
319
+ return { format: 'YYYY', valueFormat: 'YYYY' }
320
+ default:
321
+ return { format: 'YYYY-MM-DD', valueFormat: 'YYYY-MM-DD' }
322
+ }
323
+ }
324
+
325
+ const valueFormat = computed(
326
+ () => props.valueFormat || resolveDateFormats(props.type || 'date').valueFormat
327
+ )
328
+ const displayFormat = computed(
329
+ () => props.format || resolveDateFormats(props.type || 'date').format
330
+ )
331
+
332
+ const startPlaceholderFallback = computed(() => {
333
+ if (panelUnit.value === 'year') return '开始年份'
334
+ if (panelUnit.value === 'month') return '开始月份'
335
+ return '开始日期'
336
+ })
337
+ const endPlaceholderFallback = computed(() => {
338
+ if (panelUnit.value === 'year') return '结束年份'
339
+ if (panelUnit.value === 'month') return '结束月份'
340
+ return '结束日期'
341
+ })
342
+ const singlePlaceholderFallback = computed(() => {
343
+ if (panelUnit.value === 'year') return '选择年份'
344
+ if (panelUnit.value === 'month') return '选择月份'
345
+ return '选择日期'
346
+ })
347
+
348
+ const pad = (n: number) => String(n).padStart(2, '0')
349
+
350
+ const formatDate = (d: Date | null, fmt: string) => {
351
+ if (!d) return ''
352
+ return fmt
353
+ .replace('YYYY', String(d.getFullYear()))
354
+ .replace('MM', pad(d.getMonth() + 1))
355
+ .replace('DD', pad(d.getDate()))
356
+ }
357
+
358
+ const parseValue = (v: any): Date | null => {
359
+ if (!v && v !== 0) return null
360
+ if (v instanceof Date) return Number.isNaN(v.getTime()) ? null : v
361
+ const s = String(v).trim()
362
+ if (!s) return null
363
+ let m = s.match(/^(\d{4})-(\d{2})-(\d{2})/)
364
+ if (m) return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]))
365
+ m = s.match(/^(\d{4})-(\d{2})$/)
366
+ if (m) return new Date(Number(m[1]), Number(m[2]) - 1, 1)
367
+ m = s.match(/^(\d{4})$/)
368
+ if (m) return new Date(Number(m[1]), 0, 1)
369
+ return null
370
+ }
371
+
372
+ const parseRange = (v: any): [Date | null, Date | null] => {
373
+ if (!Array.isArray(v)) return [null, null]
374
+ return [parseValue(v[0]), parseValue(v[1])]
375
+ }
376
+
377
+ const toOutput = (d: Date) => formatDate(d, valueFormat.value)
378
+
379
+ const dayStart = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate())
380
+ const monthStart = (d: Date) => new Date(d.getFullYear(), d.getMonth(), 1)
381
+ const yearStart = (d: Date) => new Date(d.getFullYear(), 0, 1)
382
+
383
+ const normalizeUnit = (d: Date) => {
384
+ if (panelUnit.value === 'year') return yearStart(d)
385
+ if (panelUnit.value === 'month') return monthStart(d)
386
+ return dayStart(d)
387
+ }
388
+
389
+ const unitTime = (d: Date) => normalizeUnit(d).getTime()
390
+
391
+ const sameUnit = (a: Date | null, b: Date | null) => !!a && !!b && unitTime(a) === unitTime(b)
392
+
393
+ const addMonths = (d: Date, n: number) => {
394
+ const next = new Date(d.getFullYear(), d.getMonth() + n, 1)
395
+ if (panelUnit.value === 'date') {
396
+ const day = d.getDate()
397
+ const max = new Date(next.getFullYear(), next.getMonth() + 1, 0).getDate()
398
+ next.setDate(Math.min(day, max))
399
+ }
400
+ return normalizeUnit(next)
401
+ }
402
+
403
+ const addYears = (d: Date, n: number) => {
404
+ const next = new Date(d)
405
+ next.setFullYear(d.getFullYear() + n)
406
+ return normalizeUnit(next)
407
+ }
408
+
409
+ const shiftEndForward = (start: Date) =>
410
+ panelUnit.value === 'year' ? addYears(start, 1) : addMonths(start, 1)
411
+
412
+ const shiftStartBackward = (end: Date) =>
413
+ panelUnit.value === 'year' ? addYears(end, -1) : addMonths(end, -1)
414
+
415
+ const singleDate = computed(() => (isRange.value ? null : parseValue(props.modelValue)))
416
+ const rangeDates = computed((): [Date | null, Date | null] =>
417
+ isRange.value ? parseRange(props.modelValue) : [null, null]
418
+ )
419
+
420
+ const activeStart = computed(() => (panelVisible.value && isRange.value ? draftStart.value : rangeDates.value[0]))
421
+ const activeEnd = computed(() => (panelVisible.value && isRange.value ? draftEnd.value : rangeDates.value[1]))
422
+
423
+ const singleText = computed(() => formatDate(singleDate.value, displayFormat.value))
424
+ const displayStartText = computed(() =>
425
+ formatDate(panelVisible.value ? draftStart.value : rangeDates.value[0], displayFormat.value)
426
+ )
427
+ const displayEndText = computed(() =>
428
+ formatDate(panelVisible.value ? draftEnd.value : rangeDates.value[1], displayFormat.value)
429
+ )
430
+
431
+ const hasValue = computed(() => {
432
+ if (isRange.value) return !!(rangeDates.value[0] || rangeDates.value[1])
433
+ return !!singleDate.value
434
+ })
435
+
436
+ const canConfirm = computed(() => !!(draftStart.value && draftEnd.value))
437
+
438
+ const leftTitle = computed(() => {
439
+ if (panelUnit.value === 'year') return `${leftDecade.value}年 - ${leftDecade.value + 9}年`
440
+ if (panelUnit.value === 'month') return `${leftYear.value}年`
441
+ return `${leftYear.value}年 ${leftMonth.value + 1}月`
442
+ })
443
+
444
+ const rightTitle = computed(() => {
445
+ if (panelUnit.value === 'year') return `${rightDecade.value}年 - ${rightDecade.value + 9}年`
446
+ if (panelUnit.value === 'month') return `${rightYear.value}年`
447
+ return `${rightYear.value}年 ${rightMonth.value + 1}月`
448
+ })
449
+
450
+ const lunarCache = new Map<string, { label: string; festival?: string }>()
451
+
452
+ const lunarOfDate = (d: Date) => {
453
+ try {
454
+ const key = `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`
455
+ if (lunarCache.has(key)) return lunarCache.get(key)!
456
+ const solar = Solar.fromYmd(d.getFullYear(), d.getMonth() + 1, d.getDate())
457
+ const lunar = solar.getLunar()
458
+ const festivals = [...lunar.getFestivals(), ...solar.getFestivals()]
459
+ const jieQi = lunar.getJieQi()
460
+ let label = lunar.getDayInChinese()
461
+ let festival = ''
462
+ if (festivals.length) {
463
+ festival = festivals[0]
464
+ label = festival
465
+ } else if (jieQi) {
466
+ festival = jieQi
467
+ label = jieQi
468
+ } else if (lunar.getDay() === 1) {
469
+ label = lunar.getMonthInChinese() + '月'
470
+ }
471
+ const info = { label, festival: festival || undefined }
472
+ lunarCache.set(key, info)
473
+ return info
474
+ } catch {
475
+ return { label: '' }
476
+ }
477
+ }
478
+
479
+ const isToday = (d: Date) => {
480
+ const n = new Date()
481
+ return d.getFullYear() === n.getFullYear() && d.getMonth() === n.getMonth() && d.getDate() === n.getDate()
482
+ }
483
+
484
+ const inRangeUnit = (d: Date, start: Date | null, end: Date | null) => {
485
+ if (!start || !end) return false
486
+ const t = unitTime(d)
487
+ const a = unitTime(start)
488
+ const b = unitTime(end)
489
+ const lo = Math.min(a, b)
490
+ const hi = Math.max(a, b)
491
+ return t >= lo && t <= hi
492
+ }
493
+
494
+ const rangeStateOf = (date: Date) => {
495
+ const s = isRange.value ? activeStart.value : null
496
+ const e = isRange.value ? activeEnd.value : null
497
+ if (isRange.value) {
498
+ if (sameUnit(date, s) && sameUnit(date, e)) return 'start-date end-date'
499
+ if (sameUnit(date, s)) return 'start-date'
500
+ if (sameUnit(date, e)) return 'end-date'
501
+ if (inRangeUnit(date, s, e)) return 'in-range'
502
+ return ''
503
+ }
504
+ return ''
505
+ }
506
+
507
+ const buildDayCells = (y: number, m: number) => {
508
+ const first = new Date(y, m, 1)
509
+ const startOffset = first.getDay()
510
+ const daysInMonth = new Date(y, m + 1, 0).getDate()
511
+ const cells: any[] = []
512
+
513
+ const push = (date: Date, inMonth: boolean) => {
514
+ const disabled = props.disabledDate?.(date) ?? false
515
+ const selected = isRange.value
516
+ ? sameUnit(date, activeStart.value) || sameUnit(date, activeEnd.value)
517
+ : sameUnit(date, singleDate.value)
518
+ cells.push({
519
+ key: `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`,
520
+ date: normalizeUnit(date),
521
+ day: date.getDate(),
522
+ label: String(date.getDate()),
523
+ inMonth,
524
+ disabled,
525
+ selected,
526
+ rangeState: rangeStateOf(date),
527
+ isToday: isToday(date),
528
+ lunar: lunarOfDate(date),
529
+ })
530
+ }
531
+
532
+ for (let i = 0; i < startOffset; i++) {
533
+ push(new Date(y, m, -startOffset + i + 1), false)
534
+ }
535
+ for (let day = 1; day <= daysInMonth; day++) {
536
+ push(new Date(y, m, day), true)
537
+ }
538
+ while (cells.length % 7 !== 0) {
539
+ const last = cells[cells.length - 1].date as Date
540
+ push(new Date(last.getFullYear(), last.getMonth(), last.getDate() + 1), false)
541
+ }
542
+ return cells
543
+ }
544
+
545
+ const buildMonthCells = (y: number) =>
546
+ monthLabels.map((label, i) => {
547
+ const date = new Date(y, i, 1)
548
+ const disabled = props.disabledDate?.(date) ?? false
549
+ const selected = isRange.value
550
+ ? sameUnit(date, activeStart.value) || sameUnit(date, activeEnd.value)
551
+ : sameUnit(date, singleDate.value)
552
+ return {
553
+ key: `${y}-${i}`,
554
+ date: normalizeUnit(date),
555
+ label,
556
+ day: i + 1,
557
+ inMonth: true,
558
+ disabled,
559
+ selected,
560
+ rangeState: rangeStateOf(date),
561
+ isToday: false,
562
+ lunar: { label: '' },
563
+ }
564
+ })
565
+
566
+ const buildYearCells = (decade: number) =>
567
+ Array.from({ length: 10 }, (_, i) => {
568
+ const y = decade + i
569
+ const date = new Date(y, 0, 1)
570
+ const disabled = props.disabledDate?.(date) ?? false
571
+ const selected = isRange.value
572
+ ? sameUnit(date, activeStart.value) || sameUnit(date, activeEnd.value)
573
+ : sameUnit(date, singleDate.value)
574
+ return {
575
+ key: `y-${y}`,
576
+ date: normalizeUnit(date),
577
+ label: String(y),
578
+ day: y,
579
+ inMonth: true,
580
+ disabled,
581
+ selected,
582
+ rangeState: rangeStateOf(date),
583
+ isToday: false,
584
+ lunar: { label: '' },
585
+ }
586
+ })
587
+
588
+ const leftDayCells = computed(() => buildDayCells(leftYear.value, leftMonth.value))
589
+ const rightDayCells = computed(() => buildDayCells(rightYear.value, rightMonth.value))
590
+ const leftMonthCells = computed(() => buildMonthCells(leftYear.value))
591
+ const rightMonthCells = computed(() => buildMonthCells(rightYear.value))
592
+ const leftYearCells = computed(() => buildYearCells(leftDecade.value))
593
+ const rightYearCells = computed(() => buildYearCells(rightDecade.value))
594
+
595
+ const cellClass = (cell: any) => {
596
+ const rs = String(cell.rangeState || '')
597
+ return {
598
+ 'is-other-month': !cell.inMonth,
599
+ 'is-disabled': cell.disabled,
600
+ 'is-selected': cell.selected,
601
+ 'is-today': cell.isToday,
602
+ 'in-range': rs.includes('in-range'),
603
+ 'start-date': rs.includes('start-date'),
604
+ 'end-date': rs.includes('end-date'),
605
+ }
606
+ }
607
+
608
+ const syncRightViewAfterLeft = () => {
609
+ if (panelUnit.value === 'date') {
610
+ let y = leftYear.value
611
+ let m = leftMonth.value + 1
612
+ if (m > 11) {
613
+ m = 0
614
+ y += 1
615
+ }
616
+ rightYear.value = y
617
+ rightMonth.value = m
618
+ } else if (panelUnit.value === 'month') {
619
+ rightYear.value = leftYear.value + 1
620
+ } else {
621
+ rightDecade.value = leftDecade.value + 10
622
+ }
623
+ }
624
+
625
+ const syncLeftViewFromStart = (d: Date) => {
626
+ leftYear.value = d.getFullYear()
627
+ leftMonth.value = d.getMonth()
628
+ leftDecade.value = Math.floor(d.getFullYear() / 10) * 10
629
+ }
630
+
631
+ const syncRightViewFromEnd = (d: Date) => {
632
+ rightYear.value = d.getFullYear()
633
+ rightMonth.value = d.getMonth()
634
+ rightDecade.value = Math.floor(d.getFullYear() / 10) * 10
635
+ }
636
+
637
+ const updatePanelPosition = () => {
638
+ const root = rootRef.value
639
+ const panel = panelRef.value
640
+ if (!root) return
641
+ const rect = root.getBoundingClientRect()
642
+ const panelW = panel?.offsetWidth || (isRange.value ? 640 : 322)
643
+ const panelH = panel?.offsetHeight || 360
644
+ let top = rect.bottom + 4
645
+ let left = rect.left
646
+ if (left + panelW > window.innerWidth - 8) {
647
+ left = Math.max(8, window.innerWidth - panelW - 8)
648
+ }
649
+ if (top + panelH > window.innerHeight - 8) {
650
+ top = Math.max(8, rect.top - panelH - 4)
651
+ }
652
+ panelStyle.value = {
653
+ position: 'fixed',
654
+ top: `${Math.max(8, top)}px`,
655
+ left: `${Math.max(8, left)}px`,
656
+ zIndex: '4000',
657
+ }
658
+ }
659
+
660
+ const openPanel = async () => {
661
+ if (props.disabled) return
662
+
663
+ // 先按触发器定位,避免面板以空 style 落在页面左上角
664
+ updatePanelPosition()
665
+ panelVisible.value = true
666
+ emit('visible-change', true)
667
+
668
+ if (isRange.value) {
669
+ const [s, e] = rangeDates.value
670
+ draftStart.value = s ? normalizeUnit(s) : null
671
+ draftEnd.value = e ? normalizeUnit(e) : null
672
+ const anchorStart = draftStart.value || new Date()
673
+ const anchorEnd = draftEnd.value || shiftEndForward(normalizeUnit(anchorStart))
674
+ syncLeftViewFromStart(anchorStart)
675
+ syncRightViewFromEnd(anchorEnd)
676
+ // 保证右面板不早于左面板视图
677
+ if (panelUnit.value === 'date') {
678
+ const leftKey = leftYear.value * 12 + leftMonth.value
679
+ const rightKey = rightYear.value * 12 + rightMonth.value
680
+ if (rightKey <= leftKey) syncRightViewAfterLeft()
681
+ } else if (panelUnit.value === 'month') {
682
+ if (rightYear.value <= leftYear.value) rightYear.value = leftYear.value + 1
683
+ } else if (rightDecade.value <= leftDecade.value) {
684
+ rightDecade.value = leftDecade.value + 10
685
+ }
686
+ } else {
687
+ const anchor = singleDate.value || new Date()
688
+ syncLeftViewFromStart(anchor)
689
+ }
690
+
691
+ await nextTick()
692
+ requestAnimationFrame(() => {
693
+ updatePanelPosition()
694
+ requestAnimationFrame(() => updatePanelPosition())
695
+ })
696
+ emit('panel-change', [leftYear.value, leftMonth.value])
697
+ }
698
+
699
+ const closePanel = () => {
700
+ if (!panelVisible.value) return
701
+ panelVisible.value = false
702
+ draftStart.value = null
703
+ draftEnd.value = null
704
+ emit('visible-change', false)
705
+ }
706
+
707
+ const togglePanel = () => {
708
+ if (panelVisible.value) closePanel()
709
+ else openPanel()
710
+ }
711
+
712
+ const navLeft = (dir: number) => {
713
+ if (panelUnit.value === 'date') {
714
+ let m = leftMonth.value + dir
715
+ let y = leftYear.value
716
+ if (m < 0) {
717
+ m = 11
718
+ y -= 1
719
+ } else if (m > 11) {
720
+ m = 0
721
+ y += 1
722
+ }
723
+ leftYear.value = y
724
+ leftMonth.value = m
725
+ } else if (panelUnit.value === 'month') {
726
+ leftYear.value += dir
727
+ } else {
728
+ leftDecade.value += dir * 10
729
+ }
730
+ emit('panel-change', [leftYear.value, leftMonth.value])
731
+ }
732
+
733
+ const navRight = (dir: number) => {
734
+ if (panelUnit.value === 'date') {
735
+ let m = rightMonth.value + dir
736
+ let y = rightYear.value
737
+ if (m < 0) {
738
+ m = 11
739
+ y -= 1
740
+ } else if (m > 11) {
741
+ m = 0
742
+ y += 1
743
+ }
744
+ rightYear.value = y
745
+ rightMonth.value = m
746
+ } else if (panelUnit.value === 'month') {
747
+ rightYear.value += dir
748
+ } else {
749
+ rightDecade.value += dir * 10
750
+ }
751
+ emit('panel-change', [rightYear.value, rightMonth.value])
752
+ }
753
+
754
+ const emitChange = (val: any) => {
755
+ emit('update:modelValue', val)
756
+ emit('change', val)
757
+ emit('calendar-change', val)
758
+ }
759
+
760
+ const pickOnSide = (side: Side, cell: any) => {
761
+ if (cell.disabled) return
762
+ const d = normalizeUnit(cell.date as Date)
763
+
764
+ if (!isRange.value) {
765
+ emitChange(toOutput(d))
766
+ closePanel()
767
+ return
768
+ }
769
+
770
+ if (side === 'start') {
771
+ draftStart.value = d
772
+ if (draftEnd.value && unitTime(d) > unitTime(draftEnd.value)) {
773
+ draftEnd.value = shiftEndForward(d)
774
+ syncRightViewFromEnd(draftEnd.value)
775
+ }
776
+ } else {
777
+ draftEnd.value = d
778
+ if (draftStart.value && unitTime(d) < unitTime(draftStart.value)) {
779
+ draftStart.value = shiftStartBackward(d)
780
+ syncLeftViewFromStart(draftStart.value)
781
+ }
782
+ }
783
+ }
784
+
785
+ const onConfirm = () => {
786
+ if (!draftStart.value || !draftEnd.value) return
787
+ let s = draftStart.value
788
+ let e = draftEnd.value
789
+ if (unitTime(s) > unitTime(e)) {
790
+ e = shiftEndForward(s)
791
+ }
792
+ emitChange([toOutput(s), toOutput(e)])
793
+ closePanel()
794
+ }
795
+
796
+ /** 取消 = 空选并关闭(参考 el-date-picker 清空语义) */
797
+ const onCancel = () => {
798
+ draftStart.value = null
799
+ draftEnd.value = null
800
+ emitChange([])
801
+ closePanel()
802
+ }
803
+
804
+ const clearValue = () => {
805
+ emitChange(isRange.value ? [] : '')
806
+ }
807
+
808
+ const onDocClick = (e: MouseEvent) => {
809
+ if (!panelVisible.value) return
810
+ const t = e.target as Node
811
+ if (rootRef.value?.contains(t) || panelRef.value?.contains(t)) return
812
+ // 点外部:丢弃未确认草稿,保留原值
813
+ closePanel()
814
+ }
815
+
816
+ watch(panelVisible, (v) => {
817
+ if (v) {
818
+ document.addEventListener('click', onDocClick, true)
819
+ window.addEventListener('scroll', updatePanelPosition, true)
820
+ window.addEventListener('resize', updatePanelPosition)
821
+ } else {
822
+ document.removeEventListener('click', onDocClick, true)
823
+ window.removeEventListener('scroll', updatePanelPosition, true)
824
+ window.removeEventListener('resize', updatePanelPosition)
825
+ }
826
+ })
827
+
828
+ onBeforeUnmount(() => {
829
+ document.removeEventListener('click', onDocClick, true)
830
+ window.removeEventListener('scroll', updatePanelPosition, true)
831
+ window.removeEventListener('resize', updatePanelPosition)
832
+ })
833
+ </script>
834
+
835
+ <style lang="scss">
836
+ .qiu-date {
837
+ display: inline-flex;
838
+ min-width: 220px;
839
+
840
+ &--daterange,
841
+ &--datetimerange,
842
+ &--monthrange,
843
+ &--yearrange {
844
+ min-width: 280px;
845
+ }
846
+
847
+ &__editor {
848
+ display: flex;
849
+ flex: 1;
850
+ gap: 4px;
851
+ align-items: center;
852
+ min-height: 32px;
853
+ padding: 0 8px;
854
+ cursor: pointer;
855
+ background: var(--qiu-bg-color, #fff);
856
+ border: 1px solid var(--qiu-border-color, #dcdfe6);
857
+ border-radius: var(--qiu-border-radius-base, 4px);
858
+ transition: border-color 0.2s ease;
859
+
860
+ &:hover,
861
+ .is-focused & {
862
+ border-color: var(--qiu-color-primary, #409eff);
863
+ }
864
+ }
865
+
866
+ &__input {
867
+ flex: 1;
868
+ min-width: 0;
869
+ padding: 0;
870
+ font-size: 14px;
871
+ color: var(--qiu-text-color-primary, #303133);
872
+ cursor: pointer;
873
+ background: transparent;
874
+ border: 0;
875
+ outline: none;
876
+
877
+ &--single {
878
+ width: 100%;
879
+ }
880
+ }
881
+
882
+ &__separator {
883
+ flex-shrink: 0;
884
+ font-size: 13px;
885
+ color: var(--qiu-text-color-secondary, #909399);
886
+ }
887
+
888
+ &__clear {
889
+ flex-shrink: 0;
890
+ padding: 0 4px;
891
+ font-size: 16px;
892
+ line-height: 1;
893
+ color: var(--qiu-text-color-secondary, #909399);
894
+ cursor: pointer;
895
+ background: transparent;
896
+ border: 0;
897
+ }
898
+
899
+ &__icon {
900
+ flex-shrink: 0;
901
+ font-size: 16px;
902
+ color: var(--qiu-text-color-secondary, #909399);
903
+ }
904
+ }
905
+
906
+ .qiu-date-panel {
907
+ position: fixed;
908
+ top: 0;
909
+ left: 0;
910
+ width: 322px;
911
+ padding: 12px;
912
+ background: var(--qiu-bg-color-overlay, #fff);
913
+ border: 1px solid var(--qiu-border-color-light, #e4e7ed);
914
+ border-radius: 8px;
915
+ box-shadow: var(--qiu-box-shadow-light, 0 2px 12px rgb(0 0 0 / 10%));
916
+ z-index: 4000;
917
+
918
+ &--range {
919
+ width: auto;
920
+ max-width: calc(100vw - 16px);
921
+ }
922
+
923
+ &__body {
924
+ display: flex;
925
+ gap: 0;
926
+
927
+ &.is-range .qiu-date-panel__side + .qiu-date-panel__side {
928
+ margin-left: 12px;
929
+ padding-left: 12px;
930
+ border-left: 1px solid var(--qiu-border-color-lighter, #ebeef5);
931
+ }
932
+ }
933
+
934
+ &__side {
935
+ width: 298px;
936
+ }
937
+
938
+ &__header {
939
+ display: flex;
940
+ align-items: center;
941
+ justify-content: space-between;
942
+ margin-bottom: 8px;
943
+ }
944
+
945
+ &__title {
946
+ font-size: 14px;
947
+ font-weight: 600;
948
+ color: var(--qiu-text-color-primary, #303133);
949
+ }
950
+
951
+ &__nav {
952
+ width: 28px;
953
+ height: 28px;
954
+ font-size: 18px;
955
+ line-height: 1;
956
+ color: var(--qiu-text-color-regular, #606266);
957
+ cursor: pointer;
958
+ background: transparent;
959
+ border: 0;
960
+ border-radius: 4px;
961
+
962
+ &:hover {
963
+ color: var(--qiu-color-primary, #409eff);
964
+ background: var(--qiu-fill-color-light, #f5f7fa);
965
+ }
966
+ }
967
+
968
+ &__weeks {
969
+ display: grid;
970
+ grid-template-columns: repeat(7, 1fr);
971
+ margin-bottom: 4px;
972
+ }
973
+
974
+ &__week {
975
+ font-size: 12px;
976
+ line-height: 28px;
977
+ color: var(--qiu-text-color-secondary, #909399);
978
+ text-align: center;
979
+ }
980
+
981
+ &__grid {
982
+ display: grid;
983
+ gap: 2px 0;
984
+
985
+ &--day {
986
+ grid-template-columns: repeat(7, 1fr);
987
+ }
988
+
989
+ &--month,
990
+ &--year {
991
+ grid-template-columns: repeat(3, 1fr);
992
+ gap: 8px;
993
+ padding: 8px 0 4px;
994
+ }
995
+ }
996
+
997
+ &__cell {
998
+ height: auto;
999
+ padding: 3px 0;
1000
+ cursor: pointer;
1001
+ background: transparent;
1002
+ border: 0;
1003
+
1004
+ &.is-disabled {
1005
+ cursor: not-allowed;
1006
+ opacity: 0.4;
1007
+ }
1008
+
1009
+ &.is-other-month .qiu-date__solar {
1010
+ color: var(--qiu-text-color-placeholder, #c0c4cc);
1011
+ }
1012
+
1013
+ &--month .qiu-date__cell,
1014
+ &--year .qiu-date__cell {
1015
+ min-height: 40px;
1016
+ }
1017
+ }
1018
+
1019
+ &__footer {
1020
+ display: flex;
1021
+ gap: 8px;
1022
+ justify-content: flex-end;
1023
+ padding-top: 10px;
1024
+ margin-top: 8px;
1025
+ border-top: 1px solid var(--qiu-border-color-lighter, #ebeef5);
1026
+ }
1027
+
1028
+ &__btn {
1029
+ min-width: 60px;
1030
+ height: 28px;
1031
+ padding: 0 12px;
1032
+ font-size: 13px;
1033
+ cursor: pointer;
1034
+ border-radius: 4px;
1035
+ border: 1px solid var(--qiu-border-color, #dcdfe6);
1036
+ background: var(--qiu-bg-color, #fff);
1037
+ color: var(--qiu-text-color-regular, #606266);
1038
+
1039
+ &:disabled {
1040
+ cursor: not-allowed;
1041
+ opacity: 0.5;
1042
+ }
1043
+
1044
+ &--text {
1045
+ border-color: transparent;
1046
+ background: transparent;
1047
+ }
1048
+
1049
+ &--primary {
1050
+ color: #fff;
1051
+ background: var(--qiu-color-primary, #409eff);
1052
+ border-color: var(--qiu-color-primary, #409eff);
1053
+ }
1054
+ }
1055
+
1056
+ .qiu-date__cell {
1057
+ display: flex;
1058
+ flex-direction: column;
1059
+ align-items: center;
1060
+ justify-content: center;
1061
+ width: 100%;
1062
+ min-height: 32px;
1063
+ line-height: 1.15;
1064
+ border-radius: 4px;
1065
+ }
1066
+
1067
+ .qiu-date__solar {
1068
+ font-size: 13px;
1069
+ font-weight: 500;
1070
+ color: var(--qiu-text-color-primary, #303133);
1071
+ }
1072
+
1073
+ .qiu-date__lunar {
1074
+ margin-top: 2px;
1075
+ font-size: 10px;
1076
+ color: var(--qiu-text-color-secondary, #909399);
1077
+ transform: scale(0.92);
1078
+
1079
+ &.is-festival {
1080
+ color: var(--qiu-color-danger, #f56c6c);
1081
+ }
1082
+ }
1083
+
1084
+ &--lunar .qiu-date__cell {
1085
+ min-height: 48px;
1086
+ }
1087
+
1088
+ .qiu-date-panel__cell.in-range:not(.start-date):not(.end-date) .qiu-date__cell {
1089
+ color: var(--qiu-color-primary, #409eff);
1090
+ background-color: var(--qiu-color-primary-light-8, #ecf5ff) !important;
1091
+ border-radius: 6px;
1092
+ box-shadow: inset 0 0 0 1px var(--qiu-color-primary-light-5, #b3d8ff);
1093
+ }
1094
+
1095
+ .qiu-date-panel__cell.start-date .qiu-date__cell,
1096
+ .qiu-date-panel__cell.end-date .qiu-date__cell,
1097
+ .qiu-date-panel__cell.is-selected .qiu-date__cell {
1098
+ color: #fff;
1099
+ background-color: var(--qiu-color-primary, #409eff) !important;
1100
+ border-radius: 6px;
1101
+ }
1102
+
1103
+ .qiu-date-panel__cell.start-date .qiu-date__solar,
1104
+ .qiu-date-panel__cell.start-date .qiu-date__lunar,
1105
+ .qiu-date-panel__cell.end-date .qiu-date__solar,
1106
+ .qiu-date-panel__cell.end-date .qiu-date__lunar,
1107
+ .qiu-date-panel__cell.is-selected .qiu-date__solar,
1108
+ .qiu-date-panel__cell.is-selected .qiu-date__lunar {
1109
+ color: #fff !important;
1110
+ }
1111
+
1112
+ .qiu-date-panel__cell.is-today:not(.start-date):not(.end-date):not(.is-selected):not(.in-range)
1113
+ .qiu-date__solar {
1114
+ font-weight: 700;
1115
+ color: var(--qiu-color-primary, #409eff);
1116
+ }
1117
+
1118
+ .qiu-date-panel__cell:not(.is-disabled):hover:not(.start-date):not(.end-date):not(.is-selected)
1119
+ .qiu-date__cell {
1120
+ background: var(--qiu-fill-color-light, #f5f7fa);
1121
+ }
1122
+ }
1123
+
1124
+ .qiu-date-fade-enter-active,
1125
+ .qiu-date-fade-leave-active {
1126
+ transition: opacity 0.15s ease, transform 0.15s ease;
1127
+ }
1128
+
1129
+ .qiu-date-fade-enter-from,
1130
+ .qiu-date-fade-leave-to {
1131
+ opacity: 0;
1132
+ transform: translateY(-4px);
1133
+ }
1134
+ </style>