index.jsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import { computed, watch, nextTick, onMounted, unref } from 'vue'
  2. import { useRetrieve } from '@cip/hooks/use-retrieve'
  3. import { getFieldValue, isNotEmpty, isObject, objectEqual } from '@cip/utils/util'
  4. import { useTableSelected } from './use-table-selected'
  5. import CipTable from '../cip-table'
  6. import CipPageLayoutList from '../page-layout/list'
  7. import CipPagination from '../cip-pagination'
  8. import CipSearchForm from '../cip-search-form'
  9. import SelectTags from './tags'
  10. import './index.less'
  11. import { ElLoading } from 'element-plus'
  12. export default {
  13. name: 'CipSelectTable',
  14. props: {
  15. modelValue: [Object, Array], // 单选时为对象多选时为数组
  16. direction: {
  17. type: String,
  18. default: 'row',
  19. validate: (val) => [
  20. 'row',
  21. 'row-reverse',
  22. 'column',
  23. 'column-reverse'
  24. ].includes(val)
  25. },
  26. multiple: {
  27. type: Boolean,
  28. default: true
  29. },
  30. tableData: Array, // 支持外部数据或以给接口的方式传入 外部接口异步接口分页 [暂不考虑]
  31. entity: Object, // 设置获取数据的接口 外部数据优先级更高
  32. curdFn: Object,
  33. tableColumns: Array,
  34. searchFieldList: Array,
  35. optionProps: Object,
  36. hideSearch: { type: Boolean, default: undefined },
  37. defaultSearchModel: Object,
  38. withPagination: { type: Boolean, default: true },
  39. selectable: Function,
  40. hideIndex: { type: Boolean, default: undefined },
  41. withTags: { type: Boolean, default: true },
  42. withDivider: { type: Boolean, default: true }, // 分割线
  43. tableExpandRender: { type: Function }
  44. },
  45. directives: { loading: ElLoading.directive },
  46. emits: ['update:modelValue'],
  47. setup (props, { emit }) {
  48. const selectType = computed(() => {
  49. return props.multiple ? 'checkbox' : 'radio'
  50. })
  51. const {
  52. itemList,
  53. getItemList,
  54. searchFilter,
  55. defaultSearchFilter,
  56. search,
  57. listLoading,
  58. offset,
  59. limit,
  60. total,
  61. currentPage
  62. } = useRetrieve(props.entity, props.curdFn)
  63. const {
  64. tableRef,
  65. selectedRows,
  66. optionProps,
  67. setCurrentSelect,
  68. removeSelectRow,
  69. handleSelect,
  70. handleSelectAll
  71. } = useTableSelected(props, { itemList })
  72. // eslint-disable-next-line vue/no-setup-props-destructure
  73. defaultSearchFilter.value = props.defaultSearchModel
  74. search()
  75. watch(() => props.defaultSearchModel, (val) => {
  76. if (!objectEqual(defaultSearchFilter.value, props.defaultSearchModel)) {
  77. defaultSearchFilter.value = props.defaultSearchModel
  78. search()
  79. }
  80. }, { deep: true })
  81. const selectRadio = computed(() => {
  82. return getFieldValue(selectedRows.value[0] || {}, optionProps.value.value)
  83. })
  84. const selectable = (row) => {
  85. if (typeof props.selectable !== 'function') return true
  86. return props.selectable(row)
  87. }
  88. const currentChange = (changeRow) => {
  89. if (!props.multiple) { // 仅在非多选模式下生效
  90. if (changeRow && selectable(changeRow)) {
  91. selectedRows.value[0] = changeRow
  92. }
  93. }
  94. }
  95. const getSingelSelectedValue = (val) => {
  96. val = unref(val)
  97. return isObject(val) ? val?.[optionProps.value.value] ?? '' : val
  98. }
  99. watch(selectedRows, (val) => {
  100. if (props.multiple) {
  101. emit('update:modelValue', val)
  102. } else {
  103. const currentValue = val[0]
  104. const isSameValue = getSingelSelectedValue(currentValue) === getSingelSelectedValue(props.modelValue)
  105. if (isSameValue) {
  106. return
  107. }
  108. emit('update:modelValue', currentValue)
  109. }
  110. }, { deep: true })
  111. onMounted(() => {
  112. watch(itemList, () => {
  113. nextTick().then(() => setCurrentSelect())
  114. })
  115. watch(() => props.modelValue, (val) => {
  116. // 浅拷贝
  117. // 先清空
  118. tableRef.value.cipTableRef.clearSelection()
  119. // 赋值
  120. if (props.multiple) {
  121. selectedRows.value = val || []
  122. } else {
  123. if (isNotEmpty(val)) {
  124. selectedRows.value = [val]
  125. } else {
  126. selectedRows.value = []
  127. }
  128. }
  129. // 设置选中
  130. setCurrentSelect()
  131. }, { immediate: true })
  132. })
  133. return () => <div class={['cip-select-table', `cip-select-table--${props.direction}`]} style={{ flexDirection: props.direction }}>
  134. <CipPageLayoutList class={'cip-select-table__table'} noPadding={true}>
  135. {{
  136. filter: props.searchFieldList?.length > 0
  137. ? () => <CipSearchForm
  138. v-model:model={searchFilter.value}
  139. defaultModel={defaultSearchFilter.value}
  140. fieldList={props.searchFieldList}
  141. hideSearch={props.hideSearch}
  142. onSearch={search}
  143. />
  144. : undefined,
  145. default: () => <CipTable
  146. ref={tableRef}
  147. v-loading={listLoading.value}
  148. data={itemList.value}
  149. selectType={selectType.value}
  150. selectRadio={selectRadio.value}
  151. selectLabel={optionProps.value.value}
  152. hideIndex={props.hideIndex}
  153. offset={offset.value}
  154. columns={props.tableColumns}
  155. selectable={props.selectable}
  156. expandRender={props.tableExpandRender}
  157. onSelect={handleSelect}
  158. onSelectAll={handleSelectAll}
  159. onRow-click={currentChange}
  160. />,
  161. pagination: props.withPagination
  162. ? () => <CipPagination
  163. v-model:offset={offset.value}
  164. v-model:limit={limit.value}
  165. background={false}
  166. layout={'prev, pager, next'}
  167. total={total.value}
  168. current-page={currentPage.value}
  169. onRefresh={getItemList} />
  170. : undefined
  171. }}
  172. </CipPageLayoutList>
  173. <div class={['cip-select-table__divider', { 'without-divider': !props.withDivider }]}/>
  174. {/* v-if="!$slots.group && withTags" */}
  175. {props.withTags && <div
  176. class={['cip-select-table__tags', { 'limited-height': props.direction.indexOf('column') !== -1 }]}
  177. style={{ flexBasis: props.direction.includes('row') ? '220px' : '100px' }}
  178. >
  179. <SelectTags
  180. modelValue={selectedRows.value}
  181. optionProps={optionProps.value}
  182. onRemove={(index) => removeSelectRow(index)}
  183. />
  184. </div>}
  185. </div>
  186. }
  187. }