Przeglądaj źródła

chore(menu): 提交菜单方案A本地兜底占位及 ProductEdit 修复(部署前整合)

Xiaogang Liao 1 tydzień temu
rodzic
commit
85b9ad0d24

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-770a6ac4a2dcad36f7675b5cd08a4ebafcc01bb0
+a3e3c3a56577b827887c6a472a85344c72633b0c

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.1589",
+  "version": "1.0.1590",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 50 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,56 @@
 
 ---
 
+## v1.0.1590 (2026-10-12)
+
+### Bug 修复
+- 本地菜单补齐菜单管理入口,简化 effectiveMenuItems 清理废弃 dynamicMenuItems
+- 登录浮层面板高度降为 85vh(更紧凑)
+- 登录浮层四步闭环单行显示(防止四字文本换行)
+- 登录浮层点击协议复选框不再关闭
+
+### 文档
+- update health education knowledge base documentation for 2026 Q4
+
+### 其他
+- - .loop-pill-text 加 white-space:nowrap,四字步骤强制单行
+- - .loop-arrow 加 flex-shrink:0,箭头不被压缩
+- - 适配 750rpx 屏宽,四个 pill + 三个箭头容纳一行
+- 
+- - 面板根 view 加 @click.stop,阻止内部点击(含 checkbox)冒泡到遮罩
+- - 保留:点击遮罩空白区才关闭浮层
+- 
+- - 新增 mixins/login-sheet.js:全局 mixin(openLoginSheet 沿 $parent 链查找宿主 ref,已登录守卫、未挂浮层回退整页登录)
+- - main.js:全局注册 login-sheet 组件 + 注入 loginSheetMixin
+- - 9 个页面接入 login-sheet 组件
+- - 修复:面板高度足够显示协议行;四步闭环与五维标签强制单行显示(flex-wrap: nowrap + margin 替代 gap)
+- - DimensionVisitorCard.vue:登录引导卡片,支持通过 openLoginSheet 唤起浮层
+- 
+- resolve last_build_commit conflict
+- 
+- 
+- 
+- 
+- - 新增 api/reportParse.js;注册路由 report-parse-status 与侧边菜单
+- - npm run build 产物版本 1.0.1588
+- 
+- - LangGraphReportParseService 新增 parseByScriptWithReason 保留失败原因,专用 RestTemplate 读超时放宽至 300s
+- - health_report_drafts 新增 parse_attempt/next_retry_at/parse_started_at/parse_finished_at(迁移364 + schema.sql)
+- - 新增 /api/admin/report-parse list|retry|backfill-food 及 reparseReportFoods(只覆盖 payload_json.foods)
+- - buildFoodsFromPayload 跳过空/无名称食材;saveFoodsForReport 先删后插保证幂等;入库前幂等守卫
+- 
+
+### 新功能
+- 登录页改造为底部滑出浮层(login-sheet)
+- gut-flora-risks-detail.vue 展示 relatedBacteria 与 gut-flora-detail.vue gutStatusLevel 微标(P0+P1 完整)
+- pdf_parser.py 北京菌群 related_bacteria/gutStatusLevel 解析 + report_parse_agent.py schema 扩展
+- ReportCollectService 与 LangGraphReportParseService 映射 gutStatusLevel 与 relatedBacteria,实现 P0+P1 完整链路
+- 知识库指标章节白名单扩展(报告指标知识库.json)
+- 健康报告采集扩展疾病关联菌和肠道菌群状态字段(实体/迁移)
+- 新增报告解析进度页面(查看/重试/回填)
+- 已知类型解析失败退避重试 + 解析进度后台可见 + 食材回填
+
+
 ## v1.0.1589 (2026-10-12)
 
 ### 新功能

+ 51 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.1589
+> 当前版本: v1.0.1590
 
 ## 历史版本
 
@@ -8,6 +8,56 @@
 
 ---
 
+## v1.0.1590 (2026-10-12)
+
+### Bug 修复
+- 本地菜单补齐菜单管理入口,简化 effectiveMenuItems 清理废弃 dynamicMenuItems
+- 登录浮层面板高度降为 85vh(更紧凑)
+- 登录浮层四步闭环单行显示(防止四字文本换行)
+- 登录浮层点击协议复选框不再关闭
+
+### 文档
+- update health education knowledge base documentation for 2026 Q4
+
+### 其他
+- - .loop-pill-text 加 white-space:nowrap,四字步骤强制单行
+- - .loop-arrow 加 flex-shrink:0,箭头不被压缩
+- - 适配 750rpx 屏宽,四个 pill + 三个箭头容纳一行
+- 
+- - 面板根 view 加 @click.stop,阻止内部点击(含 checkbox)冒泡到遮罩
+- - 保留:点击遮罩空白区才关闭浮层
+- 
+- - 新增 mixins/login-sheet.js:全局 mixin(openLoginSheet 沿 $parent 链查找宿主 ref,已登录守卫、未挂浮层回退整页登录)
+- - main.js:全局注册 login-sheet 组件 + 注入 loginSheetMixin
+- - 9 个页面接入 login-sheet 组件
+- - 修复:面板高度足够显示协议行;四步闭环与五维标签强制单行显示(flex-wrap: nowrap + margin 替代 gap)
+- - DimensionVisitorCard.vue:登录引导卡片,支持通过 openLoginSheet 唤起浮层
+- 
+- resolve last_build_commit conflict
+- 
+- 
+- 
+- 
+- - 新增 api/reportParse.js;注册路由 report-parse-status 与侧边菜单
+- - npm run build 产物版本 1.0.1588
+- 
+- - LangGraphReportParseService 新增 parseByScriptWithReason 保留失败原因,专用 RestTemplate 读超时放宽至 300s
+- - health_report_drafts 新增 parse_attempt/next_retry_at/parse_started_at/parse_finished_at(迁移364 + schema.sql)
+- - 新增 /api/admin/report-parse list|retry|backfill-food 及 reparseReportFoods(只覆盖 payload_json.foods)
+- - buildFoodsFromPayload 跳过空/无名称食材;saveFoodsForReport 先删后插保证幂等;入库前幂等守卫
+- 
+
+### 新功能
+- 登录页改造为底部滑出浮层(login-sheet)
+- gut-flora-risks-detail.vue 展示 relatedBacteria 与 gut-flora-detail.vue gutStatusLevel 微标(P0+P1 完整)
+- pdf_parser.py 北京菌群 related_bacteria/gutStatusLevel 解析 + report_parse_agent.py schema 扩展
+- ReportCollectService 与 LangGraphReportParseService 映射 gutStatusLevel 与 relatedBacteria,实现 P0+P1 完整链路
+- 知识库指标章节白名单扩展(报告指标知识库.json)
+- 健康报告采集扩展疾病关联菌和肠道菌群状态字段(实体/迁移)
+- 新增报告解析进度页面(查看/重试/回填)
+- 已知类型解析失败退避重试 + 解析进度后台可见 + 食材回填
+
+
 ## v1.0.1589 (2026-10-12)
 
 ### 新功能

+ 33 - 187
cfc-web/src/views/Layout.vue

@@ -5,6 +5,11 @@
     <el-aside :class="['el-aside', { 'sidebar-mobile': isMobile, 'sidebar-open': isMobile && sidebarVisible, 'sidebar-closed': isMobile && !sidebarVisible }]" :width="isMobile ? '200px' : '200px'">
       <div class="logo">浠艾福</div>
       <el-scrollbar wrap-class="sidebar-scrollbar-wrap">
+        <div v-if="menuLoadFailed && effectiveMenuItems.length === 0" class="menu-load-failed">
+          <i class="el-icon-warning-outline"></i>
+          <p class="menu-load-failed-title">菜单加载失败</p>
+          <p class="menu-load-failed-sub">请刷新页面重试</p>
+        </div>
         <el-menu
           :default-active="activeMenu"
           class="sidebar-menu"
@@ -164,193 +169,9 @@ export default {
   data() {
     return {
       menuItems: [
-        // ===== 1. 首页 (ALL) =====
-        { path: '/dashboard', label: '首页', icon: 'el-icon-s-home', perm: 'dashboard' },
-
-        // ===== 2. 家庭运营 (family:*) =====
-        { title: '家庭运营', icon: 'el-icon-s-custom', perm: 'family:*',
-          children: [
-            { path: '/families', label: '家庭列表', icon: 'el-icon-s-custom', perm: 'family:list,family:read,family:bound' },
-            { path: '/children', label: '孩子管理', icon: 'el-icon-user-solid', perm: 'family:children,family:read,family:bound' },
-            { path: '/points', label: '积分管理', icon: 'el-icon-s-finance', perm: 'family:points' },
-            { path: '/points-log', label: '积分记录', icon: 'el-icon-document', perm: 'family:points,family:bound' },
-            { path: '/wishes', label: '心愿管理', icon: 'el-icon-star-off', perm: 'family:wishes' },
-            { path: '/rewards', label: '奖励管理', icon: 'el-icon-s-goods', perm: 'reward:list' },
-          ]},
-
-        // ===== 3. 方案中心 (plan:*) =====
-        { title: '方案中心', icon: 'el-icon-notebook-2', perm: 'plan:*',
-          children: [
-            { path: '/health-plan-manage', label: '健康方案管理', icon: 'el-icon-first-aid-kit', perm: 'plan:health' },
-            { path: '/assessment-plan-manage', label: '测评方案管理', icon: 'el-icon-edit', perm: 'plan:assessment' },
-          ]},
-
-        // ===== 4. 任务中心 (task:*) =====
-        { title: '任务中心', icon: 'el-icon-s-order', perm: 'task:*,task:read',
-          children: [
-            { path: '/tasks', label: '任务列表', icon: 'el-icon-s-order', perm: 'task:list' },
-            { path: '/task-templates', label: '任务模板', icon: 'el-icon-document', perm: 'task:templates' },
-            { path: '/growth-task', label: '成长任务管理', icon: 'el-icon-s-management', perm: 'task:growth' },
-          ]},
-
-        // ===== 5. 审核中心(归集:服务角色申请/活动审核/退款/提现) =====
-        { title: '审核中心', icon: 'el-icon-s-check', perm: 'audit',
-          children: [
-            { path: '/review-center', label: '审核中心总览', icon: 'el-icon-s-check', perm: 'audit' },
-            { path: '/service-role-applications', label: '服务角色申请审核', icon: 'el-icon-s-check', perm: 'audit:service-role' },
-            { path: '/activity-review', label: '活动审核', icon: 'el-icon-document-checked', perm: 'audit:activity' },
-            { path: '/pending-refund', label: '待退款管理', icon: 'el-icon-warning', perm: 'audit:refund' },
-            { path: '/family-earnings-withdraw', label: '收益提现审核', icon: 'el-icon-document-checked', perm: 'audit:withdraw' },
-          ]},
-
-        // ===== 5. 商城营销 (commerce:*) =====
-        { title: '商城营销', icon: 'el-icon-s-goods', perm: 'commerce:*',
-          children: [
-            { path: '/product-manage', label: '商品管理', icon: 'el-icon-s-goods', perm: 'commerce:products,commerce:self' },
-            { path: '/inventory', label: '库存管理', icon: 'el-icon-document', perm: 'inventory:self' },
-            { path: '/order-manage', label: '订单管理', icon: 'el-icon-s-order', perm: 'commerce:orders,order:self' },
-            { path: '/ecom-supplier', label: '供应商管理', icon: 'el-icon-s-shop', perm: 'commerce:supplier' },
-            { path: '/product-profit-rate', label: '产品利润率', icon: 'el-icon-data-line', perm: 'finance:profit-rate' },
-            { path: '/coupon', label: '优惠券管理', icon: 'el-icon-ticket', perm: 'commerce:coupon' },
-            { path: '/coupon-grant-log', label: '发券记录', icon: 'el-icon-document', perm: 'commerce:coupon' },
-            { path: '/discount-rules', label: '限时折扣管理', icon: 'el-icon-timer', perm: 'commerce:discount' },
-            { path: '/promotion', label: '推广管理', icon: 'el-icon-s-marketing', perm: 'commerce:promotion' },
-            { path: '/home-banner-manage', label: '首页广告栏', icon: 'el-icon-picture', perm: 'marketing:promotion' },
-            { path: '/family-earnings', label: '家庭收益', icon: 'el-icon-s-money', perm: 'finance:family-earnings' },
-          ]},
-
-        // ===== 6. 知识中心 (articles:*) =====
-        { title: '知识中心', icon: 'el-icon-document', perm: 'articles:*,knowledge:read',
-          children: [
-            { path: '/article-categories', label: '知识分类', icon: 'el-icon-folder', perm: 'articles:categories' },
-            { path: '/article-manage', label: '知识管理', icon: 'el-icon-document', perm: 'articles:manage' },
-            { path: '/comment-review', label: '评论审核', icon: 'el-icon-chat-dot-round', perm: 'articles:manage' },
-            { path: '/knowledge-tags', label: '知识标签', icon: 'el-icon-price-tag', perm: 'articles:categories' },
-            { path: '/knowledge-base', label: '知识库', icon: 'el-icon-reading', perm: 'knowledge:base' },
-            { path: '/health-knowledge', label: '健康知识库', icon: 'el-icon-first-aid-kit', perm: 'knowledge:base' },
-            { path: '/vector-knowledge', label: '向量知识库', icon: 'el-icon-data-line', perm: 'knowledge:base' },
-          ]},
-
-        // ===== 6.5 活动管理(activity:*,活动审核已移入审核中心) =====
-        { title: '活动管理', icon: 'el-icon-date', perm: 'activity:*', children: [
-          { path: '/activities', label: '活动列表', icon: 'el-icon-date', perm: 'activity:list,activity:self' },
-          { path: '/activity-registration-review', label: '活动报名审核', icon: 'el-icon-document-checked', perm: 'activity:registration' },
-        ]},
-
-        // ===== 7. 健康饮食 (health:*,报告管理/报告审核/应季食材挂载,顺序对齐方案最终菜单树) =====
-        { title: '健康饮食', icon: 'el-icon-first-aid-kit', perm: 'health:*',
-          children: [
-            { path: '/health-reports', label: '健康报告', icon: 'el-icon-document', perm: 'health:reports' },
-            { path: '/report-management', label: '报告管理', icon: 'el-icon-document', perm: 'health:reports' },
-            { path: '/report-audit', label: '报告审核', icon: 'el-icon-document-checked', perm: 'report:audit' },
-            { path: '/report-parse-status', label: '解析进度', icon: 'el-icon-data-line', perm: 'health:reports' },
-            { path: '/health-indicators', label: '健康指标', icon: 'el-icon-data-line', perm: 'health:indicators' },
-            { path: '/health-checkins', label: '健康打卡', icon: 'el-icon-s-order', perm: 'health:checkins' },
-            { path: '/emotion-alert', label: '情绪告警', icon: 'el-icon-warning', perm: 'health:checkins' },
-            { path: '/nutrition-mappings', label: '营养素映射', icon: 'el-icon-connection', perm: 'health:mappings' },
-            { path: '/foods', label: '食材管理', icon: 'el-icon-apple', perm: 'diet:foods' },
-            { path: '/recipes', label: '食谱管理', icon: 'el-icon-dish', perm: 'diet:recipes' },
-            { path: '/seasonal-foods', label: '应季食材', icon: 'el-icon-apple', perm: 'diet:foods' },
-            { path: '/nutrition-products', label: '营养产品', icon: 'el-icon-first-aid-kit', perm: 'health:products' },
-            { path: '/energy-sandbox', label: '五维能量', icon: 'el-icon-data-line', perm: 'health:energy' },
-          ]},
-
-        // ===== 8. 报告解析系统 (config:report-parser,LangGraph 管理归入) =====
-        { title: '报告解析系统', icon: 'el-icon-cpu', perm: 'config:report-parser',
-          children: [
-            { path: '/report-types', label: '报告类型管理', icon: 'el-icon-collection', perm: 'config:report-parser' },
-            { path: '/report-parser-import', label: '解析器导入', icon: 'el-icon-upload2', perm: 'config:report-parser' },
-            { path: '/report-unknown-clusters', label: '未知报告审核', icon: 'el-icon-question', perm: 'config:report-parser' },
-            { path: '/report-auto-learn', label: '报告自学习', icon: 'el-icon-magic-stick', perm: 'config:report-parser' },
-            { path: '/report-collector-trainer', label: '报告采集训练', icon: 'el-icon-film', perm: 'config:report-parser' },
-            { path: '/report-template', label: '报告模板管理', icon: 'el-icon-setting', perm: 'config:report-parser' },
-            { path: '/langgraph-admin', label: 'LangGraph 管理', icon: 'el-icon-cpu', perm: 'config:report-parser' },
-          ]},
-
-        { title: '家庭服务', icon: 'el-icon-s-custom', perm: 'service:*',
-          children: [
-            { path: '/my-families', label: '我的家庭', icon: 'el-icon-s-custom', perm: 'service:family' },
-            { path: '/teacher-team', label: '我的团队', icon: 'el-icon-s-custom', perm: 'service:team' },
-          ]},
-        { title: '业务管理', icon: 'el-icon-s-marketing', perm: 'biz:*',
-          children: [
-            { path: '/teacher-packages', label: '任务模板管理', icon: 'el-icon-s-goods', perm: 'biz:packages' },
-            { path: '/teacher-orders', label: '订单佣金', icon: 'el-icon-s-order', perm: 'biz:orders' },
-          ]},
-        // ===== 测评咨询(测评管理/订单/待分配规划师已从系统配置移入) =====
-        { title: '测评咨询', icon: 'el-icon-edit', perm: 'assessment:*,assessment:read',
-          children: [
-            { path: '/assessment-admin', label: '测评管理', icon: 'el-icon-edit', perm: 'assessment:manage' },
-            { path: '/assessment-orders', label: '测评订单', icon: 'el-icon-s-order', perm: 'assessment:orders' },
-            { path: '/assessment-assign', label: '待分配规划师', icon: 'el-icon-user', perm: 'assessment:assign' },
-            { path: '/teacher-assessment', label: 'DAN测评', icon: 'el-icon-edit', perm: 'assessment:dan' },
-            { path: '/teacher-consult', label: '家长咨询', icon: 'el-icon-chat-dot-round', perm: 'assessment:consult' },
-            { path: '/growth-records', label: '成长记录', icon: 'el-icon-document', perm: 'growth:records' },
-            { path: '/growth-plans', label: '成长计划', icon: 'el-icon-document', perm: 'growth:plans' },
-          ]},
-
-        // ===== 9. 系统配置 (system:*,权限拆分 system:base/config:member/config:dimension/config:health) =====
-        { title: '系统配置', icon: 'el-icon-s-tools', perm: 'system:*',
-          children: [
-            // --- 基础管理 ---
-            { title: '基础管理', icon: 'el-icon-s-tools', perm: 'system:base',
-              children: [
-                { path: '/sys-config', label: '系统配置', icon: 'el-icon-s-tools', perm: 'system:base' },
-                { path: '/guide-config', label: '引导配置', icon: 'el-icon-setting', perm: 'system:base' },
-                { path: '/users', label: '用户管理', icon: 'el-icon-user', perm: 'system:users' },
-                { path: '/menu-manage', label: '菜单管理', icon: 'el-icon-menu', perm: 'system:menu' },
-                { path: '/operation-logs', label: '操作日志', icon: 'el-icon-s-order', perm: 'system:logs' },
-                { path: '/membership-center', label: '会员中心', icon: 'el-icon-s-custom', perm: 'config:member' },
-                { path: '/badge-manage', label: '勋章管理', icon: 'el-icon-medal', perm: 'config:member' },
-                { path: '/virtual-goods-config', label: '虚拟支付道具', icon: 'el-icon-goods', perm: 'config:member' },
-                { path: '/gates', label: '关卡配置', icon: 'el-icon-key', perm: 'system:base' },
-                { path: '/system-prompt', label: '系统提示词', icon: 'el-icon-chat-line-square', perm: 'system:base' },
-                { path: '/file-manage', label: '文件管理', icon: 'el-icon-files', perm: 'system:base' },
-              ]},
-            // --- 配置中心 ---
-            { title: '配置中心', icon: 'el-icon-setting', perm: 'config:dimension',
-              children: [
-                { path: '/dimension-config', label: '维度配置', icon: 'el-icon-data-line', perm: 'config:dimension' },
-              ]},
-            // --- 供应商体系 ---
-            { title: '供应商体系', icon: 'el-icon-s-management', perm: 'system:supply',
-              children: [
-                { path: '/supply-system', label: '供应商体系', icon: 'el-icon-s-management', perm: 'system:supply' },
-              ]},
-            // --- 供应商管理 ---
-            { title: '供应商管理', icon: 'el-icon-s-shop', perm: 'supply:manage',
-              children: [
-                { path: '/supply-manage', label: '供应商管理', icon: 'el-icon-s-shop', perm: 'supply:manage' },
-                { path: '/supplier-products', label: '商品管理', icon: 'el-icon-s-goods', perm: 'supply:manage' },
-              ]},
-            // --- 健康配置(能量规则/行为/周期性服务已从健康饮食移入;术语统一:五维能量配置) ---
-            { title: '健康配置', icon: 'el-icon-first-aid-kit', perm: 'config:health',
-              children: [
-                { path: '/health-norm-config', label: '健康常模', icon: 'el-icon-data-line', perm: 'config:health' },
-                { path: '/health-data-source', label: '健康数据源', icon: 'el-icon-data-line', perm: 'config:health' },
-                { path: '/health-energy-config', label: '五维能量配置', icon: 'el-icon-data-line', perm: 'config:health' },
-                { path: '/energy-rule', label: '能量规则管理', icon: 'el-icon-setting', perm: 'config:health' },
-                { path: '/energy-behavior-config', label: '能量行为配置', icon: 'el-icon-edit-outline', perm: 'config:health' },
-                { path: '/periodic-service-config', label: '周期性服务配置', icon: 'el-icon-refresh', perm: 'config:health' },
-                { path: '/indicator-correlations', label: '指标关联配置', icon: 'el-icon-connection', perm: 'config:health' },
-                { path: '/indicator-mappings', label: '指标映射管理', icon: 'el-icon-sort', perm: 'config:health' },
-              ]},
-            // --- 人生维度 ---
-            { title: '人生维度', icon: 'el-icon-s-custom', perm: 'config:dimension',
-              children: [
-                { path: '/zodiac-configs', label: '星座配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
-                { path: '/bazi-configs', label: '八字配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
-                { path: '/blood-type-configs', label: '血型配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
-                { path: '/innate-portrait-config', label: '先天画像权重配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
-                { path: '/numsoul-detail-config', label: '数字能量配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
-              ]},
-            // --- 虚拟团队 ---
-            { title: '虚拟团队', icon: 'el-icon-s-custom', perm: 'system:base',
-              children: [
-                { path: '/virtual-teams', label: '虚拟团队', icon: 'el-icon-s-custom', perm: 'system:base' },
-              ]},
-          ]},
+        { path: '/dashboard', label: '首页', icon: 'el-icon-s-home', perm: 'dashboard' }
       ],
+      menuLoadFailed: false,
       profileDialogVisible: false,
       passwordDialogVisible: false,
       submitting: false,
@@ -509,9 +330,13 @@ export default {
         var res = await getUserMenus()
         if (res.data && res.data.code === 200 && res.data.data && res.data.data.length > 0) {
           this.menuItems = this.buildMenuItems(res.data.data)
+          this.menuLoadFailed = false
+        } else {
+          this.menuLoadFailed = true
         }
       } catch (e) {
-        console.warn('菜单加载失败,使用本地菜单', e)
+        this.menuLoadFailed = true
+        console.error('菜单加载失败', e)
       }
     },
     buildMenuItems(nodes) {
@@ -1013,4 +838,25 @@ export default {
     display: none;
   }
 }
+.menu-load-failed {
+  padding: 24px 16px;
+  text-align: center;
+  color: #94a3b8;
+}
+.menu-load-failed .el-icon-warning-outline {
+  font-size: 28px;
+  color: #f59e0b;
+}
+.menu-load-failed-title {
+  margin: 8px 0 0;
+  font-size: 13px;
+  font-weight: 600;
+  color: #64748b;
+}
+.menu-load-failed-sub {
+  margin: 4px 0 0;
+  font-size: 12px;
+  color: #94a3b8;
+}
+
 </style>

+ 0 - 4
cfc-web/src/views/admin/ProductEdit.vue

@@ -1164,14 +1164,10 @@ async loadGiftRule(productId) {
           }
         } catch (e) {
           this.$message.error('操作失败')
-} else {
-            this.$message.error('操作失败');
         } finally {
             this.saving = false;
         }
     }
-      })
-    }
   }
 }
 </script>