feat(订单): 添加借还动态功能
- 新增订单API模块,包含借还动态查询接口和类型定义 - 在商品详情页添加借还动态标签页,展示相关记录 - 实现分页加载和图片预览功能 - 更新环境配置,注释掉不再使用的API地址 - 移除过期的文档链接 - 修复商品详情页高度问题,适配动态列表展示
This commit is contained in:
parent
db6f31228d
commit
cdc59df3db
|
|
@ -132,8 +132,6 @@ http.post<T>('/api/users', data)
|
|||
## Documentation
|
||||
|
||||
- **Standards**: `/doc/代码编写规范.md`
|
||||
- **Cleanup**: `/doc/项目清理计划.md`
|
||||
- **Migration**: `/doc/迁移指令.md`
|
||||
- **wot-design-uni**: UI component library documentation located in `/doc/wot-design-uni/docs/`
|
||||
- View `index.md` for main documentation
|
||||
- Browse `guide/` for usage guides
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ VITE_APP_PROXY_ENABLE = true
|
|||
VITE_APP_PROXY_PREFIX = '/api/'
|
||||
|
||||
# 第二个请求地址 (目前alova中可以使用)
|
||||
VITE_API_SECONDARY_URL = 'https://wxshop.ab98.cn/shop-api/api/'
|
||||
# VITE_API_SECONDARY_URL = 'https://wxshop.ab98.cn/shop-api/api/'
|
||||
|
||||
# 认证模式,'single' | 'double' ==> 单token | 双token
|
||||
VITE_AUTH_MODE = 'single'
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ VITE_SHOW_SOURCEMAP = false
|
|||
#VITE_HUIBANG_BASEURL = 'https://www.ab98.cn'
|
||||
|
||||
# VITE_SERVER_BASEURL = 'http://localhost:8090/api/'
|
||||
VITE_SERVER_BASEURL = 'https://wxshop.ab98.cn/shop-api/api/'
|
||||
# VITE_SERVER_BASEURL = 'https://wxshop.ab98.cn/shop-api/api/'
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ VITE_DELETE_CONSOLE = false
|
|||
VITE_SHOW_SOURCEMAP = false
|
||||
|
||||
# 后台请求地址
|
||||
VITE_SERVER_BASEURL = 'https://wxshop.ab98.cn/shop-api/api/'
|
||||
VITE_HUIBANG_BASEURL = 'https://www.ab98.cn'
|
||||
# VITE_SERVER_BASEURL = 'https://wxshop.ab98.cn/shop-api/api/'
|
||||
VITE_HUIBANG_BASEURL = 'https://www.ab98.cn'
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ export interface PageResult<T> {
|
|||
count: number;
|
||||
}
|
||||
|
||||
export interface PageDTO<T> {
|
||||
total: number;
|
||||
rows: Array<T>;
|
||||
};
|
||||
/**
|
||||
* 分页查询基本参数
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
import { http } from "@/http/http";
|
||||
import { PageDTO } from "..";
|
||||
|
||||
/** 借还动态查询参数 */
|
||||
export interface SearchBorrowReturnDynamicQuery {
|
||||
/** 商品ID,精确筛选 */
|
||||
goodsId?: number;
|
||||
/** 格口ID,精确筛选 */
|
||||
cellId?: number;
|
||||
/** 状态筛选(仅对归还记录有效) */
|
||||
status?: number;
|
||||
/** 动态类型筛选 */
|
||||
dynamicType?: number;
|
||||
/** 页码(默认1) */
|
||||
pageNum?: number;
|
||||
/** 每页大小(默认10) */
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
/** 借还动态响应数据 */
|
||||
export interface BorrowReturnDynamicDTO {
|
||||
/** 订单商品ID */
|
||||
orderGoodsId: number;
|
||||
/** 动态类型(0-借出 1-归还) */
|
||||
dynamicType: number;
|
||||
/** 动态类型描述 */
|
||||
dynamicTypeStr: string;
|
||||
/** 订单ID */
|
||||
orderId: number;
|
||||
/** 订单创建时间/借出时间 */
|
||||
orderTime: string;
|
||||
/** 商品ID */
|
||||
goodsId: number;
|
||||
/** 商品名称 */
|
||||
goodsName: string;
|
||||
/** 商品单价 */
|
||||
goodsPrice: number;
|
||||
/** 数量 */
|
||||
quantity: number;
|
||||
/** 支付方式 */
|
||||
paymentMethod: string;
|
||||
/** 订单姓名 */
|
||||
orderName: string;
|
||||
/** 订单手机号 */
|
||||
orderMobile: string;
|
||||
/** 格口ID */
|
||||
cellId: number;
|
||||
/** 格口号 */
|
||||
cellNo: number;
|
||||
/** 柜机ID */
|
||||
cabinetId: number;
|
||||
/** 柜机名称 */
|
||||
cabinetName: string;
|
||||
/** 归还/审批时间(归还记录时有效) */
|
||||
operateTime?: string;
|
||||
/** 审批ID(归还记录时有效) */
|
||||
approvalId?: number;
|
||||
/** 审批状态(归还记录时有效) */
|
||||
status: number;
|
||||
/** 状态描述 */
|
||||
statusStr: string;
|
||||
/** 审批人(归还记录时有效) */
|
||||
auditName?: string;
|
||||
/** 审核说明(归还记录时有效) */
|
||||
auditRemark?: string;
|
||||
/** 归还图片(归还记录时有效) */
|
||||
images?: string;
|
||||
/** 审核图片(归还记录时有效) */
|
||||
auditImages?: string;
|
||||
}
|
||||
|
||||
/** 获取借还动态分页列表 */
|
||||
export async function getBorrowReturnDynamicApi(query: SearchBorrowReturnDynamicQuery) {
|
||||
return await http.get<PageDTO<BorrowReturnDynamicDTO>>("order/borrow-return-dynamic", query);
|
||||
}
|
||||
|
|
@ -3,6 +3,9 @@ import { ref, computed, watch } from 'vue'
|
|||
import type { Product } from '@/pinia/stores/product'
|
||||
import { useCartStore } from '@/pinia/stores/cart'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { toHttpsUrl } from '@/utils'
|
||||
// import { onLoad, onReachBottom, onShow } from '@dcloudio/uni-app'
|
||||
import { getBorrowReturnDynamicApi, type BorrowReturnDynamicDTO, type SearchBorrowReturnDynamicQuery } from '@/api/order'
|
||||
|
||||
// 定义组件接收的属性
|
||||
const props = defineProps<{
|
||||
|
|
@ -22,6 +25,30 @@ const { cartItems } = storeToRefs(cartStore)
|
|||
const showAddCart = ref<boolean>(false)
|
||||
const quantity = ref<number>(1)
|
||||
|
||||
// 标签页控制
|
||||
const activeTab = ref<number>(0)
|
||||
|
||||
// 借还动态数据
|
||||
const dynamicList = ref<BorrowReturnDynamicDTO[]>([]);
|
||||
const total = ref<number>(-1);
|
||||
const loading = ref<boolean>(false)
|
||||
// 分页参数
|
||||
const pageNum = ref<number>(1)
|
||||
const pageSize = ref<number>(20)
|
||||
// loadmore 状态
|
||||
const loadmoreState = ref<'loading' | 'finished' | 'error'>('loading')
|
||||
|
||||
// scroll-view 高度计算
|
||||
const scrollHeight = computed(() => {
|
||||
// 计算可用高度:屏幕高度 - 顶部操作栏 - 底部操作栏 - 标签栏
|
||||
const windowHeight = uni.getSystemInfoSync().windowHeight
|
||||
const headerHeight = 60 // 顶部操作栏高度
|
||||
const actionBarHeight = 64 // 底部操作栏高度
|
||||
const tabHeight = 44 // 标签栏高度
|
||||
console.log('scrollHeight', windowHeight, headerHeight, actionBarHeight, tabHeight)
|
||||
return `${windowHeight - headerHeight - actionBarHeight - tabHeight}px`
|
||||
})
|
||||
|
||||
const maxQuantity = computed(() => {
|
||||
const existingItem = cartItems.value.find(item => item.product.id === props.product.id)
|
||||
if (existingItem) {
|
||||
|
|
@ -74,11 +101,96 @@ function doShowAddCart(): boolean {
|
|||
return true
|
||||
}
|
||||
|
||||
// 获取借还动态数据(带分页)
|
||||
async function loadDynamicList(page: number = 1) {
|
||||
console.log('loadDynamicList', page)
|
||||
console.log('props.product', props.product)
|
||||
if (!props.product?.id) return
|
||||
|
||||
loading.value = true
|
||||
loadmoreState.value = 'loading'
|
||||
try {
|
||||
const query: SearchBorrowReturnDynamicQuery = {
|
||||
goodsId: props.product.id,
|
||||
cellId: props.product.cellId,
|
||||
pageNum: page,
|
||||
pageSize: pageSize.value
|
||||
}
|
||||
|
||||
const response = await getBorrowReturnDynamicApi(query)
|
||||
console.log('response', response)
|
||||
|
||||
if (response?.data?.rows) {
|
||||
if (page === 1) {
|
||||
// 首次加载,替换数据
|
||||
dynamicList.value = response.data.rows
|
||||
} else {
|
||||
// 追加数据
|
||||
dynamicList.value = [...dynamicList.value, ...response.data.rows]
|
||||
}
|
||||
total.value = response.data.total
|
||||
pageNum.value = page
|
||||
|
||||
// 判断是否已加载全部
|
||||
console.log('dynamicList.value.length', dynamicList.value.length, 'total.value', total.value)
|
||||
if (dynamicList.value.length >= total.value) {
|
||||
loadmoreState.value = 'finished'
|
||||
} else {
|
||||
loadmoreState.value = 'loading'
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取借还动态失败:', error)
|
||||
loadmoreState.value = 'error'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多数据
|
||||
function loadMoreData() {
|
||||
console.log('loadMoreData', pageNum.value, loadmoreState.value, loading.value, dynamicList.value.length, total.value)
|
||||
if (loadmoreState.value === 'finished' || loading.value) return
|
||||
if (dynamicList.value.length >= total.value) {
|
||||
loadmoreState.value = 'finished'
|
||||
return
|
||||
}
|
||||
loadDynamicList(pageNum.value + 1)
|
||||
}
|
||||
|
||||
// scroll-view 滚动到底部事件处理
|
||||
function handleScrollToLower() {
|
||||
console.log('handleScrollToLower', pageNum.value, loadmoreState.value, loading.value, dynamicList.value.length, total.value)
|
||||
loadMoreData()
|
||||
}
|
||||
|
||||
// 监听标签页切换,加载借还动态
|
||||
watch(activeTab, (newVal) => {
|
||||
if (newVal === 1 && dynamicList.value.length === 0) {
|
||||
pageNum.value = 1
|
||||
loadDynamicList(1)
|
||||
}
|
||||
})
|
||||
|
||||
const refreshDynamicList = () => {
|
||||
dynamicList.value = [];
|
||||
pageNum.value = 1;
|
||||
loadDynamicList(1);
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
refreshDynamicList();
|
||||
})
|
||||
|
||||
|
||||
|
||||
watch(() => props.product, () => {
|
||||
// 重置参数
|
||||
quantity.value = 1
|
||||
showAddCart.value = false
|
||||
}, { deep: true })
|
||||
activeTab.value = 0;
|
||||
quantity.value = 1;
|
||||
showAddCart.value = false;
|
||||
refreshDynamicList();
|
||||
}, { deep: true, immediate: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -92,85 +204,152 @@ watch(() => props.product, () => {
|
|||
</view>
|
||||
|
||||
<!-- 商品内容区域(可滚动) -->
|
||||
<scroll-view class="content-area" scroll-y>
|
||||
<!-- 商品主图 -->
|
||||
<view class="product-image-wrapper">
|
||||
<wd-img
|
||||
v-if="product"
|
||||
:src="product.image"
|
||||
width="100%"
|
||||
height="275"
|
||||
>
|
||||
<view v-if="product.stock === 0" class="sold-out-overlay">
|
||||
<text class="sold-out-text">已售罄</text>
|
||||
</view>
|
||||
<template #error>
|
||||
<view class="custom-error">
|
||||
图片加载失败
|
||||
<view class="content-area">
|
||||
<!-- 标签页内容 -->
|
||||
<view class="tab-content">
|
||||
<wd-tabs v-model="activeTab">
|
||||
<!-- 标签1:商品信息 -->
|
||||
<wd-tab title="商品信息">
|
||||
<!-- 商品主图 -->
|
||||
<view class="product-image-wrapper">
|
||||
<wd-img v-if="product" :src="toHttpsUrl(product.image)" width="100%" height="275">
|
||||
<view v-if="product.stock === 0" class="sold-out-overlay">
|
||||
<text class="sold-out-text">已售罄</text>
|
||||
</view>
|
||||
<template #error>
|
||||
<view class="custom-error">
|
||||
图片加载失败
|
||||
</view>
|
||||
</template>
|
||||
</wd-img>
|
||||
</view>
|
||||
</template>
|
||||
</wd-img>
|
||||
<!-- 分隔线 -->
|
||||
<view class="divider"></view>
|
||||
<!-- 商品信息 -->
|
||||
<view class="product-info">
|
||||
<view class="product-name">
|
||||
{{ product.name }}
|
||||
</view>
|
||||
<view class="price-row">
|
||||
<text class="product-price">¥{{ product.price.toFixed(2) }}</text>
|
||||
<text v-if="product.stock > 0" class="stock-count">
|
||||
剩余{{ product.stock }}件
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="description">
|
||||
{{ product.description }}
|
||||
</view>
|
||||
</wd-tab>
|
||||
|
||||
<!-- 标签2:借还动态 -->
|
||||
<wd-tab title="借还动态">
|
||||
<!-- 动态列表 -->
|
||||
<scroll-view class="dynamic-list-scroll" scroll-y :style="{ height: scrollHeight }"
|
||||
@scrolltolower="handleScrollToLower" :lower-threshold="100">
|
||||
<view class="dynamic-list">
|
||||
<view v-for="item in dynamicList" :key="String(item.orderGoodsId) + item.dynamicType"
|
||||
class="dynamic-item">
|
||||
<view class="dynamic-header">
|
||||
<view class="dynamic-type"
|
||||
:class="{ borrow: item.dynamicType === 0, return: item.dynamicType === 1 }">
|
||||
{{ item.dynamicTypeStr }}
|
||||
</view>
|
||||
<!-- 归还记录显示额外信息 -->
|
||||
<view v-if="item.dynamicType === 1" class="info-row">
|
||||
<text class="info-value" :class="item.status === 2 ? 'success' : 'warning'">{{ item.statusStr
|
||||
}}</text>
|
||||
</view>
|
||||
<text class="dynamic-time">{{ item.orderTime }}</text>
|
||||
</view>
|
||||
<view class="dynamic-body">
|
||||
<view class="info-row">
|
||||
<text class="info-label">借用人:</text>
|
||||
<text class="info-value">{{ item.orderName }}</text>
|
||||
<text v-if="item.dynamicType === 1 && item.auditName" class="info-label audit-name">审批人:</text>
|
||||
<text v-if="item.dynamicType === 1 && item.auditName" class="info-value">{{ item.auditName
|
||||
}}</text>
|
||||
</view>
|
||||
<view v-if="item.dynamicType === 1 && item.auditRemark && item.auditRemark != '自动审批'"
|
||||
class="info-row">
|
||||
<text class="info-label">审核说明:</text>
|
||||
<text class="info-value">{{ item.auditRemark }}</text>
|
||||
</view>
|
||||
<!-- 归还图片 -->
|
||||
<view v-if="item.dynamicType === 1 && item.images" class="image-section">
|
||||
<view class="info-label">归还图片:</view>
|
||||
<view class="image-list">
|
||||
<view v-for="(image, index) in item.images.split(',')" :key="index" class="image-item">
|
||||
<wd-img :src="toHttpsUrl(image.trim())" width="80" height="80" mode="aspectFill"
|
||||
:enable-preview="true">
|
||||
<template #error>
|
||||
<view class="image-error">图片加载失败</view>
|
||||
</template>
|
||||
</wd-img>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 审核图片 -->
|
||||
<view v-if="item.dynamicType === 1 && item.auditImages" class="image-section">
|
||||
<view class="info-label">审核图片:</view>
|
||||
<view class="image-list">
|
||||
<view v-for="(image, index) in item.auditImages.split(',')" :key="index" class="image-item">
|
||||
<wd-img :src="toHttpsUrl(image.trim())" width="80" height="80" mode="aspectFill"
|
||||
:enable-preview="true">
|
||||
<template #error>
|
||||
<view class="image-error">图片加载失败</view>
|
||||
</template>
|
||||
</wd-img>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多状态 -->
|
||||
<view v-if="dynamicList.length > 0" class="loadmore-status">
|
||||
<view v-if="loadmoreState === 'loading'" class="loading-text">
|
||||
<wd-loading size="16px" color="#969799"></wd-loading>
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
<view v-else-if="loadmoreState === 'finished'" class="finished-text">
|
||||
<text>没有更多数据了</text>
|
||||
</view>
|
||||
<view v-else-if="loadmoreState === 'error'" class="error-text" @click="loadMoreData">
|
||||
<text>加载失败,点击重试</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</wd-tab>
|
||||
</wd-tabs>
|
||||
</view>
|
||||
|
||||
<!-- 商品信息 -->
|
||||
<view class="product-info">
|
||||
<view class="product-name">
|
||||
{{ product.name }}
|
||||
</view>
|
||||
<view class="price-row">
|
||||
<text class="product-price">¥{{ product.price.toFixed(2) }}</text>
|
||||
<text v-if="product.stock > 0" class="stock-count">
|
||||
剩余{{ product.stock }}件
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<view class="divider"></view>
|
||||
|
||||
<!-- 商品详细描述 -->
|
||||
<view v-if="!showAddCart" class="description">
|
||||
{{ product.description }}
|
||||
</view>
|
||||
<!-- 购买数量选择 -->
|
||||
<view v-if="showAddCart" class="action-row">
|
||||
<view class="product-name">
|
||||
购买数量
|
||||
</view>
|
||||
<view class="cart-actions">
|
||||
<view
|
||||
class="cart-btn-minus"
|
||||
:class="{ disabled: quantity === 1 }"
|
||||
@click.stop="handleRemoveFromCart()"
|
||||
>
|
||||
<view class="cart-btn-minus" :class="{ disabled: quantity === 1 }" @click.stop="handleRemoveFromCart()">
|
||||
<wd-icon name="decrease" size="12px" :color="quantity === 1 ? '#fff' : '#F56C6C'"></wd-icon>
|
||||
</view>
|
||||
<text class="cart-count">{{ quantity }}</text>
|
||||
<view
|
||||
class="cart-btn-plus"
|
||||
:class="{ disabled: maxQuantity }"
|
||||
@click.stop="handleAddToCart()"
|
||||
>
|
||||
<view class="cart-btn-plus" :class="{ disabled: maxQuantity }" @click.stop="handleAddToCart()">
|
||||
<wd-icon name="add" size="12px" color="#fff"></wd-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作按钮栏 -->
|
||||
<view class="action-bar">
|
||||
<view
|
||||
v-if="!showAddCart"
|
||||
class="add-cart-btn"
|
||||
:class="{ disabled: product?.stock === 0 }"
|
||||
@click="doShowAddCart()"
|
||||
>
|
||||
<view v-if="activeTab === 0" class="action-bar">
|
||||
<view v-if="!showAddCart" class="add-cart-btn" :class="{ disabled: product?.stock === 0 }"
|
||||
@click="doShowAddCart()">
|
||||
{{ product?.stock === 0 ? '已售罄' : '加入购物车' }}
|
||||
</view>
|
||||
<view
|
||||
v-if="showAddCart"
|
||||
class="add-cart-btn confirm"
|
||||
@click="confirmAddCart()"
|
||||
>
|
||||
<view v-if="showAddCart" class="add-cart-btn confirm" @click="confirmAddCart()">
|
||||
确认
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -181,7 +360,7 @@ watch(() => props.product, () => {
|
|||
.detail-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 80vh;
|
||||
height: 100%;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
|
||||
|
|
@ -369,4 +548,176 @@ watch(() => props.product, () => {
|
|||
background-color: #07c160;
|
||||
}
|
||||
}
|
||||
|
||||
// 标签页内容样式
|
||||
.tab-content {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.dynamic-content {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.loading-state,
|
||||
.empty-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 16px;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
// scroll-view 样式
|
||||
.dynamic-list-scroll {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dynamic-list {
|
||||
min-height: 600rpx;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
// 加载更多状态样式
|
||||
.loadmore-status {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 16px 0;
|
||||
|
||||
.loading-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.finished-text {
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: #F56C6C;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dynamic-item {
|
||||
margin-bottom: 12px;
|
||||
padding: 12px;
|
||||
background: #f7f8fa;
|
||||
border-radius: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dynamic-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.dynamic-type {
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.borrow {
|
||||
background: #EBF5FF;
|
||||
color: #1989FA;
|
||||
}
|
||||
|
||||
&.return {
|
||||
background: #F0F9EB;
|
||||
color: #52C41A;
|
||||
}
|
||||
}
|
||||
|
||||
.dynamic-time {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
}
|
||||
|
||||
.dynamic-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #646566;
|
||||
margin-right: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #323233;
|
||||
|
||||
&.success {
|
||||
color: #52C41A;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
color: #FF976A;
|
||||
}
|
||||
}
|
||||
|
||||
.audit-name {
|
||||
margin-left: 50rpx;
|
||||
}
|
||||
|
||||
.image-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
margin-top: 8px;
|
||||
|
||||
.info-label {
|
||||
color: #646566;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.image-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.image-item {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-error {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f7f8fa;
|
||||
color: #969799;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -5,6 +5,7 @@ import { useCartStore } from '@/pinia/stores/cart'
|
|||
import { storeToRefs } from 'pinia'
|
||||
import Detail from './detail.vue'
|
||||
import Cart from './cart.vue'
|
||||
import { toHttpsUrl } from '@/utils'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
|
|
@ -30,10 +31,10 @@ const activeCategory = ref<number>(0)
|
|||
// 商品详情弹窗控制
|
||||
const showDetailPopup = ref<boolean>(false)
|
||||
// 当前查看的商品ID
|
||||
const currentProductId = ref<number>()
|
||||
const currentCellId = ref<number>()
|
||||
// 当前商品详情计算属性
|
||||
const currentProduct = computed(() =>
|
||||
categories.value.find(p => p.id === currentProductId.value)
|
||||
categories.value.find(p => p.cellId === currentCellId.value)
|
||||
)
|
||||
// 购物车弹窗控制
|
||||
const showCartPopup = ref<boolean>(false)
|
||||
|
|
@ -50,10 +51,10 @@ function handleCategoryClick(index: number) {
|
|||
|
||||
/**
|
||||
* 打开商品详情弹窗
|
||||
* @param productId - 要显示详情的商品ID
|
||||
* @param cellId - 要显示详情的格口ID
|
||||
*/
|
||||
function showProductDetail(productId: number) {
|
||||
currentProductId.value = productId
|
||||
function showProductDetail(cellId: number) {
|
||||
currentCellId.value = cellId
|
||||
showDetailPopup.value = true
|
||||
}
|
||||
|
||||
|
|
@ -136,9 +137,9 @@ function handleCheckout() {
|
|||
<view class="category-section">
|
||||
<view v-for="product in currentProducts" :key="product.cellId" class="product-item">
|
||||
<view class="product-content">
|
||||
<view class="product-image-wrapper" @click.stop="showProductDetail(product.id)">
|
||||
<view class="product-image-wrapper" @click.stop="showProductDetail(product.cellId)">
|
||||
<wd-img
|
||||
:src="product.image"
|
||||
:src="toHttpsUrl(product.image)"
|
||||
width="80"
|
||||
height="80"
|
||||
border-radius="4"
|
||||
|
|
@ -153,10 +154,10 @@ function handleCheckout() {
|
|||
</view>
|
||||
|
||||
<view class="product-info">
|
||||
<view class="product-name" @click.stop="showProductDetail(product.id)">
|
||||
<view class="product-name" @click.stop="showProductDetail(product.cellId)">
|
||||
{{ product.name }}
|
||||
</view>
|
||||
<view class="product-price" @click.stop="showProductDetail(product.id)">
|
||||
<view class="product-price" @click.stop="showProductDetail(product.cellId)">
|
||||
¥{{ product.price.toFixed(2) }}
|
||||
</view>
|
||||
<view class="action-row">
|
||||
|
|
@ -442,6 +443,6 @@ function handleCheckout() {
|
|||
}
|
||||
|
||||
.detail-container {
|
||||
height: 80vh;
|
||||
height: 92vh;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue