zero 1 mese fa
parent
commit
a852b475dc
4 ha cambiato i file con 204 aggiunte e 163 eliminazioni
  1. 2 2
      src/components/Sidebar.vue
  2. 34 102
      src/services/api.ts
  3. 17 6
      src/types/index.ts
  4. 151 53
      src/views/SourceList.vue

+ 2 - 2
src/components/Sidebar.vue

@@ -37,12 +37,12 @@
         </template>
       </el-menu-item>
 
-      <!-- <el-menu-item index="/sources" class="menu-item">
+      <el-menu-item index="/sources" class="menu-item">
         <el-icon><Link /></el-icon>
         <template #title>
           <div class="menu-title">来源管理</div>
         </template>
-      </el-menu-item> -->
+      </el-menu-item>
 
       <el-menu-item index="/categories" class="menu-item">
         <el-icon><Collection /></el-icon>

+ 34 - 102
src/services/api.ts

@@ -68,137 +68,69 @@ export const categoryApi = {
   },
 }
 
-// Sources API
-export const sourceApi = {
-  // Get all sources
-  getSources: async (page?: number, pageSize?: number): Promise<ApiResponse<Source[]>> => {
+// Config API
+export const configApi = {
+  //获取所有配置列表
+  getConfigurations: async (params: Record<string, any>): Promise<unknown> => {
     try {
-      let url = `${API_BASE_URL}/sources/`
-      if (page !== undefined && pageSize !== undefined) {
-        const skip = (page - 1) * pageSize
-        url += `?skip=${skip}&limit=${pageSize}`
-      }
-      const response = await fetch(url)
-      if (!response.ok) {
-        throw new Error(`HTTP error! status: ${response.status}`)
-      }
-      const data = await response.json()
-      return {
-        data,
-        message: 'Sources fetched successfully',
-        success: true,
-      }
+      const url = `/xiaoshi/ppa/sourceInfo/selectConfigurationList`
+      const response = await apiClient.get<unknown>(url, {params})
+      return response
     } catch (error) {
-      console.error('Error fetching sources:', error)
+      console.error(`Error from export report:`, error)
       throw error
     }
   },
 
-  // Get sources count
-  getSourcesCount: async (): Promise<ApiResponse<{ count: number }>> => {
+}
+
+// Sources API
+export const sourceApi = {
+  //获取来源列表
+  getSources: async (params?: Record<string,any>): Promise<unknown> => {
     try {
-      const response = await fetch(`${API_BASE_URL}/sources/count/`)
-      if (!response.ok) {
-        throw new Error(`HTTP error! status: ${response.status}`)
-      }
-      const data = await response.json()
-      return {
-        data,
-        message: 'Sources count fetched successfully',
-        success: true,
-      }
+      const url = `/xiaoshi/ppa/sourceInfo/selectSourceInfoList`
+      const response = await apiClient.post<unknown>(url,params)
+      return response
     } catch (error) {
-      console.error('Error fetching sources count:', error)
+      console.error('Error fetching sources:', error)
       throw error
     }
   },
 
-  // Get source by ID
-  getSource: async (id: number): Promise<ApiResponse<Source>> => {
+  //获取来源详情
+  getSource: async (params?: Record<string,any>): Promise<unknown> => {
     try {
-      const response = await fetch(`${API_BASE_URL}/sources/${id}`)
-      if (!response.ok) {
-        throw new Error(`HTTP error! status: ${response.status}`)
-      }
-      const data = await response.json()
-      return {
-        data,
-        message: 'Source fetched successfully',
-        success: true,
-      }
+      const url = `/xiaoshi/ppa/sourceInfo/selectSourceInfoDetail`
+      const response = await apiClient.post<unknown>(url,params)
+      return response
     } catch (error) {
-      console.error(`Error fetching source ${id}:`, error)
+      console.error(`Error fetching source:`, error)
       throw error
     }
   },
 
   // Create source
-  createSource: async (source: Omit<Source, 'id'>): Promise<ApiResponse<Source>> => {
+  createSource: async (params?: Record<string,any>): Promise<unknown> => {
     try {
-      const response = await fetch(`${API_BASE_URL}/sources/`, {
-        method: 'POST',
-        headers: {
-          'Content-Type': 'application/json',
-        },
-        body: JSON.stringify(source),
-      })
-      if (!response.ok) {
-        throw new Error(`HTTP error! status: ${response.status}`)
-      }
-      const data = await response.json()
-      return {
-        data,
-        message: 'Source created successfully',
-        success: true,
-      }
+      const url = `/xiaoshi/ppa/sourceInfo/addOrEditSourceInfo`
+      const response = await apiClient.post<unknown>(url,params)
+      return response
     } catch (error) {
       console.error('Error creating source:', error)
       throw error
     }
   },
 
-  // Update source
-  updateSource: async (id: number, source: Omit<Source, 'id'>): Promise<ApiResponse<Source>> => {
-    try {
-      const response = await fetch(`${API_BASE_URL}/sources/${id}`, {
-        method: 'PUT',
-        headers: {
-          'Content-Type': 'application/json',
-        },
-        body: JSON.stringify(source),
-      })
-      if (!response.ok) {
-        throw new Error(`HTTP error! status: ${response.status}`)
-      }
-      const data = await response.json()
-      return {
-        data,
-        message: 'Source updated successfully',
-        success: true,
-      }
-    } catch (error) {
-      console.error(`Error updating source ${id}:`, error)
-      throw error
-    }
-  },
 
-  // Delete source
-  deleteSource: async (id: number): Promise<ApiResponse<Source>> => {
+   // 删除来源
+  deleteSource: async (params: Record<string, any>): Promise<unknown> => {
     try {
-      const response = await fetch(`${API_BASE_URL}/sources/${id}`, {
-        method: 'DELETE',
-      })
-      if (!response.ok) {
-        throw new Error(`HTTP error! status: ${response.status}`)
-      }
-      const data = await response.json()
-      return {
-        data,
-        message: 'Source deleted successfully',
-        success: true,
-      }
+      const url = `/xiaoshi/ppa/sourceInfo/deleteSourceInfo`
+      const response = await apiClient.post<unknown>(url, params)
+      return response
     } catch (error) {
-      console.error(`Error deleting source ${id}:`, error)
+      console.error(`Error deleting report`, error)
       throw error
     }
   },

+ 17 - 6
src/types/index.ts

@@ -5,15 +5,26 @@ export interface Category {
   createTime?: Date //创建时间
   creator?: string //创建人
 }
+// 配置
+export interface Configuration {
+  id: number //配置id
+  configName: string //配置方法名称
+  configValue: string //配置方法值
+}
 // 来源
 export interface Source {
-  id: number
-  name: string
-  type: 'website' | 'official_account'
-  default_category_id: number
-  default_category_name: string
-  url: string
+  sourceInfoId: number | null
+  sourceName: string
+  sourceType: 1 | 2
+  categoryId: number | null
+  categoryName: string
+  sourceUrl: string
   created_at?: Date
+  fakeId?:string
+  configId?: number | null
+  configValue?: string
+  configName?: string
+  configKey?:string
 }
 // 资讯
 export interface NewsItem {

+ 151 - 53
src/views/SourceList.vue

@@ -14,6 +14,33 @@
         </div>
       </template>
 
+      <!-- Search form -->
+      <div class="search-container">
+        <el-form :model="searchForm" label-width="100px" class="search-form">
+          <el-row :gutter="5">
+            <el-col :span="5">
+              <el-form-item label="来源名称">
+                <el-input v-model="searchForm.sourceName" placeholder="请输入来源" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="5">
+              <el-form-item label="来源类型">
+                <el-select v-model="searchForm.sourceType" clearable placeholder="请选择来源类型">
+                  <el-option label="网站" :value="1" />
+                  <el-option label="公众号" :value="2" />
+              </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="14" class="search-actions">
+              <el-form-item label=" ">
+                <el-button type="primary" @click="handleSearch">搜索</el-button>
+                <el-button @click="resetSearch">重置</el-button>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </div>
+
       <!-- Sources table -->
       <el-table
         :data="sources"
@@ -31,23 +58,24 @@
             {{ (pagination.currentPage - 1) * pagination.pageSize + scope.$index + 1 }}
           </template>
         </el-table-column>
-        <el-table-column prop="name" label="名称" min-width="150"></el-table-column>
-        <el-table-column label="类型" width="120">
+        <el-table-column prop="sourceName" label="来源名称" min-width="150"></el-table-column>
+        <el-table-column label="来源类型" width="150">
           <template #default="scope">
-            <el-tag :type="scope.row.type === 'website' ? 'primary' : 'success'">
-              {{ scope.row.type === 'website' ? '网站' : '公众号' }}
+            <el-tag :type="scope.row.sourceType === 1 ? 'primary' : 'success'">
+              {{ scope.row.sourceType === 1 ? '网站' : '公众号' }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="default_category_name" label="默认分类" width="150"></el-table-column>
-        <el-table-column prop="url" label="链接" min-width="200">
+        <el-table-column prop="fakeId" label="公众号唯一标识" width="150"></el-table-column>
+        <el-table-column prop="sourceUrl" label="来源网址" min-width="150">
           <template #default="scope">
-            <el-link :href="scope.row.url" target="_blank" :underline="false">
-              {{ scope.row.url }}
+            <el-link :href="scope.row.sourceUrl" target="_blank" :underline="false"> 
+              {{ scope.row.sourceUrl }}
             </el-link>
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="150" fixed="right">
+        <el-table-column prop="categoryName" label="类别名称" width="180"></el-table-column>
+        <el-table-column label="操作" width="180" fixed="right">
           <template #default="scope">
             <el-button size="small" @click="editSource(scope.row)">编辑</el-button>
             <el-button size="small" type="danger" @click="deleteSource(scope.row)">删除</el-button>
@@ -73,16 +101,16 @@
     <el-dialog v-model="dialogVisible" :title="isEditing ? '编辑来源' : '添加来源'" width="500px">
       <el-form :model="currentSource" label-width="100px">
         <el-form-item label="名称">
-          <el-input v-model="currentSource.name" placeholder="请输入名称" />
+          <el-input v-model="currentSource.sourceName" placeholder="请输入名称" />
         </el-form-item>
         <el-form-item label="类型">
-          <el-select v-model="currentSource.type" placeholder="请选择类型">
-            <el-option label="网站" value="website" />
-            <el-option label="公众号" value="official_account" />
+          <el-select v-model="currentSource.sourceType" placeholder="请选择类型">
+            <el-option label="网站" :value="1" />
+            <el-option label="公众号" :value="2" />
           </el-select>
         </el-form-item>
         <el-form-item label="默认分类">
-          <el-select v-model="currentSource.default_category_id" placeholder="请选择默认分类">
+          <el-select v-model="currentSource.categoryId" clearable placeholder="请选择默认分类">
             <el-option
               v-for="category in categories"
               :key="category.id"
@@ -92,7 +120,23 @@
           </el-select>
         </el-form-item>
         <el-form-item label="链接">
-          <el-input v-model="currentSource.url" placeholder="请输入链接" />
+          <el-input v-model="currentSource.sourceUrl" placeholder="请输入链接" />
+        </el-form-item>
+        <el-form-item label="公众号唯一标识" v-if="currentSource.sourceType==2">
+          <el-input v-model="currentSource.fakeId" placeholder="请输入公众号唯一标识" />
+        </el-form-item>
+        <el-form-item label="配置方法">
+          <el-select v-model="currentSource.configId" clearable placeholder="请选择配置方法">
+            <el-option
+              v-for="configuration in configurations"
+              :key="configuration.id"
+              :label="configuration.configName"
+              :value="configuration.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="配置关键词">
+          <el-input v-model="currentSource.configKey" placeholder="请输入配置关键词" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -106,26 +150,52 @@
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted } from 'vue'
-import { ElMessage, ElMessageBox } from 'element-plus'
+import { ref, onMounted,reactive } from 'vue'
+import { ElMessage, ElMessageBox,ElLoading } from 'element-plus'
 import { Link, Plus, Refresh } from '@element-plus/icons-vue'
-import type { Source, Category } from '@/types'
-import { sourceApi, categoryApi } from '@/services/api'
+import type { Source, Category,Configuration } from '@/types'
+import { sourceApi, categoryApi,configApi } from '@/services/api'
 
 // State
 const sources = ref<Source[]>([])
 const categories = ref<Category[]>([])
+const configurations = ref<Configuration[]>([])
 const loading = ref(false)
 const dialogVisible = ref(false)
 const isEditing = ref(false)
 
 const currentSource = ref<Source>({
-  id: 0,
-  name: '',
-  type: 'website',
-  default_category_id: 0,
-  default_category_name: '',
-  url: ''
+  sourceInfoId: null,
+  sourceName: '',
+  sourceType: 1,
+  categoryId: null,
+  categoryName: '',
+  sourceUrl: '',
+  configId: null,
+  configValue: '',
+  configName: '',
+  configKey:''
+})
+
+const handleSearch = () => {
+  // 重置到第一页
+  pagination.value.currentPage = 1
+  fetchSources()
+}
+
+const resetSearch = () => {
+  // 重置搜索表单
+  searchForm.sourceName = ''
+  searchForm.sourceType = null
+  // 重置到第一页
+  pagination.value.currentPage = 1
+  fetchSources()
+}
+
+// Search form
+const searchForm = reactive({
+  sourceName: '',
+  sourceType: null as number | null,
 })
 
 const pagination = ref({
@@ -135,16 +205,18 @@ const pagination = ref({
 })
 
 const fetchSources = async () => {
+
   loading.value = true
   try {
-    const response = await sourceApi.getSources(
-      pagination.value.currentPage,
-      pagination.value.pageSize
-    )
-    sources.value = response.data
-    // 获取总数
-    const countResponse = await sourceApi.getSourcesCount()
-    pagination.value.total = countResponse.data.count
+    // 构造搜索参数
+    const params: any = {
+      pageNum: pagination.value.currentPage,
+      pageSize: pagination.value.pageSize,
+      ...searchForm,
+    }
+    const response = await sourceApi.getSources(params)
+    sources.value = response.data.data
+    pagination.value.total = response.data.total
   } catch (error) {
     ElMessage.error('获取来源列表失败')
   } finally {
@@ -155,23 +227,33 @@ const fetchSources = async () => {
 const fetchCategories = async () => {
   try {
     // 获取所有分类,不分页
-    const response = await categoryApi.getCategories()
-    categories.value = response.data
+    const response = await categoryApi.getCategories({})
+    categories.value = response.data.data
   } catch (error) {
     ElMessage.error('获取分类列表失败')
   }
 }
 
+const fetchConfigurations = async () => {
+  try {
+      // 获取所有分类,不分页
+      const response = await configApi.getConfigurations({})
+      configurations.value = response.data
+  } catch (error) {
+    ElMessage.error('获取配置列表失败')
+  }
+}
+
 const saveSource = async () => {
   try {
-    if (!currentSource.value.name || !currentSource.value.url) {
+    if (!currentSource.value.sourceName || !currentSource.value.sourceUrl) {
       ElMessage.warning('请填写必填项')
       return
     }
     
     // Find the category name for the selected category ID
     const selectedCategory = categories.value.find(
-      category => category.id === currentSource.value.default_category_id
+      category => category.id === currentSource.value.categoryId
     )
     
     if (!selectedCategory) {
@@ -182,16 +264,12 @@ const saveSource = async () => {
     // Add category name to the source object
     const sourceToSave = {
       ...currentSource.value,
-      default_category_name: selectedCategory.name
+      categoryName: selectedCategory.name
     }
-    
+    await sourceApi.createSource(sourceToSave)
     if (isEditing.value) {
-      // Update existing source
-      await sourceApi.updateSource(currentSource.value.id, sourceToSave)
       ElMessage.success('来源更新成功')
     } else {
-      // Create new source
-      await sourceApi.createSource(sourceToSave)
       ElMessage.success('来源添加成功')
     }
     
@@ -208,7 +286,10 @@ const deleteSource = async (source: Source) => {
       type: 'warning'
     })
     
-    await sourceApi.deleteSource(source.id)
+    const params = {
+      sourceInfoId: source.sourceInfoId,
+    }
+    await sourceApi.deleteSource(params)
     ElMessage.success('来源删除成功')
     fetchSources()
   } catch (error) {
@@ -231,12 +312,16 @@ const handleCurrentChange = (val: number) => {
 
 const showAddDialog = () => {
   currentSource.value = {
-    id: 0,
-    name: '',
-    type: 'website',
-    default_category_id: 0,
-    default_category_name: '',
-    url: ''
+    sourceInfoId: null,
+    sourceName: '',
+    sourceType: 1,
+    categoryId: null,
+    categoryName: '',
+    sourceUrl: '',
+    configId: null,
+    configValue: '',
+    configName: '',
+    configKey:''
   }
   isEditing.value = false
   dialogVisible.value = true
@@ -249,9 +334,22 @@ const editSource = (source: Source) => {
 }
 
 // Lifecycle
-onMounted(() => {
-  fetchSources()
-  fetchCategories()
+onMounted(async () => {
+  // fetchSources()
+  // fetchCategories()
+  // fetchConfigurations()
+  // 并行发起所有请求
+  const loadingInstance = ElLoading.service({
+    lock: true,
+  });
+  try{
+    await Promise.all([fetchSources(),fetchCategories(),fetchConfigurations()]);
+  } catch (error) {
+    ElMessage.error('请求失败');
+  } finally {
+    loadingInstance.close();
+  }
+  
 })
 </script>