Files
Situation-Awareness-Platfor…/src/utils/validator.ts
2025-03-27 09:39:01 +08:00

182 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ref } from 'vue';
import type { Ref } from 'vue';
import {
repoPathRegExp,
repoPathSuffix,
repoPathMatch,
repoNameRegExp,
tagNameHyphenRegExp,
tagNamePrefixHeadsRegExp,
tagNamePrefixRemotesRegExp,
tagNameSuffixLockRegExp,
tagNameRegExp
} from '@/utils/regex';
import { checkRepoName } from '@/api/repo';
import { reqCatch } from '@/utils/catch';
function asyncDebounce(fn: Function, wait: number) {
// 异步函数版debounce直接使用lodash的有问题
let timerId: any = null;
return function (this: any, ...params: any[]) {
return new Promise((resolve, reject) => {
clearTimeout(timerId);
timerId = setTimeout(async () => {
try {
const res = await fn.apply(this, params);
resolve(res);
} catch (err) {
reject(err);
}
}, wait);
});
};
}
interface DynamicValidator {
(validateRules: Record<string, any[]>): {
expected: number; // 期望值
validVector: Ref<number>; // 当前根据验证情况获取的值
};
}
// 动态的表单验证,能实时监控表单的验证情况,每个字段规则不能超过32条
export const useDynamicValidator: DynamicValidator = (validateRules, initValue?) => {
const keyBitMap = new Map();
const validVector = ref(0);
// hack监听校验情况按钮置灰
const suffix = (rule: any, value: string, callback: Function) => {
const keySeq = keyBitMap.get(rule.field);
if (typeof keySeq !== 'undefined') validVector.value |= keySeq;
return callback();
};
const prefix = (rule: any, value: string, callback: Function) => {
const keySeq = keyBitMap.get(rule.field);
if (typeof keySeq !== 'undefined') validVector.value &= ~keySeq;
return callback();
};
let index = 0;
let expected = 0;
for (const name in validateRules) {
const arr = validateRules[name];
keyBitMap.set(name, 1 << index);
expected += 1 << index;
++index;
arr.unshift({ validator: prefix });
arr.push({ validator: suffix });
}
!initValue ? (validVector.value = expected) : ''; // 初始化不置灰
return {
expected,
validateRules,
validVector
};
};
// 项目名称的校验
export const repoNameValidator = () => [
{ required: true, message: '项目名称不能为空' },
{
pattern: repoNameRegExp,
message:
'项目名称应当由中文、字母、数字、下划线_、点.)和连字符(-)组成,必须以字母、数字、中文、点(.或下划线_开头且长度不得超过 100 个字符。'
},
{ pattern: repoPathSuffix, message: '项目名称不能以.wiki.git.atom结尾' }
];
interface RepoPathParams {
repoData: any;
id: string | undefined;
[propName: string]: any;
}
export const repoNamePathValidator = ({ repoData, id: selfId, repoId }: RepoPathParams) => {
const { namepath } = repoData;
const emptyCheck = (rule: object, value: string, callback: Function) =>
callback(namepath.id && namepath.repoPath ? undefined : new Error('项目路径不能为空'));
const repoPathValidate = async (rule: object, value: object) => {
const { repoPath, id } = value;
if (!repoPathRegExp.test(repoPath)) {
return Promise.reject(
new Error(
'Path的长度必须在1到100个字符之间只能包含字母a-zA-Z、数字0-9、连字符-、下划线_和点.),不区分大小写,不能以连字符和(.)开头'
)
);
}
if (!repoPathSuffix.test(repoPath)) {
return Promise.reject(new Error('Path不能以.wiki.git.atom结尾'));
}
if (!repoPathMatch.test(repoPath)) {
return Promise.reject(
new Error(
'Path不能包含如下关键字codehubdashboardusersprofilemerge_requestsissuesmilestonessettingswikihometreechartblobissues-createreviewreleasetagsbranchescommitscomparenewmergefromnetworkmemberlistlabelssettingfiles'
)
);
}
return Promise.resolve('');
};
return [{ required: true, validator: emptyCheck }, { asyncValidator: asyncDebounce(repoPathValidate, 200) }];
};
// 项目路径的校验
export const repoPathValidator = ({ repoData, id }: RepoPathParams) => {
const emptyCheck = (rule: object, value: string, callback: Function) =>
callback(repoData.namespace.id && repoData.repoPath ? undefined : new Error('项目路径不能为空'));
async function isPathUsed(rule: any, value: string) {
// 项目路径是否重复验证
const { namespace } = repoData;
const params = {
name: value,
namespace_id: namespace.id === id ? null : namespace.id
};
const { data } = await reqCatch(checkRepoName, params);
return data && data.data.status ? Promise.resolve('') : Promise.reject('path已被使用请重新输入!');
}
return [
{ required: true, validator: emptyCheck },
{
pattern: repoPathRegExp,
message:
'Path的长度必须在1到100个字符之间只能包含字母a-zA-Z、数字0-9、连字符-、下划线_和点.),不区分大小写,不能以连字符和(.)开头'
},
{ pattern: repoPathSuffix, message: 'Path不能以.wiki.git.atom结尾' },
{
pattern: repoPathMatch,
message:
'Path不能包含如下关键字codehubdashboardusersprofilemerge_requestsissuesmilestonessettingswikihometreechartblobissues-createreviewreleasetagsbranchescommitscomparenewmergefromnetworkmemberlistlabelssettingfiles'
},
{ asyncValidator: asyncDebounce(isPathUsed, 100) }
];
};
// tag名称的校验
export const tagNameValidator = () => [
{ required: true, message: 'tag名称不能为空' },
{ pattern: tagNameHyphenRegExp, message: '格式错误,请勿以"-"开头' },
{ pattern: tagNamePrefixHeadsRegExp, message: '格式错误,请勿以"refs/heads/"开头' },
{ pattern: tagNamePrefixRemotesRegExp, message: '格式错误,请勿以"refs/remotes/"开头' },
{ pattern: tagNameSuffixLockRegExp, message: '格式错误,请勿以"/"或"."或".lock"结尾' },
{ pattern: tagNameRegExp, message: '格式错误名称由中文、字母、数字_.-和/组成;且/不能连续,最多可以包含 50 个字符' }
];
// 邮箱校验
export const checkEmailValidator = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error('邮箱不能为空'));
}
// 根据 value 正则校验邮箱格式成功返回回调callback
const reg = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!reg.test(value)) {
return callback(new Error('邮箱格式不正确'));
}
callback();
};
// 手机电话校验
export const checkPhoneValidator = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error('电话不能为空'));
}
// 根据 value 正则校验手机或者电话格式成功返回回调callback
const reg = /^1[3-9]\d{9}$/;
if (!reg.test(value)) {
return callback(new Error('电话格式不正确'));
}
callback();
};