index.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <el-dialog v-model="visible" title="选择设备分类" width="800px" :close-on-click-modal="false" @close="onCancel">
  3. <div style="margin-bottom: 12px">
  4. <el-input v-model="search" placeholder="输入关键字搜索" style="width: 240px; margin-right: 8px" @keyup.enter="fetchData(true)" />
  5. <el-button type="primary" @click="fetchData(true)">搜索</el-button>
  6. </div>
  7. <el-table :data="tableData" border style="width: 100%" @selection-change="onSelectionChange" ref="tableRef" row-key="id">
  8. <el-table-column type="selection" width="50" :reserve-selection="true" />
  9. <el-table-column type="index" label="序号" width="60" />
  10. <!-- <el-table-column prop="code" label="分类编号" /> -->
  11. <el-table-column prop="name" label="设备分类" />
  12. <el-table-column prop="description" label="描述" min-width="160" />
  13. <!-- <el-table-column prop="category_name" label="设备分类" />
  14. <el-table-column prop="warehouse" label="存放仓库" />-->
  15. </el-table>
  16. <el-pagination
  17. style="margin-top: 12px; text-align: right"
  18. :current-page="page"
  19. :page-size="pageSize"
  20. :total="total"
  21. @current-change="onPageChange"
  22. />
  23. <template #footer>
  24. <el-button @click="onCancel">取消</el-button>
  25. <el-button type="primary" @click="onConfirm">确定</el-button>
  26. </template>
  27. </el-dialog>
  28. </template>
  29. <script setup lang="ts">
  30. import { ref, watch, defineProps, defineEmits, nextTick } from 'vue';
  31. import * as deviceApi from '../../../deviceclass/api';
  32. import * as storeapi from '../../../storelist/api';
  33. import { status } from 'nprogress';
  34. const props = defineProps<{ visible: boolean }>();
  35. const emit = defineEmits(['update:visible', 'confirm']);
  36. const visible = ref(props.visible);
  37. watch(
  38. () => props.visible,
  39. (v) => (visible.value = v)
  40. );
  41. const search = ref('');
  42. const page = ref(1);
  43. const pageSize = ref(10);
  44. const total = ref(0);
  45. const tableData = ref<any[]>([]);
  46. const selectedRows = ref<any[]>([]);
  47. const warehouseMap = ref<Record<number, string>>({});
  48. // 用于存储所有已选中的项(跨页)
  49. const selectedMap = ref<Map<number | string, any>>(new Map());
  50. const tableRef = ref();
  51. // 标志位:是否正在恢复选中状态(避免触发 onSelectionChange 时误删数据)
  52. const isRestoring = ref(false);
  53. function fetchWarehouseMap() {
  54. storeapi.GetPermission().then((res: any) => {
  55. const map: Record<number, string> = {};
  56. res.data.forEach((item: any) => {
  57. map[item.id] = item.name;
  58. });
  59. warehouseMap.value = map;
  60. });
  61. }
  62. async function fetchData(resetPage = false) {
  63. if (resetPage) page.value = 1;
  64. await fetchWarehouseMap();
  65. deviceApi.GetList({ page: page.value, limit: pageSize.value, code: search.value,status:1 })
  66. .then((res: any) => {
  67. const devices = res.data
  68. /* .filter(device => device.available_quantity > 0)
  69. .map((device) => ({
  70. ...device,
  71. warehouse: `${warehouseMap.value[device.warehouse] || `ID:${device.warehouse}`} (${device.available_quantity})`
  72. })); */
  73. tableData.value = devices;
  74. // tableData.value = [...res.data];
  75. total.value = res.total;
  76. // 数据加载完成后,回显当前页的选中状态
  77. nextTick(() => {
  78. restoreSelection();
  79. });
  80. });
  81. }
  82. // 恢复当前页的选中状态
  83. function restoreSelection() {
  84. if (!tableRef.value) return;
  85. // 设置标志位,避免 onSelectionChange 误删数据
  86. isRestoring.value = true;
  87. // 先清空当前页的所有选中
  88. tableData.value.forEach((row: any) => {
  89. tableRef.value.toggleRowSelection(row, false);
  90. });
  91. // 根据 selectedMap 设置当前页的选中状态
  92. tableData.value.forEach((row: any) => {
  93. if (selectedMap.value.has(row.id)) {
  94. tableRef.value.toggleRowSelection(row, true);
  95. }
  96. });
  97. // 恢复标志位
  98. isRestoring.value = false;
  99. // 更新当前页的选中数组
  100. updateSelectedRows();
  101. }
  102. // 更新当前页的选中数组
  103. function updateSelectedRows() {
  104. selectedRows.value = tableData.value.filter((row: any) => selectedMap.value.has(row.id));
  105. }
  106. function onSelectionChange(val: any[]) {
  107. // 如果正在恢复选中状态,不更新 selectedMap(避免误删数据)
  108. if (isRestoring.value) {
  109. return;
  110. }
  111. // 获取当前页所有行的 id
  112. const currentPageIds = new Set(tableData.value.map((row: any) => row.id));
  113. // 移除当前页中未选中的项
  114. currentPageIds.forEach((id) => {
  115. const isSelected = val.some((item: any) => item.id === id);
  116. if (!isSelected) {
  117. selectedMap.value.delete(id);
  118. }
  119. });
  120. // 添加当前页中新选中的项
  121. val.forEach((item: any) => {
  122. if (!selectedMap.value.has(item.id)) {
  123. selectedMap.value.set(item.id, item);
  124. } else {
  125. // 如果已存在,更新数据(防止数据过期)
  126. selectedMap.value.set(item.id, item);
  127. }
  128. });
  129. // 更新当前页的选中数组
  130. selectedRows.value = val;
  131. }
  132. function onPageChange(val: number) {
  133. page.value = val;
  134. fetchData();
  135. }
  136. function onConfirm() {
  137. // 返回所有选中的项(跨页)
  138. const allSelected = Array.from(selectedMap.value.values());
  139. emit('confirm', allSelected);
  140. emit('update:visible', false);
  141. }
  142. function onCancel() {
  143. // 取消时清空选中状态
  144. selectedMap.value.clear();
  145. selectedRows.value = [];
  146. emit('update:visible', false);
  147. }
  148. watch([visible, page], (v) => {
  149. if (visible.value) {
  150. fetchData();
  151. } else {
  152. // 对话框关闭时不清空选中状态,以便下次打开时保留
  153. // 如果需要关闭时清空,可以在这里调用 selectedMap.value.clear()
  154. }
  155. });
  156. </script>