select-table.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div class="select-table">
  3. <div class="select-table-box" :style="{flexDirection: direction}">
  4. <page-layout-list class="dialog-table">
  5. <template #filter v-if="searchFieldList && searchFieldList.length>0">
  6. <cip-search-form v-model:model="searchFilter" :field-list="searchFieldList" @search="handleSearch" :hideSearch="hideSearch"></cip-search-form>
  7. </template>
  8. <cip-table v-if="checkType === 'radio'"
  9. :data="itemList"
  10. :columns="tableColumns"
  11. :offset="offset"
  12. ref="tableRef"
  13. size="small"
  14. :select-type="checkType"
  15. :select-radio="selectRadio"
  16. :select-label="optionProps.value"
  17. @current-change="currentChange"
  18. v-loading="listLoading">
  19. </cip-table>
  20. <cip-table v-if="checkType === 'checkbox'"
  21. :data="itemList"
  22. :columns="tableColumns"
  23. :offset="offset"
  24. ref="tableRef"
  25. size="small"
  26. :select-type="checkType"
  27. @select="onSelect"
  28. @select-all="onSelectAll"
  29. :selectable="selectable"
  30. v-loading="listLoading">
  31. </cip-table>
  32. <template #pagination v-if="withPagination">
  33. <cip-pagination v-model:offset="offset"
  34. v-model:limit="limit"
  35. :total="total"
  36. :current-page="currentPage"
  37. layout="total, sizes, prev, next, jumper"
  38. prev-text="上一页"
  39. next-text="下一页"
  40. @refresh="getItemList"></cip-pagination>
  41. </template>
  42. </page-layout-list>
  43. <slot name="group"></slot>
  44. <tags v-if="!$slots.group" class="dialog-tags" :style="{flexBasis: direction.includes('row')?'220px':'100px'}" :options="checkOptions" :keyProp="optionProps" @update:options="changeOptions"></tags>
  45. </div>
  46. </div>
  47. </template>
  48. <script>
  49. import { useCurd } from '@cip/hooks/use-curd'
  50. import { useTableCacheSelect } from '@cip/components/hooks/table-cache-select'
  51. import { ref, computed, nextTick, watch, watchEffect } from 'vue'
  52. import { ElLoading } from 'element-plus'
  53. import PageLayoutList from '@cip/components/page-layout/list'
  54. import CipSearchForm from '@cip/components/cip-search-form'
  55. import CipTable from '@cip/components/cip-table'
  56. import CipPagination from '@cip/components/cip-pagination'
  57. import Tags from './tags'
  58. export default {
  59. components: { Tags, PageLayoutList, CipSearchForm, CipTable, CipPagination },
  60. directives: {
  61. loading: ElLoading.directive
  62. },
  63. props: {
  64. entity: {},
  65. curdFn: {},
  66. tableColumns: {},
  67. searchFieldList: {},
  68. modelValue: [String, Object],
  69. otherValue: String,
  70. checkedItem: {},
  71. searchCustomize: {
  72. type: Boolean,
  73. default: false
  74. },
  75. optionProps: {
  76. type: Object,
  77. default: () => ({ label: 'label', value: 'value' })
  78. },
  79. defaultSearchFilter: {
  80. type: Object
  81. },
  82. checkType: {
  83. type: String,
  84. default: 'radio'
  85. },
  86. hideSearch: Boolean,
  87. withPagination: { // 是否显示分页
  88. type: Boolean,
  89. default: true
  90. },
  91. direction: { type: String, default: 'row' } // 布局方向
  92. },
  93. emits: ['selectValue', 'customizeSearch'],
  94. setup (props, { emit }) {
  95. const checkOptions = computed(() => {
  96. return cacheSelectedList.value.length === 0 ? props.checkedItem : cacheSelectedList.value
  97. })
  98. // 右侧数据改变
  99. const changeOptions = (item) => {
  100. cacheSelectedList.value = item
  101. updateSelectValue(item)
  102. handleSelectShow()
  103. }
  104. const updateSelectValue = (item) => {
  105. emit('selectValue', item)
  106. }
  107. const tableRef = ref()
  108. const CURD = useCurd(props.entity, { ...props.curdFn, itemType: props.itemType })
  109. const { itemList, getItemList, searchFilter, search } = CURD
  110. if (props.defaultSearchFilter) {
  111. searchFilter.value = { ...props.defaultSearchFilter }
  112. }
  113. getItemList()
  114. const primaryKey = ref(props.optionProps.value)
  115. const { cacheSelectedList, onSelect, onSelectAll } = useTableCacheSelect(itemList, primaryKey.value, val => {
  116. updateSelectValue(val)
  117. })
  118. // 外层触发请求
  119. const getTableList = (item = {}) => {
  120. searchFilter.value = item
  121. getItemList()
  122. }
  123. // 已选择的radio
  124. const selectRadio = computed(() => {
  125. return props.checkedItem[primaryKey.value] || radioCache.value
  126. })
  127. // radio类型时的缓存
  128. const radioCache = computed(() => {
  129. const cache = itemList.value.find(v => v[primaryKey.value] === props.modelValue)
  130. return cache ? cache[primaryKey.value] : undefined
  131. })
  132. const currentChange = (currentRow, oldCurrentRow) => {
  133. // 单选不能取消,只能有值时才填入
  134. if (currentRow) {
  135. updateSelectValue(currentRow)
  136. }
  137. }
  138. // checkbox类型更新选中视图
  139. const showSelectedView = (rows, select) => {
  140. nextTick(() => {
  141. rows.forEach(row => {
  142. tableRef.value.cipTableRef.value.toggleRowSelection(row, select)
  143. })
  144. })
  145. }
  146. // tag组件传入值需要更新table选中视图
  147. const handleSelectShow = () => {
  148. const selectedPropsCode = cacheSelectedList.value.map(button => button[primaryKey.value])
  149. const rows = itemList.value.filter(item => {
  150. return !selectedPropsCode.includes(item[primaryKey.value])
  151. })
  152. showSelectedView(rows, false)
  153. }
  154. if (props.checkType === 'checkbox') {
  155. // 分页切换时缓存数据处理
  156. watch(itemList, list => {
  157. cacheHandle()
  158. })
  159. } else {
  160. const unWatch = watchEffect(() => {
  161. if (props.checkedItem[primaryKey.value]) {
  162. const checkItem = itemList.value.filter(item => item[primaryKey.value] === props.checkedItem[props.optionProps.value])[0]
  163. if (checkItem) {
  164. updateSelectValue(checkItem)
  165. unWatch()
  166. }
  167. }
  168. })
  169. }
  170. // 缓存数据处理
  171. const cacheHandle = () => {
  172. if (cacheSelectedList.value.length === 0) {
  173. cacheSelectedList.value = props.checkedItem
  174. }
  175. const cacheSelectButtonCode = cacheSelectedList.value.map(button => button[primaryKey.value])
  176. const rows = itemList.value.filter(item => {
  177. const selectList = props.checkedItem || cacheSelectButtonCode.includes(item[primaryKey])
  178. return selectList.findIndex(v => String(v[props.optionProps.value]) === String(item[props.optionProps.value])) !== -1
  179. })
  180. showSelectedView(rows, true)
  181. }
  182. // 所有column可选
  183. const selectable = () => () => true
  184. // 搜索
  185. const handleSearch = () => {
  186. search()
  187. }
  188. return {
  189. changeOptions,
  190. checkOptions,
  191. getTableList,
  192. handleSearch,
  193. ...CURD,
  194. tableRef,
  195. selectable,
  196. selectRadio,
  197. currentChange,
  198. onSelect,
  199. onSelectAll,
  200. cacheSelectedList
  201. }
  202. }
  203. }
  204. </script>
  205. <style lang="less" scoped>
  206. .select-table{
  207. flex: 1;
  208. .select-table-box{
  209. display: flex;
  210. background: @background;
  211. padding: 20px;
  212. }
  213. .dialog-table{
  214. flex: 1;
  215. margin: 0 15px 15px 0;
  216. padding: 0;
  217. }
  218. .dialog-tags{
  219. padding: 8px 0;
  220. flex-basis: 220px;
  221. }
  222. }
  223. </style>