Showing
10 changed files
with
698 additions
and
73 deletions
@@ -35,8 +35,7 @@ | @@ -35,8 +35,7 @@ | ||
35 | "sortablejs": "^1.15.0", | 35 | "sortablejs": "^1.15.0", |
36 | "video.js": "^7.20.3", | 36 | "video.js": "^7.20.3", |
37 | "videojs-flvjs-es6": "^1.0.1", | 37 | "videojs-flvjs-es6": "^1.0.1", |
38 | - "vue": "^3.3.4", | ||
39 | - "vue3-seamless-scroll": "^2.0.1" | 38 | + "vue": "^3.3.4" |
40 | }, | 39 | }, |
41 | "devDependencies": { | 40 | "devDependencies": { |
42 | "@iconify/vue": "^4.1.1", | 41 | "@iconify/vue": "^4.1.1", |
@@ -68,9 +68,6 @@ dependencies: | @@ -68,9 +68,6 @@ dependencies: | ||
68 | vue: | 68 | vue: |
69 | specifier: ^3.3.4 | 69 | specifier: ^3.3.4 |
70 | version: 3.3.4 | 70 | version: 3.3.4 |
71 | - vue3-seamless-scroll: | ||
72 | - specifier: ^2.0.1 | ||
73 | - version: 2.0.1 | ||
74 | 71 | ||
75 | devDependencies: | 72 | devDependencies: |
76 | '@iconify/vue': | 73 | '@iconify/vue': |
@@ -6412,12 +6409,6 @@ packages: | @@ -6412,12 +6409,6 @@ packages: | ||
6412 | vue: 3.3.4 | 6409 | vue: 3.3.4 |
6413 | dev: false | 6410 | dev: false |
6414 | 6411 | ||
6415 | - /vue3-seamless-scroll@2.0.1: | ||
6416 | - resolution: {integrity: sha512-mI3BaDU3pjcPUhVSw3/xNKdfPBDABTi/OdZaZqKysx4cSdNfGRbVvGNDzzptBbJ5S7imv5T55l6x/SqgnxKreg==} | ||
6417 | - dependencies: | ||
6418 | - throttle-debounce: 5.0.0 | ||
6419 | - dev: false | ||
6420 | - | ||
6421 | /vue@3.3.4: | 6412 | /vue@3.3.4: |
6422 | resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} | 6413 | resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} |
6423 | dependencies: | 6414 | dependencies: |
1 | +import type { AlarmStatusEnum } from '@/enums/datasource' | ||
2 | + | ||
1 | /** | 3 | /** |
2 | * 告警列表 | 4 | * 告警列表 |
3 | */ | 5 | */ |
@@ -28,7 +30,7 @@ export interface AlarmListItemType { | @@ -28,7 +30,7 @@ export interface AlarmListItemType { | ||
28 | deviceName: string | 30 | deviceName: string |
29 | type: string | 31 | type: string |
30 | severity: string | 32 | severity: string |
31 | - status: string | 33 | + status: AlarmStatusEnum |
32 | startTs: string | 34 | startTs: string |
33 | endTs: string | 35 | endTs: string |
34 | ackTs: string | 36 | ackTs: string |
src/core/Library/hook/useComponentStyle.ts
0 → 100644
1 | +import type { CSSProperties } from 'vue' | ||
2 | +import type { RenderComponentProps } from '../types' | ||
3 | +import { NodeUtils } from '@/hooks/business/useNodeUtils' | ||
4 | +import { EnableEnum, GradientDirectionEnum, type MxShapeStyleType } from '@/fitCore/types' | ||
5 | + | ||
6 | +const gradientDirectionMap = { | ||
7 | + [GradientDirectionEnum.NORTH]: 'to top', | ||
8 | + [GradientDirectionEnum.EAST]: 'to right', | ||
9 | + [GradientDirectionEnum.SOUTH]: 'to bottom', | ||
10 | + [GradientDirectionEnum.WEST]: 'to left', | ||
11 | +} | ||
12 | + | ||
13 | +export interface UseComponentStyleReturnType { | ||
14 | + style: CSSProperties | ||
15 | + textAalign?: string | ||
16 | + borderColor?: string | ||
17 | + borderWidth?: number | ||
18 | + borderStyle?: string | ||
19 | + backgroundColor?: string | ||
20 | + fontFamily?: string | ||
21 | + color?: string | ||
22 | + fontSize?: number | ||
23 | + gradientBackgroundColor?: string | ||
24 | + gradientDirection?: GradientDirectionEnum | ||
25 | + opacity?: number | ||
26 | +} | ||
27 | + | ||
28 | +export function useComponentStyle(props: RenderComponentProps): UseComponentStyleReturnType { | ||
29 | + const result: UseComponentStyleReturnType = { style: {} } | ||
30 | + | ||
31 | + const nodeUtils = new NodeUtils() | ||
32 | + const { cellInfo } = props.config | ||
33 | + const { id } = cellInfo || {} | ||
34 | + if (!id) return result | ||
35 | + const cell = nodeUtils.getCellById(id) | ||
36 | + | ||
37 | + if (!cell) return result | ||
38 | + | ||
39 | + const cellState = nodeUtils.getCellState(cell) | ||
40 | + | ||
41 | + const { | ||
42 | + align, | ||
43 | + dashed, | ||
44 | + fillColor, | ||
45 | + fontColor, | ||
46 | + fontFamily, | ||
47 | + fontSize, | ||
48 | + gradientColor, | ||
49 | + gradientDirection, | ||
50 | + opacity, | ||
51 | + // shadow, | ||
52 | + strokeColor, | ||
53 | + // sketch, | ||
54 | + strokeWidth = 1, | ||
55 | + } = cellState.style as MxShapeStyleType | ||
56 | + | ||
57 | + const getBackgroundColor = () => { | ||
58 | + return { | ||
59 | + background: gradientColor !== 'none' | ||
60 | + ? gradientDirection === GradientDirectionEnum.RADIAL | ||
61 | + ? `radial-gradient(${fillColor}, ${gradientColor})` | ||
62 | + : `linear-gradient(${gradientDirectionMap[gradientDirection]}, ${fillColor}, ${gradientColor})` | ||
63 | + : fillColor, | ||
64 | + } as CSSProperties | ||
65 | + } | ||
66 | + | ||
67 | + const getBorderStyle = () => { | ||
68 | + return { | ||
69 | + borderColor: strokeColor, | ||
70 | + borderWidth: strokeWidth, | ||
71 | + borderStyle: strokeColor | ||
72 | + ? dashed === EnableEnum.ENABLE | ||
73 | + ? 'dashed' | ||
74 | + : 'solid' | ||
75 | + : 'none', | ||
76 | + } as CSSProperties | ||
77 | + } | ||
78 | + | ||
79 | + return { | ||
80 | + style: { | ||
81 | + textAlign: align, | ||
82 | + opacity, | ||
83 | + fontSize, | ||
84 | + fontFamily, | ||
85 | + color: fontColor, | ||
86 | + ...getBorderStyle(), | ||
87 | + ...getBackgroundColor(), | ||
88 | + }, | ||
89 | + textAalign: align, | ||
90 | + borderColor: strokeColor, | ||
91 | + borderWidth: strokeWidth, | ||
92 | + borderStyle: dashed === EnableEnum.ENABLE ? 'dashed' : 'solid', | ||
93 | + backgroundColor: fillColor, | ||
94 | + fontFamily, | ||
95 | + color: fontColor, | ||
96 | + fontSize, | ||
97 | + gradientBackgroundColor: gradientColor, | ||
98 | + gradientDirection, | ||
99 | + opacity, | ||
100 | + } | ||
101 | +} |
1 | +import type { CSSProperties } from 'vue' | ||
2 | +import { | ||
3 | + computed, | ||
4 | + defineComponent, | ||
5 | + getCurrentInstance, | ||
6 | + nextTick, | ||
7 | + onBeforeMount, | ||
8 | + onMounted, | ||
9 | + ref, | ||
10 | + watch, | ||
11 | +} from 'vue' | ||
12 | +import { useThrottleFn } from '@vueuse/core' | ||
13 | + | ||
14 | +interface PropsType { | ||
15 | + modelValue: boolean | ||
16 | + list: Array<unknown> | ||
17 | + step: number | ||
18 | + limitScrollNum: number | ||
19 | + hover: boolean | ||
20 | + direction: String | ||
21 | + singleHeight: number | ||
22 | + singleWidth: number | ||
23 | + singleWaitTime: number | ||
24 | + isRemUnit: boolean | ||
25 | + isWatch: boolean | ||
26 | + delay: number | ||
27 | + ease: any | ||
28 | + count: number | ||
29 | + copyNum: number | ||
30 | + wheel: boolean | ||
31 | + singleLine: boolean | ||
32 | +} | ||
33 | + | ||
34 | +function useExpose(apis: Record<string, any>) { | ||
35 | + const instance = getCurrentInstance() | ||
36 | + if (instance) | ||
37 | + Object.assign(instance.proxy as Object, apis) | ||
38 | +} | ||
39 | + | ||
40 | +const Props = { | ||
41 | + // 是否开启自动滚动 | ||
42 | + modelValue: { | ||
43 | + type: Boolean, | ||
44 | + default: true, | ||
45 | + }, | ||
46 | + // 原始数据列表 | ||
47 | + list: { | ||
48 | + type: Array, | ||
49 | + required: true, | ||
50 | + default: [], | ||
51 | + }, | ||
52 | + // 步进速度,step 需是单步大小的约数 | ||
53 | + step: { | ||
54 | + type: Number, | ||
55 | + default: 1, | ||
56 | + }, | ||
57 | + // 开启滚动的数据量 | ||
58 | + limitScrollNum: { | ||
59 | + type: Number, | ||
60 | + default: 3, | ||
61 | + }, | ||
62 | + // 是否开启鼠标悬停 | ||
63 | + hover: { | ||
64 | + type: Boolean, | ||
65 | + default: false, | ||
66 | + }, | ||
67 | + // 控制滚动方向 | ||
68 | + direction: { | ||
69 | + type: String, | ||
70 | + default: 'up', | ||
71 | + }, | ||
72 | + // 单步运动停止的高度 | ||
73 | + singleHeight: { | ||
74 | + type: Number, | ||
75 | + default: 0, | ||
76 | + }, | ||
77 | + // 单步运动停止的宽度 | ||
78 | + singleWidth: { | ||
79 | + type: Number, | ||
80 | + default: 0, | ||
81 | + }, | ||
82 | + // 单步停止等待时间 (默认值 1000ms) | ||
83 | + singleWaitTime: { | ||
84 | + type: Number, | ||
85 | + default: 1000, | ||
86 | + }, | ||
87 | + // 是否开启 rem 度量 | ||
88 | + isRemUnit: { | ||
89 | + type: Boolean, | ||
90 | + default: false, | ||
91 | + }, | ||
92 | + // 开启数据更新监听 | ||
93 | + isWatch: { | ||
94 | + type: Boolean, | ||
95 | + default: true, | ||
96 | + }, | ||
97 | + // 动画时间 | ||
98 | + delay: { | ||
99 | + type: Number, | ||
100 | + default: 0, | ||
101 | + }, | ||
102 | + // 动画方式 | ||
103 | + ease: { | ||
104 | + type: [String, Object], | ||
105 | + default: 'ease-in', | ||
106 | + }, | ||
107 | + // 动画循环次数,-1 表示一直动画 | ||
108 | + count: { | ||
109 | + type: Number, | ||
110 | + default: -1, | ||
111 | + }, | ||
112 | + // 拷贝几份滚动列表 | ||
113 | + copyNum: { | ||
114 | + type: Number, | ||
115 | + default: 1, | ||
116 | + }, | ||
117 | + // 开启鼠标悬停时支持滚轮滚动 | ||
118 | + wheel: { | ||
119 | + type: Boolean, | ||
120 | + default: false, | ||
121 | + }, | ||
122 | + // 启用单行滚动 | ||
123 | + singleLine: { | ||
124 | + type: Boolean, | ||
125 | + default: false, | ||
126 | + }, | ||
127 | +} | ||
128 | + | ||
129 | +globalThis.window.cancelAnimationFrame = (function () { | ||
130 | + return ( | ||
131 | + globalThis.window.cancelAnimationFrame | ||
132 | + || function (id) { | ||
133 | + return globalThis.window.clearTimeout(id) | ||
134 | + } | ||
135 | + ) | ||
136 | +})() | ||
137 | +globalThis.window.requestAnimationFrame = (function () { | ||
138 | + return ( | ||
139 | + globalThis.window.requestAnimationFrame | ||
140 | + || function (callback) { | ||
141 | + return globalThis.window.setTimeout(callback, 1000 / 60) | ||
142 | + } | ||
143 | + ) | ||
144 | +})() | ||
145 | + | ||
146 | +function dataWarm(list: any[]) { | ||
147 | + if (list && typeof list !== 'boolean' && list.length > 100) { | ||
148 | + console.warn( | ||
149 | + `数据达到了${list.length}条有点多哦~,可能会造成部分老旧浏览器卡顿。`, | ||
150 | + ) | ||
151 | + } | ||
152 | +} | ||
153 | + | ||
154 | +const ScrollList = defineComponent({ | ||
155 | + name: 'ScrollList', | ||
156 | + inheritAttrs: false, | ||
157 | + props: Props, | ||
158 | + emits: ['stop', 'count', 'move'], | ||
159 | + setup(_props, { slots, emit, attrs }) { | ||
160 | + const props = _props as unknown as PropsType | ||
161 | + const scrollRef = ref(null) | ||
162 | + const slotListRef = ref<HTMLDivElement | null>(null) | ||
163 | + const realBoxRef = ref<HTMLDivElement | null>(null) | ||
164 | + const reqFrame = ref<number | null>(null) | ||
165 | + const singleWaitTimeout = ref<NodeJS.Timeout | null>(null) | ||
166 | + const realBoxWidth = ref(0) | ||
167 | + const realBoxHeight = ref(0) | ||
168 | + const xPos = ref(0) | ||
169 | + const yPos = ref(0) | ||
170 | + const isHover = ref(false) | ||
171 | + const _count = ref(0) | ||
172 | + | ||
173 | + const isScroll = computed(() => props.list ? (props.list.length >= props.limitScrollNum) : false) | ||
174 | + | ||
175 | + const realBoxStyle = computed(() => { | ||
176 | + return { | ||
177 | + width: realBoxWidth.value ? `${realBoxWidth.value}px` : 'auto', | ||
178 | + transform: `translate(${xPos.value}px,${yPos.value}px)`, | ||
179 | + | ||
180 | + transition: `all ${typeof props.ease === 'string' | ||
181 | + ? props.ease | ||
182 | + : `cubic-bezier(${ | ||
183 | + props.ease.x1 | ||
184 | + },${ | ||
185 | + props.ease.y1 | ||
186 | + },${ | ||
187 | + props.ease.x2 | ||
188 | + },${ | ||
189 | + props.ease.y2 | ||
190 | + })` | ||
191 | + } ${props.delay}ms`, | ||
192 | + overflow: 'hidden', | ||
193 | + display: props.singleLine ? 'flex' : 'block', | ||
194 | + } | ||
195 | + }) | ||
196 | + | ||
197 | + const isHorizontal = computed( | ||
198 | + () => props.direction === 'left' || props.direction === 'right', | ||
199 | + ) | ||
200 | + | ||
201 | + const floatStyle = computed<CSSProperties>(() => { | ||
202 | + return isHorizontal.value | ||
203 | + ? { | ||
204 | + float: 'left', | ||
205 | + overflow: 'hidden', | ||
206 | + display: props.singleLine ? 'flex' : 'block', | ||
207 | + flexShrink: props.singleLine ? 0 : 1, | ||
208 | + } | ||
209 | + : { overflow: 'hidden' } | ||
210 | + }) | ||
211 | + | ||
212 | + const baseFontSize = computed(() => { | ||
213 | + return props.isRemUnit | ||
214 | + ? parseInt( | ||
215 | + globalThis.window.getComputedStyle( | ||
216 | + globalThis.document.documentElement, | ||
217 | + null, | ||
218 | + ).fontSize, | ||
219 | + ) | ||
220 | + : 1 | ||
221 | + }) | ||
222 | + | ||
223 | + const realSingleStopWidth = computed( | ||
224 | + () => props.singleWidth * baseFontSize.value, | ||
225 | + ) | ||
226 | + | ||
227 | + const realSingleStopHeight = computed( | ||
228 | + () => props.singleHeight * baseFontSize.value, | ||
229 | + ) | ||
230 | + | ||
231 | + const step = computed(() => { | ||
232 | + let singleStep: number | ||
233 | + const _step = props.step | ||
234 | + if (isHorizontal.value) | ||
235 | + singleStep = realSingleStopWidth.value | ||
236 | + | ||
237 | + else | ||
238 | + singleStep = realSingleStopHeight.value | ||
239 | + | ||
240 | + if (singleStep > 0 && singleStep % _step > 0) { | ||
241 | + console.error( | ||
242 | + '如果设置了单步滚动, step 需是单步大小的约数,否则无法保证单步滚动结束的位置是否准确。~~~~~', | ||
243 | + ) | ||
244 | + } | ||
245 | + return _step | ||
246 | + }) | ||
247 | + | ||
248 | + const cancel = () => { | ||
249 | + cancelAnimationFrame(reqFrame.value as number) | ||
250 | + reqFrame.value = null | ||
251 | + } | ||
252 | + | ||
253 | + const animation = ( | ||
254 | + _direction: 'up' | 'down' | 'left' | 'right', | ||
255 | + _step: number, | ||
256 | + isWheel?: boolean, | ||
257 | + ) => { | ||
258 | + reqFrame.value = requestAnimationFrame(() => { | ||
259 | + const h = realBoxHeight.value / 2 | ||
260 | + const w = realBoxWidth.value / 2 | ||
261 | + if (_direction === 'up') { | ||
262 | + if (Math.abs(yPos.value) >= h) { | ||
263 | + yPos.value = 0 | ||
264 | + _count.value += 1 | ||
265 | + emit('count', _count.value) | ||
266 | + } | ||
267 | + yPos.value -= _step | ||
268 | + } | ||
269 | + else if (_direction === 'down') { | ||
270 | + if (yPos.value >= 0) { | ||
271 | + yPos.value = h * -1 | ||
272 | + _count.value += 1 | ||
273 | + emit('count', _count.value) | ||
274 | + } | ||
275 | + yPos.value += _step | ||
276 | + } | ||
277 | + else if (_direction === 'left') { | ||
278 | + if (Math.abs(xPos.value) >= w) { | ||
279 | + xPos.value = 0 | ||
280 | + _count.value += 1 | ||
281 | + emit('count', _count.value) | ||
282 | + } | ||
283 | + xPos.value -= _step | ||
284 | + } | ||
285 | + else if (_direction === 'right') { | ||
286 | + if (xPos.value >= 0) { | ||
287 | + xPos.value = w * -1 | ||
288 | + _count.value += 1 | ||
289 | + emit('count', _count.value) | ||
290 | + } | ||
291 | + xPos.value += _step | ||
292 | + } | ||
293 | + if (isWheel) | ||
294 | + return | ||
295 | + | ||
296 | + const { singleWaitTime } = props | ||
297 | + if (singleWaitTimeout.value) | ||
298 | + clearTimeout(singleWaitTimeout.value) | ||
299 | + | ||
300 | + if (realSingleStopHeight.value) { | ||
301 | + if (Math.abs(yPos.value) % realSingleStopHeight.value < _step) { | ||
302 | + singleWaitTimeout.value = setTimeout(() => { | ||
303 | + move() | ||
304 | + }, singleWaitTime) | ||
305 | + } | ||
306 | + else { | ||
307 | + move() | ||
308 | + } | ||
309 | + } | ||
310 | + else if (realSingleStopWidth.value) { | ||
311 | + if (Math.abs(xPos.value) % realSingleStopWidth.value < _step) { | ||
312 | + singleWaitTimeout.value = setTimeout(() => { | ||
313 | + move() | ||
314 | + }, singleWaitTime) | ||
315 | + } | ||
316 | + else { | ||
317 | + move() | ||
318 | + } | ||
319 | + } | ||
320 | + else { | ||
321 | + move() | ||
322 | + } | ||
323 | + }) | ||
324 | + } | ||
325 | + | ||
326 | + function move() { | ||
327 | + cancel() | ||
328 | + if (isHover.value || !isScroll.value || _count.value === props.count) { | ||
329 | + emit('stop', _count.value) | ||
330 | + _count.value = 0 | ||
331 | + return | ||
332 | + } | ||
333 | + animation( | ||
334 | + props.direction as 'up' | 'down' | 'left' | 'right', | ||
335 | + step.value, | ||
336 | + false, | ||
337 | + ) | ||
338 | + } | ||
339 | + | ||
340 | + const initMove = () => { | ||
341 | + dataWarm(props.list) | ||
342 | + if (isHorizontal.value) { | ||
343 | + let slotListWidth = (slotListRef.value as HTMLDivElement).offsetWidth | ||
344 | + slotListWidth = slotListWidth * 2 + 1 | ||
345 | + realBoxWidth.value = slotListWidth | ||
346 | + } | ||
347 | + | ||
348 | + if (isScroll.value) { | ||
349 | + realBoxHeight.value = (realBoxRef.value as HTMLDivElement).offsetHeight | ||
350 | + if (props.modelValue) | ||
351 | + move() | ||
352 | + } | ||
353 | + else { | ||
354 | + cancel() | ||
355 | + yPos.value = xPos.value = 0 | ||
356 | + } | ||
357 | + } | ||
358 | + | ||
359 | + const startMove = () => { | ||
360 | + isHover.value = false | ||
361 | + move() | ||
362 | + } | ||
363 | + | ||
364 | + const stopMove = () => { | ||
365 | + isHover.value = true | ||
366 | + if (singleWaitTimeout.value) | ||
367 | + clearTimeout(singleWaitTimeout.value) | ||
368 | + | ||
369 | + cancel() | ||
370 | + } | ||
371 | + | ||
372 | + const hoverStop = computed( | ||
373 | + () => props.hover && props.modelValue && isScroll.value, | ||
374 | + ) | ||
375 | + | ||
376 | + const throttleFunc = useThrottleFn((e: WheelEvent) => { | ||
377 | + cancel() | ||
378 | + const singleHeight = realSingleStopHeight.value | ||
379 | + ? realSingleStopHeight.value | ||
380 | + : 15 | ||
381 | + if (e.deltaY < 0) | ||
382 | + animation('down', singleHeight, true) | ||
383 | + | ||
384 | + if (e.deltaY > 0) | ||
385 | + animation('up', singleHeight, true) | ||
386 | + }, 30) | ||
387 | + | ||
388 | + const onWheel = (e: WheelEvent) => { | ||
389 | + throttleFunc(e) | ||
390 | + } | ||
391 | + | ||
392 | + const reset = () => { | ||
393 | + cancel() | ||
394 | + isHover.value = false | ||
395 | + initMove() | ||
396 | + } | ||
397 | + | ||
398 | + const Reset = () => { | ||
399 | + reset() | ||
400 | + } | ||
401 | + | ||
402 | + useExpose({ Reset }) | ||
403 | + | ||
404 | + watch( | ||
405 | + () => props.list, | ||
406 | + () => { | ||
407 | + if (props.isWatch) { | ||
408 | + nextTick(() => { | ||
409 | + reset() | ||
410 | + }) | ||
411 | + } | ||
412 | + }, | ||
413 | + { | ||
414 | + deep: true, | ||
415 | + }, | ||
416 | + ) | ||
417 | + | ||
418 | + watch( | ||
419 | + () => props.modelValue, | ||
420 | + (newValue) => { | ||
421 | + if (newValue) | ||
422 | + startMove() | ||
423 | + | ||
424 | + else | ||
425 | + stopMove() | ||
426 | + }, | ||
427 | + ) | ||
428 | + | ||
429 | + watch( | ||
430 | + () => props.count, | ||
431 | + (newValue) => { | ||
432 | + if (newValue !== 0) | ||
433 | + startMove() | ||
434 | + }, | ||
435 | + ) | ||
436 | + | ||
437 | + onBeforeMount(() => { | ||
438 | + cancel() | ||
439 | + clearTimeout(singleWaitTimeout.value as unknown as number) | ||
440 | + }) | ||
441 | + | ||
442 | + onMounted(() => { | ||
443 | + if (isScroll.value) | ||
444 | + initMove() | ||
445 | + }) | ||
446 | + | ||
447 | + const { default: $default, html } = slots | ||
448 | + const copyNum = new Array(props.copyNum).fill(null) | ||
449 | + | ||
450 | + const getHtml = () => { | ||
451 | + return ( | ||
452 | + <> | ||
453 | + <div ref={slotListRef} style={floatStyle.value}> | ||
454 | + {$default && $default()} | ||
455 | + </div> | ||
456 | + {isScroll.value | ||
457 | + ? copyNum.map(() => { | ||
458 | + if (html && typeof html === 'function') | ||
459 | + return <div style={floatStyle.value}>{html()}</div> | ||
460 | + | ||
461 | + else | ||
462 | + return <div style={floatStyle.value}>{$default && $default()}</div> | ||
463 | + }) | ||
464 | + : null} | ||
465 | + </> | ||
466 | + ) | ||
467 | + } | ||
468 | + | ||
469 | + return () => ( | ||
470 | + <div ref={scrollRef} class={attrs.class}> | ||
471 | + {props.wheel && props.hover | ||
472 | + ? ( | ||
473 | + <div | ||
474 | + ref={realBoxRef} | ||
475 | + style={realBoxStyle.value} | ||
476 | + onMouseenter={() => { | ||
477 | + if (hoverStop.value) | ||
478 | + stopMove() | ||
479 | + }} | ||
480 | + onMouseleave={() => { | ||
481 | + if (hoverStop.value) | ||
482 | + startMove() | ||
483 | + }} | ||
484 | + onWheel={(e) => { | ||
485 | + if (hoverStop.value) | ||
486 | + onWheel(e) | ||
487 | + }} | ||
488 | + > | ||
489 | + {getHtml()} | ||
490 | + </div> | ||
491 | + ) | ||
492 | + : ( | ||
493 | + <div | ||
494 | + ref={realBoxRef} | ||
495 | + style={realBoxStyle.value} | ||
496 | + onMouseenter={() => { | ||
497 | + if (hoverStop.value) | ||
498 | + stopMove() | ||
499 | + }} | ||
500 | + onMouseleave={() => { | ||
501 | + if (hoverStop.value) | ||
502 | + startMove() | ||
503 | + }} | ||
504 | + > | ||
505 | + {getHtml()} | ||
506 | + </div> | ||
507 | + )} | ||
508 | + </div> | ||
509 | + ) | ||
510 | + }, | ||
511 | +}) | ||
512 | + | ||
513 | +export default ScrollList | ||
514 | + | ||
515 | +export { ScrollList } |
@@ -8,7 +8,7 @@ import { ComponentEnum } from '@/components/Form/src/enum' | @@ -8,7 +8,7 @@ import { ComponentEnum } from '@/components/Form/src/enum' | ||
8 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' | 8 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' |
9 | import { DateFormatEnum } from '@/enums/timeEnum' | 9 | import { DateFormatEnum } from '@/enums/timeEnum' |
10 | import type { BasicColumn } from '@/components/Table' | 10 | import type { BasicColumn } from '@/components/Table' |
11 | -import type { CodeTypeEnum, ContentDataFieldsEnum } from '@/enums/datasource' | 11 | +import { AlarmStatusEnum, type CodeTypeEnum, type ContentDataFieldsEnum } from '@/enums/datasource' |
12 | 12 | ||
13 | const contentDataStore = useContentDataStoreWithOut() | 13 | const contentDataStore = useContentDataStoreWithOut() |
14 | 14 | ||
@@ -31,37 +31,12 @@ export interface TableRecordItemType { | @@ -31,37 +31,12 @@ export interface TableRecordItemType { | ||
31 | [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<CodeTypeEnum> | 31 | [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<CodeTypeEnum> |
32 | } | 32 | } |
33 | 33 | ||
34 | -// 告警状态 | ||
35 | -export const alarmStatus = [ | ||
36 | - { | ||
37 | - label: '清除未确认', | ||
38 | - value: 'CLEARED_UNACK', | ||
39 | - color: 'red', | ||
40 | - }, | ||
41 | - { | ||
42 | - label: '激活未确认', | ||
43 | - value: 'ACTIVE_UNACK', | ||
44 | - color: 'orange', | ||
45 | - }, | ||
46 | - { | ||
47 | - label: '清除已确认', | ||
48 | - value: 'CLEARED_ACK', | ||
49 | - color: 'cyan', | ||
50 | - }, | ||
51 | - { | ||
52 | - label: '激活已确认', | ||
53 | - value: 'ACTIVE_ACK', | ||
54 | - color: 'green', | ||
55 | - }, | ||
56 | -] | ||
57 | - | ||
58 | -export interface alarmListInterface { | ||
59 | - deviceName: string | ||
60 | - deviceAlias: string | ||
61 | - status: string | ||
62 | - startTs: string | 34 | +export const AlarmColorMap = { |
35 | + [AlarmStatusEnum.CLEARED_UN_ACK]: 'red', | ||
36 | + [AlarmStatusEnum.ACTIVE_UN_ACK]: 'orange', | ||
37 | + [AlarmStatusEnum.CLEARED_ACK]: 'cyan', | ||
38 | + [AlarmStatusEnum.ACTIVE_ACK]: 'green', | ||
63 | } | 39 | } |
64 | - | ||
65 | /** | 40 | /** |
66 | * 告警列表相关枚举 | 41 | * 告警列表相关枚举 |
67 | */ | 42 | */ |
1 | <script setup lang="ts"> | 1 | <script setup lang="ts"> |
2 | import { computed, nextTick, onMounted, reactive, unref } from 'vue' | 2 | import { computed, nextTick, onMounted, reactive, unref } from 'vue' |
3 | import { Divider, Tag } from 'ant-design-vue' | 3 | import { Divider, Tag } from 'ant-design-vue' |
4 | -import Vue3SeamlessScroll from 'vue3-seamless-scroll/package/Vue3SeamlessScroll' | ||
5 | -import { useAlarmList } from './useAlarmList.hook' | ||
6 | -import { type alarmListInterface, alarmStatus } from './form.config' | 4 | +import { ScrollList } from './ScrollList' |
7 | import { fetchAlarmList } from '@/api/alarm' | 5 | import { fetchAlarmList } from '@/api/alarm' |
6 | +import type { AlarmListItemType } from '@/api/alarm/model' | ||
8 | import type { CreateComponentType } from '@/core/Library/types' | 7 | import type { CreateComponentType } from '@/core/Library/types' |
9 | import { useContentDataStore } from '@/store/modules/contentData' | 8 | import { useContentDataStore } from '@/store/modules/contentData' |
10 | import { isLightboxMode } from '@/utils/env' | 9 | import { isLightboxMode } from '@/utils/env' |
10 | +import { AlarmStatusColorEnum, AlarmStatusEnum, AlarmStatusNameEnum } from '@/enums/datasource' | ||
11 | import { formatToDateTime } from '@/utils/dateUtil' | 11 | import { formatToDateTime } from '@/utils/dateUtil' |
12 | 12 | ||
13 | const props = defineProps<{ | 13 | const props = defineProps<{ |
@@ -20,10 +20,8 @@ const getCellBounds = computed( | @@ -20,10 +20,8 @@ const getCellBounds = computed( | ||
20 | 20 | ||
21 | const contentDataStore = useContentDataStore() | 21 | const contentDataStore = useContentDataStore() |
22 | 22 | ||
23 | -const { byStatusFindLabel } = useAlarmList() | ||
24 | - | ||
25 | const initOptions = reactive<{ | 23 | const initOptions = reactive<{ |
26 | - alarmList: alarmListInterface[] | 24 | + alarmList: AlarmListItemType[] |
27 | scroll: boolean | 25 | scroll: boolean |
28 | interval: number | 26 | interval: number |
29 | polling: number | 27 | polling: number |
@@ -72,6 +70,7 @@ onMounted(async () => { | @@ -72,6 +70,7 @@ onMounted(async () => { | ||
72 | setInterval(initFetchAlarmList, initOptions.polling * 1000) | 70 | setInterval(initFetchAlarmList, initOptions.polling * 1000) |
73 | } | 71 | } |
74 | else { | 72 | else { |
73 | + const statusList = Object.values(AlarmStatusEnum) | ||
75 | Object.assign(initOptions, { | 74 | Object.assign(initOptions, { |
76 | scroll: false, | 75 | scroll: false, |
77 | interval: 0, | 76 | interval: 0, |
@@ -80,9 +79,7 @@ onMounted(async () => { | @@ -80,9 +79,7 @@ onMounted(async () => { | ||
80 | deviceName: `示例设备${index + 1}`, | 79 | deviceName: `示例设备${index + 1}`, |
81 | deviceAlias: `示例设备${index + 1}`, | 80 | deviceAlias: `示例设备${index + 1}`, |
82 | startTs: formatToDateTime(), | 81 | startTs: formatToDateTime(), |
83 | - status: alarmStatus.map(item => item.value)[ | ||
84 | - Math.floor(Math.random() * alarmStatus.length) | ||
85 | - ], | 82 | + status: statusList[index % 4], |
86 | })), | 83 | })), |
87 | }) | 84 | }) |
88 | } | 85 | } |
@@ -91,26 +88,28 @@ onMounted(async () => { | @@ -91,26 +88,28 @@ onMounted(async () => { | ||
91 | 88 | ||
92 | <template> | 89 | <template> |
93 | <div class="seamless-scroll w-full h-full flex justify-center items-center overflow-y-scroll"> | 90 | <div class="seamless-scroll w-full h-full flex justify-center items-center overflow-y-scroll"> |
94 | - <Vue3SeamlessScroll | ||
95 | - v-model="initOptions.scroll" :single-wait-time="initOptions.interval" | ||
96 | - :list="initOptions.alarmList" :limit-scroll-num="10" :is-rem-unit="true" :delay="10" :wheel="true" hover :style="{ | 91 | + <ScrollList |
92 | + v-model="initOptions.scroll" :single-wait-time="initOptions.interval" :list="initOptions.alarmList" | ||
93 | + :limit-scroll-num="10" :is-rem-unit="true" :delay="10" :wheel="true" hover :style="{ | ||
97 | width: `${getCellBounds.width}px`, | 94 | width: `${getCellBounds.width}px`, |
98 | height: `${getCellBounds.height}px`, | 95 | height: `${getCellBounds.height}px`, |
99 | }" | 96 | }" |
100 | > | 97 | > |
101 | <div v-for="(item, index) in initOptions.alarmList" :key="index" class="flex flex-col items-start h-15 px-2"> | 98 | <div v-for="(item, index) in initOptions.alarmList" :key="index" class="flex flex-col items-start h-15 px-2"> |
102 | <p class="text-xs"> | 99 | <p class="text-xs"> |
103 | - 设备:{{ item.deviceAlias || item.deviceName }} | 100 | + <span>设备:</span> |
101 | + <span class="ml-1">{{ item.deviceAlias || item.deviceName }}</span> | ||
104 | </p> | 102 | </p> |
105 | - <div class="flex items-center justify-between -mt-2"> | ||
106 | - <span class="text-xs">时间:{{ item.startTs }}</span> | ||
107 | - <Tag class="ml-2 text-xs" :color="byStatusFindLabel(item.status, 'color')"> | ||
108 | - {{ byStatusFindLabel(item.status, "") }} | 103 | + <div class="flex items-center justify-between -mt-2 text-xs"> |
104 | + <span>时间:</span> | ||
105 | + <span class="ml-1">{{ item.startTs }}</span> | ||
106 | + <Tag class="ml-2" :color="AlarmStatusColorEnum[item.status]"> | ||
107 | + {{ AlarmStatusNameEnum[item.status] }} | ||
109 | </Tag> | 108 | </Tag> |
110 | </div> | 109 | </div> |
111 | <Divider class="mt-2 divider" /> | 110 | <Divider class="mt-2 divider" /> |
112 | </div> | 111 | </div> |
113 | - </Vue3SeamlessScroll> | 112 | + </ScrollList> |
114 | </div> | 113 | </div> |
115 | </template> | 114 | </template> |
116 | 115 |
src/core/Library/packages/Basic/AlarmList/useAlarmList.hook.ts
deleted
100644 → 0
1 | -import { alarmStatus } from './form.config' | ||
2 | - | ||
3 | -export const useAlarmList = () => { | ||
4 | - // 映射label | ||
5 | - const byStatusFindLabel = (status: string, color: string) => { | ||
6 | - if (!color) return alarmStatus.find(item => item.value === status)?.label | ||
7 | - return alarmStatus.find(item => item.value === status)?.color | ||
8 | - } | ||
9 | - return { | ||
10 | - byStatusFindLabel, | ||
11 | - } | ||
12 | -} |
@@ -335,3 +335,25 @@ export enum SocketSubscriberEnum { | @@ -335,3 +335,25 @@ export enum SocketSubscriberEnum { | ||
335 | TS_SUB_CMDS = 'tsSubCmds', | 335 | TS_SUB_CMDS = 'tsSubCmds', |
336 | HISTORY_CMDS = 'historyCmds', | 336 | HISTORY_CMDS = 'historyCmds', |
337 | } | 337 | } |
338 | + | ||
339 | +export enum AlarmStatusEnum { | ||
340 | + CLEARED_UN_ACK = 'CLEARED_UNACK', | ||
341 | + ACTIVE_UN_ACK = 'ACTIVE_UNACK', | ||
342 | + CLEARED_ACK = 'CLEARED_ACK', | ||
343 | + ACTIVE_ACK = 'ACTIVE_ACK', | ||
344 | +} | ||
345 | + | ||
346 | +export enum AlarmStatusColorEnum { | ||
347 | + CLEARED_UNACK = 'red', | ||
348 | + ACTIVE_UNACK = 'orange', | ||
349 | + CLEARED_ACK = 'cyan', | ||
350 | + ACTIVE_ACK = 'green', | ||
351 | +} | ||
352 | + | ||
353 | +export enum AlarmStatusNameEnum { | ||
354 | + CLEARED_UNACK = '清除未确认', | ||
355 | + ACTIVE_UNACK = '激活未确认', | ||
356 | + CLEARED_ACK = '清除已确认', | ||
357 | + ACTIVE_ACK = '激活已确认', | ||
358 | +} | ||
359 | + |
@@ -18,6 +18,39 @@ export type MxState = mxgraph.mxCellState | @@ -18,6 +18,39 @@ export type MxState = mxgraph.mxCellState | ||
18 | 18 | ||
19 | export type MxEditor = mxgraph.mxEditor | 19 | export type MxEditor = mxgraph.mxEditor |
20 | 20 | ||
21 | +export enum EnableEnum { | ||
22 | + ENABLE = 1, | ||
23 | + CLOSE = 0, | ||
24 | +} | ||
25 | + | ||
26 | +export enum GradientDirectionEnum { | ||
27 | + WEST = 'west', | ||
28 | + NORTH = 'north', | ||
29 | + EAST = 'east', | ||
30 | + SOUTH = 'south', | ||
31 | + RADIAL = 'radial', | ||
32 | +} | ||
33 | + | ||
34 | +export interface MxShapeStyleType { | ||
35 | + align: 'center' | ||
36 | + dashed: EnableEnum | ||
37 | + fillColor: string | ||
38 | + fontColor: string | ||
39 | + fontFamily: string | ||
40 | + fontSize: number | ||
41 | + gradientColor: string | ||
42 | + gradientDirection: GradientDirectionEnum | ||
43 | + opacity: number | ||
44 | + shadow: EnableEnum | ||
45 | + strokeColor: string | ||
46 | + // fillStyle: | ||
47 | + /** | ||
48 | + * @description 草图模式 | ||
49 | + */ | ||
50 | + sketch: EnableEnum | ||
51 | + strokeWidth: number | ||
52 | +} | ||
53 | + | ||
21 | interface Entries { | 54 | interface Entries { |
22 | title: string | 55 | title: string |
23 | key?: string | 56 | key?: string |