@qilitt-mickey/vue3-temp-skill 1.0.12 → 1.1.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 (42) hide show
  1. package/README.md +66 -214
  2. package/SKILL.md +165 -527
  3. package/package.json +2 -2
  4. package/references/api-check.md +187 -128
  5. package/references/base-code-dict.md +49 -48
  6. package/references/chart-echarts.md +61 -0
  7. package/references/code-quality.md +44 -15
  8. package/references/core-kernel.md +305 -0
  9. package/references/crud-pages.md +87 -261
  10. package/references/data-compare.md +502 -501
  11. package/references/data-mapping.md +218 -213
  12. package/references/data-screen.md +94 -79
  13. package/references/data-writeback.md +104 -104
  14. package/references/detail-page.md +100 -99
  15. package/references/directives-advanced.md +27 -4
  16. package/references/download-export.md +70 -68
  17. package/references/feedback-loading.md +62 -60
  18. package/references/feedback-ui.md +125 -111
  19. package/references/file-management.md +28 -7
  20. package/references/flowchart-g6.md +249 -244
  21. package/references/form-advanced.md +264 -26
  22. package/references/graph-relation.md +12 -7
  23. package/references/http-api.md +138 -103
  24. package/references/icons.md +326 -0
  25. package/references/layout-theme.md +1 -1
  26. package/references/mobile-h5.md +20 -0
  27. package/references/particles.md +143 -0
  28. package/references/permission-auth.md +8 -31
  29. package/references/project-inventory.md +175 -120
  30. package/references/qrcode-barcode.md +107 -92
  31. package/references/rich-text.md +85 -73
  32. package/references/seamless-scroll.md +40 -38
  33. package/references/table-vxe.md +114 -0
  34. package/references/tree-table.md +2 -1
  35. package/references/ui-components.md +5 -1
  36. package/references/verify-captcha.md +110 -96
  37. package/references/websocket-realtime.md +2 -1
  38. package/references/wechat-js.md +58 -0
  39. package/references/workflow-bpmn.md +207 -206
  40. package/references/advanced-ui.md +0 -302
  41. package/references/build-optim.md +0 -282
  42. package/references/vue-core.md +0 -209
@@ -1,244 +1,249 @@
1
- # G6 流程图(@antv/g6 v5)
2
-
3
- ## 依赖
4
-
5
- `@antv/g6` v5 + `g6-extension-vue` — 支持在节点中渲染 Vue 组件的图可视化引擎。大体积依赖已单独拆包为 `antv-g6` / `antv-vendor`。
6
-
7
- ## 组件结构
8
-
9
- ```vue
10
- <!-- src/views/workflow/components/G6Flow.vue -->
11
- <script setup lang="tsx">
12
- import { ExtensionCategory, register, treeToGraphData } from '@antv/g6'
13
- import { useResizeObserver } from '@vueuse/core'
14
- import { VueNode } from 'g6-extension-vue'
15
- import { getG6WorkflowData } from '@/api/common'
16
- import { useApp } from '@/hooks/useApp'
17
-
18
- defineOptions({ name: 'G6Flow' })
19
-
20
- const props = withDefaults(defineProps<{
21
- nodeWidth?: number
22
- nodeHeight?: number
23
- getHGap?: number
24
- getVGap?: number
25
- resize?: boolean
26
- fitCenterOnResize?: boolean
27
- onBizClick?: (id: string) => void
28
- onNodeClick?: (id: string) => void
29
- }>(), {
30
- nodeWidth: 260,
31
- nodeHeight: 190,
32
- hGap: 80,
33
- getVGap: 80,
34
- resize: true,
35
- fitCenterOnResize: true,
36
- })
37
-
38
- const containerRef = ref<HTMLElement>()
39
- const treeData = ref<any>(null)
40
- const loading = ref(false)
41
- const { svgLoading } = useApp()
42
- let graph: any = null
43
- </script>
44
- ```
45
-
46
- ## 初始化图实例
47
-
48
- ```typescript
49
- const initGraph = async () => {
50
- if (!containerRef.value) return
51
- const { Graph } = await import('@antv/g6')
52
- register(ExtensionCategory.NODE, 'vue-node', VueNode)
53
-
54
- // 定义 Vue 节点组件
55
- const FlowNodeComp = defineComponent({
56
- name: 'FlowNodeComp',
57
- props: ['treeData'],
58
- setup(p: any) {
59
- const nodeData = computed(() => p.treeData)
60
- const isSelected = computed(() =>
61
- Array.isArray(p.treeData?.states) && p.treeData.states.includes('selected')
62
- )
63
-
64
- function handleNodeClick(e: Event) {
65
- e.preventDefault()
66
- e.stopPropagation()
67
- const id = nodeData.value?.id
68
- if (!id || !graph) return
69
- // 切换选中状态
70
- const data = graph.getData?.() || {}
71
- data.nodes.forEach((n: any) => {
72
- graph.setElementState?.(n.id, n.id === id ? ['selected'] : [])
73
- })
74
- // 展开/折叠
75
- const current = data.nodes.find((n: any) => n.id === id)
76
- if (current?.collapsed) {
77
- graph.expandElement?.(id, { animation: false })
78
- current.collapsed = false
79
- } else {
80
- graph.collapseElement?.(id, { animation: false })
81
- current.collapsed = true
82
- }
83
- }
84
-
85
- return () => (
86
- <div style={{
87
- width: `${props.nodeWidth}px`, height: `${props.nodeHeight}px`,
88
- border: '2px solid', borderColor: isSelected.value ? 'red' : '#9DC5EA',
89
- borderRadius: '8px', background: '#EAF4FF', cursor: 'pointer',
90
- }} onClick={handleNodeClick}>
91
- <div style={{ background: '#CFE7FF', padding: '8px', fontWeight: 600 }}>
92
- {nodeData.value?.title ?? ''}
93
- </div>
94
- <div style={{ padding: '8px' }}>
95
- <div>业务号:{nodeData.value?.caseNo ?? ''}</div>
96
- <div>{nodeData.value?.handler ?? ''}</div>
97
- <div style={{ color: '#409eff' }}>状态:{nodeData.value?.status ?? ''}</div>
98
- </div>
99
- </div>
100
- )
101
- },
102
- })
103
-
104
- graph = new Graph({
105
- container: containerRef.value,
106
- width: containerRef.value.clientWidth || 800,
107
- height: containerRef.value.clientHeight || 600,
108
- autoFit: 'view',
109
- behaviors: ['drag-canvas', 'zoom-canvas'],
110
- node: {
111
- type: 'vue-node',
112
- style: {
113
- component: d => <FlowNodeComp treeData={Object.assign({}, d)} />,
114
- size: [props.nodeWidth, props.nodeHeight],
115
- ports: [
116
- { key: 'top', placement: 'top' },
117
- { key: 'bottom', placement: 'bottom' },
118
- ],
119
- cursor: 'pointer',
120
- },
121
- animation: { enter: false },
122
- },
123
- edge: { type: 'line', style: { stroke: '#9DC5EA' }, animation: { enter: false } },
124
- layout: {
125
- type: 'compact-box',
126
- direction: 'TB',
127
- getHeight: () => props.nodeHeight,
128
- getWidth: () => props.nodeWidth,
129
- getVGap: () => props.getVGap,
130
- getHGap: () => props.getHGap,
131
- },
132
- })
133
-
134
- // 点击画布取消选中
135
- graph.on('canvas:click', () => {
136
- const data = graph.getData?.() || {}
137
- data.nodes?.forEach((n: any) => graph.setElementState?.(n.id, []))
138
- })
139
- }
140
- ```
141
-
142
- ## 数据加载与渲染
143
-
144
- ```typescript
145
- const setGraphData = () => {
146
- if (!graph || !treeData.value) return
147
- const graphData = treeToGraphData(treeData.value) // 树结构 → 图数据
148
- graph.setData(graphData)
149
- graph.render()
150
- graph.fitView?.() // 缩放至合适大小并居中
151
- }
152
-
153
- const loadData = async () => {
154
- loading.value = true
155
- const { data } = await getG6WorkflowData()
156
- treeData.value = data
157
- setGraphData()
158
- loading.value = false
159
- }
160
- ```
161
-
162
- ## 缩放控制
163
-
164
- ```typescript
165
- const handleZoomIn = () => {
166
- if (!graph) return
167
- const current = graph.getZoom?.() ?? 1
168
- graph.zoomTo?.(current + 0.1)
169
- }
170
- const handleZoomOut = () => {
171
- if (!graph) return
172
- const current = graph.getZoom?.() ?? 1
173
- graph.zoomTo?.(Math.max(0.1, current - 0.1))
174
- }
175
- const handleFitView = () => {
176
- if (!graph) return
177
- graph.fitView?.()
178
- }
179
- ```
180
-
181
- ## 响应式尺寸
182
-
183
- ```typescript
184
- const resize = () => {
185
- if (!graph || !containerRef.value || !props.resize) return
186
- const w = containerRef.value.clientWidth
187
- const h = containerRef.value.clientHeight
188
- graph.resize(w, h)
189
- if (props.fitCenterOnResize) {
190
- graph.render()
191
- graph.fitView?.()
192
- }
193
- }
194
- useResizeObserver(containerRef, () => resize())
195
- ```
196
-
197
- ## 生命周期
198
-
199
- ```typescript
200
- onMounted(async () => {
201
- await initGraph()
202
- await loadData()
203
- })
204
-
205
- onBeforeUnmount(() => {
206
- graph?.destroy?.()
207
- graph = null
208
- })
209
-
210
- defineExpose({ getInstance: () => graph })
211
- ```
212
-
213
- ## 页面用法
214
-
215
- ```vue
216
- <!-- src/views/workflow/g6/index.vue -->
217
- <template>
218
- <div :style="{ height: `calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)` }"
219
- class="pos-relative bg-[#fff] p-5 overflow-hidden">
220
- <div class="toolbar">
221
- <el-alert title="antv/g6流程图展示" type="info" :closable="false" />
222
- </div>
223
- <div class="g6-container">
224
- <G6Flow ref="flowRef" :node-width="260" :node-height="190" :get-v-gap="80" :get-h-gap="80" />
225
- </div>
226
- </div>
227
- </template>
228
- ```
229
-
230
- ## 关键约定
231
-
232
- 1. G6 5.x 必须配合 `g6-extension-vue` 才能在节点中渲染 Vue 组件。
233
- 2. `@antv/g6` 使用动态 `import()` 按需加载,避免首屏性能问题。
234
- 3. 布局使用 `compact-box`(紧凑树盒布局),方向 `TB`(从上到下)。
235
- 4. 图容器必须有明确宽高,否则初始化失败。
236
- 5. `onBeforeUnmount` 中必须调用 `graph.destroy()` 释放资源。
237
- 6. `treeToGraphData` 将树结构转为 G6 图数据格式。
238
- 7. 节点选中状态通过 `setElementState` 管理,CSS 通过 `states` 属性判断。
239
-
240
- ## 关联文件
241
-
242
- - [src/views/workflow/g6/index.vue](file:///e:/work/vue3-web-temp/src/views/workflow/g6/index.vue)
243
- - [src/views/workflow/components/G6Flow.vue](file:///e:/work/vue3-web-temp/src/views/workflow/components/G6Flow.vue)
244
- - [src/api/common.ts](file:///e:/work/vue3-web-temp/src/api/common.ts)
1
+ # G6 流程图(@antv/g6 v5)
2
+
3
+ > 按本文件示例编写;必须使用选型表中的 `@antv/g6`(见 project-inventory),勿改用同类其他流程图库;新依赖须待确认。
4
+
5
+ ## 依赖(缺则先装)
6
+
7
+ | 包 | 版本 |
8
+ |---|---|
9
+ | `@antv/g6` | `5.1.1` |
10
+ | `g6-extension-vue` | `0.1.0` |
11
+
12
+ ```bash
13
+ pnpm add @antv/g6@5.1.1 g6-extension-vue@0.1.0
14
+ ```
15
+
16
+ 大体积依赖模板侧已拆包为 `antv-g6` / `antv-vendor`。支持在节点中渲染 Vue 组件。
17
+
18
+ ## 组件结构
19
+
20
+ ```vue
21
+ <!-- G6Flow.vue -->
22
+ <script setup lang="tsx">
23
+ import { ExtensionCategory, register, treeToGraphData } from '@antv/g6'
24
+ import { useResizeObserver } from '@vueuse/core'
25
+ import { VueNode } from 'g6-extension-vue'
26
+ import { getG6WorkflowData } from '@/api/common'
27
+ import { useApp } from '@/hooks/useApp'
28
+
29
+ defineOptions({ name: 'G6Flow' })
30
+
31
+ const props = withDefaults(defineProps<{
32
+ nodeWidth?: number
33
+ nodeHeight?: number
34
+ getHGap?: number
35
+ getVGap?: number
36
+ resize?: boolean
37
+ fitCenterOnResize?: boolean
38
+ onBizClick?: (id: string) => void
39
+ onNodeClick?: (id: string) => void
40
+ }>(), {
41
+ nodeWidth: 260,
42
+ nodeHeight: 190,
43
+ hGap: 80,
44
+ getVGap: 80,
45
+ resize: true,
46
+ fitCenterOnResize: true,
47
+ })
48
+
49
+ const containerRef = ref<HTMLElement>()
50
+ const treeData = ref<any>(null)
51
+ const loading = ref(false)
52
+ const { svgLoading } = useApp()
53
+ let graph: any = null
54
+ </script>
55
+ ```
56
+
57
+ ## 初始化图实例
58
+
59
+ ```typescript
60
+ const initGraph = async () => {
61
+ if (!containerRef.value) return
62
+ const { Graph } = await import('@antv/g6')
63
+ register(ExtensionCategory.NODE, 'vue-node', VueNode)
64
+
65
+ // 定义 Vue 节点组件
66
+ const FlowNodeComp = defineComponent({
67
+ name: 'FlowNodeComp',
68
+ props: ['treeData'],
69
+ setup(p: any) {
70
+ const nodeData = computed(() => p.treeData)
71
+ const isSelected = computed(() =>
72
+ Array.isArray(p.treeData?.states) && p.treeData.states.includes('selected')
73
+ )
74
+
75
+ function handleNodeClick(e: Event) {
76
+ e.preventDefault()
77
+ e.stopPropagation()
78
+ const id = nodeData.value?.id
79
+ if (!id || !graph) return
80
+ // 切换选中状态
81
+ const data = graph.getData?.() || {}
82
+ data.nodes.forEach((n: any) => {
83
+ graph.setElementState?.(n.id, n.id === id ? ['selected'] : [])
84
+ })
85
+ // 展开/折叠
86
+ const current = data.nodes.find((n: any) => n.id === id)
87
+ if (current?.collapsed) {
88
+ graph.expandElement?.(id, { animation: false })
89
+ current.collapsed = false
90
+ } else {
91
+ graph.collapseElement?.(id, { animation: false })
92
+ current.collapsed = true
93
+ }
94
+ }
95
+
96
+ return () => (
97
+ <div style={{
98
+ width: `${props.nodeWidth}px`, height: `${props.nodeHeight}px`,
99
+ border: '2px solid', borderColor: isSelected.value ? 'red' : '#9DC5EA',
100
+ borderRadius: '8px', background: '#EAF4FF', cursor: 'pointer',
101
+ }} onClick={handleNodeClick}>
102
+ <div style={{ background: '#CFE7FF', padding: '8px', fontWeight: 600 }}>
103
+ {nodeData.value?.title ?? ''}
104
+ </div>
105
+ <div style={{ padding: '8px' }}>
106
+ <div>业务号:{nodeData.value?.caseNo ?? ''}</div>
107
+ <div>{nodeData.value?.handler ?? ''}</div>
108
+ <div style={{ color: '#409eff' }}>状态:{nodeData.value?.status ?? ''}</div>
109
+ </div>
110
+ </div>
111
+ )
112
+ },
113
+ })
114
+
115
+ graph = new Graph({
116
+ container: containerRef.value,
117
+ width: containerRef.value.clientWidth || 800,
118
+ height: containerRef.value.clientHeight || 600,
119
+ autoFit: 'view',
120
+ behaviors: ['drag-canvas', 'zoom-canvas'],
121
+ node: {
122
+ type: 'vue-node',
123
+ style: {
124
+ component: d => <FlowNodeComp treeData={Object.assign({}, d)} />,
125
+ size: [props.nodeWidth, props.nodeHeight],
126
+ ports: [
127
+ { key: 'top', placement: 'top' },
128
+ { key: 'bottom', placement: 'bottom' },
129
+ ],
130
+ cursor: 'pointer',
131
+ },
132
+ animation: { enter: false },
133
+ },
134
+ edge: { type: 'line', style: { stroke: '#9DC5EA' }, animation: { enter: false } },
135
+ layout: {
136
+ type: 'compact-box',
137
+ direction: 'TB',
138
+ getHeight: () => props.nodeHeight,
139
+ getWidth: () => props.nodeWidth,
140
+ getVGap: () => props.getVGap,
141
+ getHGap: () => props.getHGap,
142
+ },
143
+ })
144
+
145
+ // 点击画布取消选中
146
+ graph.on('canvas:click', () => {
147
+ const data = graph.getData?.() || {}
148
+ data.nodes?.forEach((n: any) => graph.setElementState?.(n.id, []))
149
+ })
150
+ }
151
+ ```
152
+
153
+ ## 数据加载与渲染
154
+
155
+ ```typescript
156
+ const setGraphData = () => {
157
+ if (!graph || !treeData.value) return
158
+ const graphData = treeToGraphData(treeData.value) // 树结构 → 图数据
159
+ graph.setData(graphData)
160
+ graph.render()
161
+ graph.fitView?.() // 缩放至合适大小并居中
162
+ }
163
+
164
+ const loadData = async () => {
165
+ loading.value = true
166
+ const { data } = await getG6WorkflowData()
167
+ treeData.value = data
168
+ setGraphData()
169
+ loading.value = false
170
+ }
171
+ ```
172
+
173
+ ## 缩放控制
174
+
175
+ ```typescript
176
+ const handleZoomIn = () => {
177
+ if (!graph) return
178
+ const current = graph.getZoom?.() ?? 1
179
+ graph.zoomTo?.(current + 0.1)
180
+ }
181
+ const handleZoomOut = () => {
182
+ if (!graph) return
183
+ const current = graph.getZoom?.() ?? 1
184
+ graph.zoomTo?.(Math.max(0.1, current - 0.1))
185
+ }
186
+ const handleFitView = () => {
187
+ if (!graph) return
188
+ graph.fitView?.()
189
+ }
190
+ ```
191
+
192
+ ## 响应式尺寸
193
+
194
+ ```typescript
195
+ const resize = () => {
196
+ if (!graph || !containerRef.value || !props.resize) return
197
+ const w = containerRef.value.clientWidth
198
+ const h = containerRef.value.clientHeight
199
+ graph.resize(w, h)
200
+ if (props.fitCenterOnResize) {
201
+ graph.render()
202
+ graph.fitView?.()
203
+ }
204
+ }
205
+ useResizeObserver(containerRef, () => resize())
206
+ ```
207
+
208
+ ## 生命周期
209
+
210
+ ```typescript
211
+ onMounted(async () => {
212
+ await initGraph()
213
+ await loadData()
214
+ })
215
+
216
+ onBeforeUnmount(() => {
217
+ graph?.destroy?.()
218
+ graph = null
219
+ })
220
+
221
+ defineExpose({ getInstance: () => graph })
222
+ ```
223
+
224
+ ## 页面用法
225
+
226
+ ```vue
227
+ <!-- g6 页面示例 -->
228
+ <template>
229
+ <div :style="{ height: `calc(100vh - 2 * var(--vts-margin) - ${headerHeight}px)` }"
230
+ class="pos-relative bg-[#fff] p-5 overflow-hidden">
231
+ <div class="toolbar">
232
+ <el-alert title="antv/g6流程图展示" type="info" :closable="false" />
233
+ </div>
234
+ <div class="g6-container">
235
+ <G6Flow ref="flowRef" :node-width="260" :node-height="190" :get-v-gap="80" :get-h-gap="80" />
236
+ </div>
237
+ </div>
238
+ </template>
239
+ ```
240
+
241
+ ## 关键约定
242
+
243
+ 1. G6 5.x 必须配合 `g6-extension-vue` 才能在节点中渲染 Vue 组件。
244
+ 2. `@antv/g6` 使用动态 `import()` 按需加载,避免首屏性能问题。
245
+ 3. 布局使用 `compact-box`(紧凑树盒布局),方向 `TB`(从上到下)。
246
+ 4. 图容器必须有明确宽高,否则初始化失败。
247
+ 5. `onBeforeUnmount` 中必须调用 `graph.destroy()` 释放资源。
248
+ 6. `treeToGraphData` 将树结构转为 G6 图数据格式。
249
+ 7. 节点选中状态通过 `setElementState` 管理,CSS 通过 `states` 属性判断。