index.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <template>
  2. <div class="select-table">
  3. <cip-search-form v-if="searchFieldList.length > 0"
  4. style="margin-bottom: 10px;"
  5. :grid="3"
  6. v-model:model="searchFilter"
  7. :field-list="searchFieldList"
  8. :default-model="config?.defaultSearchFilter"
  9. @search="handleSearch" />
  10. <div class="select-table-box">
  11. <page-layout-list class="dialog-table">
  12. <cip-table
  13. v-if="checkType === 'radio'"
  14. ref="tableRef"
  15. v-loading="listLoading"
  16. :data="itemList"
  17. :columns="tableColumns"
  18. :offset="offset"
  19. size="small"
  20. :select-type="checkType"
  21. :select-radio="selectRadio"
  22. :select-label="optionProps.value"
  23. @current-change="currentChange"></cip-table>
  24. <cip-table
  25. v-if="checkType === 'checkbox'"
  26. ref="tableRef"
  27. v-loading="listLoading"
  28. :data="itemList"
  29. :columns="tableColumns"
  30. :offset="offset"
  31. size="small"
  32. :select-type="checkType"
  33. :selectable="selectable"
  34. @select="onSelect"
  35. @select-all="onSelectAll"></cip-table>
  36. <template v-if="withPagination" #pagination>
  37. <cip-pagination
  38. v-model:offset="offset"
  39. v-model:limit="limit"
  40. :total="total"
  41. :current-page="currentPage"
  42. @refresh="getItemList"></cip-pagination>
  43. </template>
  44. </page-layout-list>
  45. <slot name="group"></slot>
  46. <tags
  47. v-if="!$slots.group && withTags"
  48. class="dialog-tags"
  49. :options="checkOptions"
  50. :key-prop="optionProps"
  51. @update:options="updateOptions"></tags>
  52. </div>
  53. </div>
  54. </template>
  55. <script>
  56. import { useCurd } from '@cip/hooks/use-curd'
  57. import { useTableCacheSelect } from '@cip/components/hooks/table-cache-select'
  58. import { ref, computed, nextTick, watch, watchEffect } from 'vue'
  59. import { ElLoading } from 'element-plus'
  60. import PageLayoutList from '@cip/components/page-layout/list'
  61. import CipSearchForm from '@cip/components/cip-search-form'
  62. import CipTable from '@cip/components/cip-table'
  63. import CipPagination from '@cip/components/cip-pagination'
  64. import { useFormInput, useOptions } from '@cip/components/hooks/form-input'
  65. import { formInputProps, fromInputEmits } from '../../form-input-props'
  66. import Tags from './tags.vue'
  67. export default {
  68. components: { Tags, PageLayoutList, CipSearchForm, CipTable, CipPagination },
  69. directives: {
  70. loading: ElLoading.directive
  71. },
  72. props: formInputProps,
  73. emits: [...fromInputEmits],
  74. setup (props, context) {
  75. const { proxyValue, updateStream, securityConfig } = useFormInput(
  76. props,
  77. context
  78. )
  79. const { optionProps } = useOptions(props, false, updateStream)
  80. const valueKey = computed(() => optionProps.value.value)
  81. const labelKey = computed(() => optionProps.value.label)
  82. const checkType = computed(() => securityConfig.value.checkType ?? 'radio')
  83. const tableColumns = computed(() => securityConfig.value.tableColumns ?? [])
  84. const searchFieldList = computed(
  85. () => securityConfig.value.searchFieldList ?? []
  86. )
  87. const withPagination = computed(
  88. () => securityConfig.value.withPagination ?? true
  89. )
  90. const withTags = computed(() => securityConfig.value.withTags ?? true)
  91. const selectable = computed(
  92. () => securityConfig.value.selectable ?? (() => true)
  93. )
  94. const multiple = computed(() => checkType.value === 'checkbox')
  95. const tableRef = ref()
  96. const CURD = useCurd(props.config.entity, {
  97. ...props.config.curdFn,
  98. itemType: props.config.itemType
  99. })
  100. const { itemList, getItemList, searchFilter, search } = CURD
  101. // 外层触发请求
  102. const getTableList = (item = {}) => {
  103. searchFilter.value = {
  104. ...props.config.defaultSearchFilter,
  105. ...searchFilter.value,
  106. ...item
  107. }
  108. getItemList()
  109. }
  110. // 外层获取search搜索条件值
  111. const getSearchFilter = () => {
  112. return { ...props.config.defaultSearchFilter, ...searchFilter.value }
  113. }
  114. const { cacheSelectedList, onSelect, onSelectAll } = useTableCacheSelect(
  115. itemList,
  116. valueKey.value,
  117. (val) => {
  118. proxyValue.value = val
  119. }
  120. )
  121. const checkOptions = computed(() => {
  122. if (cacheSelectedList.value.length === 0) {
  123. if (props.modelValue) {
  124. return multiple.value
  125. ? props.modelValue
  126. : {
  127. [valueKey.value]: props.modelValue[valueKey.value] ?? '',
  128. [labelKey.value]: props.modelValue[labelKey.value] ?? ''
  129. }
  130. }
  131. return multiple.value ? [] : {}
  132. } else {
  133. return cacheSelectedList.value
  134. }
  135. })
  136. // 右侧数据改变
  137. const updateOptions = (newSelectedValue) => {
  138. cacheSelectedList.value = newSelectedValue
  139. proxyValue.value = newSelectedValue
  140. handleSelectShow()
  141. }
  142. watch(
  143. () => props.config?.defaultSearchFilter,
  144. (val = {}) => {
  145. getTableList(val)
  146. },
  147. { immediate: true }
  148. )
  149. // 已选择的radio
  150. const selectRadio = computed(() => {
  151. if (props.modelValue && props.modelValue[valueKey.value]) {
  152. return props.modelValue[valueKey.value]
  153. }
  154. return radioCache.value
  155. })
  156. // radio类型时的缓存
  157. const radioCache = computed(() => {
  158. const cache = itemList.value?.find(
  159. (v) => v[valueKey.value] === props.modelValue
  160. )
  161. return cache ? cache[valueKey.value] : undefined
  162. })
  163. const currentChange = (currentRow) => {
  164. // 单选不能取消,只能有值时才填入
  165. if (currentRow) {
  166. proxyValue.value = currentRow
  167. }
  168. }
  169. // checkbox类型更新选中视图
  170. const showSelectedView = (rows, select) => {
  171. nextTick(() => {
  172. rows.forEach((row) => {
  173. tableRef.value.cipTableRef.toggleRowSelection(row, select)
  174. })
  175. })
  176. }
  177. // tag组件传入值需要更新table选中视图
  178. const handleSelectShow = () => {
  179. const selectedPropsCode = cacheSelectedList.value.map(
  180. (button) => button[valueKey.value]
  181. )
  182. const rows = itemList.value.filter((item) => {
  183. return !selectedPropsCode.includes(item[valueKey.value])
  184. })
  185. showSelectedView(rows, false)
  186. }
  187. if (checkType.value === 'checkbox') {
  188. // 分页切换时缓存数据处理
  189. watch(
  190. () => [itemList.value, props.modelValue],
  191. () => {
  192. cacheHandle()
  193. }
  194. )
  195. } else {
  196. const unWatch = watchEffect(() => {
  197. if (props.modelValue && props.modelValue[valueKey.value]) {
  198. const checkItem = itemList.value.filter(
  199. (item) => item[valueKey.value] === props.modelValue[valueKey.value]
  200. )[0]
  201. if (checkItem) {
  202. proxyValue.value = checkItem
  203. unWatch()
  204. }
  205. }
  206. })
  207. }
  208. // 缓存数据处理
  209. const cacheHandle = () => {
  210. if (cacheSelectedList.value.length === 0) {
  211. cacheSelectedList.value = props.modelValue ?? []
  212. }
  213. const cacheSelectButtonCode = cacheSelectedList.value.map(
  214. (button) => button[valueKey.value]
  215. )
  216. const rows = itemList.value.filter((item) => {
  217. const selectList =
  218. props.modelValue ||
  219. (cacheSelectButtonCode.includes(item[valueKey.value])
  220. ? cacheSelectButtonCode
  221. : [])
  222. return (
  223. selectList.findIndex(
  224. (v) => v[valueKey.value] === item[valueKey.value]
  225. ) !== -1
  226. )
  227. })
  228. showSelectedView(rows, true)
  229. }
  230. // 搜索
  231. const handleSearch = (type) => {
  232. search()
  233. }
  234. return {
  235. updateOptions,
  236. checkOptions,
  237. getTableList,
  238. getSearchFilter,
  239. handleSearch,
  240. optionProps,
  241. checkType,
  242. tableColumns,
  243. searchFieldList,
  244. withPagination,
  245. withTags,
  246. ...CURD,
  247. tableRef,
  248. selectable,
  249. selectRadio,
  250. currentChange,
  251. onSelect,
  252. onSelectAll,
  253. cacheSelectedList
  254. }
  255. }
  256. }
  257. </script>
  258. <style lang="less" scoped>
  259. .select-table {
  260. flex: 1;
  261. .select-table-box {
  262. display: flex;
  263. }
  264. .dialog-table {
  265. flex: 1;
  266. margin: 0 15px 15px 0;
  267. padding: 0;
  268. }
  269. .dialog-tags {
  270. padding: 8px 0;
  271. flex-basis: 220px;
  272. }
  273. }
  274. </style>