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,828 +0,0 @@
1
- <template>
2
- <Teleport :to="teleportTo" :disabled="!appendToBody">
3
- <div
4
- v-if="!props.destroyOnClose || contentAlive || dialogVisible"
5
- v-show="dialogVisible"
6
- class="qiu-dialog-root"
7
- :class="[rootClass, attrs.class]"
8
- v-bind="attrsWithoutClass"
9
- :style="{ zIndex: props.zIndex }"
10
- >
11
- <div
12
- v-if="modal && !isMinimized"
13
- class="qiu-dialog__mask"
14
- :class="modalClass"
15
- @mousedown.self="onMaskMouseDown"
16
- />
17
-
18
- <div
19
- ref="panelRef"
20
- class="qiu-dialog"
21
- :class="panelClass"
22
- :style="panelStyle"
23
- role="dialog"
24
- aria-modal="true"
25
- @mousedown="bringToFront"
26
- >
27
- <div
28
- class="qiu-dialog__header"
29
- :class="{ 'is-movable': canDrag, 'is-minimized-bar': isMinimized }"
30
- @mousedown="onHeaderMouseDown"
31
- @dblclick="onHeaderDblClick"
32
- @click="onMinimizedBarClick"
33
- >
34
- <div class="qiu-dialog__title">{{ title }}</div>
35
- <div class="qiu-dialog__actions" @mousedown.stop @click.stop>
36
- <button
37
- v-if="canMinimize && !isMinimized"
38
- type="button"
39
- class="qiu-dialog__btn"
40
- :title="translate('最小化')"
41
- @click.stop="minimize"
42
- >
43
- <qiu-icon icon="subtract-line" />
44
- </button>
45
- <button
46
- v-if="canMaximize"
47
- type="button"
48
- class="qiu-dialog__btn"
49
- :title="translate(isMinimized || isFullscreen ? '还原' : '最大化')"
50
- @click.stop="isMinimized ? restoreFromMinimize() : toggleMaximize()"
51
- >
52
- <qiu-icon
53
- :icon="
54
- isMinimized
55
- ? 'picture-in-picture-2-line'
56
- : isFullscreen
57
- ? 'fullscreen-exit-line'
58
- : 'fullscreen-line'
59
- "
60
- />
61
- </button>
62
- <button
63
- v-if="showClose"
64
- type="button"
65
- class="qiu-dialog__btn"
66
- :title="translate('关闭')"
67
- @click.stop="requestClose"
68
- >
69
- <qiu-icon icon="close-line" />
70
- </button>
71
- </div>
72
- </div>
73
-
74
- <div
75
- v-show="!isMinimized"
76
- class="qiu-dialog__body"
77
- :class="{ 'is-loading': loading }"
78
- >
79
- <div v-if="loading" class="qiu-dialog__loading">
80
- <span class="qiu-dialog__spinner" />
81
- <span v-if="loadingText" class="qiu-dialog__loading-text">{{ loadingText }}</span>
82
- </div>
83
- <slot />
84
- </div>
85
-
86
- <div v-if="!isMinimized && $slots.footer" class="qiu-dialog__footer">
87
- <slot name="footer" />
88
- </div>
89
-
90
- <!-- 拉伸条放在面板外侧,不覆盖 body 滚动条 -->
91
- <template v-if="resizable && !isFullscreen && !isMinimized">
92
- <div
93
- v-for="dir in resizeDirs"
94
- :key="dir"
95
- class="qiu-dialog__resize"
96
- :class="`qiu-dialog__resize--${dir}`"
97
- @mousedown.prevent.stop="startResize($event, dir)"
98
- />
99
- </template>
100
- </div>
101
- </div>
102
- </Teleport>
103
- </template>
104
-
105
- <script lang="ts" setup>
106
- import { translate } from '../../src/i18n'
107
- import { useBodyScrollLock } from '../useBodyScrollLock'
108
-
109
- defineOptions({ name: 'QiuDialog', inheritAttrs: false })
110
-
111
- type ResizeDir = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'
112
- type Box = { left: number; top: number; width: number; height: number }
113
-
114
- const props = withDefaults(
115
- defineProps<{
116
- modelValue?: boolean
117
- title?: string
118
- width?: string | number
119
- top?: string
120
- /** 打开时垂直水平居中;false 时用 top */
121
- alignCenter?: boolean
122
- modal?: boolean
123
- modalClass?: string
124
- appendToBody?: boolean
125
- appendTo?: string | HTMLElement
126
- lockScroll?: boolean
127
- closeOnClickModal?: boolean
128
- closeOnPressEscape?: boolean
129
- destroyOnClose?: boolean
130
- beforeClose?: (done: () => void) => void
131
- showFullscreen?: boolean
132
- showMinimize?: boolean
133
- /** 别名:优先于 showFullscreen */
134
- maximizable?: boolean
135
- /** 别名:优先于 showMinimize */
136
- minimizable?: boolean
137
- showClose?: boolean
138
- fullscreen?: boolean
139
- loading?: boolean
140
- loadingText?: string
141
- animated?: boolean
142
- theme?: string
143
- draggable?: boolean
144
- /**
145
- * 拖拽边界:
146
- * - viewport / true:限制在可视窗口内(默认)
147
- * - none / false:可拖出可视窗口外
148
- */
149
- dragBound?: boolean | 'viewport' | 'none'
150
- resizable?: boolean
151
- openInTab?: boolean
152
- minWidth?: number
153
- minHeight?: number
154
- zIndex?: number
155
- }>(),
156
- {
157
- modelValue: false,
158
- title: '',
159
- width: '520px',
160
- top: '15vh',
161
- alignCenter: true,
162
- modal: true,
163
- modalClass: '',
164
- appendToBody: true,
165
- lockScroll: true,
166
- closeOnClickModal: false,
167
- closeOnPressEscape: false,
168
- destroyOnClose: false,
169
- showFullscreen: true,
170
- showMinimize: true,
171
- maximizable: undefined,
172
- minimizable: undefined,
173
- showClose: true,
174
- fullscreen: false,
175
- loading: false,
176
- animated: true,
177
- theme: 'default',
178
- draggable: true,
179
- dragBound: 'viewport',
180
- resizable: true,
181
- openInTab: false,
182
- minWidth: 320,
183
- minHeight: 180,
184
- zIndex: 2000,
185
- }
186
- )
187
-
188
- const emit = defineEmits<{
189
- 'update:modelValue': [boolean]
190
- open: []
191
- opened: []
192
- close: []
193
- closed: []
194
- minimize: []
195
- maximize: []
196
- restore: []
197
- }>()
198
-
199
- const attrs = useAttrs()
200
- const attrsWithoutClass = computed(() => {
201
- const { class: _c, style: _s, ...rest } = attrs as Record<string, unknown>
202
- return rest
203
- })
204
-
205
- const dialogVisible = useVModel(props, 'modelValue', emit)
206
- const panelRef = ref<HTMLElement | null>(null)
207
- const isFullscreen = ref(false)
208
- const isMinimized = ref(false)
209
- const box = ref<Box | null>(null)
210
- const restoreBox = ref<Box | null>(null)
211
- const dragging = ref(false)
212
- const resizing = ref(false)
213
- const closing = ref(false)
214
- const zBoost = ref(0)
215
- const contentAlive = ref(true)
216
-
217
- const resizeDirs: ResizeDir[] = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw']
218
-
219
- const teleportTo = computed(() => {
220
- if (typeof props.appendTo === 'string') return props.appendTo
221
- if (props.appendTo instanceof HTMLElement) return props.appendTo
222
- return 'body'
223
- })
224
- const appendToBody = computed(() => props.appendToBody !== false)
225
-
226
- const canMaximize = computed(() => props.maximizable ?? props.showFullscreen)
227
- const canMinimize = computed(() => props.minimizable ?? props.showMinimize)
228
- const canDrag = computed(() => props.draggable && !isFullscreen.value && !isMinimized.value)
229
- const interacted = computed(() => !!box.value)
230
- /** 是否限制拖拽在可视窗口内 */
231
- const isViewportBound = computed(() => {
232
- const v = props.dragBound
233
- return v === true || v === 'viewport' || v === undefined
234
- })
235
-
236
- const rootClass = computed(() => ({
237
- 'is-open-in-tab': props.openInTab,
238
- 'is-minimized-root': isMinimized.value,
239
- }))
240
-
241
- const panelClass = computed(() => ({
242
- [`qiu-dialog--${props.theme}`]: true,
243
- 'qiu-dialog--minimized': isMinimized.value,
244
- 'qiu-dialog--fullscreen': isFullscreen.value,
245
- 'qiu-dialog--centered': !interacted.value && !isFullscreen.value && !isMinimized.value && props.alignCenter,
246
- 'qiu-dialog--topped': !interacted.value && !isFullscreen.value && !isMinimized.value && !props.alignCenter,
247
- 'qiu-dialog--fixed-box': interacted.value && !isFullscreen.value && !isMinimized.value,
248
- 'qiu-dialog--unbounded': !isViewportBound.value && interacted.value && !isFullscreen.value && !isMinimized.value,
249
- 'qiu-dialog--dragging': dragging.value,
250
- 'qiu-dialog--resizing': resizing.value,
251
- 'qiu-dialog--animated': props.animated && !dragging.value && !resizing.value && !closing.value,
252
- }))
253
-
254
- const panelStyle = computed(() => {
255
- const style: Record<string, string> = {
256
- zIndex: String(props.zIndex + zBoost.value + (isMinimized.value ? 100 : 0)),
257
- }
258
-
259
- if (isMinimized.value) {
260
- Object.assign(style, {
261
- left: '16px',
262
- bottom: '16px',
263
- top: 'auto',
264
- width: '240px',
265
- height: '48px',
266
- transform: 'none',
267
- })
268
- return style
269
- }
270
-
271
- if (isFullscreen.value) {
272
- Object.assign(style, {
273
- left: '0',
274
- top: '0',
275
- width: '100vw',
276
- height: '100vh',
277
- transform: 'none',
278
- borderRadius: '0',
279
- })
280
- return style
281
- }
282
-
283
- if (box.value) {
284
- Object.assign(style, {
285
- left: `${box.value.left}px`,
286
- top: `${box.value.top}px`,
287
- width: `${box.value.width}px`,
288
- height: `${box.value.height}px`,
289
- transform: 'none',
290
- })
291
- return style
292
- }
293
-
294
- // 未交互:居中或 top 定位
295
- style.width = typeof props.width === 'number' ? `${props.width}px` : String(props.width || '520px')
296
- if (!props.alignCenter) {
297
- style.top = props.top || '15vh'
298
- style.left = '50%'
299
- style.transform = 'translateX(-50%)'
300
- }
301
- return style
302
- })
303
-
304
- const clampBox = (next: Box, mode: 'drag' | 'resize' = 'resize'): Box => {
305
- const vw = window.innerWidth
306
- const vh = window.innerHeight
307
- const width = Math.max(props.minWidth, next.width)
308
- const height = Math.max(props.minHeight, next.height)
309
-
310
- // 允许拖出可视区:位置不限制;拉伸仍保证最小尺寸
311
- if (!isViewportBound.value) {
312
- return {
313
- left: next.left,
314
- top: next.top,
315
- width: mode === 'resize' ? width : Math.max(props.minWidth, next.width),
316
- height: mode === 'resize' ? height : Math.max(props.minHeight, next.height),
317
- }
318
- }
319
-
320
- // 可视窗口内:位置与尺寸都限制在窗口内
321
- const maxW = Math.max(props.minWidth, vw - 8)
322
- const maxH = Math.max(props.minHeight, vh - 8)
323
- const w = Math.min(width, maxW)
324
- const h = Math.min(height, maxH)
325
- const left = Math.min(Math.max(0, next.left), Math.max(0, vw - w))
326
- const top = Math.min(Math.max(0, next.top), Math.max(0, vh - h))
327
- return { left, top, width: w, height: h }
328
- }
329
-
330
- /** 从当前 DOM 量出像素盒(首次拖拽/拉伸时调用) */
331
- const captureBox = () => {
332
- const el = panelRef.value
333
- if (!el) return null
334
- const rect = el.getBoundingClientRect()
335
- const next = clampBox({
336
- left: rect.left,
337
- top: rect.top,
338
- width: rect.width,
339
- height: Math.max(rect.height, props.minHeight),
340
- })
341
- box.value = next
342
- return next
343
- }
344
-
345
- const ensureBox = () => box.value || captureBox()
346
-
347
- const { lock: lockScroll, unlock: unlockScroll } = useBodyScrollLock()
348
- const lockBodyScroll = (lock: boolean) => {
349
- if (!props.lockScroll) return
350
- if (lock) lockScroll()
351
- else unlockScroll()
352
- }
353
-
354
- const doClose = () => {
355
- closing.value = true
356
- emit('close')
357
- dialogVisible.value = false
358
- }
359
-
360
- const requestClose = () => {
361
- if (props.beforeClose) {
362
- props.beforeClose(() => doClose())
363
- return
364
- }
365
- doClose()
366
- }
367
-
368
- const onMaskMouseDown = () => {
369
- if (props.closeOnClickModal) requestClose()
370
- }
371
-
372
- const bringToFront = () => {
373
- zBoost.value += 1
374
- }
375
-
376
- const toggleMaximize = () => {
377
- if (isMinimized.value) {
378
- restoreFromMinimize()
379
- return
380
- }
381
- if (!isFullscreen.value) {
382
- ensureBox()
383
- if (box.value) restoreBox.value = { ...box.value }
384
- isFullscreen.value = true
385
- emit('maximize')
386
- } else {
387
- isFullscreen.value = false
388
- if (restoreBox.value) box.value = { ...restoreBox.value }
389
- emit('restore')
390
- }
391
- }
392
-
393
- const minimize = () => {
394
- if (isFullscreen.value) isFullscreen.value = false
395
- ensureBox()
396
- if (box.value) restoreBox.value = { ...box.value }
397
- isMinimized.value = true
398
- emit('minimize')
399
- }
400
-
401
- const restoreFromMinimize = () => {
402
- isMinimized.value = false
403
- if (restoreBox.value) box.value = { ...restoreBox.value }
404
- emit('restore')
405
- }
406
-
407
- const onMinimizedBarClick = () => {
408
- if (isMinimized.value) restoreFromMinimize()
409
- }
410
-
411
- const onHeaderDblClick = () => {
412
- if (isMinimized.value) restoreFromMinimize()
413
- else toggleMaximize()
414
- }
415
-
416
- const onHeaderMouseDown = (e: MouseEvent) => {
417
- if (!canDrag.value) return
418
- if ((e.target as HTMLElement).closest('.qiu-dialog__actions')) return
419
- e.preventDefault()
420
- const origin = ensureBox()
421
- if (!origin) return
422
-
423
- dragging.value = true
424
- const startX = e.clientX
425
- const startY = e.clientY
426
-
427
- const onMove = (ev: MouseEvent) => {
428
- box.value = clampBox(
429
- {
430
- ...origin,
431
- left: origin.left + ev.clientX - startX,
432
- top: origin.top + ev.clientY - startY,
433
- },
434
- 'drag'
435
- )
436
- }
437
- const onUp = () => {
438
- dragging.value = false
439
- document.removeEventListener('mousemove', onMove)
440
- document.removeEventListener('mouseup', onUp)
441
- }
442
- document.addEventListener('mousemove', onMove)
443
- document.addEventListener('mouseup', onUp)
444
- }
445
-
446
- const startResize = (e: MouseEvent, dir: ResizeDir) => {
447
- const origin = ensureBox()
448
- if (!origin) return
449
- resizing.value = true
450
- const startX = e.clientX
451
- const startY = e.clientY
452
-
453
- const onMove = (ev: MouseEvent) => {
454
- const dx = ev.clientX - startX
455
- const dy = ev.clientY - startY
456
- let { left, top, width, height } = origin
457
-
458
- if (dir.includes('e')) width = origin.width + dx
459
- if (dir.includes('s')) height = origin.height + dy
460
- if (dir.includes('w')) {
461
- width = origin.width - dx
462
- left = origin.left + dx
463
- if (width < props.minWidth) {
464
- width = props.minWidth
465
- left = origin.left + origin.width - props.minWidth
466
- }
467
- }
468
- if (dir.includes('n')) {
469
- height = origin.height - dy
470
- top = origin.top + dy
471
- if (height < props.minHeight) {
472
- height = props.minHeight
473
- top = origin.top + origin.height - props.minHeight
474
- }
475
- }
476
- box.value = clampBox({ left, top, width, height }, 'resize')
477
- }
478
-
479
- const onUp = () => {
480
- resizing.value = false
481
- document.removeEventListener('mousemove', onMove)
482
- document.removeEventListener('mouseup', onUp)
483
- }
484
- document.addEventListener('mousemove', onMove)
485
- document.addEventListener('mouseup', onUp)
486
- }
487
-
488
- const onKeydown = (e: KeyboardEvent) => {
489
- if (!dialogVisible.value || isMinimized.value) return
490
- if (props.closeOnPressEscape && e.key === 'Escape') requestClose()
491
- }
492
-
493
- const resetState = () => {
494
- isMinimized.value = false
495
- isFullscreen.value = !!props.fullscreen
496
- box.value = null
497
- restoreBox.value = null
498
- closing.value = false
499
- dragging.value = false
500
- resizing.value = false
501
- }
502
-
503
- watch(
504
- () => props.fullscreen,
505
- (v) => {
506
- isFullscreen.value = !!v
507
- },
508
- { immediate: true }
509
- )
510
-
511
- watch(dialogVisible, async (v) => {
512
- if (v) {
513
- closing.value = false
514
- if (props.destroyOnClose) contentAlive.value = true
515
- lockBodyScroll(true)
516
- emit('open')
517
- await nextTick()
518
- // 居中模式下预计算像素盒会破坏 CSS 居中;保持 CSS,直到用户拖拽/拉伸
519
- if (!props.alignCenter && !box.value && panelRef.value) {
520
- // top 模式也等用户交互再固化
521
- }
522
- emit('opened')
523
- } else {
524
- lockBodyScroll(false)
525
- emit('closed')
526
- // 关闭完成后再清状态,避免关闭瞬间尺寸跳动
527
- resetState()
528
- if (props.destroyOnClose) contentAlive.value = false
529
- }
530
- })
531
-
532
- onMounted(() => {
533
- document.addEventListener('keydown', onKeydown)
534
- if (dialogVisible.value) lockBodyScroll(true)
535
- })
536
-
537
- onBeforeUnmount(() => {
538
- document.removeEventListener('keydown', onKeydown)
539
- lockBodyScroll(false)
540
- })
541
- </script>
542
-
543
- <style lang="scss" scoped>
544
- .qiu-dialog-root {
545
- position: fixed;
546
- inset: 0;
547
- pointer-events: none;
548
-
549
- &.is-open-in-tab {
550
- position: absolute;
551
- }
552
-
553
- &.is-minimized-root {
554
- .qiu-dialog__mask {
555
- display: none;
556
- }
557
- }
558
- }
559
-
560
- .qiu-dialog__mask {
561
- position: absolute;
562
- inset: 0;
563
- pointer-events: auto;
564
- background: var(--qiu-overlay-color-lighter, rgba(0, 0, 0, 0.45));
565
- }
566
-
567
- .qiu-dialog {
568
- position: fixed;
569
- display: flex;
570
- flex-direction: column;
571
- max-width: calc(100vw - 8px);
572
- max-height: calc(100vh - 8px);
573
- pointer-events: auto;
574
- background: var(--qiu-bg-color, #fff);
575
- border: 1px solid var(--qiu-border-color-lighter, #ebeef5);
576
- border-radius: 8px;
577
- box-shadow: var(--qiu-box-shadow, 0 12px 32px rgba(0, 0, 0, 0.12));
578
- box-sizing: border-box;
579
- overflow: visible;
580
-
581
- &.qiu-dialog--animated {
582
- transition: box-shadow 0.2s ease, opacity 0.2s ease;
583
- }
584
-
585
- &.qiu-dialog--centered {
586
- top: 50%;
587
- left: 50%;
588
- transform: translate(-50%, -50%);
589
- }
590
-
591
- &.qiu-dialog--topped {
592
- /* left/transform 由 inline style 控制 */
593
- top: auto;
594
- }
595
-
596
- &.qiu-dialog--fixed-box,
597
- &.qiu-dialog--fullscreen {
598
- transform: none;
599
- }
600
-
601
- &.qiu-dialog--minimized {
602
- overflow: hidden;
603
- border-radius: 8px;
604
-
605
- .qiu-dialog__header {
606
- height: 48px;
607
- min-height: 48px;
608
- padding: 0 8px 0 12px;
609
- cursor: pointer;
610
- }
611
- }
612
-
613
- &.qiu-dialog--fullscreen {
614
- border-radius: 0;
615
- max-width: none;
616
- max-height: none;
617
- }
618
-
619
- /* 允许拖出可视区时取消 max 限制,否则会被 CSS 卡住 */
620
- &.qiu-dialog--unbounded {
621
- max-width: none;
622
- max-height: none;
623
- }
624
- }
625
-
626
- .qiu-dialog__header {
627
- position: relative;
628
- z-index: 2;
629
- display: flex;
630
- flex-shrink: 0;
631
- align-items: center;
632
- min-height: 48px;
633
- padding: 10px 108px 10px 16px;
634
- border-bottom: 1px solid var(--qiu-border-color-lighter, #ebeef5);
635
- user-select: none;
636
- box-sizing: border-box;
637
-
638
- &.is-movable {
639
- cursor: move;
640
- }
641
- }
642
-
643
- .qiu-dialog__title {
644
- flex: 1;
645
- min-width: 0;
646
- overflow: hidden;
647
- font-size: 16px;
648
- font-weight: 600;
649
- line-height: 1.4;
650
- color: var(--qiu-text-color-primary, #303133);
651
- text-overflow: ellipsis;
652
- white-space: nowrap;
653
- pointer-events: none;
654
- }
655
-
656
- .qiu-dialog__actions {
657
- position: absolute;
658
- top: 50%;
659
- right: 8px;
660
- display: inline-flex;
661
- gap: 2px;
662
- align-items: center;
663
- transform: translateY(-50%);
664
- }
665
-
666
- .qiu-dialog__btn {
667
- display: inline-flex;
668
- align-items: center;
669
- justify-content: center;
670
- width: 32px;
671
- height: 32px;
672
- padding: 0;
673
- color: var(--qiu-color-info, #909399);
674
- cursor: pointer;
675
- background: transparent;
676
- border: 0;
677
- border-radius: 4px;
678
- outline: none;
679
-
680
- &:hover {
681
- color: var(--qiu-color-primary, #409eff);
682
- background: var(--qiu-fill-color-light, #f5f7fa);
683
- }
684
-
685
- :deep(.qiu-icon) {
686
- font-size: 16px;
687
- }
688
- }
689
-
690
- .qiu-dialog__body {
691
- position: relative;
692
- z-index: 2;
693
- display: flex;
694
- flex-direction: column;
695
- flex: 1 1 auto;
696
- min-width: 0;
697
- min-height: 0;
698
- padding: 16px;
699
- overflow: auto;
700
- box-sizing: border-box;
701
- color: var(--qiu-text-color-regular, #606266);
702
- font-size: 14px;
703
-
704
- &.is-loading {
705
- pointer-events: none;
706
- }
707
- }
708
-
709
- .qiu-dialog__loading {
710
- position: absolute;
711
- inset: 0;
712
- z-index: 5;
713
- display: flex;
714
- flex-direction: column;
715
- gap: 8px;
716
- align-items: center;
717
- justify-content: center;
718
- background: color-mix(in srgb, var(--qiu-bg-color, #fff) 72%, transparent);
719
- }
720
-
721
- .qiu-dialog__spinner {
722
- width: 28px;
723
- height: 28px;
724
- border: 2px solid var(--qiu-color-primary, #0f766e);
725
- border-right-color: transparent;
726
- border-radius: 50%;
727
- animation: qiu-dialog-spin 0.7s linear infinite;
728
- }
729
-
730
- .qiu-dialog__loading-text {
731
- font-size: 13px;
732
- color: var(--qiu-text-color-secondary, #909399);
733
- }
734
-
735
- @keyframes qiu-dialog-spin {
736
- to {
737
- transform: rotate(360deg);
738
- }
739
- }
740
-
741
- .qiu-dialog__footer {
742
- position: relative;
743
- z-index: 2;
744
- display: flex;
745
- flex-shrink: 0;
746
- gap: 8px;
747
- align-items: center;
748
- justify-content: flex-end;
749
- padding: 12px 16px;
750
- border-top: 1px solid var(--qiu-border-color-lighter, #ebeef5);
751
- box-sizing: border-box;
752
- }
753
-
754
- /*
755
- 拉伸热区全部贴在面板「外侧」:
756
- - 右边用 left:100%(从右边界向外),绝不压到纵向滚动条
757
- - 下边用 top:100%,不压横向滚动条
758
- */
759
- .qiu-dialog__resize {
760
- position: absolute;
761
- z-index: 5;
762
- background: transparent;
763
- }
764
-
765
- .qiu-dialog__resize--n {
766
- bottom: 100%;
767
- left: 8px;
768
- right: 8px;
769
- height: 8px;
770
- cursor: ns-resize;
771
- }
772
-
773
- .qiu-dialog__resize--s {
774
- top: 100%;
775
- left: 8px;
776
- right: 8px;
777
- height: 8px;
778
- cursor: ns-resize;
779
- }
780
-
781
- .qiu-dialog__resize--e {
782
- left: 100%;
783
- top: 8px;
784
- bottom: 8px;
785
- width: 8px;
786
- cursor: ew-resize;
787
- }
788
-
789
- .qiu-dialog__resize--w {
790
- right: 100%;
791
- top: 8px;
792
- bottom: 8px;
793
- width: 8px;
794
- cursor: ew-resize;
795
- }
796
-
797
- .qiu-dialog__resize--ne {
798
- left: 100%;
799
- bottom: 100%;
800
- width: 12px;
801
- height: 12px;
802
- cursor: nesw-resize;
803
- }
804
-
805
- .qiu-dialog__resize--nw {
806
- right: 100%;
807
- bottom: 100%;
808
- width: 12px;
809
- height: 12px;
810
- cursor: nwse-resize;
811
- }
812
-
813
- .qiu-dialog__resize--se {
814
- left: 100%;
815
- top: 100%;
816
- width: 12px;
817
- height: 12px;
818
- cursor: nwse-resize;
819
- }
820
-
821
- .qiu-dialog__resize--sw {
822
- right: 100%;
823
- top: 100%;
824
- width: 12px;
825
- height: 12px;
826
- cursor: nesw-resize;
827
- }
828
- </style>