mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-01-01 18:05:28 +08:00
前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题
This commit is contained in:
197
jeecgboot-vue3/src/utils/helper/treeHelper.ts
Normal file
197
jeecgboot-vue3/src/utils/helper/treeHelper.ts
Normal file
@ -0,0 +1,197 @@
|
||||
interface TreeHelperConfig {
|
||||
id: string;
|
||||
children: string;
|
||||
pid: string;
|
||||
}
|
||||
|
||||
// 默认配置
|
||||
const DEFAULT_CONFIG: TreeHelperConfig = {
|
||||
id: 'id',
|
||||
children: 'children',
|
||||
pid: 'pid',
|
||||
};
|
||||
|
||||
// 获取配置。 Object.assign 从一个或多个源对象复制到目标对象
|
||||
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config);
|
||||
|
||||
// tree from list
|
||||
// 列表中的树
|
||||
export function listToTree<T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] {
|
||||
const conf = getConfig(config) as TreeHelperConfig;
|
||||
const nodeMap = new Map();
|
||||
const result: T[] = [];
|
||||
const { id, children, pid } = conf;
|
||||
|
||||
for (const node of list) {
|
||||
node[children] = node[children] || [];
|
||||
nodeMap.set(node[id], node);
|
||||
}
|
||||
for (const node of list) {
|
||||
const parent = nodeMap.get(node[pid]);
|
||||
(parent ? parent[children] : result).push(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function treeToList<T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T {
|
||||
config = getConfig(config);
|
||||
const { children } = config;
|
||||
const result: any = [...tree];
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
if (!result[i][children!]) continue;
|
||||
result.splice(i + 1, 0, ...result[i][children!]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function findNode<T = any>(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}): T | null {
|
||||
config = getConfig(config);
|
||||
const { children } = config;
|
||||
const list = [...tree];
|
||||
for (const node of list) {
|
||||
if (func(node)) return node;
|
||||
node[children!] && list.push(...node[children!]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findNodeAll<T = any>(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}): T[] {
|
||||
config = getConfig(config);
|
||||
const { children } = config;
|
||||
const list = [...tree];
|
||||
const result: T[] = [];
|
||||
for (const node of list) {
|
||||
func(node) && result.push(node);
|
||||
node[children!] && list.push(...node[children!]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function findPath<T = any>(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}): T | T[] | null {
|
||||
config = getConfig(config);
|
||||
const path: T[] = [];
|
||||
const list = [...tree];
|
||||
const visitedSet = new Set();
|
||||
const { children } = config;
|
||||
while (list.length) {
|
||||
const node = list[0];
|
||||
if (visitedSet.has(node)) {
|
||||
path.pop();
|
||||
list.shift();
|
||||
} else {
|
||||
visitedSet.add(node);
|
||||
node[children!] && list.unshift(...node[children!]);
|
||||
path.push(node);
|
||||
if (func(node)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findPathAll(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) {
|
||||
config = getConfig(config);
|
||||
const path: any[] = [];
|
||||
const list = [...tree];
|
||||
const result: any[] = [];
|
||||
const visitedSet = new Set(),
|
||||
{ children } = config;
|
||||
while (list.length) {
|
||||
const node = list[0];
|
||||
if (visitedSet.has(node)) {
|
||||
path.pop();
|
||||
list.shift();
|
||||
} else {
|
||||
visitedSet.add(node);
|
||||
node[children!] && list.unshift(...node[children!]);
|
||||
path.push(node);
|
||||
func(node) && result.push([...path]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filter<T = any>(
|
||||
tree: T[],
|
||||
func: (n: T) => boolean,
|
||||
// Partial 将 T 中的所有属性设为可选
|
||||
config: Partial<TreeHelperConfig> = {}
|
||||
): T[] {
|
||||
// 获取配置
|
||||
config = getConfig(config);
|
||||
const children = config.children as string;
|
||||
|
||||
function listFilter(list: T[]) {
|
||||
return list
|
||||
.map((node: any) => ({ ...node }))
|
||||
.filter((node) => {
|
||||
// 递归调用 对含有children项 进行再次调用自身函数 listFilter
|
||||
node[children] = node[children] && listFilter(node[children]);
|
||||
// 执行传入的回调 func 进行过滤
|
||||
return func(node) || (node[children] && node[children].length);
|
||||
});
|
||||
}
|
||||
|
||||
return listFilter(tree);
|
||||
}
|
||||
|
||||
export function forEach<T = any>(tree: T[], func: (n: T) => any, config: Partial<TreeHelperConfig> = {}): void {
|
||||
config = getConfig(config);
|
||||
const list: any[] = [...tree];
|
||||
const { children } = config;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
//func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿
|
||||
if (func(list[i])) {
|
||||
return;
|
||||
}
|
||||
children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Extract tree specified structure
|
||||
* @description: 提取树指定结构
|
||||
*/
|
||||
export function treeMap<T = any>(treeData: T[], opt: { children?: string; conversion: Fn }): T[] {
|
||||
return treeData.map((item) => treeMapEach(item, opt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Extract tree specified structure
|
||||
* @description: 提取树指定结构
|
||||
*/
|
||||
export function treeMapEach(data: any, { children = 'children', conversion }: { children?: string; conversion: Fn }) {
|
||||
const haveChildren = Array.isArray(data[children]) && data[children].length > 0;
|
||||
const conversionData = conversion(data) || {};
|
||||
if (haveChildren) {
|
||||
return {
|
||||
...conversionData,
|
||||
[children]: data[children].map((i: number) =>
|
||||
treeMapEach(i, {
|
||||
children,
|
||||
conversion,
|
||||
})
|
||||
),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...conversionData,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归遍历树结构
|
||||
* @param treeDatas 树
|
||||
* @param callBack 回调
|
||||
* @param parentNode 父节点
|
||||
*/
|
||||
export function eachTree(treeDatas: any[], callBack: Fn, parentNode = {}) {
|
||||
treeDatas.forEach((element) => {
|
||||
const newNode = callBack(element, parentNode) || element;
|
||||
if (element.children) {
|
||||
eachTree(element.children, callBack, newNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
35
jeecgboot-vue3/src/utils/helper/tsxHelper.tsx
Normal file
35
jeecgboot-vue3/src/utils/helper/tsxHelper.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import { Slots } from 'vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
|
||||
/**
|
||||
* @description: Get slot to prevent empty error
|
||||
*/
|
||||
export function getSlot(slots: Slots, slot = 'default', data?: any) {
|
||||
if (!slots || !Reflect.has(slots, slot)) {
|
||||
return null;
|
||||
}
|
||||
if (!isFunction(slots[slot])) {
|
||||
console.error(`${slot} is not a function!`);
|
||||
return null;
|
||||
}
|
||||
const slotFn = slots[slot];
|
||||
if (!slotFn) return null;
|
||||
return slotFn(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* extends slots
|
||||
* @param slots
|
||||
* @param excludeKeys
|
||||
*/
|
||||
export function extendSlots(slots: Slots, excludeKeys: string[] = []) {
|
||||
const slotKeys = Object.keys(slots);
|
||||
const ret: any = {};
|
||||
slotKeys.map((key) => {
|
||||
if (excludeKeys.includes(key)) {
|
||||
return null;
|
||||
}
|
||||
ret[key] = () => getSlot(slots, key);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
155
jeecgboot-vue3/src/utils/helper/validator.ts
Normal file
155
jeecgboot-vue3/src/utils/helper/validator.ts
Normal file
@ -0,0 +1,155 @@
|
||||
import { dateUtil } from '/@/utils/dateUtil';
|
||||
import { duplicateCheck } from '/@/views/system/user/user.api';
|
||||
|
||||
export const rules = {
|
||||
rule(type, required) {
|
||||
if (type === 'email') {
|
||||
return this.email(required);
|
||||
}
|
||||
if (type === 'phone') {
|
||||
return this.phone(required);
|
||||
}
|
||||
},
|
||||
email(required) {
|
||||
return [
|
||||
{
|
||||
required: required ? required : false,
|
||||
validator: async (_rule, value) => {
|
||||
if (required == true && !value) {
|
||||
return Promise.reject('请输入邮箱!');
|
||||
}
|
||||
if (
|
||||
value &&
|
||||
!new RegExp(
|
||||
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
).test(value)
|
||||
) {
|
||||
return Promise.reject('请输入正确邮箱格式!');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
] as ArrayRule;
|
||||
},
|
||||
phone(required) {
|
||||
return [
|
||||
{
|
||||
required: required,
|
||||
validator: async (_, value) => {
|
||||
if (required && !value) {
|
||||
return Promise.reject('请输入手机号码!');
|
||||
}
|
||||
if (!/^1[3456789]\d{9}$/.test(value)) {
|
||||
return Promise.reject('手机号码格式有误');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
];
|
||||
},
|
||||
startTime(endTime, required) {
|
||||
return [
|
||||
{
|
||||
required: required ? required : false,
|
||||
validator: (_, value) => {
|
||||
if (required && !value) {
|
||||
return Promise.reject('请选择开始时间');
|
||||
}
|
||||
if (endTime && value && dateUtil(endTime).isBefore(value)) {
|
||||
return Promise.reject('开始时间需小于结束时间');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
];
|
||||
},
|
||||
endTime(startTime, required) {
|
||||
return [
|
||||
{
|
||||
required: required ? required : false,
|
||||
validator: (_, value) => {
|
||||
if (required && !value) {
|
||||
return Promise.reject('请选择结束时间');
|
||||
}
|
||||
if (startTime && value && dateUtil(value).isBefore(startTime)) {
|
||||
return Promise.reject('结束时间需大于开始时间');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'change',
|
||||
},
|
||||
];
|
||||
},
|
||||
confirmPassword(values, required) {
|
||||
return [
|
||||
{
|
||||
required: required ? required : false,
|
||||
validator: (_, value) => {
|
||||
if (!value) {
|
||||
return Promise.reject('密码不能为空');
|
||||
}
|
||||
if (value !== values.password) {
|
||||
return Promise.reject('两次输入的密码不一致!');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
duplicateCheckRule(tableName, fieldName, model, schema, required?) {
|
||||
return [
|
||||
{
|
||||
validator: (_, value) => {
|
||||
if (!value && required) {
|
||||
return Promise.reject(`请输入${schema.label}`);
|
||||
}
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
duplicateCheck({
|
||||
tableName,
|
||||
fieldName,
|
||||
fieldVal: value,
|
||||
dataId: model.id,
|
||||
})
|
||||
.then((res) => {
|
||||
res.success ? resolve() : reject(res.message || '校验失败');
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err.message || '验证失败');
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
] as ArrayRule;
|
||||
},
|
||||
};
|
||||
|
||||
//update-begin-author:taoyan date:2022-6-16 for: 代码生成-原生表单用
|
||||
/**
|
||||
* 唯一校验函数,给原生<a-form>使用,vben的表单校验建议使用上述rules
|
||||
* @param tableName 表名
|
||||
* @param fieldName 字段名
|
||||
* @param fieldVal 字段值
|
||||
* @param dataId 数据ID
|
||||
*/
|
||||
export async function duplicateValidate(tableName, fieldName, fieldVal, dataId) {
|
||||
try {
|
||||
let params = {
|
||||
tableName,
|
||||
fieldName,
|
||||
fieldVal,
|
||||
dataId: dataId,
|
||||
};
|
||||
const res = await duplicateCheck(params);
|
||||
if (res.success) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject(res.message || '校验失败');
|
||||
}
|
||||
} catch (e) {
|
||||
return Promise.reject('校验失败,可能是断网等问题导致的校验失败');
|
||||
}
|
||||
}
|
||||
//update-end-author:taoyan date:2022-6-16 for: 代码生成-原生表单用
|
||||
Reference in New Issue
Block a user