index.jsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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: Boolean // 分割线
  42. },
  43. emits: ['update:modelValue'],
  44. setup (props, { emit }) {
  45. const selectType = computed(() => {
  46. return props.multiple ? 'checkbox' : 'radio'
  47. })
  48. const {
  49. itemList,
  50. getItemList,
  51. searchFilter,
  52. defaultSearchFilter,
  53. search,
  54. listLoading,
  55. offset,
  56. limit,
  57. total,
  58. currentPage
  59. } = useRetrieve(props.entity, props.curdFn)
  60. const {
  61. tableRef,
  62. selectedRows,
  63. optionProps,
  64. setCurrentSelect,
  65. removeSelectRow,
  66. handleSelect,
  67. handleSelectAll
  68. } = useTableSelected(props, { itemList })
  69. // eslint-disable-next-line vue/no-setup-props-destructure
  70. defaultSearchFilter.value = props.defaultSearchModel
  71. search()
  72. watch(() => props.defaultSearchModel, (val) => {
  73. if (!objectEqual(defaultSearchFilter.value, props.defaultSearchModel)) {
  74. defaultSearchFilter.value = props.defaultSearchModel
  75. search()
  76. }
  77. }, { deep: true })
  78. const selectRadio = computed(() => {
  79. return getFieldValue(selectedRows.value[0] || {}, optionProps.value.value)
  80. })
  81. const selectable = (row) => {
  82. if (typeof props.selectable !== 'function') return true
  83. return props.selectable(row)
  84. }
  85. const currentChange = (changeRow) => {
  86. if (!props.multiple) { // 仅在非多选模式下生效
  87. if (changeRow && selectable(changeRow)) {
  88. selectedRows.value[0] = changeRow
  89. }
  90. }
  91. }
  92. const getSingelSelectedValue = (val) => {
  93. val = unref(val)
  94. return isObject(val) ? val?.[optionProps.value.value] ?? '' : val
  95. }
  96. watch(selectedRows, (val) => {
  97. if(props.multiple){
  98. emit('update:modelValue', val)
  99. }else{
  100. const currentValue = val[0]
  101. const isSameValue = getSingelSelectedValue(currentValue) === getSingelSelectedValue(props.modelValue)
  102. if(isSameValue){
  103. return
  104. }
  105. emit('update:modelValue', currentValue)
  106. }
  107. }, { deep: true })
  108. onMounted(() => {
  109. watch(itemList, () => {
  110. nextTick().then(() => setCurrentSelect())
  111. })
  112. watch(() => props.modelValue, (val) => {
  113. // 浅拷贝
  114. // 先清空
  115. tableRef.value.cipTableRef.clearSelection()
  116. // 赋值
  117. if (props.multiple) {
  118. selectedRows.value = val || []
  119. } else {
  120. if (isNotEmpty(val)) {
  121. selectedRows.value = [val]
  122. } else {
  123. selectedRows.value = []
  124. }
  125. }
  126. // 设置选中
  127. setCurrentSelect()
  128. }, { immediate: true })
  129. })
  130. return () => <div class={['cip-select-table', `cip-select-table--${props.direction}`]} style={{ flexDirection: props.direction }}>
  131. <CipPageLayoutList class={'cip-select-table__table'} noPadding={true}>
  132. {{
  133. filter: props.searchFieldList?.length > 0
  134. ? () => <CipSearchForm
  135. v-model:model={searchFilter.value}
  136. defaultModel={defaultSearchFilter.value}
  137. fieldList={props.searchFieldList}
  138. hideSearch={props.hideSearch}
  139. onSearch={search}
  140. />
  141. : undefined,
  142. default: () => <CipTable
  143. ref={tableRef}
  144. v-loading={listLoading.value}
  145. data={itemList.value}
  146. selectType={selectType.value}
  147. selectRadio={selectRadio.value}
  148. selectLabel={optionProps.value.value}
  149. hideIndex={props.hideIndex}
  150. offset={offset.value}
  151. columns={props.tableColumns}
  152. selectable={props.selectable}
  153. onSelect={handleSelect}
  154. onSelectAll={handleSelectAll}
  155. onRow-click={currentChange}
  156. />,
  157. pagination: props.withPagination
  158. ? () => <CipPagination
  159. v-model:offset={offset.value}
  160. v-model:limit={limit.value}
  161. background={false}
  162. layout={'prev, pager, next'}
  163. total={total.value}
  164. current-page={currentPage.value}
  165. onRefresh={getItemList} />
  166. : undefined
  167. }}
  168. </CipPageLayoutList>
  169. {props.withDivider && <div class={'cip-select-table__divider'}/>}
  170. {/* v-if="!$slots.group && withTags" */}
  171. {props.withTags && <div
  172. class={['cip-select-table__tags', { 'limited-height': props.direction.indexOf('column') !== -1 }]}
  173. style={{ flexBasis: props.direction.includes('row') ? '220px' : '100px' }}
  174. >
  175. <SelectTags
  176. modelValue={selectedRows.value}
  177. optionProps={optionProps.value}
  178. onRemove={(index) => removeSelectRow(index)}
  179. />
  180. </div>}
  181. </div>
  182. }
  183. }