diff --git a/layouts/admin/router/adminComponentMap.uts b/layouts/admin/router/adminComponentMap.uts index cc91eca9..99df4580 100644 --- a/layouts/admin/router/adminComponentMap.uts +++ b/layouts/admin/router/adminComponentMap.uts @@ -18,6 +18,10 @@ import PlaceholderPage from '@/layouts/admin/components/PlaceholderPage.uvue' import HomeIndex from '@/layouts/admin/pages/HomeIndex.uvue' import UserCenter from '@/pages/mall/admin/userCenter/index.uvue' +// --- 店铺模块 --- +import ShopManage from '@/pages/mall/admin/shop/manage.uvue' +import ShopCreate from '@/pages/mall/admin/shop/create.uvue' + // --- 用户模块 --- import UserStatistic from '@/pages/mall/admin/user/statistics/index.uvue' import UserList from '@/pages/mall/admin/user/management/index.uvue' @@ -180,8 +184,12 @@ import MaintainSysInfo from '@/pages/mall/admin/maintain/sys/info.uvue' export const componentMap: Map = new Map([ // 首页 ['HomeIndex', HomeIndex], - ['UserCenter', UserCenter], - + ['UserCenter', UserCenter], + + // 店铺模块 + ['ShopManage', ShopManage], + ['ShopCreate', ShopCreate], + // 用户模块 ['UserStatistic', UserStatistic], ['UserList', UserList], diff --git a/layouts/admin/router/adminRoutes.uts b/layouts/admin/router/adminRoutes.uts index e64e412c..490ae930 100644 --- a/layouts/admin/router/adminRoutes.uts +++ b/layouts/admin/router/adminRoutes.uts @@ -67,12 +67,22 @@ export const topMenus: TopMenu[] = [ order: 1, groups: [] }, + { + id: 'shop', + title: '店铺', + icon: 'shop', + path: '/pages/mall/admin/shop/manage', + order: 2, + groups: [ + { id: 'shop-manage', title: '', order: 1 } + ] + }, { id: 'user', title: '用户', icon: 'user', path: '/pages/mall/admin/user/management/index', - order: 2, + order: 3, groups: [ { id: 'user-manage', title: '', order: 1 } ] @@ -233,6 +243,27 @@ export const routes: RouteRecord[] = [ order: 1 }, + // ========== 店铺模块 ========== + { + id: 'shop_manage', + title: '店铺管理', + path: '/pages/mall/admin/shop/manage', + componentKey: 'ShopManage', + parentId: 'shop', + groupId: 'shop-manage', + order: 1 + }, + { + id: 'shop_create', + title: '申请入驻', + path: '/pages/mall/admin/shop/create', + componentKey: 'ShopCreate', + parentId: 'shop', + groupId: 'shop-manage', + hidden: true, + order: 2 + }, + // ========== 用户模块 ========== // ========== 个人中心 ========== { diff --git a/layouts/admin/utils/role.uts b/layouts/admin/utils/role.uts index 9689ff10..c7e2ec31 100644 --- a/layouts/admin/utils/role.uts +++ b/layouts/admin/utils/role.uts @@ -98,11 +98,11 @@ export async function refreshAdminRole(): Promise { export function getVisibleTopMenuIds(role: string): string[] { const normRole = normalizeRole(role) if (normRole === 'admin') { - return ['home', 'user', 'order', 'product', 'marketing', 'distribution', 'kefu', 'finance', 'cms', 'decoration', 'app', 'setting', 'maintain'] + return ['home', 'shop', 'user', 'order', 'product', 'marketing', 'distribution', 'kefu', 'finance', 'cms', 'decoration', 'app', 'setting', 'maintain'] } if (normRole === 'merchant') { - return ['home', 'order', 'product', 'marketing', 'finance'] + return ['home', 'shop', 'order', 'product', 'marketing', 'finance'] } return ['home'] @@ -123,7 +123,7 @@ export function hasAdminModuleAccess(moduleId: string | undefined): boolean { } if (normRole === 'merchant') { - const allowed = ['home', 'order', 'product', 'marketing', 'finance'] + const allowed = ['home', 'shop', 'order', 'product', 'marketing', 'finance'] return allowed.includes(moduleId) } diff --git a/pages/mall/admin/product/product-management/edit.uvue b/pages/mall/admin/product/product-management/edit.uvue index 4efa8086..fca3ec19 100644 --- a/pages/mall/admin/product/product-management/edit.uvue +++ b/pages/mall/admin/product/product-management/edit.uvue @@ -160,10 +160,19 @@ import { ref, onMounted } from 'vue' import { openRoute } from '@/layouts/admin/store/adminNavStore.uts' import supa, { ensureSupabaseReady } from '@/components/supadb/aksupainstance' +import { SUPA_URL } from '@/ak/config.uts' const activeStep = ref(0) const steps = ['基础信息', '规格库存', '商品详情', '物流设置', '会员价/佣金', '营销设置', '其他设置'] +interface CategoryOption { + id: string + name: string +} +const categoryOptions = ref([]) +const categories = ref([]) +const categoryName = ref('') + const formData = ref({ id: '', merchant_id: '', @@ -181,9 +190,6 @@ const formData = ref({ published_at: null as string | null }) -const categories = ref(['361度', '特步', '匹克', '生活家居']) -const categoryName = ref('') - onMounted(async () => { await ensureSupabaseReady() const mId = supa.getSession().user?.id as string | null @@ -193,6 +199,9 @@ onMounted(async () => { } formData.value.merchant_id = mId + // 加载真实分类 + await loadCategoryOptions() + const editId = uni.getStorageSync('edit_product_id') as string | null if (editId) { uni.removeStorageSync('edit_product_id') @@ -200,6 +209,27 @@ onMounted(async () => { } }) +async function loadCategoryOptions() { + try { + const res = await supa.from('ml_categories') + .select('id, name') + .eq('is_active', true) + .order('sort_order', { ascending: true }) + .execute() + + if (res.data != null) { + const data = res.data as Array + categoryOptions.value = data.map((item: UTSJSONObject): CategoryOption => ({ + id: item.get('id') as string, + name: item.get('name') as string + })) + categories.value = categoryOptions.value.map((item: CategoryOption): string => item.name) + } + } catch (e) { + console.error('加载分类失败', e) + } +} + async function fetchProductDetail(id: string, mId: string) { try { const { data, error } = await supa @@ -228,8 +258,11 @@ async function fetchProductDetail(id: string, mId: string) { } // Try to map category - formData.value.category_id = data.category_id || '' - categoryName.value = data.category_id ? '已绑定分类' : '' + formData.value.category_id = data.category_id as string || '' + if (formData.value.category_id) { + const cat = categoryOptions.value.find((c: CategoryOption): boolean => c.id === formData.value.category_id) + categoryName.value = cat ? cat.name : '未知分类' + } } } catch (e) { console.error('获取详情失败', e) @@ -239,9 +272,9 @@ async function fetchProductDetail(id: string, mId: string) { function onCategoryChange(e: any) { const v = e.detail.value as number - categoryName.value = categories.value[v] - // In a real project, this maps to an actual category ID, but for now we use a mock one - formData.value.category_id = `cat_${v}` + const selected = categoryOptions.value[v] + categoryName.value = selected.name + formData.value.category_id = selected.id } function addTag() { @@ -305,16 +338,13 @@ async function uploadToSupabase(filePath: string): Promise { uni.showLoading({ title: '上传中...' }) try { - const { data, error } = await supa.storage.from('zhipao').upload(remotePath, filePath, {}) - if (error) { - throw error + const res = await supa.storage.from('zhipao').upload(remotePath, filePath, {}) + if (res.error != null) { + throw res.error } - const urlKey = typeof data === 'object' ? (data as any)['Key'] || (data as any)['path'] : '' - // fallback logic, generally Supabase uses 'storage/v1/object/public/bucket/' + path - if (urlKey) { - return `https://ak3.oulog.com/storage/v1/object/public/${urlKey}` - } - return '' + + return `${SUPA_URL}/storage/v1/object/public/zhipao/${remotePath}` + } catch (e: any) { console.error('上传文件失败:', e) throw new Error(e.message || '上传异常') diff --git a/pages/mall/admin/product/product-management/index.uvue b/pages/mall/admin/product/product-management/index.uvue index b638ce25..21c4efd0 100644 --- a/pages/mall/admin/product/product-management/index.uvue +++ b/pages/mall/admin/product/product-management/index.uvue @@ -1,5 +1,19 @@  + + diff --git a/pages/mall/admin/shop/manage.uvue b/pages/mall/admin/shop/manage.uvue new file mode 100644 index 00000000..cc81b110 --- /dev/null +++ b/pages/mall/admin/shop/manage.uvue @@ -0,0 +1,860 @@ + + + + + +