Commit 4d46eba5 by liangjianmin

feat(warehouseQc): 添加库内质检页面及相关功能和样式

- 新增搜索框和状态筛选功能
- 完善质检列表展示,包含详细信息
- 添加一键回库和推送质检功能
- 更新 API 接口以支持新功能
parent 5d10a8c1
.warehouseQc {
padding: 22rpx;
padding: 15rpx 22rpx;
.empty {
width: 100%;
height: 100vh;
.search-box {
height: 60rpx;
background: #ffffff;
border-radius: 10rpx;
padding: 0 18rpx 0 0;
.sn {
width: 164rpx;
height: 35rpx;
border-right: 1px solid #f0f0f2;
.uni-input {
font-size: 18rpx;
color: #292b33;
font-weight: bold;
}
.uni-arrow {
width: 14rpx;
height: 9rpx;
background: url('https://img.ichunt.com/images/ichunt/202304/10/e4c72319ad41ce1425f71cc6ec35f111.png') no-repeat center;
background-size: contain;
margin-left: 12rpx;
}
}
.search-bar {
width: calc(100% - 164rpx);
.icon-juxing1 {
font-size: 30rpx;
color: #919399;
margin-left: 17rpx;
margin-right: 13rpx;
}
.uni-input {
font-size: 18rpx;
color: #484b59;
}
.icon-a-juxing11 {
font-size: 30rpx;
color: #c6c7cc;
}
}
}
.status-filter {
margin-top: 15rpx;
padding: 12rpx 18rpx;
background: #ffffff;
border-radius: 10rpx;
flex-wrap: wrap;
.status-item {
margin-right: 30rpx;
.check-box-icon {
width: 20rpx;
height: 20rpx;
background: url('https://img.ichunt.com/images/ichunt/202304/11/0bf30da3e8ce6c476c210173b5f13d51.png') no-repeat center;
background-size: contain;
display: block;
&.curr {
background: url('https://img.ichunt.com/images/ichunt/202304/11/71a74e52e94bcf2e89f8df9817d494c6.png') no-repeat center;
background-size: contain;
}
}
.status-text {
font-size: 18rpx;
color: #484b59;
margin-left: 8rpx;
}
}
}
.list {
margin-top: 15rpx;
padding-bottom: 100rpx;
.box {
position: relative;
padding: 15rpx 17rpx 50rpx 17rpx;
background: #ffffff;
box-shadow: 0px 3rpx 3rpx 0px rgba(198, 199, 204, 0.3);
border-radius: 10rpx;
margin-bottom: 15rpx;
flex-wrap: wrap;
border: 1px solid transparent;
.check-box-icon {
position: absolute;
right: 18rpx;
top: 17rpx;
width: 20rpx;
height: 20rpx;
background: url('https://img.ichunt.com/images/ichunt/202304/11/0bf30da3e8ce6c476c210173b5f13d51.png') no-repeat center;
background-size: contain;
display: block;
}
&.curr {
border: 1px solid #1969f9;
.check-box-icon {
background: url('https://img.ichunt.com/images/ichunt/202304/11/71a74e52e94bcf2e89f8df9817d494c6.png') no-repeat center;
background-size: contain;
}
}
.status-tag {
position: absolute;
right: 50rpx;
top: 13rpx;
.status-tag-text {
display: inline-block;
padding: 5rpx 18rpx;
border-radius: 30rpx;
font-size: 18rpx;
font-weight: 500;
&.status-1 {
background: rgba(72, 75, 89, 0.08);
color: #484b59;
}
&.status-2 {
background: rgba(25, 105, 249, 0.1);
color: #1969f9;
}
&.status-3 {
background: rgba(249, 129, 25, 0.1);
color: #f98119;
}
&.status-4 {
background: rgba(0, 181, 120, 0.1);
color: #00b578;
}
}
}
.input-box {
margin-bottom: 8rpx;
flex: 0 0 50%;
.label {
font-size: 17rpx;
color: #919399;
white-space: nowrap;
}
.text {
font-size: 17rpx;
color: #484b59;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.tt {
font-size: 17rpx;
color: #1969f9;
}
}
.btn-box {
position: absolute;
right: 17rpx;
bottom: 13rpx;
.btn-primary {
padding: 0 16rpx;
height: 36rpx;
background: #1969f9;
border-radius: 8rpx;
font-size: 16rpx;
color: #ffffff;
margin-left: 10rpx;
}
.btn-danger {
padding: 0 16rpx;
height: 36rpx;
background: #fff;
border-radius: 8rpx;
font-size: 16rpx;
color: #f00;
border: 1px solid #f00;
margin-left: 10rpx;
}
}
}
}
.no-date {
margin-top: 200rpx;
.tips {
font-size: 28rpx;
.iconfont {
font-size: 120rpx;
color: #c6c7cc;
}
.text {
font-size: 22rpx;
color: #919399;
margin-top: 20rpx;
}
}
.fix-btn {
position: fixed;
bottom: 0;
width: 100%;
left: 0;
z-index: 999;
.btn1 {
width: 128rpx;
height: 75rpx;
background: #ffffff;
border-right: 1px solid #f0f0f2;
.check-box-icon {
width: 20rpx;
height: 20rpx;
background: url('https://img.ichunt.com/images/ichunt/202304/11/0bf30da3e8ce6c476c210173b5f13d51.png') no-repeat center;
background-size: contain;
display: block;
&.curr {
background: url('https://img.ichunt.com/images/ichunt/202304/11/71a74e52e94bcf2e89f8df9817d494c6.png') no-repeat center;
background-size: contain;
}
}
.text {
margin-left: 10rpx;
font-size: 20rpx;
color: #484b59;
}
}
.btn3 {
width: calc(100% - 128rpx);
height: 75rpx;
background: #1969f9;
font-size: 23rpx;
color: #ffffff;
}
}
}
<template>
<view class="warehouseQc">
<view class="empty row rowCenter verCenter">
<text class="tips">页面建设中...</text>
<!-- 搜索参数 -->
<view class="search-box row bothSide verCenter">
<view class="sn row rowCenter verCenter">
<picker @change="bindPickerChange($event, 1)" :value="index" :range="array">
<view class="row verCenter">
<view class="uni-input">{{ array[index] }}</view>
<view class="uni-arrow"></view>
</view>
</picker>
</view>
<view class="search-bar row bothSide verCenter">
<view class="row verCenter" style="width: 100%;">
<text class="iconfont icon-juxing1"></text>
<input class="uni-input" placeholder="请扫描或输入型号/入仓号/入库批次号查询" placeholder-style="color:#919399" :focus="is_focus" v-model="searchParams.mobile_search" @input="handleInput" style="width: 100%;" />
</view>
<text class="iconfont icon-a-juxing11" @click="clearInput()" v-if="input_flag"></text>
</view>
</view>
<!-- 状态多选 -->
<view class="status-filter row verCenter">
<view class="status-item row verCenter" v-for="(item, idx) in statusList" :key="item.value" @click="toggleStatus(item.value)">
<text class="check-box-icon" :class="{ curr: searchParams.status_arr.includes(item.value) }"></text>
<text class="status-text">{{ item.name }}</text>
</view>
</view>
<!-- 列表区 -->
<view class="list" v-if="list.length > 0">
<view class="box row" v-for="(item, idx) in list" :key="idx" :class="{ curr: filter_list[idx] }">
<view class="check-box-icon" @click="filterChange(idx)"></view>
<!-- 顶部信息行 -->
<view class="input-box row verCenter curr" style="flex: 0 0 100%;">
<text class="label">{{ item.warehouse_name }}</text>
<text class="tt" style="margin-left: 20rpx;">{{ item.stock_qc_req_sn }}</text>
<text class="label" style="margin-left: 20rpx;">原库位:</text>
<text class="tt" style="color: #ff3700;">{{ item.position_name }}</text>
</view>
<!-- 状态 -->
<view class="status-tag">
<text class="status-tag-text" :class="'status-' + item.status">{{ item.status_text }}</text>
</view>
<view class="input-box row verCenter" style="flex: 0 0 100%;">
<text class="label">创建时间:</text>
<text class="text">{{ item.create_time_format }}</text>
<text class="text" style="margin-left: 30rpx;">{{ item.create_name }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">货品编码:</text>
<text class="text">{{ item.goods_sn }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">自营货品ID:</text>
<text class="text">{{ item.sku_id }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">入库批次号:</text>
<text class="text">{{ item.stock_in_batch_sn }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">库存类型:</text>
<text class="text">{{ item.stock_type_text }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">货品名称:</text>
<text class="text">{{ item.goods_name }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">标准品牌:</text>
<text class="text">{{ item.brand_name }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">入 仓 号:</text>
<text class="text">{{ item.inhouse }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">销 售 员:</text>
<text class="text">{{ item.sale_name }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">采 购 员:</text>
<text class="text">{{ item.pur_user_name }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">质检数量:</text>
<text class="text" style="color: #F98119;">{{ item.qc_num }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">验货要求:</text>
<text class="text">{{ item.qc_remark }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">检验结果:</text>
<text class="text">{{ item.qc_status_text || '待处理' }}</text>
</view>
<view class="input-box row verCenter">
<text class="label">检验图片:</text>
<text class="text tt" @click="showQcPic(item)" v-if="item.status >= 2">查看</text>
</view>
<!-- 操作按钮 -->
<view class="btn-box row">
<view class="btn-danger row rowCenter verCenter" @click="cancelQc(item)" v-if="item.status === 2">取消质检</view>
<view class="btn-primary row rowCenter verCenter" @click="pushQc(item)" v-if="item.status === 1">推送质检</view>
</view>
</view>
</view>
<!-- 无数据展示 -->
<view class="no-date column rowCenter verCenter" v-else>
<text class="iconfont icon-a-juxing21"></text>
<text class="text">查不到当前数据</text>
</view>
<!-- 底部操作按钮 -->
<view class="fix-btn row verCenter">
<view class="btn1 row rowCenter verCenter" @click="allChange()">
<text class="check-box-icon" :class="{ curr: isAllSelected }"></text>
<text class="text">{{ filter_id.length || '' }}</text>
</view>
<view class="btn3 row rowCenter verCenter" @click="batchRebackToStock">一键回库</view>
</view>
</view>
</template>
<script>
import { API } from '@/util/api.js';
import { createArray } from '@/util/util.js';
import debounce from 'lodash/debounce';
export default {
data() {
return {};
return {
is_focus: true,
index: 0,
array: ['全量搜索'],
input_flag: false,
page: 1,
limit: 30,
hasMoreData: true,
list: [],
filter_list: [],
filter_id: [],
statusList: [
{ name: '新创建', value: 1 },
{ name: '待质检', value: 2 },
{ name: '待回库', value: 3 },
{ name: '已完成', value: 4 }
],
searchParams: {
mobile_search: '',
status_arr: [1, 2, 3]
}
};
},
computed: {
/**
* @return {boolean} 是否全选
*/
isAllSelected() {
return this.list.length > 0 && this.filter_list.length > 0 && this.filter_list.every(v => v);
}
},
onReachBottom() {
if (!this.hasMoreData) return;
this.page++;
this.getData();
},
onLoad() { },
onShow() {
this.resetChange();
this.getData();
},
methods: {
/**
* @param {Object} e picker事件
* @param {number} type picker类型
*/
bindPickerChange(e, type) {
if (type === 1) {
this.index = e.detail.value;
this.clearInputAndFocus();
}
},
/**
* 切换状态筛选
* @param {number} value 状态值
*/
toggleStatus(value) {
var arr = this.searchParams.status_arr;
var idx = arr.indexOf(value);
if (idx > -1) {
arr.splice(idx, 1);
} else {
arr.push(value);
}
this.resetChange();
this.getData();
},
/**
* 全选/取消全选
*/
allChange() {
var allSelected = this.isAllSelected;
this.filter_list = createArray(this.list.length, !allSelected);
if (!allSelected) {
this.filter_id = this.list.map(item => item.id);
} else {
this.filter_id = [];
}
},
/**
* 筛选过滤出选中的元素
* @param {number} idx 下标
*/
filterChange(idx) {
this.$set(this.filter_list, idx, !this.filter_list[idx]);
var selectedIndexes = this.filter_list.reduce((acc, val, i) => {
if (val) acc.push(i);
return acc;
}, []);
this.filter_id = selectedIndexes.map(i => this.list[i].id);
},
/**
* 清空搜索
*/
clearInput() {
this.resetChange();
this.searchParams.mobile_search = '';
this.input_flag = false;
this.clearInputAndFocus();
this.getData();
},
/**
* 全量搜索(防抖)
* @param {Object} event 输入事件
*/
handleInput: debounce(function (event) {
this.input_flag = !!event.target.value;
this.resetChange();
this.searchParams.mobile_search = event.target.value;
this.getData();
}, 500),
/**
* 获取列表数据
*/
getData() {
var params = {
page: this.page,
limit: this.limit,
mobile_search: this.searchParams.mobile_search,
status_in_str: this.searchParams.status_arr.join(',')
};
this.request(API.stockQualityControlList, 'GET', params, true).then(res => {
if (res.code === 0) {
var dataList = res.data || [];
if (res.data && res.data.list) {
dataList = res.data.list;
}
if (dataList.length > 0) {
this.hasMoreData = true;
this.list = this.list.concat(dataList);
this.filter_list = createArray(this.list.length, false);
} else {
this.hasMoreData = false;
}
} else {
uni.showToast({ title: res.msg || '获取数据失败', icon: 'none' });
}
});
},
/**
* 推送质检
* @param {Object} item 当前行数据
*/
pushQc(item) {
uni.showModal({
title: '推送质检',
content: '确认推送质检?',
success: res => {
if (res.confirm) {
this.request(API.stockQualityControlPushQc, 'POST', { ids: String(item.id) }, true).then(res => {
if (res.code === 0) {
uni.showToast({ title: '推送质检成功', icon: 'success' });
setTimeout(() => {
this.resetChange();
this.getData();
}, 1500);
} else {
uni.showToast({ title: res.msg || '推送质检失败', icon: 'none' });
}
});
}
}
});
},
/**
* 取消质检
* @param {Object} item 当前行数据
*/
cancelQc(item) {
uni.showModal({
title: '取消质检',
content: '确认取消已生成的质检任务吗?',
success: res => {
if (res.confirm) {
this.request(API.stockQualityControlCancel, 'POST', { ids: String(item.id) }, true).then(res => {
if (res.code === 0) {
uni.showToast({ title: '取消质检成功', icon: 'success' });
setTimeout(() => {
this.resetChange();
this.getData();
}, 1500);
} else {
uni.showToast({ title: res.msg || '取消质检失败', icon: 'none' });
}
});
}
}
});
},
/**
* 批量一键回库(仅待回库状态可操作)
*/
batchRebackToStock() {
if (this.filter_id.length === 0) {
uni.showToast({ title: '请先勾选数据', icon: 'none' });
return;
}
var selectedItems = this.filter_list.reduce((acc, val, i) => {
if (val) acc.push(this.list[i]);
return acc;
}, []);
var rebackIds = selectedItems.filter(item => item.status === 3).map(item => item.id);
if (rebackIds.length === 0) {
uni.showToast({ title: '请勾选"待回库"状态的数据', icon: 'none' });
return;
}
uni.showModal({
title: '一键回库',
content: `已选中 ${rebackIds.length} 条,是否确认货物已回到原库位?`,
success: res => {
if (res.confirm) {
this.request(API.stockQualityControlRebackToStock, 'POST', { ids: rebackIds.join(',') }, true).then(res => {
if (res.code === 0) {
uni.showToast({ title: '回库成功', icon: 'success' });
setTimeout(() => {
this.resetChange();
this.getData();
}, 1500);
} else {
uni.showToast({ title: res.msg || '回库失败', icon: 'none' });
}
});
}
}
});
},
/**
* 查看质检图片
* @param {Object} item 当前行数据
*/
showQcPic(item) {
this.request(API.stockQualityControlQcSystemData, 'POST', { wms_stock_id: item.stock_id }, true).then(res => {
if (res.code !== 0 || !res.data || !res.data.length) {
uni.showToast({ title: '暂无质检图片数据', icon: 'none' });
return;
}
var picInfo = res.data[0].pic_info || [];
if (picInfo.length === 0) {
uni.showToast({ title: '暂无质检图片', icon: 'none' });
return;
}
var urls = picInfo.map(p => p.big_img_url);
uni.previewImage({ urls: urls, current: urls[0] });
});
},
/**
* 重置列表
*/
resetChange() {
this.list = [];
this.page = 1;
this.filter_list = [];
this.filter_id = [];
this.hasMoreData = true;
},
onLoad() {},
methods: {}
/**
* 再次获取焦点
*/
clearInputAndFocus() {
this.input_flag = false;
this.is_focus = false;
setTimeout(() => {
this.is_focus = true;
}, 200);
}
}
};
</script>
......
......@@ -470,7 +470,30 @@ const API = {
* 扫码解析二维码
* */
scanQrCode: API_BASE_ICHUNT + '/supplywechatwms/scanQrCode',
stockInTaskNum: API_BASE + '/api/stockIn/stockIn/stockInTaskNum'
/**
* 获取入仓号的任务统计(总任务数 + 待理货数)
*/
stockInTaskNum: API_BASE + '/api/stockIn/stockIn/stockInTaskNum',
/**
* 库内质检-列表
*/
stockQualityControlList: API_BASE + '/api/stockQualityControl/list',
/**
* 库内质检-推送质检
*/
stockQualityControlPushQc: API_BASE + '/api/stockQualityControl/pushQc',
/**
* 库内质检-取消质检
*/
stockQualityControlCancel: API_BASE + '/api/stockQualityControl/cancel',
/**
* 库内质检-一键回库
*/
stockQualityControlRebackToStock: API_BASE + '/api/stockQualityControl/rebackToStock',
/**
* 库内质检-质检系统数据(图片/附件/结果)
*/
stockQualityControlQcSystemData: API_BASE + '/api/stockQualityControl/qcSystemData'
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment