From 59141048510ed6475c504f0a59b948f4ed7d6568 Mon Sep 17 00:00:00 2001 From: huangzhenbao <17818024429@163.com> Date: Sat, 14 Mar 2026 00:16:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=BC=96=E8=BE=91=E5=95=86?= =?UTF-8?q?=E5=93=81=E4=BF=A1=E6=81=AF=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manifest.json | 144 +++++++++--------- .../product/product-management/edit.uvue | 91 +++++++---- services/analytics/dataDetailService.uts | 48 ++++++ vite.config.js | 11 +- 4 files changed, 186 insertions(+), 108 deletions(-) diff --git a/manifest.json b/manifest.json index 98b47747..052d5646 100644 --- a/manifest.json +++ b/manifest.json @@ -1,74 +1,74 @@ { - "name": "mall", - "appid": "__UNI__YOUR_APP_ID__", - "description": "A multi-role e-commerce application.", - "versionName": "1.0.0", - "versionCode": "100", - "transformPx": false, - "app-plus": { - "usingComponents": true, - "nvueStyleCompiler": "uni-app", - "compilerVersion": 3, - "splashscreen": { - "alwaysShowBeforeRender": true, - "waiting": true, - "autoclose": true, - "delay": 0 - }, - "modules": {}, - "distribute": { - "android": { - "permissions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - }, - "ios": {}, - "sdkConfigs": {} - } - }, - "quickapp": {}, - "mp-weixin": { - "appid": "", - "setting": { - "urlCheck": false - }, - "usingComponents": true - }, - "mp-alipay": { - "usingComponents": true - }, - "mp-baidu": { - "usingComponents": true - }, - "mp-toutiao": { - "usingComponents": true - }, - "uniStatistics": { - "enable": false - }, - "vueVersion": "3", - "uni-app-x": {}, - "h5": { - "title": "mall", - "router": { - "mode": "hash", - "base": "./" - } - } + "name": "mall", + "appid": "__UNI__81482FF", + "description": "A multi-role e-commerce application.", + "versionName": "1.0.0", + "versionCode": "100", + "transformPx": false, + "app-plus": { + "usingComponents": true, + "nvueStyleCompiler": "uni-app", + "compilerVersion": 3, + "splashscreen": { + "alwaysShowBeforeRender": true, + "waiting": true, + "autoclose": true, + "delay": 0 + }, + "modules": {}, + "distribute": { + "android": { + "permissions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios": {}, + "sdkConfigs": {} + } + }, + "quickapp": {}, + "mp-weixin": { + "appid": "", + "setting": { + "urlCheck": false + }, + "usingComponents": true + }, + "mp-alipay": { + "usingComponents": true + }, + "mp-baidu": { + "usingComponents": true + }, + "mp-toutiao": { + "usingComponents": true + }, + "uniStatistics": { + "enable": false + }, + "vueVersion": "3", + "uni-app-x": {}, + "h5": { + "title": "mall", + "router": { + "mode": "hash", + "base": "./" + } + } } \ No newline at end of file diff --git a/pages/mall/admin/product/product-management/edit.uvue b/pages/mall/admin/product/product-management/edit.uvue index d867fcbf..8f86ea97 100644 --- a/pages/mall/admin/product/product-management/edit.uvue +++ b/pages/mall/admin/product/product-management/edit.uvue @@ -2,7 +2,7 @@ - {"<"} + < 返回 编辑商品 @@ -232,41 +232,76 @@ async function loadCategoryOptions() { async function fetchProductDetail(id: string, mId: string) { try { - const { data, error } = await supa + const res = await supa .from('ml_products') .select('*') .eq('id', id) .eq('merchant_id', mId) .single() + .execute() - if (error) throw error - if (data) { - formData.value.id = data.id - formData.value.name = data.name || '' - formData.value.base_price = data.base_price || 0 - formData.value.available_stock = data.available_stock || 0 - formData.value.total_stock = data.total_stock || data.available_stock || 0 - formData.value.status = data.status || 1 - formData.value.main_image_url = data.main_image_url || '' - formData.value.image_urls = data.image_urls || [] - formData.value.video_urls = data.video_urls || [] - formData.value.tags = data.tags || [] - - if (data.attributes && typeof data.attributes === 'object') { - const attrs = data.attributes as Record - formData.value.attributes.unit = attrs['unit'] || '件' - } - - // Try to map category - 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 : '未知分类' + if (res.error != null) { + console.error('[ProductEdit] 查询失败:', res.error) + uni.showToast({ title: '获取商品信息失败,或者无权限编辑', icon: 'none' }) + return + } + + // .single() 返回时 data 可能是 UTSJSONObject 或包含一条记录的数组,兼容处理 + let row : UTSJSONObject | null = null + if (res.data != null) { + const raw = res.data + if (Array.isArray(raw)) { + const arr = raw as Array + if (arr.length > 0) row = arr[0] as UTSJSONObject + } else { + row = raw as UTSJSONObject } } - } catch (e) { - console.error('获取详情失败', e) - uni.showToast({ title: '获取商品信息失败,或者无权限编辑', icon: 'none' }) + + if (row == null) { + uni.showToast({ title: '未找到该商品', icon: 'none' }) + return + } + + formData.value.id = row.getString('id') ?? '' + formData.value.name = row.getString('name') ?? '' + formData.value.base_price = row.getNumber('base_price') ?? 0 + formData.value.available_stock = row.getNumber('available_stock') ?? 0 + formData.value.total_stock = row.getNumber('total_stock') ?? row.getNumber('available_stock') ?? 0 + formData.value.status = row.getNumber('status') ?? 1 + formData.value.main_image_url = row.getString('main_image_url') ?? '' + formData.value.category_id = row.getString('category_id') ?? '' + + // image_urls / video_urls / tags 是 JSONB 数组,用 .get() 取原始值再强转 + const imgRaw = row.get('image_urls') + if (imgRaw != null && Array.isArray(imgRaw)) { + formData.value.image_urls = imgRaw as string[] + } + const vidRaw = row.get('video_urls') + if (vidRaw != null && Array.isArray(vidRaw)) { + formData.value.video_urls = vidRaw as string[] + } + const tagsRaw = row.get('tags') + if (tagsRaw != null && Array.isArray(tagsRaw)) { + formData.value.tags = tagsRaw as string[] + } + + // attributes JSONB 是对象,用 getJSON 取 + const attrsRaw = row.getJSON('attributes') + if (attrsRaw != null) { + formData.value.attributes.unit = attrsRaw.getString('unit') ?? '件' + } + + // 同步分类名称 + if (formData.value.category_id) { + const cat = categoryOptions.value.find((c: CategoryOption): boolean => c.id === formData.value.category_id) + categoryName.value = cat ? cat.name : '' + } + + console.log('[ProductEdit] 加载成功,id=', formData.value.id, 'name=', formData.value.name) + } catch (e : any) { + console.error('[ProductEdit] 获取详情异常:', e) + uni.showToast({ title: '获取商品信息失败', icon: 'none' }) } } diff --git a/services/analytics/dataDetailService.uts b/services/analytics/dataDetailService.uts index 6a3065cf..46811c43 100644 --- a/services/analytics/dataDetailService.uts +++ b/services/analytics/dataDetailService.uts @@ -41,6 +41,54 @@ export async function fetchReportRows(reportId: string, params: any): Promise) : ([] as Array) } +// 供 data-detail.uvue 使用:包含 period 字段的报表信息 +export type DataDetailReportInfo = { + id: string + title: string + description: string + definition: any + updated_at: string + period: string +} + +export async function fetchDataDetailReportInfo(reportId: string): Promise { + const row = await rpcOrNull('rpc_data_detail_report_info', { + p_report_id: reportId + } as any) + + if (row == null) return null + + return { + id: safeString(row.getAny?.('id')), + title: safeString(row.getAny?.('title')), + description: safeString(row.getAny?.('description')), + definition: row.getAny?.('definition'), + updated_at: safeString(row.getAny?.('updated_at')), + period: safeString(row.getAny?.('period')) + } +} + +// 供 data-detail.uvue 使用:支持排序和分页参数 +export async function fetchDataDetailRows( + reportId: string, + sortKey: string, + sortDir: string, + limit: number, + offset: number +): Promise> { + const result = await rpcOrNull('rpc_data_detail_rows', { + p_report_id: reportId, + p_sort_key: sortKey, + p_sort_dir: sortDir, + p_limit: limit, + p_offset: offset + } as any) + + if (result == null) return [] + const anyData = result as any + return Array.isArray(anyData) ? (anyData as Array) : ([] as Array) +} + // 保留调用,但 RPC 是模拟数据 export async function fetchDrilldown(reportId: string, itemId: string): Promise> { return await rpcOrEmptyArray('rpc_data_detail_drill_items', { diff --git a/vite.config.js b/vite.config.js index a9053208..9286707c 100644 --- a/vite.config.js +++ b/vite.config.js @@ -13,18 +13,13 @@ export default defineConfig({ // 生产环境构建配置 rollupOptions: { output: { - // 手动拆包策略:将第三方库拆分成独立文件,减少首屏主包体积 + // 将 vue + @dcloudio 合并到同一个 chunk,避免拆包后循环依赖导致 TDZ 错误 + // ("Cannot access '?' before initialization" in vendor-vue chunk) manualChunks(id) { if (id.includes("node_modules")) { - // 将 vue 相关依赖拆分到 vendor-vue - if (id.includes("vue")) { + if (id.includes("vue") || id.includes("@dcloudio")) { return "vendor-vue"; } - // 将 dcloudio (uni-app) 相关依赖拆分 - if (id.includes("@dcloudio")) { - return "vendor-uni"; - } - // 其他 node_modules 依赖放入 vendor return "vendor"; } },