select-table.vue 8.4 KB

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