form-input.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. import { computed, ref, watch, unref } from 'vue'
  2. import { useElFormItemInject } from './use-form'
  3. import {
  4. isEmpty,
  5. isNotEmpty,
  6. getLabelByValue,
  7. isObject,
  8. isArray,
  9. isNumber, getFieldValue, setFieldValue, getUsingConfig
  10. } from '@cip/utils/util'
  11. import { judgeUseFn } from '@cip/components/cip-form-item/util'
  12. import { getValueByTemplate } from '../cip-form-input/form-value-store'
  13. import { UpdateFormStream } from '../helper/update-form-stream'
  14. const useUpdateStream = (props, context) => {
  15. const updateStream = new UpdateFormStream(props, (val) => context.emit('streamUpdate:model', val))
  16. return updateStream
  17. }
  18. const useProxyOtherValue = (props, maxOtherKey = 1, updateStream) => {
  19. const result = []
  20. for (let i = 0; i < maxOtherKey; i++) {
  21. const proxyValue = computed({
  22. get () {
  23. return props.values[i + 1]
  24. },
  25. set (val) {
  26. updateStream.appendOtherValue(val, i + 1)
  27. updateStream.end()
  28. }
  29. })
  30. result.push(proxyValue)
  31. }
  32. return result
  33. }
  34. const useFormBasicConfig = (props) => {
  35. const securityConfig = computed(() => {
  36. return props.config ?? {}
  37. })
  38. const clearable = computed(() => {
  39. return securityConfig.value.clearable ?? true
  40. })
  41. const width = computed(() => {
  42. return securityConfig.value.width ?? '100%'
  43. })
  44. const inputStyle = computed(() => {
  45. return securityConfig.value.inputStyle ?? {}
  46. })
  47. const placeholder = computed(() => {
  48. return securityConfig.value.placeholder
  49. })
  50. const noMatchText = computed(() => {
  51. return securityConfig.value.noMatchText ?? '无相关内容'
  52. })
  53. return {
  54. securityConfig, clearable, width, placeholder, inputStyle, noMatchText
  55. }
  56. }
  57. export const useFormInput = (props, context, { fromModelValue, toModelValue, maxOtherKey } = {}) => {
  58. const inputRef = ref()
  59. const updateStream = useUpdateStream(props, context)
  60. const { securityConfig, clearable, width, placeholder, inputStyle, noMatchText } = useFormBasicConfig(props)
  61. const emitInput = (val) => {
  62. emitModelValue(val)
  63. }
  64. const emitModelValue = (val) => {
  65. val = isNotEmpty(toModelValue) ? toModelValue(val) : val
  66. // 同时支持2中修改方式,在formItem中不在接受update:modelValue
  67. context.emit('update:modelValue', val)
  68. updateStream.appendValue(val)
  69. updateStream.end()
  70. }
  71. // 组件单独使用时不在支持对otherValue的修改
  72. const emitOtherValue = (val) => {
  73. // context.emit('update:otherValue', val)
  74. updateStream.appendOtherValue(val)
  75. updateStream.end()
  76. }
  77. const proxyOtherValue = useProxyOtherValue(props, maxOtherKey, updateStream)
  78. const proxyValue = computed({
  79. // 单值时使用
  80. get () {
  81. let modelValue = props.modelValue
  82. if (props.values && props.values.length > 0) {
  83. modelValue = props.values[0]
  84. }
  85. return isNotEmpty(fromModelValue) ? fromModelValue(modelValue) : modelValue // props.modelValue
  86. },
  87. set (val) {
  88. emitModelValue(val)
  89. }
  90. })
  91. watch([() => securityConfig.value.defaultValue, () => props.changeCount], ([defaultValue]) => {
  92. if (props.showTemplate === true) {
  93. // 处于展示模版模式时,同步展示默认值【注:此模式仅在设计表单时开启】
  94. emitInput(defaultValue)
  95. } else {
  96. // 处于实际值展示模式时, 需要modelValue 和defaultValue都不为空才进行值的更新
  97. if (isEmpty(props.modelValue) && isNotEmpty(defaultValue)) {
  98. // emitInput(getValueByTemplate(defaultValue)) // date下需要转换值后再写入
  99. proxyValue.value = getValueByTemplate(defaultValue)
  100. }
  101. }
  102. }, { immediate: true })
  103. return {
  104. inputRef,
  105. inputStyle,
  106. proxyValue,
  107. securityConfig,
  108. emitInput,
  109. emitModelValue,
  110. emitOtherValue,
  111. updateStream,
  112. proxyOtherValue,
  113. placeholder,
  114. clearable,
  115. width,
  116. noMatchText
  117. }
  118. }
  119. export const useFormView = (props, { maxOtherKey } = {}) => {
  120. const { securityConfig, clearable, width, placeholder, inputStyle } = useFormBasicConfig(props)
  121. const proxyOtherValue = useProxyOtherValue(props, maxOtherKey, () => { })
  122. return {
  123. securityConfig, clearable, width, inputStyle, placeholder, proxyOtherValue
  124. }
  125. }
  126. export const useElementFormEvent = () => {
  127. const elFormItem = useElFormItemInject()
  128. const handleChange = (val) => {
  129. // 2.2.17 修改为 elFormItem.validate
  130. // 2.2.x 使用 elFormItem.formItemMitt
  131. // console.log(elFormItem.validate())
  132. elFormItem.validate?.('change')
  133. elFormItem.formItemMitt?.emit('el.form.change', [val])
  134. }
  135. const handleBlur = (val) => {
  136. elFormItem.validate?.('blur')
  137. elFormItem.formItemMitt?.emit('el.form.blur', [val])
  138. }
  139. return {
  140. handleChange,
  141. handleBlur
  142. }
  143. }
  144. export const useOptions = (props, multiple, updateStream, context) => {
  145. const optionProps = computed(() => {
  146. return Object.assign({ label: 'label', value: 'value', children: 'children' }, props.config?.treeProps, props.config?.optionProps)
  147. })
  148. const otherKey = computed(() => {
  149. return props.config?.otherKey
  150. })
  151. const splitKey = computed(() => {
  152. return props.config?.splitKey ?? ','
  153. })
  154. const withObject = computed(() => {
  155. // 传出的值是否为object
  156. return props.config?.withObject ?? false
  157. })
  158. const realArray = computed(() => {
  159. // 需要返回的shu
  160. return props.config?.realArray ?? false
  161. })
  162. const options = ref([])
  163. let unwatch = null
  164. const getOptions = async (val, outVal) => {
  165. if (props.config.asyncOptions) {
  166. const asyncFunc = judgeUseFn('asyncOptions', props.config)
  167. options.value = await asyncFunc(val, outVal)
  168. } else {
  169. options.value = props.config?.options ?? []
  170. }
  171. if (unwatch) unwatch() // 获取一次options后重新开启监听
  172. unwatch = watch(() => props.changeCount, () => {
  173. if (isEmpty(props.modelValue) && props.config.autoSelect && updateStream) { // modelValue为空
  174. const autoValue = isObjectOption.value ? options.value[0][optionProps.value.value] : options.value[0]
  175. const autoLabel = isObjectOption.value ? options.value[0][optionProps.value.label] : options.value[0]
  176. // eslint-disable-next-line no-unused-expressions
  177. // emitInput(autoValue)
  178. // emitOtherValue && emitOtherValue(autoLabel)
  179. updateStream.appendValue(autoValue)
  180. updateStream.appendOtherValue(autoLabel)
  181. updateStream.end()
  182. }
  183. }, { immediate: true })
  184. }
  185. // 计算option类型
  186. const isObjectOption = computed(() => {
  187. return isObject(options.value[0])
  188. })
  189. // 获取otherValue的值
  190. const getOtherValueByValue = (value) => {
  191. if (unref(multiple)) {
  192. if (withObject.value) {
  193. return value.map(i => {
  194. return options.value?.find(v => v[optionProps.value.value] === i) ?? {}
  195. })
  196. }
  197. return value.map(val => getLabelByValue(val, options.value, optionProps.value) ?? val).join(splitKey.value)
  198. } else {
  199. if (withObject.value) {
  200. return options.value?.find(v => v[optionProps.value.value] === value) ?? {}
  201. }
  202. return getLabelByValue(value, options.value, optionProps.value) ?? value
  203. }
  204. }
  205. const getValue = (modelValue) => {
  206. if (unref(multiple)) {
  207. // 防止空字符串导致的['']错误
  208. const modelArray = isArray(modelValue) ? modelValue : (modelValue ? modelValue.split(splitKey.value) : [])
  209. // 如果option的value值是数字型将值转换为数字型,否则就是字符型
  210. const autoFormat = !(props.config?.multiple && props.config?.remote)
  211. if (autoFormat) {
  212. const optionCell = isObjectOption.value ? options.value[0]?.[optionProps.value.value] : options.value[0]
  213. if (isNumber(optionCell)) {
  214. return modelArray.map(i => parseInt(i))
  215. } else {
  216. return modelArray.map(i => String(i))
  217. }
  218. }
  219. return modelArray
  220. } else {
  221. return modelValue ?? ''
  222. }
  223. }
  224. const getModelValue = (value) => {
  225. if (unref(multiple)) {
  226. if (realArray.value) {
  227. return value
  228. } else {
  229. return isArray(value) ? value.join(splitKey.value) : value
  230. }
  231. } else {
  232. return value
  233. }
  234. }
  235. // 根据otherValue跟随modelValue变化
  236. const getOtherValue = (modelValue, value) => {
  237. if (isObjectOption.value) {
  238. return getOtherValueByValue(value)
  239. } else {
  240. return modelValue
  241. }
  242. }
  243. if (!(props.config.dependOn?.length) && !(props.config.outDependOn?.length)) {
  244. getOptions() // .then(() => { console.log('[init]: getOptions') })
  245. if (props.config.options) { // 动态表单设计时修改options需要触发此方法
  246. watch(() => props.config.options, (val) => {
  247. getOptions() // .then(() => { console.log('[config.options change]: getOptions') })
  248. })
  249. }
  250. } else {
  251. watch([() => props.dependOnValues, () => props.outDependOnValues], ([dependOnValues, outDependOnValues]) => {
  252. getOptions(dependOnValues || {}, outDependOnValues || {}) // .then(() => { console.log('[dependOn change]: getOptions') })
  253. }, { immediate: true })
  254. }
  255. // options部分组件重新定义proxyOptionsValue
  256. const proxyOptionsValue = computed({
  257. get () {
  258. return getValue(props.modelValue)
  259. },
  260. set (value) {
  261. const modelValue = getModelValue(value)
  262. if (context) {
  263. context.emit('update:modelValue', modelValue)
  264. }
  265. if (updateStream) {
  266. updateStream.appendValue(modelValue)
  267. if (otherKey.value) {
  268. const otherValue = getOtherValue(modelValue, value)
  269. // context.emit('update:otherValue', otherValue)
  270. updateStream.appendOtherValue(otherValue)
  271. // 目前仅支持单选
  272. if (!unref(multiple)) {
  273. const checkOption = options.value.find(v => v[optionProps.value.value] === value)
  274. updateStream.appendOtherValue(checkOption, 2)
  275. } else {
  276. const checkOptions = options.value.filter(v => value.includes(v[optionProps.value.value]))
  277. updateStream.appendOtherValue(checkOptions, 2)
  278. }
  279. }
  280. updateStream.end()
  281. } else {
  282. console.error('updateStream 不存在,无法更新数据')
  283. }
  284. }
  285. })
  286. return {
  287. optionProps,
  288. options,
  289. getOptions,
  290. splitKey,
  291. isObjectOption,
  292. getValue,
  293. getModelValue,
  294. getOtherValue,
  295. proxyOptionsValue
  296. }
  297. }
  298. /**
  299. * 从props.config去除制定的值
  300. * propKeys事例:
  301. * [
  302. * 'a', 获取A
  303. * ['b','b1'], 获取b的值转为b1
  304. * ['c',{key:'c1', defaultValue: 1}], 获取c的值转为c1若c的值不存在则赋值1
  305. * ['d',{ defaultValue: 1}] 获取d的若d不存在则赋值1
  306. * ]
  307. * @param props
  308. * @param propKeys
  309. *
  310. */
  311. export const useInputProps = (props, propKeys = []) => {
  312. return computed(() => {
  313. const config = props.config || {}
  314. return propKeys.reduce((acc, key) => {
  315. if (typeof key !== 'string') {
  316. const getKey = key[0]
  317. let setKey = key[0]
  318. let defaultValue
  319. if (isNotEmpty(key[1])) {
  320. if (typeof key[1] === 'string') {
  321. setKey = key[1]
  322. } else {
  323. setKey = getUsingConfig(key[1].key, key[0]) // 只存在defaultValue配置时使用第一位key
  324. defaultValue = key[1].defaultValue
  325. }
  326. }
  327. const propValue = getFieldValue(config, getKey)
  328. setFieldValue(acc, setKey, getUsingConfig(propValue, defaultValue))
  329. } else {
  330. const propValue = getFieldValue(config, key)
  331. setFieldValue(acc, key, propValue)
  332. }
  333. return acc
  334. }, {}) || {}
  335. })
  336. }