完成店铺创建
This commit is contained in:
@@ -1,5 +1,19 @@
|
||||
<template>
|
||||
<view class="product-list-page">
|
||||
<!-- 店铺门禁:无店铺时显示空态 -->
|
||||
<view v-if="shopLoading" class="shop-guard-loading">
|
||||
<text class="sgl-txt">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!hasShop" class="shop-guard-empty">
|
||||
<text class="sge-icon">🏦</text>
|
||||
<text class="sge-title">您还没有店铺</text>
|
||||
<text class="sge-desc">先创建店铺,才能发布商品</text>
|
||||
<button class="sge-btn" @click="goCreateShop">立即创建店铺</button>
|
||||
</view>
|
||||
|
||||
<!-- 正常商品列表 -->
|
||||
<template v-else>
|
||||
<!-- 1. 搜索表单 -->
|
||||
<view class="search-card">
|
||||
<view class="search-row">
|
||||
@@ -158,15 +172,19 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { openRoute } from '@/layouts/admin/store/adminNavStore.uts'
|
||||
import StatusSwitch from '@/components/StatusSwitch.uvue'
|
||||
import supa, { ensureSupabaseReady } from '@/components/supadb/aksupainstance'
|
||||
|
||||
const hasShop = ref(false)
|
||||
const shopLoading = ref(true)
|
||||
|
||||
const total = ref(0)
|
||||
const activeStatus = ref('selling')
|
||||
const activeDropdownId = ref<number | null>(null)
|
||||
@@ -181,13 +199,64 @@ const statusTabs = ref([
|
||||
|
||||
const productList = ref<any[]>([])
|
||||
|
||||
onMounted(() => {
|
||||
// 监听 activeStatus 变化
|
||||
watch(activeStatus, () => {
|
||||
fetchProducts()
|
||||
})
|
||||
|
||||
// 商品模块店铺门禁
|
||||
onMounted(async () => {
|
||||
await checkShop()
|
||||
uni.$on('REFRESH_PRODUCT_LIST', () => {
|
||||
fetchProducts()
|
||||
})
|
||||
})
|
||||
|
||||
async function checkShop() {
|
||||
shopLoading.value = true
|
||||
try {
|
||||
await ensureSupabaseReady()
|
||||
const userId = supa.getSession().user?.getString('id')
|
||||
if (!userId) {
|
||||
hasShop.value = false
|
||||
shopLoading.value = false
|
||||
return
|
||||
}
|
||||
// 查询 ml_shops 确认当前用户是否已建店
|
||||
const res = await supa.from('ml_shops')
|
||||
.select('merchant_id, shop_name, status')
|
||||
.eq('merchant_id', userId)
|
||||
.single()
|
||||
.execute()
|
||||
|
||||
if (res.error != null || !res.data) {
|
||||
hasShop.value = false
|
||||
} else {
|
||||
const rawData = res.data
|
||||
let shopRow: UTSJSONObject | null = null
|
||||
if (Array.isArray(rawData)) {
|
||||
shopRow = (rawData as Array<UTSJSONObject>).length > 0 ? (rawData as Array<UTSJSONObject>)[0] : null
|
||||
} else {
|
||||
shopRow = rawData as UTSJSONObject
|
||||
}
|
||||
hasShop.value = shopRow != null
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.warn('[ProductList] 店铺检查异常:', e)
|
||||
hasShop.value = false
|
||||
} finally {
|
||||
shopLoading.value = false
|
||||
}
|
||||
|
||||
if (hasShop.value) {
|
||||
fetchProducts()
|
||||
}
|
||||
}
|
||||
|
||||
function goCreateShop() {
|
||||
openRoute('shop_manage')
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off('REFRESH_PRODUCT_LIST')
|
||||
})
|
||||
@@ -196,8 +265,8 @@ onUnmounted(() => {
|
||||
async function fetchProducts() {
|
||||
await ensureSupabaseReady()
|
||||
|
||||
// 从本地缓存获取 current merchant_id
|
||||
const currentMerchantId = supa.getSession().user?.id as string | null
|
||||
// merchant_id 来自 ml_shops 所关联的 ak_users.id(即 auth user id)
|
||||
const currentMerchantId = supa.getSession().user?.getString('id')
|
||||
|
||||
if (!currentMerchantId) {
|
||||
uni.showToast({ title: '未获取到商家信息,请重新登录', icon: 'none' })
|
||||
@@ -205,37 +274,62 @@ async function fetchProducts() {
|
||||
}
|
||||
|
||||
try {
|
||||
const { data, error, count } = await supa
|
||||
const query = supa
|
||||
.from('ml_products')
|
||||
.select('id, name, main_image_url, base_price, available_stock, status, created_at', { count: 'exact' })
|
||||
.eq('merchant_id', currentMerchantId)
|
||||
.order('created_at', { ascending: false })
|
||||
|
||||
// 根据 activeStatus 过滤
|
||||
// 1:上架 2:下架 3:草稿 4:删除
|
||||
// selling: 1, warehouse: 2+3, soldout: stock=0, alarm: stock<10, recycle: 4
|
||||
if (activeStatus.value === 'selling') {
|
||||
query.eq('status', 1)
|
||||
} else if (activeStatus.value === 'warehouse') {
|
||||
query.in('status', [2, 3])
|
||||
} else if (activeStatus.value === 'recycle') {
|
||||
query.eq('status', 4)
|
||||
} else if (activeStatus.value === 'soldout') {
|
||||
query.eq('available_stock', 0)
|
||||
} else if (activeStatus.value === 'alarm') {
|
||||
query.lt('available_stock', 10)
|
||||
}
|
||||
|
||||
const { data, error, count } = await query.order('created_at', { ascending: false }).execute()
|
||||
|
||||
if (error) {
|
||||
console.error('Fetch products error:', error)
|
||||
uni.showToast({ title: '加载失败: ' + error.message, icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
if (data) {
|
||||
productList.value = data.map((item: any) => {
|
||||
if (data != null) {
|
||||
const dataArray = data as Array<UTSJSONObject>
|
||||
productList.value = dataArray.map((item: UTSJSONObject): any => {
|
||||
return {
|
||||
id: item.id,
|
||||
image: item.main_image_url || '',
|
||||
name: item.name || '未命名商品',
|
||||
id: item.get('id'),
|
||||
image: item.get('main_image_url') || '',
|
||||
name: item.get('name') || '未命名商品',
|
||||
activities: [],
|
||||
typeName: '普通商品',
|
||||
price: item.base_price !== null ? Number(item.base_price).toFixed(2) : '0.00',
|
||||
price: item.get('base_price') != null ? Number(item.get('base_price')).toFixed(2) : '0.00',
|
||||
sales: 0,
|
||||
stock: item.available_stock || 0,
|
||||
stock: item.get('available_stock') || 0,
|
||||
sort: 0,
|
||||
status: item.status || 0
|
||||
status: item.get('status') || 0
|
||||
}
|
||||
})
|
||||
total.value = count || dataArray.length
|
||||
|
||||
// 更新 Tab 计数 (简单同步当前列表总数到对应 Tab)
|
||||
statusTabs.value.forEach(tab => {
|
||||
if (tab.key === activeStatus.value) {
|
||||
tab.count = total.value
|
||||
}
|
||||
})
|
||||
total.value = count || data.length
|
||||
}
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
console.error('获取商品列表失败:', err)
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
uni.showToast({ title: '加载失败: ' + (err.message || ''), icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,6 +377,41 @@ function moveToRecycle(id: number) {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
/* 店铺门禁状态 */
|
||||
.shop-guard-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 200px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.sgl-txt { font-size: 14px; color: #999; }
|
||||
|
||||
.shop-guard-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 80px 40px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.sge-icon { font-size: 56px; margin-bottom: 16px; }
|
||||
.sge-title { font-size: 18px; font-weight: 600; color: #333; margin-bottom: 8px; }
|
||||
.sge-desc { font-size: 13px; color: #999; margin-bottom: 28px; }
|
||||
.sge-btn {
|
||||
padding: 0 32px;
|
||||
height: 40px;
|
||||
background: #1890ff;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.search-card {
|
||||
background: #fff;
|
||||
padding: var(--admin-card-padding);
|
||||
@@ -590,3 +719,5 @@ function moveToRecycle(id: number) {
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user