feat(机柜管理): 添加商品绑定功能及API接口
- 新增商品绑定弹窗组件BindGoods,支持选择商品、设置库存和解绑 - 添加机柜商品管理相关API接口:configureGoodsCellsStock、changeGoodsCellsStock、clearGoodsCells - 扩展商品类型定义,新增ShopGoodsEntity和SearchGoodsDO接口 - 修改机柜页面布局,添加绑定商品按钮和弹窗 - 修复路由守卫中注释掉的isAdmin判断逻辑
This commit is contained in:
parent
2132e0e1e5
commit
9ff0984fe1
|
@ -19,4 +19,26 @@ export function openCabinet(cabinetId: number, pinNo: number, data: OpenCabinetA
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const configureGoodsCellsStock = (cellId: number, goodsId: number, stock: number) => {
|
||||||
|
return request<ApiResponseData<void>>({
|
||||||
|
url: `/cabinet/configureGoodsCellsStock/${cellId}/${goodsId}/${stock}`,
|
||||||
|
method: 'put'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const changeGoodsCellsStock = (cellId: number, stock: number) => {
|
||||||
|
return request<ApiResponseData<void>>({
|
||||||
|
url: `/cabinet/changeGoodsCellsStock/${cellId}/${stock}`,
|
||||||
|
method: 'put'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const clearGoodsCells = (cellId: number) => {
|
||||||
|
return request<ApiResponseData<void>>({
|
||||||
|
url: `/cabinet/clearGoodsCells/${cellId}`,
|
||||||
|
method: 'put'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
import { request } from "@/http/axios"
|
import { request } from "@/http/axios"
|
||||||
import { GetBalanceResponse, GetOrdersByOpenIdDTO, OpenCabinetApiData, QyLoginDTO, QyLoginRequestParams, ShopEntity, ShopGoodsResponseData, SubmitOrderRequestData, SubmitOrderResponseData } from './type'
|
import { GetBalanceResponse, GetOrdersByOpenIdDTO, OpenCabinetApiData, QyLoginDTO, QyLoginRequestParams, SearchGoodsDO, ShopEntity, ShopGoodsEntity, ShopGoodsResponseData, SubmitOrderRequestData, SubmitOrderResponseData } from './type'
|
||||||
import { GetOpenIdRequestParams } from './type'
|
import { GetOpenIdRequestParams } from './type'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 获取商品列表 */
|
/** 获取商品列表 */
|
||||||
|
export function getShopGoodsListApi(corpid: string, belongType: number) {
|
||||||
|
return request<ApiResponseData<SearchGoodsDO[]>>({
|
||||||
|
url: "shop/goods/list",
|
||||||
|
method: "get",
|
||||||
|
params: { corpid, belongType }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function getShopGoodsApi(shopId: number|null) {
|
export function getShopGoodsApi(shopId: number|null) {
|
||||||
return request<ShopGoodsResponseData>({
|
return request<ShopGoodsResponseData>({
|
||||||
url: "shop/goods",
|
url: "shop/goods",
|
||||||
|
|
|
@ -12,6 +12,39 @@ export type Goods = {
|
||||||
belongType: number
|
belongType: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ShopGoodsEntity {
|
||||||
|
/** 商品唯一ID */
|
||||||
|
goodsId: number;
|
||||||
|
/** 商品名称 */
|
||||||
|
goodsName: string;
|
||||||
|
/** 商品分类ID */
|
||||||
|
categoryId: number;
|
||||||
|
/** 外部归属类型的商品ID */
|
||||||
|
externalGoodsId?: number;
|
||||||
|
/** 企业微信id */
|
||||||
|
corpid?: string;
|
||||||
|
/** 每人每月限购数量 */
|
||||||
|
monthlyPurchaseLimit?: number;
|
||||||
|
/** 销售价格 */
|
||||||
|
price: number;
|
||||||
|
/** 库存数量 */
|
||||||
|
stock: number;
|
||||||
|
/** 商品状态(1上架 2下架) */
|
||||||
|
status: number;
|
||||||
|
/** 免审批(0否 1是) */
|
||||||
|
autoApproval?: number;
|
||||||
|
/** 封面图URL */
|
||||||
|
coverImg?: string;
|
||||||
|
/** 商品详情(支持2000汉字+10个图片链接) */
|
||||||
|
goodsDetail?: string;
|
||||||
|
/** 备注 */
|
||||||
|
remark?: string;
|
||||||
|
/** 商品使用说明 */
|
||||||
|
usageInstruction?: string;
|
||||||
|
/** 归属类型(0-借还柜 1-固资通) */
|
||||||
|
belongType?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export type category = {
|
export type category = {
|
||||||
categoryId: number,
|
categoryId: number,
|
||||||
categoryName: string,
|
categoryName: string,
|
||||||
|
@ -180,7 +213,33 @@ export interface OpenCabinetApiData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ShopEntity {
|
export interface ShopEntity {
|
||||||
shopId: number
|
/** 主键ID */
|
||||||
shopName: string
|
shopId: number;
|
||||||
corpid: string
|
/** 商店名称 */
|
||||||
|
shopName: string;
|
||||||
|
/** 企业微信id */
|
||||||
|
corpid: string;
|
||||||
|
/** 运行模式(0-支付模式 1-审批模式 2-借还模式 3-会员模式 4-耗材模式) */
|
||||||
|
mode?: number;
|
||||||
|
/** 借呗支付(1-正常使用 0-禁止使用) */
|
||||||
|
balanceEnable?: number;
|
||||||
|
/** 封面图URL */
|
||||||
|
coverImg?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchGoodsDO extends ShopGoodsEntity {
|
||||||
|
/** 分类名称 */
|
||||||
|
categoryName?: string;
|
||||||
|
/** 柜子ID */
|
||||||
|
cabinetId?: number;
|
||||||
|
/** 柜子名称 */
|
||||||
|
cabinetName?: string;
|
||||||
|
/** 商店名称字符串 */
|
||||||
|
shopNameStr?: string;
|
||||||
|
/** 格口编号 */
|
||||||
|
cellNo?: number;
|
||||||
|
/** 格口编号字符串 */
|
||||||
|
cellNoStr?: string;
|
||||||
|
/** 已分配库存 */
|
||||||
|
totalStock?: number;
|
||||||
}
|
}
|
|
@ -0,0 +1,341 @@
|
||||||
|
<template>
|
||||||
|
<div class="bind-goods-container">
|
||||||
|
<div class="header">
|
||||||
|
<van-nav-bar title="选择商品" left-text="取消" @click-left="onCancel" />
|
||||||
|
</div>
|
||||||
|
<div class="search-container">
|
||||||
|
<div v-if="currentGoodsName" class="current-goods-info">
|
||||||
|
<div class="goods-name">当前绑定: {{ currentGoodsName }}</div>
|
||||||
|
<div class="stock-controls">
|
||||||
|
<van-field
|
||||||
|
v-model="newStock"
|
||||||
|
type="number"
|
||||||
|
label="库存"
|
||||||
|
placeholder="输入库存数量"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
<van-button size="small" type="primary" @click="handleUpdateStock">修改库存</van-button>
|
||||||
|
<van-button size="small" type="danger" @click="handleUnbind">解绑</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<van-search v-model="searchQuery" placeholder="搜索商品名称" shape="round" />
|
||||||
|
</div>
|
||||||
|
<div class="goods-list" ref="scrollContainer">
|
||||||
|
<van-cell v-for="goods in filteredGoods" :key="goods.goodsId" class="goods-item">
|
||||||
|
<template #icon>
|
||||||
|
<van-image
|
||||||
|
:src="goods.coverImg || `${publicPath}img/product-image.svg`"
|
||||||
|
width="80"
|
||||||
|
height="80"
|
||||||
|
fit="cover"
|
||||||
|
radius="4"
|
||||||
|
class="goods-image"
|
||||||
|
:style="{ filter: goods.stock === 0 ? 'grayscale(100%)' : 'none' }"
|
||||||
|
>
|
||||||
|
</van-image>
|
||||||
|
</template>
|
||||||
|
<div class="goods-info">
|
||||||
|
<div class="name-price-container">
|
||||||
|
<div class="goods-name van-ellipsis">{{ goods.goodsName }}</div>
|
||||||
|
<div class="goods-price">¥{{ (goods.price || 0).toFixed(2) }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="stock-info">
|
||||||
|
<span>总库存: {{ goods.stock || 0 }}</span>
|
||||||
|
<span>已分配: {{ goods.totalStock || 0 }}</span>
|
||||||
|
<span>剩余: {{ (goods.stock || 0) - (goods.totalStock || 0) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-row">
|
||||||
|
<van-stepper
|
||||||
|
v-model="allocatedStocks[goods.goodsId]"
|
||||||
|
:min="1"
|
||||||
|
:max="(goods.stock || 0) - (goods.totalStock || 0)"
|
||||||
|
:disabled="goods.stock === 0 || loading"
|
||||||
|
size="small"
|
||||||
|
class="stock-stepper"
|
||||||
|
/>
|
||||||
|
<van-button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
class="bind-btn"
|
||||||
|
:disabled="(goods.stock || 0) - (goods.totalStock || 0) <= 0 || loading || !allocatedStocks[goods.goodsId]"
|
||||||
|
:loading="loading && currentBindGoodsId === goods.goodsId"
|
||||||
|
@click="handleBindGoods(goods)"
|
||||||
|
>
|
||||||
|
绑定
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-cell>
|
||||||
|
<div v-if="goodsList.length === 0 && !loading" class="empty-state">
|
||||||
|
<van-empty description="暂无商品数据" />
|
||||||
|
</div>
|
||||||
|
<div v-if="loading" class="loading-state">
|
||||||
|
<van-loading type="spinner" color="#e95d5d" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted, defineProps, defineEmits } from 'vue';
|
||||||
|
import { getShopGoodsApi, getShopGoodsListApi } from '@/common/apis/shop';
|
||||||
|
import { ShopGoodsEntity, SearchGoodsDO } from '@/common/apis/shop/type';
|
||||||
|
import { publicPath } from '@/common/utils/path';
|
||||||
|
import { useWxStore } from '@/pinia/stores/wx';
|
||||||
|
import { showToast } from 'vant';
|
||||||
|
import { configureGoodsCellsStock, changeGoodsCellsStock, clearGoodsCells } from '@/common/apis/cabinet';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
shopId: number;
|
||||||
|
lockerId: number;
|
||||||
|
visible: boolean;
|
||||||
|
currentStock?: number;
|
||||||
|
currentGoodsName?: string;
|
||||||
|
mode?: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'cancel'): void;
|
||||||
|
(e: 'success', goods: ShopGoodsEntity): void;
|
||||||
|
(e: 'unbind'): void;
|
||||||
|
(e: 'update:currentStock', stock: number): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const wxStore = useWxStore();
|
||||||
|
const searchQuery = ref('');
|
||||||
|
const newStock = ref<number>(props.currentStock || 0);
|
||||||
|
const goodsList = ref<SearchGoodsDO[]>([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const currentBindGoodsId = ref<number | null>(null);
|
||||||
|
const scrollContainer = ref<HTMLElement>();
|
||||||
|
const allocatedStocks = ref<Record<number, number>>({});
|
||||||
|
|
||||||
|
// 过滤商品列表
|
||||||
|
const filteredGoods = computed(() => {
|
||||||
|
if (!searchQuery.value) return goodsList.value;
|
||||||
|
return goodsList.value.filter(goods =>
|
||||||
|
goods.goodsName.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取商品列表
|
||||||
|
const loadGoodsList = async () => {
|
||||||
|
if (!props.shopId) return;
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const belongType = props.mode === 4 ? 1 : 0;
|
||||||
|
const response = await getShopGoodsListApi(wxStore.corpid, belongType); // 根据mode动态设置belongType参数
|
||||||
|
if (response?.code === 0 && response.data) {
|
||||||
|
goodsList.value = response.data;
|
||||||
|
// 初始化分配库存
|
||||||
|
goodsList.value.forEach(goods => {
|
||||||
|
allocatedStocks.value[goods.goodsId] = 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取商品列表失败:', error);
|
||||||
|
showToast('获取商品列表失败,请重试');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 绑定商品
|
||||||
|
const handleBindGoods = async (goods: SearchGoodsDO) => {
|
||||||
|
const remaining = (goods.stock || 0) - (goods.totalStock || 0);
|
||||||
|
if (goods.stock === 0 || remaining <= 0) {
|
||||||
|
showToast('商品剩余库存不足,无法绑定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (allocatedStocks.value[goods.goodsId] > remaining) {
|
||||||
|
showToast(`入库数量不能超过剩余数量${remaining}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBindGoodsId.value = goods.goodsId;
|
||||||
|
try {
|
||||||
|
await configureGoodsCellsStock(props.lockerId, goods.goodsId, allocatedStocks.value[goods.goodsId]);
|
||||||
|
emits('success', goods);
|
||||||
|
showToast('商品绑定成功');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('绑定商品失败:', error);
|
||||||
|
showToast('绑定商品失败,请重试');
|
||||||
|
} finally {
|
||||||
|
currentBindGoodsId.value = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdateStock = async () => {
|
||||||
|
if (newStock.value < 0) {
|
||||||
|
showToast('库存不能为负数');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await changeGoodsCellsStock(props.lockerId, newStock.value);
|
||||||
|
showToast('库存修改成功');
|
||||||
|
emits('update:currentStock', newStock.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('修改库存失败:', error);
|
||||||
|
showToast('修改库存失败,请重试');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUnbind = async () => {
|
||||||
|
try {
|
||||||
|
await clearGoodsCells(props.lockerId);
|
||||||
|
showToast('商品解绑成功');
|
||||||
|
emits('unbind');
|
||||||
|
emits('cancel');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解绑商品失败:', error);
|
||||||
|
showToast('解绑商品失败,请重试');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消绑定
|
||||||
|
const onCancel = () => {
|
||||||
|
emits('cancel');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听visible变化,当弹窗显示时加载商品列表
|
||||||
|
watch(() => props.visible, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
newStock.value = props.currentStock || 0;
|
||||||
|
loadGoodsList();
|
||||||
|
}
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始加载商品列表
|
||||||
|
if (props.visible) {
|
||||||
|
loadGoodsList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.bind-goods-container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-container {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-goods-info {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-controls .van-field {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-controls .van-button {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-image {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 90px; // 调整高度以适应新布局
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-price-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-price {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #e95d5d;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-stepper {
|
||||||
|
margin-right: 10px;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bind-btn {
|
||||||
|
background-color: #e95d5d;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-info {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-info span {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 40px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-state {
|
||||||
|
padding: 40px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -16,7 +16,7 @@
|
||||||
</van-row>
|
</van-row>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="cabinet-container van-safe-area-bottom">
|
<div v-else class="cabinet-container van-safe-area-bottom">
|
||||||
<div>
|
<div class="left-container">
|
||||||
<van-button icon="revoke" type="default" class="showShopListBtn" @click="handleBackToShopList">重选地址</van-button>
|
<van-button icon="revoke" type="default" class="showShopListBtn" @click="handleBackToShopList">重选地址</van-button>
|
||||||
<van-sidebar v-model="activeCabinet" class="cabinet-sidebar" @change="onCabinetChange">
|
<van-sidebar v-model="activeCabinet" class="cabinet-sidebar" @change="onCabinetChange">
|
||||||
<van-sidebar-item v-for="cabinet in cabinetList" :key="cabinet.cabinetId" :title="cabinet.cabinetName" />
|
<van-sidebar-item v-for="cabinet in cabinetList" :key="cabinet.cabinetId" :title="cabinet.cabinetName" />
|
||||||
|
@ -55,9 +55,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<van-button size="small" type="primary" class="detail-btn" @click="showLockerDetail(locker)">
|
<van-button size="small" type="primary" class="detail-btn" @click="showBindGoods(locker)">
|
||||||
详情
|
绑定商品
|
||||||
</van-button>
|
</van-button>
|
||||||
|
|
||||||
<van-button size="small" plain hairline :loading="openingLockerId === locker.lockerId"
|
<van-button size="small" plain hairline :loading="openingLockerId === locker.lockerId"
|
||||||
@click="handleOpenLocker(locker)">
|
@click="handleOpenLocker(locker)">
|
||||||
立即开启
|
立即开启
|
||||||
|
@ -66,6 +67,22 @@
|
||||||
</div>
|
</div>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<VanPopup v-model:show="showBindGoodsPopup" position="bottom" :style="{ height: '95%' }" round>
|
||||||
|
<BindGoods
|
||||||
|
v-if="currentLocker"
|
||||||
|
:shop-id="shopId"
|
||||||
|
:locker-id="currentLocker.lockerId"
|
||||||
|
:visible="showBindGoodsPopup"
|
||||||
|
:current-stock="currentLocker.stock"
|
||||||
|
:current-goods-name="currentLocker.goodsName"
|
||||||
|
:mode="selectedShop?.mode"
|
||||||
|
@cancel="showBindGoodsPopup = false"
|
||||||
|
@success="handleBindSuccess"
|
||||||
|
@unbind="handleBindSuccess"
|
||||||
|
@update:currentStock="handleStockUpdate"
|
||||||
|
/>
|
||||||
|
</VanPopup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -74,10 +91,13 @@ import { throttle } from 'lodash-es';
|
||||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
|
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
|
||||||
import { getShopListApi } from '@/common/apis/shop';
|
import { getShopListApi } from '@/common/apis/shop';
|
||||||
import { ShopEntity } from '@/common/apis/shop/type';
|
import { ShopEntity } from '@/common/apis/shop/type';
|
||||||
import { getCabinetDetailApi, openCabinet } from '@/common/apis/cabinet';
|
import { getCabinetDetailApi, openCabinet, changeGoodsCellsStock, clearGoodsCells } from '@/common/apis/cabinet';
|
||||||
import type { CabinetDetailDTO } from '@/common/apis/cabinet/type';
|
import type { CabinetDetailDTO } from '@/common/apis/cabinet/type';
|
||||||
import { useWxStore, useWxStoreOutside } from '@/pinia/stores/wx';
|
import { useWxStore, useWxStoreOutside } from '@/pinia/stores/wx';
|
||||||
import { publicPath } from "@/common/utils/path";
|
import { publicPath } from "@/common/utils/path";
|
||||||
|
import BindGoods from './components/BindGoods.vue';
|
||||||
|
import VanPopup from 'vant/es/popup';
|
||||||
|
import { showDialog, showToast } from 'vant';
|
||||||
|
|
||||||
const wxStore = useWxStore();
|
const wxStore = useWxStore();
|
||||||
const { userid: qyUserid, name: qyName } = storeToRefs(wxStore);
|
const { userid: qyUserid, name: qyName } = storeToRefs(wxStore);
|
||||||
|
@ -86,12 +106,15 @@ const activeCabinet = ref(0)
|
||||||
const cabinetList = ref<CabinetItem[]>([])
|
const cabinetList = ref<CabinetItem[]>([])
|
||||||
const lockerList = ref<LockerItem[]>([])
|
const lockerList = ref<LockerItem[]>([])
|
||||||
const openingLockerId = ref<number | null>(null)
|
const openingLockerId = ref<number | null>(null)
|
||||||
|
const showBindGoodsPopup = ref(false)
|
||||||
|
const currentLocker = ref<LockerItem | null>(null)
|
||||||
const cabinetData = ref<CabinetDetailDTO[]>([]);
|
const cabinetData = ref<CabinetDetailDTO[]>([]);
|
||||||
const scrollContainer = ref<HTMLElement>();
|
const scrollContainer = ref<HTMLElement>();
|
||||||
// 机柜地址选择相关状态
|
// 机柜地址选择相关状态
|
||||||
const showShopList = ref(true);
|
const showShopList = ref(true);
|
||||||
const shopList = ref<ShopEntity[]>([]);
|
const shopList = ref<ShopEntity[]>([]);
|
||||||
const shopId = ref<number>(0);
|
const shopId = ref<number>(0);
|
||||||
|
const selectedShop = ref<ShopEntity | null>(null);
|
||||||
const headerHeight = ref(150);
|
const headerHeight = ref(150);
|
||||||
let scrollListener: any[] = [];
|
let scrollListener: any[] = [];
|
||||||
|
|
||||||
|
@ -158,10 +181,16 @@ const onCabinetChange = (index: number) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showLockerDetail = (locker: LockerItem) => {
|
const showBindGoods = (locker: LockerItem) => {
|
||||||
// 实现详情弹窗逻辑
|
currentLocker.value = locker;
|
||||||
|
showBindGoodsPopup.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleBindSuccess = () => {
|
||||||
|
showBindGoodsPopup.value = false;
|
||||||
|
loadCabinetDetail();
|
||||||
|
};
|
||||||
|
|
||||||
const handleOpenLocker = async (locker: LockerItem) => {
|
const handleOpenLocker = async (locker: LockerItem) => {
|
||||||
openingLockerId.value = locker.lockerId
|
openingLockerId.value = locker.lockerId
|
||||||
try {
|
try {
|
||||||
|
@ -204,7 +233,11 @@ const getShopList = async () => {
|
||||||
|
|
||||||
// 选择商店
|
// 选择商店
|
||||||
const handleShopSelect = (selectedShopId: number) => {
|
const handleShopSelect = (selectedShopId: number) => {
|
||||||
shopId.value = selectedShopId;
|
const shop = shopList.value.find(s => s.shopId === selectedShopId);
|
||||||
|
if (shop) {
|
||||||
|
selectedShop.value = shop;
|
||||||
|
shopId.value = selectedShopId;
|
||||||
|
}
|
||||||
showShopList.value = false;
|
showShopList.value = false;
|
||||||
loadCabinetDetail(selectedShopId);
|
loadCabinetDetail(selectedShopId);
|
||||||
};
|
};
|
||||||
|
@ -222,6 +255,14 @@ const throttledScroll = throttle(() => {
|
||||||
headerHeight.value = Math.max(150 - scrollTop * 0.5, 60);
|
headerHeight.value = Math.max(150 - scrollTop * 0.5, 60);
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleStockUpdate = (newStock: number) => {
|
||||||
|
if (currentLocker.value) {
|
||||||
|
currentLocker.value.stock = newStock;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init();
|
init();
|
||||||
scrollListener.push(window.addEventListener('scroll', throttledScroll));
|
scrollListener.push(window.addEventListener('scroll', throttledScroll));
|
||||||
|
@ -257,6 +298,10 @@ onBeforeUnmount(() => {
|
||||||
height: calc(100vh - var(--van-tabbar-height));
|
height: calc(100vh - var(--van-tabbar-height));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.left-container {
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
/* 机柜选择相关样式 */
|
/* 机柜选择相关样式 */
|
||||||
.shop {
|
.shop {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -333,7 +378,7 @@ onBeforeUnmount(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.cabinet-sidebar {
|
.cabinet-sidebar {
|
||||||
width: 120px;
|
width: 90px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
@ -494,4 +539,14 @@ onBeforeUnmount(() => {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.adjust-btn {
|
||||||
|
background-color: #4e80ee;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unbind-btn {
|
||||||
|
color: #999;
|
||||||
|
border-color: #999;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
|
@ -25,10 +25,10 @@ export function registerNavigationGuard(router: Router) {
|
||||||
if (corpid) {
|
if (corpid) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* const isAdmin = urlParams.get('isAdmin') || undefined;
|
const isAdmin = urlParams.get('isAdmin') || undefined;
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
return true;
|
return true;
|
||||||
} */
|
}
|
||||||
|
|
||||||
// useAb98UserStore位置不能放在外面,否则会导致路由守卫无法正常工作
|
// useAb98UserStore位置不能放在外面,否则会导致路由守卫无法正常工作
|
||||||
const ab98UserStore = useAb98UserStore();
|
const ab98UserStore = useAb98UserStore();
|
||||||
|
|
|
@ -17,6 +17,7 @@ declare module 'vue' {
|
||||||
VanCol: typeof import('vant/es')['Col']
|
VanCol: typeof import('vant/es')['Col']
|
||||||
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||||
VanDivider: typeof import('vant/es')['Divider']
|
VanDivider: typeof import('vant/es')['Divider']
|
||||||
|
VanEmpty: typeof import('vant/es')['Empty']
|
||||||
VanField: typeof import('vant/es')['Field']
|
VanField: typeof import('vant/es')['Field']
|
||||||
VanForm: typeof import('vant/es')['Form']
|
VanForm: typeof import('vant/es')['Form']
|
||||||
VanGrid: typeof import('vant/es')['Grid']
|
VanGrid: typeof import('vant/es')['Grid']
|
||||||
|
@ -32,6 +33,7 @@ declare module 'vue' {
|
||||||
VanSearch: typeof import('vant/es')['Search']
|
VanSearch: typeof import('vant/es')['Search']
|
||||||
VanSidebar: typeof import('vant/es')['Sidebar']
|
VanSidebar: typeof import('vant/es')['Sidebar']
|
||||||
VanSidebarItem: typeof import('vant/es')['SidebarItem']
|
VanSidebarItem: typeof import('vant/es')['SidebarItem']
|
||||||
|
VanStepper: typeof import('vant/es')['Stepper']
|
||||||
VanTabbar: typeof import('vant/es')['Tabbar']
|
VanTabbar: typeof import('vant/es')['Tabbar']
|
||||||
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
VanTabbarItem: typeof import('vant/es')['TabbarItem']
|
||||||
VanTag: typeof import('vant/es')['Tag']
|
VanTag: typeof import('vant/es')['Tag']
|
||||||
|
|
Loading…
Reference in New Issue