index.jsx 6.2 KB

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