foucui 1.0.1 → 1.0.2

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 (234) hide show
  1. package/dist/components/QiuCanvasKit/QiuCanvasEditor.vue.d.ts +3 -1
  2. package/dist/components/QiuCanvasKit/components/DataModulesPanel.vue.d.ts +1 -0
  3. package/dist/components/QiuTable/index.vue.d.ts +12 -12
  4. package/dist/foucui.css +1 -1
  5. package/dist/foucui.js +7476 -7373
  6. package/dist/foucui.umd.cjs +19 -19
  7. package/package.json +23 -13
  8. package/components/QiuAffix/index.vue +0 -186
  9. package/components/QiuAlert/index.vue +0 -208
  10. package/components/QiuAnchor/context.ts +0 -18
  11. package/components/QiuAnchor/index.vue +0 -180
  12. package/components/QiuAnchorLink/index.vue +0 -67
  13. package/components/QiuApp/index.vue +0 -9
  14. package/components/QiuAutocomplete/index.vue +0 -408
  15. package/components/QiuAvatar/index.vue +0 -140
  16. package/components/QiuBacktop/index.vue +0 -121
  17. package/components/QiuBadge/api/index.ts +0 -389
  18. package/components/QiuBadge/components/BadgeImagePickerDialog.vue +0 -243
  19. package/components/QiuBadge/components/BadgeLibraryManagerDialog.vue +0 -30
  20. package/components/QiuBadge/components/BadgeLibraryPanel.vue +0 -182
  21. package/components/QiuBadge/composables/useTableHostHeight.ts +0 -53
  22. package/components/QiuBadge/index.ts +0 -18
  23. package/components/QiuBadge/shared/BadgeTemplateRenderer.vue +0 -32
  24. package/components/QiuBadge/shared/assetUrl.ts +0 -26
  25. package/components/QiuBadge/shared/badgeTemplate.ts +0 -309
  26. package/components/QiuBadge/utils/chinaAreaData.ts +0 -44
  27. package/components/QiuBadge/utils/hostRegion.ts +0 -22
  28. package/components/QiuBadge/utils/pca-code.json +0 -1
  29. package/components/QiuBadge/utils/pdfFromElement.ts +0 -348
  30. package/components/QiuBadge/views/BadgeLibraryView.vue +0 -32
  31. package/components/QiuBadge/views/BadgeManageView.vue +0 -1364
  32. package/components/QiuBadge/views/BadgeTemplateEditorView.vue +0 -10
  33. package/components/QiuBadge/views/BadgeTemplateListView.vue +0 -229
  34. package/components/QiuBadge/views/DeskLabelTemplateListView.vue +0 -227
  35. package/components/QiuBadge/views/DeskLabelView.vue +0 -683
  36. package/components/QiuBadgeDot/index.vue +0 -87
  37. package/components/QiuButton/index.vue +0 -247
  38. package/components/QiuButtonGroup/index.vue +0 -63
  39. package/components/QiuCanvasKit/QiuCanvasEditor.vue +0 -5503
  40. package/components/QiuCanvasKit/QiuCanvasRenderer.vue +0 -348
  41. package/components/QiuCanvasKit/assetUrl.ts +0 -11
  42. package/components/QiuCanvasKit/components/DataModulesPanel.vue +0 -352
  43. package/components/QiuCanvasKit/export/html.ts +0 -132
  44. package/components/QiuCanvasKit/export/pdf.ts +0 -48
  45. package/components/QiuCanvasKit/export/png.ts +0 -50
  46. package/components/QiuCanvasKit/index.ts +0 -20
  47. package/components/QiuCanvasKit/modules/badgeCompat.ts +0 -84
  48. package/components/QiuCanvasKit/modules/dataRegistry.ts +0 -207
  49. package/components/QiuCanvasKit/modules/merge.ts +0 -71
  50. package/components/QiuCanvasKit/presets/badge.ts +0 -67
  51. package/components/QiuCanvasKit/presets/banner.ts +0 -79
  52. package/components/QiuCanvasKit/types.ts +0 -138
  53. package/components/QiuCard/index.vue +0 -104
  54. package/components/QiuCarousel/context.ts +0 -16
  55. package/components/QiuCarousel/index.vue +0 -343
  56. package/components/QiuCarouselItem/index.vue +0 -47
  57. package/components/QiuCascader/index.vue +0 -879
  58. package/components/QiuCascader/types.ts +0 -48
  59. package/components/QiuCheckbox/QiuCheckboxGroup.vue +0 -78
  60. package/components/QiuCheckbox/index.vue +0 -231
  61. package/components/QiuCheckbox/types.ts +0 -8
  62. package/components/QiuCode/index.vue +0 -64
  63. package/components/QiuCol/col.scss +0 -55
  64. package/components/QiuCol/index.vue +0 -64
  65. package/components/QiuCollapse/context.ts +0 -10
  66. package/components/QiuCollapse/index.vue +0 -70
  67. package/components/QiuCollapseItem/index.vue +0 -167
  68. package/components/QiuColorField/index.vue +0 -296
  69. package/components/QiuColorPicker/README.md +0 -118
  70. package/components/QiuColorPicker/index.vue +0 -60
  71. package/components/QiuColorfulCard/index.vue +0 -101
  72. package/components/QiuCombobox/index.vue +0 -277
  73. package/components/QiuConfigProvider/index.vue +0 -31
  74. package/components/QiuContextMenu/index.vue +0 -209
  75. package/components/QiuDate/index.vue +0 -1134
  76. package/components/QiuDescriptions/context.ts +0 -20
  77. package/components/QiuDescriptions/index.vue +0 -115
  78. package/components/QiuDescriptionsItem/index.vue +0 -103
  79. package/components/QiuDialog/index.vue +0 -828
  80. package/components/QiuDigitalCard/index.vue +0 -159
  81. package/components/QiuDivider/index.vue +0 -185
  82. package/components/QiuDot/index.vue +0 -83
  83. package/components/QiuDrawer/index.vue +0 -350
  84. package/components/QiuDropdown/QiuDropdownItem.vue +0 -74
  85. package/components/QiuDropdown/QiuDropdownMenu.vue +0 -22
  86. package/components/QiuDropdown/context.ts +0 -9
  87. package/components/QiuDropdown/index.vue +0 -189
  88. package/components/QiuEmpty/index.vue +0 -73
  89. package/components/QiuForm/index.vue +0 -172
  90. package/components/QiuForm/types.ts +0 -39
  91. package/components/QiuFormItem/index.vue +0 -276
  92. package/components/QiuFullscreen/index.vue +0 -11
  93. package/components/QiuGrid/index.vue +0 -408
  94. package/components/QiuHoverCard/index.vue +0 -192
  95. package/components/QiuIcon/index.vue +0 -117
  96. package/components/QiuIconPicker/iconify.libraries.ts +0 -182
  97. package/components/QiuIconPicker/icons.catalog.ts +0 -3072
  98. package/components/QiuIconPicker/index.vue +0 -488
  99. package/components/QiuImage/index.vue +0 -177
  100. package/components/QiuInput/index.vue +0 -328
  101. package/components/QiuInputNumber/index.vue +0 -295
  102. package/components/QiuInputOtp/index.vue +0 -190
  103. package/components/QiuKbd/index.vue +0 -57
  104. package/components/QiuLayoutContainer/index.vue +0 -50
  105. package/components/QiuLinkPreview/index.vue +0 -224
  106. package/components/QiuLoading/index.ts +0 -176
  107. package/components/QiuLoading/spinner.vue +0 -820
  108. package/components/QiuLoading/types.ts +0 -44
  109. package/components/QiuMention/index.vue +0 -299
  110. package/components/QiuMenu/QiuMenuRoot.vue +0 -241
  111. package/components/QiuMenu/components/QiuMenuItem.vue +0 -340
  112. package/components/QiuMenu/components/QiuSubMenu.vue +0 -504
  113. package/components/QiuMenu/context.ts +0 -21
  114. package/components/QiuMenu/index.vue +0 -43
  115. package/components/QiuMenuNav/QiuMenuNavItem.vue +0 -100
  116. package/components/QiuMenuNav/QiuMenuNavSub.vue +0 -120
  117. package/components/QiuMenuNav/context.ts +0 -14
  118. package/components/QiuMenuNav/index.vue +0 -148
  119. package/components/QiuMsg/QiuMsgItem.vue +0 -180
  120. package/components/QiuMsg/index.ts +0 -158
  121. package/components/QiuMsg/types.ts +0 -23
  122. package/components/QiuMsgBox/index.ts +0 -147
  123. package/components/QiuNotification/QiuNotificationItem.vue +0 -168
  124. package/components/QiuNotification/index.ts +0 -155
  125. package/components/QiuNotification/types.ts +0 -14
  126. package/components/QiuPage/index.vue +0 -12
  127. package/components/QiuPageHeader/index.vue +0 -115
  128. package/components/QiuPageMain/index.vue +0 -78
  129. package/components/QiuPagination/index.vue +0 -421
  130. package/components/QiuPasswordStrength/index.vue +0 -101
  131. package/components/QiuPopconfirm/index.vue +0 -196
  132. package/components/QiuPopover/index.vue +0 -277
  133. package/components/QiuProgress/index.vue +0 -235
  134. package/components/QiuQrcode/index.vue +0 -302
  135. package/components/QiuQueryForm/components/QiuQueryFormBottomPanel.vue +0 -13
  136. package/components/QiuQueryForm/components/QiuQueryFormLeftPanel.vue +0 -37
  137. package/components/QiuQueryForm/components/QiuQueryFormRightPanel.vue +0 -37
  138. package/components/QiuQueryForm/components/QiuQueryFormTopPanel.vue +0 -13
  139. package/components/QiuQueryForm/index.vue +0 -117
  140. package/components/QiuRadio/QiuRadioGroup.vue +0 -75
  141. package/components/QiuRadio/index.vue +0 -191
  142. package/components/QiuRadio/types.ts +0 -9
  143. package/components/QiuRate/index.vue +0 -184
  144. package/components/QiuRefresh/index.vue +0 -32
  145. package/components/QiuResult/index.vue +0 -103
  146. package/components/QiuRow/index.vue +0 -60
  147. package/components/QiuRow/types.ts +0 -5
  148. package/components/QiuScrollbar/index.vue +0 -107
  149. package/components/QiuSearchBar/index.vue +0 -154
  150. package/components/QiuSegmented/index.vue +0 -120
  151. package/components/QiuSelect/QiuOption.vue +0 -93
  152. package/components/QiuSelect/index.vue +0 -452
  153. package/components/QiuSelect/types.ts +0 -15
  154. package/components/QiuSkeleton/index.vue +0 -78
  155. package/components/QiuSlider/index.vue +0 -266
  156. package/components/QiuSpace/index.vue +0 -95
  157. package/components/QiuSparkline/index.vue +0 -92
  158. package/components/QiuStatistic/index.vue +0 -4
  159. package/components/QiuStatistics/index.vue +0 -123
  160. package/components/QiuStep/index.vue +0 -220
  161. package/components/QiuSteps/context.ts +0 -25
  162. package/components/QiuSteps/index.vue +0 -84
  163. package/components/QiuSwitch/index.vue +0 -145
  164. package/components/QiuTabBar/index.vue +0 -218
  165. package/components/QiuTabBar/types.ts +0 -19
  166. package/components/QiuTabPane/index.vue +0 -82
  167. package/components/QiuTable/columns.ts +0 -16
  168. package/components/QiuTable/export.ts +0 -102
  169. package/components/QiuTable/index.ts +0 -24
  170. package/components/QiuTable/index.vue +0 -3503
  171. package/components/QiuTable/registry.ts +0 -75
  172. package/components/QiuTable/styles/table.scss +0 -1230
  173. package/components/QiuTable/types.ts +0 -413
  174. package/components/QiuTable/useArea.ts +0 -202
  175. package/components/QiuTable/useColumns.ts +0 -325
  176. package/components/QiuTable/useEdit.ts +0 -136
  177. package/components/QiuTable/useExtras.ts +0 -115
  178. package/components/QiuTable/useHistory.ts +0 -77
  179. package/components/QiuTable/useMerge.ts +0 -105
  180. package/components/QiuTable/useResize.ts +0 -86
  181. package/components/QiuTable/useScrollSync.ts +0 -152
  182. package/components/QiuTable/useVirtual.ts +0 -97
  183. package/components/QiuTable/utils.ts +0 -165
  184. package/components/QiuTableColumn/index.vue +0 -101
  185. package/components/QiuTag/index.vue +0 -143
  186. package/components/QiuText/index.vue +0 -99
  187. package/components/QiuTime/index.vue +0 -548
  188. package/components/QiuTimeAgo/index.vue +0 -103
  189. package/components/QiuTimeline/index.vue +0 -54
  190. package/components/QiuTimelineItem/index.vue +0 -140
  191. package/components/QiuTips/index.vue +0 -323
  192. package/components/QiuTooltip/index.vue +0 -237
  193. package/components/QiuTransfer/index.vue +0 -277
  194. package/components/QiuTree/QiuTreeNode.vue +0 -146
  195. package/components/QiuTree/index.vue +0 -143
  196. package/components/QiuTree/types.ts +0 -30
  197. package/components/QiuTreeSelect/index.vue +0 -259
  198. package/components/QiuTrend/index.vue +0 -92
  199. package/components/QiuUpload/index.vue +0 -628
  200. package/components/QiuUploadCrop/index.vue +0 -1267
  201. package/components/QiuWatermark/index.vue +0 -121
  202. package/components/useBodyScrollLock.ts +0 -28
  203. package/dist/components/QiuBadge/utils/pca-code.json.d.ts +0 -3
  204. package/plugins/qiu.ts +0 -83
  205. package/plugins/shortcuts.ts +0 -69
  206. package/src/bridge/@/api/media.ts +0 -8
  207. package/src/bridge/@/api/notice.ts +0 -5
  208. package/src/bridge/@/config/index.ts +0 -38
  209. package/src/bridge/@/config/media.config.ts +0 -37
  210. package/src/bridge/@/config/security.config.ts +0 -8
  211. package/src/bridge/@/i18n/index.ts +0 -6
  212. package/src/bridge/@/store/modules/bing.ts +0 -9
  213. package/src/bridge/@/store/modules/errorLog.ts +0 -9
  214. package/src/bridge/@/store/modules/media.ts +0 -10
  215. package/src/bridge/@/store/modules/routes.ts +0 -10
  216. package/src/bridge/@/store/modules/settings.ts +0 -9
  217. package/src/bridge/@/store/modules/tabs.ts +0 -9
  218. package/src/bridge/@/store/modules/user.ts +0 -9
  219. package/src/bridge/@/utils/convertToCamelCase.ts +0 -11
  220. package/src/bridge/@/utils/index.ts +0 -9
  221. package/src/bridge/@/utils/pageTitle.ts +0 -4
  222. package/src/bridge/@/utils/routes.ts +0 -14
  223. package/src/bridge/@/utils/validate.ts +0 -17
  224. package/src/bridge/@qiu/plugins/shortcuts.ts +0 -3
  225. package/src/i18n.ts +0 -8
  226. package/src/icons/qiu-logo.svg +0 -1
  227. package/styles/dark.scss +0 -194
  228. package/styles/normalize.css +0 -349
  229. package/styles/plain.scss +0 -423
  230. package/styles/qiu-tokens.scss +0 -40
  231. package/styles/qiu.scss +0 -1149
  232. package/styles/technology.scss +0 -452
  233. package/styles/var.scss +0 -382
  234. package/styles/variables.scss +0 -77
@@ -1,121 +0,0 @@
1
- <template>
2
- <Teleport to="body">
3
- <Transition name="qiu-backtop-fade">
4
- <button
5
- v-show="visible"
6
- type="button"
7
- class="qiu-backtop"
8
- :style="btnStyle"
9
- aria-label="回到顶部"
10
- @click="scrollToTop"
11
- >
12
- <slot>
13
- <qiu-icon icon="arrow-up-line" />
14
- </slot>
15
- </button>
16
- </Transition>
17
- </Teleport>
18
- </template>
19
-
20
- <script lang="ts" setup>
21
- defineOptions({ name: 'QiuBacktop' })
22
-
23
- const props = withDefaults(
24
- defineProps<{
25
- /** 滚动超过该高度后显示 */
26
- scrollVisibilityHeight?: number
27
- right?: number
28
- bottom?: number
29
- zIndex?: number
30
- /** 滚动容器选择器,默认 window */
31
- target?: string
32
- }>(),
33
- {
34
- scrollVisibilityHeight: 200,
35
- right: 40,
36
- bottom: 40,
37
- zIndex: 100,
38
- target: '',
39
- }
40
- )
41
-
42
- const visible = ref(false)
43
-
44
- const getScrollContainer = (): HTMLElement | Window => {
45
- if (!props.target) return window
46
- const el = document.querySelector(props.target)
47
- return (el as HTMLElement) || window
48
- }
49
-
50
- const getScrollTop = (container: HTMLElement | Window) => {
51
- if (container === window) return window.scrollY || document.documentElement.scrollTop
52
- return (container as HTMLElement).scrollTop
53
- }
54
-
55
- const btnStyle = computed(() => ({
56
- right: `${props.right}px`,
57
- bottom: `${props.bottom}px`,
58
- zIndex: String(props.zIndex),
59
- }))
60
-
61
- const onScroll = () => {
62
- const container = getScrollContainer()
63
- visible.value = getScrollTop(container) >= props.scrollVisibilityHeight
64
- }
65
-
66
- const scrollToTop = () => {
67
- const container = getScrollContainer()
68
- if (container === window) {
69
- window.scrollTo({ top: 0, behavior: 'smooth' })
70
- } else {
71
- ;(container as HTMLElement).scrollTo({ top: 0, behavior: 'smooth' })
72
- }
73
- }
74
-
75
- let containerEl: HTMLElement | Window = window
76
-
77
- onMounted(() => {
78
- containerEl = getScrollContainer()
79
- containerEl.addEventListener('scroll', onScroll, { passive: true })
80
- onScroll()
81
- })
82
-
83
- onBeforeUnmount(() => {
84
- containerEl.removeEventListener('scroll', onScroll)
85
- })
86
- </script>
87
-
88
- <style lang="scss" scoped>
89
- .qiu-backtop {
90
- position: fixed;
91
- display: inline-flex;
92
- align-items: center;
93
- justify-content: center;
94
- width: 40px;
95
- height: 40px;
96
- font-size: 18px;
97
- color: var(--qiu-color-primary, var(--qiu-color-primary, #0f766e));
98
- cursor: pointer;
99
- background: var(--qiu-bg-color, var(--qiu-bg-color, #fff));
100
- border: 1px solid var(--qiu-border-color-lighter, var(--qiu-border-color-lighter, #ebeef5));
101
- border-radius: 50%;
102
- box-shadow: var(--qiu-box-shadow-light, 0 2px 12px rgba(0, 0, 0, 0.1));
103
- transition: background 0.15s, color 0.15s;
104
-
105
- &:hover {
106
- color: #fff;
107
- background: var(--qiu-color-primary, var(--qiu-color-primary, #0f766e));
108
- }
109
- }
110
-
111
- .qiu-backtop-fade-enter-active,
112
- .qiu-backtop-fade-leave-active {
113
- transition: opacity 0.2s ease, transform 0.2s ease;
114
- }
115
-
116
- .qiu-backtop-fade-enter-from,
117
- .qiu-backtop-fade-leave-to {
118
- opacity: 0;
119
- transform: translateY(8px);
120
- }
121
- </style>
@@ -1,389 +0,0 @@
1
- /**
2
- * QiuBadge 本地演示 API(localStorage)
3
- * 先保证编辑器可独立跑通;后续再对接真实后端。
4
- */
5
- import type { BadgeTemplateDoc } from '../shared/badgeTemplate'
6
-
7
- const LS_TEMPLATES = 'qiu-badge-templates'
8
- const LS_DESK = 'qiu-badge-desk-templates'
9
- const LS_LIBRARY = 'qiu-badge-library'
10
- const LS_COMPETITIONS = 'qiu-badge-competitions'
11
-
12
- type ApiOk<T> = { code: number; data: T; msg?: string }
13
-
14
- const ok = <T>(data: T): ApiOk<T> => ({ code: 0, data })
15
-
16
- const readJson = <T>(key: string, fallback: T): T => {
17
- try {
18
- const raw = localStorage.getItem(key)
19
- if (!raw) return fallback
20
- return JSON.parse(raw) as T
21
- } catch {
22
- return fallback
23
- }
24
- }
25
-
26
- const writeJson = (key: string, value: unknown) => {
27
- localStorage.setItem(key, JSON.stringify(value))
28
- }
29
-
30
- export interface BadgeTemplateRow {
31
- id: number
32
- competition_id: number
33
- name: string
34
- width_mm: number
35
- height_mm: number
36
- is_default: boolean
37
- update_time: string
38
- doc?: BadgeTemplateDoc | null
39
- default_test_json?: Record<string, unknown> | null
40
- kind?: 'badge' | 'desk'
41
- }
42
-
43
- export interface BadgeLibraryImage {
44
- id: number
45
- url: string
46
- name: string
47
- create_time: string
48
- }
49
-
50
- const nowText = () => {
51
- const d = new Date()
52
- const p = (n: number) => String(n).padStart(2, '0')
53
- return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
54
- }
55
-
56
- const ensureDemoCompetitions = () => {
57
- let list = readJson<any[]>(LS_COMPETITIONS, [])
58
- if (!list.length) {
59
- list = [
60
- {
61
- id: 1,
62
- name: '演示比赛 A',
63
- area_code: 'A01',
64
- host_region: '110000',
65
- start_date: '2026-08-01',
66
- status: 1,
67
- },
68
- {
69
- id: 2,
70
- name: '演示比赛 B',
71
- area_code: 'B02',
72
- host_region: '310000',
73
- start_date: '2026-09-01',
74
- status: 2,
75
- },
76
- ]
77
- writeJson(LS_COMPETITIONS, list)
78
- }
79
- return list
80
- }
81
-
82
- const listStore = (kind: 'badge' | 'desk') =>
83
- readJson<BadgeTemplateRow[]>(kind === 'badge' ? LS_TEMPLATES : LS_DESK, [])
84
-
85
- const saveStore = (kind: 'badge' | 'desk', rows: BadgeTemplateRow[]) =>
86
- writeJson(kind === 'badge' ? LS_TEMPLATES : LS_DESK, rows)
87
-
88
- const nextId = (rows: BadgeTemplateRow[]) =>
89
- rows.reduce((m, r) => Math.max(m, Number(r.id) || 0), 0) + 1
90
-
91
- const emptyDoc = (name: string, w = 90, h = 54): BadgeTemplateDoc =>
92
- ({
93
- version: 1,
94
- canvas: {
95
- widthMm: w,
96
- heightMm: h,
97
- background: '#ffffff',
98
- },
99
- elements: [],
100
- guides: [],
101
- regions: [],
102
- }) as BadgeTemplateDoc
103
-
104
- /** —— competition / template —— */
105
- export const getCompetitions = async (params?: any) => {
106
- const list = ensureDemoCompetitions()
107
- const page = Number(params?.page || 1)
108
- const pageSize = Number(params?.page_size || params?.pageSize || 20)
109
- const kw = String(params?.keyword || params?.q || '').trim()
110
- let rows = list
111
- if (kw) rows = rows.filter((r) => `${r.name}${r.area_code}`.includes(kw))
112
- const start = (page - 1) * pageSize
113
- return ok({
114
- list: rows.slice(start, start + pageSize),
115
- total: rows.length,
116
- page,
117
- page_size: pageSize,
118
- })
119
- }
120
-
121
- export const getCompetition = async (id: number) => {
122
- const row = ensureDemoCompetitions().find((r) => r.id === Number(id))
123
- return ok(row || { id, name: `比赛 ${id}`, status: 1 })
124
- }
125
-
126
- export const listBadgeTemplates = async (competitionId: number) => {
127
- const rows = listStore('badge').filter((r) => r.competition_id === Number(competitionId))
128
- return ok({ list: rows })
129
- }
130
-
131
- export const createBadgeTemplate = async (competitionId: number, data: { name: string }) => {
132
- const rows = listStore('badge')
133
- const id = nextId(rows)
134
- const row: BadgeTemplateRow = {
135
- id,
136
- competition_id: Number(competitionId),
137
- name: data.name || '未命名模板',
138
- width_mm: 90,
139
- height_mm: 54,
140
- is_default: rows.filter((r) => r.competition_id === Number(competitionId)).length === 0,
141
- update_time: nowText(),
142
- doc: emptyDoc(data.name || '未命名模板'),
143
- kind: 'badge',
144
- }
145
- rows.push(row)
146
- saveStore('badge', rows)
147
- return ok(row)
148
- }
149
-
150
- export const getBadgeTemplateOne = async (competitionId: number, templateId: number) => {
151
- const row = listStore('badge').find(
152
- (r) => r.id === Number(templateId) && r.competition_id === Number(competitionId)
153
- )
154
- if (!row) return ok(null)
155
- return ok({
156
- ...row,
157
- template_json: row.doc || emptyDoc(row.name, row.width_mm, row.height_mm),
158
- doc: row.doc || emptyDoc(row.name, row.width_mm, row.height_mm),
159
- default_test_json: row.default_test_json || {},
160
- })
161
- }
162
-
163
- export const getBadgeTemplate = async (competitionId: number) => {
164
- const rows = listStore('badge').filter((r) => r.competition_id === Number(competitionId))
165
- const row = rows.find((r) => r.is_default) || rows[0]
166
- if (!row) return ok(null)
167
- return getBadgeTemplateOne(competitionId, row.id)
168
- }
169
-
170
- export const putBadgeTemplateOne = async (
171
- competitionId: number,
172
- templateId: number,
173
- data: Record<string, unknown>
174
- ) => {
175
- const rows = listStore('badge')
176
- const idx = rows.findIndex(
177
- (r) => r.id === Number(templateId) && r.competition_id === Number(competitionId)
178
- )
179
- if (idx < 0) return ok(null)
180
- const doc = (data.doc || data.template_json || data.template || rows[idx].doc) as BadgeTemplateDoc
181
- const name = String(data.name || rows[idx].name)
182
- const width = Number((doc as any)?.canvas?.widthMm || data.width_mm || rows[idx].width_mm)
183
- const height = Number((doc as any)?.canvas?.heightMm || data.height_mm || rows[idx].height_mm)
184
- rows[idx] = {
185
- ...rows[idx],
186
- name,
187
- width_mm: width,
188
- height_mm: height,
189
- doc,
190
- default_test_json: (data.default_test_json as Record<string, unknown>) ?? rows[idx].default_test_json ?? {},
191
- update_time: nowText(),
192
- }
193
- saveStore('badge', rows)
194
- return ok(rows[idx])
195
- }
196
-
197
- export const deleteBadgeTemplate = async (competitionId: number, templateId: number) => {
198
- const rows = listStore('badge').filter(
199
- (r) => !(r.id === Number(templateId) && r.competition_id === Number(competitionId))
200
- )
201
- saveStore('badge', rows)
202
- return ok(true)
203
- }
204
-
205
- export const setDefaultBadgeTemplate = async (competitionId: number, templateId: number) => {
206
- const rows = listStore('badge').map((r) =>
207
- r.competition_id === Number(competitionId)
208
- ? { ...r, is_default: r.id === Number(templateId) }
209
- : r
210
- )
211
- saveStore('badge', rows)
212
- return ok(true)
213
- }
214
-
215
- /** desk label templates */
216
- export const listDeskLabelTemplates = async (competitionId: number) => {
217
- const rows = listStore('desk').filter((r) => r.competition_id === Number(competitionId))
218
- return ok({ list: rows })
219
- }
220
-
221
- export const createDeskLabelTemplate = async (competitionId: number, data: { name: string }) => {
222
- const rows = listStore('desk')
223
- const id = nextId(rows)
224
- const row: BadgeTemplateRow = {
225
- id,
226
- competition_id: Number(competitionId),
227
- name: data.name || '未命名桌签',
228
- width_mm: 150,
229
- height_mm: 50,
230
- is_default: rows.filter((r) => r.competition_id === Number(competitionId)).length === 0,
231
- update_time: nowText(),
232
- doc: emptyDoc(data.name || '未命名桌签', 150, 50),
233
- kind: 'desk',
234
- }
235
- rows.push(row)
236
- saveStore('desk', rows)
237
- return ok(row)
238
- }
239
-
240
- export const getDeskLabelTemplateOne = async (competitionId: number, templateId: number) => {
241
- const row = listStore('desk').find(
242
- (r) => r.id === Number(templateId) && r.competition_id === Number(competitionId)
243
- )
244
- if (!row) return ok(null)
245
- return ok({
246
- ...row,
247
- template_json: row.doc || emptyDoc(row.name, row.width_mm, row.height_mm),
248
- doc: row.doc || emptyDoc(row.name, row.width_mm, row.height_mm),
249
- default_test_json: row.default_test_json || {},
250
- })
251
- }
252
-
253
- export const getDeskLabelTemplate = async (competitionId: number) => {
254
- const rows = listStore('desk').filter((r) => r.competition_id === Number(competitionId))
255
- const row = rows.find((r) => r.is_default) || rows[0]
256
- if (!row) return ok(null)
257
- return getDeskLabelTemplateOne(competitionId, row.id)
258
- }
259
-
260
- export const putDeskLabelTemplateOne = async (
261
- competitionId: number,
262
- templateId: number,
263
- data: Record<string, unknown>
264
- ) => {
265
- const rows = listStore('desk')
266
- const idx = rows.findIndex(
267
- (r) => r.id === Number(templateId) && r.competition_id === Number(competitionId)
268
- )
269
- if (idx < 0) return ok(null)
270
- const doc = (data.doc || data.template_json || data.template || rows[idx].doc) as BadgeTemplateDoc
271
- const name = String(data.name || rows[idx].name)
272
- const width = Number((doc as any)?.canvas?.widthMm || data.width_mm || rows[idx].width_mm)
273
- const height = Number((doc as any)?.canvas?.heightMm || data.height_mm || rows[idx].height_mm)
274
- rows[idx] = {
275
- ...rows[idx],
276
- name,
277
- width_mm: width,
278
- height_mm: height,
279
- doc,
280
- default_test_json: (data.default_test_json as Record<string, unknown>) ?? rows[idx].default_test_json ?? {},
281
- update_time: nowText(),
282
- }
283
- saveStore('desk', rows)
284
- return ok(rows[idx])
285
- }
286
-
287
- export const deleteDeskLabelTemplate = async (competitionId: number, templateId: number) => {
288
- const rows = listStore('desk').filter(
289
- (r) => !(r.id === Number(templateId) && r.competition_id === Number(competitionId))
290
- )
291
- saveStore('desk', rows)
292
- return ok(true)
293
- }
294
-
295
- export const setDefaultDeskLabelTemplate = async (competitionId: number, templateId: number) => {
296
- const rows = listStore('desk').map((r) =>
297
- r.competition_id === Number(competitionId)
298
- ? { ...r, is_default: r.id === Number(templateId) }
299
- : r
300
- )
301
- saveStore('desk', rows)
302
- return ok(true)
303
- }
304
-
305
- /** —— upload / library —— */
306
- export const getBadgeLibraryImages = async (params?: { page?: number; page_size?: number }) => {
307
- const list = readJson<BadgeLibraryImage[]>(LS_LIBRARY, [])
308
- const page = Number(params?.page || 1)
309
- const pageSize = Number(params?.page_size || 40)
310
- const start = (page - 1) * pageSize
311
- return ok({ list: list.slice(start, start + pageSize), total: list.length, page, page_size: pageSize })
312
- }
313
-
314
- export const uploadBadgeLibraryImage = async (file: File) => {
315
- const url = await new Promise<string>((resolve, reject) => {
316
- const reader = new FileReader()
317
- reader.onload = () => resolve(String(reader.result || ''))
318
- reader.onerror = () => reject(new Error('read failed'))
319
- reader.readAsDataURL(file)
320
- })
321
- const list = readJson<BadgeLibraryImage[]>(LS_LIBRARY, [])
322
- const id = list.reduce((m, r) => Math.max(m, r.id), 0) + 1
323
- const row: BadgeLibraryImage = {
324
- id,
325
- url,
326
- name: file.name,
327
- create_time: nowText(),
328
- }
329
- list.unshift(row)
330
- writeJson(LS_LIBRARY, list)
331
- return ok(row)
332
- }
333
-
334
- export const deleteBadgeLibraryImage = async (id: number) => {
335
- const list = readJson<BadgeLibraryImage[]>(LS_LIBRARY, []).filter((r) => r.id !== Number(id))
336
- writeJson(LS_LIBRARY, list)
337
- return ok(true)
338
- }
339
-
340
- /** —— student / print data stubs —— */
341
- export const getBadgeSchools = async (_competitionId: number) =>
342
- ok([
343
- { id: 1, name: '演示学校一', short_name: '校一' },
344
- { id: 2, name: '演示学校二', short_name: '校二' },
345
- ])
346
-
347
- export const getBadges = async (_competitionId: number, _params?: any) =>
348
- ok({
349
- list: [
350
- {
351
- id: 1,
352
- student_name: '张三',
353
- competition_no: 'A001',
354
- school_name: '演示学校一',
355
- age_group: '小学组',
356
- competition_room: '101',
357
- seat_no: '01',
358
- },
359
- {
360
- id: 2,
361
- student_name: '李四',
362
- competition_no: 'A002',
363
- school_name: '演示学校一',
364
- age_group: '小学组',
365
- competition_room: '101',
366
- seat_no: '02',
367
- },
368
- ],
369
- total: 2,
370
- })
371
-
372
- export const getBadgesExportData = async (competitionId: number, params?: any) =>
373
- getBadges(competitionId, params)
374
-
375
- export const getStudents = async (_competitionId: number, _params?: any) =>
376
- ok({ list: [], total: 0 })
377
-
378
- export const finalizeSeatAssignmentLock = async (_competitionId: number, _data?: any) => ok(true)
379
-
380
- export const getDeskLabels = async (_competitionId: number) =>
381
- ok([
382
- {
383
- id: 1,
384
- competition_room: '101',
385
- seat_no: '01',
386
- student_name: '张三',
387
- school_name: '演示学校一',
388
- },
389
- ])