@a2simcode/ui 0.0.248 → 0.0.249

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.
@@ -0,0 +1,210 @@
1
+ export default {
2
+ props: [
3
+ {
4
+ name: 'dataSource',
5
+ description: '数据源',
6
+ type: 'Record<string, any>[]',
7
+ default: '[]',
8
+ },
9
+ {
10
+ name: 'loadSrc',
11
+ description: '根据行数据返回图片地址',
12
+ type: '(item: Record<string, any>) => string',
13
+ default: 'undefined',
14
+ },
15
+ {
16
+ name: 'labelKey',
17
+ description: '标题字段',
18
+ type: 'string',
19
+ default: "'f_Name'",
20
+ },
21
+ {
22
+ name: 'rowKey',
23
+ description: '行唯一键字段(用于单选/多选)',
24
+ type: 'string',
25
+ default: "'f_Id'",
26
+ },
27
+ {
28
+ name: 'buttons',
29
+ description: '操作按钮配置(支持 children 下拉)',
30
+ type: 'ButtonCompType[]',
31
+ default: '[]',
32
+ },
33
+ {
34
+ name: 'maxBtns',
35
+ description: '最多显示按钮数量,超出部分折叠到下拉',
36
+ type: 'number',
37
+ default: '3',
38
+ },
39
+ {
40
+ name: 'setButton',
41
+ description: '行级按钮处理方法(可动态隐藏/禁用)',
42
+ type: '(data: { buttons: ButtonCompType[]; row: Record<string, any> }) => void',
43
+ default: 'undefined',
44
+ },
45
+ {
46
+ name: 'showBigEditButton',
47
+ description: '是否在卡片中部展示大编辑按钮(需要存在 id=edit 的按钮)',
48
+ type: 'boolean',
49
+ default: 'false',
50
+ },
51
+ {
52
+ name: 'loading',
53
+ description: '加载状态',
54
+ type: 'boolean',
55
+ default: 'false',
56
+ },
57
+ {
58
+ name: 'isRadio',
59
+ description: '是否单选',
60
+ type: 'boolean',
61
+ default: 'false',
62
+ },
63
+ {
64
+ name: 'isMultiSelect',
65
+ description: '是否多选',
66
+ type: 'boolean',
67
+ default: 'false',
68
+ },
69
+ {
70
+ name: 'isPage',
71
+ description: '是否分页',
72
+ type: 'boolean',
73
+ default: 'false',
74
+ },
75
+ {
76
+ name: 'pageTotal',
77
+ description: '总数据条数',
78
+ type: 'number',
79
+ default: '0',
80
+ },
81
+ {
82
+ name: 'tablePage',
83
+ description: '当前页码(v-model:tablePage)',
84
+ type: 'number',
85
+ default: '1',
86
+ },
87
+ {
88
+ name: 'pageSize',
89
+ description: '分页大小(v-model:pageSize)',
90
+ type: 'number',
91
+ default: '50',
92
+ },
93
+ {
94
+ name: 'pageSizes',
95
+ description: '分页大小选项',
96
+ type: 'number[]',
97
+ default: 'undefined',
98
+ },
99
+ {
100
+ name: 'pageLayoutSimple',
101
+ description: '是否使用简洁分页布局',
102
+ type: 'boolean',
103
+ default: 'false',
104
+ },
105
+ {
106
+ name: 'backgroundColor',
107
+ description: '外层背景色',
108
+ type: 'string',
109
+ default: "''",
110
+ },
111
+ {
112
+ name: 'cardWidth',
113
+ description: '卡片宽度(number 或 string)',
114
+ type: 'number | string',
115
+ default: "'25%'",
116
+ },
117
+ {
118
+ name: 'cardHeight',
119
+ description: '卡片高度(已废弃,不再生效)',
120
+ type: 'number',
121
+ default: 'undefined',
122
+ },
123
+ {
124
+ name: 'cardAspectRatio',
125
+ description: '卡片宽高比(例如 258/184)',
126
+ type: 'number | string',
127
+ default: '258 / 184',
128
+ },
129
+ {
130
+ name: 'imageFit',
131
+ description: '图片填充模式',
132
+ type: "'fill' | 'contain' | 'cover' | 'none' | 'scale-down'",
133
+ default: "'contain'",
134
+ },
135
+ {
136
+ name: 'fallback',
137
+ description: '图片加载失败时展示的兜底图片地址',
138
+ type: 'string',
139
+ default: "''",
140
+ },
141
+ {
142
+ name: 'itemRender',
143
+ description: '自定义卡片渲染方法(优先于 slot=item)',
144
+ type: '(data: { item: Record<string, any>; index: number }) => any',
145
+ default: 'undefined',
146
+ },
147
+ ],
148
+ events: [
149
+ {
150
+ name: 'click',
151
+ description: '点击操作按钮时触发',
152
+ type: '(id: string, data: { item: Record<string, any>; index: number; button: ButtonCompType }) => void',
153
+ },
154
+ {
155
+ name: 'loadPageData',
156
+ description: '分页变更时触发',
157
+ type: '(data: { rows: number; page: number }) => void',
158
+ },
159
+ {
160
+ name: 'update:pageSize',
161
+ description: '分页大小双向绑定更新事件',
162
+ type: '(value: number) => void',
163
+ },
164
+ {
165
+ name: 'update:tablePage',
166
+ description: '页码双向绑定更新事件',
167
+ type: '(value: number) => void',
168
+ },
169
+ {
170
+ name: 'selectionChange',
171
+ description: '选中项变化时触发',
172
+ type: '(data: { selections: string[]; rows: Record<string, any>[] }) => void',
173
+ },
174
+ ],
175
+ slots: [
176
+ {
177
+ name: 'item',
178
+ description: '自定义卡片内容,参数:{ item, index }',
179
+ },
180
+ ],
181
+ methods: [
182
+ {
183
+ name: 'clearSelection',
184
+ description: '清空选中项',
185
+ type: '() => void',
186
+ },
187
+ {
188
+ name: 'toggleRowSelection',
189
+ description: '切换行选中状态',
190
+ type: '(rows: Record<string, any>[], selected: boolean) => void',
191
+ },
192
+ {
193
+ name: 'getSelections',
194
+ description: '获取选中行数据',
195
+ type: '() => Record<string, any>[]',
196
+ },
197
+ ],
198
+ types: [
199
+ {
200
+ name: 'CardListProps',
201
+ properties: [
202
+ { name: 'dataSource', type: 'Record<string, any>[]', description: '数据源' },
203
+ { name: 'loadSrc', type: '(item: Record<string, any>) => string', description: '根据行数据返回图片地址' },
204
+ { name: 'labelKey', type: 'string', description: '标题字段' },
205
+ { name: 'rowKey', type: 'string', description: '行唯一键字段' },
206
+ { name: 'buttons', type: 'ButtonCompType[]', description: '操作按钮配置' },
207
+ ],
208
+ },
209
+ ],
210
+ }
@@ -1,5 +1,11 @@
1
1
  export default {
2
2
  "props": [
3
+ {
4
+ "name": "viewMode",
5
+ "description": "显示方式 table 表格 card 卡片",
6
+ "type": "'table' | 'card'",
7
+ "default": "'table'"
8
+ },
3
9
  {
4
10
  "name": "modelValue",
5
11
  "description": "输入值【作为表单的编辑表格使用】",
@@ -221,6 +227,54 @@ export default {
221
227
  "description": "是否支持行拖动排序",
222
228
  "type": "boolean",
223
229
  "default": "false"
230
+ },
231
+ {
232
+ "name": "cardLabelKey",
233
+ "description": "卡片视图标题字段名",
234
+ "type": "string",
235
+ "default": "'f_Name'"
236
+ },
237
+ {
238
+ "name": "cardLoadSrc",
239
+ "description": "卡片视图图片加载方法",
240
+ "type": "(item: Record<string, any>) => string",
241
+ "default": "undefined"
242
+ },
243
+ {
244
+ "name": "cardFallback",
245
+ "description": "卡片视图图片加载失败兜底图",
246
+ "type": "string",
247
+ "default": "''"
248
+ },
249
+ {
250
+ "name": "cardBackgroundColor",
251
+ "description": "卡片视图背景色",
252
+ "type": "string",
253
+ "default": "''"
254
+ },
255
+ {
256
+ "name": "cardShowBigEditButton",
257
+ "description": "卡片视图是否展示大编辑按钮(需要 buttons 中包含 id 为 edit 的按钮)",
258
+ "type": "boolean",
259
+ "default": "false"
260
+ },
261
+ {
262
+ "name": "cardWidth",
263
+ "description": "卡片视图卡片宽度",
264
+ "type": "number",
265
+ "default": "258"
266
+ },
267
+ {
268
+ "name": "cardHeight",
269
+ "description": "卡片视图卡片高度",
270
+ "type": "number",
271
+ "default": "184"
272
+ },
273
+ {
274
+ "name": "cardImageFit",
275
+ "description": "卡片视图图片填充方式",
276
+ "type": "'fill' | 'contain' | 'cover' | 'none' | 'scale-down'",
277
+ "default": "'fill'"
224
278
  }
225
279
  ],
226
280
  "events": [
@@ -205,6 +205,19 @@
205
205
  </template>
206
206
  </Demo>
207
207
 
208
+ ## 卡片视图
209
+
210
+ 通过 `view-mode="card"` 切换为卡片展示模式,并使用 `card-label-key / card-load-src` 指定卡片标题字段和图片来源。
211
+
212
+ <Demo :source-code="tablePanelCardCode">
213
+ <template #source>
214
+ <table-panel-card />
215
+ </template>
216
+ <template #description>
217
+ 卡片模式会使用内置的 `JCardList` 渲染数据,并复用表格面板的搜索、筛选、排序、分页能力。
218
+ </template>
219
+ </Demo>
220
+
208
221
  ## 自定义渲染(掩码示例)
209
222
 
210
223
  通过 `render-v-node` 可以跳过内置表格渲染,使用 VNode 自定义每条记录的展示方式。下面示例用卡片布局展示行数据,并支持一键切换手机号/邮箱的掩码显示。
@@ -278,6 +291,7 @@ import TablePanelSubTableLazy from '../examples/table-panel/sub-table-lazy.vue'
278
291
  import TablePanelGetSelection from '../examples/table-panel/get-selection.vue'
279
292
  import TablePanelButtonVisibility from '../examples/table-panel/button-visibility.vue'
280
293
  import TablePanelModelValue from '../examples/table-panel/model-value.vue'
294
+ import TablePanelCard from '../examples/table-panel/card.vue'
281
295
  import TablePanelMask from '../examples/table-panel/mask.vue'
282
296
  import tablePanelApi from './meta/table-panel'
283
297
 
@@ -293,5 +307,6 @@ import tablePanelSubTableLazyCode from '../examples/table-panel/sub-table-lazy.v
293
307
  import tablePanelGetSelectionCode from '../examples/table-panel/get-selection.vue?raw'
294
308
  import tablePanelButtonVisibilityCode from '../examples/table-panel/button-visibility.vue?raw'
295
309
  import tablePanelModelValueCode from '../examples/table-panel/model-value.vue?raw'
310
+ import tablePanelCardCode from '../examples/table-panel/card.vue?raw'
296
311
  import tablePanelMaskCode from '../examples/table-panel/mask.vue?raw'
297
312
  </script>
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <div style="padding: 12px">
3
+ <j-card-list
4
+ :data-source="list"
5
+ :load-src="loadSrc"
6
+ :buttons="buttons"
7
+ :show-big-edit-button="true"
8
+ :is-multi-select="true"
9
+ @click="handleClick"
10
+ />
11
+ </div>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { ref } from 'vue'
16
+ import { ElMessage } from 'element-plus'
17
+
18
+ const list = ref([
19
+ { f_Id: '1', f_Name: '卡片 1', img: 'https://picsum.photos/seed/simcode-1/600/400' },
20
+ { f_Id: '2', f_Name: '卡片 2', img: 'https://picsum.photos/seed/simcode-2/600/400' },
21
+ { f_Id: '3', f_Name: '卡片 3', img: 'https://picsum.photos/seed/simcode-3/600/400' },
22
+ { f_Id: '4', f_Name: '卡片 4', img: 'https://picsum.photos/seed/simcode-4/600/400' },
23
+ ])
24
+
25
+ const loadSrc = (row: any) => row.img
26
+
27
+ const buttons = ref([
28
+ {
29
+ id: 'edit',
30
+ label: '编辑',
31
+ config: { type: 'primary', icon: 'material-symbols-light:edit-outline' },
32
+ click: (scope: any) => {
33
+ ElMessage.info(`点击编辑:${scope?.data?.f_Name || ''}`)
34
+ },
35
+ },
36
+ {
37
+ id: 'delete',
38
+ label: '删除',
39
+ config: { status: 'danger', icon: 'material-symbols-light:delete-outline' },
40
+ click: (scope: any) => {
41
+ ElMessage.warning(`点击删除:${scope?.data?.f_Name || ''}`)
42
+ },
43
+ },
44
+ {
45
+ id: 'more',
46
+ label: '更多',
47
+ config: { icon: 'material-symbols-light:more-horiz' },
48
+ children: [
49
+ {
50
+ id: 'copy',
51
+ label: '复制',
52
+ click: (scope: any) => {
53
+ ElMessage.success(`点击复制:${scope?.data?.f_Name || ''}`)
54
+ },
55
+ },
56
+ {
57
+ id: 'detail',
58
+ label: '详情',
59
+ click: (scope: any) => {
60
+ ElMessage.info(`点击详情:${scope?.data?.f_Name || ''}`)
61
+ },
62
+ },
63
+ ],
64
+ },
65
+ ])
66
+
67
+ const handleClick = (id: string, payload: any) => {
68
+ ElMessage.success(`触发 click 事件:${id}(${payload?.item?.f_Name || ''})`)
69
+ }
70
+ </script>
@@ -0,0 +1,69 @@
1
+ <template>
2
+ <div style="padding: 12px">
3
+ <div style="margin-bottom: 12px; display: flex; gap: 8px">
4
+ <j-button type="primary" label="获取选中项" @click="handleGetSelections" />
5
+ <j-button label="清空选中" @click="handleClear" />
6
+ </div>
7
+
8
+ <j-card-list
9
+ ref="cardListRef"
10
+ :data-source="list"
11
+ :load-src="loadSrc"
12
+ :is-radio="true"
13
+ :is-page="true"
14
+ :page-total="total"
15
+ v-model:table-page="page"
16
+ v-model:page-size="pageSize"
17
+ :page-sizes="[4, 8, 12]"
18
+ :loading="loading"
19
+ @load-page-data="handleLoadPageData"
20
+ />
21
+ </div>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { ref } from 'vue'
26
+ import { ElMessage } from 'element-plus'
27
+
28
+ const loading = ref(false)
29
+ const total = ref(40)
30
+ const page = ref(1)
31
+ const pageSize = ref(4)
32
+
33
+ const buildList = (p: number, s: number) => {
34
+ const start = (p - 1) * s + 1
35
+ return Array.from({ length: s }).map((_, i) => {
36
+ const id = String(start + i)
37
+ return {
38
+ f_Id: id,
39
+ f_Name: `第 ${id} 条`,
40
+ img: `https://picsum.photos/seed/simcode-page-${id}/600/400`,
41
+ }
42
+ })
43
+ }
44
+
45
+ const list = ref(buildList(page.value, pageSize.value))
46
+
47
+ const loadSrc = (row: any) => row.img
48
+
49
+ const handleLoadPageData = async (data: any) => {
50
+ loading.value = true
51
+ page.value = data.page
52
+ pageSize.value = data.rows
53
+ await new Promise((r) => setTimeout(r, 300))
54
+ list.value = buildList(page.value, pageSize.value)
55
+ loading.value = false
56
+ }
57
+
58
+ const cardListRef = ref<any>()
59
+
60
+ const handleGetSelections = () => {
61
+ const rows = cardListRef.value?.getSelections?.() || []
62
+ ElMessage.info(`选中:${rows?.[0]?.f_Name || '无'}`)
63
+ }
64
+
65
+ const handleClear = () => {
66
+ cardListRef.value?.clearSelection?.()
67
+ ElMessage.success('已清空')
68
+ }
69
+ </script>
@@ -0,0 +1,101 @@
1
+ <template>
2
+ <div style="position: relative; width: 100%; height: 520px">
3
+ <j-table-panel
4
+ view-mode="card"
5
+ row-key="id"
6
+ :columns="columns"
7
+ :load-data="loadData"
8
+ :actions="actions"
9
+ :is-page="true"
10
+ card-label-key="name"
11
+ :card-load-src="cardLoadSrc"
12
+ :card-width="25"
13
+ :card-show-big-edit-button="true"
14
+ card-image-fit="cover"
15
+ />
16
+ </div>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { ref } from 'vue'
21
+ import { ElMessage } from 'element-plus'
22
+
23
+ const columns = ref([
24
+ {
25
+ id: 'id',
26
+ type: '',
27
+ config: {
28
+ label: 'ID',
29
+ width: 80,
30
+ },
31
+ },
32
+ {
33
+ id: 'name',
34
+ type: '',
35
+ config: {
36
+ label: '名称',
37
+ filter: {
38
+ isSearchKeyword: true,
39
+ },
40
+ },
41
+ },
42
+ {
43
+ id: 'category',
44
+ type: '',
45
+ config: {
46
+ label: '分类',
47
+ width: 120,
48
+ filter: {
49
+ isSearchKeyword: true,
50
+ },
51
+ },
52
+ },
53
+ ])
54
+
55
+ const actions = ref([
56
+ {
57
+ id: 'edit',
58
+ label: '编辑',
59
+ config: { icon: 'mdi:pencil' },
60
+ click: (row: Record<string, any>) => {
61
+ ElMessage.info(`编辑:${row.name}`)
62
+ },
63
+ },
64
+ {
65
+ id: 'delete',
66
+ label: '删除',
67
+ config: { icon: 'mdi:delete', status: 'danger' },
68
+ click: (row: Record<string, any>) => {
69
+ ElMessage.warning(`删除:${row.name}`)
70
+ },
71
+ },
72
+ ])
73
+
74
+ const mockData = Array.from({ length: 30 }).map((_, index) => {
75
+ const id = index + 1
76
+ const category = ['办公用品', '科技产品', '家具'][id % 3]
77
+ return {
78
+ id,
79
+ name: `示例数据 ${id}`,
80
+ category,
81
+ cover: `https://picsum.photos/seed/table-panel-card-${id}/400/300`,
82
+ }
83
+ })
84
+
85
+ const cardLoadSrc = (item: Record<string, any>) => {
86
+ return item.cover || ''
87
+ }
88
+
89
+ const loadData = async (params: any) => {
90
+ const rows = params?.pagination?.rows ?? 12
91
+ const page = params?.pagination?.page ?? 1
92
+
93
+ const start = Math.max(0, (page - 1) * rows)
94
+ const end = start + rows
95
+
96
+ return {
97
+ rows: mockData.slice(start, end),
98
+ records: mockData.length,
99
+ }
100
+ }
101
+ </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a2simcode/ui",
3
- "version": "0.0.248",
3
+ "version": "0.0.249",
4
4
  "description": "A Vue 3 UI Component Library",
5
5
  "type": "module",
6
6
  "main": "./dist/simcode-ui.umd.js",
@@ -82,7 +82,7 @@
82
82
  "element-plus": "2.14.2",
83
83
  "sortablejs": "1.15.7",
84
84
  "sql-formatter": "15.7.2",
85
- "vue": "3.5.38",
85
+ "vue": "3.5.39",
86
86
  "@wangeditor/editor": "5.1.23",
87
87
  "diagram-js": "15.13.0",
88
88
  "diagram-js-direct-editing": "3.3.0",
@@ -225,7 +225,7 @@
225
225
  "vite-plugin-dts": "4.5.4",
226
226
  "vitepress": "1.6.4",
227
227
  "vitest": "4.1.0",
228
- "vue": "3.5.38",
228
+ "vue": "3.5.39",
229
229
  "vue-docgen-api": "4.79.2",
230
230
  "vue-tsc": "3.2.7"
231
231
  }