feat(机柜页面): 增加商店选择功能并优化机柜展示
- 在机柜页面添加商店列表选择功能,用户需先选择商店才能查看对应机柜 - 修改getCabinetDetailApi和getShopListApi接口,支持传入shopId和mode参数 - 添加返回商店列表按钮,优化页面交互流程 - 实现滚动时头部高度动态调整效果 - 新增相关样式和状态管理逻辑
This commit is contained in:
parent
87574aebf6
commit
2132e0e1e5
|
@ -3,10 +3,13 @@ import type { CabinetDetailResponse } from './type'
|
|||
import { OpenCabinetApiData } from '../shop/type'
|
||||
|
||||
/** 获取智能柜详情接口 */
|
||||
export function getCabinetDetailApi() {
|
||||
export function getCabinetDetailApi(shopId: number) {
|
||||
return request<CabinetDetailResponse>({
|
||||
url: 'cabinet/detail',
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params: {
|
||||
shopId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -74,10 +74,16 @@ export function getBalanceByQyUserid(corpid: string, userid: string) {
|
|||
})
|
||||
}
|
||||
|
||||
export function getShopListApi(corpid: string) {
|
||||
export function getShopListApi(corpid: string, mode?: number) {
|
||||
const params: any = {
|
||||
corpid
|
||||
};
|
||||
if (typeof mode !== 'undefined') {
|
||||
params.mode = mode;
|
||||
}
|
||||
return request<ApiResponseData<ShopEntity[]>>({
|
||||
url: "shop/list",
|
||||
method: "get",
|
||||
params: { corpid }
|
||||
params
|
||||
})
|
||||
}
|
|
@ -1,16 +1,36 @@
|
|||
<template>
|
||||
<div class="cabinet-container van-safe-area-bottom">
|
||||
<div v-if="showShopList" class="shop-list">
|
||||
<div class="shop-prompt">
|
||||
<van-cell title="请选择机柜地址:" center />
|
||||
</div>
|
||||
<van-row :gutter="[10, 10]" class="shop-row" justify="start">
|
||||
<van-col v-for="shop in shopList" :key="shop.shopId" span="12" class="shop-col">
|
||||
<div class="shop-item" @click="handleShopSelect(shop.shopId)">
|
||||
<div class="shop-info">
|
||||
<van-icon name="shop-o" size="20" class="shop-icon" />
|
||||
<div class="shop-name van-ellipsis">{{ shop.shopName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-col>
|
||||
<van-col v-if="shopList.length % 2 === 0" span="12" class="shop-col"></van-col>
|
||||
</van-row>
|
||||
</div>
|
||||
<div v-else class="cabinet-container van-safe-area-bottom">
|
||||
<div>
|
||||
<van-button icon="revoke" type="default" class="showShopListBtn" @click="handleBackToShopList">重选地址</van-button>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="product-list">
|
||||
<van-cell v-for="locker in lockerList" :key="locker.lockerId" class="product-item">
|
||||
<template #icon>
|
||||
<div class="image-container">
|
||||
<van-image width="80" height="80"
|
||||
:src="locker.coverImg ? locker.coverImg : `${publicPath}` + 'img/product-image.svg'" fit="cover"
|
||||
radius="4" class="product-image" :style="{ filter: locker.stock === 0 ? 'grayscale(100%)' : 'none' }">
|
||||
:src="locker.coverImg ? locker.coverImg : `${publicPath}` + 'img/product-image.svg'"
|
||||
fit="cover" radius="4" class="product-image"
|
||||
:style="{ filter: locker.stock === 0 ? 'grayscale(100%)' : 'none' }">
|
||||
</van-image>
|
||||
<div v-if="locker.stock >= 0" class="stock-overlay">
|
||||
库存: {{ locker.stock }}
|
||||
|
@ -50,11 +70,14 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { getCabinetDetailApi, openCabinet } from '@/common/apis/cabinet'
|
||||
import type { CabinetDetailDTO } from '@/common/apis/cabinet/type'
|
||||
import { useWxStore, useWxStoreOutside } from '@/pinia/stores/wx'
|
||||
import { publicPath } from "@/common/utils/path"
|
||||
import { throttle } from 'lodash-es';
|
||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
|
||||
import { getShopListApi } from '@/common/apis/shop';
|
||||
import { ShopEntity } from '@/common/apis/shop/type';
|
||||
import { getCabinetDetailApi, openCabinet } from '@/common/apis/cabinet';
|
||||
import type { CabinetDetailDTO } from '@/common/apis/cabinet/type';
|
||||
import { useWxStore, useWxStoreOutside } from '@/pinia/stores/wx';
|
||||
import { publicPath } from "@/common/utils/path";
|
||||
|
||||
const wxStore = useWxStore();
|
||||
const { userid: qyUserid, name: qyName } = storeToRefs(wxStore);
|
||||
|
@ -64,6 +87,13 @@ const cabinetList = ref<CabinetItem[]>([])
|
|||
const lockerList = ref<LockerItem[]>([])
|
||||
const openingLockerId = ref<number | null>(null)
|
||||
const cabinetData = ref<CabinetDetailDTO[]>([]);
|
||||
const scrollContainer = ref<HTMLElement>();
|
||||
// 机柜地址选择相关状态
|
||||
const showShopList = ref(true);
|
||||
const shopList = ref<ShopEntity[]>([]);
|
||||
const shopId = ref<number>(0);
|
||||
const headerHeight = ref(150);
|
||||
let scrollListener: any[] = [];
|
||||
|
||||
interface CabinetItem {
|
||||
cabinetId: number
|
||||
|
@ -83,10 +113,12 @@ interface LockerItem {
|
|||
coverImg?: string
|
||||
}
|
||||
|
||||
// 获取柜机列表
|
||||
const loadCabinetDetail = async () => {
|
||||
// 获取机柜列表
|
||||
const loadCabinetDetail = async (selectedShopId?: number) => {
|
||||
const targetShopId = selectedShopId || shopId.value;
|
||||
if (!targetShopId) return;
|
||||
try {
|
||||
const { data } = await getCabinetDetailApi();
|
||||
const { data } = await getCabinetDetailApi(targetShopId);
|
||||
cabinetData.value = data;
|
||||
cabinetList.value = data.map(cabinet => ({
|
||||
cabinetId: cabinet.cabinetId,
|
||||
|
@ -149,7 +181,56 @@ const handleOpenLocker = async (locker: LockerItem) => {
|
|||
}
|
||||
}
|
||||
|
||||
loadCabinetDetail()
|
||||
// 初始化方法
|
||||
const init = async () => {
|
||||
if (showShopList.value) {
|
||||
await getShopList();
|
||||
} else if (shopId.value) {
|
||||
await loadCabinetDetail();
|
||||
}
|
||||
};
|
||||
|
||||
// 获取商店列表
|
||||
const getShopList = async () => {
|
||||
try {
|
||||
const res = await getShopListApi(wxStore.corpid, -1);
|
||||
if (res?.code === 0 && res?.data?.length > 0) {
|
||||
shopList.value = res.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取商店列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 选择商店
|
||||
const handleShopSelect = (selectedShopId: number) => {
|
||||
shopId.value = selectedShopId;
|
||||
showShopList.value = false;
|
||||
loadCabinetDetail(selectedShopId);
|
||||
};
|
||||
|
||||
// 返回商店列表
|
||||
const handleBackToShopList = () => {
|
||||
showShopList.value = true;
|
||||
shopId.value = 0;
|
||||
};
|
||||
|
||||
// 监听滚动事件调整头部高度
|
||||
const throttledScroll = throttle(() => {
|
||||
if (!scrollContainer.value) return;
|
||||
const scrollTop = scrollContainer.value.scrollTop;
|
||||
headerHeight.value = Math.max(150 - scrollTop * 0.5, 60);
|
||||
}, 100);
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
scrollListener.push(window.addEventListener('scroll', throttledScroll));
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
scrollListener.forEach(listener => window.removeEventListener('scroll', listener));
|
||||
scrollListener = [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -176,6 +257,81 @@ loadCabinetDetail()
|
|||
height: calc(100vh - var(--van-tabbar-height));
|
||||
}
|
||||
|
||||
/* 机柜选择相关样式 */
|
||||
.shop {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.shop-header {
|
||||
overflow: hidden;
|
||||
transition: height 0.3s ease;
|
||||
}
|
||||
|
||||
.shop-cover {
|
||||
width: 100%;
|
||||
transform: translateY(calc((150px - var(--header-height)) / 2));
|
||||
scale: calc(1 + (150 - var(--header-height)) / 150);
|
||||
}
|
||||
|
||||
.shop-list {
|
||||
.shop-prompt {
|
||||
margin: 8px;
|
||||
height: 44px !important;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.shop-row {
|
||||
margin: 8px 0;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.shop-col {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.shop-item {
|
||||
height: 60px !important;
|
||||
padding: 12px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
transition: transform 0.2s;
|
||||
|
||||
.shop-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.shop-name {
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin: 2px 0 4px 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.showShopListBtn {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.cabinet-sidebar {
|
||||
width: 120px;
|
||||
height: 100%;
|
||||
|
|
Loading…
Reference in New Issue