@zl-ui-kit/components 0.10.2 → 0.10.4

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 (2) hide show
  1. package/README.md +244 -9
  2. package/package.json +7 -7
package/README.md CHANGED
@@ -41,6 +41,7 @@ ZL UI 业务组件库 —— Element Plus 体系,`Zl` 前缀,55 个业务组
41
41
  - [6.2 Mock 模块(playground 离线联调)](#62-mock-模块playground-离线联调)
42
42
  - [6.3 组件对接实战(对应 `/use-request` 页面)](#63-组件对接实战对应-use-request-页面)
43
43
  - [6.4 常见坑位](#64-常见坑位)
44
+ - [6.5 组合用法范式(列表页 / 抽屉表单 / 卡片列表)](#65-组合用法范式列表页-抽屉表单-卡片列表)
44
45
  - [7. 表单与交互组件](#7-表单与交互组件)
45
46
  - [ZlForm —— schema 驱动](#zlform-schema-驱动)
46
47
  - [ZlSearch —— 查询条](#zlsearch-查询条)
@@ -992,6 +993,234 @@ req.cancel() // 取消进行中请求
992
993
 
993
994
  ---
994
995
 
996
+ ### 6.5 组合用法范式(列表页 / 抽屉表单 / 卡片列表)
997
+
998
+ §6.3 与 §7 是「单组件」用法;这里给出三种最常见的**页面级组合范式**,把数据组件、`ZlForm`、`ZlAction` 与 `useRequest` 家族串起来。命名与字段均按当前 Element Plus 版组件的实际 API 书写,可直接套用。
999
+
1000
+ #### 6.5.1 列表页范式:ZlSearchTable + usePageableRequest(内置)
1001
+
1002
+ `ZlSearchTable` 内部已用 `usePageableRequest` 驱动分页与查询,页面只需传 `request` / `columns` / `queryItems`;新增、导入、导出等按钮统一放进 `search-actions` 插槽;行内操作交给列的 `actions`;字典列与超长列用同名插槽(`#<prop>`)接管。
1003
+
1004
+ ```vue
1005
+ <script setup lang="ts">
1006
+ import { ref } from 'vue'
1007
+ import { ZlSearchTable, ZlAction, ZlDictTag, ZlAutoTooltip } from '@zl-ui-kit/components'
1008
+ import { useRequest, useDict, useGlobalMessage } from '@zl-ui-kit/composables'
1009
+ import EditDrawer from './EditDrawer.vue'
1010
+
1011
+ const { Message, Modal } = useGlobalMessage()
1012
+ const statusOptions = useDict('resourceStatus') // 字典项数组,渲染用 statusOptions.value
1013
+
1014
+ // 列定义:prop 命名;slot:true 的列用同名插槽 #<prop> 接管;actions 列渲染行内操作
1015
+ const columns = [
1016
+ { prop: 'name', label: '名称', minWidth: 160 },
1017
+ { prop: 'type', label: '类型', width: 120 },
1018
+ { prop: 'status', label: '状态', width: 100, slot: true },
1019
+ {
1020
+ prop: 'actions',
1021
+ label: '操作',
1022
+ width: 180,
1023
+ fixed: 'right',
1024
+ actions: [
1025
+ { label: '编辑', handler: (row: any) => openEdit(row) },
1026
+ { label: '删除', visible: (row: any) => row.id !== 1, handler: (row: any) => onDelete(row) },
1027
+ ],
1028
+ },
1029
+ ]
1030
+
1031
+ const queryItems = [
1032
+ {
1033
+ model: 'keyword',
1034
+ label: '名称',
1035
+ component: 'el-input',
1036
+ props: { placeholder: '请输入名称', clearable: true },
1037
+ },
1038
+ {
1039
+ model: 'status',
1040
+ label: '状态',
1041
+ component: 'el-select',
1042
+ props: { options: statusOptions, clearable: true },
1043
+ },
1044
+ ]
1045
+
1046
+ const tableRef = ref()
1047
+ const editVisible = ref(false)
1048
+ const editData = ref<any>({})
1049
+
1050
+ function openEdit(row?: any) {
1051
+ editData.value = row ? { ...row } : {}
1052
+ editVisible.value = true
1053
+ }
1054
+
1055
+ // 删除:确认框 + 反馈 + 原地重查(保持当前页码)
1056
+ function onDelete(row: any) {
1057
+ Modal.confirmPromise({ title: '确认删除', content: `确认删除「${row.name}」?` }, async () => {
1058
+ await removeApi(row.id)
1059
+ Message.success('删除成功')
1060
+ tableRef.value?.refresh()
1061
+ })
1062
+ }
1063
+
1064
+ // 导出:带 loading 的单次请求;outputFile 选项触发浏览器下载
1065
+ const { loading: exportLoading, run: runExport } = useRequest(exportApi, {
1066
+ manual: true,
1067
+ outputFile: () => `list_${Date.now()}.xlsx`,
1068
+ })
1069
+ function onExport() {
1070
+ runExport(tableRef.value?.search.params) // 用当前查询条件导出
1071
+ }
1072
+ </script>
1073
+
1074
+ <template>
1075
+ <ZlSearchTable
1076
+ ref="tableRef"
1077
+ :request="getPageApi"
1078
+ :columns="columns"
1079
+ :query-items="queryItems"
1080
+ :pagination="{ pageSize: 10 }"
1081
+ height="420"
1082
+ >
1083
+ <!-- 查询条右侧操作区:新增 / 导出 统一归位到这里 -->
1084
+ <template #search-actions>
1085
+ <ZlAction
1086
+ :actions="[
1087
+ { label: '新增', icon: 'zl:plus', handler: () => openEdit() },
1088
+ { label: '导出', icon: 'zl:download', disabled: exportLoading, handler: onExport },
1089
+ ]"
1090
+ />
1091
+ </template>
1092
+
1093
+ <!-- 状态列:字典标签(全局 setDictSource 已注册,无需逐行传 dict) -->
1094
+ <template #status="{ row }">
1095
+ <ZlDictTag dict-key="resourceStatus" :value="row.status" />
1096
+ </template>
1097
+
1098
+ <!-- 名称列:超长省略 + 悬浮提示 -->
1099
+ <template #name="{ row }">
1100
+ <ZlAutoTooltip>{{ row.name }}</ZlAutoTooltip>
1101
+ </template>
1102
+ </ZlSearchTable>
1103
+
1104
+ <!-- 新增 / 编辑抽屉(实现见 6.5.2) -->
1105
+ <EditDrawer v-model:visible="editVisible" :data="editData" @saved="tableRef?.refresh()" />
1106
+ </template>
1107
+ ```
1108
+
1109
+ > 行内改状态、删除后刷新用 `tableRef.refresh()`(原地重查、保持页码);换查询条件由 `ZlSearch` 自动回到第 1 页。`search-actions` 之外的批量按钮(如「导入」)也可放进这里。
1110
+
1111
+ #### 6.5.2 抽屉表单范式:ZlDrawer + ZlForm + useRequest
1112
+
1113
+ 新增 / 编辑 / 详情建议抽成独立的抽屉子组件,用 `defineModel('visible')` 承接父级 `v-model:visible`,内部用 `ZlForm` 的 `validate()` 校验,保存走 `useRequest`,反馈用 `useGlobalMessage`,保存成功后再通知父级 `refresh()`。
1114
+
1115
+ ```vue
1116
+ <script setup lang="ts">
1117
+ import { ref, watch } from 'vue'
1118
+ import { ZlDrawer, ZlForm } from '@zl-ui-kit/components'
1119
+ import { useRequest, useDict, useGlobalMessage } from '@zl-ui-kit/composables'
1120
+
1121
+ const props = defineProps<{ data?: any }>()
1122
+ const emit = defineEmits<{ saved: [] }>()
1123
+ const visible = defineModel<boolean>('visible', { required: true })
1124
+
1125
+ const { Message } = useGlobalMessage()
1126
+ const typeOptions = useDict('resourceType')
1127
+
1128
+ const model = ref<any>({})
1129
+ const formRef = ref()
1130
+
1131
+ // 打开即回填:新增给默认值,编辑用传入行数据
1132
+ watch(
1133
+ visible,
1134
+ (open) => {
1135
+ if (open) model.value = props.data ? { ...props.data } : { status: 'enabled' }
1136
+ },
1137
+ { immediate: true },
1138
+ )
1139
+
1140
+ const items = [
1141
+ { model: 'name', label: '名称', component: 'el-input', rules: [{ required: true, message: '请输入名称' }] },
1142
+ { model: 'type', label: '类型', component: 'el-select', props: { options: typeOptions } },
1143
+ {
1144
+ model: 'status',
1145
+ label: '状态',
1146
+ component: 'ZlSwitch',
1147
+ props: { checkedValue: 'enabled', uncheckedValue: 'disabled' },
1148
+ },
1149
+ ]
1150
+
1151
+ // 确定回调:校验 → 保存 → 关闭 → 通知父级刷新
1152
+ async function onSubmit() {
1153
+ await formRef.value?.validate()
1154
+ const isEdit = !!props.data?.id
1155
+ await saveApi({ ...model.value, id: props.data?.id })
1156
+ Message.success(isEdit ? '修改成功' : '新增成功')
1157
+ visible.value = false
1158
+ emit('saved')
1159
+ }
1160
+ </script>
1161
+
1162
+ <template>
1163
+ <ZlDrawer
1164
+ v-model:visible="visible"
1165
+ :title="data?.id ? '编辑' : '新增'"
1166
+ :on-ok="onSubmit"
1167
+ :auto-close-after-confirm="false"
1168
+ >
1169
+ <ZlForm ref="formRef" :model="model" :items="items" label-width="auto" />
1170
+ </ZlDrawer>
1171
+ </template>
1172
+ ```
1173
+
1174
+ > `ZlForm` 的 `validate()` 返回 `Promise<boolean>`(`0.9.0` 及更早版本成功时 `resolve(undefined)`,判断成功请用 `await` 捕获异常而非当布尔用)。表单数据用 `:model` 传入,`props` 里的 `update:modelValue` 会写回该对象,无需手写 `v-model`。`ZlDrawer` 的 `onOk` 异步期间确定按钮自动保持 loading,`auto-close-after-confirm` 默认 `true`,需要自行控制关闭时设为 `false`。
1175
+
1176
+ #### 6.5.3 卡片列表范式:ZlCardPage + ZlCard + ZlAction
1177
+
1178
+ 分页卡片列表用 `ZlCardPage`(内部同样 `usePageableRequest`),默认插槽逐项渲染 `ZlCard`;卡片的图标、标题、副标题、底部操作区用具名插槽;底部操作按钮同样用 `ZlAction`,状态角标用 `ZlDictTag`。
1179
+
1180
+ ```vue
1181
+ <script setup lang="ts">
1182
+ import { ZlCardPage, ZlCard, ZlAction, ZlIcon, ZlDictTag } from '@zl-ui-kit/components'
1183
+ import { useDict } from '@zl-ui-kit/composables'
1184
+
1185
+ const typeOptions = useDict('resourceType')
1186
+
1187
+ function cardActions(data: any) {
1188
+ return [
1189
+ { label: '查看', icon: 'zl:eye', handler: () => open(data) },
1190
+ { label: '编辑', icon: 'zl:edit', handler: () => openEdit(data) },
1191
+ ]
1192
+ }
1193
+ </script>
1194
+
1195
+ <template>
1196
+ <ZlCardPage :request="getPageApi" :query-items="queryItems" :pagination="{ pageSize: 30 }">
1197
+ <!-- 顶部操作区:新增统一放这里 -->
1198
+ <template #search-actions>
1199
+ <ZlAction :actions="[{ label: '新增', icon: 'zl:plus', handler: onAdd }]" />
1200
+ </template>
1201
+
1202
+ <!-- 逐项渲染卡片 -->
1203
+ <template #default="{ data }">
1204
+ <ZlCard>
1205
+ <template #icon>
1206
+ <ZlIcon :icon="`zl:${data.type === '数据库' ? 'database' : 'folder'}`" />
1207
+ </template>
1208
+ <template #title>{{ data.name }}</template>
1209
+ <template #subtitle>{{ data.createTime }}</template>
1210
+ <template #footer>
1211
+ <ZlDictTag dict-key="resourceStatus" :value="data.status" />
1212
+ <ZlAction :actions="cardActions(data)" />
1213
+ </template>
1214
+ </ZlCard>
1215
+ </template>
1216
+ </ZlCardPage>
1217
+ </template>
1218
+ ```
1219
+
1220
+ > 卡片列表的分页键名、条件重查(如页签切换)与列表页一致,参见 §6.3 ②。`ZlCard` 的 `icon` / `title` / `subtitle` / `footer` 均为具名插槽;需要正文区时用默认插槽。`ZlIcon` 的 `icon` 传 `zl:` 前缀图标名,未注册的图标会渲染空白。
1221
+
1222
+ ---
1223
+
995
1224
  ## 7. 表单与交互组件
996
1225
 
997
1226
  ### ZlForm —— schema 驱动
@@ -3262,10 +3491,12 @@ import { ZlAction } from '@zl-ui-kit/components'
3262
3491
  </script>
3263
3492
 
3264
3493
  <template>
3265
- <ZlAction />
3494
+ <ZlAction :actions="actions" />
3266
3495
  </template>
3267
3496
  ```
3268
3497
 
3498
+ > 示例中的 `actions` 是数组 / 对象 / 函数等非字面量入参,由调用方提供数据;其余属性写法可直接照搬。
3499
+
3269
3500
  > 把 `$attrs` 透传给 `ZlActionList`,未列出的属性会继续下传
3270
3501
 
3271
3502
  > 纯容器组件:不接收 props,也无自定义事件/插槽/暴露方法。
@@ -3653,7 +3884,7 @@ import { ZlCardPage } from '@zl-ui-kit/components'
3653
3884
  </script>
3654
3885
 
3655
3886
  <template>
3656
- <ZlCardPage :request="mockPageRequest" card-min-width="180px" />
3887
+ <ZlCardPage :request="mockPageRequest" card-min-width="200px" />
3657
3888
  </template>
3658
3889
  ```
3659
3890
 
@@ -3894,11 +4125,11 @@ import { ZlDictTag } from '@zl-ui-kit/components'
3894
4125
  </script>
3895
4126
 
3896
4127
  <template>
3897
- <ZlDictTag dict-key="dictTagDemo" value="1" :dict="dict" />
4128
+ <ZlDictTag dict-key="resourceStatus" :value="data.status" />
3898
4129
  </template>
3899
4130
  ```
3900
4131
 
3901
- > 示例中的 `dict` 是数组 / 对象 / 函数等非字面量入参,由调用方提供数据;其余属性写法可直接照搬。
4132
+ > 示例中的 `value` 是数组 / 对象 / 函数等非字面量入参,由调用方提供数据;其余属性写法可直接照搬。
3902
4133
 
3903
4134
  **props**
3904
4135
 
@@ -3928,10 +4159,12 @@ import { ZlDrawer } from '@zl-ui-kit/components'
3928
4159
  </script>
3929
4160
 
3930
4161
  <template>
3931
- <ZlDrawer v-model:visible="value" title="抽屉标题" />
4162
+ <ZlDrawer v-model:visible="value" title="新增" :on-ok="onOk" />
3932
4163
  </template>
3933
4164
  ```
3934
4165
 
4166
+ > 示例中的 `onOk` 是数组 / 对象 / 函数等非字面量入参,由调用方提供数据;其余属性写法可直接照搬。
4167
+
3935
4168
  **插槽用法**
3936
4169
 
3937
4170
  ```vue
@@ -4163,7 +4396,7 @@ import { ZlForm } from '@zl-ui-kit/components'
4163
4396
  </script>
4164
4397
 
4165
4398
  <template>
4166
- <ZlForm :model="model" :items="items" label-width="80px" style="max-width: 420px" />
4399
+ <ZlForm :model="model.value" :items="items" label-width="80px" />
4167
4400
  </template>
4168
4401
  ```
4169
4402
 
@@ -4396,10 +4629,12 @@ import { ZlIcon } from '@zl-ui-kit/components'
4396
4629
  </script>
4397
4630
 
4398
4631
  <template>
4399
- <ZlIcon icon="zl:bug" />
4632
+ <ZlIcon :icon="icon" />
4400
4633
  </template>
4401
4634
  ```
4402
4635
 
4636
+ > 示例中的 `icon` 是数组 / 对象 / 函数等非字面量入参,由调用方提供数据;其余属性写法可直接照搬。
4637
+
4403
4638
  **插槽用法**
4404
4639
 
4405
4640
  ```vue
@@ -4876,10 +5111,10 @@ import { ZlSearchTable } from '@zl-ui-kit/components'
4876
5111
  <template>
4877
5112
  <ZlSearchTable
4878
5113
  :request="mockPageRequest"
4879
- :columns="tableColumns"
5114
+ :columns="columns"
4880
5115
  :query-items="queryItems"
4881
5116
  :pagination="{ pageSize: 5 }"
4882
- height="320"
5117
+ height="340"
4883
5118
  />
4884
5119
  </template>
4885
5120
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zl-ui-kit/components",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "type": "module",
5
5
  "description": "ZL UI 业务组件库(Element Plus 体系,Zl 前缀)——首批:Icon/AutoTooltip/Tag/CornerTag/Text/Title/Copy/Empty/Pagination/DictTag",
6
6
  "license": "MIT",
@@ -39,12 +39,12 @@
39
39
  "file-type": "^20.4.1",
40
40
  "dt-sql-parser": "^4.3.1",
41
41
  "sql-formatter": "^15.4.2",
42
- "@zl-ui-kit/utils": "0.10.2",
43
- "@zl-ui-kit/icons": "0.10.2",
44
- "@zl-ui-kit/composables": "0.10.2"
42
+ "@zl-ui-kit/composables": "0.10.4",
43
+ "@zl-ui-kit/icons": "0.10.4",
44
+ "@zl-ui-kit/utils": "0.10.4"
45
45
  },
46
46
  "peerDependencies": {
47
- "@vueuse/core": "^12.3.0",
47
+ "@vueuse/core": "^12.3.0 || ^13.0.0 || ^14.0.0 || ^15.0.0",
48
48
  "element-plus": "^2.9.2",
49
49
  "vue": "^3.5.13",
50
50
  "monaco-editor": "^0.41.0",
@@ -79,7 +79,7 @@
79
79
  "@typescript-eslint/eslint-plugin": "^8.19.1",
80
80
  "@typescript-eslint/parser": "^8.19.1",
81
81
  "@vitejs/plugin-vue": "^5.2.1",
82
- "@vueuse/core": "^12.3.0",
82
+ "@vueuse/core": "^12.3.0 || ^13.0.0 || ^14.0.0 || ^15.0.0",
83
83
  "cross-env": "^7.0.3",
84
84
  "element-plus": "^2.9.2",
85
85
  "eslint-plugin-vue": "^9.32.0",
@@ -100,7 +100,7 @@
100
100
  "echarts": "^5.6.0",
101
101
  "@jichuang/vite-config": "1.0.0",
102
102
  "@jichuang/tsconfig": "1.0.0",
103
- "@zl-ui-kit/theme": "0.10.2",
103
+ "@zl-ui-kit/theme": "0.10.4",
104
104
  "@jichuang/eslint-config": "1.0.0"
105
105
  },
106
106
  "repository": {