Files
admin-ui/src/views/assets/operation/count/component/scopeSelectDialog.vue

314 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-dialog
v-model="visible"
:title="dialogTitle"
width="800px"
:close-on-click-modal="false"
@close="handleClose"
>
<!-- 搜索栏 -->
<div class="search-bar">
<el-input
v-model="searchKeyword"
placeholder="请输入关键词搜索"
clearable
style="width: 300px"
@keyup.enter="handleSearch"
>
<template #append>
<el-button @click="handleSearch">
<el-icon><ele-Search /></el-icon>
</el-button>
</template>
</el-input>
</div>
<!-- 数据表格 -->
<el-table
ref="tableRef"
:data="tableData"
v-loading="loading"
border
style="width: 100%; margin-top: 15px"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="name" :label="getColumnLabel()" min-width="200" show-overflow-tooltip />
<el-table-column prop="code" label="编码" width="150" show-overflow-tooltip v-if="scope <= 2" />
</el-table>
<!-- 分页 -->
<div class="pagination-box">
<el-pagination
v-model:current-page="pageNum"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
<!-- 已选项展示 -->
<div class="selected-box" v-if="selectedItems.length > 0">
<span class="selected-label">已选择 {{ selectedItems.length }} </span>
<el-tag
v-for="item in selectedItems"
:key="item.id"
size="small"
closable
style="margin-right: 4px; margin-bottom: 4px"
@close="removeSelected(item)"
>
{{ item.name }}
</el-tag>
</div>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { listWarehouses } from '/@/api/assets/warehouse';
import { listZones } from '/@/api/assets/zone';
import { listLocations } from '/@/api/assets/location';
const emit = defineEmits(['confirm']);
const visible = ref(false);
const loading = ref(false);
const scope = ref(1); // 1-仓库 2-库区 3-库位
const searchKeyword = ref('');
const tableData = ref<any[]>([]);
const total = ref(0);
const pageNum = ref(1);
const pageSize = ref(10);
const tableRef = ref();
// 已选项
const selectedItems = ref<any[]>([]);
// 父级ID库区需要仓库ID库位需要库区ID
const parentWarehouseIds = ref<string[]>([]);
const parentZoneIds = ref<string[]>([]);
// 弹窗标题
const dialogTitle = computed(() => {
const titles: Record<number, string> = {
1: '选择仓库',
2: '选择库区',
3: '选择库位',
};
return titles[scope.value] || '选择';
});
// 获取列标题
const getColumnLabel = () => {
const labels: Record<number, string> = {
1: '仓库名称',
2: '库区名称',
3: '库位名称',
};
return labels[scope.value] || '名称';
};
// 打开弹窗
const open = async (data: {
scope: number;
selectedIds: string[];
selectedNames: string[];
warehouseIds?: string[];
zoneIds?: string[];
}) => {
scope.value = data.scope;
parentWarehouseIds.value = data.warehouseIds || [];
parentZoneIds.value = data.zoneIds || [];
// 恢复已选项
selectedItems.value = data.selectedIds.map((id, idx) => ({
id,
name: data.selectedNames[idx] || id,
}));
searchKeyword.value = '';
pageNum.value = 1;
visible.value = true;
await loadData();
};
// 加载数据
const loadData = async () => {
loading.value = true;
try {
let res: any;
const params = {
keyword: searchKeyword.value,
pageNum: pageNum.value,
pageSize: pageSize.value,
};
if (scope.value === 1) {
// 加载仓库
res = await listWarehouses(params);
const list = res.data?.list || [];
tableData.value = list.map((item: any) => ({
id: item.id,
name: item.warehouseName || item.name,
code: item.warehouseCode || item.code,
}));
total.value = res.data?.total || 0;
} else if (scope.value === 2) {
// 加载库区
if (parentWarehouseIds.value.length === 0) {
tableData.value = [];
total.value = 0;
return;
}
const allZones: any[] = [];
let totalCount = 0;
for (const warehouseId of parentWarehouseIds.value) {
res = await listZones({ ...params, warehouseId });
const list = res.data?.list || res.data?.items || res.data || [];
const zones = (Array.isArray(list) ? list : []).map((item: any) => ({
id: item.id || item._id,
name: item.zoneName || item.name,
code: item.zoneCode || item.code,
}));
allZones.push(...zones);
totalCount += res.data?.total || zones.length;
}
tableData.value = allZones;
total.value = totalCount;
} else if (scope.value === 3) {
// 加载库位
if (parentZoneIds.value.length === 0) {
tableData.value = [];
total.value = 0;
return;
}
const allLocations: any[] = [];
let totalCount = 0;
for (const zoneId of parentZoneIds.value) {
res = await listLocations({ ...params, zoneId });
const list = res.data?.list || res.data?.items || res.data || [];
const locations = (Array.isArray(list) ? list : []).map((item: any) => ({
id: item.id || item._id,
name: item.locationName || item.name,
code: item.locationCode || item.code,
}));
allLocations.push(...locations);
totalCount += res.data?.total || locations.length;
}
tableData.value = allLocations;
total.value = totalCount;
}
// 恢复选中状态
setTimeout(() => {
tableData.value.forEach((row: any) => {
if (selectedItems.value.some(item => item.id === row.id)) {
tableRef.value?.toggleRowSelection(row, true);
}
});
}, 0);
} catch (error) {
console.error('加载数据失败:', error);
} finally {
loading.value = false;
}
};
// 搜索
const handleSearch = () => {
pageNum.value = 1;
loadData();
};
// 分页大小变化
const handleSizeChange = () => {
pageNum.value = 1;
loadData();
};
// 页码变化
const handleCurrentChange = () => {
loadData();
};
// 选择变化
const handleSelectionChange = (selection: any[]) => {
// 合并当前页选中和之前选中的(去除当前页取消选中的)
const currentPageIds = tableData.value.map(item => item.id);
// 移除当前页的旧选中
const otherSelected = selectedItems.value.filter(item => !currentPageIds.includes(item.id));
// 添加当前页新选中
selectedItems.value = [...otherSelected, ...selection];
};
// 移除已选
const removeSelected = (item: any) => {
const idx = selectedItems.value.findIndex(i => i.id === item.id);
if (idx > -1) {
selectedItems.value.splice(idx, 1);
// 取消表格选中
const row = tableData.value.find(r => r.id === item.id);
if (row) {
tableRef.value?.toggleRowSelection(row, false);
}
}
};
// 关闭弹窗
const handleClose = () => {
visible.value = false;
};
// 确认选择
const handleConfirm = () => {
emit('confirm', {
selectedIds: selectedItems.value.map(item => item.id),
selectedNames: selectedItems.value.map(item => item.name),
});
handleClose();
};
defineExpose({
open,
});
</script>
<style scoped lang="scss">
.search-bar {
display: flex;
align-items: center;
}
.pagination-box {
display: flex;
justify-content: flex-end;
margin-top: 15px;
}
.selected-box {
margin-top: 15px;
padding: 10px;
background: #f5f7fa;
border-radius: 4px;
.selected-label {
font-size: 14px;
color: #606266;
margin-right: 8px;
}
}
</style>