ModalSelect.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import type VbModalVue from '@@@/modal/VbModal.vue';
  2. <script setup lang="ts">
  3. const props = withDefaults(
  4. defineProps<{
  5. modelValue?: any[] | any
  6. selectList?: any[] | any
  7. tableOpts: {
  8. columns: any[]
  9. queryParams: any
  10. tableListFun: any
  11. searchFormItems?: any[]
  12. customBtns?: any[]
  13. }
  14. modalTitle: string
  15. showTag?: boolean
  16. tagId?: string
  17. tagName?: string
  18. optionSelectFun?: (v: any) => any // 自定义选项数据转换,如果需要回显则需要配置,一般不需要
  19. convertDataFun: (v: any) => any
  20. modalConfig?: any
  21. multiple?: boolean
  22. saveAutoClose?: boolean
  23. queryCustomFun?: (v: any) => any
  24. }>(),
  25. {
  26. showTag: false,
  27. tagId: "id",
  28. tagName: "name",
  29. multiple: true,
  30. saveAutoClose: true
  31. }
  32. )
  33. const emits = defineEmits<{
  34. (e: "update:modelValue", v: any[]): void
  35. (e: "update:selectList", v: any[]): void
  36. (e: "confirm", v: any[]): void
  37. }>()
  38. const selectIds = ref<string[]>([])
  39. const selectList = ref<any[]>([])
  40. const tableRef = ref()
  41. const modalRef = ref()
  42. const tableOpts = reactive(props.tableOpts)
  43. const modalOpts = computed(() => {
  44. return Object.assign(
  45. {
  46. title: props.modalTitle,
  47. modalDialogStyle: "width:1200px;max-width:1200px;",
  48. modalBodyClass: "pt-0",
  49. saveAutoClose: false
  50. },
  51. props.modalConfig || {}
  52. )
  53. })
  54. const { queryParams } = toRefs(tableOpts)
  55. /** 搜索按钮操作 */
  56. function handleQuery(query?: any) {
  57. query = query || tableRef.value?.getQueryParams() || queryParams.value
  58. if (props.queryCustomFun) {
  59. query = props.queryCustomFun(query)
  60. }
  61. tableRef.value?.query(query)
  62. //addDateRange(query, query.dateRange)
  63. initSelectData()
  64. }
  65. /** 重置按钮操作 */
  66. function resetQuery(query?: any) {
  67. query = query || tableRef.value?.getQueryParams() || queryParams.value
  68. query.dateRange = []
  69. addDateRange(query, query.dateRange)
  70. }
  71. function onCheckboxChange(isChecked: boolean, row: any) {
  72. if (!props.multiple && isChecked) {
  73. selectList.value = []
  74. }
  75. if (isChecked) {
  76. selectList.value.push(convertData(row))
  77. } else {
  78. selectList.value = selectList.value.filter((item: any) => item[props.tagId] != row[props.tagId])
  79. }
  80. selectIds.value = selectList.value.map((v: any) => String(v[props.tagId]))
  81. emits("update:selectList", selectList.value)
  82. }
  83. function onCheckboxAll(isChecked: boolean, rows: any[]) {
  84. if (isChecked) {
  85. rows.forEach((row) => {
  86. if (!selectList.value.some((item: any) => item[props.tagId] === row[props.tagId])) {
  87. selectList.value.push(convertData(row))
  88. }
  89. })
  90. } else {
  91. selectList.value = selectList.value.filter((item: any) => {
  92. return !rows.some((row) => row[props.tagId] == item[props.tagId])
  93. })
  94. }
  95. selectIds.value = selectList.value.map((v: any) => String(v[props.tagId]))
  96. emits("update:selectList", selectList.value)
  97. }
  98. function handleCloseTag(item: any) {
  99. const index = selectList.value.findIndex((v: any) => v[props.tagId] == item[props.tagId])
  100. if (index > -1) {
  101. const row = tableRef.value.getData().find((v: any) => v[props.tagId] == item[props.tagId])
  102. tableRef.value?.setSelecteds([row], false)
  103. selectList.value.splice(index, 1)
  104. }
  105. }
  106. /**
  107. * 初始化选中数据
  108. */
  109. function initSelectData() {
  110. const ids = selectIds.value
  111. if (ids.length > 0) {
  112. if (props.optionSelectFun) {
  113. props.optionSelectFun(ids).then((res: any) => {
  114. selectList.value = res.data ? res.data.map((v: any) => convertData(v)) : []
  115. emits("update:selectList", selectList.value)
  116. })
  117. }
  118. let i = 0,
  119. data = []
  120. init()
  121. function init() {
  122. data = toValue(tableRef.value.getData())
  123. if (i <= 100 && data.length <= 0) {
  124. i++
  125. setTimeout(init, 100)
  126. }
  127. if (data.length > 0) {
  128. const rows = data.filter((item: any) => {
  129. return ids.includes(String(item[props.tagId]))
  130. })
  131. nextTick(() => {
  132. tableRef.value.setSelecteds(rows, true)
  133. })
  134. }
  135. }
  136. }
  137. }
  138. function convertData(row: any) {
  139. return props.convertDataFun(row)
  140. }
  141. function confirm() {
  142. emits("update:modelValue", selectIds.value)
  143. emits("confirm", selectList.value)
  144. if (props.saveAutoClose) {
  145. close()
  146. }
  147. }
  148. function initSelectIds() {
  149. selectIds.value = []
  150. const data = props.modelValue
  151. if (!data) {
  152. return
  153. }
  154. if (data instanceof Array) {
  155. selectIds.value = data.map((v) => String(v))
  156. } else if (typeof data === "string") {
  157. selectIds.value = data.split(",").map((v) => String(v))
  158. } else if (typeof data === "number") {
  159. selectIds.value = [String(data)]
  160. } else {
  161. console.warn("<ModalSelect> 数据的数据类型应该是数组、字符串或数字")
  162. }
  163. }
  164. function init() {
  165. //initSelectIds()
  166. }
  167. function open() {
  168. initSelectIds()
  169. handleQuery()
  170. modalRef.value.show()
  171. }
  172. function close() {
  173. tableRef.value.clearSelecteds()
  174. selectList.value = []
  175. modalRef.value.hide()
  176. }
  177. onMounted(init)
  178. defineExpose({
  179. open,
  180. close,
  181. handleQuery
  182. })
  183. </script>
  184. <template>
  185. <div>
  186. <VbModal
  187. v-model:modal="modalRef"
  188. :title="modalOpts.title"
  189. v-bind="modalOpts"
  190. :save-auto-close="false"
  191. @confirm="confirm"
  192. append-to-body>
  193. <template #body>
  194. <transition-group name="vb-fade">
  195. <el-card shadow="hover" class="mt-5 mb-2">
  196. <el-tag
  197. v-for="(data, key) in selectList"
  198. :key="key"
  199. closable
  200. style="margin: 2px"
  201. @close="handleCloseTag(data)">
  202. {{ data[props.tagName] }}
  203. </el-tag>
  204. </el-card>
  205. </transition-group>
  206. <VbDataTable
  207. ref="tableRef"
  208. v-model:query-params="queryParams"
  209. :search-form-items="tableOpts.searchFormItems"
  210. :columns="tableOpts.columns"
  211. :remote-fun="tableOpts.tableListFun"
  212. :check-multiple="multiple"
  213. :has-checkbox="true"
  214. :show-right-toolbar="false"
  215. :reset-search-form-fun="resetQuery"
  216. :custom-search-fun="handleQuery"
  217. :page-size="10"
  218. :init-search="false"
  219. :page-size-array="[10, 20, 50, 100]"
  220. @checkbox-change="onCheckboxChange"
  221. @checkbox-all="onCheckboxAll"
  222. table-box-height="70vh">
  223. <template v-for="(_, name) in $slots" #[name]="{ row }">
  224. <slot :name="name" :row="row" />
  225. </template>
  226. </VbDataTable>
  227. </template>
  228. </VbModal>
  229. </div>
  230. </template>