@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.
- package/README.md +229 -0
- package/SKILL.md +621 -0
- package/bin/cli.js +579 -0
- package/package.json +46 -0
- package/references/advanced-ui.md +302 -0
- package/references/api-check.md +272 -0
- package/references/base-code-dict.md +48 -0
- package/references/build-optim.md +282 -0
- package/references/code-quality.md +235 -0
- package/references/crud-pages.md +316 -0
- package/references/data-compare.md +501 -0
- package/references/data-mapping.md +213 -0
- package/references/data-screen.md +79 -0
- package/references/data-writeback.md +104 -0
- package/references/detail-page.md +99 -0
- package/references/directives-advanced.md +93 -0
- package/references/download-export.md +68 -0
- package/references/feedback-loading.md +60 -0
- package/references/feedback-ui.md +111 -0
- package/references/file-management.md +132 -0
- package/references/flowchart-g6.md +244 -0
- package/references/form-advanced.md +137 -0
- package/references/graph-relation.md +253 -0
- package/references/http-api.md +188 -0
- package/references/layout-theme.md +540 -0
- package/references/mobile-h5.md +271 -0
- package/references/permission-auth.md +235 -0
- package/references/project-inventory.md +326 -0
- package/references/qrcode-barcode.md +92 -0
- package/references/rich-text.md +73 -0
- package/references/seamless-scroll.md +38 -0
- package/references/tree-table.md +111 -0
- package/references/ui-components.md +161 -0
- package/references/verify-captcha.md +96 -0
- package/references/vue-core.md +209 -0
- package/references/websocket-realtime.md +176 -0
- 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`。
|