consumer模块完成度95%,完成部署消费者端(外网可访问consumer.meitizs.com),消费者小程序能正常运行在微信开发者工具上
This commit is contained in:
@@ -29,8 +29,8 @@ export const WS_URL: string = 'ws://119.146.131.237:9126/realtime/v1/websocket'
|
|||||||
// export const WS_URL: string = 'ws://192.168.1.64:3000/realtime/v1'
|
// export const WS_URL: string = 'ws://192.168.1.64:3000/realtime/v1'
|
||||||
|
|
||||||
// 路由配置
|
// 路由配置
|
||||||
export const HOME_REDIRECT: string = '/pages/mall/consumer/index'
|
export const HOME_REDIRECT: string = '/pages/main/index'
|
||||||
export const TABORPAGE: string = '/pages/mall/consumer/index'
|
export const TABORPAGE: string = '/pages/main/index'
|
||||||
|
|
||||||
// 测试模式:放开任意跳转(禁用启动页/登录/401 的强制重定向)
|
// 测试模式:放开任意跳转(禁用启动页/登录/401 的强制重定向)
|
||||||
export const IS_TEST_MODE: boolean = true
|
export const IS_TEST_MODE: boolean = true
|
||||||
20
pages.json
20
pages.json
@@ -69,7 +69,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/mall/consumer/index",
|
"path": "pages/main/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "首页",
|
"navigationBarTitleText": "首页",
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
@@ -77,14 +77,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/mall/consumer/category",
|
"path": "pages/main/category",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "分类",
|
"navigationBarTitleText": "分类",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/mall/consumer/messages",
|
"path": "pages/main/messages",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "消息",
|
"navigationBarTitleText": "消息",
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
@@ -92,14 +92,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/mall/consumer/cart",
|
"path": "pages/main/cart",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "购物车",
|
"navigationBarTitleText": "购物车",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/mall/consumer/profile",
|
"path": "pages/main/profile",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "我的",
|
"navigationBarTitleText": "我的",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
@@ -912,31 +912,31 @@
|
|||||||
"borderStyle": "black",
|
"borderStyle": "black",
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"pagePath": "pages/mall/consumer/index",
|
"pagePath": "pages/main/index",
|
||||||
"text": "首页",
|
"text": "首页",
|
||||||
"iconPath": "static/tabbar/home.png",
|
"iconPath": "static/tabbar/home.png",
|
||||||
"selectedIconPath": "static/tabbar/home.png"
|
"selectedIconPath": "static/tabbar/home.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/mall/consumer/category",
|
"pagePath": "pages/main/category",
|
||||||
"text": "分类",
|
"text": "分类",
|
||||||
"iconPath": "static/tabbar/category.png",
|
"iconPath": "static/tabbar/category.png",
|
||||||
"selectedIconPath": "static/tabbar/category.png"
|
"selectedIconPath": "static/tabbar/category.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/mall/consumer/messages",
|
"pagePath": "pages/main/messages",
|
||||||
"text": "消息",
|
"text": "消息",
|
||||||
"iconPath": "static/tabbar/message.png",
|
"iconPath": "static/tabbar/message.png",
|
||||||
"selectedIconPath": "static/tabbar/message.png"
|
"selectedIconPath": "static/tabbar/message.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/mall/consumer/cart",
|
"pagePath": "pages/main/cart",
|
||||||
"text": "购物车",
|
"text": "购物车",
|
||||||
"iconPath": "static/tabbar/cart.png",
|
"iconPath": "static/tabbar/cart.png",
|
||||||
"selectedIconPath": "static/tabbar/cart.png"
|
"selectedIconPath": "static/tabbar/cart.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/mall/consumer/profile",
|
"pagePath": "pages/main/profile",
|
||||||
"text": "我的",
|
"text": "我的",
|
||||||
"iconPath": "static/tabbar/user.png",
|
"iconPath": "static/tabbar/user.png",
|
||||||
"selectedIconPath": "static/tabbar/user.png"
|
"selectedIconPath": "static/tabbar/user.png"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- pages/mall/consumer/cart.uvue -->
|
<!-- pages/main/cart.uvue -->
|
||||||
<template>
|
<template>
|
||||||
<view class="cart-page">
|
<view class="cart-page">
|
||||||
<!-- 智能顶部导航栏 - 与消息页保持一致 -->
|
<!-- 智能顶部导航栏 - 与消息页保持一致 -->
|
||||||
@@ -202,6 +202,24 @@ type CartGroup = {
|
|||||||
items: LocalCartItem[]
|
items: LocalCartItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const compareStrings = (a: string, b: string): boolean => {
|
||||||
|
console.log('[compareStrings] a length:', a.length, 'b length:', b.length)
|
||||||
|
console.log('[compareStrings] a type:', typeof a, 'b type:', typeof b)
|
||||||
|
console.log('[compareStrings] a value:', JSON.stringify(a))
|
||||||
|
console.log('[compareStrings] b value:', JSON.stringify(b))
|
||||||
|
|
||||||
|
if (a.length !== b.length) return false
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
const aCode = a.charCodeAt(i)
|
||||||
|
const bCode = b.charCodeAt(i)
|
||||||
|
if (aCode != null && bCode != null && aCode !== bCode) {
|
||||||
|
console.log('[compareStrings] mismatch at index:', i, 'a:', aCode, 'b:', bCode)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type RecommendProduct = {
|
type RecommendProduct = {
|
||||||
id: string
|
id: string
|
||||||
shopId: string
|
shopId: string
|
||||||
@@ -216,6 +234,7 @@ type RecommendProduct = {
|
|||||||
// 响应式数据
|
// 响应式数据
|
||||||
const cartItems = ref<LocalCartItem[]>([])
|
const cartItems = ref<LocalCartItem[]>([])
|
||||||
const recommendProducts = ref<RecommendProduct[]>([])
|
const recommendProducts = ref<RecommendProduct[]>([])
|
||||||
|
const recommendPage = ref<number>(1)
|
||||||
const loading = ref<boolean>(false)
|
const loading = ref<boolean>(false)
|
||||||
const statusBarHeight = ref(0)
|
const statusBarHeight = ref(0)
|
||||||
const isManageMode = ref(false)
|
const isManageMode = ref(false)
|
||||||
@@ -223,9 +242,11 @@ const updatingItems = ref<Set<string>>(new Set()) // Track items being updated t
|
|||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const cartGroups = computed<CartGroup[]>(() => {
|
const cartGroups = computed<CartGroup[]>(() => {
|
||||||
|
console.log('[cartGroups] 计算购物车分组, cartItems count:', cartItems.value.length)
|
||||||
const groups = new Map<string, CartGroup>()
|
const groups = new Map<string, CartGroup>()
|
||||||
|
|
||||||
cartItems.value.forEach((item: LocalCartItem) => {
|
cartItems.value.forEach((item: LocalCartItem) => {
|
||||||
|
console.log('[cartGroups] item:', item.id, 'shopId:', item.shopId, 'shopName:', item.shopName)
|
||||||
const shopKey = item.shopId
|
const shopKey = item.shopId
|
||||||
if (!groups.has(shopKey)) {
|
if (!groups.has(shopKey)) {
|
||||||
groups.set(shopKey, {
|
groups.set(shopKey, {
|
||||||
@@ -244,6 +265,7 @@ const cartGroups = computed<CartGroup[]>(() => {
|
|||||||
|
|
||||||
const groupArray: CartGroup[] = []
|
const groupArray: CartGroup[] = []
|
||||||
groups.forEach((value: CartGroup) => {
|
groups.forEach((value: CartGroup) => {
|
||||||
|
console.log('[cartGroups] group:', value.shopId, 'items count:', value.items.length)
|
||||||
groupArray.push(value)
|
groupArray.push(value)
|
||||||
})
|
})
|
||||||
return groupArray
|
return groupArray
|
||||||
@@ -266,8 +288,17 @@ const totalPrice = computed(() => {
|
|||||||
|
|
||||||
// 检查店铺是否全选
|
// 检查店铺是否全选
|
||||||
const isShopSelected = (shopId: string): boolean => {
|
const isShopSelected = (shopId: string): boolean => {
|
||||||
const shopItems = cartItems.value.filter((item: LocalCartItem): boolean => item.shopId === shopId)
|
const shopItems: LocalCartItem[] = []
|
||||||
return shopItems.length > 0 && shopItems.every((item: LocalCartItem): boolean => item.selected)
|
for (let i = 0; i < cartItems.value.length; i++) {
|
||||||
|
if (compareStrings(cartItems.value[i].shopId, shopId)) {
|
||||||
|
shopItems.push(cartItems.value[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shopItems.length === 0) return false
|
||||||
|
for (let i = 0; i < shopItems.length; i++) {
|
||||||
|
if (!shopItems[i].selected) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleManageMode = () => {
|
const toggleManageMode = () => {
|
||||||
@@ -285,25 +316,49 @@ onMounted(() => {
|
|||||||
initPage()
|
initPage()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 提取更新列表的辅助函数以减少重复代码
|
||||||
|
const updateRecommendList = (recommends: Product[]) => {
|
||||||
|
recommendProducts.value = recommends.map((p: Product): RecommendProduct => {
|
||||||
|
return {
|
||||||
|
id: p.id,
|
||||||
|
shopId: p.merchant_id ?? 'unknown',
|
||||||
|
shopName: p.shop_name ?? '商城推荐',
|
||||||
|
name: p.name,
|
||||||
|
price: p.base_price ?? p.market_price ?? 0,
|
||||||
|
image: p.main_image_url ?? p.image_url ?? '/static/images/default-product.png',
|
||||||
|
skuId: '',
|
||||||
|
merchant_id: p.merchant_id ?? ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const refreshRecommend = async () => {
|
const refreshRecommend = async () => {
|
||||||
try {
|
try {
|
||||||
// 使用 searchProducts 获取销售额排序的 6 个产品
|
// 递增页码以获取不同的商品
|
||||||
const hotResp = await supabaseService.searchProducts('', 1, 6, 'sales')
|
recommendPage.value = recommendPage.value + 1
|
||||||
|
|
||||||
|
// 使用 searchProducts 获取不同页码的 6 个产品
|
||||||
|
const hotResp = await supabaseService.searchProducts('', recommendPage.value, 6, 'sales')
|
||||||
const recommends = hotResp.data
|
const recommends = hotResp.data
|
||||||
|
|
||||||
|
// 如果新页码没有数据,重置为第一页再试一次
|
||||||
|
if (recommends.length === 0 && recommendPage.value > 1) {
|
||||||
|
recommendPage.value = 1
|
||||||
|
const firstPageResp = await supabaseService.searchProducts('', 1, 6, 'sales')
|
||||||
|
const firstRecommends = firstPageResp.data
|
||||||
|
|
||||||
|
if (firstRecommends.length > 0) {
|
||||||
|
updateRecommendList(firstRecommends)
|
||||||
|
uni.showToast({
|
||||||
|
title: '已重置推荐',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (recommends.length > 0) {
|
if (recommends.length > 0) {
|
||||||
recommendProducts.value = recommends.map((p: Product): RecommendProduct => {
|
updateRecommendList(recommends)
|
||||||
return {
|
|
||||||
id: p.id,
|
|
||||||
shopId: p.merchant_id ?? 'unknown',
|
|
||||||
shopName: p.shop_name ?? '商城推荐',
|
|
||||||
name: p.name,
|
|
||||||
price: p.base_price ?? p.market_price ?? 0,
|
|
||||||
image: p.main_image_url ?? p.image_url ?? '/static/images/default-product.png',
|
|
||||||
skuId: '',
|
|
||||||
merchant_id: p.merchant_id ?? ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '已更新推荐',
|
title: '已更新推荐',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -409,41 +464,84 @@ const toggleSelect = async (itemId: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toggleShopSelect = async (shopId: string) => {
|
const toggleShopSelect = async (shopId: string) => {
|
||||||
// 获取该店铺下所有商品的ID
|
console.log('[toggleShopSelect] shopId:', shopId)
|
||||||
const shopItems = cartItems.value.filter((item: LocalCartItem): boolean => item.shopId === shopId)
|
console.log('[toggleShopSelect] shopId length:', shopId.length)
|
||||||
|
console.log('[toggleShopSelect] cartItems.value.length:', cartItems.value.length)
|
||||||
|
|
||||||
|
// 用 for 循环替代 filter,避免安卓端 UTS filter 的问题
|
||||||
|
const shopItems: LocalCartItem[] = []
|
||||||
|
for (let i = 0; i < cartItems.value.length; i++) {
|
||||||
|
const item = cartItems.value[i]
|
||||||
|
const itemShopId = item.shopId
|
||||||
|
// 安卓端字符串比较问题:使用 localeCompare 或逐字符比较
|
||||||
|
const isMatch = compareStrings(itemShopId, shopId)
|
||||||
|
console.log('[toggleShopSelect] checking item:', item.id, 'item.shopId:', itemShopId, 'match:', isMatch)
|
||||||
|
if (isMatch) {
|
||||||
|
shopItems.push(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('[toggleShopSelect] shopItems count:', shopItems.length)
|
||||||
|
|
||||||
if (shopItems.length === 0) return
|
if (shopItems.length === 0) return
|
||||||
|
|
||||||
const isAllShopSelected = shopItems.every((item: LocalCartItem): boolean => item.selected)
|
// 用 for 循环替代 every
|
||||||
const newState = !isAllShopSelected
|
let allSelected = true
|
||||||
|
for (let i = 0; i < shopItems.length; i++) {
|
||||||
|
if (!shopItems[i].selected) {
|
||||||
|
allSelected = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const newState = !allSelected
|
||||||
|
console.log('[toggleShopSelect] allSelected:', allSelected, 'newState:', newState)
|
||||||
|
|
||||||
const shopItemIds = shopItems.map((item: LocalCartItem): string => item.id)
|
const shopItemIds: string[] = []
|
||||||
|
for (let i = 0; i < shopItems.length; i++) {
|
||||||
|
shopItemIds.push(shopItems[i].id)
|
||||||
|
}
|
||||||
|
console.log('[toggleShopSelect] shopItemIds:', shopItemIds)
|
||||||
|
|
||||||
// 乐观更新本地状态
|
// 创建全新的数组来触发响应式更新
|
||||||
const oldStates = new Map<string, boolean>()
|
const newCartItems: LocalCartItem[] = []
|
||||||
cartItems.value.forEach(item => {
|
for (let i = 0; i < cartItems.value.length; i++) {
|
||||||
if (item.shopId === shopId) {
|
const item = cartItems.value[i]
|
||||||
oldStates.set(item.id, item.selected)
|
const isMatch = compareStrings(item.shopId, shopId)
|
||||||
item.selected = newState
|
if (isMatch) {
|
||||||
}
|
console.log('[toggleShopSelect] updating item:', item.id, 'to selected:', newState)
|
||||||
})
|
// 创建新的对象
|
||||||
cartItems.value = [...cartItems.value]
|
const newItem: LocalCartItem = {
|
||||||
|
id: item.id,
|
||||||
|
shopId: item.shopId,
|
||||||
|
shopName: item.shopName,
|
||||||
|
name: item.name,
|
||||||
|
price: item.price,
|
||||||
|
image: item.image,
|
||||||
|
spec: item.spec,
|
||||||
|
quantity: item.quantity,
|
||||||
|
selected: newState,
|
||||||
|
productId: item.productId,
|
||||||
|
skuId: item.skuId,
|
||||||
|
merchantId: item.merchantId
|
||||||
|
}
|
||||||
|
newCartItems.push(newItem)
|
||||||
|
} else {
|
||||||
|
newCartItems.push(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 替换整个数组
|
||||||
|
cartItems.value = newCartItems
|
||||||
|
|
||||||
// 批量更新到Supabase
|
// 批量更新到Supabase
|
||||||
const success = await supabaseService.batchUpdateCartItemSelection(shopItemIds, newState)
|
const success = await supabaseService.batchUpdateCartItemSelection(shopItemIds, newState)
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
console.error('批量更新店铺商品选中状态失败')
|
console.error('批量更新店铺商品选中状态失败')
|
||||||
// 回滚
|
|
||||||
cartItems.value.forEach(item => {
|
|
||||||
if (item.shopId === shopId && oldStates.has(item.id)) {
|
|
||||||
item.selected = oldStates.get(item.id)!
|
|
||||||
}
|
|
||||||
})
|
|
||||||
cartItems.value = [...cartItems.value]
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '操作失败',
|
title: '操作失败',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
|
// 重新加载数据以确保状态一致
|
||||||
|
loadCartData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +766,7 @@ const navigateToShop = (shopId: string, merchantId: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const goShopping = () => {
|
const goShopping = () => {
|
||||||
uni.switchTab({ url: '/pages/mall/consumer/index' })
|
uni.switchTab({ url: '/pages/main/index' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigateToProduct = (product: any) => {
|
const navigateToProduct = (product: any) => {
|
||||||
@@ -655,7 +655,7 @@ async function addToCart(product: Product): Promise<void> {
|
|||||||
|
|
||||||
// 导航函数
|
// 导航函数
|
||||||
function navigateToSearch(): void { uni.navigateTo({ url: '/pages/mall/consumer/search' }) }
|
function navigateToSearch(): void { uni.navigateTo({ url: '/pages/mall/consumer/search' }) }
|
||||||
function navigateToCart(): void { uni.navigateTo({ url: '/pages/mall/consumer/cart' }) }
|
function navigateToCart(): void { uni.navigateTo({ url: '/pages/main/cart' }) }
|
||||||
function navigateToProduct(product: Product): void {
|
function navigateToProduct(product: Product): void {
|
||||||
const id = (product.id ?? '').toString()
|
const id = (product.id ?? '').toString()
|
||||||
if (id === '') return
|
if (id === '') return
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- pages/mall/consumer/index.uvue -->
|
<!-- pages/main/index.uvue -->
|
||||||
<template>
|
<template>
|
||||||
<view class="medic-home">
|
<view class="medic-home">
|
||||||
<!-- 智能顶部导航栏 - 添加滚动隐藏效果 -->
|
<!-- 智能顶部导航栏 - 添加滚动隐藏效果 -->
|
||||||
@@ -404,7 +404,7 @@ const onParentCategoryClick = async (category: Category): Promise<void> => {
|
|||||||
console.log('[onParentCategoryClick] 没有二级分类,直接跳转到分类页')
|
console.log('[onParentCategoryClick] 没有二级分类,直接跳转到分类页')
|
||||||
uni.setStorageSync('selectedCategory', category.id)
|
uni.setStorageSync('selectedCategory', category.id)
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/category'
|
url: '/pages/main/category'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,10 +415,10 @@ const onSubCategoryClick = (category: Category): void => {
|
|||||||
uni.setStorageSync('selectedCategory', category.id)
|
uni.setStorageSync('selectedCategory', category.id)
|
||||||
const timestamp = Date.now()
|
const timestamp = Date.now()
|
||||||
const randomParam = Math.random().toString(36).substring(2, 8)
|
const randomParam = Math.random().toString(36).substring(2, 8)
|
||||||
const url = `/pages/mall/consumer/category?categoryId=${category.id}&name=${encodeURIComponent(category.name)}×tamp=${timestamp}&random=${randomParam}`
|
const url = `/pages/main/category?categoryId=${category.id}&name=${encodeURIComponent(category.name)}×tamp=${timestamp}&random=${randomParam}`
|
||||||
|
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/category'
|
url: '/pages/main/category'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -739,10 +739,10 @@ const switchCategory = (category: any) => {
|
|||||||
const randomParam = Math.random().toString(36).substring(2, 8)
|
const randomParam = Math.random().toString(36).substring(2, 8)
|
||||||
|
|
||||||
// 构建带参数的URL,直接通过URL传递分类信息
|
// 构建带参数的URL,直接通过URL传递分类信息
|
||||||
const url = `/pages/mall/consumer/category?categoryId=${categoryId}&name=${encodeURIComponent(categoryName)}×tamp=${timestamp}&random=${randomParam}`
|
const url = `/pages/main/category?categoryId=${categoryId}&name=${encodeURIComponent(categoryName)}×tamp=${timestamp}&random=${randomParam}`
|
||||||
|
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/category',
|
url: '/pages/main/category',
|
||||||
success: () => {
|
success: () => {
|
||||||
// 通过 Storage 传递参数已在上面设置
|
// 通过 Storage 传递参数已在上面设置
|
||||||
console.log('跳转分类页面成功,categoryId:', categoryId)
|
console.log('跳转分类页面成功,categoryId:', categoryId)
|
||||||
@@ -1064,7 +1064,7 @@ export default {
|
|||||||
|
|
||||||
goShopping() {
|
goShopping() {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/index'
|
url: '/pages/main/index'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ const deleteAddress = () => {
|
|||||||
.form-group {
|
.form-group {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 0 16px;
|
padding: 16px; /* 给整个组增加内边距 */
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.02);
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.02);
|
||||||
}
|
}
|
||||||
@@ -415,46 +415,62 @@ const deleteAddress = () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 18px 0;
|
padding: 0 16px;
|
||||||
border-bottom: 1px solid #f9f9f9;
|
min-height: 52px;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border-radius: 26px; /* 增加大圆角,使其从直角变为圆角 */
|
||||||
|
margin-bottom: 12px;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-item:last-child {
|
.form-item:last-child {
|
||||||
border-bottom: none;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-item {
|
.detail-item {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 16px; /* 详细地址区域也增加圆角 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-item .label {
|
.detail-item .label {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #333;
|
color: #666;
|
||||||
font-weight: 500;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 15px;
|
height: 44px; /* 增加高度 */
|
||||||
|
line-height: 44px;
|
||||||
|
font-size: 16px;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
padding: 0 4px;
|
||||||
|
background-color: transparent; /* 确保输入框背景透明 */
|
||||||
|
border: none; /* 强制去除安卓原生边框 */
|
||||||
|
outline: none; /* 强制去除焦点边框 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.textarea {
|
.textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 60px;
|
height: 80px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 1.5;
|
line-height: 1.6;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
padding: 4px 0;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none; /* 强制去除安卓原生边框 */
|
||||||
|
outline: none; /* 强制去除焦点边框 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder {
|
.placeholder {
|
||||||
color: #ccc;
|
color: #bbb;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,10 +497,11 @@ const deleteAddress = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tag-item {
|
.tag-item {
|
||||||
padding: 6px 18px;
|
padding: 8px 20px; /* 增大点击区域 */
|
||||||
background-color: #f7f7f7;
|
background-color: #f7f7f7;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
|
margin-bottom: 8px; /* 增加底部间距 */
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +511,7 @@ const deleteAddress = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tag-text {
|
.tag-text {
|
||||||
font-size: 13px;
|
font-size: 14px; /* 增大标签文字 */
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,6 +523,7 @@ const deleteAddress = () => {
|
|||||||
/* 开关项 */
|
/* 开关项 */
|
||||||
.switch-item {
|
.switch-item {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
min-height: 72px; /* 增加开关项高度 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.switch-label-group {
|
.switch-label-group {
|
||||||
@@ -514,9 +532,9 @@ const deleteAddress = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sub-label {
|
.sub-label {
|
||||||
font-size: 12px;
|
font-size: 13px; /* 增大副标题 */
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-top: 4px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 智能填写 */
|
/* 智能填写 */
|
||||||
|
|||||||
@@ -433,6 +433,8 @@ const sendMessage = async () => {
|
|||||||
|
|
||||||
// 清空输入框
|
// 清空输入框
|
||||||
inputMessage.value = ''
|
inputMessage.value = ''
|
||||||
|
// 发送消息时确保收起表情面板
|
||||||
|
showEmoji.value = false
|
||||||
|
|
||||||
// 发送到 Supabase
|
// 发送到 Supabase
|
||||||
if (merchantId.value != '') {
|
if (merchantId.value != '') {
|
||||||
@@ -461,12 +463,17 @@ const simulateCustomerReply = async () => {
|
|||||||
// 插入表情
|
// 插入表情
|
||||||
function insertEmoji(emoji: string): void {
|
function insertEmoji(emoji: string): void {
|
||||||
inputMessage.value += emoji
|
inputMessage.value += emoji
|
||||||
|
showEmoji.value = false // 选中表情后收起表情列表
|
||||||
inputFocus.value = true
|
inputFocus.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示表情选择器
|
// 显示表情选择器
|
||||||
function showEmojiPicker(): void {
|
function showEmojiPicker(): void {
|
||||||
showEmoji.value = !showEmoji.value
|
showEmoji.value = !showEmoji.value
|
||||||
|
if (showEmoji.value) {
|
||||||
|
// 如果打开表情,通常需要收起键盘
|
||||||
|
uni.hideKeyboard()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示图片选择器
|
// 显示图片选择器
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<!-- 结算页面 -->
|
<!-- 结算页面 -->
|
||||||
<template>
|
<template>
|
||||||
<view class="checkout-page">
|
<view class="checkout-page">
|
||||||
<scroll-view class="checkout-content" scroll-y>
|
<scroll-view class="checkout-content" direction="vertical">
|
||||||
<!-- 收货地址 -->
|
<!-- 收货地址 -->
|
||||||
<view class="address-section" @click="selectAddress">
|
<view class="address-section" @click="selectAddress">
|
||||||
<view v-if="selectedAddress" class="address-info">
|
<view v-if="selectedAddress" class="address-info">
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
<text class="popup-close" @click="showAddressPopup = false">×</text>
|
<text class="popup-close" @click="showAddressPopup = false">×</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view class="address-list-container" scroll-y="true" :scroll-with-animation="true">
|
<scroll-view class="address-list-container" direction="vertical" :scroll-with-animation="true">
|
||||||
<!-- 登录提示 -->
|
<!-- 登录提示 -->
|
||||||
<view v-if="isLoggedIn == false" class="login-prompt" @click="goToLogin">
|
<view v-if="isLoggedIn == false" class="login-prompt" @click="goToLogin">
|
||||||
<text class="login-prompt-icon">🔒</text>
|
<text class="login-prompt-icon">🔒</text>
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view class="form-content" scroll-y="true">
|
<scroll-view class="form-content" direction="vertical">
|
||||||
<view class="form-section">
|
<view class="form-section">
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="form-label">收货人</text>
|
<text class="form-label">收货人</text>
|
||||||
@@ -1422,14 +1422,20 @@ const goToLogin = () => {
|
|||||||
.checkout-page {
|
.checkout-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1; /* replace height: 100vh */
|
position: absolute;
|
||||||
background-color: #f5f5f5;
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
/* 顶部栏 */
|
/* 顶部栏 */
|
||||||
.checkout-header {
|
.checkout-header {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
border-bottom: 1px solid #e5e5e5;
|
border-bottom: 1px solid #e5e5e5;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-title {
|
.header-title {
|
||||||
@@ -1441,6 +1447,9 @@ const goToLogin = () => {
|
|||||||
|
|
||||||
.checkout-content {
|
.checkout-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.address-section {
|
.address-section {
|
||||||
@@ -1524,6 +1533,7 @@ const goToLogin = () => {
|
|||||||
.address-popup {
|
.address-popup {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 60vh; /* 显式高度保证内部 scroll-view direction="vertical" 生效 */
|
||||||
border-radius: 20px 20px 0 0;
|
border-radius: 20px 20px 0 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -1619,13 +1629,13 @@ const goToLogin = () => {
|
|||||||
background-color: #f8f8f8;
|
background-color: #f8f8f8;
|
||||||
width: 92%;
|
width: 92%;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
height: 85vh;
|
height: 600px; /* 改用具体的像素高度,Android 端的 scroll-view 计算更稳健 */
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10000;
|
z-index: 10001;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-header {
|
.form-header {
|
||||||
@@ -1646,24 +1656,14 @@ const goToLogin = () => {
|
|||||||
|
|
||||||
.form-content {
|
.form-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100px; /* 进一步减小初始高度,确保安卓端 flex:1 接管 */
|
width: 100%;
|
||||||
min-height: 0;
|
/* 在 Android 下,scroll-view 如果不给明确的高度且处于 flex 容器,必须通过 flex-grow 撑开 */
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
background-color: #ffffff;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.address-form-popup {
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
width: 92%;
|
|
||||||
max-width: 500px;
|
|
||||||
height: 80vh; /* 稍微压低高度确保不在边缘产生冲突 */
|
|
||||||
border-radius: 16px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
z-index: 10001;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-section {
|
.form-section {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
const useCoupon = (coupon: Coupon) => {
|
const useCoupon = (coupon: Coupon) => {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/index'
|
url: '/pages/main/index'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ const addToCart = async (product: FavoriteType) => {
|
|||||||
|
|
||||||
const goShopping = () => {
|
const goShopping = () => {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/index'
|
url: '/pages/main/index'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ const loadMore = () => {
|
|||||||
|
|
||||||
const goShopping = () => {
|
const goShopping = () => {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/index'
|
url: '/pages/main/index'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ const rePurchase = async () => {
|
|||||||
if (successCount > 0) {
|
if (successCount > 0) {
|
||||||
uni.showToast({ title: '已加入购物车' })
|
uni.showToast({ title: '已加入购物车' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.switchTab({ url: '/pages/mall/consumer/cart' })
|
uni.switchTab({ url: '/pages/main/cart' })
|
||||||
}, 1000)
|
}, 1000)
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({ title: '操作失败', icon: 'none' })
|
uni.showToast({ title: '操作失败', icon: 'none' })
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="orders-page">
|
<view class="orders-page">
|
||||||
<!-- 顶部标题栏 -->
|
<!-- 顶部标题栏 -->
|
||||||
<view class="orders-header">
|
<view class="orders-header" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
<view class="header-search full-width">
|
<view class="header-search full-width">
|
||||||
<input
|
<input
|
||||||
class="search-input"
|
class="search-input"
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
<!-- 订单列表 -->
|
<!-- 订单列表 -->
|
||||||
<scroll-view
|
<scroll-view
|
||||||
scroll-y
|
direction="vertical"
|
||||||
class="orders-content"
|
class="orders-content"
|
||||||
refresher-enabled
|
refresher-enabled
|
||||||
:refresher-triggered="refreshing"
|
:refresher-triggered="refreshing"
|
||||||
@@ -125,29 +125,30 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="order.status === 2" class="action-buttons">
|
<view v-if="order.status === 2" class="action-buttons">
|
||||||
<button class="action-btn remind" @click="remindShipping(order.id)">提醒发货</button>
|
<button class="action-btn remind" @click.stop="remindShipping(order.id)">提醒发货</button>
|
||||||
<button class="action-btn refund" @click.stop="onApplyRefund(order)">申请售后</button>
|
<button class="action-btn refund" @click.stop="onApplyRefund(order)">申请售后</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="order.status === 3" class="action-buttons">
|
<view v-if="order.status === 3" class="action-buttons">
|
||||||
<button class="action-btn view" @click="viewLogistics(order.id)">查看物流</button>
|
<button class="action-btn view" @click.stop="viewLogistics(order.id)">查看物流</button>
|
||||||
<button class="action-btn confirm" @click="confirmReceipt(order.id)">确认收货</button>
|
<button class="action-btn confirm" @click.stop="confirmReceipt(order.id)">确认收货</button>
|
||||||
<button class="action-btn refund" @click.stop="onApplyRefund(order)">申请售后</button>
|
<button class="action-btn refund" @click.stop="onApplyRefund(order)">申请售后</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="order.status === 4" class="action-buttons">
|
<view v-if="order.status === 4" class="action-buttons">
|
||||||
<button class="action-btn review" @click="goReview(order)">评价</button>
|
<button class="action-btn review" @click.stop="goReview(order)">评价</button>
|
||||||
<button class="action-btn refund" @click.stop="onApplyRefund(order)">申请售后</button>
|
<button class="action-btn refund" @click.stop="onApplyRefund(order)">申请售后</button>
|
||||||
<button class="action-btn repurchase" @click="repurchase(order)">再次购买</button>
|
<button class="action-btn repurchase" @click.stop="repurchase(order)">再次购买</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="order.status === 5" class="action-buttons">
|
<view v-if="order.status === 5" class="action-buttons">
|
||||||
<button class="action-btn view" @click="viewOrderDetail(order.id)">查看详情</button>
|
<button class="action-btn view" @click.stop="viewOrderDetail(order.id)">查看详情</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="order.status === 6" class="action-buttons">
|
<view v-if="order.status === 6" class="action-buttons">
|
||||||
<button class="action-btn view" @click="viewOrderDetail(order.id)">查看详情</button>
|
<button class="action-btn view" @click.stop="viewOrderDetail(order.id)">查看详情</button>
|
||||||
<button class="action-btn refund" @click="viewRefundProgress(order.id)">退款进度</button>
|
<button class="action-btn cancel" @click.stop="cancelRefund(order.id)">取消退款</button>
|
||||||
|
<button class="action-btn refund" @click.stop="viewRefundProgress(order.id)">退款进度</button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="order.status === 7" class="action-buttons">
|
<view v-if="order.status === 7" class="action-buttons">
|
||||||
@@ -222,6 +223,7 @@ const hasMore = ref<boolean>(true)
|
|||||||
const refreshing = ref<boolean>(false)
|
const refreshing = ref<boolean>(false)
|
||||||
const page = ref<number>(1)
|
const page = ref<number>(1)
|
||||||
const activeTab = ref<string>('all')
|
const activeTab = ref<string>('all')
|
||||||
|
const statusBarHeight = ref<number>(0)
|
||||||
const searchKeyword = ref<string>('')
|
const searchKeyword = ref<string>('')
|
||||||
|
|
||||||
// 订单标签页 - 使用 ref 以便整体替换
|
// 订单标签页 - 使用 ref 以便整体替换
|
||||||
@@ -504,6 +506,10 @@ const loadOrders = async () => {
|
|||||||
|
|
||||||
// 生命周期
|
// 生命周期
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
|
// 初始化状态栏高度
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
statusBarHeight.value = systemInfo.statusBarHeight ?? 0
|
||||||
|
|
||||||
if (options == null) return
|
if (options == null) return
|
||||||
const statusVal = options['status']
|
const statusVal = options['status']
|
||||||
if (statusVal != null) {
|
if (statusVal != null) {
|
||||||
@@ -518,7 +524,7 @@ onLoad((options) => {
|
|||||||
if (type === 'pending') activeTab.value = 'pending'
|
if (type === 'pending') activeTab.value = 'pending'
|
||||||
else if (type === 'shipped') activeTab.value = 'delivering' // 映射到待收货
|
else if (type === 'shipped') activeTab.value = 'delivering' // 映射到待收货
|
||||||
else if (type === 'review') activeTab.value = 'completed' // 映射到已完成
|
else if (type === 'review') activeTab.value = 'completed' // 映射到已完成
|
||||||
else if (type === 'refund') activeTab.value = 'all' // 申请售后默认显示全部
|
else if (type === 'refund') activeTab.value = 'aftersale' // 退款/售后跳转到售后标签页
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -771,15 +777,11 @@ const viewLogistics = (orderId: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// goReview 必须在 doConfirmReceipt 之前定义,因为 doConfirmReceipt 会调用它
|
// goReview 必须在 doConfirmReceipt 之前定义,因为 doConfirmReceipt 会调用它
|
||||||
const goReview = (order: any) => {
|
const goReview = (order: OrderItem) => {
|
||||||
const orderObj = order as Record<string, any>
|
const productIds = order.products.map((p: OrderProduct): string => {
|
||||||
const products = orderObj['products'] as any[]
|
return p.id
|
||||||
const productIds = products.map((p: any) => {
|
|
||||||
const pObj = p as Record<string, any>
|
|
||||||
const pid = pObj['id']
|
|
||||||
return pid != null ? pid as string : ''
|
|
||||||
}).join(',')
|
}).join(',')
|
||||||
const orderId = orderObj['id'] as string
|
const orderId = order.id
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/mall/consumer/review?orderId=${orderId}&productIds=${productIds}`
|
url: `/pages/mall/consumer/review?orderId=${orderId}&productIds=${productIds}`
|
||||||
})
|
})
|
||||||
@@ -798,22 +800,15 @@ const doConfirmReceipt = async (orderId: string) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 更新本地状态
|
// 更新本地状态
|
||||||
const index = orders.value.findIndex((o: any) => {
|
const index = orders.value.findIndex((o: OrderItem): boolean => o.id === orderId)
|
||||||
const obj = o as Record<string, any>
|
|
||||||
return obj['id'] === orderId
|
|
||||||
})
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
const orderObj = orders.value[index] as Record<string, any>
|
orders.value[index].status = 4
|
||||||
orderObj['status'] = 4
|
|
||||||
orders.value = [...orders.value]
|
orders.value = [...orders.value]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跳转到评价页面
|
// 跳转到评价页面
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const order = orders.value.find((o: any) => {
|
const order = orders.value.find((o: OrderItem): boolean => o.id === orderId)
|
||||||
const obj = o as Record<string, any>
|
|
||||||
return obj['id'] === orderId
|
|
||||||
})
|
|
||||||
if (order != null) {
|
if (order != null) {
|
||||||
goReview(order)
|
goReview(order)
|
||||||
}
|
}
|
||||||
@@ -845,11 +840,10 @@ const confirmReceipt = (orderId: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const repurchase = (order: any) => {
|
const repurchase = (order: OrderItem) => {
|
||||||
const orderObj = order as Record<string, any>
|
const products = order.products
|
||||||
const products = orderObj['products'] as any[]
|
|
||||||
|
|
||||||
if (products == null || products.length === 0) {
|
if (products.length === 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '订单无商品',
|
title: '订单无商品',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -864,12 +858,12 @@ const repurchase = (order: any) => {
|
|||||||
let successCount = 0
|
let successCount = 0
|
||||||
|
|
||||||
for (let i = 0; i < products.length; i++) {
|
for (let i = 0; i < products.length; i++) {
|
||||||
const pObj = products[i] as Record<string, any>
|
const product = products[i]
|
||||||
const productId = pObj['id'] as string
|
const productId = product.id
|
||||||
const merchantId = orderObj['merchant_id'] as string
|
const merchantId = order.merchant_id
|
||||||
|
|
||||||
if (productId != null && productId !== '') {
|
if (productId != null && productId !== '') {
|
||||||
supabaseService.addToCart(productId, 1, '', merchantId ?? '').then((success) => {
|
supabaseService.addToCart(productId, 1, '', merchantId ?? '').then((success: boolean) => {
|
||||||
completed++
|
completed++
|
||||||
if (success) successCount++
|
if (success) successCount++
|
||||||
if (completed === total) {
|
if (completed === total) {
|
||||||
@@ -929,9 +923,8 @@ const viewOrderDetail = (orderId: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onApplyRefund = (order: any) => {
|
const onApplyRefund = (order: OrderItem) => {
|
||||||
const orderObj = order as Record<string, any>
|
const orderId = order.id
|
||||||
const orderId = orderObj['id']
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/mall/consumer/apply-refund?orderId=${orderId}`
|
url: `/pages/mall/consumer/apply-refund?orderId=${orderId}`
|
||||||
})
|
})
|
||||||
@@ -943,6 +936,32 @@ const viewRefundProgress = (orderId: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const doCancelRefund = async (orderId: string) => {
|
||||||
|
uni.showLoading({ title: '处理中...' })
|
||||||
|
const result = await supabaseService.cancelRefund(orderId)
|
||||||
|
uni.hideLoading()
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
uni.showToast({ title: '已取消退款', icon: 'success' })
|
||||||
|
loadOrders()
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: result.message, icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消退款申请
|
||||||
|
const cancelRefund = (orderId: string) => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确认取消',
|
||||||
|
content: '确定要取消退款申请吗?',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
doCancelRefund(orderId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 处理订单操作
|
// 处理订单操作
|
||||||
const handleOrderAction = (order: OrderItem, action: string) => {
|
const handleOrderAction = (order: OrderItem, action: string) => {
|
||||||
if (action === '取消订单') {
|
if (action === '取消订单') {
|
||||||
@@ -963,6 +982,8 @@ const handleOrderAction = (order: OrderItem, action: string) => {
|
|||||||
deleteOrder(order.id)
|
deleteOrder(order.id)
|
||||||
} else if (action === '退款进度') {
|
} else if (action === '退款进度') {
|
||||||
viewRefundProgress(order.id)
|
viewRefundProgress(order.id)
|
||||||
|
} else if (action === '取消退款') {
|
||||||
|
cancelRefund(order.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -982,7 +1003,7 @@ const showOrderMenu = (order: OrderItem) => {
|
|||||||
} else if (status === 5) {
|
} else if (status === 5) {
|
||||||
actions = ['删除订单', '再次购买', '联系卖家']
|
actions = ['删除订单', '再次购买', '联系卖家']
|
||||||
} else if (status === 6) {
|
} else if (status === 6) {
|
||||||
actions = ['退款进度', '联系卖家']
|
actions = ['取消退款', '退款进度', '联系卖家']
|
||||||
} else if (status === 7) {
|
} else if (status === 7) {
|
||||||
actions = ['再次购买', '联系卖家']
|
actions = ['再次购买', '联系卖家']
|
||||||
}
|
}
|
||||||
@@ -1001,59 +1022,75 @@ const navigateToSearch = () => {
|
|||||||
uni.navigateTo({ url: '/pages/mall/consumer/search' })
|
uni.navigateTo({ url: '/pages/mall/consumer/search' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigateToProduct = (product: any) => {
|
const navigateToProduct = (product: OrderProduct) => {
|
||||||
const productObj = product as Record<string, any>
|
const productId = product.id
|
||||||
const productId = productObj['id']
|
|
||||||
uni.navigateTo({ url: `/pages/mall/consumer/product-detail?id=${productId}` })
|
uni.navigateTo({ url: `/pages/mall/consumer/product-detail?id=${productId}` })
|
||||||
}
|
}
|
||||||
|
|
||||||
const goShopping = () => {
|
const goShopping = () => {
|
||||||
uni.switchTab({ url: '/pages/mall/consumer/index' })
|
uni.switchTab({ url: '/pages/main/index' })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.orders-page {
|
.orders-page {
|
||||||
position: absolute;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
/* 采用相对于窗口的 100% 方案 */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/* App/小程序通过 fixed 解决根容器撑满问题,H5/电脑端建议使用 flex 1 */
|
||||||
|
/* #ifdef APP-PLUS || MP-WEIXIN */
|
||||||
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
display: flex;
|
/* #endif */
|
||||||
flex-direction: column;
|
/* #ifdef H5 */
|
||||||
|
position: relative;
|
||||||
|
/* #endif */
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 头部 */
|
/* 头部:确保显式可见且不被遮挡 */
|
||||||
.orders-header {
|
.orders-header {
|
||||||
background-color: white;
|
background-color: #ffffff;
|
||||||
padding: 15px;
|
padding: 10px 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
width: 100%;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eeeeee;
|
||||||
z-index: 10;
|
z-index: 999;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-search.full-width {
|
.header-search.full-width {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
border: 1px solid #ddd;
|
line-height: normal;
|
||||||
|
border: 1px solid #dddddd;
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
padding: 0 40px 0 16px;
|
padding: 0 40px 0 16px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
color: #333;
|
color: #333333;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-input::placeholder {
|
.search-input::placeholder {
|
||||||
@@ -1086,7 +1123,7 @@ const goShopping = () => {
|
|||||||
/* cursor: pointer; removed */
|
/* cursor: pointer; removed */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 标签页 */
|
/* 标签页容器:确保在安卓下层级正确且不随内容滚动 */
|
||||||
.order-tabs-fixed-container {
|
.order-tabs-fixed-container {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
@@ -1094,26 +1131,25 @@ const goShopping = () => {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 10;
|
z-index: 100 !important;
|
||||||
height: 50px;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 安卓端滚动修复 */
|
/* 安卓端滚动修复:关键容器 */
|
||||||
.orders-content {
|
.orders-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 0; /* 关键:强制 flex: 1 生效 */
|
/* 极致方案:不再设置 height: 0,改用 flex: 1 填满,并显式设置 scroll-y 的表现 */
|
||||||
|
min-height: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.orders-header {
|
/* 顶部内容区域必须显式不可伸缩,防止撑占滚动空间 */
|
||||||
background-color: white;
|
.orders-header, .order-tabs-fixed-container {
|
||||||
padding: 15px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item-fixed {
|
.tab-item-fixed {
|
||||||
@@ -1456,6 +1492,16 @@ const goShopping = () => {
|
|||||||
border-color: #34c759;
|
border-color: #34c759;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-btn.refund {
|
||||||
|
color: #666;
|
||||||
|
border-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.cancel {
|
||||||
|
color: #ff6b6b;
|
||||||
|
border-color: #ff6b6b;
|
||||||
|
}
|
||||||
|
|
||||||
.action-btn.review {
|
.action-btn.review {
|
||||||
color: #ff9500;
|
color: #ff9500;
|
||||||
border-color: #ff9500;
|
border-color: #ff9500;
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ const viewOrder = () => {
|
|||||||
|
|
||||||
const goHome = () => {
|
const goHome = () => {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/index'
|
url: '/pages/main/index'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<!-- 支付页面 -->
|
<!-- 支付页面 -->
|
||||||
<template>
|
<template>
|
||||||
<view class="payment-page">
|
<view class="payment-page">
|
||||||
<view class="payment-content">
|
<scroll-view class="payment-content" direction="vertical">
|
||||||
<!-- 价格明细 -->
|
<!-- 价格明细 -->
|
||||||
<view class="price-detail-section">
|
<view class="price-detail-section">
|
||||||
<text class="section-title">价格明细</text>
|
<text class="section-title">价格明细</text>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<text class="forgot-password" @click="forgotPassword">忘记密码?</text>
|
<text class="forgot-password" @click="forgotPassword">忘记密码?</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</scroll-view>
|
||||||
|
|
||||||
<!-- 底部支付按钮 -->
|
<!-- 底部支付按钮 -->
|
||||||
<view class="payment-bottom">
|
<view class="payment-bottom">
|
||||||
@@ -614,8 +614,15 @@ onUnmounted(() => {
|
|||||||
.payment-page {
|
.payment-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.payment-header {
|
.payment-header {
|
||||||
|
|||||||
@@ -832,7 +832,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
goToCart() {
|
goToCart() {
|
||||||
uni.switchTab({ url: '/pages/mall/consumer/cart' })
|
uni.switchTab({ url: '/pages/main/cart' })
|
||||||
},
|
},
|
||||||
|
|
||||||
decreaseQuantity() {
|
decreaseQuantity() {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
const usePacket = (item: RedPacket) => {
|
const usePacket = (item: RedPacket) => {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/index'
|
url: '/pages/main/index'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
<!-- 评价页面 -->
|
<!-- 评价页面 -->
|
||||||
<template>
|
<template>
|
||||||
<view class="review-page">
|
<view class="review-page">
|
||||||
<!-- 顶部栏 -->
|
<!-- 顶部栏:已移除“发表评价”文字 -->
|
||||||
<view class="review-header">
|
<view class="review-header">
|
||||||
<text class="back-btn" @click="goBack">‹</text>
|
<view class="header-back" @click="goBack">
|
||||||
<text class="header-title">评价商品</text>
|
<image class="back-icon" src="/static/icons/back.png" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
<view class="header-title-placeholder"></view>
|
||||||
|
<view class="header-right"></view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view class="review-content" direction="vertical">
|
<scroll-view class="review-content" direction="vertical">
|
||||||
@@ -145,7 +148,6 @@
|
|||||||
<script setup lang="uts">
|
<script setup lang="uts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import supa from '@/components/supadb/aksupainstance.uts'
|
|
||||||
import { supabaseService } from '@/utils/supabaseService.uts'
|
import { supabaseService } from '@/utils/supabaseService.uts'
|
||||||
|
|
||||||
type OrderType = {
|
type OrderType = {
|
||||||
@@ -195,72 +197,58 @@ const isSubmitting = ref<boolean>(false)
|
|||||||
|
|
||||||
const loadOrderData = async (): Promise<void> => {
|
const loadOrderData = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const orderRes = await supa
|
console.log('[loadOrderData] 开始加载订单数据, orderId:', orderId.value)
|
||||||
.from('ml_orders')
|
|
||||||
.select('*')
|
|
||||||
.eq('id', orderId.value)
|
|
||||||
.single()
|
|
||||||
.execute()
|
|
||||||
|
|
||||||
if (orderRes.error != null) {
|
|
||||||
console.error('加载订单失败:', orderRes.error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orderRes.data != null) {
|
|
||||||
const orderData = orderRes.data as UTSJSONObject
|
|
||||||
order.value = {
|
|
||||||
id: orderData.getString('id') ?? '',
|
|
||||||
order_no: orderData.getString('order_no') ?? '',
|
|
||||||
created_at: orderData.getString('created_at') ?? '',
|
|
||||||
merchant_id: orderData.getString('merchant_id') ?? ''
|
|
||||||
} as OrderType
|
|
||||||
}
|
|
||||||
|
|
||||||
const itemsRes = await supa
|
|
||||||
.from('ml_order_items')
|
|
||||||
.select(`
|
|
||||||
*,
|
|
||||||
product:product_id(images)
|
|
||||||
`)
|
|
||||||
.eq('order_id', orderId.value)
|
|
||||||
.execute()
|
|
||||||
|
|
||||||
if (itemsRes.error != null) {
|
|
||||||
console.error('加载订单商品失败:', itemsRes.error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawData = itemsRes.data
|
|
||||||
let itemsArray: Array<any> = []
|
|
||||||
if (rawData != null) {
|
|
||||||
itemsArray = rawData as Array<any>
|
|
||||||
}
|
|
||||||
|
|
||||||
const processedItems: Array<OrderItemType> = []
|
// 使用 supabaseService 获取订单详情
|
||||||
for (let i: number = 0; i < itemsArray.length; i++) {
|
const orderDetailRaw = await supabaseService.getOrderDetail(orderId.value)
|
||||||
const item = itemsArray[i] as UTSJSONObject
|
console.log('[loadOrderData] orderDetailRaw:', JSON.stringify(orderDetailRaw))
|
||||||
const productObjRaw = item.get('product')
|
|
||||||
const productObj = (productObjRaw != null) ? (productObjRaw as UTSJSONObject) : null
|
if (orderDetailRaw == null) {
|
||||||
const imagesArrRaw = (productObj != null) ? productObj.get('images') : null
|
console.error('加载订单失败: 未找到订单')
|
||||||
const imagesArr = (imagesArrRaw != null) ? (imagesArrRaw as Array<string>) : []
|
uni.showToast({ title: '订单不存在', icon: 'none' })
|
||||||
const firstImage = (imagesArr.length > 0) ? imagesArr[0] : '/static/default-product.png'
|
return
|
||||||
const skuSpecRaw = item.get('sku_specifications')
|
|
||||||
const skuSpec = (skuSpecRaw != null) ? (skuSpecRaw as any) : null
|
|
||||||
const processedItem: OrderItemType = {
|
|
||||||
id: (item.getNumber('id') ?? 0) as number,
|
|
||||||
order_id: (item.getNumber('order_id') ?? 0) as number,
|
|
||||||
product_id: (item.getNumber('product_id') ?? 0) as number,
|
|
||||||
product_name: item.getString('product_name') ?? '',
|
|
||||||
price: (item.getNumber('price') ?? 0) as number,
|
|
||||||
quantity: (item.getNumber('quantity') ?? 1) as number,
|
|
||||||
sku_specifications: skuSpec,
|
|
||||||
product_image: firstImage
|
|
||||||
}
|
|
||||||
processedItems.push(processedItem)
|
|
||||||
}
|
}
|
||||||
orderItems.value = processedItems
|
|
||||||
|
|
||||||
|
// 转换为 UTSJSONObject
|
||||||
|
const orderDetail = JSON.parse(JSON.stringify(orderDetailRaw)) as UTSJSONObject
|
||||||
|
|
||||||
|
// 解析订单基本信息
|
||||||
|
order.value = {
|
||||||
|
id: orderDetail.getString('id') ?? '',
|
||||||
|
order_no: orderDetail.getString('order_no') ?? '',
|
||||||
|
created_at: orderDetail.getString('created_at') ?? '',
|
||||||
|
merchant_id: orderDetail.getString('merchant_id') ?? ''
|
||||||
|
} as OrderType
|
||||||
|
|
||||||
|
// 解析订单商品
|
||||||
|
const itemsRaw = orderDetail.get('ml_order_items')
|
||||||
|
console.log('[loadOrderData] itemsRaw:', JSON.stringify(itemsRaw))
|
||||||
|
|
||||||
|
if (itemsRaw != null) {
|
||||||
|
const itemsList = itemsRaw as any[]
|
||||||
|
const processedItems: Array<OrderItemType> = []
|
||||||
|
|
||||||
|
for (let i: number = 0; i < itemsList.length; i++) {
|
||||||
|
const itemStr = JSON.stringify(itemsList[i])
|
||||||
|
const item = JSON.parse(itemStr) as UTSJSONObject
|
||||||
|
const skuSpec = item.get('sku_specifications')
|
||||||
|
|
||||||
|
processedItems.push({
|
||||||
|
id: (item.getNumber('id') ?? 0) as number,
|
||||||
|
order_id: (item.getNumber('order_id') ?? 0) as number,
|
||||||
|
product_id: (item.getNumber('product_id') ?? 0) as number,
|
||||||
|
product_name: item.getString('product_name') ?? '',
|
||||||
|
price: (item.getNumber('price') ?? 0) as number,
|
||||||
|
quantity: (item.getNumber('quantity') ?? 1) as number,
|
||||||
|
sku_specifications: skuSpec,
|
||||||
|
product_image: item.getString('product_image') ?? item.getString('image_url') ?? '/static/default-product.png'
|
||||||
|
} as OrderItemType)
|
||||||
|
}
|
||||||
|
orderItems.value = processedItems
|
||||||
|
console.log('[loadOrderData] processedItems count:', processedItems.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化评价数据
|
||||||
const count = orderItems.value.length
|
const count = orderItems.value.length
|
||||||
const newRatings: Array<number> = []
|
const newRatings: Array<number> = []
|
||||||
const newContents: Array<string> = []
|
const newContents: Array<string> = []
|
||||||
@@ -274,23 +262,25 @@ const loadOrderData = async (): Promise<void> => {
|
|||||||
contents.value = newContents
|
contents.value = newContents
|
||||||
images.value = newImages
|
images.value = newImages
|
||||||
|
|
||||||
const orderObj = order.value as UTSJSONObject
|
// 获取商家信息
|
||||||
const merchantId = orderObj.getString('merchant_id')
|
const orderObj = order.value
|
||||||
if (merchantId != null && merchantId !== '') {
|
if (orderObj != null) {
|
||||||
const merchantRes = await supa
|
const merchantId = orderObj.merchant_id
|
||||||
.from('ml_shops')
|
if (merchantId != '') {
|
||||||
.select('id, shop_name, rating')
|
const shopInfo = await supabaseService.getShopByMerchantId(merchantId)
|
||||||
.eq('id', merchantId)
|
if (shopInfo != null) {
|
||||||
.single()
|
merchant.value = {
|
||||||
.execute()
|
id: shopInfo.id,
|
||||||
|
shop_name: shopInfo.shop_name,
|
||||||
if (merchantRes.error == null && merchantRes.data != null) {
|
rating: shopInfo.rating_avg ?? 5
|
||||||
merchant.value = merchantRes.data as MerchantType
|
} as MerchantType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('加载订单数据异常:', err)
|
console.error('加载订单数据异常:', err)
|
||||||
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,10 +312,19 @@ const formatTime = (timeStr?: string): string => {
|
|||||||
|
|
||||||
const getSpecText = (specs: any | null): string => {
|
const getSpecText = (specs: any | null): string => {
|
||||||
if (specs == null) return ''
|
if (specs == null) return ''
|
||||||
if (specs instanceof UTSJSONObject) {
|
if (typeof specs === 'string') return specs as string
|
||||||
return '规格信息'
|
|
||||||
|
try {
|
||||||
|
const specObj = JSON.parse(JSON.stringify(specs)) as UTSJSONObject
|
||||||
|
const jsonStr = JSON.stringify(specObj)
|
||||||
|
if (jsonStr == '{}' || jsonStr == 'null') return ''
|
||||||
|
|
||||||
|
// 简单解析:直接返回 JSON 字符串(去除大括号)
|
||||||
|
const cleanStr = jsonStr.replace(/^\{|\}$/g, '').replace(/"/g, '').replace(/:/g, ': ').replace(/,/g, '; ')
|
||||||
|
return cleanStr
|
||||||
|
} catch (e) {
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
return specs as string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取评分文本
|
// 获取评分文本
|
||||||
@@ -548,23 +547,37 @@ const goBack = (): void => {
|
|||||||
|
|
||||||
.review-header {
|
.review-header {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
padding: 15px;
|
padding: 10px 15px;
|
||||||
|
height: 44px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-back {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #e5e5e5;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-btn {
|
.back-icon {
|
||||||
font-size: 24px;
|
width: 20px;
|
||||||
color: #333333;
|
height: 20px;
|
||||||
padding: 5px;
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-title {
|
.header-title-placeholder {
|
||||||
font-size: 18px;
|
flex: 1;
|
||||||
font-weight: bold;
|
}
|
||||||
color: #333333;
|
|
||||||
|
.header-right {
|
||||||
|
width: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-content {
|
.review-content {
|
||||||
@@ -632,39 +645,46 @@ const goBack = (): void => {
|
|||||||
|
|
||||||
.rating-section {
|
.rating-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 20px;
|
||||||
|
padding: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-label {
|
.rating-label {
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
margin-right: 15px;
|
font-weight: 500;
|
||||||
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-stars {
|
.rating-stars {
|
||||||
display: flex;
|
display: flex;
|
||||||
/* gap: 10px; removed */
|
flex-direction: row;
|
||||||
}
|
align-items: center;
|
||||||
|
margin-right: 15px;
|
||||||
.rating-stars.small {
|
|
||||||
/* gap: 5px; removed */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.star-icon {
|
.star-icon {
|
||||||
font-size: 24px;
|
font-size: 26px;
|
||||||
color: #cccccc;
|
margin-right: 8px;
|
||||||
margin-right: 10px;
|
color: #e0e0e0;
|
||||||
|
transition: transform 0.1s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.star-icon.active {
|
.star-icon.active {
|
||||||
color: #ff5000;
|
color: #ff5000;
|
||||||
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-text {
|
.rating-text {
|
||||||
margin-left: 15px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666666;
|
color: #999999;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating-stars.small {
|
||||||
|
/* gap: 5px; removed */
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-section {
|
.content-section {
|
||||||
@@ -783,28 +803,49 @@ const goBack = (): void => {
|
|||||||
|
|
||||||
.merchant-section {
|
.merchant-section {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
padding: 15px;
|
padding: 20px 15px;
|
||||||
margin-bottom: 10px;
|
margin-top: 15px;
|
||||||
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
/* display: block; removed */
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: 600;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 20px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 4px solid #ff5000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.merchant-rating {
|
.merchant-rating {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 20px;
|
||||||
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rating-item {
|
.rating-item {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #333333;
|
color: #666666;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.merchant-rating .rating-stars.small {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.merchant-rating .rating-stars.small .star-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 5px;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.merchant-rating .rating-stars.small .star-icon.active {
|
||||||
|
color: #ff5000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tips-section {
|
.tips-section {
|
||||||
|
|||||||
@@ -821,7 +821,7 @@ const goBack = () => {
|
|||||||
} else {
|
} else {
|
||||||
// 如果只有一页(由于深链接或重定向),返回首页
|
// 如果只有一页(由于深链接或重定向),返回首页
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/index'
|
url: '/pages/main/index'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ onBackPress((options) => {
|
|||||||
// 无论是什么触发的返回(系统返回键或导航栏返回按钮),都跳转到profile
|
// 无论是什么触发的返回(系统返回键或导航栏返回按钮),都跳转到profile
|
||||||
// 注意:onBackPress 只能在 page 中使用,component 中无效
|
// 注意:onBackPress 只能在 page 中使用,component 中无效
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/mall/consumer/profile'
|
url: '/pages/main/profile'
|
||||||
})
|
})
|
||||||
// 返回 true 表示阻止默认返回行为
|
// 返回 true 表示阻止默认返回行为
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ const goToShop = (shop: FollowedShop): void => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const goHome = (): void => {
|
const goHome = (): void => {
|
||||||
uni.switchTab({ url: '/pages/mall/consumer/index' })
|
uni.switchTab({ url: '/pages/main/index' })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ const confirmSubscribe = async () => {
|
|||||||
if (ins != null && ins.error == null) {
|
if (ins != null && ins.error == null) {
|
||||||
uni.showToast({ title: '订阅成功', icon: 'success' })
|
uni.showToast({ title: '订阅成功', icon: 'success' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.redirectTo({ url: '/pages/mall/consumer/profile' })
|
uni.redirectTo({ url: '/pages/main/profile' })
|
||||||
}, 600)
|
}, 600)
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({ title: ins?.error?.message ?? '订阅失败', icon: 'none' })
|
uni.showToast({ title: ins?.error?.message ?? '订阅失败', icon: 'none' })
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
try {
|
try {
|
||||||
const sessionInfo = supa.getSession()
|
const sessionInfo = supa.getSession()
|
||||||
if (sessionInfo != null && sessionInfo.user != null) {
|
if (sessionInfo != null && sessionInfo.user != null) {
|
||||||
uni.reLaunch({ url: '/pages/mall/consumer/index' })
|
uni.reLaunch({ url: '/pages/main/index' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -182,12 +182,12 @@ const checkLoginStatus = (): void => {
|
|||||||
const opts = currentPage.options as UTSJSONObject
|
const opts = currentPage.options as UTSJSONObject
|
||||||
const redirect = opts.getString('redirect')
|
const redirect = opts.getString('redirect')
|
||||||
if (redirect != null && redirect != '') {
|
if (redirect != null && redirect != '') {
|
||||||
uni.reLaunch({ url: `/pages/mall/consumer/index` })
|
uni.reLaunch({ url: `/pages/main/index` })
|
||||||
} else {
|
} else {
|
||||||
uni.reLaunch({ url: '/pages/mall/consumer/index' })
|
uni.reLaunch({ url: '/pages/main/index' })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.reLaunch({ url: '/pages/mall/consumer/index' })
|
uni.reLaunch({ url: '/pages/main/index' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -291,7 +291,7 @@ const handleLogin = async () => {
|
|||||||
|
|
||||||
uni.showToast({ title: '管理员登录成功', icon: 'success' })
|
uni.showToast({ title: '管理员登录成功', icon: 'success' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.reLaunch({ url: '/pages/mall/consumer/index' })
|
uni.reLaunch({ url: '/pages/main/index' })
|
||||||
}, 500)
|
}, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -360,7 +360,7 @@ const handleLogin = async () => {
|
|||||||
|
|
||||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.reLaunch({ url: '/pages/mall/consumer/index' })
|
uni.reLaunch({ url: '/pages/main/index' })
|
||||||
}, 500)
|
}, 500)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('登录错误:', err)
|
console.error('登录错误:', err)
|
||||||
|
|||||||
25
project.config.json
Normal file
25
project.config.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"setting": {
|
||||||
|
"es6": true,
|
||||||
|
"postcss": true,
|
||||||
|
"minified": true,
|
||||||
|
"uglifyFileName": false,
|
||||||
|
"enhance": true,
|
||||||
|
"packNpmRelationList": [],
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
},
|
||||||
|
"useCompilerPlugins": false,
|
||||||
|
"minifyWXML": true
|
||||||
|
},
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"simulatorPluginLibVersion": {},
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [],
|
||||||
|
"include": []
|
||||||
|
},
|
||||||
|
"appid": "wxe98d61426b6456c1",
|
||||||
|
"editorSetting": {}
|
||||||
|
}
|
||||||
14
project.private.config.json
Normal file
14
project.private.config.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"libVersion": "3.14.2",
|
||||||
|
"projectname": "mall",
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": true,
|
||||||
|
"coverView": true,
|
||||||
|
"lazyloadPlaceholderEnable": false,
|
||||||
|
"skylineRenderEnable": false,
|
||||||
|
"preloadBackgroundData": false,
|
||||||
|
"autoAudits": false,
|
||||||
|
"showShadowRootInWxmlPanel": true,
|
||||||
|
"compileHotReLoad": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -194,11 +194,12 @@ export class AkReq {
|
|||||||
resolve(result);
|
resolve(result);
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
|
const errStatus = (err.errCode != null && typeof err.errCode === 'number') ? err.errCode : 0;
|
||||||
const result = AkReq.createResponse<any>(
|
const result = AkReq.createResponse<any>(
|
||||||
err.errCode,
|
errStatus,
|
||||||
err.data ?? {},
|
|
||||||
{} as UTSJSONObject,
|
{} as UTSJSONObject,
|
||||||
new UniError('uni-request', err.errCode, err.errMsg ?? 'request fail')
|
{} as UTSJSONObject,
|
||||||
|
new UniError('uni-request', errStatus, err.errMsg ?? 'request fail')
|
||||||
);
|
);
|
||||||
resolve(result);
|
resolve(result);
|
||||||
}
|
}
|
||||||
@@ -302,11 +303,12 @@ export class AkReq {
|
|||||||
resolve(result);
|
resolve(result);
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
|
const errStatus = (err.errCode != null && typeof err.errCode === 'number') ? err.errCode : 0;
|
||||||
const result = AkReq.createResponse<any>(
|
const result = AkReq.createResponse<any>(
|
||||||
err.errCode,
|
errStatus,
|
||||||
err.data ?? {},
|
|
||||||
{} as UTSJSONObject,
|
{} as UTSJSONObject,
|
||||||
new UniError('uni-upload', err.errCode, err.errMsg ?? 'upload fail')
|
{} as UTSJSONObject,
|
||||||
|
new UniError('uni-upload', errStatus, err.errMsg ?? 'upload fail')
|
||||||
);
|
);
|
||||||
resolve(result);
|
resolve(result);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user