@@ -1,14 +1,25 @@
import { ref } from 'vue' ;
import type { Ref } from 'vue' ;
import { repoPathRegExp , repoPathSuffix , repoPathMatch , repoNameRegExp , tagNameHyphenRegExp , tagNamePrefixHeadsRegExp , tagNamePrefixRemotesRegExp , tagNameSuffixLockRegExp , tagNameRegExp } from '@/utils/regex' ;
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 [ ] ) {
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 ( ) = > {
timerId = setTimeout ( async ( ) = > {
try {
const res = await fn . apply ( this , params ) ;
resolve ( res ) ;
@@ -19,14 +30,14 @@ function asyncDebounce(fn:Function, wait:number) { // 异步函数版debounce,
} ) ;
} ;
}
interface DynamicValidator {
( validateRules :Record < string , any [ ] > ) : {
expected :number , // 期望值
validVector :Ref < number > // 当前根据验证情况获取的值
}
interface DynamicValidator {
( validateRules : Record < string , any [ ] > ) : {
expected : number ; // 期望值
validVector : Ref < number > ; // 当前根据验证情况获取的值
} ;
}
// 动态的表单验证,能实时监控表单的验证情况,每个字段规则不能超过32条
export const useDynamicValidator :DynamicValidator = ( validateRules , initValue ? ) = > {
export const useDynamicValidator : DynamicValidator = ( validateRules , initValue ? ) = > {
const keyBitMap = new Map ( ) ;
const validVector = ref ( 0 ) ;
// hack: 监听校验情况按钮置灰
@@ -40,7 +51,8 @@ export const useDynamicValidator:DynamicValidator = (validateRules, initValue?)
if ( typeof keySeq !== 'undefined' ) validVector . value &= ~ keySeq ;
return callback ( ) ;
} ;
let index = 0 ; let expected = 0 ;
let index = 0 ;
let expected = 0 ;
for ( const name in validateRules ) {
const arr = validateRules [ name ] ;
keyBitMap . set ( name , 1 << index ) ;
@@ -49,7 +61,7 @@ export const useDynamicValidator:DynamicValidator = (validateRules, initValue?)
arr . unshift ( { validator : prefix } ) ;
arr . push ( { validator : suffix } ) ;
}
! initValue ? validVector . value = expected : '' ; // 初始化不置灰
! initValue ? ( validVector . value = expected ) : '' ; // 初始化不置灰
return {
expected ,
validateRules ,
@@ -59,62 +71,77 @@ export const useDynamicValidator:DynamicValidator = (validateRules, initValue?)
// 项目名称的校验
export const repoNameValidator = ( ) = > [
{ required : true , message : '项目名称不能为空' } ,
{ pattern : repoNameRegExp , message : '项目名称应当由中文、字母、数字、下划线( _) 、点( .)和连字符(-)组成,必须以字母、数字、中文、点(.) 或下划线( _) 开头, 且长度不得超过 100 个字符。' } ,
{
pattern : repoNameRegExp ,
message :
'项目名称应当由中文、字母、数字、下划线( _) 、点( .)和连字符(-)组成,必须以字母、数字、中文、点(.) 或下划线( _) 开头, 且长度不得超过 100 个字符。'
} ,
{ pattern : repoPathSuffix , message : '项目名称不能以.wiki, .git, .atom结尾' }
] ;
interface RepoPathParams {
repoData :any ,
id :string | undefined ,
[ propName : string ] : any ,
interface RepoPathParams {
repoData : any ;
id : string | undefined ;
[ propName : string ] : any ;
}
export const repoNamePathValidator = ( { repoData , id : selfId , repoId } : RepoPathParams ) = > {
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-z, A-Z) 、数字( 0-9) 、连字符( -) 、下划线( _) 和点( .),不区分大小写,不能以连字符和(.)开头' ) ) ;
if ( ! repoPathRegExp . test ( repoPath ) ) {
return Promise . reject (
new Error (
'Path的长度必须在1到100个字符之间, 只能包含字母( a-z, A-Z) 、数字( 0-9) 、连字符( -) 、下划线( _) 和点( .),不区分大小写,不能以连字符和(.)开头'
)
) ;
}
if ( ! repoPathSuffix . test ( repoPath ) ) {
if ( ! repoPathSuffix . test ( repoPath ) ) {
return Promise . reject ( new Error ( 'Path不能以.wiki, .git, .atom结尾' ) ) ;
}
if ( ! repoPathMatch . test ( repoPath ) ) {
return Promise . reject ( new Error ( 'Path不能包含如下关键字: codehub, dashboard, users, profile, merge_requests, issues, milestones, settings, wiki, home, tree, chart, blob, issues-create, review, release, tags, branches, commits, compare, newmergefrom, network, memberlist, labels, setting, files' ) )
if ( ! repoPathMatch . test ( repoPath ) ) {
return Promise . reject (
new Error (
'Path不能包含如下关键字: codehub, dashboard, users, profile, merge_requests, issues, milestones, settings, wiki, home, tree, chart, blob, issues-create, review, release, tags, branches, commits, compare, newmergefrom, network, memberlist, labels, setting, files'
)
) ;
}
return Promise . resolve ( '' ) ;
} ;
}
return [
{ required : true , validator : emptyCheck } ,
{ asyncValidator : asyncDebounce ( repoPathValidate , 200 ) }
] ;
return [ { required : true , validator : emptyCheck } , { asyncValidator : asyncDebounce ( repoPathValidate , 200 ) } ] ;
} ;
// 项目路径的校验
export const repoPathValidator = ( { repoData , id } : RepoPathParams ) = > {
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 ) { // 项目路径是否重复验证
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 data && data . data . status ? Promise . resolve ( '' ) : Promise . reject ( 'path已被使用, 请重新输入!' ) ;
}
return [
{ required : true , validator : emptyCheck } ,
{ pattern : repoPathRegExp , message : 'Path的长度必须在1到100个字符之间, 只能包含字母( a-z, A-Z) 、数字( 0-9) 、连字符( -) 、下划线( _) 和点( .),不区分大小写,不能以连字符和(.)开头' } ,
{
pattern : repoPathRegExp ,
message :
'Path的长度必须在1到100个字符之间, 只能包含字母( a-z, A-Z) 、数字( 0-9) 、连字符( -) 、下划线( _) 和点( .),不区分大小写,不能以连字符和(.)开头'
} ,
{ pattern : repoPathSuffix , message : 'Path不能以.wiki, .git, .atom结尾' } ,
{ pattern : repoPathMatch , message : 'Path不能包含如下关键字: codehub, dashboard, users, profile, merge_requests, issues, milestones, settings, wiki, home, tree, chart, blob, issues-create, review, release, tags, branches, commits, compare, newmergefrom, network, memberlist, labels, setting, files' } ,
{
pattern : repoPathMatch ,
message :
'Path不能包含如下关键字: codehub, dashboard, users, profile, merge_requests, issues, milestones, settings, wiki, home, tree, chart, blob, issues-create, review, release, tags, branches, commits, compare, newmergefrom, network, memberlist, labels, setting, files'
} ,
{ asyncValidator : asyncDebounce ( isPathUsed , 100 ) }
] ;
} ;
@@ -128,3 +155,27 @@ export const tagNameValidator = () => [
{ 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-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/ ;
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 ( ) ;
} ;