index.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import { getCurrentInstance, h, ref, defineComponent } from 'vue'
  2. import { ElTable, ElTableColumn, ElRadio } from 'element-plus'
  3. import { getFieldValue, isNotEmpty, isEmpty, isArray } from '@cip/utils/util'
  4. // import { handleFormConfig, handleTableConfig } from '../helper/d-render'
  5. import CipFormItem from '@cip/components/cip-form-item'
  6. import CipTableHandler from '@cip/components/cip-table-handler'
  7. import './index.less'
  8. // import { getViewComponent } from '@cip/components/cip-form-input/util'
  9. // import { useFieldValue } from '@cip/components/cip-form-item/form-item-hooks'
  10. export default defineComponent({
  11. name: 'CipTable',
  12. inheritAttrs: false,
  13. props: {
  14. offset: Number,
  15. height: {
  16. type: String
  17. },
  18. selectable: {
  19. type: Function
  20. },
  21. selectRadio: {
  22. type: [String, Number]
  23. },
  24. selectLabel: {
  25. type: String
  26. },
  27. selectType: {
  28. type: String
  29. },
  30. selectColumns: Array,
  31. columns: { type: Array, default: () => [] },
  32. fieldKey: String,
  33. tableHeaderLabel: String,
  34. data: {
  35. type: Array,
  36. default: () => []
  37. },
  38. dependOnValues: Object, // 作为basic-table组件时对外部的依赖
  39. inForm: Boolean, // 是否为表单的输入或展示
  40. rowKey: [String, Function],
  41. treeProps: {
  42. type: Object,
  43. default: () => ({})
  44. },
  45. handlerWidth: {
  46. type: String,
  47. default: '120px'
  48. },
  49. withTableHandle: Boolean,
  50. hideIndex: Boolean,
  51. indexFixed: Boolean // 左侧悬浮
  52. },
  53. emits: ['sort', 'update:data', 'update:selectColumns'],
  54. setup (props, context) {
  55. const instance = getCurrentInstance()
  56. const cipTableRef = ref()
  57. instance.ctx.cipTableRef = cipTableRef
  58. const updateData = (val, index) => {
  59. console.log('updateData')
  60. const data = props.data
  61. data[index] = val
  62. context.emit('update:data', data)
  63. }
  64. const getFormItem = (key, config, row, index) => {
  65. return h(CipFormItem, {
  66. key: index,
  67. model: row,
  68. fieldKey: key,
  69. config: config,
  70. inTable: true,
  71. tableDependOnValues: props.dependOnValues,
  72. tableData: props.data,
  73. 'onUpdate:model': (val) => {
  74. row = val
  75. updateData(val, index)
  76. }
  77. })
  78. }
  79. const tableColumn = ({ key, config } = {}) => {
  80. const headerSlots = ({ column, $index }) => {
  81. return <span>
  82. {config.required === true && <span class={['cip-danger-color']} style={{ marginRight: '4px' }}>*</span>}
  83. {config.label}
  84. </span>
  85. }
  86. const { children, ...tableColumnConfig } = config
  87. return h(ElTableColumn, {
  88. prop: key,
  89. align: config.type === 'number' ? 'right' : '', // 针对数字类型进行居右优化
  90. style: 'display: flex;',
  91. ...tableColumnConfig
  92. }, {
  93. header: headerSlots,
  94. default: ({ row, $index, column }) => {
  95. // if ($index === -1) return // 如果写上这个代码 children 将失效
  96. // const otherValue = !isEmpty(config.otherKey) ? getFieldValue(row, config.otherKey) : undefined
  97. if (isArray(config.children) && config.children.length > 0) {
  98. return config.children.map(tableColumn)
  99. } else {
  100. if ($index < 0) return null
  101. const modelValue = getFieldValue(row, key)
  102. // const [otherValue] = useFieldValue({ value: config.otherKey }, { value: row }, () => {})
  103. // 同时开放key值插槽及key+'Slot' 的插槽
  104. if (!['default', 'append', 'expand', '_handler'].includes(key) && context.slots[key]) {
  105. return context.slots[key]({ row, $index, column })
  106. }
  107. // 特殊字段插槽 ['default', 'append']
  108. if (context.slots[`${key}Slot`]) {
  109. return context.slots[key]({ row, $index, column })
  110. }
  111. const inputConfig = { ...config } // 进行一次浅拷贝
  112. inputConfig.width = '100%'
  113. inputConfig.hideLabel = true
  114. // config.labelWidth = 0
  115. if (inputConfig.writable === true) {
  116. // 将form 输入组件的宽度设为100% config中的width 代表表格宽度
  117. inputConfig.ruleKey = `${props.fieldKey}.${$index}.${key}`
  118. return getFormItem(key, inputConfig, row, $index)
  119. }
  120. if (!inputConfig.writable) {
  121. // if ((config.dependOn?.length > 0 || config.outDependOn?.length > 0)) {
  122. // 开启响应的效果 开启只读模式
  123. inputConfig.readable = true
  124. if (!inputConfig.dynamic) {
  125. inputConfig.dependOn = []
  126. }
  127. // ERROR: 此处将导致watch 出现错误
  128. return getFormItem(key, inputConfig, row, $index)
  129. // } else {
  130. // // TODO: 考虑是否合并, 合并后样式是否有异常
  131. // const viewProps = {
  132. // modelValue,
  133. // model: row,
  134. // config: config,
  135. // otherValue: otherValue.value
  136. // }
  137. // // 存在otherKey的时候把otherKey的值赋给otherValue
  138. // return h(getViewComponent(config.type), viewProps)
  139. // }
  140. } else {
  141. return modelValue
  142. }
  143. }
  144. }
  145. })
  146. }
  147. const tableColumns = () => props.columns.map(tableColumn)
  148. const tableDefaultSlots = () => {
  149. const slots = tableColumns()
  150. if (isNotEmpty(props.offset) && props.offset > -1 && !props.hideIndex) {
  151. const indexColumn = h(ElTableColumn, { label: '序号', fixed: props.indexFixed ? 'left' : '', width: isEmpty(props.rowKey) ? '55px' : '75px' }, {
  152. default: ({ $index }) => `${$index + 1 + props.offset}`
  153. })
  154. slots.unshift(indexColumn)
  155. }
  156. if (props.selectType === 'checkbox') {
  157. const option = { type: 'selection', width: '45px', fixed: 'left' }
  158. if (isNotEmpty(props.selectable)) { // 选择
  159. option.selectable = (row, index) => props.selectable(row || {}, index)
  160. }
  161. const selectionColumn = h(ElTableColumn, option)
  162. slots.unshift(selectionColumn)
  163. }
  164. if (props.selectType === 'radio') {
  165. const selectionColumn = h(ElTableColumn, { width: '45px', fixed: 'left' }, {
  166. default: ({ row }) => h(ElRadio, {
  167. label: row[props.selectLabel] ?? row.id,
  168. modelValue: props.selectRadio
  169. }, { default: () => '' })
  170. })
  171. slots.unshift(selectionColumn)
  172. }
  173. if (context.slots.expand) {
  174. const expendColumn = h(ElTableColumn, { type: 'expand', width: '32px' }, {
  175. default: ({ row, index }) => context.slots.expand({ row, index })
  176. })
  177. slots.unshift(expendColumn)
  178. }
  179. // jsx编译时有时候会去除_handler插槽
  180. if (props.withTableHandle && (context.slots._handler || context.slots.$handler)) {
  181. const handlerSlot = context.slots._handler || context.slots.$handler
  182. const handlerColumn = h(ElTableColumn, { label: '操作', fixed: 'right', width: props.handlerWidth || '120px' }, {
  183. default: ({ row, $index }) => h(CipTableHandler, { limit: 3 }, {
  184. default: () => handlerSlot({ row, $index })
  185. })
  186. })
  187. slots.unshift(handlerColumn)
  188. // 内部组件必须使用cip-table-button
  189. }
  190. if (context.slots.default) {
  191. slots.push(context.slots.default())
  192. }
  193. if (context.slots.prepend) {
  194. const prependSlots = context.slots.prepend()
  195. if (isArray(prependSlots)) {
  196. slots.unshift(...prependSlots)
  197. } else {
  198. slots.unshift(prependSlots)
  199. }
  200. }
  201. if (context.slots.append) {
  202. const appendSlots = context.slots.append()
  203. if (isArray(appendSlots)) {
  204. slots.push(...appendSlots)
  205. } else {
  206. slots.push(appendSlots)
  207. }
  208. }
  209. if (props.tableHeaderLabel) return h(ElTableColumn, { label: props.tableHeaderLabel, align: 'center' }, { default: () => slots })
  210. return slots
  211. }
  212. const onSortChange = ({ prop, order }) => {
  213. context.emit('sort', { prop, order })
  214. }
  215. return () => h(ElTable, {
  216. ...context.attrs,
  217. data: props.data,
  218. ref: cipTableRef,
  219. height: props.height,
  220. class: 'cip-table',
  221. rowKey: props.rowKey,
  222. treeProps: props.treeProps,
  223. onSortChange,
  224. onSelectionChange: (val) => {
  225. context.emit('update:selectColumns', val)
  226. }
  227. }, {
  228. default: tableDefaultSlots
  229. })
  230. }
  231. })