292 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| // components/dynamicForm/index.js
 | |
| import formatTime from './utils/formatTime';
 | |
| 
 | |
| Component({
 | |
|   /**
 | |
|    * 组件的属性列表
 | |
|    */
 | |
|   properties: {
 | |
|     formData: Array,
 | |
|     showSubmitBtn: {
 | |
|       type: Boolean,
 | |
|       value: true
 | |
|     },
 | |
|     toSubmit: Number
 | |
|   },
 | |
|   //监听数据变化, 当toSubmit 值变化时, 代表父组件点击提交案例事件
 | |
|   observers: {
 | |
|     'toSubmit': function (e) {
 | |
|       if (e) {
 | |
|         this.formSubmit();
 | |
|       }
 | |
|     },
 | |
|     'formData': function () {
 | |
|       this.formInit();
 | |
|     }
 | |
|   },
 | |
|   /**
 | |
|    * 组件的初始数据
 | |
|    */
 | |
|   data: {
 | |
|     pickerMap: {},
 | |
|     fileMap: {},
 | |
|     inputMap: {}
 | |
|   },
 | |
|   lifetimes: {
 | |
|     attached: function () {
 | |
|       this.formInit();
 | |
|     },
 | |
|     moved: function () { },
 | |
|     detached: function () { },
 | |
|   },
 | |
|   pageLifetimes: {
 | |
|     // 组件所在页面的生命周期函数
 | |
|     show: function () { },
 | |
|     hide: function () { },
 | |
|     resize: function () { },
 | |
|   },
 | |
|   /**
 | |
|    * 组件的方法列表
 | |
|    */
 | |
|   methods: {
 | |
|     //表单初始化
 | |
|     formInit() {
 | |
| 
 | |
|       const pickerMap = {}, fileMap = {}, inputMap = {}, dateMap = {};//存储各表单变化后的值,表单id为索引
 | |
|       const pickers = [], files = [], inputs = [], datePickers = [];
 | |
|       this.data.formData.forEach(val => {
 | |
|         switch (val.type) {
 | |
|           case 'picker':
 | |
|             pickers.push(val);
 | |
|             break;
 | |
|           case 'file':
 | |
|             files.push(val);
 | |
|             break;
 | |
|           case 'input':
 | |
|           case 'textarea':
 | |
|             inputs.push(val);
 | |
|             break;
 | |
|           case 'date':
 | |
|             datePickers.push(val);
 | |
|             break;
 | |
|           default:
 | |
|             break;
 | |
|         }
 | |
|       });
 | |
|       pickers.forEach(val => {
 | |
|         pickerMap[val.id] = {
 | |
|           original: val,
 | |
|           hasChoose: val.defaultIdx != 'undefined',
 | |
|           error:null,
 | |
|           idx: val.defaultIdx || 0
 | |
|         };
 | |
|       });
 | |
|       files.forEach(val => {
 | |
|         fileMap[val.id] = {
 | |
|           original: val,
 | |
|           error: null,
 | |
|           list: val.fileList
 | |
|         };
 | |
|       });
 | |
|       inputs.forEach(val => {
 | |
|         inputMap[val.id] = {
 | |
|           original: val,
 | |
|           value: val.defaultValue || '',
 | |
|           placeholder: val.placeholder,
 | |
|           error: null,
 | |
|           rules: val.rules ? val.rules.map(val => {
 | |
|             val.regular = new RegExp(val.regular);
 | |
|             return val;
 | |
|           }) : []
 | |
|         };
 | |
|       });
 | |
|       datePickers.forEach(val => {
 | |
|         dateMap[val.id] = {
 | |
|           original: val,
 | |
|           config: val.config,
 | |
|           completeTime: val.completeTime,
 | |
|           show: false,
 | |
|           hasChoose: !!val.config.initStartTime,
 | |
|           error: null,
 | |
|           startDate: val.config.initStartTime || formatTime(),
 | |
|           endDate: val.config.initEndTime || formatTime()
 | |
|         };
 | |
|         if (!val.completeTime){
 | |
|           dateMap[val.id].startDate = dateMap[val.id].startDate.split(' ')[0];
 | |
|           dateMap[val.id].endDate = dateMap[val.id].endDate.split(' ')[0];
 | |
|         }
 | |
|       });
 | |
|       this.setData({
 | |
|         pickers,
 | |
|         inputs,
 | |
|         datePickers,
 | |
|         files,
 | |
|         pickerMap,
 | |
|         inputMap,
 | |
|         fileMap,
 | |
|         dateMap
 | |
|       });
 | |
|     },
 | |
|     //提交表单
 | |
|     formSubmit() {
 | |
|       let formData = {};
 | |
|       const { pickerMap, inputMap, dateMap, fileMap } = this.data;
 | |
|       for (let i in this.data) { //获取表单数据后缀为Map
 | |
|         if (i.match(/Map$/)) {
 | |
|           formData = Object.assign({}, formData, this.data[i]);
 | |
|         }
 | |
|       }
 | |
|       let hasError = false;
 | |
|       for (let i in formData) {//循环验证所有表单数据规则
 | |
|         let info = formData[i];
 | |
|         if (info.original.type === 'input' || info.original.type === 'textarea') {
 | |
|           if (!info.value){
 | |
|             if (info.original.isRequired){
 | |
|               info.error = info.original.lable + '不可为空';
 | |
|               hasError = true;
 | |
|             }
 | |
|           } else if (info.rules){
 | |
|             for (let val of info.rules) {
 | |
|               if (!info.value.match(val.regular)) {
 | |
|                 info.error = val.tips || '格式有误';
 | |
|                 hasError = true;
 | |
|                 break;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           this.setData({
 | |
|             [`inputMap.${i}`]: info
 | |
|           });
 | |
|         } else if (info.original.type === 'file') {
 | |
|           if (info.list.length === 0 && info.original.isRequired) {
 | |
|             let error = '请选择文件';
 | |
|             if (info.original.accept === 'video') {
 | |
|               error = '请选择视频';
 | |
|             } else if (info.original.accept === 'image') {
 | |
|               error = '请选择图片';
 | |
|             }
 | |
|             info.error = error;
 | |
|             hasError = true;
 | |
|             this.setData({
 | |
|               [`fileMap.${i}`]: info
 | |
|             });
 | |
|           }
 | |
|         } else if (info.original.type === 'picker' || info.original.type === 'date'){
 | |
|           if (!info.hasChoose && info.original.isRequired){
 | |
|             info.error = '请选择' + info.original.lable;
 | |
|             hasError = true;
 | |
|             this.setData({
 | |
|               [`${info.original.type}Map.${i}`]: info
 | |
|             });
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       if (hasError) {
 | |
|         wx.showToast({
 | |
|           title: '表单填写有误',
 | |
|           icon: 'none'
 | |
|         });
 | |
|         return;
 | |
|       }
 | |
|       this.triggerEvent('dynamicFormSubmit', formData);
 | |
|       console.log(formData);
 | |
| 
 | |
|     },
 | |
|     //更新数据劫持
 | |
|     updateData(key,val){
 | |
|       this.setData({
 | |
|         [key]: val
 | |
|       });
 | |
|       this.triggerEvent('dynamicFormChange', { key, val});
 | |
|     },
 | |
|     //显示选择器
 | |
|     datePickerShow(e) {
 | |
|       if (e.target.dataset.disabled) {
 | |
|         return;
 | |
|       }
 | |
|       this.setData({
 | |
|         [`dateMap.${e.target.dataset.id}.show`]: true
 | |
|       });
 | |
|     },
 | |
|     //隐藏时间选择器
 | |
|     datePickerHide(id) {
 | |
|       if (typeof id === 'object') {
 | |
|         id = id.target.id;
 | |
|       }
 | |
|       this.setData({
 | |
|         [`dateMap.${id}.show`]: false
 | |
|       });
 | |
|     },
 | |
|     //设置选择器时间
 | |
|     setPickerTime(e) {
 | |
|       const {dateMap} = this.data;
 | |
|       const { startTime, endTime } = e.detail;
 | |
|       const date = dateMap[e.target.id];
 | |
|       if (!date.hasChoose){
 | |
|         date.hasChoose = true;
 | |
|         date.error = null;
 | |
|       }
 | |
|       date.show = false;
 | |
|       date.startDate = date.completeTime ? startTime :startTime.split(' ')[0];
 | |
|       date.endDate = date.completeTime ?endTime :endTime.split(' ')[0];
 | |
|       this.updateData(`dateMap.${e.target.id}`,date);
 | |
|     },
 | |
|     //输入框
 | |
|     onInput(e) {
 | |
|       const { value } = e.detail;
 | |
|       const info = this.data.inputMap[e.target.id] || {};
 | |
|       if (!info) {
 | |
|         return;
 | |
|       }
 | |
|       info.value = e.detail.value;
 | |
|       info.error = null;
 | |
|       if (info.rules && info.value) {
 | |
|         for (let val of info.rules) {
 | |
|           if (!info.value.match(val.regular)) {
 | |
|             info.error = val.tips || '格式有误';
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       this.updateData(`inputMap.${e.target.id}`, info);
 | |
|     },
 | |
|     //picker选择
 | |
|     onPickerChange(e) {
 | |
|       const { id } = e.target;
 | |
|       const picker = this.data.pickerMap[id];
 | |
|       if(!picker.hasChoose){
 | |
|         picker.hasChoose = true;
 | |
|         picker.error = null;
 | |
|       }
 | |
|       picker.idx = e.detail.value;
 | |
|       picker.data = this.data.pickers.filter(val => val.id === id)[0].range[e.detail.value];
 | |
|       this.updateData(`pickerMap.${e.target.id}`, picker);
 | |
|     },
 | |
|     // 选择文件
 | |
|     onFileRead(e) {
 | |
|       console.log(e);
 | |
|       for (let val of e.detail.file) {
 | |
|         const size = this.data.fileMap[e.target.id].original.maxSize;
 | |
|         if (val.size > size * 1024 * 1024) {
 | |
|           wx.showToast({
 | |
|             title: `请选择${size}MB以内的文件`,
 | |
|             icon: 'none'
 | |
|           });
 | |
|           return;
 | |
|         }
 | |
|       }
 | |
|       const files = this.data.fileMap[e.target.id];
 | |
|       files.error = null;
 | |
|       files.list = files.list.concat(e.detail.file);
 | |
|       this.updateData(`fileMap.${e.target.id}`, files);
 | |
|     },
 | |
|     //删除文件
 | |
|     onFileDelete(e) {
 | |
|       console.log(e);
 | |
|       const files = this.data.fileMap[e.target.id].list;
 | |
|       files.splice(e.detail.index, 1);
 | |
|       this.updateData(`fileMap.${e.target.id}.list`, files);
 | |
|     }
 | |
|   }
 | |
| });
 |