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,132 @@
1
+ /**
2
+ * Banner / 画布 HTML 导出(含链接热区)
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ import type { CanvasKitDoc, CanvasKitElement, MergeContext } from '../types'
8
+ import { mergeTemplateText, sortCanvasElements } from '../modules/merge'
9
+ import { downloadBlob } from './png'
10
+
11
+ const MM_TO_PX = 96 / 25.4
12
+
13
+ export type ExportHtmlOptions = {
14
+ fileName?: string
15
+ title?: string
16
+ /** 合并后再写死 URL / 文本 */
17
+ context?: MergeContext | Record<string, string>
18
+ /** 导出单位:优先 canvas.unit */
19
+ forceUnit?: 'mm' | 'px'
20
+ }
21
+
22
+ function canvasSize(doc: CanvasKitDoc, unit: 'mm' | 'px') {
23
+ const c = doc.canvas
24
+ if (unit === 'px') {
25
+ const w = c.widthPx ?? Math.round(c.widthMm * MM_TO_PX)
26
+ const h = c.heightPx ?? Math.round(c.heightMm * MM_TO_PX)
27
+ return { w, h, unit: 'px' as const }
28
+ }
29
+ return { w: c.widthMm, h: c.heightMm, unit: 'mm' as const }
30
+ }
31
+
32
+ function esc(s: string) {
33
+ return String(s || '')
34
+ .replace(/&/g, '&amp;')
35
+ .replace(/</g, '&lt;')
36
+ .replace(/>/g, '&gt;')
37
+ .replace(/"/g, '&quot;')
38
+ }
39
+
40
+ function resolveAsset(src: string) {
41
+ return src || ''
42
+ }
43
+
44
+ function elBoxStyle(el: CanvasKitElement, unit: 'mm' | 'px') {
45
+ const x = unit === 'px' ? `${Math.round(el.xMm * MM_TO_PX)}px` : `${el.xMm}mm`
46
+ const y = unit === 'px' ? `${Math.round(el.yMm * MM_TO_PX)}px` : `${el.yMm}mm`
47
+ const w = unit === 'px' ? `${Math.round(el.wMm * MM_TO_PX)}px` : `${el.wMm}mm`
48
+ const h = unit === 'px' ? `${Math.round(el.hMm * MM_TO_PX)}px` : `${el.hMm}mm`
49
+ const transforms: string[] = []
50
+ if (el.rotation) transforms.push(`rotate(${el.rotation}deg)`)
51
+ if (el.flipX) transforms.push('scaleX(-1)')
52
+ if (el.flipY) transforms.push('scaleY(-1)')
53
+ return `position:absolute;left:${x};top:${y};width:${w};height:${h};z-index:${el.zIndex ?? 1};box-sizing:border-box;${
54
+ transforms.length ? `transform:${transforms.join(' ')};transform-origin:center center;` : ''
55
+ }`
56
+ }
57
+
58
+ function renderElementHtml(el: CanvasKitElement, ctx: MergeContext, unit: 'mm' | 'px'): string {
59
+ const box = elBoxStyle(el, unit)
60
+ let inner = ''
61
+ if (el.type === 'text') {
62
+ const text = esc(mergeTemplateText(el.text, ctx))
63
+ const vertical = el.textDirection === 'vertical'
64
+ inner = `<div style="${box}display:flex;align-items:center;justify-content:flex-start;font-size:${el.fontSize}pt;font-family:${esc(
65
+ el.fontFamily
66
+ )};color:${esc(el.color)};white-space:pre-wrap;word-break:break-word;overflow:hidden;${
67
+ vertical ? 'writing-mode:vertical-rl;text-orientation:upright;' : ''
68
+ }">${text}</div>`
69
+ } else if (el.type === 'image' || el.type === 'seal') {
70
+ const src = esc(resolveAsset(el.src))
71
+ inner = `<div style="${box}display:flex;align-items:center;justify-content:center;"><img src="${src}" alt="" style="max-width:100%;max-height:100%;object-fit:contain"/></div>`
72
+ } else if (el.type === 'shape') {
73
+ const bg = esc(el.background || 'transparent')
74
+ const opacity = el.opacity != null ? `opacity:${el.opacity};` : ''
75
+ inner = `<div style="${box}${opacity}background:${bg};border-radius:${el.shape === 'circle' ? '50%' : '0'};"></div>`
76
+ } else {
77
+ return ''
78
+ }
79
+
80
+ if (el.link?.href) {
81
+ const href = esc(mergeTemplateText(el.link.href, ctx))
82
+ const target = el.link.target === '_self' ? '_self' : '_blank'
83
+ const rel = target === '_blank' ? ' noopener noreferrer' : ''
84
+ return `<a href="${href}" target="${target}" rel="${rel.trim()}" style="display:contents;text-decoration:none;color:inherit;">${inner}</a>`
85
+ }
86
+ return inner
87
+ }
88
+
89
+ /** 生成自包含 HTML 字符串(Banner 投放用) */
90
+ export function buildCanvasHtml(doc: CanvasKitDoc, options: ExportHtmlOptions = {}): string {
91
+ const ctx = (options.context || {}) as MergeContext
92
+ const unit = options.forceUnit || doc.canvas.unit || (doc.mode === 'banner' ? 'px' : 'mm')
93
+ const size = canvasSize(doc, unit)
94
+ const showBorder = doc.canvas.showBorder !== false && doc.mode !== 'banner'
95
+ const border = showBorder
96
+ ? `border:${doc.canvas.borderWidthMm || 0.35}mm solid ${esc(doc.canvas.borderColor || '#334155')};`
97
+ : 'border:none;'
98
+ const bg = doc.canvas.backgroundImage
99
+ ? `background-image:url(${esc(doc.canvas.backgroundImage)});background-size:cover;background-position:center;`
100
+ : `background:${esc(doc.canvas.background || 'transparent')};`
101
+ const els = sortCanvasElements(doc.elements || [])
102
+ .map((el) => renderElementHtml(el, ctx, unit))
103
+ .join('\n')
104
+
105
+ const title = esc(options.title || 'Banner')
106
+ return `<!DOCTYPE html>
107
+ <html lang="zh-CN">
108
+ <head>
109
+ <meta charset="utf-8"/>
110
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
111
+ <title>${title}</title>
112
+ <style>
113
+ html,body{margin:0;padding:0;background:#f8fafc;}
114
+ .qiu-canvas-banner{position:relative;overflow:hidden;margin:0 auto;${border}${bg}
115
+ width:${size.w}${size.unit};height:${size.h}${size.unit};}
116
+ a{color:inherit;}
117
+ </style>
118
+ </head>
119
+ <body>
120
+ <div class="qiu-canvas-banner">
121
+ ${els}
122
+ </div>
123
+ </body>
124
+ </html>`
125
+ }
126
+
127
+ export function downloadCanvasHtml(doc: CanvasKitDoc, options: ExportHtmlOptions = {}) {
128
+ const html = buildCanvasHtml(doc, options)
129
+ const blob = new Blob([html], { type: 'text/html;charset=utf-8' })
130
+ downloadBlob(blob, options.fileName || `banner-${Date.now()}.html`)
131
+ return blob
132
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 画布导出:PDF(单页,基于 html2canvas + jspdf)
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ import { jsPDF } from 'jspdf'
8
+ import { exportElementToPng, downloadBlob } from './png'
9
+
10
+ export type ExportPdfOptions = {
11
+ fileName?: string
12
+ /** mm */
13
+ widthMm?: number
14
+ heightMm?: number
15
+ scale?: number
16
+ }
17
+
18
+ export async function exportElementToPdf(
19
+ el: HTMLElement,
20
+ options: ExportPdfOptions = {}
21
+ ): Promise<Blob> {
22
+ const png = await exportElementToPng(el, { scale: options.scale ?? 2 })
23
+ const dataUrl = await blobToDataUrl(png)
24
+ const w = options.widthMm ?? 210
25
+ const h = options.heightMm ?? 297
26
+ const pdf = new jsPDF({
27
+ orientation: w > h ? 'landscape' : 'portrait',
28
+ unit: 'mm',
29
+ format: [w, h],
30
+ })
31
+ pdf.addImage(dataUrl, 'PNG', 0, 0, w, h)
32
+ return pdf.output('blob')
33
+ }
34
+
35
+ export async function downloadElementPdf(el: HTMLElement, options: ExportPdfOptions = {}) {
36
+ const blob = await exportElementToPdf(el, options)
37
+ downloadBlob(blob, options.fileName || `canvas-${Date.now()}.pdf`)
38
+ return blob
39
+ }
40
+
41
+ function blobToDataUrl(blob: Blob): Promise<string> {
42
+ return new Promise((resolve, reject) => {
43
+ const reader = new FileReader()
44
+ reader.onload = () => resolve(String(reader.result || ''))
45
+ reader.onerror = () => reject(reader.error)
46
+ reader.readAsDataURL(blob)
47
+ })
48
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * 画布导出:PNG(基于 DOM 节点 html2canvas)
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ import html2canvas from 'html2canvas'
8
+
9
+ export type ExportPngOptions = {
10
+ fileName?: string
11
+ scale?: number
12
+ backgroundColor?: string | null
13
+ }
14
+
15
+ export async function exportElementToPng(
16
+ el: HTMLElement,
17
+ options: ExportPngOptions = {}
18
+ ): Promise<Blob> {
19
+ const canvas = await html2canvas(el, {
20
+ scale: options.scale ?? 2,
21
+ backgroundColor: options.backgroundColor === undefined ? '#ffffff' : options.backgroundColor,
22
+ useCORS: true,
23
+ logging: false,
24
+ })
25
+ return new Promise((resolve, reject) => {
26
+ canvas.toBlob(
27
+ (blob) => {
28
+ if (!blob) reject(new Error('PNG export failed'))
29
+ else resolve(blob)
30
+ },
31
+ 'image/png',
32
+ 1
33
+ )
34
+ })
35
+ }
36
+
37
+ export function downloadBlob(blob: Blob, fileName: string) {
38
+ const url = URL.createObjectURL(blob)
39
+ const a = document.createElement('a')
40
+ a.href = url
41
+ a.download = fileName
42
+ a.click()
43
+ URL.revokeObjectURL(url)
44
+ }
45
+
46
+ export async function downloadElementPng(el: HTMLElement, options: ExportPngOptions = {}) {
47
+ const blob = await exportElementToPng(el, options)
48
+ downloadBlob(blob, options.fileName || `canvas-${Date.now()}.png`)
49
+ return blob
50
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * QiuCanvasKit — 统一证件 / 桌签 / Banner 画布套件
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ export { default as QiuCanvasEditor } from './QiuCanvasEditor.vue'
8
+ export { default as QiuCanvasRenderer } from './QiuCanvasRenderer.vue'
9
+ export { default as QiuCanvasDataModulesPanel } from './components/DataModulesPanel.vue'
10
+
11
+ export * from './types'
12
+ export * from './modules/dataRegistry'
13
+ export * from './modules/merge'
14
+ export * from './modules/badgeCompat'
15
+ export * from './presets/badge'
16
+ export * from './presets/banner'
17
+ export * from './export/png'
18
+ export * from './export/pdf'
19
+ export * from './export/html'
20
+ export { resolveAssetUrl } from './assetUrl'
@@ -0,0 +1,84 @@
1
+ /**
2
+ * 证件套打:扁平行 → 合并表(兼容旧 API)
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ import { mapFlatRowToContext } from './dataRegistry'
8
+ import type { MergeContext } from '../types'
9
+
10
+ function deriveSchoolShortName(schoolName: string): string {
11
+ let name = String(schoolName ?? '').trim()
12
+ if (!name) return ''
13
+ name = name.replace(/\s+/g, '')
14
+ name = name.replace(/^[中国中华人民共和國共和国]+/, '')
15
+ const adminPrefix =
16
+ /^(?:[^省特别行政区]+省|内蒙古自治区|广西壮族自治区|宁夏回族自治区|新疆维吾尔自治区|西藏自治区|北京市|天津市|上海市|重庆市|香港特别行政区|澳门特别行政区|台湾省|[^市]+市|[^区县旗]+区|[^区县旗]+县|[^区县旗]+旗|[^镇乡街道]+镇|[^镇乡街道]+乡|[^镇乡街道]+街道)/
17
+ let stripped = true
18
+ while (stripped && name) {
19
+ stripped = false
20
+ const next = name.replace(adminPrefix, '')
21
+ if (next !== name) {
22
+ name = next
23
+ stripped = true
24
+ }
25
+ }
26
+ return name || schoolName.trim()
27
+ }
28
+
29
+ /** 将接口返回的一条证件记录转为占位符合并表(扁平,兼容旧模板) */
30
+ export function flattenBadgeForMerge(
31
+ b: Record<string, unknown>,
32
+ competitionNameFallback?: string
33
+ ): Record<string, string> {
34
+ const cn =
35
+ (b.competition_name != null ? String(b.competition_name) : '') || (competitionNameFallback ?? '')
36
+ const schoolName = String(b.school_name ?? '')
37
+ const schoolShortName =
38
+ String(b.school_short_name ?? b.school_name_short ?? '').trim() || deriveSchoolShortName(schoolName)
39
+ return {
40
+ competition_name: cn,
41
+ student_name: String(b.student_name ?? ''),
42
+ competition_no: String(b.competition_no ?? ''),
43
+ school_name: schoolName,
44
+ school_short_name: schoolShortName,
45
+ age_group: String(b.age_group ?? ''),
46
+ competition_room: String(b.competition_room ?? ''),
47
+ seat_no: String(b.seat_no ?? ''),
48
+ floor: String(b.floor ?? ''),
49
+ teacher_name: String(b.teacher_name ?? ''),
50
+ date: String(b.date ?? b.competition_date ?? ''),
51
+ session: String(b.session ?? b.competition_session ?? ''),
52
+ enroll_teacher_name: String(b.enroll_teacher_name ?? ''),
53
+ teacher_phone: String(b.teacher_phone ?? ''),
54
+ signup_teacher_name: String(b.signup_teacher_name ?? ''),
55
+ signup_teacher_phone: String(b.signup_teacher_phone ?? ''),
56
+ signup_teacher_department: String(b.signup_teacher_department ?? ''),
57
+ signup_teacher_position: String(b.signup_teacher_position ?? ''),
58
+ signup_teacher_id_card: String(b.signup_teacher_id_card ?? ''),
59
+ signup_teacher_email: String(b.signup_teacher_email ?? ''),
60
+ signup_teacher_username: String(b.signup_teacher_username ?? ''),
61
+ venue_name: String(b.venue_name ?? ''),
62
+ venue_address: String(b.venue_address ?? ''),
63
+ competition_daily_start: String(b.competition_daily_start ?? ''),
64
+ competition_daily_end: String(b.competition_daily_end ?? ''),
65
+ }
66
+ }
67
+
68
+ export function flattenDeskLabelForMerge(
69
+ row: Record<string, unknown>,
70
+ competitionNameFallback?: string
71
+ ): Record<string, string> {
72
+ return flattenBadgeForMerge(row, competitionNameFallback)
73
+ }
74
+
75
+ /** 扁平行 → 嵌套 context(推荐套打入口) */
76
+ export function mapRowToContext(
77
+ row: Record<string, unknown>,
78
+ competitionNameFallback?: string
79
+ ): MergeContext {
80
+ const flat = flattenBadgeForMerge(row, competitionNameFallback)
81
+ return mapFlatRowToContext(flat, competitionNameFallback)
82
+ }
83
+
84
+ export { deriveSchoolShortName }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * 画布数据模块注册:内置模块 + 自定义合并
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ import type { DataModuleDef, MergeContext } from '../types'
8
+
9
+ /** 旧扁平 key → module.field(兼容期) */
10
+ export const LEGACY_FLAT_KEY_MAP: Record<string, string> = {
11
+ competition_name: 'competition.name',
12
+ student_name: 'student.name',
13
+ competition_no: 'student.competition_no',
14
+ school_name: 'school.name',
15
+ school_short_name: 'school.short_name',
16
+ age_group: 'student.age_group',
17
+ competition_room: 'classroom.name',
18
+ seat_no: 'classroom.seat_no',
19
+ floor: 'classroom.floor',
20
+ teacher_name: 'teacher.name',
21
+ date: 'competition.date',
22
+ session: 'competition.session',
23
+ enroll_teacher_name: 'teacher.enroll_name',
24
+ teacher_phone: 'teacher.phone',
25
+ signup_teacher_name: 'teacher.signup_name',
26
+ signup_teacher_phone: 'teacher.signup_phone',
27
+ signup_teacher_department: 'teacher.signup_department',
28
+ signup_teacher_position: 'teacher.signup_position',
29
+ signup_teacher_id_card: 'teacher.signup_id_card',
30
+ signup_teacher_email: 'teacher.signup_email',
31
+ signup_teacher_username: 'teacher.signup_username',
32
+ venue_name: 'classroom.venue_name',
33
+ venue_address: 'classroom.venue_address',
34
+ competition_daily_start: 'competition.daily_start',
35
+ competition_daily_end: 'competition.daily_end',
36
+ }
37
+
38
+ export const BUILTIN_DATA_MODULES: DataModuleDef[] = [
39
+ {
40
+ id: 'student',
41
+ label: '学生',
42
+ builtin: true,
43
+ enabled: true,
44
+ fields: [
45
+ { key: 'name', label: '姓名' },
46
+ { key: 'competition_no', label: '参赛编号' },
47
+ { key: 'age_group', label: '年龄段' },
48
+ ],
49
+ sample: { name: '张三', competition_no: 'A001', age_group: '中班' },
50
+ },
51
+ {
52
+ id: 'teacher',
53
+ label: '教师',
54
+ builtin: true,
55
+ enabled: true,
56
+ fields: [
57
+ { key: 'name', label: '监考教师' },
58
+ { key: 'phone', label: '手机' },
59
+ { key: 'enroll_name', label: '带队教师' },
60
+ { key: 'signup_name', label: '报名教师' },
61
+ { key: 'signup_phone', label: '报名教师手机' },
62
+ { key: 'signup_department', label: '报名教师部门' },
63
+ { key: 'signup_position', label: '报名教师职务' },
64
+ { key: 'signup_id_card', label: '报名教师身份证' },
65
+ { key: 'signup_email', label: '报名教师邮箱' },
66
+ { key: 'signup_username', label: '报名教师账号' },
67
+ ],
68
+ sample: { name: '李老师', phone: '13800000000', signup_name: '王老师' },
69
+ },
70
+ {
71
+ id: 'classroom',
72
+ label: '教室',
73
+ builtin: true,
74
+ enabled: true,
75
+ fields: [
76
+ { key: 'name', label: '考场/教室' },
77
+ { key: 'seat_no', label: '座位号' },
78
+ { key: 'floor', label: '楼层' },
79
+ { key: 'venue_name', label: '场地名称' },
80
+ { key: 'venue_address', label: '场地地址' },
81
+ ],
82
+ sample: { name: '301 教室', seat_no: '12', floor: '3F' },
83
+ },
84
+ {
85
+ id: 'school',
86
+ label: '学校',
87
+ builtin: true,
88
+ enabled: true,
89
+ fields: [
90
+ { key: 'name', label: '学校全称' },
91
+ { key: 'short_name', label: '学校简称' },
92
+ ],
93
+ sample: { name: '示范幼儿园', short_name: '示范园' },
94
+ },
95
+ {
96
+ id: 'competition',
97
+ label: '比赛',
98
+ builtin: true,
99
+ enabled: true,
100
+ fields: [
101
+ { key: 'name', label: '比赛名称' },
102
+ { key: 'date', label: '比赛日期' },
103
+ { key: 'session', label: '场次' },
104
+ { key: 'daily_start', label: '当天开始' },
105
+ { key: 'daily_end', label: '当天结束' },
106
+ ],
107
+ sample: { name: '示例比赛', date: '2026-08-16', session: '上午场' },
108
+ },
109
+ ]
110
+
111
+ export function cloneBuiltinModules(): DataModuleDef[] {
112
+ return BUILTIN_DATA_MODULES.map((m) => ({
113
+ ...m,
114
+ fields: m.fields.map((f) => ({ ...f })),
115
+ sample: m.sample ? { ...m.sample } : undefined,
116
+ }))
117
+ }
118
+
119
+ /** 合并内置 + 模板/业务传入模块 */
120
+ export function resolveDataModules(
121
+ override?: DataModuleDef[] | null,
122
+ docModules?: DataModuleDef[] | null
123
+ ): DataModuleDef[] {
124
+ const map = new Map<string, DataModuleDef>()
125
+ for (const m of cloneBuiltinModules()) map.set(m.id, m)
126
+ for (const m of override || []) {
127
+ const prev = map.get(m.id)
128
+ map.set(m.id, prev ? { ...prev, ...m, fields: m.fields?.length ? m.fields : prev.fields } : { ...m })
129
+ }
130
+ for (const m of docModules || []) {
131
+ const prev = map.get(m.id)
132
+ map.set(m.id, prev ? { ...prev, ...m, fields: m.fields?.length ? m.fields : prev.fields } : { ...m })
133
+ }
134
+ return [...map.values()].filter((m) => m.enabled !== false)
135
+ }
136
+
137
+ export function placeholderToken(moduleId: string, fieldKey: string) {
138
+ return `{{${moduleId}.${fieldKey}}}`
139
+ }
140
+
141
+ export function listInsertableFields(modules: DataModuleDef[]) {
142
+ const out: { moduleId: string; moduleLabel: string; key: string; label: string; token: string }[] = []
143
+ for (const m of modules) {
144
+ for (const f of m.fields) {
145
+ out.push({
146
+ moduleId: m.id,
147
+ moduleLabel: m.label,
148
+ key: f.key,
149
+ label: f.label,
150
+ token: placeholderToken(m.id, f.key),
151
+ })
152
+ }
153
+ }
154
+ return out
155
+ }
156
+
157
+ /** 用模块 sample 拼预览上下文 */
158
+ export function sampleContextFromModules(modules: DataModuleDef[]): MergeContext {
159
+ const ctx: MergeContext = {}
160
+ for (const m of modules) {
161
+ ctx[m.id] = { ...(m.sample || {}) }
162
+ }
163
+ return ctx
164
+ }
165
+
166
+ /**
167
+ * 旧扁平行 → 嵌套 context(套打时)
168
+ * 同时保留扁平 key,便于兼容旧模板。
169
+ */
170
+ export function mapFlatRowToContext(
171
+ row: Record<string, unknown>,
172
+ competitionNameFallback?: string
173
+ ): MergeContext {
174
+ const flat: Record<string, string> = {}
175
+ for (const [k, v] of Object.entries(row)) {
176
+ if (v == null) continue
177
+ flat[k] = String(v)
178
+ }
179
+ if (!flat.competition_name && competitionNameFallback) {
180
+ flat.competition_name = competitionNameFallback
181
+ }
182
+ const ctx: MergeContext = { ...flat }
183
+ for (const [flatKey, path] of Object.entries(LEGACY_FLAT_KEY_MAP)) {
184
+ const [mod, field] = path.split('.')
185
+ const val = flat[flatKey] ?? ''
186
+ if (!ctx[mod] || typeof ctx[mod] === 'string') ctx[mod] = {}
187
+ ;(ctx[mod] as Record<string, string>)[field] = val
188
+ }
189
+ return ctx
190
+ }
191
+
192
+ export function createCustomModule(label: string, fields?: DataModuleDef['fields']): DataModuleDef {
193
+ const id = `custom_${Date.now().toString(36)}`
194
+ return {
195
+ id,
196
+ label: label || '自定义模块',
197
+ builtin: false,
198
+ enabled: true,
199
+ fields: fields?.length
200
+ ? fields
201
+ : [
202
+ { key: 'name', label: '名称' },
203
+ { key: 'value', label: '值' },
204
+ ],
205
+ sample: { name: '示例', value: '123' },
206
+ }
207
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * 模板占位符合并:支持 {{module.field}} 与旧扁平 {{student_name}}
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ import type { MergeContext } from '../types'
8
+ import { LEGACY_FLAT_KEY_MAP } from './dataRegistry'
9
+
10
+ function lookupPath(ctx: MergeContext, path: string): string {
11
+ const parts = path.split('.').filter(Boolean)
12
+ if (parts.length === 1) {
13
+ const v = ctx[parts[0]]
14
+ if (v == null) return ''
15
+ if (typeof v === 'string') return v
16
+ return ''
17
+ }
18
+ if (parts.length >= 2) {
19
+ const mod = ctx[parts[0]]
20
+ if (mod && typeof mod === 'object') {
21
+ const v = (mod as Record<string, string>)[parts[1]]
22
+ return v != null && v !== '' ? String(v) : ''
23
+ }
24
+ }
25
+ return ''
26
+ }
27
+
28
+ function resolveToken(ctx: MergeContext, raw: string): string {
29
+ const key = String(raw || '').trim()
30
+ if (!key) return ''
31
+
32
+ // 新式:module.field
33
+ if (key.includes('.')) {
34
+ const nested = lookupPath(ctx, key)
35
+ if (nested) return nested
36
+ }
37
+
38
+ // 扁平:student_name
39
+ const flat = ctx[key]
40
+ if (typeof flat === 'string' && flat !== '') return flat
41
+
42
+ // 旧扁平 → 新路径
43
+ const mapped = LEGACY_FLAT_KEY_MAP[key]
44
+ if (mapped) {
45
+ const via = lookupPath(ctx, mapped)
46
+ if (via) return via
47
+ }
48
+
49
+ return ''
50
+ }
51
+
52
+ /**
53
+ * 合并模板文本。
54
+ * context 可为嵌套模块对象,也可混入扁平 string 字段。
55
+ */
56
+ export function mergeTemplateText(text: string, context: MergeContext | Record<string, string>): string {
57
+ if (!text) return ''
58
+ const ctx = context as MergeContext
59
+ return text.replace(/\{\{\s*([a-zA-Z0-9_.]+)\s*\}\}/g, (_, k: string) => resolveToken(ctx, k))
60
+ }
61
+
62
+ /** @deprecated 使用 mergeTemplateText;保留旧名兼容 */
63
+ export function mergeBadgeText(text: string, data: Record<string, string>) {
64
+ return mergeTemplateText(text, data)
65
+ }
66
+
67
+ export function sortCanvasElements<T extends { zIndex?: number }>(els: T[]): T[] {
68
+ return [...els].sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0))
69
+ }
70
+
71
+ export { sortCanvasElements as sortBadgeElements }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * 证件场景默认占位符列表(旧扁平 key,兼容)
3
+ * @author qiuye
4
+ * @email yjk150@qq.com
5
+ * @date 2026-08-16
6
+ */
7
+ export const BADGE_PLACEHOLDER_KEYS = [
8
+ 'competition_name',
9
+ 'student_name',
10
+ 'competition_no',
11
+ 'school_name',
12
+ 'school_short_name',
13
+ 'age_group',
14
+ 'competition_room',
15
+ 'seat_no',
16
+ 'floor',
17
+ 'teacher_name',
18
+ 'date',
19
+ 'session',
20
+ 'enroll_teacher_name',
21
+ 'teacher_phone',
22
+ 'signup_teacher_name',
23
+ 'signup_teacher_phone',
24
+ 'signup_teacher_department',
25
+ 'signup_teacher_position',
26
+ 'signup_teacher_id_card',
27
+ 'signup_teacher_email',
28
+ 'signup_teacher_username',
29
+ 'venue_name',
30
+ 'venue_address',
31
+ 'competition_daily_start',
32
+ 'competition_daily_end',
33
+ ] as const
34
+
35
+ export type BadgePlaceholderKey = (typeof BADGE_PLACEHOLDER_KEYS)[number]
36
+
37
+ export const BADGE_PLACEHOLDER_LABELS: Record<string, string> = {
38
+ competition_name: '比赛名称',
39
+ student_name: '学生姓名',
40
+ competition_no: '参赛编号',
41
+ school_name: '学校',
42
+ school_short_name: '学校简称',
43
+ age_group: '年龄段',
44
+ competition_room: '考场/教室',
45
+ seat_no: '座位号',
46
+ floor: '楼层',
47
+ teacher_name: '监考教师',
48
+ date: '比赛日期',
49
+ session: '场次',
50
+ enroll_teacher_name: '报名/带队教师(扩展)',
51
+ teacher_phone: '教师手机(扩展)',
52
+ signup_teacher_name: '报名教师姓名',
53
+ signup_teacher_phone: '报名教师手机',
54
+ signup_teacher_department: '报名教师部门',
55
+ signup_teacher_position: '报名教师职务',
56
+ signup_teacher_id_card: '报名教师身份证',
57
+ signup_teacher_email: '报名教师邮箱',
58
+ signup_teacher_username: '报名教师账号',
59
+ venue_name: '场地名称',
60
+ venue_address: '场地地址',
61
+ competition_daily_start: '比赛当天开始时间',
62
+ competition_daily_end: '比赛当天结束时间',
63
+ }
64
+
65
+ export const DESK_LABEL_PLACEHOLDER_KEYS = BADGE_PLACEHOLDER_KEYS
66
+ export type DeskLabelPlaceholderKey = BadgePlaceholderKey
67
+ export const DESK_LABEL_PLACEHOLDER_LABELS: Record<string, string> = BADGE_PLACEHOLDER_LABELS