UNPKG

asp-smart-ui-plus-test

Version:

A Component Library for Vue 3

484 lines (422 loc) 13.1 kB
var pattern = { email: /^\S+?@\S+?\.\S+?$/, idcard: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/, url: new RegExp( '^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 'i') } const FORMAT_MAPPING = { int: 'integer', bool: 'boolean', double: 'number', long: 'number', password: 'string' // "fileurls": 'array' } function formatMessage (args, resources = '') { var defaultMessage = ['label'] defaultMessage.forEach((item) => { if (args[item] === undefined) { args[item] = '' } }) let str = resources for (const key in args) { const reg = new RegExp('{' + key + '}') str = str.replace(reg, args[key]) } return str } function isEmptyValue (value, type) { if (value === undefined || value === null) { return true } if (typeof value === 'string' && !value) { return true } if (Array.isArray(value) && !value.length) { return true } if (type === 'object' && !Object.keys(value).length) { return true } return false } const types = { integer (value) { return types.number(value) && parseInt(value, 10) === value }, string (value) { return typeof value === 'string' }, number (value) { if (isNaN(value)) { return false } return typeof value === 'number' }, boolean: function (value) { return typeof value === 'boolean' }, float: function (value) { return types.number(value) && !types.integer(value) }, array (value) { return Array.isArray(value) }, object (value) { return typeof value === 'object' && !types.array(value) }, date (value) { return value instanceof Date }, timestamp (value) { if (!this.integer(value) || Math.abs(value).toString().length > 16) { return false } return true }, file (value) { return typeof value.url === 'string' }, email (value) { return typeof value === 'string' && !!value.match(pattern.email) && value.length < 255 }, url (value) { return typeof value === 'string' && !!value.match(pattern.url) }, pattern (reg, value) { try { return new RegExp(reg).test(value) } catch (e) { return false } }, method (value) { return typeof value === 'function' }, idcard (value) { return typeof value === 'string' && !!value.match(pattern.idcard) }, 'url-https' (value) { return this.url(value) && value.startsWith('https://') }, 'url-scheme' (value) { return value.startsWith('://') }, 'url-web' (value) { return false } } class RuleValidator { constructor (message) { this._message = message } async validateRule (fieldKey, fieldValue, value, data, allData) { var result = null const rules = fieldValue.rules const hasRequired = rules.findIndex((item) => { return item.required }) if (hasRequired < 0) { if (value === null || value === undefined) { return result } if (typeof value === 'string' && !value.length) { return result } } var message = this._message if (rules === undefined) { return message.default } for (var i = 0; i < rules.length; i++) { const rule = rules[i] const vt = this._getValidateType(rule) Object.assign(rule, { label: fieldValue.label || `["${fieldKey}"]` }) if (RuleValidatorHelper[vt]) { result = RuleValidatorHelper[vt](rule, value, message) if (result != null) { break } } if (rule.validateExpr) { const now = Date.now() const resultExpr = rule.validateExpr(value, allData, now) if (resultExpr === false) { result = this._getMessage(rule, rule.errorMessage || this._message.default) break } } if (rule.validateFunction) { result = await this.validateFunction(rule, value, data, allData, vt) if (result !== null) { break } } } if (result !== null) { result = message.TAG + result } return result } async validateFunction (rule, value, data, allData, vt) { let result = null try { let callbackMessage = null const res = await rule.validateFunction(rule, value, allData || data, (message) => { callbackMessage = message }) if (callbackMessage || (typeof res === 'string' && res) || res === false) { result = this._getMessage(rule, callbackMessage || res, vt) } } catch (e) { result = this._getMessage(rule, e.message, vt) } return result } _getMessage (rule, message, vt) { return formatMessage(rule, message || rule.errorMessage || this._message[vt] || message.default) } _getValidateType (rule) { var result = '' if (rule.required) { result = 'required' } else if (rule.format) { result = 'format' } else if (rule.arrayType) { result = 'arrayTypeFormat' } else if (rule.range) { result = 'range' } else if (rule.maximum !== undefined || rule.minimum !== undefined) { result = 'rangeNumber' } else if (rule.maxLength !== undefined || rule.minLength !== undefined) { result = 'rangeLength' } else if (rule.pattern) { result = 'pattern' } else if (rule.validateFunction) { result = 'validateFunction' } return result } } const RuleValidatorHelper = { required (rule, value, message) { if (rule.required && isEmptyValue(value, rule.format || typeof value)) { return formatMessage(rule, rule.errorMessage || message.required) } return null }, range (rule, value, message) { const { range, errorMessage } = rule const list = new Array(range.length) for (let i = 0; i < range.length; i++) { const item = range[i] if (types.object(item) && item.value !== undefined) { list[i] = item.value } else { list[i] = item } } let result = false if (Array.isArray(value)) { result = (new Set(value.concat(list)).size === list.length) } else { if (list.indexOf(value) > -1) { result = true } } if (!result) { return formatMessage(rule, errorMessage || message.enum) } return null }, rangeNumber (rule, value, message) { if (!types.number(value)) { return formatMessage(rule, rule.errorMessage || message.pattern.mismatch) } const { minimum, maximum, exclusiveMinimum, exclusiveMaximum } = rule const min = exclusiveMinimum ? value <= minimum : value < minimum const max = exclusiveMaximum ? value >= maximum : value > maximum if (minimum !== undefined && min) { return formatMessage(rule, rule.errorMessage || message.number[exclusiveMinimum ? 'exclusiveMinimum' : 'minimum' ]) } else if (maximum !== undefined && max) { return formatMessage(rule, rule.errorMessage || message.number[exclusiveMaximum ? 'exclusiveMaximum' : 'maximum' ]) } else if (minimum !== undefined && maximum !== undefined && (min || max)) { return formatMessage(rule, rule.errorMessage || message.number.range) } return null }, rangeLength (rule, value, message) { if (!types.string(value) && !types.array(value)) { return formatMessage(rule, rule.errorMessage || message.pattern.mismatch) } const min = rule.minLength const max = rule.maxLength const val = value.length if (min !== undefined && val < min) { return formatMessage(rule, rule.errorMessage || message.length.minLength) } else if (max !== undefined && val > max) { return formatMessage(rule, rule.errorMessage || message.length.maxLength) } else if (min !== undefined && max !== undefined && (val < min || val > max)) { return formatMessage(rule, rule.errorMessage || message.length.range) } return null }, pattern (rule, value, message) { if (!types.pattern(rule.pattern, value)) { return formatMessage(rule, rule.errorMessage || message.pattern.mismatch) } return null }, format (rule, value, message) { var customTypes = Object.keys(types) var format = FORMAT_MAPPING[rule.format] ? FORMAT_MAPPING[rule.format] : (rule.format || rule.arrayType) if (customTypes.indexOf(format) > -1) { if (!types[format](value)) { return formatMessage(rule, rule.errorMessage || message.typeError) } } return null }, arrayTypeFormat (rule, value, message) { if (!Array.isArray(value)) { return formatMessage(rule, rule.errorMessage || message.typeError) } for (let i = 0; i < value.length; i++) { const element = value[i] const formatResult = this.format(rule, element, message) if (formatResult !== null) { return formatResult } } return null } } class SchemaValidator extends RuleValidator { constructor (schema, options) { super(SchemaValidator.message) this._schema = schema this._options = options || null } updateSchema (schema) { this._schema = schema } async validate (data, allData) { let result = this._checkFieldInSchema(data) if (!result) { result = await this.invokeValidate(data, false, allData) } return result.length ? result[0] : null } async validateAll (data, allData) { let result = this._checkFieldInSchema(data) if (!result) { result = await this.invokeValidate(data, true, allData) } return result } async validateUpdate (data, allData) { let result = this._checkFieldInSchema(data) if (!result) { result = await this.invokeValidateUpdate(data, false, allData) } return result.length ? result[0] : null } async invokeValidate (data, all, allData) { const result = [] const schema = this._schema for (const key in schema) { const value = schema[key] const errorMessage = await this.validateRule(key, value, data[key], data, allData) if (errorMessage != null) { result.push({ key, errorMessage }) if (!all) break } } return result } async invokeValidateUpdate (data, all, allData) { const result = [] for (const key in data) { const errorMessage = await this.validateRule(key, this._schema[key], data[key], data, allData) if (errorMessage != null) { result.push({ key, errorMessage }) if (!all) break } } return result } _checkFieldInSchema (data) { var keys = Object.keys(data) var keys2 = Object.keys(this._schema) if (new Set(keys.concat(keys2)).size === keys2.length) { return '' } var noExistFields = keys.filter((key) => { return keys2.indexOf(key) < 0 }) var errorMessage = formatMessage({ field: JSON.stringify(noExistFields) }, SchemaValidator.message.TAG + SchemaValidator.message.defaultInvalid) return [{ key: 'invalid', errorMessage }] } } function Message () { return { TAG: '', default: '验证错误', defaultInvalid: '提交的字段{field}在数据库中并不存在', validateFunction: '验证无效', required: '{label}必填', enum: '{label}超出范围', timestamp: '{label}格式无效', whitespace: '{label}不能为空', typeError: '{label}类型无效', date: { format: '{label}日期{value}格式无效', parse: '{label}日期无法解析,{value}无效', invalid: '{label}日期{value}无效' }, length: { minLength: '{label}长度不能少于{minLength}', maxLength: '{label}长度不能超过{maxLength}', range: '{label}必须介于{minLength}和{maxLength}之间' }, number: { minimum: '{label}不能小于{minimum}', maximum: '{label}不能大于{maximum}', exclusiveMinimum: '{label}不能小于等于{minimum}', exclusiveMaximum: '{label}不能大于等于{maximum}', range: '{label}必须介于{minimum}and{maximum}之间' }, pattern: { mismatch: '{label}格式不匹配' } } } SchemaValidator.message = new Message() export default SchemaValidator