-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
513 additions
and
235 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import Emitter from './emitter'; | ||
import {getPropByPath} from './utils'; | ||
import AsyncValidator, {ValidateRule} from 'async-validator'; | ||
import debounce from 'lodash.debounce'; | ||
import Component from 'vue-class-component'; | ||
import {Inject, Prop, Watch} from 'vue-property-decorator'; | ||
|
||
|
||
const noop = function noop(a?, b?) { | ||
}; | ||
|
||
@Component({ | ||
name: 'FormComponent' | ||
}) | ||
export class FormComponent extends Emitter { | ||
|
||
/** | ||
* class 前缀 | ||
*/ | ||
@Prop({type: String}) | ||
public prefixCls?: string; | ||
@Prop({type: Boolean}) | ||
public disabled: boolean; | ||
@Prop({type: Boolean, default: false}) | ||
public error: boolean; | ||
@Prop({type: String}) | ||
public errorMessage: string; | ||
public currentErrorMessage = this.errorMessage; | ||
public isCurrentError = this.error; | ||
@Inject({from: 'list', default: undefined}) | ||
public list: any; | ||
@Prop({type: String}) | ||
public prop: string; | ||
@Prop({type: Boolean}) | ||
public readOnly: boolean; | ||
/** | ||
* 是否必须 | ||
*/ | ||
@Prop({type: Boolean, default: false}) | ||
public required: boolean; | ||
@Prop({type: Array}) | ||
public rules: ValidateRule[]; | ||
public validateStatus: '' | 'success' | 'warning' | 'error' | 'validating' = ''; | ||
@Prop() | ||
public value: any; | ||
public currentValue = this.value; | ||
private validateDisabled: boolean = true; | ||
|
||
get fieldValue() { | ||
return this.currentValue; | ||
} | ||
|
||
get errorIcon() { | ||
return this.isCurrentError ? ( | ||
<div | ||
class={`${this.prefixCls}-error-extra`} | ||
onClick={(e) => { | ||
if (this.currentErrorMessage && this.$toast) { | ||
this.$toast.info(this.currentErrorMessage); | ||
} | ||
this.$emit('error-click', e); | ||
}} | ||
/> | ||
) : null; | ||
} | ||
|
||
get isDisabled() { | ||
let disabled = this.disabled; | ||
if (this.list) { | ||
if (!disabled) { | ||
disabled = this.list.disabled; | ||
} | ||
} | ||
return disabled; | ||
} | ||
|
||
get isReadonly() { | ||
let isReadonly = this.readOnly; | ||
if (this.list) { | ||
if (!isReadonly) { | ||
isReadonly = this.list.readOnly; | ||
} | ||
} | ||
return isReadonly; | ||
} | ||
|
||
public created() { | ||
if (this.list) { | ||
this.dispatch('DForm', 'd.form.addField', [this]); | ||
} | ||
this.validate = debounce(this.validate, 300); | ||
} | ||
|
||
@Watch('error') | ||
public errorChanged(error: boolean) { | ||
this.isCurrentError = error; | ||
} | ||
|
||
@Watch('errorMessage') | ||
public errorMessageChanged(errorMessage: string) { | ||
this.currentErrorMessage = errorMessage; | ||
} | ||
|
||
public getFilteredRule(trigger) { | ||
const rules = this.getRules(); | ||
return rules.filter(rule => { | ||
if (!rule.trigger || trigger === '') { | ||
return true; | ||
} | ||
if (Array.isArray(rule.trigger)) { | ||
return rule.trigger.indexOf(trigger) > -1; | ||
} else { | ||
return rule.trigger === trigger; | ||
} | ||
}).map(rule => Object.assign({}, rule)); | ||
} | ||
|
||
public getRules(): ValidateRule[] { | ||
let formRules: any = this.list && this.list.rules; | ||
const prop = getPropByPath(formRules, this.prop || ''); | ||
formRules = formRules ? (prop.o[this.prop || ''] || prop.v) : []; | ||
const selfRules = this.rules; | ||
let requiredRule = this.required !== undefined ? {required: this.required} : []; | ||
if ((formRules && formRules.some(rule => rule.required !== undefined)) | ||
|| (selfRules && selfRules.some(rule => rule.required !== undefined))) { | ||
requiredRule = []; | ||
} | ||
return [].concat(selfRules || formRules || []).concat(requiredRule); | ||
} | ||
|
||
public onFieldBlur() { | ||
this.validate('blur'); | ||
} | ||
|
||
public onFieldChange() { | ||
if (this.validateDisabled) { | ||
this.validateDisabled = false; | ||
return; | ||
} | ||
this.validate('change'); | ||
} | ||
|
||
public validate(trigger, callback = noop) { | ||
this.$nextTick(() => { | ||
this.validateDisabled = false; | ||
const rules = this.getFilteredRule(trigger); | ||
if ((!rules || rules.length === 0) && this.required === undefined) { | ||
callback(); | ||
return true; | ||
} | ||
this.validateStatus = 'validating'; | ||
const descriptor = {}; | ||
if (rules && rules.length > 0) { | ||
rules.forEach(rule => { | ||
delete rule.trigger; | ||
}); | ||
} | ||
descriptor[this.prop] = rules; | ||
const validator = new AsyncValidator(descriptor); | ||
const model = { | ||
[this.prop]: this.fieldValue | ||
}; | ||
validator.validate(model, {firstFields: true}, (errors, invalidFields) => { | ||
this.validateStatus = !errors ? 'success' : 'error'; | ||
this.isCurrentError = this.validateStatus === 'error'; | ||
this.currentErrorMessage = errors ? errors[0].message : ''; | ||
callback(this.currentErrorMessage, invalidFields); | ||
this.$emit('validate', !errors, errors); | ||
this.list && this.list.$emit('validate', this.prop, !errors, this.currentErrorMessage || null); | ||
}); | ||
}); | ||
} | ||
|
||
@Watch('value') | ||
public valueChanged(value: any) { | ||
this.currentValue = value; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
export const getPropByPath = function getPropByPath(obj, path, strict?) { | ||
let tempObj = obj; | ||
let copyPath = path; | ||
copyPath = copyPath.replace(/\[(\w+)]/g, '.$1'); | ||
copyPath = copyPath.replace(/^\./, ''); | ||
|
||
const keyArr = copyPath.split('.'); | ||
let i = 0; | ||
for (const len = keyArr.length; i < len - 1; ++i) { | ||
if (!tempObj && !strict) { | ||
break; | ||
} | ||
const key = keyArr[i]; | ||
if (key in tempObj) { | ||
tempObj = tempObj[key]; | ||
} else { | ||
if (strict) { | ||
throw new Error('please transfer a valid prop path to form item!'); | ||
} | ||
break; | ||
} | ||
} | ||
return { | ||
o: tempObj, | ||
k: keyArr[i], | ||
v: tempObj ? tempObj[keyArr[i]] : null | ||
}; | ||
}; | ||
|
||
export const noop = function noop(a?, b?) { | ||
}; |
Oops, something went wrong.