From cdc59df3db5507dc9f0a384c9ca541b11b3aad2f Mon Sep 17 00:00:00 2001 From: dzq Date: Sat, 29 Nov 2025 11:29:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=AE=A2=E5=8D=95):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=80=9F=E8=BF=98=E5=8A=A8=E6=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增订单API模块,包含借还动态查询接口和类型定义 - 在商品详情页添加借还动态标签页,展示相关记录 - 实现分页加载和图片预览功能 - 更新环境配置,注释掉不再使用的API地址 - 移除过期的文档链接 - 修复商品详情页高度问题,适配动态列表展示 --- CLAUDE.md | 2 - env/.env | 2 +- env/.env.development | 2 +- env/.env.production | 4 +- src/api/index.ts | 4 + src/api/order/index.ts | 75 +++ src/pages/index/components/detail.vue | 479 +++++++++++++++--- .../index/components/product-container.vue | 21 +- 8 files changed, 509 insertions(+), 80 deletions(-) create mode 100644 src/api/order/index.ts diff --git a/CLAUDE.md b/CLAUDE.md index 22bdabf..621c8c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -132,8 +132,6 @@ http.post('/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 diff --git a/env/.env b/env/.env index 2698e4b..393be2c 100644 --- a/env/.env +++ b/env/.env @@ -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' diff --git a/env/.env.development b/env/.env.development index 70cdde6..a3b30af 100644 --- a/env/.env.development +++ b/env/.env.development @@ -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/' diff --git a/env/.env.production b/env/.env.production index 6135d8d..1b7b694 100644 --- a/env/.env.production +++ b/env/.env.production @@ -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' diff --git a/src/api/index.ts b/src/api/index.ts index c4e4065..b72c963 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -22,6 +22,10 @@ export interface PageResult { count: number; } +export interface PageDTO { + total: number; + rows: Array; +}; /** * 分页查询基本参数 */ diff --git a/src/api/order/index.ts b/src/api/order/index.ts new file mode 100644 index 0000000..376b202 --- /dev/null +++ b/src/api/order/index.ts @@ -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>("order/borrow-return-dynamic", query); +} \ No newline at end of file diff --git a/src/pages/index/components/detail.vue b/src/pages/index/components/detail.vue index 76b425a..baf450f 100644 --- a/src/pages/index/components/detail.vue +++ b/src/pages/index/components/detail.vue @@ -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(false) const quantity = ref(1) +// 标签页控制 +const activeTab = ref(0) + +// 借还动态数据 +const dynamicList = ref([]); +const total = ref(-1); +const loading = ref(false) +// 分页参数 +const pageNum = ref(1) +const pageSize = ref(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 })