@qilitt-mickey/vue3-temp-skill 1.0.8

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 (37) hide show
  1. package/README.md +229 -0
  2. package/SKILL.md +621 -0
  3. package/bin/cli.js +579 -0
  4. package/package.json +46 -0
  5. package/references/advanced-ui.md +302 -0
  6. package/references/api-check.md +272 -0
  7. package/references/base-code-dict.md +48 -0
  8. package/references/build-optim.md +282 -0
  9. package/references/code-quality.md +235 -0
  10. package/references/crud-pages.md +316 -0
  11. package/references/data-compare.md +501 -0
  12. package/references/data-mapping.md +213 -0
  13. package/references/data-screen.md +79 -0
  14. package/references/data-writeback.md +104 -0
  15. package/references/detail-page.md +99 -0
  16. package/references/directives-advanced.md +93 -0
  17. package/references/download-export.md +68 -0
  18. package/references/feedback-loading.md +60 -0
  19. package/references/feedback-ui.md +111 -0
  20. package/references/file-management.md +132 -0
  21. package/references/flowchart-g6.md +244 -0
  22. package/references/form-advanced.md +137 -0
  23. package/references/graph-relation.md +253 -0
  24. package/references/http-api.md +188 -0
  25. package/references/layout-theme.md +540 -0
  26. package/references/mobile-h5.md +271 -0
  27. package/references/permission-auth.md +235 -0
  28. package/references/project-inventory.md +326 -0
  29. package/references/qrcode-barcode.md +92 -0
  30. package/references/rich-text.md +73 -0
  31. package/references/seamless-scroll.md +38 -0
  32. package/references/tree-table.md +111 -0
  33. package/references/ui-components.md +161 -0
  34. package/references/verify-captcha.md +96 -0
  35. package/references/vue-core.md +209 -0
  36. package/references/websocket-realtime.md +176 -0
  37. package/references/workflow-bpmn.md +206 -0
@@ -0,0 +1,132 @@
1
+ # 文件管理与预览
2
+
3
+ ## ReAttachment 附件管理
4
+
5
+ 集附件类型选择、上传、下载、删除于一体的表单组件。
6
+
7
+ ### Props
8
+
9
+ ```typescript
10
+ type Props = {
11
+ required?: boolean // 是否必填,默认 true
12
+ accepts?: string // 允许的文件类型,默认 '.png,.jpg,.jpeg,.pdf,.doc,.docx,...'
13
+ limit?: number // 最大上传数量,默认 10
14
+ size?: number // 单文件大小上限(字节),默认 10MB
15
+ disabled?: boolean // 是否禁用
16
+ autoUpload?: boolean // 是否自动上传,默认 false
17
+ queryParams?: () => Record<string, any> // 查询附件列表的参数
18
+ pageStatus?: string // 'create' | 'edit' | 'view'
19
+ needQuery?: boolean // 是否需要从接口查询已有附件
20
+ }
21
+ ```
22
+
23
+ ### 基本用法
24
+
25
+ ```vue
26
+ <script setup lang="ts">
27
+ import ReAttachment from '@/components/ReAttachment'
28
+
29
+ const attachmentData = ref({
30
+ attachmentType: '',
31
+ attachmentList: [],
32
+ })
33
+ </script>
34
+
35
+ <template>
36
+ <ReAttachment v-model="attachmentData" page-status="edit" :need-query="true"
37
+ :query-params="() => ({ businessId: formData.id })" />
38
+ </template>
39
+ ```
40
+
41
+ ### 数据适配
42
+
43
+ 组件内部通过 `mapRemote` 函数将后端附件对象适配为 `UploadUserFile` 格式:
44
+
45
+ - `name`:优先 `attachmentName` / `fileName`,否则从 `filePath` / `url` 提取
46
+ - `url`:优先后端 `url`,其次 `filePath`
47
+ - `size`:通过 `formatFileSize` 统一转为字节数
48
+ - `uid`:使用 `fileUuid`,不以 `id` 强制赋值
49
+
50
+ ### 表单校验
51
+
52
+ - 组件通过 `inject('FORM_VALIDATE')` 向父表单透传校验状态。
53
+ - 附件类型和附件列表均有独立的 `rules` 校验。
54
+ - 文件大小超限时自动过滤并提示。
55
+
56
+ ### 删除逻辑
57
+
58
+ - 本地文件(`raw instanceof File`):直接从列表移除。
59
+ - 已上传文件(有 `id`):弹出确认框 → 调用 `deleteAttachmentById` 接口删除。
60
+
61
+ ### 下载
62
+
63
+ - 本地文件:使用 `downloadByData(raw, name)` 流下载。
64
+ - 远端文件:调用 `downloadAttachment(url, name)` 通过接口下载。
65
+
66
+ ## ReFileViewer 文件预览
67
+
68
+ 支持图片、PDF、Office 文档等在线预览。
69
+
70
+ ```vue
71
+ <script setup lang="ts">
72
+ import ReFileViewer from '@/components/ReFileViewer'
73
+
74
+ const showViewer = ref(false)
75
+ const viewerUrl = ref('')
76
+ </script>
77
+
78
+ <template>
79
+ <el-button @click="showViewer = true">预览文件</el-button>
80
+ <ReFileViewer v-model:visible="showViewer" :url="viewerUrl" />
81
+ </template>
82
+ ```
83
+
84
+ ### 文件类型判断
85
+
86
+ ```typescript
87
+ import { checkFileType } from '@/utils/utils'
88
+
89
+ const fileType = checkFileType(fileName) // → 'image' | 'pdf' | 'word' | 'excel' | 'ppt' | 'other'
90
+ ```
91
+
92
+ ### 预览策略
93
+
94
+ | 文件类型 | 预览方式 |
95
+ |---------|---------|
96
+ | 图片(png/jpg/gif) | 直接 `<img>` 渲染 |
97
+ | PDF | `<iframe>` 或浏览器原生 |
98
+ | Office(doc/xls/ppt) | 转 PDF 后预览,或使用在线预览服务 |
99
+ | 其他 | 提示不支持预览,提供下载 |
100
+
101
+ ## 工具函数
102
+
103
+ ```typescript
104
+ import { formatFileSize, checkFileType, downloadAttachment } from '@/utils/utils'
105
+
106
+ // 文件大小格式化
107
+ formatFileSize(1024) // → { bytes: 1024, label: '1KB' }
108
+ formatFileSize(10485760) // → { bytes: 10485760, label: '10MB' }
109
+
110
+ // 文件类型检测
111
+ checkFileType('report.pdf') // → 'pdf'
112
+ checkFileType('photo.jpg') // → 'image'
113
+
114
+ // 附件下载(通过接口)
115
+ downloadAttachment(url, fileName)
116
+ ```
117
+
118
+ ## 关键约定
119
+
120
+ 1. 附件组件使用 `v-model` 双向绑定,数据格式为 `{ attachmentType, attachmentList }`。
121
+ 2. `pageStatus` 控制编辑态:`view` 模式下所有操作禁用。
122
+ 3. 文件大小校验在 `onChange` 中实时执行,超限文件自动过滤。
123
+ 4. 文件预览组件通过 `v-model:visible` 控制显示隐藏。
124
+ 5. 附件类型选项从数据字典 `baseCodeGet('PackType')` 获取。
125
+ 6. 删除已上传附件必须弹确认框,防止误操作。
126
+
127
+ ## 关联文件
128
+
129
+ - [src/components/ReAttachment/src/index.vue](file:///e:/work/vue3-web-temp/src/components/ReAttachment/src/index.vue)
130
+ - [src/components/ReFileViewer/src/index.vue](file:///e:/work/vue3-web-temp/src/components/ReFileViewer/src/index.vue)
131
+ - [src/utils/utils.ts](file:///e:/work/vue3-web-temp/src/utils/utils.ts)
132
+ - [src/views/function/fileView/index.vue](file:///e:/work/vue3-web-temp/src/views/function/fileView/index.vue)
@@ -0,0 +1,244 @@
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)
@@ -0,0 +1,137 @@
1
+ # 高级表单组件
2
+
3
+ 规范图标选择器、分段控制器、卡片选择、锚点导航、可折叠面板及地址解析等高级表单组件的使用。在开发复杂表单时参照。
4
+
5
+ ## ReIconPicker 图标选择器
6
+
7
+ ```vue
8
+ <script setup lang="ts">
9
+ import ReIconPicker from "@/components/ReIconPicker";
10
+
11
+ const icon = ref("");
12
+ </script>
13
+
14
+ <template>
15
+ <ReIconPicker v-model="icon" clearable />
16
+ </template>
17
+ ```
18
+
19
+ - 默认支持本地图标、Element Plus、Remix Icon 三类。
20
+ - 支持搜索、分页、自定义 `sources`。
21
+ - 选中值存储为图标名称字符串。
22
+
23
+ ## ReSegmented 分段控制器
24
+
25
+ ```vue
26
+ <script setup lang="ts">
27
+ import { ReSegmented } from "@/components/ReSegmented";
28
+
29
+ const options = [
30
+ { label: "日", value: "day" },
31
+ { label: "周", value: "week" },
32
+ { label: "月", value: "month" },
33
+ ];
34
+ const active = ref(0);
35
+ </script>
36
+
37
+ <template>
38
+ <ReSegmented v-model="active" :options="options" @change="onChange" />
39
+ </template>
40
+ ```
41
+
42
+ - `block`:宽度铺满父容器。
43
+ - `resize`:内容变化时自动重算滑块位置。
44
+ - `options` 支持 `icon`、`tip`、`disabled`。
45
+
46
+ ## ReCheckCard 卡片选择
47
+
48
+ ```vue
49
+ <script setup lang="ts">
50
+ import ReCheckCard from "@/components/ReCheckCard";
51
+
52
+ const value = ref("");
53
+ const options = [
54
+ { title: "选项一", value: "1", description: "描述一", avatar: "ep:check" },
55
+ { title: "选项二", value: "2", description: "描述二", avatar: "ep:star" },
56
+ ];
57
+ </script>
58
+
59
+ <template>
60
+ <ReCheckCard v-model="value" :options="options" />
61
+ <ReCheckCard v-model="values" :options="options" multiple />
62
+ </template>
63
+ ```
64
+
65
+ ## ReAnchor 锚点导航
66
+
67
+ 用于长表单/详情页模块跳转。
68
+
69
+ ```vue
70
+ <script setup lang="ts">
71
+ import { ReAnchor } from "@/components/ReAnchor";
72
+
73
+ const modules = [
74
+ { refName: "baseInfo", title: "基本信息", icon: "ep:document" },
75
+ { refName: "contactInfo", title: "联系方式", icon: "ep:phone" },
76
+ ];
77
+ </script>
78
+
79
+ <template>
80
+ <ReAnchor :anchor-modules="modules" />
81
+
82
+ <div id="baseInfo">...</div>
83
+ <div id="contactInfo">...</div>
84
+ </template>
85
+ ```
86
+
87
+ - 支持 `scrollContent` 指定滚动容器,用于弹窗场景。
88
+ - `instanceId` 用于多实例区分相同 ID。
89
+
90
+ ## ReCollapsible 可折叠面板
91
+
92
+ ```vue
93
+ <script setup lang="ts">
94
+ import ReCollapsible from "@/components/ReCollapsible";
95
+
96
+ const collapsed = ref(false);
97
+ </script>
98
+
99
+ <template>
100
+ <ReCollapsible v-model:collapsed="collapsed" width="260" position="right">
101
+ <div>面板内容</div>
102
+ </ReCollapsible>
103
+ </template>
104
+ ```
105
+
106
+ - 支持 `left` / `right` 位置。
107
+ - 暴露 `toggle()` 与 `collapsed` 状态。
108
+
109
+ ## 地址解析
110
+
111
+ ```vue
112
+ <script setup lang="ts">
113
+ import AddressParse, { Utils } from "address-parse";
114
+
115
+ function parseAddress(text: string) {
116
+ const [result] = AddressParse.parse(text);
117
+ const codeArr = Utils.getTargetAreaListByCode("province", result.code, true);
118
+
119
+ return {
120
+ name: result.name,
121
+ phone: result.mobile || result.phone,
122
+ address: result.details,
123
+ provinceCode: codeArr[0]?.code,
124
+ cityCode: codeArr[1]?.code,
125
+ areaCode: codeArr[2]?.code,
126
+ };
127
+ }
128
+ </script>
129
+ ```
130
+
131
+ - 地址与姓名、手机之间建议用空格或逗号分隔,识别更准确。
132
+
133
+ ## 关键约定
134
+
135
+ 1. 图标选择器返回值直接用于 `svg-icon` 的 `name`。
136
+ 2. 分段控制器 `v-model` 为索引数字时使用响应式;传字符串需自行维护选中态。
137
+ 3. 锚点模块 ID 与 `refName` 保持一致,弹窗内指定 `scrollContent`。