您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

334 行
10 KiB

  1. import get from 'lodash/get'
  2. import moment from 'moment'
  3. /**
  4. * 表单数据处理相关方法
  5. * (配合 <l-customform> 使用,注意本工具类不包含拉取表单数据的代码)
  6. *
  7. * 提供以下工具方法:
  8. *
  9. * 【新建表单时使用】:
  10. * async getDefaultData(schemeItem, { processId })
  11. * 获取单个表单项的默认数据
  12. *
  13. * 【打开一个表单时使用】:
  14. * async getSourceData(schemeItem)
  15. * 获取表单中的选单数据 / 获取单条表单项的选单数据
  16. *
  17. * async convertToFormValue(schemeItem, val)
  18. * 将从 API 拉取的表单数据格式化规范化
  19. *
  20. * 【提交表单时使用】:
  21. * async convertToPostData(schemeItem, val, formValue, scheme)
  22. * 将本地表单数据格式化为提交时的格式
  23. */
  24. export default {
  25. methods: {
  26. /**
  27. * 获取一个 scheme 表单项的源数据 (加载表单时使用)
  28. * 参数: 单个 schemeItem
  29. *
  30. * radio、select、checkbox、layer 这四种表单项,需要加载额外的选单数据
  31. * 选单数据有两种获取方式:
  32. * 1、来自数据字典:
  33. * 数据字典在 this.GET_GLOBAL('dataDictionary')
  34. * 表单使用的字段在 schemeItem.itemCode
  35. * 选单数据中的 text 字段作为显示, value 字段作为值
  36. *
  37. * 2、来自数据源:
  38. * 将 schemeItem.dataSourceId 按符号「,」逗号分割为数组,分割为: [code, displayField, valueField]
  39. * 数据源需要请求 API 来获取,请求需要带上数据源的编号 code
  40. * displayField、valueField 分别为展示字段和值绑定字段
  41. *
  42. * 选单数据有两种格式:
  43. * 1、对于 radio、select、checkbox 来说:
  44. * 只需要一个数组,数组形如: [{ text: '选项文字', value: '选项值' }, ...]
  45. * 将获取的数据绑定到组件的 range 属性上即可
  46. * 全局数据中默认是对象形式,使用 Object.values() 转化即可
  47. *
  48. * 2、对于 layer 来说:
  49. * 返回一个对象,形如 { source, layerData, selfField }
  50. * source: 为弹层中列出的数据,是一个数组
  51. * layerData: 需要在弹层窗口中展示的字段及标题文字,形如: [{ name:'要展示的字段名', label:'标题文字' }]
  52. * selfField: 该表单值绑定哪个字段,默认为绑定到自身的字段
  53. */
  54. async getSourceData(schemeItem) {
  55. if (['radio', 'select', 'checkbox'].includes(schemeItem.type)) {
  56. // radio select checkbox 三种情况
  57. if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) {
  58. // dataSource 为 0,使用 clientData
  59. return Object
  60. .values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode])
  61. .map(t => ({
  62. value: t.value,
  63. text: t.text
  64. }))
  65. } else {
  66. // dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段
  67. const [code, displayField = schemeItem.showField, valueField = schemeItem.saveField] =
  68. schemeItem.dataSourceId
  69. .split(',')
  70. const sourceData = await this.FETCH_DATASOURCE(code)
  71. if (!sourceData) {
  72. return []
  73. }
  74. return sourceData.data.map(t => ({
  75. text: t[displayField],
  76. value: t[valueField]
  77. }))
  78. }
  79. } else if (['layer'].includes(schemeItem.type)) {
  80. // layer 需要更多属性
  81. if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) {
  82. // dataSource 为 0,使用 clientData
  83. // clientData 对象转数组后,隐含 key:item.text 和 value:item.value 的关系
  84. const [keyItem, valueItem] = schemeItem.layerData
  85. const source = Object
  86. .values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode])
  87. .map(t => ({
  88. value: t.value,
  89. text: t.text
  90. }))
  91. return {
  92. source,
  93. layerData: [{
  94. name: 'text',
  95. label: keyItem.label || '',
  96. value: keyItem.value || ''
  97. },
  98. {
  99. name: 'value',
  100. label: valueItem.label || '',
  101. value: valueItem.value || ''
  102. }
  103. ]
  104. }
  105. } else {
  106. // dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段
  107. const [code] = schemeItem.dataSourceId.split(',')
  108. const sourceData = await this.FETCH_DATASOURCE(code)
  109. if (!sourceData) {
  110. return []
  111. }
  112. const source = sourceData.data
  113. return {
  114. source,
  115. layerData: schemeItem.layerData.filter(t => (!t.hide) && (t.value || t.label))
  116. }
  117. }
  118. }
  119. return []
  120. },
  121. /**
  122. * 获取一个 scheme 表单项的默认值 (用户新建表单时使用,或是编辑草稿)
  123. * 参数: 单个 schemeItem , { processId }
  124. *
  125. * 每种类别的表单项分别获取的默认值:
  126. *
  127. * currentInfo: 根据类别取当前用户/部门/公司/时间日期
  128. * datetime: 根据 dfValue 字段表示昨天/今天/明天,格式化为字符串
  129. * radio、select: 有 dfValue 则使用,否则取第一条
  130. * checkbox: 有 dfValue 则使用,否则为空数组
  131. * encode: 根据 rulecode 请求表单编码
  132. * upload: 空数组
  133. * guid: 赋值第二个参数中的 processId,但是如果在子表格中,赋空字符串
  134. * girdtable: 递归所有表格项 scheme 依次为它们生成默认值
  135. * datetimerange: 字符串 0
  136. */
  137. async getDefaultData(item, prop) {
  138. const {
  139. processId
  140. } = prop
  141. switch (item.type) {
  142. case 'currentInfo':
  143. switch (item.dataType) {
  144. case 'user':
  145. return this.GET_GLOBAL('loginUser').userId
  146. case 'department':
  147. return this.GET_GLOBAL('loginUser').departmentId
  148. case 'company':
  149. return this.GET_GLOBAL('loginUser').companyId
  150. case 'time':
  151. return moment().format('YYYY-MM-DD HH:mm:ss')
  152. default:
  153. return ''
  154. }
  155. case 'datetime':
  156. const datetimeFormat = item.table ?
  157. (Number(item.dateformat) === 0 ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss') :
  158. (item.datetime === 'datetime' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
  159. const today = moment()
  160. const dfDatetime = [
  161. today.subtract(1, 'day'),
  162. today,
  163. today.add(1, 'day')
  164. ][Number(item.dfvalue)] || today
  165. return dfDatetime.format(datetimeFormat) || ''
  166. case 'radio':
  167. case 'select':
  168. const radioItem = item.__sourceData__.find(t => t.value === item.dfvalue) || item
  169. .__sourceData__[0]
  170. return item.type === 'radio' ? radioItem.value : ''
  171. case 'checkbox':
  172. if (!item.dfvalue) {
  173. return []
  174. }
  175. return item.dfvalue.split(',').filter(t => item.__sourceData__.find(s => s.value === t))
  176. case 'encode':
  177. const result = await this.FETCH_ENCODE(item.rulecode)
  178. return result
  179. case 'upload':
  180. return []
  181. case 'guid':
  182. return item.table ? processId : ''
  183. case 'girdtable':
  184. const tableItemObj = {}
  185. for (const fieldItem of item.fieldsData) {
  186. tableItemObj[fieldItem.field] = await this.getDefaultData(fieldItem, prop)
  187. }
  188. return this.COPY(tableItemObj)
  189. case 'datetimerange':
  190. return '0'
  191. default:
  192. return item.dfvalue || ''
  193. }
  194. },
  195. /**
  196. * 将单条 formData 值转化为 formValue 值 (拉取表单数据时使用)
  197. * 参数: 单个 schemeItem , 数据值
  198. *
  199. * 具体执行逻辑:
  200. * radio、select: 剔除无效值
  201. * checkbox: 分割成数组并剔除无效值
  202. * upload: 分割成数组,拉取其中所有文件的信息
  203. * datetime: 按照时间日期格式进行格式化字符串
  204. * 其他类型: 保留原值
  205. */
  206. async convertToFormValue(item, val) {
  207. switch (item.type) {
  208. case 'upload':
  209. if (!val) {
  210. return []
  211. }
  212. const uidList = val;
  213. const fileList = []
  214. const wxlist = await this.FETCH_FILEList(uidList);
  215. for (const wxfile of wxlist) {
  216. const fileInfo = await this.FETCH_FILEINFO(wxfile.F_Id)
  217. if (!fileInfo) {
  218. continue
  219. }
  220. const fileType = fileInfo.F_FileType
  221. const fileSize = fileInfo.F_FileSize
  222. const path = this.API + '/learun/adms/annexes/wxdown?' + this.URL_QUERY(wxfile.F_Id, true)
  223. fileList.push({
  224. path,
  225. type: fileType,
  226. uid:wxfile.F_Id,
  227. folderId:wxfile.F_FolderId,
  228. size: fileSize
  229. })
  230. }
  231. return fileList
  232. case 'select':
  233. case 'radio':
  234. if (!val || !item.__sourceData__.map(t => t.value).includes(val)) {
  235. return ''
  236. }
  237. return val
  238. case 'checkbox':
  239. const validValue = item.__sourceData__.map(t => t.value)
  240. const checkboxVal = val.split(',') || []
  241. return checkboxVal.filter(t => validValue.includes(t))
  242. case 'datetime':
  243. if (!val) {
  244. return ''
  245. }
  246. return moment(val).format(
  247. Number(item.dateformat) === 0 || item.datetime === 'date' ?
  248. 'YYYY-MM-DD' :
  249. 'YYYY-MM-DD HH:mm:ss'
  250. )
  251. default:
  252. return val || ''
  253. }
  254. },
  255. /**
  256. * 将一个 formValue 值转化为 post 提交值(提交表单数据时使用)
  257. * 参数: 单个 schemeItem , 表单项值 , 所有 formValue , scheme
  258. *
  259. * 具体执行逻辑:
  260. * checkbox: 将数组使用符号「,」逗号拼接成字符串
  261. * datetimerange: 获取开始日期、结束日期,计算差值天数并保留整数
  262. * datetime: 格式化为完整时间日期字符串
  263. * upload: 依次上传文件,将返回的文件 ID 使用符号「,」逗号拼接成字符串
  264. * 其他类型: 保留原值
  265. */
  266. async convertToPostData(item, val, formValue, scheme, guid) {
  267. switch (item.type) {
  268. case 'checkbox':
  269. return val ? val.join(',') : ''
  270. case 'datetimerange':
  271. const startTime = get(formValue, scheme.find(t => t.id === item.startTime).__valuePath__, null)
  272. const endTime = get(formValue, scheme.find(t => t.id === item.endTime).__valuePath__, null)
  273. if (!startTime || !endTime || moment(endTime).isBefore(startTime)) {
  274. return ''
  275. } else {
  276. return moment.duration(moment(endTime).diff(moment(startTime))).asDays().toFixed(0)
  277. }
  278. case 'datetime':
  279. return val ? moment(val).format('YYYY-MM-DD HH:mm:ss') : ''
  280. case 'upload':
  281. var uploadUid = '';
  282. for (const item of val) {
  283. if (item.uid) {
  284. uploadUid = item.uid
  285. continue
  286. }
  287. const fileId = await this.HTTP_UPLOAD(item.path || item, undefined, guid || '')
  288. if (fileId) {
  289. uploadUid = fileId;
  290. }
  291. }
  292. return uploadUid;
  293. default:
  294. return val || ''
  295. }
  296. }
  297. }
  298. }