veui
Version:
Baidu Enterprise UI for Vue.js.
271 lines (252 loc) • 8.35 kB
JavaScript
import { reduce, forEach, isPlainObject } from 'lodash'
import Vue from 'vue'
export const ValidityStatus = {
SUCCESS: 'success',
WARNING: 'warning',
ERROR: 'error'
}
const ValidityStatusOrder = {
[ValidityStatus.SUCCESS]: 3,
[ValidityStatus.WARNING]: 2,
[ValidityStatus.ERROR]: 1
}
function createValidityMixinImpl () {
return new Vue({
data () {
return {
ruleValidities: {}, // Record<fieldName, Array<{status, name: ruleName, message}>>
validatorValidities: {}, // Record<validatorName, {fieldName1: message, fieldName2: message2}>
inputValidities: {} // Record<fieldName, Array<{status, message}>>
}
},
computed: {
validities () {
// => Record<fieldName, [{message}]>
let result = reduce(
this.validatorValidities,
(acc, validities) => {
forEach(validities, (fieldValidities, fieldName) => {
acc[fieldName] = (acc[fieldName] || []).concat(fieldValidities)
})
return acc
},
{}
)
result = mergeValidities(result, this.ruleValidities)
result = sortValidities(mergeValidities(result, this.inputValidities))
const msgMap = {}
forEach(result, (validities, fieldName) => {
result[fieldName] = validities.filter(({ message }) => {
if (!msgMap[fieldName]) {
msgMap[fieldName] = [message]
return true
}
const seen = msgMap[fieldName].indexOf(message) >= 0
if (!seen) {
msgMap[fieldName].push(message)
}
return !seen
})
})
return result
}
},
methods: {
/**
* @public
* 获取指定字段的校验信息
* @param {Array<string> | string} fields 指定字段
* @return Array<Validity>
*/
getValidities (fields) {
fields = Array.isArray(fields) ? fields : [fields]
return fields.reduce((acc, name) => {
const validity = this.validities[name]
if (validity) {
return acc.concat(
validity.map((item) => ({ ...item, fieldName: name }))
)
}
return acc
}, [])
},
getRuleValidities (fieldName) {
return this.ruleValidities[fieldName]
},
/**
* 更新 rule 校验结果
* @param {Array<string> | string} fieldName 指定字段
* @param {undefined | Array<string>} ruleNames undefined 表示要更新该字段的所有 rules
* @param {true | undefined | Array<Validity>} validities true 和 undefined 表示校验成功
*/
updateRuleValidities (fieldName, ruleNames, validities) {
if (ruleNames && ruleNames.length) {
const prev = (this.ruleValidities[fieldName] || []).filter(
({ name }) => ruleNames.indexOf(name) === -1
)
// TODO 以前也没有保证顺序
validities = Array.isArray(validities)
? [...validities, ...prev]
: prev
if (!validities.length) {
validities = null
}
}
if (validities && validities.length) {
this.$set(this.ruleValidities, fieldName, validities)
} else if (this.ruleValidities[fieldName] != null) {
this.$delete(this.ruleValidities, fieldName)
}
},
updateValidatorValidities (validatorName, validities) {
if (validities && Object.keys(validities).length) {
this.$set(this.validatorValidities, validatorName, validities)
} else if (this.validatorValidities[validatorName] != null) {
this.$delete(this.validatorValidities, validatorName)
}
},
updateInputValidities (fieldName, validities) {
if (isPlainObject(validities)) {
validities = [validities]
}
if (Array.isArray(validities)) {
this.$set(this.inputValidities, fieldName, validities)
} else if (this.inputValidities[fieldName] != null) {
this.$delete(this.inputValidities, fieldName)
}
},
// 删掉指定 field 的指定 validity
clearValiditiesOfFields (fieldNames) {
fieldNames.forEach((fieldName) => {
this.$delete(this.ruleValidities, fieldName)
this.$delete(this.inputValidities, fieldName)
})
Object.keys(this.validatorValidities).forEach((validatorName) => {
let validity = this.validatorValidities[validatorName]
fieldNames.forEach((fieldName) => {
if (validity[fieldName]) {
if (Object.keys(validity).length === 1) {
this.$delete(this.validatorValidities, validatorName)
} else {
this.$delete(validity, fieldName)
}
}
})
})
},
clearValidities (fieldNames) {
if (fieldNames) {
return this.clearValiditiesOfFields(fieldNames)
}
this.ruleValidities = {}
this.validatorValidities = {}
this.inputValidities = {}
}
}
})
}
export default function useValidity (namespace) {
return {
computed: {
[namespace] () {
const impl = createValidityMixinImpl()
return {
getValidities: () => impl.validities,
getValiditiesOf: impl.getValidities,
clearValidities: impl.clearValidities,
updateRuleValidities: impl.updateRuleValidities,
updateValidatorValidities: impl.updateValidatorValidities,
updateInputValidities: impl.updateInputValidities
}
}
}
}
}
function mergeValidities (dest, validities) {
return reduce(
validities,
(acc, fieldValidities, fieldName) => {
acc[fieldName] = (acc[fieldName] || []).concat(fieldValidities)
return acc
},
dest
)
}
function sortValidities (validities) {
forEach(validities, (fieldValidities) => {
fieldValidities.sort(
(a, b) => ValidityStatusOrder[a.status] - ValidityStatusOrder[b.status]
)
})
return validities
}
/*
* type SimpleSuccess = true | null | undefined
* type RuleResultSingle = SimpleSuccess | string | {status: ValidityStatus, message?: string}
* type RuleResult = RuleResultSingle | Array<RuleResultSingle>
* type ValidatorResult = SimpleSuccess | Record<fieldNameString, RuleResult>
*/
export function isSimpleValid (validity) {
return validity === true || validity == null
}
function normalize (value) {
if (isSimpleValid(value)) {
return true
}
let result = value
if (!isPlainObject(value)) {
result = { message: value || '' }
}
result.status = result.status || ValidityStatus.ERROR
return result
}
/**
* normalize 一个 field 的校验结果
* @param {RuleResult} value 校验结果
* @return true | Array<{status: ValidityStatus, message?: string}>
*/
export function normalizeValidities (value) {
if (Array.isArray(value)) {
return value.reduce((acc, val) => {
const itemResult = normalize(val)
if (itemResult !== true) {
acc.push(itemResult)
}
return acc
}, [])
}
value = normalize(value)
return value === true ? value : [value]
}
export function normalizeValiditiesOfFields (validitiesOfFields) {
if (isPlainObject(validitiesOfFields)) {
return Object.keys(validitiesOfFields).reduce((acc, fieldName) => {
const fieldResult = normalizeValidities(validitiesOfFields[fieldName])
if (fieldResult !== true) {
acc[fieldName] = fieldResult
}
return acc
}, {})
}
return isSimpleValid(validitiesOfFields)
}
export function isValid (normalizedValidities) {
if (typeof normalizedValidities === 'boolean') {
return normalizedValidities
}
if (Array.isArray(normalizedValidities)) {
return normalizedValidities.every(isValid)
}
if (isPlainObject(normalizedValidities)) {
return normalizedValidities.status !== ValidityStatus.ERROR
}
// never
}
export function isAllValid (normalizedValiditiesOfFields) {
if (isPlainObject(normalizedValiditiesOfFields)) {
return Object.keys(normalizedValiditiesOfFields).every((k) =>
isValid(normalizedValiditiesOfFields[k])
)
}
return isSimpleValid(normalizedValiditiesOfFields)
}