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,548 +0,0 @@
1
- <template>
2
- <div
3
- ref="rootRef"
4
- class="qiu-time"
5
- :class="[
6
- `qiu-time--${resolvedSize}`,
7
- attrs.class,
8
- {
9
- 'is-disabled': disabled,
10
- 'is-focused': panelVisible,
11
- 'is-fit': fit,
12
- },
13
- ]"
14
- :style="attrs.style as any"
15
- >
16
- <div class="qiu-time__editor" tabindex="0" @click="togglePanel" @keydown.enter.prevent="togglePanel">
17
- <span class="qiu-time__value" :class="{ 'is-placeholder': !displayText }">
18
- {{ displayText || placeholder }}
19
- </span>
20
- <button
21
- v-if="clearable && hasValue && !disabled"
22
- type="button"
23
- class="qiu-time__clear"
24
- tabindex="-1"
25
- @mousedown.prevent
26
- @click.stop="clearValue"
27
- >
28
- ×
29
- </button>
30
- <qiu-icon icon="time-line" class="qiu-time__icon" />
31
- </div>
32
-
33
- <Teleport to="body">
34
- <Transition name="qiu-time-fade">
35
- <div
36
- v-if="panelVisible"
37
- ref="panelRef"
38
- class="qiu-time-panel"
39
- :style="panelStyle"
40
- @mousedown.prevent
41
- >
42
- <div class="qiu-time-panel__body">
43
- <div class="qiu-time-panel__spinner">
44
- <ul ref="hourListRef" class="qiu-time-panel__list">
45
- <li
46
- v-for="h in hours"
47
- :key="`h-${h}`"
48
- class="qiu-time-panel__item"
49
- :class="{ 'is-active': draft.hour === h }"
50
- @click="setDraft('hour', h)"
51
- >
52
- {{ pad(h) }}
53
- </li>
54
- </ul>
55
- </div>
56
- <div class="qiu-time-panel__spinner">
57
- <ul ref="minuteListRef" class="qiu-time-panel__list">
58
- <li
59
- v-for="m in minutes"
60
- :key="`m-${m}`"
61
- class="qiu-time-panel__item"
62
- :class="{ 'is-active': draft.minute === m }"
63
- @click="setDraft('minute', m)"
64
- >
65
- {{ pad(m) }}
66
- </li>
67
- </ul>
68
- </div>
69
- <div v-if="showSeconds" class="qiu-time-panel__spinner">
70
- <ul ref="secondListRef" class="qiu-time-panel__list">
71
- <li
72
- v-for="s in seconds"
73
- :key="`s-${s}`"
74
- class="qiu-time-panel__item"
75
- :class="{ 'is-active': draft.second === s }"
76
- @click="setDraft('second', s)"
77
- >
78
- {{ pad(s) }}
79
- </li>
80
- </ul>
81
- </div>
82
- </div>
83
- <div class="qiu-time-panel__footer">
84
- <button type="button" class="qiu-time-panel__btn is-text" @click="pickNow">此刻</button>
85
- <div class="qiu-time-panel__actions">
86
- <button type="button" class="qiu-time-panel__btn" @click="cancelPanel">取消</button>
87
- <button type="button" class="qiu-time-panel__btn is-primary" @click="confirmPanel">
88
- 确定
89
- </button>
90
- </div>
91
- </div>
92
- </div>
93
- </Transition>
94
- </Teleport>
95
- </div>
96
- </template>
97
-
98
- <script lang="ts" setup>
99
- import type { CSSProperties } from 'vue'
100
-
101
- defineOptions({
102
- name: 'QiuTime',
103
- inheritAttrs: false,
104
- })
105
-
106
- type TimeParts = { hour: number; minute: number; second: number }
107
-
108
- const props = withDefaults(
109
- defineProps<{
110
- modelValue?: string | null
111
- /** 展示/绑定格式:HH:mm:ss 或 HH:mm */
112
- format?: 'HH:mm:ss' | 'HH:mm'
113
- placeholder?: string
114
- clearable?: boolean
115
- disabled?: boolean
116
- size?: 'large' | 'default' | 'small'
117
- /** 按内容自适应宽度(表格单元格内推荐) */
118
- fit?: boolean
119
- hourStep?: number
120
- minuteStep?: number
121
- secondStep?: number
122
- }>(),
123
- {
124
- modelValue: null,
125
- format: 'HH:mm:ss',
126
- placeholder: '选择时间',
127
- clearable: true,
128
- disabled: false,
129
- size: 'default',
130
- fit: false,
131
- hourStep: 1,
132
- minuteStep: 1,
133
- secondStep: 1,
134
- }
135
- )
136
-
137
- const emit = defineEmits<{
138
- 'update:modelValue': [string | null]
139
- change: [string | null]
140
- clear: []
141
- 'visible-change': [boolean]
142
- }>()
143
-
144
- const attrs = useAttrs()
145
- const rootRef = ref<HTMLElement | null>(null)
146
- const panelRef = ref<HTMLElement | null>(null)
147
- const hourListRef = ref<HTMLElement | null>(null)
148
- const minuteListRef = ref<HTMLElement | null>(null)
149
- const secondListRef = ref<HTMLElement | null>(null)
150
- const panelVisible = ref(false)
151
- const panelStyle = ref<CSSProperties>({
152
- position: 'fixed',
153
- top: '-9999px',
154
- left: '-9999px',
155
- zIndex: 3100,
156
- })
157
-
158
- const draft = reactive<TimeParts>({ hour: 0, minute: 0, second: 0 })
159
-
160
- const resolvedSize = computed(() => props.size || 'default')
161
- const showSeconds = computed(() => props.format !== 'HH:mm')
162
- const hasValue = computed(() => props.modelValue != null && props.modelValue !== '')
163
-
164
- const pad = (n: number) => String(n).padStart(2, '0')
165
-
166
- const rangeByStep = (max: number, step: number) => {
167
- const s = Math.max(1, Math.floor(step || 1))
168
- const list: number[] = []
169
- for (let i = 0; i <= max; i += s) list.push(i)
170
- if (list[list.length - 1] !== max && max % s === 0) {
171
- /* already includes */
172
- }
173
- return list
174
- }
175
-
176
- const hours = computed(() => rangeByStep(23, props.hourStep))
177
- const minutes = computed(() => rangeByStep(59, props.minuteStep))
178
- const seconds = computed(() => rangeByStep(59, props.secondStep))
179
-
180
- const parseTime = (val?: string | null): TimeParts | null => {
181
- if (!val) return null
182
- const m = String(val).trim().match(/^(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/)
183
- if (!m) return null
184
- const hour = Math.min(23, Math.max(0, Number(m[1])))
185
- const minute = Math.min(59, Math.max(0, Number(m[2])))
186
- const second = Math.min(59, Math.max(0, Number(m[3] ?? 0)))
187
- return { hour, minute, second }
188
- }
189
-
190
- const formatParts = (p: TimeParts) => {
191
- if (showSeconds.value) return `${pad(p.hour)}:${pad(p.minute)}:${pad(p.second)}`
192
- return `${pad(p.hour)}:${pad(p.minute)}`
193
- }
194
-
195
- const displayText = computed(() => {
196
- const p = parseTime(props.modelValue)
197
- return p ? formatParts(p) : ''
198
- })
199
-
200
- const syncDraftFromModel = () => {
201
- const p = parseTime(props.modelValue) || { hour: 0, minute: 0, second: 0 }
202
- draft.hour = p.hour
203
- draft.minute = p.minute
204
- draft.second = p.second
205
- }
206
-
207
- const scrollActiveIntoView = async () => {
208
- await nextTick()
209
- const scrollList = (el: HTMLElement | null, active: number) => {
210
- if (!el) return
211
- const item = el.querySelector('.qiu-time-panel__item.is-active') as HTMLElement | null
212
- if (item) {
213
- el.scrollTop = Math.max(0, item.offsetTop - el.clientHeight / 2 + item.clientHeight / 2)
214
- return
215
- }
216
- const idx = Array.from(el.children).findIndex((n) => Number((n as HTMLElement).textContent) === active)
217
- if (idx >= 0) {
218
- const node = el.children[idx] as HTMLElement
219
- el.scrollTop = Math.max(0, node.offsetTop - el.clientHeight / 2 + node.clientHeight / 2)
220
- }
221
- }
222
- scrollList(hourListRef.value, draft.hour)
223
- scrollList(minuteListRef.value, draft.minute)
224
- if (showSeconds.value) scrollList(secondListRef.value, draft.second)
225
- }
226
-
227
- const updatePanelPosition = () => {
228
- const trigger = rootRef.value
229
- const panel = panelRef.value
230
- if (!trigger || !panel) return
231
- const rect = trigger.getBoundingClientRect()
232
- const panelRect = panel.getBoundingClientRect()
233
- const gap = 4
234
- const vw = window.innerWidth
235
- const vh = window.innerHeight
236
- let top = rect.bottom + gap
237
- let left = rect.left
238
- if (top + panelRect.height > vh - 4) top = rect.top - panelRect.height - gap
239
- if (top < 4) top = 4
240
- if (left + panelRect.width > vw - 4) left = vw - panelRect.width - 4
241
- if (left < 4) left = 4
242
- panelStyle.value = {
243
- position: 'fixed',
244
- top: `${Math.round(top)}px`,
245
- left: `${Math.round(left)}px`,
246
- zIndex: 3100,
247
- }
248
- }
249
-
250
- const openPanel = async () => {
251
- if (props.disabled) return
252
- syncDraftFromModel()
253
- panelVisible.value = true
254
- emit('visible-change', true)
255
- await nextTick()
256
- updatePanelPosition()
257
- await scrollActiveIntoView()
258
- requestAnimationFrame(() => updatePanelPosition())
259
- }
260
-
261
- const closePanel = () => {
262
- if (!panelVisible.value) return
263
- panelVisible.value = false
264
- emit('visible-change', false)
265
- }
266
-
267
- const togglePanel = () => {
268
- if (props.disabled) return
269
- panelVisible.value ? closePanel() : openPanel()
270
- }
271
-
272
- const setDraft = (key: keyof TimeParts, value: number) => {
273
- draft[key] = value
274
- }
275
-
276
- const emitValue = (val: string | null) => {
277
- emit('update:modelValue', val)
278
- emit('change', val)
279
- }
280
-
281
- const confirmPanel = () => {
282
- emitValue(formatParts({ ...draft }))
283
- closePanel()
284
- }
285
-
286
- const cancelPanel = () => {
287
- closePanel()
288
- }
289
-
290
- const pickNow = () => {
291
- const now = new Date()
292
- draft.hour = now.getHours()
293
- draft.minute = now.getMinutes()
294
- draft.second = now.getSeconds()
295
- emitValue(formatParts({ ...draft }))
296
- closePanel()
297
- }
298
-
299
- const clearValue = () => {
300
- emitValue(null)
301
- emit('clear')
302
- }
303
-
304
- const onDocClick = (e: MouseEvent) => {
305
- if (!panelVisible.value) return
306
- const t = e.target as Node
307
- if (rootRef.value?.contains(t) || panelRef.value?.contains(t)) return
308
- closePanel()
309
- }
310
-
311
- const onScrollOrResize = () => {
312
- if (panelVisible.value) updatePanelPosition()
313
- }
314
-
315
- watch(panelVisible, (v) => {
316
- if (v) {
317
- document.addEventListener('mousedown', onDocClick, true)
318
- window.addEventListener('scroll', onScrollOrResize, true)
319
- window.addEventListener('resize', onScrollOrResize)
320
- } else {
321
- document.removeEventListener('mousedown', onDocClick, true)
322
- window.removeEventListener('scroll', onScrollOrResize, true)
323
- window.removeEventListener('resize', onScrollOrResize)
324
- }
325
- })
326
-
327
- onBeforeUnmount(() => {
328
- document.removeEventListener('mousedown', onDocClick, true)
329
- window.removeEventListener('scroll', onScrollOrResize, true)
330
- window.removeEventListener('resize', onScrollOrResize)
331
- })
332
- </script>
333
-
334
- <style lang="scss" scoped>
335
- .qiu-time {
336
- position: relative;
337
- display: inline-flex;
338
- box-sizing: border-box;
339
- width: 100%;
340
- max-width: 100%;
341
- vertical-align: middle;
342
-
343
- &.is-fit {
344
- width: auto;
345
- min-width: 120px;
346
- }
347
-
348
- &.is-disabled .qiu-time__editor {
349
- cursor: not-allowed;
350
- background: var(--qiu-fill-color-light, var(--qiu-fill-color-light, #f5f7fa));
351
- color: var(--qiu-text-color-placeholder, var(--qiu-text-color-placeholder, #a8abb2));
352
- }
353
-
354
- &.is-focused .qiu-time__editor {
355
- border-color: var(--qiu-color-primary, var(--qiu-color-primary));
356
- box-shadow: 0 0 0 1px
357
- color-mix(in srgb, var(--qiu-color-primary, var(--qiu-color-primary)) 25%, transparent);
358
- }
359
- }
360
-
361
- .qiu-time__editor {
362
- display: inline-flex;
363
- align-items: center;
364
- box-sizing: border-box;
365
- width: 100%;
366
- min-width: 0;
367
- padding: 0 8px 0 12px;
368
- cursor: pointer;
369
- background: var(--qiu-bg-color, var(--qiu-bg-color, #fff));
370
- border: 1px solid var(--qiu-border-color, var(--qiu-border-color, #dcdfe6));
371
- border-radius: var(--qiu-border-radius-base, var(--qiu-border-radius-base, 4px));
372
- outline: none;
373
- transition: border-color 0.2s ease, box-shadow 0.2s ease;
374
-
375
- &:hover {
376
- border-color: var(--qiu-border-color-hover, var(--qiu-border-color-hover, #c0c4cc));
377
- }
378
- }
379
-
380
- .qiu-time--large .qiu-time__editor {
381
- height: 40px;
382
- font-size: 16px;
383
- }
384
-
385
- .qiu-time--default .qiu-time__editor {
386
- height: 32px;
387
- font-size: 14px;
388
- }
389
-
390
- .qiu-time--small .qiu-time__editor {
391
- height: 24px;
392
- font-size: 12px;
393
- }
394
-
395
- .qiu-time__value {
396
- flex: 1;
397
- min-width: 0;
398
- overflow: hidden;
399
- text-overflow: ellipsis;
400
- white-space: nowrap;
401
- color: var(--qiu-text-color-primary, var(--qiu-text-color-primary, #303133));
402
- line-height: 1;
403
-
404
- &.is-placeholder {
405
- color: var(--qiu-text-color-placeholder, var(--qiu-text-color-placeholder, #a8abb2));
406
- }
407
- }
408
-
409
- .qiu-time__clear,
410
- .qiu-time__icon {
411
- flex-shrink: 0;
412
- margin-left: 4px;
413
- color: var(--qiu-text-color-placeholder, var(--qiu-text-color-placeholder, #a8abb2));
414
- }
415
-
416
- .qiu-time__clear {
417
- display: inline-flex;
418
- align-items: center;
419
- justify-content: center;
420
- width: 16px;
421
- height: 16px;
422
- padding: 0;
423
- font-size: 14px;
424
- line-height: 1;
425
- cursor: pointer;
426
- background: transparent;
427
- border: 0;
428
- border-radius: 50%;
429
-
430
- &:hover {
431
- color: var(--qiu-text-color-regular, var(--qiu-text-color-regular, #606266));
432
- }
433
- }
434
-
435
- .qiu-time__icon {
436
- font-size: 14px;
437
- }
438
-
439
- .qiu-time-panel {
440
- box-sizing: border-box;
441
- width: auto;
442
- overflow: hidden;
443
- background: var(--qiu-bg-color-overlay, var(--qiu-bg-color-overlay, #fff));
444
- border: 1px solid var(--qiu-border-color-light, var(--qiu-border-color-light, #e4e7ed));
445
- border-radius: var(--qiu-border-radius-base, var(--qiu-border-radius-base, 4px));
446
- box-shadow: var(--qiu-box-shadow-light, var(--qiu-box-shadow-light, 0 4px 12px rgb(0 0 0 / 10%)));
447
- }
448
-
449
- .qiu-time-panel__body {
450
- display: flex;
451
- height: 204px;
452
- border-bottom: 1px solid var(--qiu-border-color-lighter, var(--qiu-border-color-lighter, #ebeef5));
453
- }
454
-
455
- .qiu-time-panel__spinner {
456
- flex: 1;
457
- min-width: 56px;
458
- overflow: hidden;
459
- border-right: 1px solid var(--qiu-border-color-lighter, var(--qiu-border-color-lighter, #ebeef5));
460
-
461
- &:last-child {
462
- border-right: 0;
463
- }
464
- }
465
-
466
- .qiu-time-panel__list {
467
- height: 100%;
468
- margin: 0;
469
- padding: 0;
470
- overflow-x: hidden;
471
- overflow-y: auto;
472
- list-style: none;
473
- scrollbar-width: thin;
474
- }
475
-
476
- .qiu-time-panel__item {
477
- height: 32px;
478
- padding: 0 10px;
479
- font-size: 13px;
480
- line-height: 32px;
481
- color: var(--qiu-text-color-regular, var(--qiu-text-color-regular, #606266));
482
- text-align: center;
483
- cursor: pointer;
484
- user-select: none;
485
-
486
- &:hover {
487
- background: var(--qiu-fill-color-light, var(--qiu-fill-color-light, #f5f7fa));
488
- }
489
-
490
- &.is-active {
491
- font-weight: 600;
492
- color: var(--qiu-color-primary, var(--qiu-color-primary));
493
- background: var(--qiu-color-primary-light-9, var(--qiu-color-primary-light-9, #ecf5ff));
494
- }
495
- }
496
-
497
- .qiu-time-panel__footer {
498
- display: flex;
499
- gap: 8px;
500
- align-items: center;
501
- justify-content: space-between;
502
- padding: 8px 10px;
503
- }
504
-
505
- .qiu-time-panel__actions {
506
- display: inline-flex;
507
- gap: 8px;
508
- }
509
-
510
- .qiu-time-panel__btn {
511
- height: 28px;
512
- padding: 0 12px;
513
- font-size: 13px;
514
- color: var(--qiu-text-color-regular, var(--qiu-text-color-regular, #606266));
515
- cursor: pointer;
516
- background: var(--qiu-fill-color-blank, #fff);
517
- border: 1px solid var(--qiu-border-color, var(--qiu-border-color, #dcdfe6));
518
- border-radius: 4px;
519
-
520
- &.is-text {
521
- padding: 0 4px;
522
- color: var(--qiu-color-primary, var(--qiu-color-primary));
523
- background: transparent;
524
- border-color: transparent;
525
- }
526
-
527
- &.is-primary {
528
- color: #fff;
529
- background: var(--qiu-color-primary, var(--qiu-color-primary));
530
- border-color: var(--qiu-color-primary, var(--qiu-color-primary));
531
- }
532
-
533
- &:hover {
534
- opacity: 0.92;
535
- }
536
- }
537
-
538
- .qiu-time-fade-enter-active,
539
- .qiu-time-fade-leave-active {
540
- transition: opacity 0.15s ease, transform 0.15s ease;
541
- }
542
-
543
- .qiu-time-fade-enter-from,
544
- .qiu-time-fade-leave-to {
545
- opacity: 0;
546
- transform: translateY(-4px);
547
- }
548
- </style>
@@ -1,103 +0,0 @@
1
- <template>
2
- <span class="qiu-time-ago" :title="absoluteTitle">
3
- <slot :value="text">{{ text }}</slot>
4
- </span>
5
- </template>
6
-
7
- <script lang="ts" setup>
8
- import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
9
-
10
- defineOptions({ name: 'QiuTimeAgo' })
11
-
12
- const props = withDefaults(
13
- defineProps<{
14
- /** 时间:Date / 时间戳(ms) / 时间字符串 */
15
- value?: Date | number | string
16
- /** 是否自动刷新 */
17
- autoUpdate?: boolean
18
- /** 刷新间隔(ms) */
19
- interval?: number
20
- }>(),
21
- {
22
- value: undefined,
23
- autoUpdate: true,
24
- interval: 30000,
25
- }
26
- )
27
-
28
- const emit = defineEmits<{
29
- update: [string]
30
- }>()
31
-
32
- const text = ref('')
33
- const absoluteTitle = ref('')
34
- let timer: ReturnType<typeof setInterval> | undefined
35
-
36
- const toDate = (val?: Date | number | string): Date | null => {
37
- if (!val) return null
38
- if (val instanceof Date) return isNaN(val.getTime()) ? null : val
39
- if (typeof val === 'number') return new Date(val)
40
- const d = new Date(val)
41
- return isNaN(d.getTime()) ? null : d
42
- }
43
-
44
- const diffText = (date: Date) => {
45
- const now = Date.now()
46
- const diff = now - date.getTime()
47
- const abs = Math.abs(diff)
48
- const future = diff < 0
49
- const sec = Math.floor(abs / 1000)
50
- const min = Math.floor(sec / 60)
51
- const hr = Math.floor(min / 60)
52
- const day = Math.floor(hr / 24)
53
-
54
- let rel: string
55
- if (sec < 10) rel = '刚刚'
56
- else if (sec < 60) rel = `${sec} 秒${future ? '后' : '前'}`
57
- else if (min < 60) rel = `${min} 分钟${future ? '后' : '前'}`
58
- else if (hr < 24) rel = `${hr} 小时${future ? '后' : '前'}`
59
- else if (day < 30) rel = `${day} 天${future ? '后' : '前'}`
60
- else {
61
- const y = date.getFullYear()
62
- const m = String(date.getMonth() + 1).padStart(2, '0')
63
- const d = String(date.getDate()).padStart(2, '0')
64
- text.value = `${y}-${m}-${d}`
65
- return
66
- }
67
- text.value = rel
68
- }
69
-
70
- const refresh = () => {
71
- const d = toDate(props.value)
72
- if (!d) {
73
- text.value = '--'
74
- absoluteTitle.value = ''
75
- return
76
- }
77
- const pad = (n: number) => String(n).padStart(2, '0')
78
- absoluteTitle.value = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
79
- diffText(d)
80
- emit('update', text.value)
81
- }
82
-
83
- watch(() => props.value, refresh, { immediate: false })
84
-
85
- onMounted(() => {
86
- refresh()
87
- if (props.autoUpdate && props.interval > 0) {
88
- timer = setInterval(refresh, props.interval)
89
- }
90
- })
91
-
92
- onBeforeUnmount(() => {
93
- if (timer) clearInterval(timer)
94
- })
95
- </script>
96
-
97
- <style lang="scss" scoped>
98
- .qiu-time-ago {
99
- display: inline;
100
- font-size: inherit;
101
- color: inherit;
102
- }
103
- </style>
@@ -1,54 +0,0 @@
1
- <template>
2
- <ul
3
- class="qiu-timeline"
4
- :class="{
5
- 'qiu-timeline--center': center,
6
- }"
7
- >
8
- <slot />
9
- </ul>
10
- </template>
11
-
12
- <script lang="ts" setup>
13
- defineOptions({ name: 'QiuTimeline' })
14
-
15
- withDefaults(
16
- defineProps<{
17
- center?: boolean
18
- }>(),
19
- {
20
- center: false,
21
- }
22
- )
23
- </script>
24
-
25
- <style lang="scss" scoped>
26
- .qiu-timeline {
27
- padding: 0;
28
- margin: 0;
29
- list-style: none;
30
-
31
- &--center {
32
- :deep(.qiu-timeline-item__wrapper) {
33
- width: 50%;
34
- }
35
-
36
- :deep(.qiu-timeline-item:nth-child(odd) .qiu-timeline-item__wrapper) {
37
- margin-left: 50%;
38
- padding-left: 24px;
39
- text-align: left;
40
- }
41
-
42
- :deep(.qiu-timeline-item:nth-child(even) .qiu-timeline-item__wrapper) {
43
- margin-right: 50%;
44
- padding-right: 24px;
45
- text-align: right;
46
- }
47
-
48
- :deep(.qiu-timeline-item__dot) {
49
- left: 50%;
50
- transform: translateX(-50%);
51
- }
52
- }
53
- }
54
- </style>