Explorar el Código

-fix:修复了oss解析报错

Diamond_ore hace 1 mes
padre
commit
5868122013
Se han modificado 35 ficheros con 1470 adiciones y 1320 borrados
  1. 2 0
      .gitignore
  2. 1 0
      .vscode/settings.json
  3. 1 1
      README.md
  4. BIN
      dist/assets/17-BJ4I6Ces.png
  5. BIN
      dist/assets/18-CsyhSRVL.png
  6. BIN
      dist/assets/19-LEWFVOdg.png
  7. BIN
      dist/assets/20-pqZy7Dwl.png
  8. 0 0
      dist/assets/FileSaver.min-D3PRR5IN.js
  9. 0 5
      dist/assets/index-CiTXxE2V.js
  10. 0 0
      dist/assets/index-FSswvpXT.css
  11. 0 1
      dist/assets/jszip.min-DXNZmKaK.js
  12. 0 1
      dist/assets/pptxgen.es-C5rj3hyV.js
  13. 0 15
      dist/index.html
  14. BIN
      shudao-chat-go/assets/17-BJ4I6Ces.png
  15. BIN
      shudao-chat-go/assets/18-CsyhSRVL.png
  16. BIN
      shudao-chat-go/assets/19-LEWFVOdg.png
  17. BIN
      shudao-chat-go/assets/20-pqZy7Dwl.png
  18. 0 0
      shudao-chat-go/assets/FileSaver.min-B0XflAa7.js
  19. 0 0
      shudao-chat-go/assets/FileSaver.min-CZqS48m5.js
  20. 0 5
      shudao-chat-go/assets/index-CzKMobZS.js
  21. 0 5
      shudao-chat-go/assets/index-Da_yc_YZ.js
  22. 0 0
      shudao-chat-go/assets/index-do3o3H5j.css
  23. 0 0
      shudao-chat-go/assets/index-zInGiJys.css
  24. 0 1
      shudao-chat-go/assets/jszip.min-D5L-YwUr.js
  25. 0 1
      shudao-chat-go/assets/jszip.min-DFyRfgcg.js
  26. 0 1
      shudao-chat-go/assets/pptxgen.es-B4Lmziee.js
  27. 0 1
      shudao-chat-go/assets/pptxgen.es-D9PcTWAG.js
  28. 16 8
      shudao-chat-go/controllers/hazard.go
  29. BIN
      shudao-chat-go/shudao-chat-go.tar.gz
  30. 1 0
      shudao-chat-go/utils/auth_middleware.go
  31. 1 1
      shudao-chat-go/utils/config.go
  32. 15 15
      shudao-chat-go/views/index.html
  33. 28 6
      src/views/HazardDetection.vue
  34. 734 675
      src/views/PolicyDocument.vue
  35. 671 578
      src/views/mobile/m-PolicyDocument.vue

+ 2 - 0
.gitignore

@@ -1 +1,3 @@
 node_modules
+./dist
+assets

+ 1 - 0
.vscode/settings.json

@@ -0,0 +1 @@
+{}

+ 1 - 1
README.md

@@ -80,7 +80,7 @@ go install github.com/beego/bee/v2@latest
 - 找到进程:ps -ef | grep shudao-chat-go
 - 杀死进程:kill -9 1029395   # 将 12345 替换为你找到的实际PID
 - nohup ./shudao-chat-go &
-- tail -f nohup.out #查看实时状态
+  - tail -f nohup.out #查看实时状态
 
 
 ---

BIN
dist/assets/17-BJ4I6Ces.png


BIN
dist/assets/18-CsyhSRVL.png


BIN
dist/assets/19-LEWFVOdg.png


BIN
dist/assets/20-pqZy7Dwl.png


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/assets/FileSaver.min-D3PRR5IN.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 5
dist/assets/index-CiTXxE2V.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
dist/assets/index-FSswvpXT.css


+ 0 - 1
dist/assets/jszip.min-DXNZmKaK.js

@@ -1 +0,0 @@
-import{r as a,g as p}from"./index-CiTXxE2V.js";function f(t,n){for(var o=0;o<n.length;o++){const e=n[o];if(typeof e!="string"&&!Array.isArray(e)){for(const r in e)if(r!=="default"&&!(r in t)){const i=Object.getOwnPropertyDescriptor(e,r);i&&Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var s=a();const c=p(s),g=f({__proto__:null,default:c},[s]);export{c as J,g as j};

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 1
dist/assets/pptxgen.es-C5rj3hyV.js


+ 0 - 15
dist/index.html

@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<html lang="">
-  <head>
-    <meta charset="UTF-8">
-    <!-- 网站图标 -->
-    <link rel="icon" href="/favicon.ico" sizes="any">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
-    <title>蜀道安全管理AI智能助手</title>
-    <script type="module" crossorigin src="/assets/index-CiTXxE2V.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-FSswvpXT.css">
-  </head>
-  <body>
-    <div id="app"></div>
-  </body>
-</html>

BIN
shudao-chat-go/assets/17-BJ4I6Ces.png


BIN
shudao-chat-go/assets/18-CsyhSRVL.png


BIN
shudao-chat-go/assets/19-LEWFVOdg.png


BIN
shudao-chat-go/assets/20-pqZy7Dwl.png


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
shudao-chat-go/assets/FileSaver.min-B0XflAa7.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
shudao-chat-go/assets/FileSaver.min-CZqS48m5.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 5
shudao-chat-go/assets/index-CzKMobZS.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 5
shudao-chat-go/assets/index-Da_yc_YZ.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
shudao-chat-go/assets/index-do3o3H5j.css


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
shudao-chat-go/assets/index-zInGiJys.css


+ 0 - 1
shudao-chat-go/assets/jszip.min-D5L-YwUr.js

@@ -1 +0,0 @@
-import{r as a,g as p}from"./index-Da_yc_YZ.js";function f(t,n){for(var o=0;o<n.length;o++){const e=n[o];if(typeof e!="string"&&!Array.isArray(e)){for(const r in e)if(r!=="default"&&!(r in t)){const i=Object.getOwnPropertyDescriptor(e,r);i&&Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var s=a();const c=p(s),g=f({__proto__:null,default:c},[s]);export{c as J,g as j};

+ 0 - 1
shudao-chat-go/assets/jszip.min-DFyRfgcg.js

@@ -1 +0,0 @@
-import{r as a,g as p}from"./index-CzKMobZS.js";function f(t,n){for(var o=0;o<n.length;o++){const e=n[o];if(typeof e!="string"&&!Array.isArray(e)){for(const r in e)if(r!=="default"&&!(r in t)){const i=Object.getOwnPropertyDescriptor(e,r);i&&Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}var s=a();const c=p(s),g=f({__proto__:null,default:c},[s]);export{c as J,g as j};

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 1
shudao-chat-go/assets/pptxgen.es-B4Lmziee.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 1
shudao-chat-go/assets/pptxgen.es-D9PcTWAG.js


+ 16 - 8
shudao-chat-go/controllers/hazard.go

@@ -485,22 +485,30 @@ func downloadImageFromOSS(imageURL string) ([]byte, error) {
 func downloadImageFromProxy(proxyURL string) ([]byte, error) {
 	fmt.Printf("通过代理接口下载图片: %s\n", proxyURL)
 
-	// 从代理URL中提取原始OSS URL
-	// 格式: /apiv1/oss/parse/?url=http://172.16.17.52:8060/...
+	// 从代理URL中提取加密的URL参数
+	// 格式: /apiv1/oss/parse/?url=<加密字符串>
 	parsedURL, err := url.Parse(proxyURL)
 	if err != nil {
 		return nil, fmt.Errorf("解析代理URL失败: %v", err)
 	}
 
-	// 获取url参数
-	originalURL := parsedURL.Query().Get("url")
-	if originalURL == "" {
-		return nil, fmt.Errorf("代理URL中缺少原始URL参数")
+	// 获取url参数(加密的)
+	encryptedURL := parsedURL.Query().Get("url")
+	if encryptedURL == "" {
+		return nil, fmt.Errorf("代理URL中缺少URL参数")
 	}
 
-	fmt.Printf("从代理URL提取的原始URL: %s\n", originalURL)
+	fmt.Printf("从代理URL提取的加密URL: %s\n", encryptedURL)
 
-	// 直接使用原始URL下载图片
+	// 解密URL
+	originalURL, err := utils.DecryptURL(encryptedURL)
+	if err != nil {
+		return nil, fmt.Errorf("解密URL失败: %v", err)
+	}
+
+	fmt.Printf("解密后的原始URL: %s\n", originalURL)
+
+	// 使用解密后的原始URL下载图片
 	client := &http.Client{
 		Timeout: 30 * time.Second,
 	}

BIN
shudao-chat-go/shudao-chat-go.tar.gz


+ 1 - 0
shudao-chat-go/utils/auth_middleware.go

@@ -29,6 +29,7 @@ func AuthMiddleware(ctx *context.Context) {
 		"/assets/",
 		"/static/",
 		"/src/",
+		"/apiv1/oss/parse", // OSS代理解析接口,用于图片/文件资源访问,不需要token认证
 	}
 
 	// 特殊处理:精确匹配根路径 "/"

+ 1 - 1
shudao-chat-go/utils/config.go

@@ -6,7 +6,7 @@ import (
 
 // GetBaseURL 获取基础URL
 func GetBaseURL() string {
-	return web.AppConfig.DefaultString("base_url")
+	return web.AppConfig.DefaultString("base_url","https://aqai.shudaodsj.com:22001")
 }
 
 // GetProxyURL 生成OSS代理URL(加密版本)

+ 15 - 15
shudao-chat-go/views/index.html

@@ -1,15 +1,15 @@
-<!DOCTYPE html>
-<html lang="">
-  <head>
-    <meta charset="UTF-8">
-    <!-- 网站图标 -->
-    <link rel="icon" href="/favicon.ico" sizes="any">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
-    <title>蜀道安全管理AI智能助手</title>
-    <script type="module" crossorigin src="/assets/index-Da_yc_YZ.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-do3o3H5j.css">
-  </head>
-  <body>
-    <div id="app"></div>
-  </body>
-</html>
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="UTF-8">
+    <!-- 网站图标 -->
+    <link rel="icon" href="/favicon.ico" sizes="any">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+    <title>蜀道安全管理AI智能助手</title>
+    <script type="module" crossorigin src="/assets/index-Cqc2C3YC.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-S39HVMOn.css">
+  </head>
+  <body>
+    <div id="app"></div>

+  </body>
+</html>

+ 28 - 6
src/views/HazardDetection.vue

@@ -270,7 +270,11 @@
                                     <!-- 流程步骤1 -->
                                     <div class="process-step">
                                         <div class="step-icon-wrapper">
-                                            <el-icon class="step-icon" :size="40" color="#3E7BFA">
+                                            <el-icon
+                                                class="step-icon"
+                                                :size="40"
+                                                color="#3E7BFA"
+                                            >
                                                 <Upload />
                                             </el-icon>
                                             <div class="step-number">1</div>
@@ -291,13 +295,19 @@
                                     <!-- 流程步骤2 -->
                                     <div class="process-step">
                                         <div class="step-icon-wrapper">
-                                            <el-icon class="step-icon" :size="40" color="#3E7BFA">
+                                            <el-icon
+                                                class="step-icon"
+                                                :size="40"
+                                                color="#3E7BFA"
+                                            >
                                                 <View />
                                             </el-icon>
                                             <div class="step-number">2</div>
                                         </div>
                                         <div class="step-content">
-                                            <div class="step-title">场景识别</div>
+                                            <div class="step-title">
+                                                场景识别
+                                            </div>
                                             <div class="step-desc">
                                                 智能识别场景要素
                                             </div>
@@ -310,7 +320,11 @@
                                     <!-- 流程步骤3 -->
                                     <div class="process-step">
                                         <div class="step-icon-wrapper">
-                                            <el-icon class="step-icon" :size="40" color="#3E7BFA">
+                                            <el-icon
+                                                class="step-icon"
+                                                :size="40"
+                                                color="#3E7BFA"
+                                            >
                                                 <DataAnalysis />
                                             </el-icon>
                                             <div class="step-number">3</div>
@@ -331,7 +345,11 @@
                                     <!-- 流程步骤4 -->
                                     <div class="process-step">
                                         <div class="step-icon-wrapper">
-                                            <el-icon class="step-icon" :size="40" color="#3E7BFA">
+                                            <el-icon
+                                                class="step-icon"
+                                                :size="40"
+                                                color="#3E7BFA"
+                                            >
                                                 <Bell />
                                             </el-icon>
                                             <div class="step-number">4</div>
@@ -3085,7 +3103,11 @@ onMounted(() => {
                         display: flex;
                         align-items: center;
                         justify-content: center;
-                        background: linear-gradient(135deg, #EBF3FF 0%, #F5F9FF 100%);
+                        background: linear-gradient(
+                            135deg,
+                            #ebf3ff 0%,
+                            #f5f9ff 100%
+                        );
                         border-radius: 50%;
                         box-shadow: 0 4px 12px rgba(62, 123, 250, 0.15);
 

+ 734 - 675
src/views/PolicyDocument.vue

@@ -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)">查看详情 &gt;</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)"
+                                >
+                                    查看详情 &gt;
+                                </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>

+ 671 - 578
src/views/mobile/m-PolicyDocument.vue

@@ -1,710 +1,803 @@
 <template>
-  <div class="mobile-policy-document">
-    <MobileHeader title="政策文件" :showMenu="false" @back="goBack" />
+    <div class="mobile-policy-document">
+        <MobileHeader title="政策文件" :showMenu="false" @back="goBack" />
 
-    <div class="main-content">
-      <!-- 页面标题与返回首页(移动端仅展示标题) -->
-      <!-- <div class="page-header">
+        <div class="main-content">
+            <!-- 页面标题与返回首页(移动端仅展示标题) -->
+            <!-- <div class="page-header">
         <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>
-            <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)">查看详情 &gt;</button>
-              </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>
-        </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)"
+                                >
+                                    查看详情 &gt;
+                                </button>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <div v-if="hasMore && !loading" class="load-more">
+                    <span>上拉加载更多</span>
+                </div>
+            </div>
         </div>
-      </div>
-    </div>
 
-    <div v-if="previewVisible" class="preview-modal" @click.self="closePreview">
-      <div class="preview-content">
-        <div class="preview-header">
-          <h3 class="preview-title">{{ previewTitle }}</h3>
-          <button class="close-btn" @click="closePreview">×</button>
-        </div>
-        <div class="preview-body">
-          <iframe
-            v-if="previewUrl"
-            :src="previewUrl"
-            class="preview-frame"
-            frameborder="0"
-            allowfullscreen
-          ></iframe>
-          <div v-else class="preview-placeholder">
-            暂无可预览内容
-          </div>
+        <div
+            v-if="previewVisible"
+            class="preview-modal"
+            @click.self="closePreview"
+        >
+            <div class="preview-content">
+                <div class="preview-header">
+                    <h3 class="preview-title">{{ previewTitle }}</h3>
+                    <button class="close-btn" @click="closePreview">×</button>
+                </div>
+                <div class="preview-body">
+                    <iframe
+                        v-if="previewUrl"
+                        :src="previewUrl"
+                        class="preview-frame"
+                        frameborder="0"
+                        allowfullscreen
+                    ></iframe>
+                    <div v-else class="preview-placeholder">暂无可预览内容</div>
+                </div>
+            </div>
         </div>
-      </div>
     </div>
-  </div>
-
 </template>
 
 <script setup>
-import { ref, computed, onMounted, onUnmounted } from 'vue'
-import { useRouter } from 'vue-router'
-import MobileHeader from '@/components/MobileHeader.vue'
-import { apis } from '@/request/apis.js'
+import { ref, computed, onMounted, onUnmounted } from "vue";
+import { useRouter } from "vue-router";
+import MobileHeader from "@/components/MobileHeader.vue";
+import { apis } from "@/request/apis.js";
 
-const router = useRouter()
+const router = useRouter();
 
 // 响应式数据(与PC端保持一致)
-const searchText = ref('')
-const activeTab = ref(0)
-const policyFiles = ref([])
-const loading = ref(false)
-const page = ref(1)
-const pageSize = ref(10)
-const hasMore = ref(true)
-const documentList = ref(null)
-const previewVisible = ref(false)
-const previewFile = ref(null)
-
-let searchTimer = null
-let scrollTimer = null
+const searchText = ref("");
+const activeTab = ref(0);
+const policyFiles = ref([]);
+const loading = ref(false);
+const page = ref(1);
+const pageSize = ref(10);
+const hasMore = ref(true);
+const documentList = ref(null);
+const previewVisible = ref(false);
+const previewFile = ref(null);
+
+let searchTimer = null;
+let scrollTimer = null;
 
 const goBack = () => {
-  router.go(-1)
-}
+    router.go(-1);
+};
 
 const setActiveTab = (tabIndex) => {
-  activeTab.value = tabIndex
-  page.value = 1
-  policyFiles.value = []
-  hasMore.value = true
-  fetchPolicyFiles()
-}
+    activeTab.value = tabIndex;
+    page.value = 1;
+    policyFiles.value = [];
+    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,
-    }
-    const response = await apis.getPolicyFile(params)
-    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,
+        };
+        const response = await apis.getPolicyFile(params);
+        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)
-  searchTimer = setTimeout(() => {
-    page.value = 1
-    policyFiles.value = []
-    hasMore.value = true
-    fetchPolicyFiles()
-  }, 300)
-}
+    if (searchTimer) clearTimeout(searchTimer);
+    searchTimer = setTimeout(() => {
+        page.value = 1;
+        policyFiles.value = [];
+        hasMore.value = true;
+        fetchPolicyFiles();
+    }, 300);
+};
 
 const handleSearch = () => {
-  if (searchText.value.trim()) {
-    page.value = 1
-    policyFiles.value = []
-    hasMore.value = true
-    fetchPolicyFiles()
-  }
-}
+    if (searchText.value.trim()) {
+        page.value = 1;
+        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;
     }
-  }
-  
-  previewFile.value = file
-  previewVisible.value = true
-}
+
+    // 检查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;
+        }
+    }
+
+    previewFile.value = file;
+    previewVisible.value = true;
+};
 
 // 图标
-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,
-    1: wordIcon,
-    2: excelIcon,
-    3: pdfIcon,
-    4: pdfIcon,
-    5: pdfIcon,
-  }
-  return iconMap[fileType] || pdfIcon
-}
+    const iconMap = {
+        0: pdfIcon,
+        1: wordIcon,
+        2: excelIcon,
+        3: pdfIcon,
+        4: pdfIcon,
+        5: pdfIcon,
+    };
+    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 previewUrl = computed(() => {
-  if (!previewFile.value || !previewFile.value.policy_file_url) return ''
-  const fileType = previewFile.value.file_type
-  const url = previewFile.value.policy_file_url
-  if (fileType === 0 || fileType === 4 || fileType === 5) {
-    return url
-  }
-  if (fileType === 1 || fileType === 2 || fileType === 3) {
-    const encodedUrl = encodeURIComponent(url)
-    return `https://view.officeapps.live.com/op/embed.aspx?src=${encodedUrl}`
-  }
-  return url
-})
-
-const previewTitle = computed(() => previewFile.value?.policy_name || '政策文件预览')
+    if (!previewFile.value || !previewFile.value.policy_file_url) return "";
+    const fileType = previewFile.value.file_type;
+    const url = previewFile.value.policy_file_url;
+    if (fileType === 0 || fileType === 4 || fileType === 5) {
+        return url;
+    }
+    if (fileType === 1 || fileType === 2 || fileType === 3) {
+        const encodedUrl = encodeURIComponent(url);
+        return `https://view.officeapps.live.com/op/embed.aspx?src=${encodedUrl}`;
+    }
+    return url;
+});
+
+const previewTitle = computed(
+    () => previewFile.value?.policy_name || "政策文件预览"
+);
 
 const closePreview = () => {
-  previewVisible.value = false
-  previewFile.value = null
-}
+    previewVisible.value = false;
+    previewFile.value = null;
+};
 
 const getTags = (tagString) => {
-  if (!tagString) return ['政策文件']
-  return tagString
-    .split(',')
-    .map(tag => tag.trim())
-    .filter(tag => tag.length > 0)
-}
+    if (!tagString) return ["政策文件"];
+    return tagString
+        .split(",")
+        .map((tag) => tag.trim())
+        .filter((tag) => tag.length > 0);
+};
 
 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}`;
+};
 
 const handleScroll = (event) => {
-  if (scrollTimer) clearTimeout(scrollTimer)
-  scrollTimer = setTimeout(() => {
-    const target = event.target
-    const scrollTop = target.scrollTop
-    const scrollHeight = target.scrollHeight
-    const clientHeight = target.clientHeight
-    if (scrollTop + clientHeight >= scrollHeight - 50 && hasMore.value && !loading.value) {
-      page.value++
-      fetchPolicyFiles(true)
-    }
-  }, 100)
-}
+    if (scrollTimer) clearTimeout(scrollTimer);
+    scrollTimer = setTimeout(() => {
+        const target = event.target;
+        const scrollTop = target.scrollTop;
+        const scrollHeight = target.scrollHeight;
+        const clientHeight = target.clientHeight;
+        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>
 .mobile-policy-document {
-  min-height: 100vh;
-  background: #EBF3FF;
-  font-family: "Alibaba PuHuiTi 3.0", sans-serif;
-  display: flex;
-  flex-direction: column;
+    min-height: 100vh;
+    background: #ebf3ff;
+    font-family: "Alibaba PuHuiTi 3.0", sans-serif;
+    display: flex;
+    flex-direction: column;
 }
 
 .main-content {
-  padding: 12px 0 0 0;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
+    padding: 12px 0 0 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
 }
 
 .page-header {
-  display: flex;
-  align-items: center;
-  justify-content: flex-start;
-  margin-bottom: 10px;
-
-  .page-title {
-    font-size: 18px;
-    font-weight: 900;
-    color: #111827;
-    margin: 0;
-  }
+    display: flex;
+    align-items: center;
+    justify-content: flex-start;
+    margin-bottom: 10px;
+
+    .page-title {
+        font-size: 18px;
+        font-weight: 900;
+        color: #111827;
+        margin: 0;
+    }
 }
 
 .search-section {
-  margin-bottom: 10px;
-  // padding: 0 14px;
-  width: 100%;
-  max-width: 450px;
-
-  .search-box {
-    position: relative;
+    margin-bottom: 10px;
+    // padding: 0 14px;
     width: 100%;
+    max-width: 450px;
+
+    .search-box {
+        position: relative;
+        width: 100%;
+
+        .search-icon-left {
+            position: absolute;
+            left: 12px;
+            z-index: 10;
+            top: 50%;
+            transform: translateY(-50%);
+
+            .search-icon {
+                width: 28px;
+                height: 28px;
+                opacity: 0.6;
+            }
+        }
 
-    .search-icon-left {
-      position: absolute;
-      left: 12px;
-      z-index: 10;
-      top: 50%;
-      transform: translateY(-50%);
-
-      .search-icon {
-        width: 28px;
-        height: 28px;
-        opacity: 0.6;
-      }
-    }
-
-    .search-input {
-      width: 100%;
-      // margin: 0 auto;
-      height: 62px;
-      padding: 0 14px 0 42px;
-      border: 1px solid #e5e7eb;
-      border-radius: 8px;
-      font-size: 20px !important;
-      background: #fff;
-      outline: none;
-      transition: all 0.3s ease;
-      /* 光标优化 */
-      caret-color: #000;
-      /* 强制渲染 */
-      -webkit-appearance: none;
-      appearance: none;
-      color: #000 !important;
-
-      &:focus {
-        border-color: #3b82f6;
-        box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-      }
-
-      &::placeholder {
-        color: #9ca3af;
-      }
+        .search-input {
+            width: 100%;
+            // margin: 0 auto;
+            height: 62px;
+            padding: 0 14px 0 42px;
+            border: 1px solid #e5e7eb;
+            border-radius: 8px;
+            font-size: 20px !important;
+            background: #fff;
+            outline: none;
+            transition: all 0.3s ease;
+            /* 光标优化 */
+            caret-color: #000;
+            /* 强制渲染 */
+            -webkit-appearance: none;
+            appearance: none;
+            color: #000 !important;
+
+            &:focus {
+                border-color: #3b82f6;
+                box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
+            }
+
+            &::placeholder {
+                color: #9ca3af;
+            }
+        }
     }
-  }
 }
 
 .category-tabs {
-  display: flex;
-  overflow-x: auto;
-  -webkit-overflow-scrolling: touch;
-  gap: 0;
-  margin-bottom: 10px;
-  border-bottom: 1px solid #E5E7EB;
-  width: 100%;
-  justify-content: center;
-
-
-  .tab-btn {
-    padding: 10px 12px;
-    border: none;
-    background: transparent;
-    font-size: 18px;
-    color: #6b7280;
-    cursor: pointer;
-    transition: all 0.3s ease;
-    position: relative;
-    border-bottom: 2px solid transparent;
-    white-space: nowrap;
+    display: flex;
+    overflow-x: auto;
+    -webkit-overflow-scrolling: touch;
+    gap: 0;
+    margin-bottom: 10px;
+    border-bottom: 1px solid #e5e7eb;
+    width: 100%;
+    justify-content: center;
 
-    &:hover {
-      color: #2563EB;
-    }
+    .tab-btn {
+        padding: 10px 12px;
+        border: none;
+        background: transparent;
+        font-size: 18px;
+        color: #6b7280;
+        cursor: pointer;
+        transition: all 0.3s ease;
+        position: relative;
+        border-bottom: 2px solid transparent;
+        white-space: nowrap;
+
+        &:hover {
+            color: #2563eb;
+        }
 
-    &.active {
-      color: #2563EB;
-      border-bottom-color: #2563EB;
+        &.active {
+            color: #2563eb;
+            border-bottom-color: #2563eb;
+        }
     }
-  }
 }
 
 .document-list {
-  width: 100%;
-  max-width: 450px;
-  display: flex;
-  flex-direction: column;
-  gap: 10px;
-  min-height: 300px;
-  max-height: calc(100vh - 180px);
-  overflow-y: auto;
-  // padding: 0 14px;
+    width: 100%;
+    max-width: 450px;
+    display: flex;
+    flex-direction: column;
+    gap: 10px;
+    min-height: 300px;
+    max-height: calc(100vh - 180px);
+    overflow-y: auto;
+    // padding: 0 14px;
 }
 
 .document-item {
-  background: #fff;
-  width: 100%;
-  border-radius: 12px;
-  padding: 14px;
-  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
-  transition: all 0.3s ease;
-  display: flex;
-  gap: 12px;
-  border: 1px solid #f1f5f9;
-
-  .doc-icon {
-    flex-shrink: 0;
-
-    .file-icon {
-      width: 22px;
-      height: 22px;
-      object-fit: contain;
-    }
-  }
-
-  .doc-content {
-    flex: 1;
-
-    .doc-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: flex-start;
-      margin-bottom: 6px;
-
-      .doc-title {
-        font-size: 16px;
-        font-weight: 600;
-        color: #1f2937;
-        margin: 0;
-        line-height: 1.4;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        display: -webkit-box;
-        line-clamp: 1;
-        -webkit-line-clamp: 1;
-        -webkit-box-orient: vertical;
-        flex: 1;
-        margin-right: 10px;
-      }
-
-      .doc-date {
-        font-size: 12px;
-        color: #6b7280;
-        white-space: nowrap;
-      }
-    }
+    background: #fff;
+    width: 100%;
+    border-radius: 12px;
+    padding: 14px;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
+    transition: all 0.3s ease;
+    display: flex;
+    gap: 12px;
+    border: 1px solid #f1f5f9;
 
-    .doc-tags {
-      display: flex;
-      gap: 8px;
-      margin-bottom: 6px;
-      flex-wrap: wrap;
-
-      .tag {
-        padding: 3px 10px;
-        font-size: 12px;
-        border-radius: 12px;
-        font-weight: 500;
-        display: flex;
-        align-items: center;
-        gap: 4px;
-        background: #EFF6FF;
-        color: #2563EB;
-        white-space: nowrap;
+    .doc-icon {
+        flex-shrink: 0;
 
-        .tag-icon {
-          width: 12px;
-          height: 12px;
-          flex-shrink: 0;
+        .file-icon {
+            width: 22px;
+            height: 22px;
+            object-fit: contain;
         }
-      }
     }
 
-    .doc-description {
-      font-size: 13px;
-      color: #6b7280;
-      line-height: 1.5;
-      margin: 0 0 6px 0;
-      display: -webkit-box;
-      line-clamp: 2;
-      -webkit-line-clamp: 2;
-      -webkit-box-orient: vertical;
-      overflow: hidden;
-    }
+    .doc-content {
+        flex: 1;
 
-    .doc-footer {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-
-      .doc-info {
-        display: flex;
-        gap: 16px;
-
-        .info-item {
-          display: flex;
-          align-items: center;
-          gap: 6px;
-          font-size: 12px;
-          color: #6b7280;
-
-          .info-icon {
-            width: 14px;
-            height: 14px;
-            opacity: 0.6;
-          }
+        .doc-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: flex-start;
+            margin-bottom: 6px;
+
+            .doc-title {
+                font-size: 16px;
+                font-weight: 600;
+                color: #1f2937;
+                margin: 0;
+                line-height: 1.4;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                display: -webkit-box;
+                line-clamp: 1;
+                -webkit-line-clamp: 1;
+                -webkit-box-orient: vertical;
+                flex: 1;
+                margin-right: 10px;
+            }
+
+            .doc-date {
+                font-size: 12px;
+                color: #6b7280;
+                white-space: nowrap;
+            }
         }
-      }
 
-      .doc-actions {
-        display: flex;
+        .doc-tags {
+            display: flex;
+            gap: 8px;
+            margin-bottom: 6px;
+            flex-wrap: wrap;
+
+            .tag {
+                padding: 3px 10px;
+                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:first-child {
-          margin-right: 6px;
+        .doc-description {
+            font-size: 13px;
+            color: #6b7280;
+            line-height: 1.5;
+            margin: 0 0 6px 0;
+            display: -webkit-box;
+            line-clamp: 2;
+            -webkit-line-clamp: 2;
+            -webkit-box-orient: vertical;
+            overflow: hidden;
         }
 
-        .action-btn {
-          padding: 4px 0;
-          border: none;
-          border-radius: 6px;
-          font-size: 13px;
-          cursor: pointer;
-          transition: all 0.3s ease;
-          display: flex;
-          align-items: center;
-          gap: 6px;
-
-          &.view-btn {
-            color: #3b82f6;
-            background: transparent;
-          }
+        .doc-footer {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+
+            .doc-info {
+                display: flex;
+                gap: 16px;
+
+                .info-item {
+                    display: flex;
+                    align-items: center;
+                    gap: 6px;
+                    font-size: 12px;
+                    color: #6b7280;
+
+                    .info-icon {
+                        width: 14px;
+                        height: 14px;
+                        opacity: 0.6;
+                    }
+                }
+            }
+
+            .doc-actions {
+                display: flex;
+
+                .action-btn:first-child {
+                    margin-right: 6px;
+                }
+
+                .action-btn {
+                    padding: 4px 0;
+                    border: none;
+                    border-radius: 6px;
+                    font-size: 13px;
+                    cursor: pointer;
+                    transition: all 0.3s ease;
+                    display: flex;
+                    align-items: center;
+                    gap: 6px;
+
+                    &.view-btn {
+                        color: #3b82f6;
+                        background: transparent;
+                    }
+                }
+            }
         }
-      }
     }
-  }
 }
 
 .loading {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  padding: 30px 16px;
-  color: #6b7280;
-  font-size: 14px;
-
-  .loading-spinner {
-    border: 4px solid #f3f3f3;
-    border-top: 4px solid #3b82f6;
-    border-radius: 50%;
-    width: 36px;
-    height: 36px;
-    animation: spin 1s linear infinite;
-    margin-bottom: 12px;
-  }
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 30px 16px;
+    color: #6b7280;
+    font-size: 14px;
+
+    .loading-spinner {
+        border: 4px solid #f3f3f3;
+        border-top: 4px solid #3b82f6;
+        border-radius: 50%;
+        width: 36px;
+        height: 36px;
+        animation: spin 1s linear infinite;
+        margin-bottom: 12px;
+    }
 }
 
 @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: 40px 16px;
-  color: #9ca3af;
-  font-size: 18px;
-  text-align: center;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 40px 16px;
+    color: #9ca3af;
+    font-size: 18px;
+    text-align: center;
 }
 
 .load-more {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  padding: 16px;
-  color: #6b7280;
-  font-size: 13px;
-  border-top: 1px solid #e5e7eb;
-  margin-top: 6px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 16px;
+    color: #6b7280;
+    font-size: 13px;
+    border-top: 1px solid #e5e7eb;
+    margin-top: 6px;
 }
 
-.document-list::-webkit-scrollbar { width: 4px; }
-.document-list::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 3px; }
-.document-list::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 3px; }
-.document-list::-webkit-scrollbar-thumb:hover { background: #a8a8a8; }
+.document-list::-webkit-scrollbar {
+    width: 4px;
+}
+.document-list::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 3px;
+}
+.document-list::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 3px;
+}
+.document-list::-webkit-scrollbar-thumb:hover {
+    background: #a8a8a8;
+}
 
 .preview-modal {
-  position: fixed;
-  inset: 0;
-  background: rgba(0, 0, 0, 0.65);
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  padding: 20px;
-  z-index: 999;
+    position: fixed;
+    inset: 0;
+    background: rgba(0, 0, 0, 0.65);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 20px;
+    z-index: 999;
 }
 
 .preview-content {
-  width: 100%;
-  max-width: 640px;
-  height: 90vh;
-  background: #fff;
-  border-radius: 12px;
-  display: flex;
-  flex-direction: column;
-  overflow: hidden;
+    width: 100%;
+    max-width: 640px;
+    height: 90vh;
+    background: #fff;
+    border-radius: 12px;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
 }
 
 .preview-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 14px 16px;
-  background: #f8fafc;
-  border-bottom: 1px solid #e5e7eb;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 14px 16px;
+    background: #f8fafc;
+    border-bottom: 1px solid #e5e7eb;
 }
 
 .preview-title {
-  margin: 0;
-  font-size: 16px;
-  color: #111827;
-  font-weight: 600;
+    margin: 0;
+    font-size: 16px;
+    color: #111827;
+    font-weight: 600;
 }
 
 .close-btn {
-  border: none;
-  background: transparent;
-  font-size: 24px;
-  cursor: pointer;
-  color: #6b7280;
-  line-height: 1;
-  padding: 4px 8px;
+    border: none;
+    background: transparent;
+    font-size: 24px;
+    cursor: pointer;
+    color: #6b7280;
+    line-height: 1;
+    padding: 4px 8px;
 }
 
 .preview-body {
-  flex: 1;
-  background: #111827;
-  display: flex;
-  align-items: center;
-  justify-content: center;
+    flex: 1;
+    background: #111827;
+    display: flex;
+    align-items: center;
+    justify-content: center;
 }
 
 .preview-frame {
-  width: 100%;
-  height: 100%;
-  border: none;
+    width: 100%;
+    height: 100%;
+    border: none;
 }
 
 .preview-placeholder {
-  color: #fff;
-  font-size: 16px;
+    color: #fff;
+    font-size: 16px;
 }
 </style>

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio