Przeglądaj źródła

feat: Add article type and fix search bindings

E2E Test Bot 1 dzień temu
rodzic
commit
816695a674
1 zmienionych plików z 64 dodań i 6 usunięć
  1. 64 6
      cfc-web/src/views/admin/HomeBannerManage.vue

+ 64 - 6
cfc-web/src/views/admin/HomeBannerManage.vue

@@ -16,6 +16,7 @@
           <el-option label="全部类型" value="" />
           <el-option label="活动" value="activity" />
           <el-option label="商品" value="product" />
+          <el-option label="文章" value="article" />
           <el-option label="链接" value="link" />
         </el-select>
         <el-button type="primary" size="mini" @click="loadList">查询</el-button>
@@ -42,6 +43,9 @@
               <div v-else-if="row.bannerType === 'product' && row.refId">
                 <el-tag size="mini" type="info">商品 #{{ row.refId }}</el-tag>
               </div>
+              <div v-else-if="row.bannerType === 'article' && row.refId">
+                <el-tag size="mini" type="success">文章 #{{ row.refId }}</el-tag>
+              </div>
               <div v-else-if="row.bannerType === 'link' && row.linkUrl">
                 <el-tag size="mini" type="info">{{ row.linkUrl }}</el-tag>
               </div>
@@ -105,6 +109,7 @@
           <el-select v-model="form.bannerType" placeholder="选择类型" style="width:100%;">
             <el-option label="活动" value="activity" />
             <el-option label="商品" value="product" />
+            <el-option label="文章" value="article" />
             <el-option label="链接" value="link" />
           </el-select>
         </el-form-item>
@@ -117,11 +122,12 @@
             filterable
             :remote="true"
             :remote-method="searchActivities"
+            :loading="activityLoading"
             style="width:100%"
             clearable
           >
-            <el-option key="" label="-- 请选择 --" value="">
-            </el-option>
+            <el-option v-for="item in activityOptions" :key="item.id" :label="item.title + ' (ID:' + item.id + ')'" :value="item.id" />
+            <el-option v-if="activityOptions.length === 0 && !activityLoading" label="暂无数据" value="" disabled />
           </el-select>
         </el-form-item>
 
@@ -133,11 +139,29 @@
             filterable
             :remote="true"
             :remote-method="searchProducts"
+            :loading="productLoading"
+            style="width:100%"
+            clearable
+          >
+            <el-option v-for="item in productOptions" :key="item.id" :label="item.name + ' (¥' + (item.price/100).toFixed(2) + ')'" :value="item.id" />
+            <el-option v-if="productOptions.length === 0 && !productLoading" label="暂无数据" value="" disabled />
+          </el-select>
+        </el-form-item>
+
+        <!-- 文章选择器 -->
+        <el-form-item v-if="form.bannerType === 'article'" label="关联文章">
+          <el-select
+            v-model="form.refId"
+            placeholder="搜索文章"
+            filterable
+            :remote="true"
+            :remote-method="searchArticles"
+            :loading="articleLoading"
             style="width:100%"
             clearable
           >
-            <el-option key="" label="-- 请选择 --" value="">
-            </el-option>
+            <el-option v-for="item in articleOptions" :key="item.id" :label="item.title + ' (ID:' + item.id + ')'" :value="item.id" />
+            <el-option v-if="articleOptions.length === 0 && !articleLoading" label="暂无数据" value="" disabled />
           </el-select>
         </el-form-item>
 
@@ -208,6 +232,7 @@
 import { getHomeBannerList, saveHomeBanner, deleteHomeBanner, batchDeleteHomeBanner, toggleHomeBanner, updateBannerSort } from '@/api/homeBanner'
 import { getActivityList } from '@/api/activity'
 import { getProductList } from '@/api/admin'
+import { adminArticleList } from '@/api/article'
 
 // 小程序已注册页面(供链接类型选择)
 const MINI_PAGES = [
@@ -288,6 +313,11 @@ export default {
       productLoading: false,
       productOptions: [],
       productPage: 1,
+      // 文章搜索状态
+      articleSearchKeyword: '',
+      articleLoading: false,
+      articleOptions: [],
+      articlePage: 1,
       showPagePicker: false
     }
   },
@@ -369,6 +399,10 @@ export default {
           this.productSearchKeyword = ''
           this.productOptions = []
           this.loadProductOptions()
+        } else if (row.bannerType === 'article') {
+          this.articleSearchKeyword = ''
+          this.articleOptions = []
+          this.loadArticleOptions()
         }
       } else {
         this.editId = null
@@ -386,6 +420,7 @@ export default {
         }
         this.activityOptions = []
         this.productOptions = []
+        this.articleOptions = []
       }
       this.dialogVisible = true
       this.$nextTick(function() {
@@ -491,6 +526,29 @@ export default {
       this.searchProducts(this.productSearchKeyword)
     },
 
+    // 文章搜索
+    searchArticles: async function(query) {
+      this.articleLoading = true
+      this.articleOptions = []
+      try {
+        const res = await adminArticleList({
+          keyword: query || undefined,
+          current: 1,
+          size: 20
+        })
+        const data = (res && res.data) || {}
+        this.articleOptions = data.list || data.records || []
+        this.articlePage = 1
+        this.articleLoading = false
+      } catch (e) {
+        console.error('[HomeBanner] 搜索文章失败', e)
+        this.articleLoading = false
+      }
+    },
+    loadArticleOptions() {
+      this.searchArticles(this.articleSearchKeyword)
+    },
+
     handleUploadSuccess(res) {
       if (res && res.code === 200 && res.data && res.data.url) {
         this.form.coverImage = res.data.url
@@ -525,11 +583,11 @@ export default {
     },
     // --- 工具方法 ---
     typeLabel(type) {
-      var map = { activity: '活动', product: '商品', link: '链接' }
+      var map = { activity: '活动', product: '商品', article: '文章', link: '链接' }
       return map[type] || type || '-'
     },
     typeTag(type) {
-      var map = { activity: 'success', product: 'warning', link: 'info' }
+      var map = { activity: 'success', product: 'warning', article: 'info', link: 'info' }
       return map[type] || ''
     },
     sortIndex(col) {