盘点列表完成

master
lynn 2 years ago
parent 6833f2f332
commit 62d2e2f13f

@ -40,9 +40,22 @@ export function getStocktakingPlanDetail(params) {
} }
// 获取盘点计划物资关联列表 // 获取盘点计划物资关联列表
export function getStocktakingPlanLinkList(params) { export function getStocktakingPlanLinkList(data) {
return request({ return request({
url: '/api/admin/material-infos-plan-link/index', url: '/api/admin/material-infos-plan-link/index',
method: 'post',
data,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
}
// 获取单个盘点计划详情
export function getStocktakingPlanLinkDetail(params) {
return request({
url: '/api/admin/material-infos-plan-link/show',
method: 'get', method: 'get',
params params
}) })

@ -98,6 +98,9 @@
<template slot-scope="{ row }" slot="area"> <template slot-scope="{ row }" slot="area">
{{ row.material_info ? row.material_info.suozaicangku : '-' }} {{ row.material_info ? row.material_info.suozaicangku : '-' }}
</template> </template>
<template slot-scope="{ row }" slot="executor">
{{ row.responsible_admin ? row.responsible_admin.name : '-' }}
</template>
<template slot-scope="{ row }" slot="startTime"> <template slot-scope="{ row }" slot="startTime">
{{ row.material_infos_plan ? row.material_infos_plan.start_date : '-' }} {{ row.material_infos_plan ? row.material_infos_plan.start_date : '-' }}
</template> </template>
@ -109,7 +112,7 @@
</template> </template>
<template slot-scope="{ row }" slot="action"> <template slot-scope="{ row }" slot="action">
<div style="display: flex; gap: 8px; justify-content: center;"> <div style="display: flex; gap: 8px; justify-content: center;">
<Button type="primary" size="small" style="border-radius: 6px;" @click="viewInventoryDetail(row.id)">查看</Button> <Button type="primary" size="small" style="border-radius: 6px;" @click="viewInventoryDetail(row)">查看</Button>
</div> </div>
</template> </template>
</Table> </Table>
@ -248,23 +251,23 @@
<div class="detail-item"> <div class="detail-item">
<span class="label">盘点单号:</span> <span class="label">盘点单号:</span>
<span class="value">{{ detailModal.data.no }}</span> <span class="value">{{ detailModal.data.no }}</span>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<span class="label">所属计划:</span> <span class="label">所属计划:</span>
<span class="value">{{ detailModal.data.planName }}</span> <span class="value">{{ detailModal.data.planName }}</span>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<span class="label">盘点区域:</span> <span class="label">盘点区域:</span>
<span class="value">{{ detailModal.data.area }}</span> <span class="value">{{ detailModal.data.area }}</span>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<span class="label">执行人:</span> <span class="label">执行人:</span>
<span class="value">{{ detailModal.data.executor }}</span> <span class="value">{{ detailModal.data.executor }}</span>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<span class="label">开始时间:</span> <span class="label">开始时间:</span>
<span class="value">{{ detailModal.data.startTime }}</span> <span class="value">{{ detailModal.data.startTime }}</span>
</div> </div>
<div class="detail-item"> <div class="detail-item">
<span class="label">完成时间:</span> <span class="label">完成时间:</span>
<span class="value">{{ detailModal.data.endTime || '-' }}</span> <span class="value">{{ detailModal.data.endTime || '-' }}</span>
@ -276,36 +279,56 @@
{{ getInventoryStatusText(detailModal.data.status) }} {{ getInventoryStatusText(detailModal.data.status) }}
</Tag> </Tag>
</span> </span>
</div>
</div>
<div class="progress-section">
<div class="progress-header">
<h3>盘点进度</h3>
<div class="progress-stats">
<span>已盘点:{{ detailModal.data.checked_count || 0 }}</span>
<span>总数量:{{ detailModal.data.total_count || 0 }}</span>
<span>完成率:{{ detailModal.data.progress || '0%' }}</span>
</div> </div>
</div> </div>
<Progress :percent="detailModal.data.progress_number || 0" :stroke-color="getProgressColor(detailModal.data.progress_number)" />
<div class="material-info-section">
<h3>物资基本信息</h3>
<div class="material-info-content">
<div class="info-item">
<span class="label">物资名称:</span>
<span class="value">{{ detailModal.data.material_info && detailModal.data.material_info.zichanmingcheng || '-' }}</span>
</div>
<div class="info-item">
<span class="label">物资代码:</span>
<span class="value">{{ detailModal.data.material_info && detailModal.data.material_info.wuzibianma || '-' }}</span>
</div>
<div class="info-item">
<span class="label">规格型号:</span>
<span class="value">{{ detailModal.data.material_info && detailModal.data.material_info.guigexinghao || '-' }}</span>
</div> </div>
<div class="info-item">
<span class="label">计量单位:</span>
<span class="value">{{ detailModal.data.material_info && detailModal.data.material_info.jiliangdanwei || '-' }}</span>
</div>
<div class="info-item">
<span class="label">当前库存:</span>
<span class="value">{{ detailModal.data.material_info && detailModal.data.material_info.inventorys_total || '0' }}</span>
</div>
</div>
</div>
<div class="material-section"> <div class="history-section">
<h3>盘点物资列表</h3> <h3>盘点历史记录</h3>
<Table <Table
:columns="detailColumns" :columns="detailColumns"
:data="detailModal.data.materials || []" :data="detailModal.data.history || []"
:loading="detailModal.loading" :loading="detailModal.loading"
border border
> >
<template slot-scope="{ row }" slot="status"> <template slot-scope="{ row }" slot="status">
<Tag :color="getInventoryStatusColor(row.status)">{{ getInventoryStatusText(row.status) }}</Tag> <Tag :color="getInventoryStatusColor(row.status)">{{ getInventoryStatusText(row.status) }}</Tag>
</template> </template>
<template slot-scope="{ row }" slot="diff_quantity"> <template slot-scope="{ row }" slot="photos">
<span :style="{ color: row.diff_quantity > 0 ? '#19be6b' : row.diff_quantity < 0 ? '#ed4014' : '#515a6e' }"> <div class="photo-list" v-if="row.files && row.files.length">
{{ row.diff_quantity > 0 ? '+' + row.diff_quantity : row.diff_quantity }} <div class="photo-item" v-for="(file, index) in row.files.slice(0, 3)" :key="index">
</span> <img :src="file.url" @click="previewImage(file.url)" />
</div>
<div class="photo-more" v-if="row.files.length > 3">
+{{ row.files.length - 3 }}
</div>
</div>
<span v-else>-</span>
</template> </template>
</Table> </Table>
<div class="pagination-container"> <div class="pagination-container">
@ -319,17 +342,22 @@
:total="detailModal.total" :total="detailModal.total"
/> />
</div> </div>
</div>
</div> </div>
</div>
<template slot="footer"> <template slot="footer">
<Button @click="detailModal.visible = false">关闭</Button> <Button @click="detailModal.visible = false">关闭</Button>
</template> </template>
</Modal> </Modal>
<!-- 预览弹窗 -->
<div v-if="previewUrl" class="image-preview-modal" @click="closePreview">
<img :src="previewUrl" class="image-preview-large" />
</div>
</div> </div>
</template> </template>
<script> <script>
import { saveStocktakingPlan, getStocktakingPlanList, deleteStocktakingPlan, getStocktakingPlanLinkList } from '@/api/system/stocktaking' import { saveStocktakingPlan, getStocktakingPlanList, deleteStocktakingPlan, getStocktakingPlanLinkList, getStocktakingPlanLinkDetail } from '@/api/system/stocktaking'
import { getStorehouseTypeList } from '@/api/system/storehouseType' import { getStorehouseTypeList } from '@/api/system/storehouseType'
import { getparameteritem } from '@/api/system/dictionary' import { getparameteritem } from '@/api/system/dictionary'
import { index as getWarehouseList } from '@/api/system/baseForm' import { index as getWarehouseList } from '@/api/system/baseForm'
@ -388,7 +416,11 @@ export default {
slot: 'area', slot: 'area',
key: 'material_info.suozaicangku' key: 'material_info.suozaicangku'
}, },
{ title: '执行人', key: 'executor' }, {
title: '执行人',
slot: 'executor',
key: 'responsible_admin.name'
},
{ {
title: '开始时间', title: '开始时间',
slot: 'startTime', slot: 'startTime',
@ -491,24 +523,40 @@ export default {
total: 0 total: 0
}, },
detailColumns: [ detailColumns: [
{ title: '物资名称', key: 'zichanmingcheng', minWidth: 150 },
{ title: '规格型号', key: 'guigexinghao', minWidth: 120 },
{ title: '单位', key: 'jiliangdanwei', width: 80 },
{ title: '当前库存', key: 'rukushuliang', width: 100 },
{ title: '盘点数量', key: 'check_quantity', width: 100 },
{ {
title: '差异数量', title: '盘点日期',
slot: 'diff_quantity', key: 'check_date',
key: 'diff_quantity', width: 180,
width: 100 align: 'center'
},
{
title: '盘点数量',
key: 'check_num',
width: 100,
align: 'center'
}, },
{ {
title: '状态', title: '状态',
slot: 'status', slot: 'status',
key: 'status', key: 'status',
width: 100 width: 100,
align: 'center'
},
{
title: '备注',
key: 'remark',
minWidth: 200,
tooltip: true,
align: 'center'
},
{
title: '照片',
slot: 'photos',
width: 200,
align: 'center'
} }
] ],
previewUrl: ''
} }
}, },
mounted() { mounted() {
@ -720,33 +768,43 @@ export default {
}, },
async searchList() { async searchList() {
this.listLoading = true this.listLoading = true;
try { try {
const params = { const formData = new FormData();
keyword: this.listSearch.keyword, formData.append('page', this.listSearch.pageIndex);
page: this.listSearch.pageIndex, formData.append('page_size', this.listSearch.pageSize);
page_size: this.listSearch.pageSize,
// 只添加非空的搜索条件
if (this.listSearch.keyword) {
formData.append('keyword', this.listSearch.keyword);
} }
// 计划筛选 // 计划筛选
if (this.listSearch.planId) { if (this.listSearch.planId) {
params.filter = JSON.stringify([{ key: 'material_infos_plan_id', op: 'eq', value: this.listSearch.planId }]) const filterIndex = this.listSearch.keyword ? 1 : 0;
formData.append(`filter[${filterIndex}][key]`, 'material_infos_plan_id');
formData.append(`filter[${filterIndex}][op]`, 'eq');
formData.append(`filter[${filterIndex}][value]`, this.listSearch.planId);
} }
// 状态筛选 // 状态筛选
if (this.listSearch.status) { if (this.listSearch.status) {
params.filter = params.filter || '[]' const filterIndex = (this.listSearch.keyword ? 1 : 0) + (this.listSearch.planId ? 1 : 0);
let filterArr = JSON.parse(params.filter) formData.append(`filter[${filterIndex}][key]`, 'status');
filterArr.push({ key: 'status', op: 'eq', value: this.listSearch.status }) formData.append(`filter[${filterIndex}][op]`, 'eq');
params.filter = JSON.stringify(filterArr) formData.append(`filter[${filterIndex}][value]`, this.listSearch.status);
} }
const res = await getStocktakingPlanLinkList(params)
if (res && res.list.data) { const res = await getStocktakingPlanLinkList(formData);
this.inventoryList = res.list.data if (res && res.list) {
this.listTotal = res.list.total || 0 this.inventoryList = res.list.data;
this.listTotal = res.list.total;
} }
} catch (e) { } catch (error) {
this.$Message.error('获取盘点列表失败') this.$Message.error('获取盘点列表失败');
console.error('获取盘点列表失败:', error);
} finally { } finally {
this.listLoading = false this.listLoading = false;
} }
}, },
resetListSearch() { resetListSearch() {
@ -768,57 +826,44 @@ export default {
this.listSearch.pageIndex = 1 this.listSearch.pageIndex = 1
this.searchList() this.searchList()
}, },
async viewInventoryDetail(id) { async viewInventoryDetail(row) {
this.detailModal.loading = true; this.detailModal.loading = true;
this.detailModal.visible = true; this.detailModal.visible = true;
this.detailModal.pageIndex = 1; this.detailModal.pageIndex = 1;
try {
// 模拟数据
const mockData = {
no: 'PD202403150001',
planName: '2024年第一季度盘点计划',
area: 'A区仓库',
executor: '张三',
startTime: '2024-03-15 09:00:00',
endTime: '2024-03-15 17:00:00',
status: '1',
checked_count: 8,
total_count: 10,
progress: '80%',
progress_number: 80,
materials: Array.from({ length: 25 }, (_, index) => ({
id: index + 1,
zichanmingcheng: `物资${index + 1}`,
guigexinghao: `型号${index + 1}`,
jiliangdanwei: '个',
rukushuliang: Math.floor(Math.random() * 10) + 1,
check_quantity: Math.floor(Math.random() * 10) + 1,
diff_quantity: Math.floor(Math.random() * 10) - 5,
status: Math.random() > 0.5 ? '1' : '0'
}))
};
// 模拟分页 // 先用列表行数据初始化基本信息
const start = (this.detailModal.pageIndex - 1) * this.detailModal.pageSize; this.detailModal.data = {
const end = start + this.detailModal.pageSize; id: row.id,
const pagedMaterials = mockData.materials.slice(start, end); no: row.no,
planName: row.material_infos_plan ? row.material_infos_plan.name : '-',
area: row.material_info ? row.material_info.suozaicangku : '-',
executor: row.responsible_admin ? row.responsible_admin.name : '-',
startTime: row.material_infos_plan ? row.material_infos_plan.start_date : '-',
endTime: row.material_infos_plan ? row.material_infos_plan.end_date : '-',
status: row.status,
material_info: row.material_info || {},
history: []
};
this.detailModal.data = { try {
...mockData, // 获取物资详情,包含盘点历史
materials: pagedMaterials const res = await request({
}; url: '/api/admin/material-infos/show',
this.detailModal.total = mockData.materials.length; method: 'get',
params: {
id: row.material_info.id
}
});
// 实际接口调用 if (res) {
// const res = await getStocktakingPlanLinkList({ // 更新物资信息和历史记录数据
// id, this.detailModal.data = {
// page: this.detailModal.pageIndex, ...this.detailModal.data,
// page_size: this.detailModal.pageSize material_info: res || {},
// }); history: res.material_infos_plan_link || []
// if (res && res.data) { };
// this.detailModal.data = res.data; this.detailModal.total = res.material_infos_plan_link ? res.material_infos_plan_link.length : 0;
// this.detailModal.total = res.total || 0; }
// }
} catch (error) { } catch (error) {
this.$Message.error('获取盘点任务详情失败'); this.$Message.error('获取盘点任务详情失败');
console.error('获取盘点任务详情失败:', error); console.error('获取盘点任务详情失败:', error);
@ -834,9 +879,6 @@ export default {
this.searchMaterials() this.searchMaterials()
}, },
isSelected(item) { isSelected(item) {
// console.log('isSelected called', item.id)
// console.log('materialModal.selectedMaterialIds', this.materialModal.selectedMaterialIds)
// console.log('this.materialModal.selectedMaterialIds.has(item.id)', this.materialModal.selectedMaterialIds.has(item.id))
return this.materialModal.selectedMaterialIds.has(item.id); return this.materialModal.selectedMaterialIds.has(item.id);
}, },
handleSelect(selection, item) { handleSelect(selection, item) {
@ -861,28 +903,6 @@ export default {
}); });
} }
}, },
// console.log('handleSelectionChange called', selection);
// // 如果是初始加载,跳过处理
// if (this.materialModal.isInitialLoad) {
// this.materialModal.isInitialLoad = false;
// return;
// }
// // 更新选中状态集合
// const planId = this.materialModal.currentPlanId;
// if (planId) {
// // 更新界面
// this.$nextTick(() => {
// if (this.$refs.materialTable) {
// this.materialList.forEach(row => {
// this.$refs.materialTable.toggleRowSelection(row, this.materialModal.selectedMaterialIds.has(row.id));
// });
// }
// });
// }
// },
handleSelectAll(selection) { handleSelectAll(selection) {
console.log('handleSelectAll called', selection); console.log('handleSelectAll called', selection);
@ -1129,12 +1149,6 @@ export default {
this.$Message.error('物资关联失败'); this.$Message.error('物资关联失败');
} }
}, },
getProgressColor(percent) {
if (percent >= 100) return '#19be6b';
if (percent >= 60) return '#2d8cf0';
if (percent >= 30) return '#ff9900';
return '#ed4014';
},
handleDetailPageChange(page) { handleDetailPageChange(page) {
this.detailModal.pageIndex = page; this.detailModal.pageIndex = page;
this.viewInventoryDetail(this.detailModal.data.id); this.viewInventoryDetail(this.detailModal.data.id);
@ -1143,6 +1157,12 @@ export default {
this.detailModal.pageSize = size; this.detailModal.pageSize = size;
this.detailModal.pageIndex = 1; this.detailModal.pageIndex = 1;
this.viewInventoryDetail(this.detailModal.data.id); this.viewInventoryDetail(this.detailModal.data.id);
},
previewImage(url) {
this.previewUrl = url;
},
closePreview() {
this.previewUrl = '';
} }
}, },
watch: { watch: {
@ -1341,33 +1361,38 @@ export default {
} }
} }
.progress-section { .material-info-section {
margin-bottom: 30px; margin-bottom: 30px;
.progress-header { h3 {
display: flex; margin: 0 0 15px 0;
justify-content: space-between; font-size: 16px;
align-items: center; color: #17233d;
margin-bottom: 15px; }
h3 { .material-info-content {
margin: 0; background: #f8f8f9;
font-size: 16px; padding: 20px;
color: #17233d; border-radius: 8px;
} display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
.progress-stats { .info-item {
display: flex; .label {
gap: 20px; font-weight: bold;
span {
color: #666; color: #666;
margin-right: 10px;
}
.value {
color: #333;
} }
} }
} }
} }
.material-section { .history-section {
h3 { h3 {
margin: 0 0 15px 0; margin: 0 0 15px 0;
font-size: 16px; font-size: 16px;
@ -1375,4 +1400,47 @@ export default {
} }
} }
} }
.photo-list {
display: flex;
gap: 8px;
align-items: center;
.photo-item {
width: 40px;
height: 40px;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.photo-more {
color: #666;
font-size: 12px;
}
}
.image-preview-modal {
position: fixed;
z-index: 2000;
left: 0; top: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7);
display: flex;
align-items: center;
justify-content: center;
}
.image-preview-large {
max-width: 90vw;
max-height: 90vh;
border-radius: 8px;
box-shadow: 0 4px 24px rgba(0,0,0,0.3);
background: #fff;
}
</style> </style>

Loading…
Cancel
Save