314 lines
7.5 KiB
Vue
314 lines
7.5 KiB
Vue
|
|
<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>
|