| | |
| | | <view @tap="evt=>handleOpen(evt)"> |
| | | <AtInput |
| | | ref="input" |
| | | :name="itemData.name" |
| | | :title="itemData.label" |
| | | :required="itemData.required" |
| | | :error="itemData.error" |
| | | :name="itemRes.name" |
| | | :title="itemRes.label" |
| | | :required="itemRes.required" |
| | | :error="itemRes.error" |
| | | :placeholder="placeholder" |
| | | :value="selected" |
| | | > |
| | |
| | | default: false, |
| | | }, |
| | | placeholder: String, |
| | | itemData: Object, |
| | | itemRes: Object, |
| | | }, |
| | | data() { |
| | | return { |
| | |
| | | }, |
| | | computed: { |
| | | selected() { |
| | | const curVal = this.itemData.formData[this.itemData.name]; |
| | | const curVal = this.itemRes.formData[this.itemRes.name]; |
| | | if (curVal && curVal.length === 3) { |
| | | return getRegionNames(curVal).join(' / '); |
| | | } else { |
| | |
| | | evt.preventDefault(); |
| | | return; |
| | | } |
| | | const curVal = this.itemData.formData[this.itemData.name]; |
| | | const curVal = this.itemRes.formData[this.itemRes.name]; |
| | | const range = [ |
| | | locationTree, |
| | | locationTree[0].children, |
| | |
| | | codes[1] = city.value; |
| | | const area = city.children[detail[2]]; |
| | | codes[2] = area.value; |
| | | this.itemData.onChange(codes); |
| | | this.itemRes.onChange(codes); |
| | | }, |
| | | }, |
| | | mounted() {}, |
| | |
| | | class="c-form" |
| | | @submit="evt=>handleSubmit()" |
| | | > |
| | | <slot :formData="formData" /> |
| | | <slot :formRes="formRes" /> |
| | | </form> |
| | | </template> |
| | | |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | formRes: { |
| | | formData: this.formData, |
| | | }, |
| | | validators: {}, |
| | | }; |
| | | }, |
| | |
| | | handleSubmit() { |
| | | const checklist = []; |
| | | Object.keys(this.validators).forEach((key) => { |
| | | checklist.push(this.validators[key]()); |
| | | // 仍有效的验证器 |
| | | if (this.validators[key]) { |
| | | checklist.push(this.validators[key]()); |
| | | } |
| | | }); |
| | | Promise.all(checklist).then((validations) => { |
| | | for (let validation of validations) { |
| | | // 第一个不通过项提示 |
| | | if (!validation.passed) { |
| | | Taro.showToast({ |
| | | title: validation.msg, |
| | |
| | | this.onFinish && this.onFinish(); |
| | | }); |
| | | }, |
| | | preCheckValidators(callback) { |
| | | const checklist = []; |
| | | Object.keys(this.validators).forEach((key) => { |
| | | // 仍有效的验证器 |
| | | if (this.validators[key]) { |
| | | checklist.push(this.validators[key]('msgOnly')); |
| | | } |
| | | }); |
| | | Promise.all(checklist).then((validations) => { |
| | | for (let validation of validations) { |
| | | // 跳过同意协议 |
| | | if (validation.name === '$agreement') { |
| | | continue; |
| | | } |
| | | if (!validation.passed) { |
| | | Taro.showToast({ |
| | | title: validation.msg, |
| | | icon: 'none', |
| | | mask: false, |
| | | duration: 2000, |
| | | }); |
| | | // 检查失败 |
| | | callback && callback(false); |
| | | return; |
| | | } |
| | | } |
| | | // 检查通过 |
| | | callback && callback(true); |
| | | }); |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.formData.$handleChange = (evt = []) => { |
| | | // 当表单项变化时 |
| | | this.formRes.$handleChange = (evt = []) => { |
| | | Object.keys(evt).forEach((key) => { |
| | | if (typeof this.formData[key] === 'undefined') { |
| | | this.$set(this.formData, key, evt[key]); |
| | | // 直接改值 |
| | | if (typeof this.formRes.formData[key] === 'undefined') { |
| | | this.$set(this.formRes.formData, key, evt[key]); |
| | | } else { |
| | | this.formData[key] = evt[key]; |
| | | this.formRes.formData[key] = evt[key]; |
| | | } |
| | | }); |
| | | this.onChange && this.onChange(evt); |
| | | }; |
| | | this.formData.$regItemValidator = (name, cb) => { |
| | | // 注册表单验证器 |
| | | this.formRes.$regItemValidator = (name, cb) => { |
| | | this.validators[name] = cb; |
| | | }; |
| | | }, |
| | |
| | | AtFloatLayout, |
| | | }, |
| | | props: { |
| | | formData: Object, |
| | | formRes: Object, |
| | | protocol: String, |
| | | }, |
| | | data() { |
| | | return { |
| | | name: 'agreement', |
| | | name: '$agreement', |
| | | protocolShow: false, |
| | | checked: false, |
| | | }; |
| | |
| | | }, |
| | | mounted() { |
| | | this.$nextTick(() => { |
| | | this.formData.$regItemValidator(this.name, () => { |
| | | this.formRes.$regItemValidator(this.name, () => { |
| | | if (this.checked) { |
| | | return Promise.resolve({ |
| | | name: this.name, |
| | |
| | | |
| | | <template> |
| | | <view class="c-form-item"> |
| | | <slot :itemData="itemData" /> |
| | | <slot :itemRes="itemRes" /> |
| | | </view> |
| | | </template> |
| | | |
| | |
| | | label: String, |
| | | required: Boolean, |
| | | rules: Array, |
| | | formData: Object, |
| | | formRes: Object, |
| | | }, |
| | | data() { |
| | | return { |
| | |
| | | }; |
| | | }, |
| | | computed: { |
| | | itemData() { |
| | | itemRes() { |
| | | return { |
| | | formData: this.formData, |
| | | formData: this.formRes.formData, |
| | | name: this.name, |
| | | label: this.label, |
| | | required: this.isRequired, |
| | |
| | | } |
| | | } |
| | | // 未改变值不触发 |
| | | if (this.formData[this.name] === evt) { |
| | | if (this.formRes.formData[this.name] === evt) { |
| | | return; |
| | | } |
| | | this.formData.$handleChange({ |
| | | this.formRes.$handleChange({ |
| | | [this.name]: evt, |
| | | }); |
| | | }, |
| | |
| | | this.$nextTick(() => { |
| | | // 未设置验证 |
| | | if (!this.required && !this.rules) { |
| | | this.formData.$regItemValidator(this.name, () => { |
| | | this.formRes.$regItemValidator(this.name, (validateType) => { |
| | | this.error = false; |
| | | return Promise.resolve({ |
| | | name: this.name, |
| | |
| | | validator.messages(validateMsgs); |
| | | // 注册验证 |
| | | let errTimer = null; |
| | | this.formData.$regItemValidator(this.name, () => { |
| | | this.formRes.$regItemValidator(this.name, (validateType) => { |
| | | return validator |
| | | .validate({ |
| | | [this.name]: this.formData[this.name], |
| | | [this.name]: this.formRes.formData[this.name], |
| | | }) |
| | | .then( |
| | | (res) => { |
| | |
| | | }; |
| | | }, |
| | | ({ errors, fields }) => { |
| | | this.error = true; |
| | | clearTimeout(errTimer); |
| | | errTimer = setTimeout(() => { |
| | | this.error = false; |
| | | }, 5000); |
| | | if (validateType !== 'msgOnly') { |
| | | this.error = true; |
| | | clearTimeout(errTimer); |
| | | errTimer = setTimeout(() => { |
| | | this.error = false; |
| | | }, 5000); |
| | | } |
| | | return { |
| | | name: this.name, |
| | | passed: false, |
| | |
| | | }); |
| | | }, |
| | | beforeDestroy() { |
| | | this.formData.$regItemValidator(this.name, null); |
| | | this.formRes.$regItemValidator(this.name, null); |
| | | }, |
| | | }; |
| | | </script> |
| | |
| | | <view class="c-image-picker"> |
| | | <AtInput |
| | | ref="input" |
| | | :name="itemData.name" |
| | | :title="itemData.label" |
| | | :required="itemData.required" |
| | | :error="itemData.error" |
| | | :name="itemRes.name" |
| | | :title="itemRes.label" |
| | | :required="itemRes.required" |
| | | :error="itemRes.error" |
| | | /> |
| | | <AtImagePicker |
| | | ref="picker" |
| | |
| | | AtCurtain, |
| | | }, |
| | | props: { |
| | | itemData: Object, |
| | | itemRes: Object, |
| | | }, |
| | | data() { |
| | | return { |
| | |
| | | }, |
| | | computed: { |
| | | files() { |
| | | const value = this.itemData.formData[this.itemData.name]; |
| | | const value = this.itemRes.formData[this.itemRes.name]; |
| | | let files = []; |
| | | if (Object.prototype.toString.call(value) === '[object String]') { |
| | | files = value.split(',').map((url) => ({ url })); |
| | |
| | | } |
| | | value.push(file.url); |
| | | }); |
| | | this.itemData.onChange(value); |
| | | this.itemRes.onChange(value); |
| | | }, |
| | | handleImgView(index, file) { |
| | | this.curtainImg = file.url; |
| | |
| | | |
| | | <template> |
| | | <AtInput |
| | | :name="itemData.name" |
| | | :title="itemData.label" |
| | | :name="itemRes.name" |
| | | :title="itemRes.label" |
| | | :type="type" |
| | | :placeholder="placeholder" |
| | | :required="itemData.required" |
| | | :error="itemData.error" |
| | | :value="itemData.formData[itemData.name]" |
| | | :onChange="evt=>itemData.onChange(evt)" |
| | | :required="itemRes.required" |
| | | :error="itemRes.error" |
| | | :value="itemRes.formData[itemRes.name]" |
| | | :onChange="evt=>itemRes.onChange(evt)" |
| | | > |
| | | <slot /> |
| | | </AtInput> |
| | |
| | | props: { |
| | | type: String, |
| | | placeholder: String, |
| | | itemData: Object, |
| | | itemRes: Object, |
| | | }, |
| | | mounted() {}, |
| | | }; |
| | | </script> |
| | |
| | | <template> |
| | | <view class="c-input-phone-code"> |
| | | <AtInput |
| | | :name="itemData.name" |
| | | :title="itemData.label" |
| | | :name="itemRes.name" |
| | | :title="itemRes.label" |
| | | type="text" |
| | | :placeholder="placeholder" |
| | | :required="itemData.required" |
| | | :error="itemData.error" |
| | | :value="itemData.formData[itemData.name]" |
| | | :onChange="evt=>itemData.onChange(evt)" |
| | | :required="itemRes.required" |
| | | :error="itemRes.error" |
| | | :value="itemRes.formData[itemRes.name]" |
| | | :onChange="evt=>itemRes.onChange(evt)" |
| | | > |
| | | <AtButton |
| | | class="c-input-phone-btn" |
| | |
| | | }, |
| | | props: { |
| | | placeholder: String, |
| | | itemData: Object, |
| | | itemRes: Object, |
| | | autoStart: { type: Boolean, default: true }, |
| | | onCallPhoneCode: Function, |
| | | }, |
| | | data() { |
| | |
| | | if (this.holding) { |
| | | return; |
| | | } |
| | | this.holding = true; |
| | | this.cd = 60; |
| | | this.onCallPhoneCode(); |
| | | const timer = setInterval(() => { |
| | | this.cd -= 1; |
| | | if (this.cd === 0) { |
| | | this.holding = false; |
| | | this.cd = 60; |
| | | } |
| | | }, 1000); |
| | | const startCD = () => { |
| | | this.holding = true; |
| | | this.cd = 60; |
| | | setInterval(() => { |
| | | this.cd -= 1; |
| | | if (this.cd === 0) { |
| | | this.holding = false; |
| | | this.cd = 60; |
| | | } |
| | | }, 1000); |
| | | }; |
| | | if (this.autoStart) { |
| | | startCD(); |
| | | this.onCallPhoneCode(() => null); |
| | | } else { |
| | | this.onCallPhoneCode(() => { |
| | | startCD(); |
| | | }); |
| | | } |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | > |
| | | <AtInput |
| | | ref="input" |
| | | :name="itemData.name" |
| | | :title="itemData.label" |
| | | :required="itemData.required" |
| | | :error="itemData.error" |
| | | :name="itemRes.name" |
| | | :title="itemRes.label" |
| | | :required="itemRes.required" |
| | | :error="itemRes.error" |
| | | :placeholder="placeholder" |
| | | :value="selected" |
| | | > |
| | |
| | | props: { |
| | | options: Array, |
| | | placeholder: String, |
| | | itemData: Object, |
| | | itemRes: Object, |
| | | }, |
| | | data() { |
| | | return {}; |
| | |
| | | return typeof (this.options[0] || {}).value === 'undefined' ? 'id' : 'value'; |
| | | }, |
| | | current() { |
| | | const curVal = this.itemData.formData[this.itemData.name]; |
| | | const curVal = this.itemRes.formData[this.itemRes.name]; |
| | | for (let i = 0, item; (item = this.options[i]); i++) { |
| | | if (curVal === item[this.optionKey]) { |
| | | return i; |
| | |
| | | return -1; |
| | | }, |
| | | selected() { |
| | | const curVal = this.itemData.formData[this.itemData.name]; |
| | | const curVal = this.itemRes.formData[this.itemRes.name]; |
| | | for (let i = 0, item; (item = this.options[i]); i++) { |
| | | if (curVal === item[this.optionKey]) { |
| | | return item.name; |
| | |
| | | methods: { |
| | | handleChange(evt) { |
| | | const item = this.options[evt.value]; |
| | | this.itemData.onChange(item[this.optionKey]); |
| | | this.itemRes.onChange(item[this.optionKey]); |
| | | }, |
| | | }, |
| | | mounted() {}, |
| | |
| | | <template> |
| | | <view :class="['c-switch', className]"> |
| | | <AtSwitch |
| | | :title="itemData.label" |
| | | :checked="itemData.formData[itemData.name]" |
| | | :onChange="evt=>itemData.onChange(evt)" |
| | | :title="itemRes.label" |
| | | :checked="itemRes.formData[itemRes.name]" |
| | | :onChange="evt=>itemRes.onChange(evt)" |
| | | /> |
| | | </view> |
| | | </template> |
| | |
| | | name: 'CSwitch', |
| | | components: { AtSwitch }, |
| | | props: { |
| | | itemData: Object, |
| | | itemRes: Object, |
| | | }, |
| | | data() { |
| | | return {}; |
| | |
| | | computed: { |
| | | className() { |
| | | let className = ''; |
| | | if (this.itemData.required) { |
| | | if (this.itemRes.required) { |
| | | className += 'c-switch-required '; |
| | | } |
| | | if (this.itemData.error) { |
| | | if (this.itemRes.error) { |
| | | className += 'c-switch-error '; |
| | | } |
| | | return className; |
| | |
| | | <view class="c-textarea"> |
| | | <AtInput |
| | | ref="input" |
| | | :name="itemData.name" |
| | | :title="itemData.label" |
| | | :required="itemData.required" |
| | | :error="itemData.error" |
| | | :name="itemRes.name" |
| | | :title="itemRes.label" |
| | | :required="itemRes.required" |
| | | :error="itemRes.error" |
| | | /> |
| | | <textarea |
| | | ref="textarea" |
| | | class="textarea" |
| | | :style="{height: height || '2rem'}" |
| | | :placeholder="placeholder" |
| | | :value="itemData.formData[itemData.name]" |
| | | :value="itemRes.formData[itemRes.name]" |
| | | :autoFocus="true" |
| | | @input="evt=>itemData.onChange(evt.detail.value)" |
| | | @input="evt=>itemRes.onChange(evt.detail.value)" |
| | | /> |
| | | </view> |
| | | </template> |
| | |
| | | props: { |
| | | height: String, |
| | | placeholder: String, |
| | | itemData: Object, |
| | | itemRes: Object, |
| | | }, |
| | | data() { |
| | | return {}; |