import get from 'lodash/get' import moment from 'moment' /** * 表单数据处理相关方法 * (配合 使用,注意本工具类不包含拉取表单数据的代码) * * 提供以下工具方法: * * 【新建表单时使用】: * async getDefaultData(schemeItem, { processId }) * 获取单个表单项的默认数据 * * 【打开一个表单时使用】: * async getSourceData(schemeItem) * 获取表单中的选单数据 / 获取单条表单项的选单数据 * * async convertToFormValue(schemeItem, val) * 将从 API 拉取的表单数据格式化规范化 * * 【提交表单时使用】: * async convertToPostData(schemeItem, val, formValue, scheme) * 将本地表单数据格式化为提交时的格式 */ export default { methods: { /** * 获取一个 scheme 表单项的源数据 (加载表单时使用) * 参数: 单个 schemeItem * * radio、select、checkbox、layer 这四种表单项,需要加载额外的选单数据 * 选单数据有两种获取方式: * 1、来自数据字典: * 数据字典在 this.GET_GLOBAL('dataDictionary') * 表单使用的字段在 schemeItem.itemCode * 选单数据中的 text 字段作为显示, value 字段作为值 * * 2、来自数据源: * 将 schemeItem.dataSourceId 按符号「,」逗号分割为数组,分割为: [code, displayField, valueField] * 数据源需要请求 API 来获取,请求需要带上数据源的编号 code * displayField、valueField 分别为展示字段和值绑定字段 * * 选单数据有两种格式: * 1、对于 radio、select、checkbox 来说: * 只需要一个数组,数组形如: [{ text: '选项文字', value: '选项值' }, ...] * 将获取的数据绑定到组件的 range 属性上即可 * 全局数据中默认是对象形式,使用 Object.values() 转化即可 * * 2、对于 layer 来说: * 返回一个对象,形如 { source, layerData, selfField } * source: 为弹层中列出的数据,是一个数组 * layerData: 需要在弹层窗口中展示的字段及标题文字,形如: [{ name:'要展示的字段名', label:'标题文字' }] * selfField: 该表单值绑定哪个字段,默认为绑定到自身的字段 */ async getSourceData(schemeItem) { if (['radio', 'select', 'checkbox'].includes(schemeItem.type)) { // radio select checkbox 三种情况 if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) { // dataSource 为 0,使用 clientData return Object .values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode]) .map(t => ({ value: t.value, text: t.text })) } else { // dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段 const [code, displayField = schemeItem.showField, valueField = schemeItem.saveField] = schemeItem.dataSourceId .split(',') const sourceData = await this.FETCH_DATASOURCE(code) if (!sourceData) { return [] } return sourceData.data.map(t => ({ text: t[displayField], value: t[valueField] })) } } else if (['layer'].includes(schemeItem.type)) { // layer 需要更多属性 if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) { // dataSource 为 0,使用 clientData // clientData 对象转数组后,隐含 key:item.text 和 value:item.value 的关系 const [keyItem, valueItem] = schemeItem.layerData const source = Object .values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode]) .map(t => ({ value: t.value, text: t.text })) return { source, layerData: [{ name: 'text', label: keyItem.label || '', value: keyItem.value || '' }, { name: 'value', label: valueItem.label || '', value: valueItem.value || '' } ] } } else { // dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段 const [code] = schemeItem.dataSourceId.split(',') const sourceData = await this.FETCH_DATASOURCE(code) if (!sourceData) { return [] } const source = sourceData.data return { source, layerData: schemeItem.layerData.filter(t => (!t.hide) && (t.value || t.label)) } } } return [] }, /** * 获取一个 scheme 表单项的默认值 (用户新建表单时使用,或是编辑草稿) * 参数: 单个 schemeItem , { processId } * * 每种类别的表单项分别获取的默认值: * * currentInfo: 根据类别取当前用户/部门/公司/时间日期 * datetime: 根据 dfValue 字段表示昨天/今天/明天,格式化为字符串 * radio、select: 有 dfValue 则使用,否则取第一条 * checkbox: 有 dfValue 则使用,否则为空数组 * encode: 根据 rulecode 请求表单编码 * upload: 空数组 * guid: 赋值第二个参数中的 processId,但是如果在子表格中,赋空字符串 * girdtable: 递归所有表格项 scheme 依次为它们生成默认值 * datetimerange: 字符串 0 */ async getDefaultData(item, prop) { const { processId } = prop switch (item.type) { case 'currentInfo': switch (item.dataType) { case 'user': return this.GET_GLOBAL('loginUser').userId case 'department': return this.GET_GLOBAL('loginUser').departmentId case 'company': return this.GET_GLOBAL('loginUser').companyId case 'time': return moment().format('YYYY-MM-DD HH:mm:ss') default: return '' } case 'datetime': const datetimeFormat = item.table ? (Number(item.dateformat) === 0 ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss') : (item.datetime === 'datetime' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD') const today = moment() const dfDatetime = [ today.subtract(1, 'day'), today, today.add(1, 'day') ][Number(item.dfvalue)] || today return dfDatetime.format(datetimeFormat) || '' case 'radio': case 'select': const radioItem = item.__sourceData__.find(t => t.value === item.dfvalue) || item .__sourceData__[0] return item.type === 'radio' ? radioItem.value : '' case 'checkbox': if (!item.dfvalue) { return [] } return item.dfvalue.split(',').filter(t => item.__sourceData__.find(s => s.value === t)) case 'encode': const result = await this.FETCH_ENCODE(item.rulecode) return result case 'upload': return [] case 'guid': return item.table ? processId : '' case 'girdtable': const tableItemObj = {} for (const fieldItem of item.fieldsData) { tableItemObj[fieldItem.field] = await this.getDefaultData(fieldItem, prop) } return this.COPY(tableItemObj) case 'datetimerange': return '0' default: return item.dfvalue || '' } }, /** * 将单条 formData 值转化为 formValue 值 (拉取表单数据时使用) * 参数: 单个 schemeItem , 数据值 * * 具体执行逻辑: * radio、select: 剔除无效值 * checkbox: 分割成数组并剔除无效值 * upload: 分割成数组,拉取其中所有文件的信息 * datetime: 按照时间日期格式进行格式化字符串 * 其他类型: 保留原值 */ async convertToFormValue(item, val) { switch (item.type) { case 'upload': if (!val) { return [] } const uidList = val; const fileList = [] const wxlist = await this.FETCH_FILEList(uidList); for (const wxfile of wxlist) { const fileInfo = await this.FETCH_FILEINFO(wxfile.F_Id) if (!fileInfo) { continue } const fileType = fileInfo.F_FileType const fileSize = fileInfo.F_FileSize const fileName = fileInfo.F_FileName const path = this.API + '/learun/adms/annexes/wxdown?' + this.URL_QUERY(wxfile.F_Id, true) fileList.push({ path, type: fileType, uid:wxfile.F_Id, folderId:wxfile.F_FolderId, size: fileSize, name:fileName }) } return fileList case 'select': case 'radio': if (!val || !item.__sourceData__.map(t => t.value).includes(val)) { return '' } return val case 'checkbox': const validValue = item.__sourceData__.map(t => t.value) const checkboxVal = val.split(',') || [] return checkboxVal.filter(t => validValue.includes(t)) case 'datetime': if (!val) { return '' } return moment(val).format( Number(item.dateformat) === 0 || item.datetime === 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss' ) default: return val || '' } }, /** * 将一个 formValue 值转化为 post 提交值(提交表单数据时使用) * 参数: 单个 schemeItem , 表单项值 , 所有 formValue , scheme * * 具体执行逻辑: * checkbox: 将数组使用符号「,」逗号拼接成字符串 * datetimerange: 获取开始日期、结束日期,计算差值天数并保留整数 * datetime: 格式化为完整时间日期字符串 * upload: 依次上传文件,将返回的文件 ID 使用符号「,」逗号拼接成字符串 * 其他类型: 保留原值 */ async convertToPostData(item, val, formValue, scheme, guid) { switch (item.type) { case 'checkbox': return val ? val.join(',') : '' case 'datetimerange': const startTime = get(formValue, scheme.find(t => t.id === item.startTime).__valuePath__, null) const endTime = get(formValue, scheme.find(t => t.id === item.endTime).__valuePath__, null) if (!startTime || !endTime || moment(endTime).isBefore(startTime)) { return '' } else { return moment.duration(moment(endTime).diff(moment(startTime))).asDays().toFixed(0) } case 'datetime': return val ? moment(val).format('YYYY-MM-DD HH:mm:ss') : '' case 'upload': var uploadUid = ''; for (const item of val) { if (item.folderId) { uploadUid = item.folderId continue } const fileId = await this.HTTP_UPLOAD(item.path || item, undefined, guid || '') if (fileId) { uploadUid = fileId; } } return uploadUid; default: return val || '' } } } }