fzzj vor 8 Monaten
Ursprung
Commit
07a2d07fe7

+ 20
- 4
RuoYi-App/App.vue Datei anzeigen

@@ -54,6 +54,7 @@ export default {
54 54
     this.initTheme(); // 确保正确调用
55 55
     this.initStoreState();
56 56
     this.safeUpdateMenuVisibility();
57
+	
57 58
   },
58 59
   beforeDestroy() {
59 60
     this.isMounted = false;
@@ -67,7 +68,16 @@ export default {
67 68
           this.safeUpdateMenuVisibility();
68 69
         }
69 70
       }
70
-    }
71
+    },
72
+	  '$store.state.token': {
73
+	    handler(newToken) {
74
+	      if (newToken) {
75
+	        console.log('检测到新token,重新加载数据');
76
+	        this.reloadData();
77
+	      }
78
+	    },
79
+	    immediate: true
80
+	  }
71 81
   },
72 82
   methods: {
73 83
     // 确保 initTheme 方法正确定义
@@ -75,8 +85,8 @@ export default {
75 85
       console.log('主题初始化开始');
76 86
       
77 87
       // 设置默认主题
78
-      const themeName = uni.getStorageSync('selectedTheme') || 'aydzBlue';
79
-      
88
+      //const themeName = uni.getStorageSync('selectedTheme') || 'aydzBlue';
89
+        const themeName = localStorage.getItem('selectedTheme') || 'aydzBlue';
80 90
       // 应用主题变量
81 91
       const themes = {
82 92
         aydzBlue: {
@@ -157,7 +167,13 @@ export default {
157 167
           this.$router.push('/pages/login');
158 168
         }
159 169
       }
160
-    }
170
+    },
171
+	  reloadData() {
172
+	    // 在需要的地方调用此方法重新加载数据
173
+	    if (this.$route.path === '/pages/novel/list') {
174
+	      this.$refs.novelList?.initData?.();
175
+	    }
176
+	  }
161 177
   }
162 178
 }
163 179
 </script>

+ 7
- 0
RuoYi-App/api/urls.js Datei anzeigen

@@ -0,0 +1,7 @@
1
+// 修正重复的/api路径
2
+export default {
3
+  NOVEL_LIST: '/novel/list', // 从 /api/novel/list 改为 /novel/list
4
+  CATEGORY_TREE: '/category/tree',
5
+  HOT_NOVELS: '/novel/hot',
6
+  ADS: '/ad/position'
7
+}

+ 1
- 1
RuoYi-App/components/AdBanner.vue Datei anzeigen

@@ -22,7 +22,7 @@ export default {
22 22
   methods: {
23 23
     handleAdClick(ad) {
24 24
       // 广告点击统计
25
-      this.$http.post('/java-api/ad/click', { adId: ad.id });
25
+      this.$http.post('/ad/click', { adId: ad.id });
26 26
       
27 27
       // 处理跳转
28 28
       if (ad.linkType === 'NOVEL') {

+ 1
- 1
RuoYi-App/config.js Datei anzeigen

@@ -2,7 +2,7 @@
2 2
 module.exports = {
3 3
   //baseUrl: 'https://vue.ruoyi.vip/prod-api',
4 4
    //baseUrl: 'http://localhost:8080',
5
-   baseUrl: process.env.VUE_APP_BASE_API || '/',
5
+   baseUrl: process.env.VUE_APP_BASE_API || 'http://localhost:8080',
6 6
   // 应用信息
7 7
   appInfo: {
8 8
     // 应用名称

+ 2
- 2
RuoYi-App/pages/login.vue Datei anzeigen

@@ -45,8 +45,8 @@
45 45
 </template>
46 46
 
47 47
 <script>
48
-  import { getCodeImg } from '@/api/login'
49
-  import { getToken } from '@/utils/auth'
48
+  //import { getCodeImg } from '@/api/login'
49
+  //import { getToken } from '@/utils/auth'
50 50
 
51 51
   export default {
52 52
     data() {

+ 2
- 2
RuoYi-App/pages/novel/detail.vue Datei anzeigen

@@ -64,7 +64,7 @@ export default {
64 64
       }
65 65
       
66 66
       // 加载章节广告
67
-      const adRes = await this.$http.get('/java-api/ad/position?code=CHAPTER_FOOTER');
67
+      const adRes = await this.$http.get('/ad/position?code=CHAPTER_FOOTER');
68 68
       this.chapterAds = adRes.data;
69 69
     },
70 70
     
@@ -87,7 +87,7 @@ export default {
87 87
     // 定时显示中间广告
88 88
     scheduleMidAd() {
89 89
       setTimeout(async () => {
90
-        const res = await this.$http.get('/java-api/ad/position?code=MID_CHAPTER');
90
+        const res = await this.$http.get('/ad/position?code=MID_CHAPTER');
91 91
         this.midAds = res.data;
92 92
         this.showMidAd = true;
93 93
         

+ 22
- 12
RuoYi-App/pages/novel/list.vue Datei anzeigen

@@ -28,7 +28,7 @@
28 28
       <view v-if="novels.length === 0 && !error" class="empty-container">
29 29
         <image src="/static/empty-book.png" class="empty-img" />
30 30
         <text class="empty-text">暂无小说数据</text>
31
-        <button class="btn-refresh" @click="loadNovels">重新加载</button>
31
+		<button class="btn-refresh" @click="reloadData">重新加载</button>
32 32
       </view>
33 33
       
34 34
       <!-- 错误状态 -->
@@ -96,6 +96,7 @@
96 96
 <script>
97 97
 // 确保路径正确
98 98
 import AdBanner from '@/components/AdBanner';
99
+import urls from '@/api/urls';
99 100
 
100 101
 export default {
101 102
   components: { AdBanner },
@@ -166,7 +167,10 @@ export default {
166 167
         // 加载分类
167 168
     async loadCategories() {
168 169
       try {
169
-        const res = await this.$http.get('/java-api/category/tree');
170
+        // 公开API,不需要认证
171
+              const res = await this.$http.get('/category/tree', {}, {
172
+                header: { isToken: false } // 明确不携带token
173
+              });
170 174
         this.categories = res?.data ? [{ id: 0, name: '全部' }, ...res.data] : [];
171 175
       } catch (e) {
172 176
         console.error('加载分类失败', e);
@@ -176,8 +180,10 @@ export default {
176 180
     // 加载热门小说
177 181
     async loadHotNovels() {
178 182
       try {
179
-        const res = await this.$http.get('/novel/hot');
180
-        
183
+      // 公开API,不需要认证
184
+      const res = await this.$http.get('/novel/hot', {}, {
185
+        header: { isToken: false } // 明确不携带token
186
+      });
181 187
         // 处理响应
182 188
         if (res?.data?.rows) {
183 189
           this.hotNovels = res.data.rows;
@@ -197,8 +203,9 @@ export default {
197 203
       this.loading = true;
198 204
       this.error = null;
199 205
       try {
200
-        const res = await this.$http.get('/novel/list');
201
-        
206
+        // 使用正确的请求方式
207
+        //const res = await this.$http.get('/novel/list');
208
+         const res = await this.$http.get('/novel/list', {}, { header: { isToken: false } });
202 209
         // 处理响应
203 210
         if (res?.data?.rows) {
204 211
           this.novels = res.data.rows;
@@ -206,12 +213,12 @@ export default {
206 213
           this.novels = res.data;
207 214
         } else {
208 215
           console.warn('小说列表API返回格式未知', res);
209
-          this.novels = this.mockNovels; // 使用模拟数据
216
+          this.novels = this.mockNovels;
210 217
         }
211 218
       } catch (e) {
212 219
         console.error('加载小说失败', e);
213 220
         this.error = '加载失败,请重试';
214
-        this.novels = this.mockNovels; // 使用模拟数据
221
+        this.novels = this.mockNovels;
215 222
       } finally {
216 223
         this.loading = false;
217 224
       }
@@ -221,10 +228,9 @@ export default {
221 228
     async loadAds() {
222 229
       try {
223 230
         const [topRes, bottomRes] = await Promise.all([
224
-          this.$http.get('/java-api/ad/position?code=TOP_BANNER'),
225
-          this.$http.get('/java-api/ad/position?code=BOTTOM_BANNER')
231
+          this.$http.get('/ad/position?code=TOP_BANNER', {}, { header: { isToken: false } }),
232
+          this.$http.get('/ad/position?code=BOTTOM_BANNER', {}, { header: { isToken: false } })
226 233
         ]);
227
-        
228 234
         this.topAds = topRes?.data || topRes || [];
229 235
         this.bottomAds = bottomRes?.data || bottomRes || [];
230 236
       } catch (e) {
@@ -267,11 +273,15 @@ export default {
267 273
       }
268 274
       uni.navigateTo({ url: '/pages/author/apply' });
269 275
     },
270
-    
276
+
271 277
     goMore() {
272 278
       uni.navigateTo({
273 279
         url: '/pages/novel/more'
274 280
       });
281
+    },
282
+        // 确保重新加载按钮绑定到正确的方法
283
+    reloadData() {
284
+      this.initData();
275 285
     }
276 286
   }
277 287
 }

+ 2
- 2
RuoYi-App/router/index.js Datei anzeigen

@@ -7,7 +7,7 @@ Vue.use(Router)
7 7
 const routes = [
8 8
   {
9 9
     path: '/',
10
-    redirect: '/pages/novel/list'
10
+    redirect: '/pages/index/index'
11 11
   },
12 12
   {
13 13
     path: '/pages/novel/list',
@@ -74,4 +74,4 @@ router.onReady(() => {
74 74
   console.log('Router is ready');
75 75
 })
76 76
 
77
-export default router
77
+export default router

+ 5
- 5
RuoYi-App/services/api.js Datei anzeigen

@@ -2,11 +2,11 @@ import request from '@/utils/request'
2 2
 // Java 后台接口
3 3
 const javaApi = {
4 4
   // 小说相关接口
5
-  getNovelList: (params) => request({ url: '/java-api/novel/list', params }),
6
-  getChapterContent: (chapterId) => request({ url: `/java-api/novel/chapter/${chapterId}` }),
5
+  getNovelList: (params) => request({ url: '/novel/list', params }),
6
+  getChapterContent: (chapterId) => request({ url: `/novel/chapter/${chapterId}` }),
7 7
   
8 8
   // 作家申请
9
-  applyAuthor: (data) => request({ url: '/java-api/author/apply', method: 'post', data })
9
+  applyAuthor: (data) => request({ url: '/author/apply', method: 'post', data })
10 10
 }
11 11
 
12 12
 // PHP 后台接口 (预留)
@@ -84,7 +84,7 @@ export default {
84 84
   // 保存阅读进度
85 85
   saveReadingProgress(chapter) {
86 86
     return request({
87
-      url: '/java-api/reading/progress',
87
+      url: '/reading/progress',
88 88
       method: 'post',
89 89
       data: { chapter }
90 90
     })
@@ -93,7 +93,7 @@ export default {
93 93
   // 获取阅读进度
94 94
   getReadingProgress() {
95 95
     return request({
96
-      url: '/java-api/reading/progress',
96
+      url: '/reading/progress',
97 97
       method: 'get'
98 98
     })
99 99
   }

+ 7
- 2
RuoYi-App/utils/auth.js Datei anzeigen

@@ -1,11 +1,16 @@
1 1
 const TokenKey = 'App-Token'
2 2
 
3 3
 export function getToken() {
4
-  return uni.getStorageSync(TokenKey)
4
+  //return uni.getStorageSync(TokenKey)
5
+    // 确保使用正确的存储方式
6
+    return uni.getStorageSync('token') || localStorage.getItem('token') || '';
5 7
 }
6 8
 
7 9
 export function setToken(token) {
8
-  return uni.setStorageSync(TokenKey, token)
10
+	  // 同时设置到uni和localStorage确保兼容性
11
+	  uni.setStorageSync('token', token);
12
+	  localStorage.setItem('token', token);
13
+  return uni.setStorageSync('token', token)
9 14
 }
10 15
 
11 16
 export function removeToken() {

+ 74
- 72
RuoYi-App/utils/request.js Datei anzeigen

@@ -1,91 +1,93 @@
1 1
 // src/utils/request.js
2 2
 import config from '@/config'
3
+import { getToken } from '@/utils/auth'
4
+import { toast, showConfirm, tansParams } from '@/utils/common'
5
+
3 6
 const baseUrl = config.baseUrl
4
-// 使用直接导出的函数,避免 this 上下文问题
5
-export function get(url, params = {}, options = {}) {
6
-  return request('GET', url, params, options)
7
-}
7
+let timeout = 10000
8 8
 
9
-export function post(url, data = {}, options = {}) {
10
-  return request('POST', url, data, options)
11
-}
9
+const request = (configObj) => {  // 重命名参数为 configObj
10
+  // 确保传入的配置对象有效
11
+  configObj = configObj || {}
12
+  configObj.header = configObj.header || {}
13
+  
14
+  // 处理 token
15
+  const token = getToken()
16
+  // 只有存在token且未明确禁止携带token时才添加
17
+  if (token && configObj.header.isToken !== false) {
18
+    configObj.header['Authorization'] = 'Bearer ' + token
19
+  } else if (!token) {
20
+    console.warn('请求未携带Token:', configObj.url)
21
+  }
12 22
 
13
-function request(method, url, data = {}, options = {}) {
23
+  
24
+  // GET 请求参数处理
25
+  if (configObj.params) {
26
+    let url = configObj.url + '?' + tansParams(configObj.params)
27
+    url = url.slice(0, -1)
28
+    configObj.url = url
29
+  }
30
+  
14 31
   return new Promise((resolve, reject) => {
15
-    // 处理路径
16
-    let finalUrl = url;
17
-    
18
-    // 特殊处理 Java API
19
-    if (url.startsWith('/java-api')) {
20
-        finalUrl = url
21
-      }
22
-    // 普通 API 处理
23
-    else if (!url.startsWith('http')) {
24
-      // 确保只有一个 /api 前缀
25
-      if (!url.startsWith('/api')) {
26
-        finalUrl = '/api' + (url.startsWith('/') ? url : `/${url}`);
27
-      }
28
-    }
29
-    
30
-    const baseUrl = process.env.VUE_APP_BASE_API || '/';
31
-    const fullUrl = baseUrl + finalUrl;
32
-    
33
-    console.log('请求URL:', fullUrl, '方法:', method);
34
-    
35 32
     uni.request({
36
-      url: fullUrl,
37
-      method,
38
-      data,
39
-      header: {
40
-        'Content-Type': 'application/json',
41
-        ...(options.headers || {})
42
-      },
33
+      method: configObj.method || 'get',
34
+      timeout: configObj.timeout || timeout,
35
+      url: (configObj.baseUrl || baseUrl) + configObj.url,
36
+      data: configObj.data,
37
+      header: configObj.header,
38
+      dataType: 'json',
43 39
       success: (res) => {
44
-        console.log('API响应:', res);
45
-        
46
-        // 处理未授权情况
40
+        // 处理401认证失败
47 41
         if (res.statusCode === 401) {
48
-          uni.showToast({
49
-            title: '请先登录',
50
-            icon: 'none'
51
-          });
52
-          uni.navigateTo({
53
-            url: '/pages/login'
54
-          });
55
-          reject(new Error('未授权访问'));
56
-          return;
57
-        }
58
-        
59
-        // 统一处理成功响应
60
-        if (res.statusCode >= 200 && res.statusCode < 300) {
61
-          resolve(res.data)
42
+          // 更友好的错误处理
43
+          const errorMsg = res.data?.msg || '认证失败,请重新登录';
44
+          console.warn('认证失败:', configObj.url, errorMsg);
45
+          
46
+          // 显示提示但不强制跳转
47
+          toast(errorMsg);
48
+          
49
+          // 清除无效token
50
+          if (token) {
51
+            uni.removeStorageSync('token');
52
+            localStorage.removeItem('token');
53
+          }
54
+          
55
+          reject(new Error(errorMsg));
56
+        } else if (res.statusCode === 200) {
57
+          resolve(res.data);
62 58
         } else {
63
-          // 尝试提取错误消息
64
-          const errorMsg = res.data?.msg || res.data?.message || '请求失败';
65
-          reject(new Error(errorMsg))
59
+          reject(res.data);
66 60
         }
67 61
       },
68 62
       fail: (err) => {
69
-        console.error('请求失败:', err);
63
+        let message = '后端接口连接异常'
64
+        if (err.errMsg.includes('timeout')) {
65
+          message = '请求超时'
66
+        }
67
+        toast(message)
70 68
         reject(err)
71 69
       }
72 70
     })
73 71
   })
74 72
 }
75
-service.interceptors.request.use(config => {
76
-  // 从Vuex或localStorage获取token
77
-  const token = store.state.token || localStorage.getItem('token');
78
-  
79
-  if (token) {
80
-    config.headers['Authorization'] = `Bearer ${token}`;
81
-  }
82
-  return config;
83
-}, error => {
84
-  return Promise.reject(error);
85
-});
86
-// 导出对象以兼容旧代码
87
-export default {
88
-  get,
89
-  post,
90
-  request
73
+
74
+// 添加便捷方法
75
+request.get = (url, params, config = {}) => {
76
+  return request({
77
+    url,
78
+    params,
79
+    method: 'get',
80
+    ...config
81
+  })
91 82
 }
83
+
84
+request.post = (url, data, config = {}) => {
85
+  return request({
86
+    url,
87
+    data,
88
+    method: 'post',
89
+    ...config
90
+  })
91
+}
92
+
93
+export default request

+ 7
- 10
RuoYi-App/vue.config.js Datei anzeigen

@@ -1,19 +1,16 @@
1 1
 // vue.config.js
2
+const path = require('path');
3
+
2 4
 module.exports = {
3 5
   devServer: {
4 6
     proxy: {
5
-      '/java-api': {
7
+      // 统一代理配置
8
+      '/': {
6 9
         target: 'http://localhost:8080',
7 10
         changeOrigin: true,
8
-        pathRewrite: { 
9
-          '^/java-api': '/java-api' // 保持原始路径
10
-        }
11
-      },
12
-      '/api': {
13
-        target: 'http://localhost:8080',
14
-        changeOrigin: true,
15
-        pathRewrite: { 
16
-          '^/api': '/api' // 修正路径重写规则
11
+        pathRewrite: {
12
+          '^/api': '', // 移除多余的/api前缀
13
+          '^/': '' 
17 14
         }
18 15
       }
19 16
     }

+ 7
- 3
RuoYi-Vue/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java Datei anzeigen

@@ -129,12 +129,16 @@ public class SecurityConfig
129 129
     }
130 130
     // SecurityConfig.java
131 131
 
132
+
132 133
     protected void configure(HttpSecurity http) throws Exception {
133 134
         http
134 135
                 .authorizeRequests()
135
-                .antMatchers("/api/novel/list").permitAll() // 放行小说列表
136
-                .antMatchers("/java-api/category/tree").permitAll() // 放行分类
137
-                .antMatchers("/api/novel/hot").permitAll() // 放行热门小说
136
+                // 放行公共API
137
+                .antMatchers("/novel/list").permitAll()
138
+                .antMatchers("/category/tree").permitAll()
139
+                .antMatchers("/novel/hot").permitAll()
140
+                .antMatchers("/ad/position").permitAll()
141
+                // 其他请求需要认证
138 142
                 .anyRequest().authenticated()
139 143
                 .and()
140 144
                 .csrf().disable();

+ 1
- 1
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/controller/NovelController.java Datei anzeigen

@@ -29,7 +29,7 @@ import java.util.concurrent.CompletableFuture;
29 29
 
30 30
 // NovelController.java
31 31
 @RestController
32
-@RequestMapping("/api/novel")
32
+@RequestMapping("/novel")
33 33
 public class NovelController extends BaseController {
34 34
 
35 35
 

Laden…
Abbrechen
Speichern