Переглянути джерело

feat(photography): 优化详情页模板选择与发布功能

- 添加模板选择禁用状态控制
- 实现模板点击事件统一处理
- 增加发布区域禁用状态样式
- 完善模板选择逻辑与缓存机制
- 添加模板分页跳转功能
- 优化电商平台选择器禁用状态
- 补充模板选择相关的计算属性
- 改进模板加载与默认选择逻辑
- 增加模板缓存键常量定义
- 修复模板列表为空时的处理逻辑
- 移除旧版模板选择方法
- 添加禁用状态下的样式类名
panqiuyao 2 тижнів тому
батько
коміт
6e47ceabfb
1 змінених файлів з 120 додано та 38 видалено
  1. 120 38
      frontend/src/views/Photography/detail.vue

+ 120 - 38
frontend/src/views/Photography/detail.vue

@@ -146,7 +146,7 @@
 
         <!-- 右:选择详情模板 -->
         <div class="template-col">
-          <div class="template-section ">
+          <div :class="['template-section', { 'template-section--disabled': !isDetailServiceSelected }]">
             <div class="flex between">
               <div class="section-title">
                 <img src="@/assets/images/Photography/zhuangshi.png" style="width: 32px; height: 32px;" />
@@ -161,7 +161,7 @@
 
             <div class="template-list">
               <div v-for="(template, index) in visibleTemplates" :key="index" class="template-item"
-                @click="selectTemplate(template)" v-log="{ describe: { action: '点击选择详情模板', template_name: template.template_name } }">
+                @click="handleTemplateItemClick(template)" v-log="{ describe: { action: '点击选择详情模板', template_name: template.template_name } }">
                 <el-image :src="template.template_cover_image" fit="contain" class="cur-p"
                   style="width: 100%; display: block;" />
                 <div class="select-warp" :class="form.selectTemplate?.id == template.id ? 'active' : ''">
@@ -184,13 +184,23 @@
             </div>
 
             <!-- 模板下:一键上架 和 电商平台(多选) -->
-            <div class="publish-section flex left" v-if="onlineStoreTempList.length || onlineStoreTempListForeign.length">
+            <div
+              class="publish-section flex left"
+              :class="{ 'publish-section--disabled': !canUsePublishSection }"
+              v-if="onlineStoreTempList.length || onlineStoreTempListForeign.length"
+            >
               <div class="form-item flex left">
                 <div class="fw-b">一键上架:</div>
                </div>
               <div class="form-item flex left mar-top-10" style="margin-right: 10px !important;"  v-if="onlineStoreTempList.length">
                 <div class="label">国内电商平台:</div>
-                <el-select  v-model="domesticPlatforms" multiple placeholder="请选择平台" style="min-width: 200px;">
+                <el-select
+                  v-model="domesticPlatforms"
+                  multiple
+                  placeholder="请选择平台"
+                  style="min-width: 200px;"
+                  :disabled="!canUsePublishSection"
+                >
                   <el-option
                     v-for="store in onlineStoreTempList"
                     :key="store.show_name"
@@ -202,7 +212,13 @@
               </div>
               <div class="form-item flex left mar-top-10" v-if="onlineStoreTempListForeign.length">
                 <div class="label">国外电商平台:</div>
-                <el-select  v-model="foreignPlatforms" multiple placeholder="请选择平台" style="min-width: 200px;">
+                <el-select
+                  v-model="foreignPlatforms"
+                  multiple
+                  placeholder="请选择平台"
+                  style="min-width: 200px;"
+                  :disabled="!canUsePublishSection"
+                >
                   <el-option
                     v-for="store in onlineStoreTempListForeign"
                     :key="store.show_name"
@@ -528,6 +544,12 @@ const form = reactive({
   excel_path: '', // 商品基础资料EXCEL文件选择
   services: ['is_detail'], // 勾选服务内容(多选)默认包含详情页生成
 })
+
+const templatesLoaded = ref(false)
+const lastSelectedTemplateId = ref<string | number | null>(null)
+const isDetailServiceSelected = computed(() => form.services.includes('is_detail'))
+const hasTemplates = computed(() => templates.value.length > 0)
+const canUsePublishSection = computed(() => isDetailServiceSelected.value && hasTemplates.value)
 onMounted(() => {
   // 页面访问埋点
 
@@ -566,6 +588,77 @@ const visibleTemplates = computed(() => {
   const data = templates.value.slice(startIndex, startIndex + itemsPerPage);
   return data
 });
+
+const selectTemplate = (template: any, options: { saveCache?: boolean; ensureVisible?: boolean } = {}) => {
+  if (!isDetailServiceSelected.value) return
+  if (!template || !template.id) return
+  form.selectTemplate = template
+  lastSelectedTemplateId.value = template.id
+  if (options.ensureVisible) {
+    jumpToTemplatePageById(template.id)
+  }
+  const shouldSaveCache = options.saveCache !== undefined ? options.saveCache : true
+  if (shouldSaveCache) {
+    try {
+      localStorage.setItem(DETAIL_TEMPLATE_CACHE_KEY, JSON.stringify(template))
+      console.log('selectTemplate - saved to cache:', template);
+    } catch {}
+  }
+};
+
+const handleTemplateItemClick = (template: any) => {
+  if (!isDetailServiceSelected.value) return
+  selectTemplate(template)
+};
+
+const clearTemplateSelection = () => {
+  form.selectTemplate = {}
+};
+
+const findTemplateById = (templateId: string | number | null) => {
+  if (templateId === null || templateId === undefined) return null
+  return templates.value.find(template => String(template.id) === String(templateId)) || null
+};
+
+const jumpToTemplatePageById = (templateId: string | number | null) => {
+  if (templateId === null || templateId === undefined) return
+  const index = templates.value.findIndex(template => String(template.id) === String(templateId))
+  if (index === -1) return
+  const targetPage = Math.floor(index / itemsPerPage) + 1
+  if (queryParams.current !== targetPage) {
+    queryParams.current = targetPage
+  }
+};
+
+const ensureDefaultTemplateSelection = (options: { ensureVisible?: boolean } = {}) => {
+  if (!templatesLoaded.value || !isDetailServiceSelected.value || !templates.value.length) {
+    return
+  }
+
+  if (form.selectTemplate && (form.selectTemplate as any).id) {
+    if (options.ensureVisible) {
+      jumpToTemplatePageById((form.selectTemplate as any).id)
+    }
+    return
+  }
+
+  const cachedTemplate = findTemplateById(lastSelectedTemplateId.value)
+  const templateToSelect = cachedTemplate || templates.value[0]
+  if (templateToSelect) {
+    selectTemplate(templateToSelect, {
+      ensureVisible: options.ensureVisible,
+      saveCache: !cachedTemplate
+    })
+  }
+};
+
+watch(isDetailServiceSelected, (selected) => {
+  if (selected) {
+    ensureDefaultTemplateSelection({ ensureVisible: true })
+  } else {
+    clearTemplateSelection()
+  }
+});
 // 查看模板详情
 const viewTemplate = (template) => {
   // 展示大图
@@ -577,7 +670,7 @@ const viewTemplate = (template) => {
 const getCompanyTemplates = async () => {
   const { data } = await getCompanyTemplatesApi()
   console.log(data);
-  templates.value = data.list
+  templates.value = data.list || []
   // 获取电商平台列表 - 支持新的数据结构
   if (data.online_store_temp_list) {
     onlineStoreTempList.value = data.online_store_temp_list
@@ -587,6 +680,8 @@ const getCompanyTemplates = async () => {
     onlineStoreTempListForeign.value = data.online_store_temp_list_foreign
   }
 
+  templatesLoaded.value = true
+
   // 获取模板列表后,尝试从缓存恢复模板选择
   loadTemplateFromCache()
 
@@ -632,6 +727,7 @@ const DETAIL_SCENE_PROMPT_CACHE_KEY = 'scene_prompt_cache'
 const DETAIL_LOGO_CACHE_KEY = 'detail_logo_cache'
 const DETAIL_DATA_TYPE_CACHE_KEY = 'detail_data_type_cache'
 const DETAIL_SERVICES_CACHE_KEY = 'detail_services_cache'
+const DETAIL_TEMPLATE_CACHE_KEY = 'detail_template_cache'
 
 // 读取本地缓存
 const loadDetailCache = () => {
@@ -749,37 +845,20 @@ const saveServicesToCache = (services: string[]) => {
 
 // 从缓存加载模板选择
 const loadTemplateFromCache = () => {
+  lastSelectedTemplateId.value = null
   try {
-    const template = localStorage.getItem('detail_template_cache')
+    const template = localStorage.getItem(DETAIL_TEMPLATE_CACHE_KEY)
     if (template) {
       const parsed = JSON.parse(template)
       if (parsed && parsed.id) {
-        // 检查缓存的模板是否还在当前模板列表中
-        const templateExists = templates.value.some(t => t.id === parsed.id)
-        if (templateExists) {
-          form.selectTemplate = parsed
-          console.log('loadTemplateFromCache - template:', parsed);
-        } else {
-          console.log('缓存的模板不在当前模板列表中,使用默认模板');
-          // 如果缓存的模板不存在,使用默认模板(第一个)
-          if (templates.value.length > 0) {
-            form.selectTemplate = templates.value[0]
-          }
-        }
-      }
-    } else {
-      // 没有缓存时,使用默认模板
-      if (templates.value.length > 0) {
-        form.selectTemplate = templates.value[0]
+        lastSelectedTemplateId.value = parsed.id
+        console.log('loadTemplateFromCache - template id:', parsed.id);
       }
     }
   } catch (error) {
     console.error('加载模板缓存失败:', error);
-    // 出错时使用默认模板
-    if (templates.value.length > 0) {
-      form.selectTemplate = templates.value[0]
-    }
   }
+  ensureDefaultTemplateSelection({ ensureVisible: true })
 }
 
 const openModelDialog = () => {
@@ -789,16 +868,6 @@ const openScenePromptDialog = () => {
   scenePromptDialogVisible.value = true
 }
 
-// 选择模板
-const selectTemplate = (template: any) => {
-  form.selectTemplate = template
-  // 保存模板选择到缓存
-  try {
-    localStorage.setItem('detail_template_cache', JSON.stringify(template))
-    console.log('selectTemplate - saved to cache:', template);
-  } catch {}
-}
-
 // 选择LOGO
 const selectLogo = (logoPath: string) => {
   form.logo_path = logoPath
@@ -1593,6 +1662,19 @@ const selectFolder = () => {
   margin-bottom: 20px;
 }
 
+.template-section--disabled {
+  opacity: 0.8;
+
+  .template-list,
+  .template-pagination {
+    pointer-events: none;
+  }
+}
+
+.publish-section--disabled {
+  opacity: 0.6;
+}
+
 .logo-template-row {
   display: flex;
   gap: 24px;