Files
klp-mono/apps/hand-factory/pages/search/search.vue
砂糖 ac55c9a4d1 feat(search): 添加分页功能并更新版本号至1.3.26
在搜索页面添加分页控件,包括上一页/下一页按钮和分页信息显示
更新应用版本号至1.3.26,涉及config.js、manifest.json等文件
2026-03-06 13:56:02 +08:00

875 lines
20 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>
<view class="typing-container">
<view class="form-card" v-show='currentView == "search"'>
<view class="card-title">
<text class="title-dot"></text>
<text class="title-text">设置条件查询钢卷</text>
</view>
<!-- 当前钢卷号 -->
<view class="form-item form-item-optional">
<text class="form-label">入场钢卷号</text>
<input v-model="form.enterCoilNo" placeholder="请输入当前钢卷号" class="form-input"
:disabled="coilDetail.dataType === 0" />
</view>
<view class="form-item form-item-optional">
<text class="form-label">当前钢卷号</text>
<input v-model="form.currentCoilNo" placeholder="请输入当前钢卷号" class="form-input"
:disabled="coilDetail.dataType === 0" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
</view>
<!-- 班组 -->
<view class="form-item form-item-optional">
<text class="form-label">班组</text>
<input v-model="form.team" placeholder="请输入班组名称" class="form-input" />
</view>
<!-- 库区选择 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">逻辑库区</text>
<klp-warehouse-picker v-model="form.warehouseId" :disabled="coilDetail.dataType === 0" placeholder="请选择目标库区" />
</view>
<view class="form-item form-item-optional">
<text class="form-label-optional">真实库区</text>
<klp-actual-warehouse-picker v-model="form.actualWarehouseId" :disabled="coilDetail.dataType === 0"
placeholder="请选择目标库区" />
</view>
<!-- 物品类型产品原材料选择使用封装组件 -->
<klp-material-picker
:item-type.sync="form.itemType"
:item-id.sync="form.itemId"
:material-type.sync="form.materialType"
:disabled="coilDetail.dataType === 0"
:page-size="2000"
/>
<view class="form-item form-item-optional">
<text class="form-label-optional">品名</text>
<input v-model="form.itemName" placeholder="请输入品名" class="form-input" />
</view>
<view class="form-item form-item-optional">
<text class="form-label-optional">规格</text>
<input v-model="form.itemSpecification" placeholder="请输入规格" class="form-input" />
</view>
<view class="form-item form-item-optional">
<text class="form-label-optional">材质</text>
<input v-model="form.itemMaterial" placeholder="请输入材质" class="form-input" />
</view>
<view class="form-item form-item-optional">
<text class="form-label-optional">厂家</text>
<input v-model="form.itemManufacturer" placeholder="请输入厂家" class="form-input" />
</view>
<!-- 毛重 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">毛重 ()</text>
<input v-model="form.grossWeight" type="digit" placeholder="请输入毛重" class="form-input"
:disabled="coilDetail.dataType === 0" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
</view>
<!-- 净重 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">净重 ()</text>
<input v-model="form.netWeight" type="digit" placeholder="请输入净重" class="form-input"
:disabled="coilDetail.dataType === 0" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
</view>
<!-- 长度 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">长度 ()</text>
<input v-model="form.length" type="digit" placeholder="请输入长度" class="form-input"
:disabled="coilDetail.dataType === 0" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
</view>
</view>
<view v-show='currentView == "list"' class="list-wrap">
<!-- 列表中尽可能多的展示信息 -->
<uni-list v-if="list.length > 0">
<uni-list-item
v-for="item in list"
:key="item.coilId"
:title="item.currentCoilNo"
:note="`入场号:${item.enterCoilNo} | 净重:${item.netWeight}吨 | ${item.warehouseName} | ${item.materialType} | ${getStatusText(item.status)}`"
clickable
@click="showCoilDetail(item)"
></uni-list-item>
</uni-list>
<!-- 空列表兜底 -->
<view class="empty-list" v-else>
<text>暂无符合条件的钢卷数据</text>
</view>
<!-- 分页控件 -->
<view class="pagination" v-if="total > 0">
<view class="pagination-info">
<text> {{ total }} / {{ totalPages }} </text>
<text>当前第 {{ pager.pageNum }} </text>
</view>
<view class="pagination-btns">
<button
class="page-btn"
@click="prevPage"
:disabled="pager.pageNum <= 1"
>
上一页
</button>
<button
class="page-btn"
@click="nextPage"
:disabled="pager.pageNum >= totalPages"
>
下一页
</button>
</view>
</view>
</view>
<!-- 钢卷详情弹窗 -->
<uni-popup ref="shipPopup" type="bottom">
<view style="background-color: white; padding: 20rpx;">
<!-- 弹窗标题+关闭按钮 -->
<view class="popup-header flex justify-between align-center mb-20">
<text class="font-32 font-bold">钢卷详情</text>
<text class="icon-close font-40" @click="closePopup"></text>
</view>
<view class="info-card" v-if="coilDetail.coilId">
<view class="info-grid">
<view class="info-item">
<text class="item-label">入场钢卷号</text>
<text class="item-value">{{ coilDetail.enterCoilNo || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">当前钢卷号</text>
<text class="item-value">{{ coilDetail.currentCoilNo || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">厂家卷号</text>
<text class="item-value">{{ coilDetail.supplierCoilNo || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">状态</text>
<text class="item-value">{{ getStatusText(coilDetail.status) }}</text>
</view>
<view class="info-item">
<text class="item-label">毛重 ()</text>
<text class="item-value">{{ coilDetail.grossWeight || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">净重 ()</text>
<text class="item-value">{{ coilDetail.netWeight || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">逻辑库区</text>
<text class="item-value">{{ coilDetail.warehouseName || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">真实库区</text>
<text class="item-value">{{ coilDetail.actualWarehouseName || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">班组</text>
<text class="item-value">{{ coilDetail.team || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">物料类型</text>
<text class="item-value">{{ coilDetail.materialType || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">品名</text>
<text class="item-value">{{ coilDetail.itemName || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">规格</text>
<text class="item-value">{{ coilDetail.specification || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">材质</text>
<text class="item-value">{{ coilDetail.material || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">厂家</text>
<text class="item-value">{{ coilDetail.manufacturer || '-' }}</text>
</view>
</view>
</view>
</view>
</uni-popup>
<!-- 新增查询悬浮按钮 - search视图显示 -->
<view class="float-btn search-btn" v-show="currentView === 'search'" @click="searchCoilList">
<text class="btn-text">查询</text>
</view>
<!-- 新增重新查找悬浮按钮 - list视图显示 -->
<view class="float-btn back-btn" v-show="currentView === 'list'" @click="backToSearch">
<text class="btn-text">重新查找</text>
</view>
</view>
</template>
<script>
import { getMaterialCoil, listMaterialCoil } from '@/api/wms/coil';
import { addPendingAction } from '@/api/wms/pendingAction';
export default {
data() {
return {
// 补全表单所有绑定字段的初始值,解决双向绑定警告
form: {
enterCoilNo: '',
currentCoilNo: '',
team: '',
warehouseId: '',
actualWarehouseId: '',
itemType: 'product',
itemId: '',
materialType: '',
itemName: '',
itemSpecification: '',
itemMaterial: '',
itemManufacturer: '',
grossWeight: '',
netWeight: '',
length: '',
},
pager: {
pageNum: 1,
pageSize: 20,
},
total: 0,
coilDetail: {}, // 钢卷详情数据
list: [], // 钢卷列表数据
loading: false,
currentView: 'search' // 视图切换search=查询页list=列表页
}
},
computed: {
// 计算总页数
totalPages() {
if (this.total === 0) return 0;
return Math.ceil(this.total / this.pager.pageSize);
}
},
methods: {
// ✅ 新增封装通用滚动到顶部方法uniapp全端兼容
scrollToPageTop() {
uni.pageScrollTo({
scrollTop: 0,
duration: 300, // 顺滑滚动,毫秒值
fail: () => {} // 容错处理,防止报错
})
},
// 获取设备信息(原有方法不变)
getDeviceInfo() {
try {
const systemInfo = uni.getSystemInfoSync();
return `${systemInfo.platform} ${systemInfo.model}`;
} catch (e) {
return 'Unknown Device';
}
},
// 查询钢卷列表(原有方法优化+✅新增滚动到顶部)
async searchCoilList() {
// 重置页码为1
this.pager.pageNum = 1;
uni.showLoading({
title: '正在查询,请稍后'
});
try {
const res = await listMaterialCoil({
...this.form,
...this.pager,
selectType: this.form.itemType
});
this.list = res.rows || [];
this.total = res.total || 0;
console.log(this.list)
this.currentView = 'list'
// ✅ 切换视图后,滚动到页面顶部
this.scrollToPageTop()
} catch (err) {
console.error('查询钢卷列表失败:', err);
uni.showToast({
title: '查询失败,检查网络后重试',
icon: 'none',
duration: 2000
})
} finally {
uni.hideLoading()
}
},
// 上一页
async prevPage() {
if (this.pager.pageNum <= 1) return;
this.pager.pageNum -= 1;
await this.loadPageData();
},
// 下一页
async nextPage() {
if (this.pager.pageNum >= this.totalPages) return;
this.pager.pageNum += 1;
await this.loadPageData();
},
// 加载指定页码的数据
async loadPageData() {
uni.showLoading({
title: '加载中...'
});
try {
const res = await listMaterialCoil({
...this.form,
...this.pager,
selectType: this.form.itemType
});
this.list = res.rows || [];
// 滚动到列表顶部
this.scrollToPageTop();
} catch (err) {
console.error('加载分页数据失败:', err);
uni.showToast({
title: '加载失败,请重试',
icon: 'none',
duration: 2000
})
} finally {
uni.hideLoading();
}
},
// 回到查询页面(原有方法+✅新增滚动到顶部)
backToSearch() {
this.currentView = 'search';
// 可选:重置表单数据,如需保留查询条件则注释此行
// this.form = this.$options.data().form;
// ✅ 切换视图后,滚动到页面顶部
this.scrollToPageTop()
},
// 点击列表项-展示钢卷详情弹窗
showCoilDetail(item) {
this.coilDetail = { ...item }; // 深拷贝防止原数据被修改
this.$refs.shipPopup.open(); // 打开底部弹窗
},
// 关闭弹窗
closePopup() {
this.$refs.shipPopup.close();
},
// 格式化状态文本0=在库 1=已出库
getStatusText(status) {
return status === 0 ? '在库' : status === 1 ? '已出库' : '未知';
}
},
}
</script>
<style scoped lang="scss">
.typing-container {
padding: 20rpx;
padding-bottom: 30rpx;
min-height: 100vh;
}
// 列表页样式补充
.list-wrap {
// ✅ 移除原按钮样式,无需保留
.empty-list {
text-align: center;
padding: 100rpx 0;
color: #999;
font-size: 28rpx;
}
// 分页样式
.pagination {
margin-top: 40rpx;
padding: 20rpx;
display: flex;
flex-direction: column;
align-items: center;
gap: 20rpx;
.pagination-info {
display: flex;
gap: 30rpx;
font-size: 26rpx;
color: #666;
text {
display: block;
}
}
.pagination-btns {
display: flex;
gap: 20rpx;
.page-btn {
width: 160rpx;
height: 70rpx;
line-height: 70rpx;
background: #f0f7ff;
border: 1rpx solid #007aff;
border-radius: 8rpx;
color: #007aff;
font-size: 28rpx;
&:disabled {
background: #f5f5f5;
border-color: #ddd;
color: #999;
}
}
}
}
}
// ✅ 核心新增:悬浮按钮样式(全局通用)
.float-btn {
position: fixed;
right: 30rpx;
bottom: 60rpx;
z-index: 9999; // 置顶层级,永不遮挡
width: 120rpx;
height: 120rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 28rpx;
font-weight: 500;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.15);
transition: all 0.2s ease;
&:active {
transform: scale(0.95); // 按压缩放动效
opacity: 0.9;
}
.btn-text {
color: #fff;
}
}
// 查询悬浮按钮-主色调(渐变蓝,和原有按钮风格一致)
.search-btn {
background: linear-gradient(135deg, #007aff 0%, #0051d5 100%);
}
// 重新查找悬浮按钮-次要色调(灰色系,区分查询按钮)
.back-btn {
background: linear-gradient(135deg, #666 0%, #333 100%);
}
// 弹窗样式补充
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.mb-20 {margin-bottom: 20rpx;}
.font-32 {font-size:32rpx;}
.font-40 {font-size:40rpx;}
.font-bold {font-weight: bold;}
.icon-close {color:#999;}
/* 扫码区域 */
.scan-section {
padding: 80rpx 40rpx;
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.scan-btn-wrapper {
display: flex;
flex-direction: column;
align-items: center;
gap: 30rpx;
.scan-icon {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
background: linear-gradient(135deg, #007aff 0%, #0051d5 100%);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(0, 122, 255, 0.3);
&:active {
transform: scale(0.95);
}
}
.icon-camera {
font-size: 70rpx;
}
.scan-tip {
font-size: 28rpx;
color: #666;
}
}
}
/* 卡片样式 */
.info-card,
.material-card,
.form-card {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
/* 警告卡片 */
.warning-card {
background: #fff2f0;
border: 2rpx solid #ffccc7;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
gap: 20rpx;
.warning-icon {
font-size: 48rpx;
flex-shrink: 0;
}
.warning-content {
flex: 1;
.warning-title {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #cf1322;
margin-bottom: 8rpx;
}
.warning-desc {
display: block;
font-size: 24rpx;
color: #a8071a;
line-height: 1.4;
}
}
}
.card-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 25rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
.title-dot {
width: 8rpx;
height: 28rpx;
background: #007aff;
border-radius: 4rpx;
margin-right: 12rpx;
}
.title-text {
flex: 1;
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.status-badge {
font-size: 22rpx;
padding: 4rpx 12rpx;
border-radius: 12rpx;
margin-right: 10rpx;
&.status-1 {
background: #d1f2eb;
color: #0c6957;
}
&.status-0 {
background: #f8d7da;
color: #721c24;
}
}
.more-btn {
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 16rpx;
background: #f0f7ff;
border-radius: 20rpx;
border: 1rpx solid #007aff;
.icon-more {
font-size: 24rpx;
color: #007aff;
}
.more-text {
font-size: 24rpx;
color: #007aff;
}
}
} // ✅ 修复补全card-title的闭合大括号
/* 信息网格 */
.info-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
.info-item {
flex: 1;
min-width: 45%;
background: #f8f9fa;
padding: 20rpx;
border-radius: 12rpx;
&.full-width {
flex: 0 0 100%;
}
.item-label {
display: block;
font-size: 24rpx;
color: #999;
margin-bottom: 10rpx;
}
.item-value {
display: block;
font-size: 28rpx;
color: #333;
font-weight: 500;
}
}
}
/* 表单项 */
.form-item {
margin-bottom: 30rpx;
&:last-of-type {
margin-bottom: 0;
}
.form-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 500;
// &::before {
// content: '*';
// color: #ff4d4f;
// margin-right: 6rpx;
// }
}
.form-label-optional {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 500;
}
.form-input {
width: 100%;
height: 88rpx;
padding: 0 24rpx;
background: #f8f9fa;
border: 2rpx solid #e8e8e8;
border-radius: 12rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
transition: all 0.3s;
&:focus {
background: #fff;
border-color: #007aff;
}
&.form-input-disabled {
background: #f5f5f5;
color: #999;
cursor: not-allowed;
}
}
}
/* 操作者信息 */
.operator-info {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0;
margin-top: 20rpx;
.operator-label {
font-size: 26rpx;
color: #999;
}
.operator-name {
font-size: 26rpx;
color: #007aff;
font-weight: 500;
}
}
/* 操作按钮 */
.action-buttons {
display: flex;
gap: 20rpx;
margin-top: 30rpx;
.btn {
flex: 1;
height: 88rpx;
border-radius: 12rpx;
font-size: 30rpx;
font-weight: 500;
border: none;
transition: all 0.2s;
&:active {
transform: scale(0.98);
}
&[disabled] {
opacity: 0.6;
}
}
.btn-secondary {
background: #f5f5f5;
color: #666;
}
.btn-primary {
background: linear-gradient(135deg, #007aff 0%, #0051d5 100%);
color: #fff;
box-shadow: 0 4rpx 16rpx rgba(0, 122, 255, 0.3);
}
}
/* BOM弹窗 */
.bom-popup {
background: #fff;
border-radius: 24rpx 24rpx 0 0;
max-height: 70vh;
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.popup-title {
font-size: 32rpx;
color: #333;
font-weight: 600;
}
.popup-close {
font-size: 40rpx;
color: #999;
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.popup-body {
padding: 30rpx;
max-height: 500rpx;
.bom-item {
display: flex;
gap: 20rpx;
padding: 24rpx;
background: #f8f9fa;
border-radius: 12rpx;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
.bom-index {
width: 60rpx;
height: 60rpx;
background: #007aff;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
font-weight: bold;
flex-shrink: 0;
}
.bom-content {
flex: 1;
.bom-row {
display: flex;
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
.bom-label {
font-size: 26rpx;
color: #666;
min-width: 120rpx;
}
.bom-value {
font-size: 26rpx;
color: #333;
font-weight: 500;
}
}
}
}
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
}
}
</style>