|
|
@@ -1473,6 +1473,334 @@ import { getToken, getTenantId, setAuthCache, getAuthCache, clearAuthCache } fro
|
|
|
| `rowDragSort` | 拖拽排序 | JVxeDragSortCell |
|
|
|
| `slot` | 插槽自定义 | JVxeSlotCell |
|
|
|
|
|
|
+### 19.3 数据校验(validateRules)
|
|
|
+
|
|
|
+JVxeTable 完全支持对输入数据进行校验检查,包括非空、纯数字、纯字母、正则、自定义函数等。校验规则通过列配置中的 `validateRules`
|
|
|
+数组定义。
|
|
|
+
|
|
|
+#### 19.3.1 两级校验机制
|
|
|
+
|
|
|
+| 层级 | 配置位置 | 说明 |
|
|
|
+|---------|---------------------|-----------------------------------------|
|
|
|
+| **组件级** | `editRules` prop | 全局 vxe-table 原生 `editRules`,可对所有列施加通用校验 |
|
|
|
+| **列级** | `validateRules` 列属性 | 每列独立配置校验规则数组,优先级更高 |
|
|
|
+
|
|
|
+两种校验规则通过 `lodash.merge` 合并后传入底层 vxe-table。
|
|
|
+
|
|
|
+#### 19.3.2 validateRules 规则项字段
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|-------------|---------------------|------------------------------------------------------|
|
|
|
+| `required` | `boolean` | 是否必填(非空校验) |
|
|
|
+| `pattern` | `string` / `RegExp` | 正则表达式,支持快捷值 |
|
|
|
+| `message` | `string` | 校验失败提示,支持 `${title}`、`${key}`、`${defaultValue}` 变量替换 |
|
|
|
+| `validator` | `function` | 自定义异步校验函数(Promise 形式) |
|
|
|
+| `handler` | `function` | 旧版回调式校验函数(兼容模式,内部转为 validator) |
|
|
|
+| `unique` | `boolean` | 唯一性校验(同一列中值不能重复) |
|
|
|
+
|
|
|
+#### 19.3.3 内置快捷校验值(fooPatterns)
|
|
|
+
|
|
|
+组件内置了常用校验规则的快捷值,使用时直接传入 `pattern` 对应的快捷字符串即可,无需写正则。
|
|
|
+
|
|
|
+定义位置:[useValidateRules.ts](file:///d:/Code/Project/湛江人社/code/zjrs-jeecgBoot/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/hooks/useValidateRules.ts#L82-L105)
|
|
|
+
|
|
|
+| 快捷值 | 含义 | 对应正则 |
|
|
|
+|---------|-----------|-------------------------------------------------------------|
|
|
|
+| `*` | 非空 | 等同于 `required: true` |
|
|
|
+| `n` | 纯数字(含小数) | `/^-?\d+(\.?\d+\|\d?)$/` |
|
|
|
+| `s` | 纯字母 | `/^[A-Z\|a-z]+$/` |
|
|
|
+| `z` | 整数 | `/^-?\d+$/` |
|
|
|
+| `e` | 电子邮件 | `/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/` |
|
|
|
+| `m` | 手机号码 | `/^1[3456789]\d{9}$/` |
|
|
|
+| `p` | 邮政编码 | `/^\d{6}$/` |
|
|
|
+| `url` | 网址 | URL 格式正则 |
|
|
|
+| `money` | 金额 | `/^(([1-9][0-9]*)\|([0]\.\d{0,2}\|[1-9][0-9]*\.\d{0,5}))$/` |
|
|
|
+| `n6-16` | 6到16位数字 | `/^\d{6,16}$/` |
|
|
|
+| `*6-16` | 6到16位任意字符 | `/^.{6,16}$/` |
|
|
|
+| `s6-18` | 6到18位字母 | `/^[a-z\|A-Z]{6,18}$/` |
|
|
|
+| `only` | 唯一性校验 | 同 `unique: true`,遍历整表检查同列值是否重复 |
|
|
|
+
|
|
|
+#### 19.3.4 使用示例
|
|
|
+
|
|
|
+```typescript
|
|
|
+import {JVxeTable, JVxeTypes} from '/@/components/jeecg/JVxeTable';
|
|
|
+
|
|
|
+const columns = [
|
|
|
+ {
|
|
|
+ key: 'name',
|
|
|
+ title: '姓名',
|
|
|
+ type: JVxeTypes.input,
|
|
|
+ // 非空校验
|
|
|
+ validateRules: [{required: true, message: '${title}不能为空'}],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'age',
|
|
|
+ title: '年龄',
|
|
|
+ type: JVxeTypes.inputNumber,
|
|
|
+ // 整数校验 + 非空
|
|
|
+ validateRules: [
|
|
|
+ {required: true, message: '${title}不能为空'},
|
|
|
+ {pattern: 'z', message: '${title}必须为整数'},
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'email',
|
|
|
+ title: '邮箱',
|
|
|
+ type: JVxeTypes.input,
|
|
|
+ // 非必填但格式校验
|
|
|
+ validateRules: [{pattern: 'e', message: '${title}格式不正确'}],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'phone',
|
|
|
+ title: '手机号',
|
|
|
+ type: JVxeTypes.input,
|
|
|
+ // 手机号校验
|
|
|
+ validateRules: [{pattern: 'm', message: '${title}格式不正确'}],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'code',
|
|
|
+ title: '编码',
|
|
|
+ type: JVxeTypes.input,
|
|
|
+ // 纯字母校验 + 唯一性校验
|
|
|
+ validateRules: [
|
|
|
+ {required: true, message: '${title}不能为空'},
|
|
|
+ {pattern: 's', message: '${title}只能包含字母'},
|
|
|
+ {unique: true, message: '${title}不能重复'},
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'amount',
|
|
|
+ title: '金额',
|
|
|
+ type: JVxeTypes.inputNumber,
|
|
|
+ // 金额格式校验
|
|
|
+ validateRules: [{pattern: 'money', message: '${title}格式不正确'}],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'idCard',
|
|
|
+ title: '身份证号',
|
|
|
+ type: JVxeTypes.input,
|
|
|
+ // 自定义正则校验
|
|
|
+ validateRules: [{
|
|
|
+ pattern: '^\\d{6}(18|19|20)?\\d{2}(0[1-9]|1[012])(0[1-9]|[12]\\d|3[01])\\d{3}(\\d|[xX])$',
|
|
|
+ message: '${title}格式不正确',
|
|
|
+ }],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'customField',
|
|
|
+ title: '自定义校验',
|
|
|
+ type: JVxeTypes.input,
|
|
|
+ // 自定义校验函数(handler 回调式,兼容旧版)
|
|
|
+ validateRules: [{
|
|
|
+ handler: (event, callback) => {
|
|
|
+ const {cellValue} = event;
|
|
|
+ if (cellValue && cellValue.length < 3) {
|
|
|
+ callback(false, '长度不能少于3位');
|
|
|
+ } else {
|
|
|
+ callback(true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ message: '${title}校验不通过',
|
|
|
+ }],
|
|
|
+ },
|
|
|
+];
|
|
|
+```
|
|
|
+
|
|
|
+#### 19.3.5 非编辑组件的必填标记
|
|
|
+
|
|
|
+对于 `checkbox`、`radio`、`upload`、`progress`、`departSelect`、`userSelect`、`image`、`file` 等非文本编辑组件,如果配置了
|
|
|
+`validateRules` 且包含 `required`,会在列头的 `title` 前自动加 ` * ` 标记,提示用户该列为必填。
|
|
|
+
|
|
|
+定义位置:[useColumns.ts](file:///d:/Code/Project/湛江人社/code/zjrs-jeecgBoot/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/hooks/useColumns.ts#L125-L149)
|
|
|
+
|
|
|
+#### 19.3.6 手动触发校验
|
|
|
+
|
|
|
+JVxeTable 对外暴露了两个校验方法,可在外部通过 ref 调用:
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|----------------------------|--------------------------------|
|
|
|
+| `validateTable(rows?)` | 校验当前表格,成功返回 `null`,失败返回 errMap |
|
|
|
+| `fullValidateTable(rows?)` | 完整校验所有数据(无论是否修改过) |
|
|
|
+
|
|
|
+```vue
|
|
|
+
|
|
|
+<template>
|
|
|
+ <JVxeTable ref="tableRef" :columns="columns" :dataSource="dataSource"/>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+ import {ref} from 'vue';
|
|
|
+
|
|
|
+ const tableRef = ref();
|
|
|
+
|
|
|
+ async function handleSubmit() {
|
|
|
+ // 调用表格校验
|
|
|
+ const errMap = await tableRef.value.validateTable();
|
|
|
+ if (errMap) {
|
|
|
+ console.log('校验失败:', errMap);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 校验通过,执行后续逻辑
|
|
|
+ console.log('校验通过');
|
|
|
+ }
|
|
|
+</script>
|
|
|
+```
|
|
|
+
|
|
|
+定义位置:[useMethods.ts](file:///d:/Code/Project/湛江人社/code/zjrs-jeecgBoot/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts#L580-L595)
|
|
|
+
|
|
|
+### 19.4 插槽自定义字段输入(slotName + JVxeTypes.slot)
|
|
|
+
|
|
|
+JVxeTable 支持通过插槽(slot)方式自定义某个字段的输入框内容,适用于需要自定义编辑组件(如下拉框、级联选择、日期范围等)且选项数据来自父组件的场景。
|
|
|
+
|
|
|
+#### 19.4.1 插槽机制原理
|
|
|
+
|
|
|
+JVxeTable 的插槽机制分两层:
|
|
|
+
|
|
|
+**第一层:`JVxeTypes.slot` + `slotName`(推荐方式)**
|
|
|
+
|
|
|
+这是 JVxeTable 内置的插槽支持机制,完全集成到行编辑系统中。
|
|
|
+
|
|
|
+- 列配置中设置 `type: JVxeTypes.slot`,同时指定 `slotName`(如 `'myFieldSlot'`)
|
|
|
+- JVxeTable 内部的 `JVxeSlotCell` 组件负责渲染该单元格
|
|
|
+- `useColumns.ts` 中的 `handleSlots()`
|
|
|
+ 方法([源码](file:///d:/Code/Project/湛江人社/code/zjrs-jeecgBoot/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/hooks/useColumns.ts#L402-L408)
|
|
|
+ )会检查父组件是否传入了同名插槽,若有则将插槽函数注入渲染参数
|
|
|
+
|
|
|
+**第二层:`$slots` 透传至底层 `vxe-grid`**
|
|
|
+
|
|
|
+在 [JVxeTable.ts](file:///d:/Code/Project/湛江人社/code/zjrs-jeecgBoot/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/JVxeTable.ts#L77-L81)
|
|
|
+的 render 函数中,`this.$slots` 被完整透传给底层的 `vxe-grid` 组件。这意味着所有传递给 JVxeTable 的插槽也会被 vxe-grid
|
|
|
+接收,可以使用 vxe-grid 原生的所有插槽能力。
|
|
|
+
|
|
|
+#### 19.4.2 slot 插槽接收的参数
|
|
|
+
|
|
|
+[JVxeSlotCell.ts](file:///d:/Code/Project/湛江人社/code/zjrs-jeecgBoot/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/components/cells/JVxeSlotCell.ts#L10-L24)
|
|
|
+中定义了插槽函数接收的参数对象:
|
|
|
+
|
|
|
+| 参数 | 类型 | 说明 |
|
|
|
+|----------------------|-------------------|------------------------------|
|
|
|
+| `value` | `any` | 当前单元格的值 |
|
|
|
+| `row` | `object` | 当前行数据 |
|
|
|
+| `column` | `object` | 当前列配置信息 |
|
|
|
+| `params` | `object` | vxe-table 原始渲染参数 |
|
|
|
+| `$table` | `object` | vxe-table 实例,可调用内置方法 |
|
|
|
+| `rowId` | `string` | 当前行唯一标识 |
|
|
|
+| `index` / `rowIndex` | `number` | 当前行下标 |
|
|
|
+| `columnIndex` | `number` | 当前列下标 |
|
|
|
+| `scrolling` | `boolean` | 是否正在滚动 |
|
|
|
+| `reloadEffect` | `boolean` | 是否开启了数据刷新特效 |
|
|
|
+| `triggerChange` | `(value) => void` | **触发值变更**,用于将插槽组件的值更新到单元格数据中 |
|
|
|
+
|
|
|
+#### 19.4.3 下拉框选项来自父组件的实现示例
|
|
|
+
|
|
|
+**场景**:在 JVxeTable 中,某个字段需要使用下拉选择,下拉选项来自父组件(如通过 props 传入、API 加载、或父组件的响应式数据)。
|
|
|
+
|
|
|
+**列配置(data 文件)**:
|
|
|
+
|
|
|
+```typescript
|
|
|
+import {JVxeTypes} from '/@/components/jeecg/JVxeTable';
|
|
|
+
|
|
|
+export const studyAbroadColumns: JVxeColumn[] = [
|
|
|
+ {
|
|
|
+ title: '国家/地区',
|
|
|
+ key: 'country',
|
|
|
+ type: JVxeTypes.slot, // 使用 slot 类型
|
|
|
+ slotName: 'countrySlot', // 插槽名称,与模板中的 #countrySlot 对应
|
|
|
+ width: 160,
|
|
|
+ validateRules: [{required: true, message: '${title}不能为空'}],
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '学校名称',
|
|
|
+ key: 'schoolName',
|
|
|
+ type: JVxeTypes.input,
|
|
|
+ width: 200,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '开始日期',
|
|
|
+ key: 'startDate',
|
|
|
+ type: JVxeTypes.date,
|
|
|
+ width: 140,
|
|
|
+ },
|
|
|
+ // ... 其他列
|
|
|
+];
|
|
|
+```
|
|
|
+
|
|
|
+**父组件模板**:
|
|
|
+
|
|
|
+```vue
|
|
|
+
|
|
|
+<template>
|
|
|
+ <JVxeTable
|
|
|
+ ref="studyAbroadTableRef"
|
|
|
+ :columns="computedStudyAbroadColumns"
|
|
|
+ :dataSource="studyAbroadData.dataSource"
|
|
|
+ :height="250"
|
|
|
+ keepSource
|
|
|
+ rowNumber
|
|
|
+ rowSelection
|
|
|
+ stripe
|
|
|
+ toolbar
|
|
|
+ >
|
|
|
+ <!-- 自定义国家/地区字段的下拉选择框 -->
|
|
|
+ <template #countrySlot="{ row, triggerChange }">
|
|
|
+ <a-select
|
|
|
+ :value="row.country"
|
|
|
+ :options="countryOptions"
|
|
|
+ placeholder="请选择国家/地区"
|
|
|
+ allow-clear
|
|
|
+ :bordered="false"
|
|
|
+ style="width: 100%"
|
|
|
+ @change="(val) => triggerChange(val)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </JVxeTable>
|
|
|
+</template>
|
|
|
+```
|
|
|
+
|
|
|
+**父组件脚本**:
|
|
|
+
|
|
|
+```typescript
|
|
|
+<script lang = "ts"
|
|
|
+setup >
|
|
|
+import {ref} from 'vue';
|
|
|
+import {JVxeTable} from '/@/components/jeecg/JVxeTable';
|
|
|
+import {studyAbroadColumns} from '../ResumeInfo.data';
|
|
|
+
|
|
|
+// 下拉选项数据——来自父组件,可以是 props、API 加载、或本地定义的响应式数据
|
|
|
+const countryOptions = ref([
|
|
|
+ {label: '美国', value: '美国'},
|
|
|
+ {label: '英国', value: '英国'},
|
|
|
+ {label: '澳大利亚', value: '澳大利亚'},
|
|
|
+ {label: '日本', value: '日本'},
|
|
|
+ {label: '新加坡', value: '新加坡'},
|
|
|
+]);
|
|
|
+
|
|
|
+// 也可以是通过 API 动态加载
|
|
|
+// import { getCountryList } from '../xxx.api';
|
|
|
+// onMounted(async () => {
|
|
|
+// const res = await getCountryList();
|
|
|
+// countryOptions.value = res.map(item => ({ label: item.name, value: item.code }));
|
|
|
+// });
|
|
|
+</script>
|
|
|
+```
|
|
|
+
|
|
|
+#### 19.4.4 关键注意点
|
|
|
+
|
|
|
+1. **`triggerChange` 是必须调用的**:插槽组件值变更时,必须调用 `triggerChange(newValue)` 将值同步回 JVxeTable
|
|
|
+ 的数据源,否则表格数据不会更新。
|
|
|
+
|
|
|
+2. **插槽名称要唯一**:每个 `JVxeTypes.slot` 列需要指定不同的 `slotName`,同一个 JVxeTable 内不能重名。
|
|
|
+
|
|
|
+3. **slot 列支持校验**:`validateRules` 对 slot 列同样生效,非空校验会在列头显示 ` * ` 标记。
|
|
|
+
|
|
|
+4. **`bordered: false`**:插槽内部使用 Ant Design 组件时,建议设置 `:bordered="false"` 以与表格单元格样式融合。
|
|
|
+
|
|
|
+5. **插槽作用域来自父组件**:插槽模板在父组件中编写,可以直接访问父组件的所有响应式数据(props、ref、computed
|
|
|
+ 等),因此下拉选项可以灵活地来自任何父组件数据源。
|
|
|
+
|
|
|
+6. **与普通 select 类型对比**:
|
|
|
+ - `JVxeTypes.select`:适用于选项固定或通过 `dictCode` 从字典加载的场景
|
|
|
+ - `JVxeTypes.slot`:适用于选项来自父组件、需要完全自定义UI、或涉及复杂交互的场景
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 二十、WebSocket 实时推送
|