ry_app/pages/navailable/navailable.vue

899 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="container">
<!-- 顶部状态栏/时间 -->
<view class="status-bar">
<text class="time">9:41</text>
</view>
<!-- 搜索栏 -->
<view class="search-bar">
<view class="search-input">
<uni-icons type="search" size="18" color="#999"></uni-icons>
<input
type="text"
placeholder="搜索商品名称、条码"
placeholder-class="placeholder"
v-model="searchText"
@confirm="onSearch"
<uni-icons type="scan" size="18" color="#999"></uni-icons>
</view>
</view>
<!-- 筛选标签 -->
<view class="filter-tabs">
<scroll-view class="tabs-scroll" scroll-x="true">
<view
class="tab-item"
:class="{ active: currentTab === 'all' }"
@tap="switchTab('all')"
>
全部
</view>
<view
class="tab-item"
:class="{ active: currentTab === 'expiring' }"
@tap="navigateToExpiredPage"
>
临期/过期<text class="badge">0</text>
</view>
<view
class="tab-item"
:class="{ active: currentTab === 'outstock' }"
@tap="switchTab('outstock')"
>
缺货<text class="badge">0</text>
</view>
<view class="tab-item filter-btn" @tap="showFilter = !showFilter">
<text>筛选</text>
<uni-icons type="arrowdown" size="14" color="#666"></uni-icons>
</view>
</scroll-view>
</view>
<!-- 库存不足预警设置 -->
<view class="store-status">
<view class="status-content">
<view class="dui">
<image class="dui-img" src="http://193.112.94.36:8099/static/images/Mask group (1).png"></image>
</view>
<view class="status-left">
<text class="status-text">库存不足预警设置</text>
<text class="status-num">库存低于已设置阈值时会收到APP推送提醒</text>
</view>
</view>
<view class="status-right" @tap="goToSettings">
<text class="set-text">设置</text>
<uni-icons type="forward" size="14" color="#666"></uni-icons>
</view>
</view>
<!-- 商品列表/空状态 -->
<scroll-view class="goods-list" scroll-y="true">
<view class="empty-state" v-if="goodsList.length === 0">
<image class="empty-img" src="/static/empty.png"></image>
<text class="empty-text">没有找到相关商品</text>
</view>
<view class="goods-item" v-for="item in goodsList" :key="item.id">
<view class="goods-more-icon" @tap="toggleDeleteMenu(item)">
<uni-icons type="more-filled" size="18"></uni-icons>
</view>
<view class="goods-delete-menu" v-if="item.showDeleteMenu" @tap="showDeleteConfirm(item)">
<text class="delete-menu-text">删除商品</text>
</view>
<view class="goods-top" @tap="goToStockDetail(item)">
<view class="goods-tou">
<image :src="item.mainImage ? 'http://193.112.94.36:8081' + item.mainImage : '/static/687b6f95b14eff60f4b77147b3726ab2.jpg'"></image>
</view>
<view class="goods-info">
<text class="goods-name">{{ item.productName }}</text>
<text class="goods-barcode">{{ item.productBarCode }}</text>
<text class="goods-price">¥{{ item.storePrice ? item.storePrice.toFixed(2) : '0.00' }}</text>
</view>
</view>
<view class="goods-divider"></view>
<view class="goods-stock" >
<text class="stock-label">总库存</text>
<text class="stock-num">{{ item.stockQuantity }} 件</text>
<text class="stock-arrow">></text>
</view>
</view>
</scroll-view>
<!-- 底部操作按钮 -->
<view class="bottom-actions">
<view class="action-btn more-btn" @tap="showMoreActions()">
<text>更多</text>
</view>
<button class="action-button primary" @tap="addNewGoods">
添加商品/库存
</button>
<!-- <button class="action-button" @tap="batchOperation">
批量操作
</button> -->
</view>
<!-- 更多操作弹窗 -->
<uni-popup ref="popup" type="bottom">
<view class="popup-content">
<view class="popup-item" @tap="goToInventoryCount">
<uni-icons type="scan" size="20" color="#333"></uni-icons>
<text>盘点库存</text>
</view>
<view class="popup-item" @tap="goToOutbound">
<uni-icons type="arrowright" size="20" color="#333"></uni-icons>
<text>出库</text>
</view>
<view class="popup-item" @tap="batchDeleteGoods">
<uni-icons type="trash" size="20" color="#333"></uni-icons>
<text>批量删除商品</text>
</view>
<view class="popup-item" @tap="goToCategoryManagement">
<uni-icons type="apps" size="20" color="#333"></uni-icons>
<text>分类管理</text>
</view>
<view class="popup-item" @tap="goToBrandManagement">
<uni-icons type="navigate" size="20" color="#333"></uni-icons>
<text>品牌管理</text>
</view>
<view class="popup-item" @tap="goToBarcodeSettings">
<uni-icons type="settings" size="20" color="#333"></uni-icons>
<text>条码规则设置</text>
</view>
<view class="popup-item cancel" @tap="$refs.popup.close()">
<text>取消</text>
</view>
</view>
</uni-popup>
<!-- 更多操作弹窗 -->
<!-- <uni-popup ref="popup" type="bottom">
<view class="popup-content">
<view class="popup-item" @tap="editGoods(selectedGoods)">
<uni-icons type="compose" size="20" color="#333"></uni-icons>
<text>编辑商品</text>
</view>
<view class="popup-item" @tap="adjustStock(selectedGoods)">
<uni-icons type="plus" size="20" color="#333"></uni-icons>
<text>调整库存</text>
</view>
<view class="popup-item" @tap="deleteGoods(selectedGoods)">
<uni-icons type="trash" size="20" color="#ff4444"></uni-icons>
<text style="color: #ff4444;">删除商品</text>
</view>
<view class="popup-item cancel" @tap="$refs.popup.close()">
<text>取消</text>
</view>
</view>
</uni-popup> -->
</view>
</template>
<script>
import { getProductList as fetchProductList, deleteProduct } from '@/api/product'
import { getToken, getStoreId } from '@/utils/auth'
export default {
data() {
return {
currentTab: 'expiring',
searchText: '',
showFilter: false,
selectedGoods: null,
storeId: null, // 门店ID
goodsList: []
}
},
onLoad(options) {
// 获取门店ID
const storeId = getStoreId();
if (storeId) {
this.storeId = storeId;
console.log('当前门店ID:', storeId);
} else {
uni.showToast({
title: '请先选择门店',
icon: 'none'
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
return;
}
// 处理tab参数
if (options && options.tab) {
this.currentTab = options.tab;
}
this.getProductList();
},
onShow() {
this.getProductList();
},
methods: {
async getProductList(searchParams = {}) {
try {
const token = getToken();
console.log('当前Token:', token);
console.log('Token是否存在:', !!token);
console.log('查询参数:', searchParams);
// 添加门店ID参数
if (this.storeId) {
searchParams.storeId = this.storeId;
}
// 如果是缺货标签,调用缺货商品接口
if (this.currentTab === 'outstock') {
// 这里应该调用缺货商品接口传参stockQuantity=0
// 暂时使用原接口,后续需要替换为正确的接口
searchParams.stockQuantity = 0;
}
const res = await fetchProductList(searchParams);
console.log('商品列表接口返回:', res);
if (res && res.code === 200 && res.data) {
this.goodsList = res.data.map(item => ({
...item,
showDeleteMenu: false
}));
console.log('处理后的商品列表:', this.goodsList);
} else {
this.goodsList = [];
uni.showToast({
title: res?.msg || '获取商品列表失败',
icon: 'none'
});
}
} catch (error) {
this.goodsList = [];
console.error('获取商品列表失败:', error);
console.error('错误详情:', JSON.stringify(error));
uni.showToast({
title: '网络请求失败',
icon: 'none'
});
}
},
switchTab(tab) {
if (tab === 'all') {
// 跳转到商品列表页面,并传递当前标签
uni.navigateTo({
url: `/pages/product/product?tab=${tab}`
});
} else if (tab === 'outstock') {
// 跳转到缺货页面
uni.navigateTo({
url: `/pages/navailable/navailable?tab=${tab}`
});
} else {
this.currentTab = tab;
// 这里可以添加筛选逻辑
console.log('切换到标签:', tab);
}
},
// 缺货页面批量删除商品
batchDeleteGoods() {
this.$refs.popup.close();
uni.navigateTo({
url: '/pages/batchDeleteProduct/batchDeleteProduct'
});
},
// 分类管理
goToCategoryManagement() {
this.$refs.popup.close();
uni.navigateTo({
url: '/pages/category/category'
});
},
// 品牌管理
goToBrandManagement() {
this.$refs.popup.close();
uni.navigateTo({
url: '/pages/addBrand/addBrand'
});
},
// 条码规则设置
goToBarcodeSettings() {
this.$refs.popup.close();
uni.navigateTo({
url: '/pages/barcodeSettings/barcodeSettings'
});
},
// 盘点库存
goToInventoryCount() {
this.$refs.popup.close();
uni.navigateTo({
url: '/pages/inventoryCount/inventoryCount'
});
},
// 出库
goToOutbound() {
this.$refs.popup.close();
uni.navigateTo({
url: '/pages/outbound/outbound'
});
},
onSearch() {
console.log('搜索关键词:', this.searchText);
if (!this.searchText || this.searchText.trim() === '') {
this.getProductList();
return;
}
const searchText = this.searchText.trim();
let searchParams = {};
if (/^\d+$/.test(searchText)) {
searchParams = { productBarCode: searchText };
console.log('按条形码精准查询:', searchParams);
} else {
searchParams = { productName: searchText };
console.log('商品名称模糊查询:', searchParams);
}
this.getProductList(searchParams);
},
goToAlertSettings() {
uni.navigateTo({
url: '/pages/alertSettings/index'
});
},
showMoreActions() {
this.$refs.popup.open();
},
goToStockTake() {
this.$refs.moreMenu.close();
uni.navigateTo({
url: '/pages/stockTake/index'
});
},
goToOutbound() {
this.$refs.moreMenu.close();
uni.navigateTo({
url: '/pages/outbound/index'
});
},
batchDelete() {
this.$refs.moreMenu.close();
uni.showModal({
title: '批量删除',
content: '确定要批量删除商品吗?',
success: (res) => {
if (res.confirm) {
// 执行批量删除操作
}
}
});
},
goToCategory() {
this.$refs.moreMenu.close();
uni.navigateTo({
url: '/pages/category/index'
});
},
goToBrand() {
this.$refs.moreMenu.close();
uni.navigateTo({
url: '/pages/brand/index'
});
},
goToBarcodeRule() {
this.$refs.moreMenu.close();
uni.navigateTo({
url: '/pages/barcodeRule/index'
});
},
goToStockDetail(item) {
// 跳转到编辑页面传递商品ID
uni.navigateTo({
url: `/pages/edit/edit?id=${item.id}`
});
},
toggleDeleteMenu(item) {
item.showDeleteMenu = !item.showDeleteMenu;
},
showDeleteConfirm(item) {
uni.showModal({
title: '确认删除',
content: `确定要删除商品"${item.productName}"吗?`,
success: async (res) => {
if (res.confirm) {
try {
const result = await deleteProduct(item.id);
console.log('删除商品结果:', result);
if (result && result.code === 200) {
uni.showToast({
title: '删除成功',
icon: 'success'
});
// 重新加载商品列表
this.getProductList();
} else {
uni.showToast({
title: result?.msg || '删除失败',
icon: 'none'
});
}
} catch (error) {
console.error('删除商品失败:', error);
uni.showToast({
title: '删除失败',
icon: 'none'
});
}
}
}
});
},
addNewGoods() {
uni.navigateTo({
url: '/pages/enter/enter'
});
},
// 临期/过期商品页面,不需要跳转
navigateToExpiredPage() {
uni.navigateTo({
url: '/pages/expired/expired'
});
},
editGoods(goods) {
this.$refs.popup.close();
uni.navigateTo({
url: `/pages/goods/edit?id=${goods.id}`
});
},
adjustStock(goods) {
this.$refs.popup.close();
uni.showModal({
title: '调整库存',
content: `调整 ${goods.productName} 的库存数量`,
editable: true,
placeholderText: '请输入调整数量',
success: (res) => {
if (res.confirm && res.content) {
console.log('调整库存数量:', res.content);
}
}
});
},
deleteGoods(goods) {
this.$refs.popup.close();
uni.showModal({
title: '确认删除',
content: `确定要删除商品"${goods.productName}"吗?`,
success: (res) => {
if (res.confirm) {
console.log('删除商品:', goods);
uni.showToast({
title: '删除成功',
icon: 'success'
});
}
}
});
}
}
}
</script>
<style scoped>
.container {
background-color: #f5f5f5;
min-height: 100vh;
}
.goods-tou{
width: 100rpx;
height: 100rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
.dui-img {
width: 24rpx;
height: 24rpx;
}
.goods-tou image {
width: 100%;
height: 100%;
border-radius: 8rpx;
}
/* 状态栏 */
.status-bar {
padding: 10px 16px;
background-color: #fff;
}
.time {
font-size: 16px;
font-weight: 600;
}
/* 搜索栏 */
.search-bar {
padding: 12px 16px;
background-color: #fff;
}
.search-input {
display: flex;
align-items: center;
background-color: #f5f5f5;
border-radius: 8px;
padding: 10px 12px;
}
.search-input input {
flex: 1;
margin-left: 8px;
font-size: 14px;
}
.placeholder {
color: #999;
}
/* 筛选标签 */
.filter-tabs {
background-color: #fff;
padding: 12px 16px;
border-bottom: 1px solid #eee;
}
.tabs-scroll {
white-space: nowrap;
}
.tab-item {
display: inline-block;
padding: 6px 12px;
margin-right: 10px;
border-radius: 16px;
font-size: 14px;
background-color: #f5f5f5;
color: #666;
}
.tab-item.active {
background-color: #e8f4ff;
color: #007aff;
}
.badge {
margin-left: 4px;
color: #ff4444;
}
.filter-btn {
display: inline-flex;
align-items: center;
}
/* 库存不足预警栏 */
.alert-bar {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #E8F4FF;
padding: 12px 16px;
margin: 8px 16px;
border-radius: 8px;
}
.alert-left {
display: flex;
align-items: flex-start;
}
.alert-text-group {
margin-left: 8px;
}
.alert-text {
display: block;
font-size: 14px;
color: #333;
font-weight: 500;
}
.alert-desc {
display: block;
font-size: 12px;
color: #666;
margin-top: 2px;
}
.alert-right {
display: flex;
align-items: center;
}
.setting-text {
font-size: 14px;
color: #007AFF;
margin-right: 4px;
}
/* 商品列表 */
.goods-list {
height: calc(100vh - 320px);
padding: 16px;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.empty-img {
width: 120rpx;
height: 120rpx;
margin-bottom: 16rpx;
}
.empty-text {
font-size: 14px;
color: #999;
}
.goods-item {
background-color: #fff;
border-radius: 8px;
padding: 16px;
margin-bottom: 12px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
position: relative;
}
.goods-more-icon {
position: absolute;
top: 12px;
right: 12px;
z-index: 10;
}
.goods-delete-menu {
position: absolute;
top: 40px;
right: 12px;
background-color: #fff;
border-radius: 8rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
padding: 12rpx 24rpx;
z-index: 9;
}
.delete-menu-text {
font-size: 28rpx;
color: #ff4444;
}
.goods-top {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
}
.goods-info {
flex: 1;
margin-bottom: 0;
}
.goods-name {
display: block;
font-size: 16px;
font-weight: 500;
color: #333;
margin-bottom: 6px;
}
.goods-barcode {
font-size: 12px;
color: #999;
display: block;
margin-bottom: 8px;
}
.goods-price {
font-size: 18px;
color: #ff4444;
font-weight: 600;
}
.goods-divider {
height: 1px;
border-bottom: 1px dashed #e0e0e0;
margin-bottom: 12px;
}
.goods-stock {
display: flex;
align-items: center;
padding: 8px 0;
margin-bottom: 4px;
}
.stock-arrow {
font-size: 20px;
color: #999;
margin-left: auto;
}
.stock-label {
font-size: 14px;
color: #666;
}
.stock-num {
font-size: 16px;
color: #333;
font-weight: 500;
}
/* 底部操作按钮 */
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
padding: 16px;
background-color: #fff;
border-top: 1px solid #eee;
}
.action-btn {
padding: 8px 16px;
border-radius: 6px;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
}
.more-btn {
background-color: #f5f5f5;
color: #666;
margin-right: 8px;
}
.action-button {
flex: 1;
margin: 0 8px;
padding: 12px;
border-radius: 8px;
font-size: 16px;
background-color: #f5f5f5;
color: #333;
border: none;
}
.action-button.primary {
background-color: #007aff;
color: #fff;
}
/* 左侧菜单样式 */
.menu-content {
background-color: #fff;
height: 100vh;
width: 280rpx;
padding: 20rpx 0;
}
.menu-item {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
font-size: 14px;
border-bottom: 1px solid #f5f5f5;
}
.menu-item text {
margin-left: 12rpx;
}
/* 弹窗样式 */
.popup-content {
background-color: #fff;
border-radius: 16px 16px 0 0;
padding: 20px;
}
.popup-item {
display: flex;
align-items: center;
padding: 16px 0;
border-bottom: 1px solid #f5f5f5;
font-size: 16px;
}
.popup-item:last-child {
border-bottom: none;
}
.popup-item text {
margin-left: 12px;
}
.popup-item.cancel {
justify-content: center;
color: #666;
}
/* 微店状态栏 */
.store-status {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background-color: #fff;
border-radius: 20rpx;
margin-top: 8px;
}
.status-content {
display: flex;
align-items: center;
}
.dui {
margin-right: 12rpx;
}
.dui-img {
width: 24rpx;
height: 24rpx;
}
.status-left {
display: flex;
flex-direction: column;
margin-left: 0;
}
.status-text {
font-size: 14px;
color: #333;
}
.status-num {
font-size: 12px;
color: #666;
margin-top: 4px;
}
.status-right {
display: flex;
align-items: center;
margin-right: 1rpx;
}
.set-text {
font-size: 14px;
color: #666;
margin-right: 4px;
}
</style>