merchapp/java-mall-app-shop-admin/pages/warehouse/manage/batchSearch.vue
2025-07-28 01:55:47 +08:00

817 lines
21 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="batch-search-container">
<navBar
class="nav-bar"
:statusBar="true"
:border="false"
:fixed="true"
:height="'44px'"
rightWidth="0"
:leftWidth="30"
backgroundColor="#fff"
>
<block slot="left">
<u-icon
name="arrow-left"
color="#000"
size="20"
@click="pageBack()"
></u-icon>
</block>
<block slot="default">
<u-search
v-model="inputSearch"
class="search"
placeholder="请输入商品名称查找"
:showAction="false"
@change="handerSearch"
bgColor="#eeeeee"
></u-search>
</block>
</navBar>
<view class="commodity-status" v-if="searchCommodityList.length > 0">
<u-tabs
class="u-tabs"
ref="tabsRef"
:list="searchCommodityStatusList"
@click="handerCommodityStatus"
itemStyle="padding-left: 15px; padding-right: 15px; height: 57px;"
activeStyle="font-weight: bold;color: #000;"
inactiveStyle="color:#999999;"
lineColor="#e41f19"
></u-tabs>
</view>
<view
class="no-data"
v-if="searchCommodityList.length <= 0 && isNoCommodityData"
>
<view class="no-data-bg"></view>
<view class="no-data-tips">暂无商品</view>
</view>
<favorite-loading
class="commodity-loading"
v-show="loadingCommodityData"
:color="'#fe4119'"
text=""
animation="spinner15"
></favorite-loading>
<scroll-view
v-if="searchCommodityList.length > 0 && !loadingCommodityData"
scroll-y
class="batch-search-scroll"
:show-scrollbar="false"
@scrolltolower="handerScrolltolower"
refresher-enabled
:refresher-triggered="isRefreshing"
@refresherrefresh="handleRefresh"
>
<u-checkbox-group
class="commodity-list"
v-model="checkboxList"
placement="column"
@change="handleSingleCheckboxChange($event, true)"
>
<view
class="commodity-item"
v-for="(item, index) of searchCommodityList"
:key="index"
>
<u-checkbox
class="commodity-checkbox"
:key="index"
:name="item.product_id"
></u-checkbox>
<view
class="commodity-info"
@click="handleSingleCheckboxChange([item.product_id])"
>
<view
:class="[
'commodity-img',
{ 'commodity-img-sold-out': item.product_state_id == 1002 },
]"
>
<u--image
:src="item.product_image"
radius="8"
width="60px"
height="60px"
@click="handlerShowImg(item.product_image)"
></u--image>
</view>
<view class="commodity-info-box">
<view class="commodity-name" v-html="item.searchName"></view>
<view class="commodity-inventory">
库存{{ item.itemQuantity }}
</view>
<view class="commodity-price">
<block class="currency">¥</block>
{{ item.product_unit_price }}
</view>
</view>
</view>
</view>
</u-checkbox-group>
<view
class="m-loading-box"
v-if="searchCommodityList.length > 0 && !isNoCommodityData"
>
<block v-if="loadingDownCommodityData">
<view class="u-loadmore">
<view class="u-loading"></view>
<text class="u-loadmore-tips">正在加载...</text>
</view>
</block>
<block v-else>
<view class="u-loadmore u-loadmore-line">
<text class="u-loadmore-tips">没有更多商品了 ~</text>
</view>
</block>
</view>
</scroll-view>
<view class="bottom" v-if="searchCommodityList.length > 0">
<u-checkbox-group
v-model="checkboxAllList"
placement="column"
@change="handleSelectAll($event, true)"
>
<u-checkbox
class="commodity-checkbox"
:name="'select-all'"
label="全选"
></u-checkbox>
</u-checkbox-group>
<u-button
class="commodity-btn-item"
:hairline="true"
:plain="true"
shape="circle"
@click="affirmSelect"
>
确定选择
</u-button>
</view>
<u-popup
class="affirm-popup"
zIndex="10077"
:show="showBackPopup"
mode="center"
>
<view class="affirm-popup-content">
<view class="affirm-popup-title">确认退出</view>
<view class="affirm-popup-tips">
您搜索后选择或取消选择商品的操作暂未保存,现在退出将全部失效,确认退出么?
</view>
<view class="popup-btn-list">
<u-button
class="btn-item"
:hairline="true"
:plain="true"
shape="circle"
@click="showBackPopup = false"
>
取消
</u-button>
<u-button
class="btn-item btn-item-2"
:hairline="true"
:plain="true"
shape="circle"
@click="handerPageBack"
>
退出
</u-button>
</view>
</view>
</u-popup>
<tui-gallery
:urls="showImgList"
:show="showImg"
@hide="hideImg"
></tui-gallery>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import { GetProductList } from "@/api/warehouse/productList";
import navBar from "@/components/uni-nav-bar/uni-nav-bar";
import tuiCollapse from "../manage/components/tui-collapse/tui-collapse.vue";
import favoriteLoading from "@/components/favorite-loading/favorite-loading.vue";
import tuiGallery from "@/components/tui-gallery/tui-gallery.vue";
export default {
name: "batchSearch",
props: {
selectCommodityList: {
type: Array,
default: [],
},
},
components: {
navBar,
tuiCollapse,
favoriteLoading,
tuiGallery,
},
data() {
return {
height: 0, //scroll-view高度
top: 0,
searchCommodityStatusList: [
{
value: null,
name: "全部",
badge: {
value: 0,
},
},
{
// 1001-正常;1002-下架仓库中;1000-违规禁售
value: 1001,
name: "销售中",
badge: {
value: 0,
},
},
{
value: 1002,
name: "仓库中",
badge: {
value: 0,
},
},
{
value: 1000,
name: "违规禁售",
badge: {
value: 0,
},
},
{
value: 1003,
name: "待审核",
badge: {
value: 0,
},
},
],
searchCommodityList: [],
pageNum: 1,
pageSize: 20,
loadingCommodityData: false,
loadingDownCommodityData: false,
isNoCommodityData: false,
isNoDownCommodityData: false,
isRefreshing: false,
time: null,
searchTime: null,
showImgList: [],
showImg: false,
inputSearch: "",
checkboxList: [],
checkboxAllList: [],
showBackPopup: false,
};
},
computed: {
allSelectedExistInCurrentPage() {
if (this.selectCommodityList.length === 0) return false;
// 获取当前页面的所有商品ID
const currentPageIds = this.searchCommodityList.map(
(item) => item.product_id
);
// 检查selectCommodityList中的所有商品是否都在当前页面
return this.selectCommodityList.every((selectedItem) =>
currentPageIds.includes(selectedItem.product_id)
);
},
},
onLoad: function (options) {
setTimeout(() => {
uni.getSystemInfo({
success: (res) => {
let header = 60;
let top = 0;
//#ifdef H5
top = 44;
//#endif
this.height = res.windowHeight - uni.upx2px(header);
this.top = top + uni.upx2px(header);
},
});
}, 50);
},
onReady() {},
onShow() {
this.getProductCategoryTree();
},
mounted() {},
methods: {
pageBack() {
if (this.checkboxList.length > 0) {
this.showBackPopup = true;
} else {
this.$emit("pageBack");
}
},
handerPageBack() {
this.$emit("pageBack");
},
// 点击标题切换当前页时改变样式
swichNav: function (e) {
let cur = e.currentTarget.dataset.current;
if (this.currentTab == cur) {
return false;
} else {
this.currentTab = cur;
this.checkCor();
}
},
//判断当前滚动超过一屏时设置tab标题滚动条。
checkCor: function () {
if (this.currentTab > 6) {
this.scrollViewId = `id_${this.currentTab - 2}`;
} else {
this.scrollViewId = `id_0`;
}
},
handerSearch() {
clearTimeout(this.searchTime);
this.searchTime = setTimeout(() => {
if (this.inputSearch.length == 0) {
this.pageNum = 1;
this.searchCommodityList = [];
this.checkboxList = [];
this.checkboxAllList = [];
return;
}
this.getProductList();
}, 500);
},
async getProductList() {
this.isNoCommodityData = false;
if (this.loadingDownCommodityData) {
this.loadingCommodityData = false;
} else {
this.loadingCommodityData = true;
}
if (this.isRefreshing) {
this.pageNum = 1;
this.isNoCommodityData = false;
this.isNoDownCommodityData = false;
}
let params = {
kind_id: "1201,1202,1203",
pageNum: this.pageNum,
pageSize: this.pageSize,
product_state_id: this.currProductStateId,
product_name: this.inputSearch,
openCount: true,
};
let res = await GetProductList(params);
if (res && res.status == 200) {
if (this.loadingDownCommodityData) {
if (res.data.items.length <= 0) {
this.loadingDownCommodityData = false;
this.isNoDownCommodityData = true;
return;
} else {
this.searchCommodityList = [
...this.searchCommodityList,
...res.data.items,
];
}
} else {
this.searchCommodityList = res.data.items;
}
if (this.searchCommodityList.length <= 0) {
this.isNoCommodityData = true;
}
// 初始化选中状态如果商品已在selectCommodityList中自动勾选
this.checkboxList = [
...this.checkboxList,
...this.searchCommodityList
.filter((item) =>
this.selectCommodityList.some(
(selected) => selected.product_id === item.product_id
)
)
.map((item) => item.product_id),
];
if (this.allSelectedExistInCurrentPage) {
this.checkboxAllList = ["select-all"];
} else {
this.checkboxAllList = [];
}
this.searchCommodityList.forEach((item) => {
if (item.product_name.indexOf(this.inputSearch) >= 0) {
item.searchName = item.product_name.replace(
new RegExp(this.inputSearch, "g"),
"<font style='color:#fe4119;padding:0 4px'>" +
this.inputSearch +
"</font>"
);
} else {
item.searchName = item.name;
}
});
var {
allRecords,
normalRecords,
offRecords,
illegalRecords,
unCheckedRecords,
} = res.data;
this.searchCommodityStatusList[0].badge.value = allRecords;
this.searchCommodityStatusList[1].badge.value = normalRecords;
this.searchCommodityStatusList[2].badge.value = offRecords;
this.searchCommodityStatusList[3].badge.value = illegalRecords;
this.searchCommodityStatusList[4].badge.value = unCheckedRecords;
this.$nextTick(() => {
this.$refs.tabsRef.init();
});
}
this.loadingDownCommodityData = false;
this.loadingCommodityData = false;
this.isRefreshing = false;
},
handleRefresh() {
this.isRefreshing = true;
this.getProductList();
},
handerScrolltolower() {
clearTimeout(this.time);
this.checkboxAllList = [];
if (this.isNoDownCommodityData) return;
this.loadingDownCommodityData = true;
this.pageNum = this.pageNum + 1;
this.time = setTimeout(() => {
this.getProductList();
}, 500);
},
handerCommodityStatus(e) {
this.pageNum = 1;
this.pageSize = 20;
this.isNoDownCommodityData = false;
this.isNoCommodityData = false;
this.currProductStateId = e.value;
this.searchCommodityList = [];
this.getProductList();
},
handerSearchCommodityStatus() {},
emptySelectAll() {
this.showAffirmEmptyPopup = true;
},
affirmSelect() {
// 计算最终选中数量
const totalSelected = [
...new Set([
...this.selectCommodityList.map((item) => item.product_id),
...this.checkboxList,
]),
].length;
if (totalSelected > 100) {
uni.showToast({
title: `总数不能超过100个当前${totalSelected}`,
icon: "none",
});
return;
}
// 从searchCommodityList中找出所有被选中的商品对象
const selectedCommodities = this.searchCommodityList.filter((item) =>
this.checkboxList.includes(item.product_id)
);
// 过滤掉已经在父组件selectCommodityList中的商品
const newSelectedCommodities = selectedCommodities.filter(
(item) =>
!this.selectCommodityList.some(
(selected) => selected.product_id === item.product_id
)
);
// 传递给父组件的是新增的商品对象数组
this.$emit("searchCommodity", newSelectedCommodities);
this.$emit("pageBack");
},
hideImg() {
this.showImg = false;
},
handlerShowImg(url) {
if (!url) return;
this.showImg = true;
this.showImgList = [
{
src: url,
desc: "", // You can add description if needed
},
];
},
handleSelectAll(list) {
// 获取当前页所有商品ID包括滚动加载的
const currentPageIds = this.searchCommodityList.map(
(item) => item.product_id
);
if (list.length > 0) {
// 全选操作
if (currentPageIds.length + this.checkboxList.length > 100) {
// 如果超过限制,计算还能选多少
const remaining = 100 - this.checkboxList.length;
const toSelect = currentPageIds.slice(
0,
remaining > 0 ? remaining : 0
);
this.checkboxList = [...this.checkboxList, ...toSelect];
if (remaining <= 0) {
this.$refs.uToast.show({
message: "已达到100个商品上限",
type: "error",
duration: 1000,
});
}
// 取消全选复选框的选中状态
setTimeout(() => {
this.checkboxAllList = [];
}, 0);
} else {
// 可以全部选中当前页
this.checkboxList = [
...new Set([...this.checkboxList, ...currentPageIds]),
];
}
} else {
// 取消全选:只取消当前页商品的选择
this.checkboxList = this.checkboxList.filter(
(id) => !currentPageIds.includes(id)
);
}
},
handleSingleCheckboxChange(list, isFromCheckbox = false) {
const remaining = 100 - this.selectCommodityList.length;
const currentSelected = this.checkboxList.length;
// 处理单个商品点击
if (!isFromCheckbox) {
const productId = list[0];
const isAlreadySelected = this.checkboxList.includes(productId);
// 如果是取消选中操作,直接处理
if (isAlreadySelected) {
this.checkboxList = this.checkboxList.filter(
(id) => id !== productId
);
return;
}
// 如果是选中操作,检查限额
if (currentSelected >= remaining) {
this.$refs.uToast.show({
message: "最多可选100个商品超出的商品无法选中",
type: "error",
duration: 1000,
});
return;
}
this.checkboxList = [...this.checkboxList, productId];
return;
}
// 处理复选框组变化
if (list.length - currentSelected > remaining) {
return;
}
this.checkboxList = list;
},
},
};
</script>
<style lang="scss" scoped>
@import "@/styles/variables.scss";
.batch-search-container {
width: 100vw;
height: 100vh;
background: #fff;
.nav-bar {
padding-top: 10px;
}
.batch-search-scroll {
height: calc(100vh - 230px);
}
.commodity-list {
padding: 48rpx 52rpx 0;
.commodity-item {
display: flex;
align-items: center;
margin-bottom: 40rpx;
.commodity-checkbox {
margin-bottom: 20px;
margin-right: 20rpx;
}
.commodity-info {
display: flex;
.commodity-img {
position: relative;
margin-right: 20rpx;
width: 60px;
height: 60px;
border: 1px solid #ebebeb;
border-radius: 16rpx;
}
.commodity-img-sold-out {
&::before {
position: absolute;
bottom: 0;
width: 100%;
height: 20px;
line-height: 20px;
content: "已下架";
text-align: center;
background: rgba(0, 0, 0, 0.6);
color: #fff;
z-index: 99;
font-size: 14px;
border-bottom-left-radius: 16rpx;
border-bottom-right-radius: 16rpx;
}
}
.commodity-info-box {
display: flex;
flex-flow: column;
justify-content: space-between;
.commodity-name {
font-weight: bold;
font-size: 18px;
word-break: break-all; /* 允许在任意字符间断行 */
overflow-wrap: break-word; /* 优先在单词间断行 */
display: -webkit-box;
-webkit-line-clamp: 2; /* 限制最多2行 */
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis; /* 超出部分显示省略号 */
}
.commodity-inventory {
font-size: 28rpx;
color: #626262;
margin: 6rpx 0;
}
.commodity-price {
font-size: 32rpx;
font-weight: bold;
color: #ea3938;
.currency {
margin-right: 4px;
font-size: 24rpx;
}
}
}
}
}
}
.commodity-loading {
margin: 70% auto;
display: flex;
}
.m-loading-box {
text-align: center;
padding: 40rpx;
color: #aaaa;
font-size: 28rpx;
}
.bottom {
position: fixed;
width: 92%;
bottom: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
margin: 40px 0;
.commodity-btn-item {
margin: 0;
margin-right: 20rpx;
width: 360rpx;
height: 38px;
font-size: 28rpx;
border: none;
color: #fff;
background: $base-color;
&::after {
border: none;
}
}
}
.affirm-popup {
::v-deep.u-popup__content {
border-radius: 16rpx;
}
::v-deep.u-fade-enter-to {
z-index: 10076 !important;
}
.affirm-popup-content {
width: 600rpx;
.affirm-popup-title {
padding: 40rpx;
text-align: center;
font-weight: bold;
}
.affirm-popup-tips {
padding: 0 60rpx;
font-size: 28rpx;
text-align: center;
}
.popup-btn-list {
display: flex;
margin: 50rpx;
.btn-item {
width: 46%;
height: 80rpx;
border-color: #909193;
&::after {
border: none;
}
}
.btn-item-2 {
background: $base-color;
color: #fff;
border: none;
}
}
}
}
.commodity-type-popup {
.commodity-type-popup-content {
height: 500px;
}
}
.no-data {
.no-data-bg {
margin: 60% auto;
margin-bottom: 0;
width: 300rpx;
height: 200rpx;
background-image: url("../../../static/no-commodity.png");
background-size: 100%;
}
.no-data-tips {
margin: 80rpx auto;
color: #aaaaaa;
text-align: center;
}
}
}
</style>