|
|
@@ -1,157 +1,208 @@
|
|
|
<template>
|
|
|
- <div class="policy-container">
|
|
|
- <!-- 顶部导航栏 -->
|
|
|
- <div class="header">
|
|
|
- <div class="header-left">
|
|
|
- <div class="logo-section" @click="goToHome">
|
|
|
- <img src="../assets/new_index/1.png" alt="logo" class="logo-img" />
|
|
|
- <!-- <span class="logo-text">蜀道AI安全助手</span> -->
|
|
|
+ <div class="policy-container">
|
|
|
+ <!-- 顶部导航栏 -->
|
|
|
+ <div class="header">
|
|
|
+ <div class="header-left">
|
|
|
+ <div class="logo-section" @click="goToHome">
|
|
|
+ <img
|
|
|
+ src="../assets/new_index/1.png"
|
|
|
+ alt="logo"
|
|
|
+ class="logo-img"
|
|
|
+ />
|
|
|
+ <!-- <span class="logo-text">蜀道AI安全助手</span> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
|
|
|
- <!-- 主内容区域 -->
|
|
|
- <div class="main-content">
|
|
|
- <!-- 页面标题 -->
|
|
|
- <div class="page-header">
|
|
|
- <div class="back-button1" @click="goToHome">
|
|
|
- <img src="../assets/Policy/9.png" alt="返回" class="back-icon" />
|
|
|
- <span class="back-text">返回首页</span>
|
|
|
- </div>
|
|
|
- <h1 class="page-title">政策文件</h1>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 搜索栏 -->
|
|
|
- <div class="search-section">
|
|
|
- <div class="search-box">
|
|
|
- <div class="search-icon-left">
|
|
|
- <img src="../assets/Policy/8.png" alt="搜索" class="search-icon" />
|
|
|
- </div>
|
|
|
- <input
|
|
|
- type="text"
|
|
|
- placeholder="搜索政策文件..."
|
|
|
- class="search-input"
|
|
|
- v-model="searchText"
|
|
|
- maxlength="100"
|
|
|
- @input="handleSearchInput"
|
|
|
- @keyup.enter="handleSearch"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 分类标签 -->
|
|
|
- <div class="category-tabs">
|
|
|
- <button
|
|
|
- class="tab-btn"
|
|
|
- :class="{ active: activeTab === 0 }"
|
|
|
- @click="setActiveTab(0)"
|
|
|
- >
|
|
|
- 全部政策
|
|
|
- </button>
|
|
|
- <button
|
|
|
- class="tab-btn"
|
|
|
- :class="{ active: activeTab === 1 }"
|
|
|
- @click="setActiveTab(1)"
|
|
|
- >
|
|
|
- 国家法规
|
|
|
- </button>
|
|
|
- <button
|
|
|
- class="tab-btn"
|
|
|
- :class="{ active: activeTab === 2 }"
|
|
|
- @click="setActiveTab(2)"
|
|
|
- >
|
|
|
- 行业法规
|
|
|
- </button>
|
|
|
- <button
|
|
|
- class="tab-btn"
|
|
|
- :class="{ active: activeTab === 3 }"
|
|
|
- @click="setActiveTab(3)"
|
|
|
- >
|
|
|
- 地方法规
|
|
|
- </button>
|
|
|
- <button
|
|
|
- class="tab-btn"
|
|
|
- :class="{ active: activeTab === 4 }"
|
|
|
- @click="setActiveTab(4)"
|
|
|
- >
|
|
|
- 内部条例
|
|
|
- </button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 文档列表 -->
|
|
|
- <div class="document-list" ref="documentList" @scroll="handleScroll">
|
|
|
- <!-- 加载中提示 -->
|
|
|
- <div v-if="loading" class="loading">
|
|
|
- <div class="loading-spinner"></div>
|
|
|
- <span>加载中...</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 无数据提示 -->
|
|
|
- <div v-if="!loading && policyFiles.length === 0" class="no-data">
|
|
|
- <span>暂无数据</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 文档项 -->
|
|
|
- <div
|
|
|
- v-for="(file, index) in policyFiles"
|
|
|
- :key="file.id || index"
|
|
|
- class="document-item"
|
|
|
- >
|
|
|
- <div class="doc-icon">
|
|
|
- <img :src="getFileIcon(file.file_type)" :alt="getFileTypeName(file.file_type)" class="file-icon" />
|
|
|
- </div>
|
|
|
- <div class="doc-content">
|
|
|
- <div class="doc-header">
|
|
|
- <h3 class="doc-title">{{ file.policy_name }}</h3>
|
|
|
- <span class="doc-date">{{ formatTime(file.publish_time) }}</span>
|
|
|
+ <!-- 主内容区域 -->
|
|
|
+ <div class="main-content">
|
|
|
+ <!-- 页面标题 -->
|
|
|
+ <div class="page-header">
|
|
|
+ <div class="back-button1" @click="goToHome">
|
|
|
+ <img
|
|
|
+ src="../assets/Policy/9.png"
|
|
|
+ alt="返回"
|
|
|
+ class="back-icon"
|
|
|
+ />
|
|
|
+ <span class="back-text">返回首页</span>
|
|
|
+ </div>
|
|
|
+ <h1 class="page-title">政策文件</h1>
|
|
|
</div>
|
|
|
- <div class="doc-tags">
|
|
|
- <span
|
|
|
- v-for="(tag, tagIndex) in getTags(file.file_tag)"
|
|
|
- :key="tagIndex"
|
|
|
- class="tag tag-blue"
|
|
|
- >
|
|
|
- <img src="../assets/Policy/10.png" alt="标签图标" class="tag-icon" />
|
|
|
- {{ tag }}
|
|
|
- </span>
|
|
|
+
|
|
|
+ <!-- 搜索栏 -->
|
|
|
+ <div class="search-section">
|
|
|
+ <div class="search-box">
|
|
|
+ <div class="search-icon-left">
|
|
|
+ <img
|
|
|
+ src="../assets/Policy/8.png"
|
|
|
+ alt="搜索"
|
|
|
+ class="search-icon"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ placeholder="搜索政策文件..."
|
|
|
+ class="search-input"
|
|
|
+ v-model="searchText"
|
|
|
+ maxlength="100"
|
|
|
+ @input="handleSearchInput"
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <p class="doc-description">
|
|
|
- {{ file.policy_content }}
|
|
|
- </p>
|
|
|
- <div class="doc-footer">
|
|
|
- <div class="doc-info">
|
|
|
- <span class="info-item">
|
|
|
- <img src="../assets/Policy/5.png" alt="部门" class="info-icon" />
|
|
|
- {{ file.policy_department }}
|
|
|
- </span>
|
|
|
- <span class="info-item">
|
|
|
- <img src="../assets/Policy/6.png" alt="次数" class="info-icon" />
|
|
|
- {{ file.view_count }} 次查看
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <div class="doc-actions">
|
|
|
- <button class="action-btn view-btn" @click="viewPolicy(file)">查看详情 ></button>
|
|
|
- <button class="action-btn download-btn" @click="downloadPolicy(file)">
|
|
|
- <img src="../assets/Policy/7.png" alt="" class="action-icon" />
|
|
|
+
|
|
|
+ <!-- 分类标签 -->
|
|
|
+ <div class="category-tabs">
|
|
|
+ <button
|
|
|
+ class="tab-btn"
|
|
|
+ :class="{ active: activeTab === 0 }"
|
|
|
+ @click="setActiveTab(0)"
|
|
|
+ >
|
|
|
+ 全部政策
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="tab-btn"
|
|
|
+ :class="{ active: activeTab === 1 }"
|
|
|
+ @click="setActiveTab(1)"
|
|
|
+ >
|
|
|
+ 国家法规
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="tab-btn"
|
|
|
+ :class="{ active: activeTab === 2 }"
|
|
|
+ @click="setActiveTab(2)"
|
|
|
+ >
|
|
|
+ 行业法规
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="tab-btn"
|
|
|
+ :class="{ active: activeTab === 3 }"
|
|
|
+ @click="setActiveTab(3)"
|
|
|
+ >
|
|
|
+ 地方法规
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="tab-btn"
|
|
|
+ :class="{ active: activeTab === 4 }"
|
|
|
+ @click="setActiveTab(4)"
|
|
|
+ >
|
|
|
+ 内部条例
|
|
|
</button>
|
|
|
- </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 加载更多提示 -->
|
|
|
- <div v-if="hasMore && !loading" class="load-more">
|
|
|
- <span>上拉加载更多</span>
|
|
|
+
|
|
|
+ <!-- 文档列表 -->
|
|
|
+ <div
|
|
|
+ class="document-list"
|
|
|
+ ref="documentList"
|
|
|
+ @scroll="handleScroll"
|
|
|
+ >
|
|
|
+ <!-- 加载中提示 -->
|
|
|
+ <div v-if="loading" class="loading">
|
|
|
+ <div class="loading-spinner"></div>
|
|
|
+ <span>加载中...</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 无数据提示 -->
|
|
|
+ <div
|
|
|
+ v-if="!loading && policyFiles.length === 0"
|
|
|
+ class="no-data"
|
|
|
+ >
|
|
|
+ <span>暂无数据</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 文档项 -->
|
|
|
+ <div
|
|
|
+ v-for="(file, index) in policyFiles"
|
|
|
+ :key="file.id || index"
|
|
|
+ class="document-item"
|
|
|
+ >
|
|
|
+ <div class="doc-icon">
|
|
|
+ <img
|
|
|
+ :src="getFileIcon(file.file_type)"
|
|
|
+ :alt="getFileTypeName(file.file_type)"
|
|
|
+ class="file-icon"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="doc-content">
|
|
|
+ <div class="doc-header">
|
|
|
+ <h3 class="doc-title">{{ file.policy_name }}</h3>
|
|
|
+ <span class="doc-date">{{
|
|
|
+ formatTime(file.publish_time)
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="doc-tags">
|
|
|
+ <span
|
|
|
+ v-for="(tag, tagIndex) in getTags(
|
|
|
+ file.file_tag
|
|
|
+ )"
|
|
|
+ :key="tagIndex"
|
|
|
+ class="tag tag-blue"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src="../assets/Policy/10.png"
|
|
|
+ alt="标签图标"
|
|
|
+ class="tag-icon"
|
|
|
+ />
|
|
|
+ {{ tag }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <p class="doc-description">
|
|
|
+ {{ file.policy_content }}
|
|
|
+ </p>
|
|
|
+ <div class="doc-footer">
|
|
|
+ <div class="doc-info">
|
|
|
+ <span class="info-item">
|
|
|
+ <img
|
|
|
+ src="../assets/Policy/5.png"
|
|
|
+ alt="部门"
|
|
|
+ class="info-icon"
|
|
|
+ />
|
|
|
+ {{ file.policy_department }}
|
|
|
+ </span>
|
|
|
+ <span class="info-item">
|
|
|
+ <img
|
|
|
+ src="../assets/Policy/6.png"
|
|
|
+ alt="次数"
|
|
|
+ class="info-icon"
|
|
|
+ />
|
|
|
+ {{ file.view_count }} 次查看
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="doc-actions">
|
|
|
+ <button
|
|
|
+ class="action-btn view-btn"
|
|
|
+ @click="viewPolicy(file)"
|
|
|
+ >
|
|
|
+ 查看详情 >
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="action-btn download-btn"
|
|
|
+ @click="downloadPolicy(file)"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ src="../assets/Policy/7.png"
|
|
|
+ alt=""
|
|
|
+ class="action-icon"
|
|
|
+ />
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 加载更多提示 -->
|
|
|
+ <div v-if="hasMore && !loading" class="load-more">
|
|
|
+ <span>上拉加载更多</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import { ref, onMounted, onUnmounted } from "vue";
|
|
|
import { useRouter } from "vue-router";
|
|
|
-import { apis } from '@/request/apis.js'
|
|
|
+import { apis } from "@/request/apis.js";
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
@@ -170,685 +221,693 @@ let searchTimer = null;
|
|
|
|
|
|
// 方法
|
|
|
const goToHome = () => {
|
|
|
- router.push("/");
|
|
|
+ router.push("/");
|
|
|
};
|
|
|
|
|
|
const setActiveTab = (tabIndex) => {
|
|
|
- activeTab.value = tabIndex;
|
|
|
- page.value = 1; // Reset page when changing category
|
|
|
- policyFiles.value = []; // Clear previous data
|
|
|
- hasMore.value = true;
|
|
|
- fetchPolicyFiles();
|
|
|
+ activeTab.value = tabIndex;
|
|
|
+ page.value = 1; // Reset page when changing category
|
|
|
+ policyFiles.value = []; // Clear previous data
|
|
|
+ hasMore.value = true;
|
|
|
+ fetchPolicyFiles();
|
|
|
};
|
|
|
|
|
|
const fetchPolicyFiles = async (isLoadMore = false) => {
|
|
|
- if (loading.value) return;
|
|
|
-
|
|
|
- loading.value = true;
|
|
|
- try {
|
|
|
- const params = {
|
|
|
- page: page.value,
|
|
|
- pageSize: pageSize.value,
|
|
|
- search: searchText.value,
|
|
|
- policy_type: activeTab.value === 0 ? '' : activeTab.value, // 0表示全部,不传policy_type
|
|
|
- };
|
|
|
-
|
|
|
- console.log('请求参数:', params);
|
|
|
- const response = await apis.getPolicyFile(params);
|
|
|
- console.log('API响应:', response);
|
|
|
-
|
|
|
- if (response && response.data) {
|
|
|
- const newFiles = response.data;
|
|
|
- if (isLoadMore) {
|
|
|
- policyFiles.value = [...policyFiles.value, ...newFiles];
|
|
|
- } else {
|
|
|
- policyFiles.value = newFiles;
|
|
|
- }
|
|
|
-
|
|
|
- // 判断是否还有更多数据
|
|
|
- hasMore.value = newFiles.length === pageSize.value;
|
|
|
+ if (loading.value) return;
|
|
|
+
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ page: page.value,
|
|
|
+ pageSize: pageSize.value,
|
|
|
+ search: searchText.value,
|
|
|
+ policy_type: activeTab.value === 0 ? "" : activeTab.value, // 0表示全部,不传policy_type
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log("请求参数:", params);
|
|
|
+ const response = await apis.getPolicyFile(params);
|
|
|
+ console.log("API响应:", response);
|
|
|
+
|
|
|
+ if (response && response.data) {
|
|
|
+ const newFiles = response.data;
|
|
|
+ if (isLoadMore) {
|
|
|
+ policyFiles.value = [...policyFiles.value, ...newFiles];
|
|
|
+ } else {
|
|
|
+ policyFiles.value = newFiles;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断是否还有更多数据
|
|
|
+ hasMore.value = newFiles.length === pageSize.value;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("获取政策文件失败:", error);
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error("获取政策文件失败:", error);
|
|
|
- } finally {
|
|
|
- loading.value = false;
|
|
|
- }
|
|
|
};
|
|
|
|
|
|
const handleSearchInput = () => {
|
|
|
- // 清除之前的定时器
|
|
|
- if (searchTimer) {
|
|
|
- clearTimeout(searchTimer);
|
|
|
- }
|
|
|
-
|
|
|
- // 设置新的定时器,300ms后执行搜索
|
|
|
- searchTimer = setTimeout(() => {
|
|
|
- page.value = 1; // Reset page when input changes
|
|
|
- policyFiles.value = [];
|
|
|
- hasMore.value = true;
|
|
|
- fetchPolicyFiles();
|
|
|
- }, 300);
|
|
|
+ // 清除之前的定时器
|
|
|
+ if (searchTimer) {
|
|
|
+ clearTimeout(searchTimer);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置新的定时器,300ms后执行搜索
|
|
|
+ searchTimer = setTimeout(() => {
|
|
|
+ page.value = 1; // Reset page when input changes
|
|
|
+ policyFiles.value = [];
|
|
|
+ hasMore.value = true;
|
|
|
+ fetchPolicyFiles();
|
|
|
+ }, 300);
|
|
|
};
|
|
|
|
|
|
const handleSearch = () => {
|
|
|
- if (searchText.value.trim()) {
|
|
|
- page.value = 1; // Reset page when searching
|
|
|
- policyFiles.value = [];
|
|
|
- hasMore.value = true;
|
|
|
- fetchPolicyFiles();
|
|
|
- }
|
|
|
+ if (searchText.value.trim()) {
|
|
|
+ page.value = 1; // Reset page when searching
|
|
|
+ policyFiles.value = [];
|
|
|
+ hasMore.value = true;
|
|
|
+ fetchPolicyFiles();
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const viewPolicy = async (file) => {
|
|
|
- console.log("查看政策文件:", file);
|
|
|
- console.log("文件ID:", file.id, "文件所有字段:", Object.keys(file));
|
|
|
-
|
|
|
- if (!file.policy_file_url) {
|
|
|
- alert('文件链接不存在');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查ID是否存在
|
|
|
- if (!file.id) {
|
|
|
- console.error('政策文件ID不存在,跳过次数更新');
|
|
|
- } else {
|
|
|
- // 前端直接更新查看次数显示
|
|
|
- file.view_count = (file.view_count || 0) + 1;
|
|
|
-
|
|
|
- // 更新查看次数到后端
|
|
|
- try {
|
|
|
- await apis.updatePolicyFileCount({
|
|
|
- policy_file_id: file.id,
|
|
|
- action_type: 1 // 1-查看
|
|
|
- });
|
|
|
- console.log('查看次数更新成功');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新查看次数失败:', error);
|
|
|
- // 如果后端更新失败,回滚前端显示
|
|
|
- file.view_count = (file.view_count || 1) - 1;
|
|
|
+ console.log("查看政策文件:", file);
|
|
|
+ console.log("文件ID:", file.id, "文件所有字段:", Object.keys(file));
|
|
|
+
|
|
|
+ if (!file.policy_file_url) {
|
|
|
+ alert("文件链接不存在");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查ID是否存在
|
|
|
+ if (!file.id) {
|
|
|
+ console.error("政策文件ID不存在,跳过次数更新");
|
|
|
+ } else {
|
|
|
+ // 前端直接更新查看次数显示
|
|
|
+ file.view_count = (file.view_count || 0) + 1;
|
|
|
+
|
|
|
+ // 更新查看次数到后端
|
|
|
+ try {
|
|
|
+ await apis.updatePolicyFileCount({
|
|
|
+ policy_file_id: file.id,
|
|
|
+ action_type: 1, // 1-查看
|
|
|
+ });
|
|
|
+ console.log("查看次数更新成功");
|
|
|
+ } catch (error) {
|
|
|
+ console.error("更新查看次数失败:", error);
|
|
|
+ // 如果后端更新失败,回滚前端显示
|
|
|
+ file.view_count = (file.view_count || 1) - 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据文件类型决定查看方式
|
|
|
+ const fileType = file.file_type;
|
|
|
+
|
|
|
+ if (fileType === 0) {
|
|
|
+ // PDF文件 - 新窗口预览
|
|
|
+ window.open(file.policy_file_url, "_blank");
|
|
|
+ } else if (fileType === 1 || fileType === 2) {
|
|
|
+ // Word/Excel文件 - 使用Office Online预览或Google Docs预览
|
|
|
+ const encodedUrl = encodeURIComponent(file.policy_file_url);
|
|
|
+
|
|
|
+ // 尝试使用Office Online预览
|
|
|
+ const officeOnlineUrl = `https://view.officeapps.live.com/op/embed.aspx?src=${encodedUrl}`;
|
|
|
+ window.open(officeOnlineUrl, "_blank");
|
|
|
+ } else {
|
|
|
+ // 其他文件类型 - 直接打开
|
|
|
+ window.open(file.policy_file_url, "_blank");
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- // 根据文件类型决定查看方式
|
|
|
- const fileType = file.file_type;
|
|
|
-
|
|
|
- if (fileType === 0) {
|
|
|
- // PDF文件 - 新窗口预览
|
|
|
- window.open(file.policy_file_url, '_blank');
|
|
|
- } else if (fileType === 1 || fileType === 2) {
|
|
|
- // Word/Excel文件 - 使用Office Online预览或Google Docs预览
|
|
|
- const encodedUrl = encodeURIComponent(file.policy_file_url);
|
|
|
-
|
|
|
- // 尝试使用Office Online预览
|
|
|
- const officeOnlineUrl = `https://view.officeapps.live.com/op/embed.aspx?src=${encodedUrl}`;
|
|
|
- window.open(officeOnlineUrl, '_blank');
|
|
|
- } else {
|
|
|
- // 其他文件类型 - 直接打开
|
|
|
- window.open(file.policy_file_url, '_blank');
|
|
|
- }
|
|
|
};
|
|
|
|
|
|
const downloadPolicy = async (file) => {
|
|
|
- console.log("下载政策文件:", file);
|
|
|
- console.log("文件ID:", file.id, "文件所有字段:", Object.keys(file));
|
|
|
-
|
|
|
- if (!file.policy_file_url) {
|
|
|
- alert('文件链接不存在');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查ID是否存在
|
|
|
- if (!file.id) {
|
|
|
- console.error('政策文件ID不存在,跳过次数更新');
|
|
|
- } else {
|
|
|
- // 更新下载次数
|
|
|
- try {
|
|
|
- await apis.updatePolicyFileCount({
|
|
|
- policy_file_id: file.id,
|
|
|
- action_type: 2 // 2-下载
|
|
|
- });
|
|
|
- console.log('下载次数更新成功');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新下载次数失败:', error);
|
|
|
+ console.log("下载政策文件:", file);
|
|
|
+ console.log("文件ID:", file.id, "文件所有字段:", Object.keys(file));
|
|
|
+
|
|
|
+ if (!file.policy_file_url) {
|
|
|
+ alert("文件链接不存在");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查ID是否存在
|
|
|
+ if (!file.id) {
|
|
|
+ console.error("政策文件ID不存在,跳过次数更新");
|
|
|
+ } else {
|
|
|
+ // 更新下载次数
|
|
|
+ try {
|
|
|
+ await apis.updatePolicyFileCount({
|
|
|
+ policy_file_id: file.id,
|
|
|
+ action_type: 2, // 2-下载
|
|
|
+ });
|
|
|
+ console.log("下载次数更新成功");
|
|
|
+ } catch (error) {
|
|
|
+ console.error("更新下载次数失败:", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据文件类型设置下载文件名
|
|
|
+ let fileName = file.policy_name || "政策文件";
|
|
|
+ const fileType = file.file_type;
|
|
|
+
|
|
|
+ // 添加文件扩展名
|
|
|
+ if (fileType === 0) {
|
|
|
+ fileName += ".pdf";
|
|
|
+ } else if (fileType === 1) {
|
|
|
+ fileName += ".docx";
|
|
|
+ } else if (fileType === 2) {
|
|
|
+ fileName += ".xlsx";
|
|
|
+ } else if (fileType === 3) {
|
|
|
+ fileName += ".pptx";
|
|
|
+ } else if (fileType === 4) {
|
|
|
+ fileName += ".txt";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fileType === 0) {
|
|
|
+ // PDF文件 - 通过后端代理下载
|
|
|
+ console.log("PDF下载URL:", file.policy_file_url);
|
|
|
+
|
|
|
+ // 调用后端下载接口
|
|
|
+ downloadFileViaBackend(file.policy_file_url, fileName);
|
|
|
+ } else {
|
|
|
+ // 其他文件类型 - 使用window.open方式下载
|
|
|
+ console.log("其他文件类型下载URL111111:", file.policy_file_url);
|
|
|
+ window.open(file.policy_file_url, "_blank");
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- // 根据文件类型设置下载文件名
|
|
|
- let fileName = file.policy_name || '政策文件';
|
|
|
- const fileType = file.file_type;
|
|
|
-
|
|
|
- // 添加文件扩展名
|
|
|
- if (fileType === 0) {
|
|
|
- fileName += '.pdf';
|
|
|
- } else if (fileType === 1) {
|
|
|
- fileName += '.docx';
|
|
|
- } else if (fileType === 2) {
|
|
|
- fileName += '.xlsx';
|
|
|
- } else if (fileType === 3) {
|
|
|
- fileName += '.pptx';
|
|
|
- } else if (fileType === 4) {
|
|
|
- fileName += '.txt';
|
|
|
- }
|
|
|
-
|
|
|
- if (fileType === 0) {
|
|
|
- // PDF文件 - 通过后端代理下载
|
|
|
- console.log('PDF下载URL:', file.policy_file_url);
|
|
|
-
|
|
|
- // 调用后端下载接口
|
|
|
- downloadFileViaBackend(file.policy_file_url, fileName);
|
|
|
- } else {
|
|
|
- // 其他文件类型 - 使用window.open方式下载
|
|
|
- console.log('其他文件类型下载URL111111:', file.policy_file_url);
|
|
|
- window.open(file.policy_file_url, '_blank');
|
|
|
- }
|
|
|
};
|
|
|
|
|
|
// 最简单的下载方式
|
|
|
const downloadFileViaBackend = (fileUrl, fileName) => {
|
|
|
- const downloadUrl = `/apiv1/download_file?pdf_oss_download_link=${encodeURIComponent(fileUrl)}&file_name=${encodeURIComponent(fileName)}`;
|
|
|
-
|
|
|
- // 创建隐藏的a标签进行下载
|
|
|
- const a = document.createElement('a');
|
|
|
- a.href = downloadUrl;
|
|
|
- a.download = fileName || 'download_file';
|
|
|
- a.style.display = 'none';
|
|
|
- document.body.appendChild(a);
|
|
|
- a.click();
|
|
|
- document.body.removeChild(a);
|
|
|
+ const downloadUrl = `/apiv1/download_file?pdf_oss_download_link=${encodeURIComponent(
|
|
|
+ fileUrl
|
|
|
+ )}&file_name=${encodeURIComponent(fileName)}`;
|
|
|
+
|
|
|
+ // 创建隐藏的a标签进行下载
|
|
|
+ const a = document.createElement("a");
|
|
|
+ a.href = downloadUrl;
|
|
|
+ a.download = fileName || "download_file";
|
|
|
+ a.style.display = "none";
|
|
|
+ document.body.appendChild(a);
|
|
|
+ a.click();
|
|
|
+ document.body.removeChild(a);
|
|
|
};
|
|
|
// 导入文件类型图标
|
|
|
-import pdfIcon from '@/assets/Policy/2.png'
|
|
|
-import wordIcon from '@/assets/Policy/3.png'
|
|
|
-import excelIcon from '@/assets/Policy/4.png'
|
|
|
+import pdfIcon from "@/assets/Policy/2.png";
|
|
|
+import wordIcon from "@/assets/Policy/3.png";
|
|
|
+import excelIcon from "@/assets/Policy/4.png";
|
|
|
|
|
|
const getFileIcon = (fileType) => {
|
|
|
- // 根据文件类型返回对应的图标
|
|
|
- const iconMap = {
|
|
|
- 0: pdfIcon, // PDF
|
|
|
- 1: wordIcon, // Word
|
|
|
- 2: excelIcon, // Excel
|
|
|
- 3: pdfIcon, // PPT (暂时用PDF图标)
|
|
|
- 4: pdfIcon, // TXT (暂时用PDF图标)
|
|
|
- 5: pdfIcon, // 其他 (暂时用PDF图标)
|
|
|
- };
|
|
|
- return iconMap[fileType] || pdfIcon;
|
|
|
+ // 根据文件类型返回对应的图标
|
|
|
+ const iconMap = {
|
|
|
+ 0: pdfIcon, // PDF
|
|
|
+ 1: wordIcon, // Word
|
|
|
+ 2: excelIcon, // Excel
|
|
|
+ 3: pdfIcon, // PPT (暂时用PDF图标)
|
|
|
+ 4: pdfIcon, // TXT (暂时用PDF图标)
|
|
|
+ 5: pdfIcon, // 其他 (暂时用PDF图标)
|
|
|
+ };
|
|
|
+ return iconMap[fileType] || pdfIcon;
|
|
|
};
|
|
|
|
|
|
const getFileTypeName = (fileType) => {
|
|
|
- const typeMap = {
|
|
|
- 0: 'PDF',
|
|
|
- 1: 'Word',
|
|
|
- 2: 'Excel',
|
|
|
- 3: 'PPT',
|
|
|
- 4: 'TXT',
|
|
|
- 5: '其他',
|
|
|
- };
|
|
|
- return typeMap[fileType] || '文件';
|
|
|
+ const typeMap = {
|
|
|
+ 0: "PDF",
|
|
|
+ 1: "Word",
|
|
|
+ 2: "Excel",
|
|
|
+ 3: "PPT",
|
|
|
+ 4: "TXT",
|
|
|
+ 5: "其他",
|
|
|
+ };
|
|
|
+ return typeMap[fileType] || "文件";
|
|
|
};
|
|
|
|
|
|
const getTags = (tagString) => {
|
|
|
- console.log('原始标签字符串:', tagString);
|
|
|
- if (!tagString) return ['政策文件'];
|
|
|
- // 按逗号分割标签,并去除空格
|
|
|
- const tags = tagString.split(',').map(tag => tag.trim()).filter(tag => tag.length > 0);
|
|
|
- console.log('拆分后的标签数组:', tags);
|
|
|
- return tags;
|
|
|
+ console.log("原始标签字符串:", tagString);
|
|
|
+ if (!tagString) return ["政策文件"];
|
|
|
+ // 按逗号分割标签,并去除空格
|
|
|
+ const tags = tagString
|
|
|
+ .split(",")
|
|
|
+ .map((tag) => tag.trim())
|
|
|
+ .filter((tag) => tag.length > 0);
|
|
|
+ console.log("拆分后的标签数组:", tags);
|
|
|
+ return tags;
|
|
|
};
|
|
|
|
|
|
const formatTime = (timestamp) => {
|
|
|
- if (!timestamp) return '';
|
|
|
- const date = new Date(timestamp * 1000); // 后端时间戳是秒,需要转换为毫秒
|
|
|
- const year = date.getFullYear();
|
|
|
- const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
- const day = String(date.getDate()).padStart(2, '0');
|
|
|
- return `${year}-${month}-${day}`;
|
|
|
+ if (!timestamp) return "";
|
|
|
+ const date = new Date(timestamp * 1000); // 后端时间戳是秒,需要转换为毫秒
|
|
|
+ const year = date.getFullYear();
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
|
+ const day = String(date.getDate()).padStart(2, "0");
|
|
|
+ return `${year}-${month}-${day}`;
|
|
|
};
|
|
|
|
|
|
// 防抖滚动处理
|
|
|
let scrollTimer = null;
|
|
|
const handleScroll = (event) => {
|
|
|
- // 清除之前的定时器
|
|
|
- if (scrollTimer) {
|
|
|
- clearTimeout(scrollTimer);
|
|
|
- }
|
|
|
-
|
|
|
- // 设置新的定时器,100ms后执行检查
|
|
|
- scrollTimer = setTimeout(() => {
|
|
|
- const target = event.target;
|
|
|
- const scrollTop = target.scrollTop;
|
|
|
- const scrollHeight = target.scrollHeight;
|
|
|
- const clientHeight = target.clientHeight;
|
|
|
-
|
|
|
- // 当滚动到距离底部50px时,加载更多
|
|
|
- if (scrollTop + clientHeight >= scrollHeight - 50 && hasMore.value && !loading.value) {
|
|
|
- page.value++;
|
|
|
- fetchPolicyFiles(true); // 标记为加载更多
|
|
|
+ // 清除之前的定时器
|
|
|
+ if (scrollTimer) {
|
|
|
+ clearTimeout(scrollTimer);
|
|
|
}
|
|
|
- }, 100);
|
|
|
+
|
|
|
+ // 设置新的定时器,100ms后执行检查
|
|
|
+ scrollTimer = setTimeout(() => {
|
|
|
+ const target = event.target;
|
|
|
+ const scrollTop = target.scrollTop;
|
|
|
+ const scrollHeight = target.scrollHeight;
|
|
|
+ const clientHeight = target.clientHeight;
|
|
|
+
|
|
|
+ // 当滚动到距离底部50px时,加载更多
|
|
|
+ if (
|
|
|
+ scrollTop + clientHeight >= scrollHeight - 50 &&
|
|
|
+ hasMore.value &&
|
|
|
+ !loading.value
|
|
|
+ ) {
|
|
|
+ page.value++;
|
|
|
+ fetchPolicyFiles(true); // 标记为加载更多
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
};
|
|
|
|
|
|
// 监听滚动事件
|
|
|
onMounted(() => {
|
|
|
- // 初始加载数据
|
|
|
- fetchPolicyFiles();
|
|
|
+ // 初始加载数据
|
|
|
+ fetchPolicyFiles();
|
|
|
});
|
|
|
|
|
|
// 组件卸载时移除事件监听和清理定时器
|
|
|
onUnmounted(() => {
|
|
|
- // 清理滚动定时器
|
|
|
- if (scrollTimer) {
|
|
|
- clearTimeout(scrollTimer);
|
|
|
- }
|
|
|
- // 清理搜索定时器
|
|
|
- if (searchTimer) {
|
|
|
- clearTimeout(searchTimer);
|
|
|
- }
|
|
|
+ // 清理滚动定时器
|
|
|
+ if (scrollTimer) {
|
|
|
+ clearTimeout(scrollTimer);
|
|
|
+ }
|
|
|
+ // 清理搜索定时器
|
|
|
+ if (searchTimer) {
|
|
|
+ clearTimeout(searchTimer);
|
|
|
+ }
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
.policy-container {
|
|
|
- min-height: 100vh;
|
|
|
- background-image: url("../assets/Policy/1.png");
|
|
|
- background-size: cover;
|
|
|
- background-position: center;
|
|
|
- background-repeat: no-repeat;
|
|
|
- font-family: "Alibaba PuHuiTi 3.0", sans-serif;
|
|
|
- overflow-x: hidden; /* 防止出现横向滚动条 */
|
|
|
+ min-height: 100vh;
|
|
|
+ background-image: url("../assets/Policy/1.png");
|
|
|
+ background-size: cover;
|
|
|
+ background-position: center;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ font-family: "Alibaba PuHuiTi 3.0", sans-serif;
|
|
|
+ overflow-x: hidden; /* 防止出现横向滚动条 */
|
|
|
}
|
|
|
|
|
|
/* 顶部导航栏 */
|
|
|
.header {
|
|
|
- padding: 19px 0 0 105px;
|
|
|
+ padding: 19px 0 0 105px;
|
|
|
|
|
|
- .logo-section {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- // gap: 7px;
|
|
|
- cursor: pointer;
|
|
|
- transition: opacity 0.3s ease;
|
|
|
+ .logo-section {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ // gap: 7px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: opacity 0.3s ease;
|
|
|
|
|
|
- &:hover {
|
|
|
- opacity: 0.8;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
|
|
|
- .logo-img {
|
|
|
- width: 151px;
|
|
|
- height: 44px;
|
|
|
- // border-radius: 50%;
|
|
|
- }
|
|
|
+ .logo-img {
|
|
|
+ width: 151px;
|
|
|
+ height: 44px;
|
|
|
+ // border-radius: 50%;
|
|
|
+ }
|
|
|
|
|
|
- .logo-text {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: bold;
|
|
|
- color: #2563eb;
|
|
|
- margin-bottom: 5px;
|
|
|
+ .logo-text {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #2563eb;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/* 主内容区域 */
|
|
|
.main-content {
|
|
|
- max-width: 968px;
|
|
|
- margin: 0 auto;
|
|
|
- padding: 14px 0;
|
|
|
- text-align: left;
|
|
|
+ max-width: 968px;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 14px 0;
|
|
|
+ text-align: left;
|
|
|
}
|
|
|
|
|
|
/* 页面头部区域 */
|
|
|
.page-header {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-start;
|
|
|
- width: 968px;
|
|
|
- margin-bottom: 14px;
|
|
|
-
|
|
|
- .back-button1 {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
- cursor: pointer;
|
|
|
- transition: opacity 0.3s ease;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- opacity: 0.8;
|
|
|
- }
|
|
|
-
|
|
|
- .back-icon {
|
|
|
- width: 20px;
|
|
|
- height: 20px;
|
|
|
+ justify-content: flex-start;
|
|
|
+ width: 968px;
|
|
|
+ margin-bottom: 14px;
|
|
|
+
|
|
|
+ .back-button1 {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: opacity 0.3s ease;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ opacity: 0.8;
|
|
|
+ }
|
|
|
+
|
|
|
+ .back-icon {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .back-text {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #3b82f6;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- .back-text {
|
|
|
- font-size: 16px;
|
|
|
- color: #3b82f6;
|
|
|
- font-weight: 500;
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 900;
|
|
|
+ color: #111827;
|
|
|
+ margin: 0;
|
|
|
+ margin-left: 19px;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- .page-title {
|
|
|
- font-size: 18px;
|
|
|
- font-weight: 900;
|
|
|
- color: #111827;
|
|
|
- margin: 0;
|
|
|
- margin-left: 19px;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/* 搜索栏 */
|
|
|
.search-section {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-start;
|
|
|
- margin-bottom: 14px;
|
|
|
-
|
|
|
- .search-box {
|
|
|
- position: relative;
|
|
|
- width: 100%;
|
|
|
- max-width: 968px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-start;
|
|
|
+ margin-bottom: 14px;
|
|
|
+
|
|
|
+ .search-box {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 968px;
|
|
|
+
|
|
|
+ .search-icon-left {
|
|
|
+ position: absolute;
|
|
|
+ left: 14px;
|
|
|
+ z-index: 10;
|
|
|
+ top: 14px;
|
|
|
+
|
|
|
+ .search-icon {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .search-icon-left {
|
|
|
- position: absolute;
|
|
|
- left: 14px;
|
|
|
- z-index: 10;
|
|
|
- top: 14px;
|
|
|
-
|
|
|
- .search-icon {
|
|
|
- width: 20px;
|
|
|
- height: 20px;
|
|
|
- opacity: 0.6;
|
|
|
- }
|
|
|
- }
|
|
|
+ .search-input {
|
|
|
+ width: 968px;
|
|
|
+ height: 48px;
|
|
|
+ padding: 0 60px 0 50px;
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-size: 16px;
|
|
|
+ background: white;
|
|
|
+ outline: none;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ border-color: #3b82f6;
|
|
|
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
|
+ }
|
|
|
|
|
|
- .search-input {
|
|
|
- width: 968px;
|
|
|
- height: 48px;
|
|
|
- padding: 0 60px 0 50px;
|
|
|
- border: 1px solid #e5e7eb;
|
|
|
- border-radius: 8px;
|
|
|
- font-size: 16px;
|
|
|
- background: white;
|
|
|
- outline: none;
|
|
|
- transition: all 0.3s ease;
|
|
|
-
|
|
|
- &:focus {
|
|
|
- border-color: #3b82f6;
|
|
|
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
|
- }
|
|
|
-
|
|
|
- &::placeholder {
|
|
|
- color: #9ca3af;
|
|
|
- }
|
|
|
+ &::placeholder {
|
|
|
+ color: #9ca3af;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/* 分类标签 */
|
|
|
.category-tabs {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-start;
|
|
|
- gap: 0;
|
|
|
- margin-bottom: 14px;
|
|
|
- border-bottom: 1px solid #E5E7EB;
|
|
|
- width: 100%;
|
|
|
-
|
|
|
- .tab-btn {
|
|
|
- padding: 12px 24px;
|
|
|
- border: none;
|
|
|
- background: transparent;
|
|
|
- font-size: 14px;
|
|
|
- color: #6b7280;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s ease;
|
|
|
- position: relative;
|
|
|
- border-bottom: 2px solid transparent;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-start;
|
|
|
+ gap: 0;
|
|
|
+ margin-bottom: 14px;
|
|
|
+ border-bottom: 1px solid #e5e7eb;
|
|
|
+ width: 100%;
|
|
|
|
|
|
- &:hover {
|
|
|
- color: #2563EB;
|
|
|
- }
|
|
|
+ .tab-btn {
|
|
|
+ padding: 12px 24px;
|
|
|
+ border: none;
|
|
|
+ background: transparent;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #6b7280;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ position: relative;
|
|
|
+ border-bottom: 2px solid transparent;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #2563eb;
|
|
|
+ }
|
|
|
|
|
|
- &.active {
|
|
|
- color: #2563EB;
|
|
|
- border-bottom-color: #2563EB;
|
|
|
+ &.active {
|
|
|
+ color: #2563eb;
|
|
|
+ border-bottom-color: #2563eb;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/* 文档列表 */
|
|
|
.document-list {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 10px;
|
|
|
- min-height: 400px; /* 设置最小高度 */
|
|
|
- max-height: calc(100vh - 300px); /* 设置最大高度,防止超出视窗 */
|
|
|
- overflow-y: auto; /* Enable scrolling for the list */
|
|
|
- overflow-x: hidden; /* 禁用横向滚动 */
|
|
|
- padding-right: 10px; /* Add some padding for scrollbar */
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 10px;
|
|
|
+ min-height: 400px; /* 设置最小高度 */
|
|
|
+ max-height: calc(100vh - 300px); /* 设置最大高度,防止超出视窗 */
|
|
|
+ overflow-y: auto; /* Enable scrolling for the list */
|
|
|
+ overflow-x: hidden; /* 禁用横向滚动 */
|
|
|
+ padding-right: 10px; /* Add some padding for scrollbar */
|
|
|
}
|
|
|
|
|
|
/* 文档项 */
|
|
|
.document-item {
|
|
|
- background: white;
|
|
|
- width: 968px;
|
|
|
- height: 166px;
|
|
|
- border-radius: 12px;
|
|
|
- padding: 20px 24px;
|
|
|
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
- transition: all 0.3s ease;
|
|
|
- display: flex;
|
|
|
- gap: 16px;
|
|
|
- border: 1px solid #f1f5f9;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- transform: translateY(-1px);
|
|
|
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
- }
|
|
|
-
|
|
|
- .doc-icon {
|
|
|
- flex-shrink: 0;
|
|
|
-
|
|
|
- .file-icon {
|
|
|
- width: 24px;
|
|
|
- height: 24px;
|
|
|
- object-fit: contain;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .doc-content {
|
|
|
- flex: 1;
|
|
|
-
|
|
|
- .doc-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: flex-start;
|
|
|
- margin-bottom: 8px;
|
|
|
-
|
|
|
- .doc-title {
|
|
|
- font-size: 18px;
|
|
|
- font-weight: 600;
|
|
|
- color: #1f2937;
|
|
|
- margin: 0;
|
|
|
- line-height: 1.4;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- display: -webkit-box;
|
|
|
- -webkit-line-clamp: 1;
|
|
|
- -webkit-box-orient: vertical;
|
|
|
- flex: 1;
|
|
|
- margin-right: 16px;
|
|
|
- }
|
|
|
+ background: white;
|
|
|
+ width: 968px;
|
|
|
+ height: 166px;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 20px 24px;
|
|
|
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ display: flex;
|
|
|
+ gap: 16px;
|
|
|
+ border: 1px solid #f1f5f9;
|
|
|
|
|
|
- .doc-date {
|
|
|
- font-size: 14px;
|
|
|
- color: #6b7280;
|
|
|
- white-space: nowrap;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ transform: translateY(-1px);
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
}
|
|
|
|
|
|
- .doc-tags {
|
|
|
- display: flex;
|
|
|
- gap: 12px; /* 增加标签之间的间距 */
|
|
|
- margin-bottom: 8px;
|
|
|
- flex-wrap: wrap; /* 允许标签换行 */
|
|
|
-
|
|
|
- .tag {
|
|
|
- padding: 4px 12px;
|
|
|
- font-size: 12px;
|
|
|
- border-radius: 12px;
|
|
|
- font-weight: 500;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 4px;
|
|
|
- background: #EFF6FF;
|
|
|
- color: #2563EB;
|
|
|
- white-space: nowrap; /* 防止标签文字换行 */
|
|
|
-
|
|
|
- .tag-icon {
|
|
|
- width: 12px;
|
|
|
- height: 12px;
|
|
|
- flex-shrink: 0;
|
|
|
+ .doc-icon {
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ .file-icon {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ object-fit: contain;
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- .doc-description {
|
|
|
- font-size: 14px;
|
|
|
- color: #6b7280;
|
|
|
- line-height: 1.6;
|
|
|
- margin: 0 0 5px 0;
|
|
|
- }
|
|
|
+ .doc-content {
|
|
|
+ flex: 1;
|
|
|
|
|
|
- .doc-footer {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
+ .doc-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-bottom: 8px;
|
|
|
+
|
|
|
+ .doc-title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+ margin: 0;
|
|
|
+ line-height: 1.4;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ display: -webkit-box;
|
|
|
+ -webkit-line-clamp: 1;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
+ flex: 1;
|
|
|
+ margin-right: 16px;
|
|
|
+ }
|
|
|
|
|
|
- .doc-info {
|
|
|
- display: flex;
|
|
|
- gap: 24px;
|
|
|
-
|
|
|
- .info-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
- font-size: 14px;
|
|
|
- color: #6b7280;
|
|
|
-
|
|
|
- .info-icon {
|
|
|
- width: 16px;
|
|
|
- height: 16px;
|
|
|
- opacity: 0.6;
|
|
|
- }
|
|
|
+ .doc-date {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #6b7280;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- .doc-actions {
|
|
|
- display: flex;
|
|
|
|
|
|
- //doc-actions下的第一个action-btn
|
|
|
- .action-btn:first-child {
|
|
|
- margin-right: 8px;
|
|
|
+ .doc-tags {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px; /* 增加标签之间的间距 */
|
|
|
+ margin-bottom: 8px;
|
|
|
+ flex-wrap: wrap; /* 允许标签换行 */
|
|
|
+
|
|
|
+ .tag {
|
|
|
+ padding: 4px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+ background: #eff6ff;
|
|
|
+ color: #2563eb;
|
|
|
+ white-space: nowrap; /* 防止标签文字换行 */
|
|
|
+
|
|
|
+ .tag-icon {
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- .action-btn {
|
|
|
- padding: 6px 0;
|
|
|
- border: none;
|
|
|
- border-radius: 6px;
|
|
|
- font-size: 14px;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s ease;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
-
|
|
|
-
|
|
|
- &.view-btn {
|
|
|
- color: #3b82f6;
|
|
|
- background: transparent;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- &.download-btn {
|
|
|
+ .doc-description {
|
|
|
+ font-size: 14px;
|
|
|
color: #6b7280;
|
|
|
- background: transparent;
|
|
|
-
|
|
|
+ line-height: 1.6;
|
|
|
+ margin: 0 0 5px 0;
|
|
|
+ }
|
|
|
|
|
|
+ .doc-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .doc-info {
|
|
|
+ display: flex;
|
|
|
+ gap: 24px;
|
|
|
+
|
|
|
+ .info-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #6b7280;
|
|
|
+
|
|
|
+ .info-icon {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .action-icon {
|
|
|
- width: 72px;
|
|
|
- height: 28px;
|
|
|
+ .doc-actions {
|
|
|
+ display: flex;
|
|
|
+
|
|
|
+ //doc-actions下的第一个action-btn
|
|
|
+ .action-btn:first-child {
|
|
|
+ margin-right: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-btn {
|
|
|
+ padding: 6px 0;
|
|
|
+ border: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+
|
|
|
+ &.view-btn {
|
|
|
+ color: #3b82f6;
|
|
|
+ background: transparent;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.download-btn {
|
|
|
+ color: #6b7280;
|
|
|
+ background: transparent;
|
|
|
+
|
|
|
+ .action-icon {
|
|
|
+ width: 72px;
|
|
|
+ height: 28px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
/* 加载中提示 */
|
|
|
.loading {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 40px 20px;
|
|
|
- color: #6b7280;
|
|
|
- font-size: 16px;
|
|
|
-
|
|
|
- .loading-spinner {
|
|
|
- border: 4px solid #f3f3f3;
|
|
|
- border-top: 4px solid #3b82f6;
|
|
|
- border-radius: 50%;
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- animation: spin 1s linear infinite;
|
|
|
- margin-bottom: 16px;
|
|
|
- }
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 40px 20px;
|
|
|
+ color: #6b7280;
|
|
|
+ font-size: 16px;
|
|
|
+
|
|
|
+ .loading-spinner {
|
|
|
+ border: 4px solid #f3f3f3;
|
|
|
+ border-top: 4px solid #3b82f6;
|
|
|
+ border-radius: 50%;
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ animation: spin 1s linear infinite;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@keyframes spin {
|
|
|
- 0% { transform: rotate(0deg); }
|
|
|
- 100% { transform: rotate(360deg); }
|
|
|
+ 0% {
|
|
|
+ transform: rotate(0deg);
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ transform: rotate(360deg);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* 无数据提示 */
|
|
|
.no-data {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- padding: 60px 20px;
|
|
|
- color: #9ca3af;
|
|
|
- font-size: 16px;
|
|
|
- text-align: center;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ padding: 60px 20px;
|
|
|
+ color: #9ca3af;
|
|
|
+ font-size: 16px;
|
|
|
+ text-align: center;
|
|
|
}
|
|
|
|
|
|
/* 加载更多提示 */
|
|
|
.load-more {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- padding: 20px;
|
|
|
- color: #6b7280;
|
|
|
- font-size: 14px;
|
|
|
- border-top: 1px solid #e5e7eb;
|
|
|
- margin-top: 10px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ padding: 20px;
|
|
|
+ color: #6b7280;
|
|
|
+ font-size: 14px;
|
|
|
+ border-top: 1px solid #e5e7eb;
|
|
|
+ margin-top: 10px;
|
|
|
}
|
|
|
|
|
|
/* 滚动条样式 */
|
|
|
.document-list::-webkit-scrollbar {
|
|
|
- width: 6px;
|
|
|
+ width: 6px;
|
|
|
}
|
|
|
|
|
|
.document-list::-webkit-scrollbar-track {
|
|
|
- background: #f1f1f1;
|
|
|
- border-radius: 3px;
|
|
|
+ background: #f1f1f1;
|
|
|
+ border-radius: 3px;
|
|
|
}
|
|
|
|
|
|
.document-list::-webkit-scrollbar-thumb {
|
|
|
- background: #c1c1c1;
|
|
|
- border-radius: 3px;
|
|
|
+ background: #c1c1c1;
|
|
|
+ border-radius: 3px;
|
|
|
}
|
|
|
|
|
|
.document-list::-webkit-scrollbar-thumb:hover {
|
|
|
- background: #a8a8a8;
|
|
|
+ background: #a8a8a8;
|
|
|
}
|
|
|
-
|
|
|
</style>
|