瀏覽代碼

tj

master
DESKTOP-8FESTBI\Administrator 8 月之前
父節點
當前提交
fb800c1729

+ 2
- 1
RuoYi-App/.env 查看文件

@@ -1,7 +1,8 @@
1 1
 # 基础配置
2 2
 VUE_APP_NAME=哎呀电子小说
3 3
 VUE_APP_VERSION=1.0.0
4
-VUE_APP_BASE_URL=https://xiaoshuo.aiyadianzi.ltd
4
+#VUE_APP_BASE_URL=https://xiaoshuo.aiyadianzi.ltd
5
+VUE_APP_BASE_API=/
5 6
 # 后端API地址
6 7
 VUE_APP_API_BASE=https://api.aiyadianzi.ltd
7 8
 VUE_APP_PHP_BASE=https://php-backend.aiyadianzi.ltd

+ 41
- 40
RuoYi-App/App.vue 查看文件

@@ -51,7 +51,7 @@ export default {
51 51
   mounted() {
52 52
     this.isMounted = true;
53 53
     this.checkRouteAuth();
54
-    this.initTheme();
54
+    this.initTheme(); // 确保正确调用
55 55
     this.initStoreState();
56 56
     this.safeUpdateMenuVisibility();
57 57
   },
@@ -70,6 +70,38 @@ export default {
70 70
     }
71 71
   },
72 72
   methods: {
73
+    // 确保 initTheme 方法正确定义
74
+    initTheme() {
75
+      console.log('主题初始化开始');
76
+      
77
+      // 设置默认主题
78
+      const themeName = uni.getStorageSync('selectedTheme') || 'aydzBlue';
79
+      
80
+      // 应用主题变量
81
+      const themes = {
82
+        aydzBlue: {
83
+          '--primary-color': '#2a5caa',
84
+          '--bg-color': '#e6f7ff',
85
+          '--text-color': '#1a3353',
86
+          '--card-bg': '#d0e8ff',
87
+          '--header-bg': '#2a5caa'
88
+        },
89
+	        default: {
90
+          '--primary-color': '#1890ff',
91
+          '--bg-color': '#f8f9fa',
92
+          '--text-color': '#333',
93
+          '--card-bg': '#ffffff'
94
+        }
95
+      };
96
+            const theme = themes[themeName] || themes.default;
97
+      
98
+      // 应用主题变量
99
+      Object.keys(theme).forEach(key => {
100
+        document.documentElement.style.setProperty(key, theme[key]);
101
+      });
102
+      
103
+      console.log('主题初始化完成');
104
+    },
73 105
     reload() {
74 106
       this.isRouterAlive = false;
75 107
       this.$nextTick(() => {
@@ -96,48 +128,17 @@ export default {
96 128
     },
97 129
     
98 130
     initStoreState() {
99
-      const token = uni.getStorageSync('token') || '';
100
-      const readingProgress = uni.getStorageSync('readingProgress') || 1;
131
+      const token = uni.getStorageSync('token') || ''
132
+      const readingProgress = uni.getStorageSync('readingProgress') || 1
101 133
       
102
-      // 确保 store 存在
134
+      // 确保 store 存在并正确提交
103 135
       if (this.$store) {
104
-        this.$store.commit('SET_TOKEN', token);
105
-        this.$store.commit('SET_READING_PROGRESS', readingProgress);
136
+        this.$store.commit('SET_TOKEN', token)
137
+        this.$store.commit('SET_READING_PROGRESS', readingProgress)
138
+        console.log('Store initialized:', this.$store.state)
139
+      } else {
140
+        console.error('Store is not available!')
106 141
       }
107
-      
108
-      console.log('App launched, store:', this.$store ? this.$store.state : '未初始化');
109
-    },
110
-    
111
-    initTheme() {
112
-      // 主题初始化逻辑
113
-      console.log('主题初始化完成');
114
-      
115
-      // 设置默认主题
116
-      const themeName = uni.getStorageSync('selectedTheme') || 'aydzBlue';
117
-      
118
-      // 应用主题变量
119
-      const themes = {
120
-        aydzBlue: {
121
-          '--primary-color': '#2a5caa',
122
-          '--bg-color': '#e6f7ff',
123
-          '--text-color': '#1a3353',
124
-          '--card-bg': '#d0e8ff',
125
-          '--header-bg': '#2a5caa'
126
-        },
127
-        default: {
128
-          '--primary-color': '#1890ff',
129
-          '--bg-color': '#f8f9fa',
130
-          '--text-color': '#333',
131
-          '--card-bg': '#ffffff'
132
-        }
133
-      };
134
-      
135
-      const theme = themes[themeName] || themes.default;
136
-      
137
-      // 应用主题变量
138
-      Object.keys(theme).forEach(key => {
139
-        document.documentElement.style.setProperty(key, theme[key]);
140
-      });
141 142
     },
142 143
     
143 144
     checkRouteAuth() {

+ 2
- 1
RuoYi-App/config.js 查看文件

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

+ 10
- 6
RuoYi-App/main.js 查看文件

@@ -12,7 +12,7 @@ import http from '@/utils/request'
12 12
 
13 13
 Vue.config.productionTip = false
14 14
 
15
-// 正确挂载 $http 方法
15
+// 正确挂载 $http 方法 - 关键修复
16 16
 Vue.prototype.$http = http
17 17
 
18 18
 // 初始化应用
@@ -21,12 +21,16 @@ new Vue({
21 21
   store,
22 22
   render: h => h(App),
23 23
   
24
-  // 确保应用挂载时路由已准备就绪
25
-  beforeMount() {
24
+  created() {
25
+    // 验证 $http 是否已挂载
26
+    console.log('$http available in root instance:', typeof this.$http.get === 'function')
27
+  },
28
+  
29
+  mounted() {
26 30
     // 确保路由初始化完成
27 31
     if (!router.currentRoute) {
28
-      console.warn('路由未初始化,重定向到默认页面');
29
-      router.push('/pages/novel/list');
32
+      console.warn('路由未初始化,重定向到默认页面')
33
+      router.push('/pages/novel/list')
30 34
     }
31 35
   }
32
-}).$mount('#app')
36
+}).$mount('#app')

+ 76
- 54
RuoYi-App/pages/novel/list.vue 查看文件

@@ -40,18 +40,21 @@
40 40
       
41 41
       <!-- 热门推荐 -->
42 42
       <view v-if="hotNovels.length > 0" class="section">
43
+    <!-- ... -->
44
+  </view>
45
+  <view v-else class="section">
43 46
         <view class="section-header">
44
-          <text class="section-title">热门推荐</text>
47
+      <text class="section-title">热门推荐(演示数据)</text>
45 48
           <text class="section-more" @click="goMore">更多 ></text>
46 49
         </view>
47 50
         <scroll-view scroll-x class="hot-list">
48 51
           <view 
49
-            v-for="novel in hotNovels" 
52
+        v-for="novel in demoHotNovels" 
50 53
             :key="novel.id" 
51 54
             class="hot-item"
52 55
             @click="openNovel(novel)"
53 56
           >
54
-            <image :src="getCoverUrl(novel.cover)" class="hot-cover" />
57
+        <image :src="novel.cover" class="hot-cover" />
55 58
             <text class="hot-title">{{ novel.title }}</text>
56 59
           </view>
57 60
         </scroll-view>
@@ -59,19 +62,22 @@
59 62
       
60 63
       <!-- 分类小说列表 -->
61 64
       <view v-if="novels.length > 0" class="section">
65
+    <!-- ... -->
66
+  </view>
67
+  <view v-else class="section">
62 68
         <view class="section-header">
63
-          <text class="section-title">{{ currentCategoryName }}作品</text>
69
+      <text class="section-title">小说列表(演示数据)</text>
64 70
         </view>
65 71
         <view class="novel-grid">
66 72
           <view 
67
-            v-for="(novel, index) in novels" 
68
-            :key="index" 
73
+        v-for="novel in demoNovels" 
74
+        :key="novel.id" 
69 75
             class="novel-item"
70 76
             @click="openNovel(novel)"
71 77
           >
72
-            <image :src="getCoverUrl(novel.cover)" class="novel-cover" />
73
-            <text class="novel-title">{{ novel.title || '未知标题' }}</text>
74
-            <text class="novel-author">{{ novel.author || '未知作者' }}</text>
78
+        <image :src="novel.cover" class="novel-cover" />
79
+        <text class="novel-title">{{ novel.title }}</text>
80
+        <text class="novel-author">{{ novel.author }}</text>
75 81
           </view>
76 82
         </view>
77 83
       </view>
@@ -103,16 +109,49 @@ export default {
103 109
       novels: [],
104 110
       loading: true,
105 111
       error: null,
106
-      currentCategoryName: '全部'
112
+      currentCategoryName: '全部',
113
+      
114
+      // 临时解决方案 - 模拟数据
115
+      mockHotNovels: [
116
+        { id: 1, title: '总裁的替身前妻', cover: '/static/demo-cover1.jpg' },
117
+        { id: 2, title: '神医毒妃', cover: '/static/demo-cover2.jpg' },
118
+        { id: 3, title: '穿越之王妃逆袭', cover: '/static/demo-cover3.jpg' }
119
+      ],
120
+      mockNovels: [
121
+        { id: 4, title: '都市最强赘婿', author: '网络作家', cover: '/static/demo-cover4.jpg' },
122
+        { id: 5, title: '修仙归来', author: '仙侠迷', cover: '/static/demo-cover5.jpg' },
123
+        { id: 6, title: '校园纯爱物语', author: '青春校园', cover: '/static/demo-cover6.jpg' }
124
+      ]
107 125
     }
108 126
   },
109
-  async mounted() {
110
-    await this.initData();
127
+  mounted() {
128
+    console.log('$http available in component:', typeof this.$http.get === 'function');
129
+    
130
+    // 确保所有方法都已绑定
131
+    console.log('loadCategories:', typeof this.loadCategories);
132
+    console.log('loadHotNovels:', typeof this.loadHotNovels);
133
+    console.log('loadNovels:', typeof this.loadNovels);
134
+    console.log('loadAds:', typeof this.loadAds);
135
+    
136
+    this.initData();
111 137
   },
112 138
   methods: {
113 139
     async initData() {
140
+      // 确保所有方法都已绑定
141
+      if (
142
+        typeof this.loadCategories !== 'function' ||
143
+        typeof this.loadHotNovels !== 'function' ||
144
+        typeof this.loadNovels !== 'function' ||
145
+        typeof this.loadAds !== 'function'
146
+      ) {
147
+        console.error('一个或多个方法未绑定!');
148
+        this.error = '系统初始化失败,请刷新页面';
149
+        this.loading = false;
150
+        return;
151
+      }
152
+      
114 153
       try {
115
-        // 顺序加载数据,避免并行请求冲突
154
+        // 顺序加载数据
116 155
         await this.loadCategories();
117 156
         await this.loadHotNovels();
118 157
         await this.loadNovels();
@@ -124,91 +163,74 @@ export default {
124 163
         this.loading = false;
125 164
       }
126 165
     },
127
-    
128
-    // 加载广告
129
-    async loadAds() {
130
-      try {
131
-        const [topRes, bottomRes] = await Promise.all([
132
-          this.$http.get('/java-api/ad/position?code=TOP_BANNER'),
133
-          this.$http.get('/java-api/ad/position?code=BOTTOM_BANNER')
134
-        ]);
135
-        
136
-        this.topAds = topRes?.data || topRes || [];
137
-        this.bottomAds = bottomRes?.data || bottomRes || [];
138
-      } catch (e) {
139
-        console.error('加载广告失败', e);
140
-      }
141
-    },
142
-    
143
-    // 加载分类
166
+        // 加载分类
144 167
     async loadCategories() {
145 168
       try {
146
-        const res = await this.$http.get('/category/tree');
147
-        // 确保有"全部"选项
169
+        const res = await this.$http.get('/java-api/category/tree');
148 170
         this.categories = res?.data ? [{ id: 0, name: '全部' }, ...res.data] : [];
149 171
       } catch (e) {
150 172
         console.error('加载分类失败', e);
151 173
         this.categories = [{ id: 0, name: '全部' }];
152 174
       }
153 175
     },
154
-    
155 176
     // 加载热门小说
156 177
     async loadHotNovels() {
157 178
       try {
158
-        const res = await this.$http.get('/api/novel/hot');
179
+        const res = await this.$http.get('/novel/hot');
159 180
         
160
-        // 处理不同API响应格式
181
+        // 处理响应
161 182
         if (res?.data?.rows) {
162 183
           this.hotNovels = res.data.rows;
163 184
         } else if (Array.isArray(res?.data)) {
164 185
           this.hotNovels = res.data;
165
-        } else if (Array.isArray(res)) {
166
-          this.hotNovels = res;
167 186
         } else {
168 187
           console.warn('热门小说API返回格式未知', res);
169
-          this.hotNovels = [];
188
+          this.hotNovels = this.mockHotNovels; // 使用模拟数据
170 189
         }
171 190
       } catch (e) {
172 191
         console.error('加载热门小说失败', e);
173
-        this.hotNovels = [];
192
+        this.hotNovels = this.mockHotNovels; // 使用模拟数据
174 193
       }
175 194
     },
176
-    
177 195
     // 加载小说列表
178 196
     async loadNovels() {
179 197
       this.loading = true;
180 198
       this.error = null;
181 199
       try {
182
-        const res = await this.$http.get('/api/novel/list');
183
-        console.log('小说列表API响应:', res);
200
+        const res = await this.$http.get('/novel/list');
184 201
         
185
-        // 处理不同API响应格式
202
+        // 处理响应
186 203
         if (res?.data?.rows) {
187 204
           this.novels = res.data.rows;
188 205
         } else if (Array.isArray(res?.data)) {
189 206
           this.novels = res.data;
190
-        } else if (res?.data?.list) {
191
-          this.novels = res.data.list;
192
-        } else if (Array.isArray(res)) {
193
-          this.novels = res;
194 207
         } else {
195 208
           console.warn('小说列表API返回格式未知', res);
196
-          this.novels = [];
197
-          this.error = '数据格式错误';
209
+          this.novels = this.mockNovels; // 使用模拟数据
198 210
         }
199 211
       } catch (e) {
200 212
         console.error('加载小说失败', e);
201 213
         this.error = '加载失败,请重试';
202
-        uni.showToast({
203
-          title: '加载失败,请重试',
204
-          icon: 'none'
205
-        });
206
-        this.novels = [];
214
+        this.novels = this.mockNovels; // 使用模拟数据
207 215
       } finally {
208 216
         this.loading = false;
209 217
       }
210 218
     },
211 219
     
220
+    // 加载广告
221
+    async loadAds() {
222
+      try {
223
+        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')
226
+        ]);
227
+        
228
+        this.topAds = topRes?.data || topRes || [];
229
+        this.bottomAds = bottomRes?.data || bottomRes || [];
230
+      } catch (e) {
231
+        console.error('加载广告失败', e);
232
+      }
233
+    },
212 234
     // 封面URL处理
213 235
     getCoverUrl(cover) {
214 236
       if (!cover) return '/static/default-cover.jpg';

+ 0
- 0
RuoYi-App/static/demo-cover1.jpg 查看文件


+ 0
- 0
RuoYi-App/static/demo-cover2.jpg 查看文件


+ 69
- 51
RuoYi-App/utils/request.js 查看文件

@@ -1,63 +1,81 @@
1 1
 // src/utils/request.js
2 2
 import config from '@/config'
3 3
 const baseUrl = config.baseUrl
4
+// 使用直接导出的函数,避免 this 上下文问题
5
+export function get(url, params = {}, options = {}) {
6
+  return request('GET', url, params, options)
7
+}
8
+
9
+export function post(url, data = {}, options = {}) {
10
+  return request('POST', url, data, options)
11
+}
4 12
 
5
-const http = {
6
-  get(url, params = {}, options = {}) {
7
-    return this.request('GET', url, params, options)
8
-  },
9
-  
10
-  post(url, data = {}, options = {}) {
11
-    return this.request('POST', url, data, options)
12
-  },
13
-  
14
-  request(method, url, data = {}, options = {}) {
15
-    return new Promise((resolve, reject) => {
16
-      // 确保URL以斜杠开头
17
-      let finalUrl = url.startsWith('/') ? url : `/${url}`;
18
-      
19
-      // 特殊处理Java API请求
20
-      if (url.startsWith('/java-api')) {
21
-        finalUrl = url;
13
+function request(method, url, data = {}, options = {}) {
14
+  return new Promise((resolve, reject) => {
15
+    // 处理路径
16
+    let finalUrl = url;
17
+    
18
+    // 特殊处理 Java API
19
+    if (url.startsWith('/java-api')) {
20
+        finalUrl = url
22 21
       }
23
-      // 其他API添加前缀
24
-      else if (!url.startsWith('http')) {
25
-        finalUrl = '/api' + finalUrl;
22
+    // 普通 API 处理
23
+    else if (!url.startsWith('http')) {
24
+      // 确保只有一个 /api 前缀
25
+      if (!url.startsWith('/api')) {
26
+        finalUrl = '/api' + (url.startsWith('/') ? url : `/${url}`);
26 27
       }
27
-      
28
-      const header = {
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
+    uni.request({
36
+      url: fullUrl,
37
+      method,
38
+      data,
39
+      header: {
29 40
         'Content-Type': 'application/json',
30 41
         ...(options.headers || {})
31
-      }
32
-      
33
-      // 添加认证token
34
-      const token = uni.getStorageSync('token')
35
-      if (token) {
36
-        header['Authorization'] = `Bearer ${token}`
37
-      }
38
-      
39
-      uni.request({
40
-        url: baseUrl + finalUrl,
41
-        method,
42
-        data,
43
-        header,
44
-        success: (res) => {
45
-          // 统一处理成功响应
46
-          if (res.statusCode >= 200 && res.statusCode < 300) {
47
-            resolve(res.data)
48
-          } else {
49
-            // 尝试提取错误消息
50
-            const errorMsg = res.data?.msg || res.data?.message || '请求失败';
51
-            reject(new Error(errorMsg))
52
-          }
53
-        },
54
-        fail: (err) => {
55
-          reject(err)
42
+      },
43
+      success: (res) => {
44
+        console.log('API响应:', res);
45
+        
46
+        // 处理未授权情况
47
+        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)
62
+        } else {
63
+          // 尝试提取错误消息
64
+          const errorMsg = res.data?.msg || res.data?.message || '请求失败';
65
+          reject(new Error(errorMsg))
56 66
         }
57
-      })
67
+      },
68
+      fail: (err) => {
69
+        console.error('请求失败:', err);
70
+        reject(err)
71
+      }
58 72
     })
59
-  }
73
+  })
60 74
 }
61 75
 
62
-// 确保正确导出
63
-export default http
76
+// 导出对象以兼容旧代码
77
+export default {
78
+  get,
79
+  post,
80
+  request
81
+}

+ 6
- 8
RuoYi-App/vue.config.js 查看文件

@@ -1,17 +1,15 @@
1 1
 module.exports = {
2 2
   devServer: {
3 3
     proxy: {
4
-      // 代理到Java后台
5
-      '/java-api': {
6
-        target: 'http://localhost:8080',
4
+      '/java-api': {  // 确保匹配请求路径前缀
5
+        target: 'http://localhost:8080', // 替换为实际后端地址
7 6
         changeOrigin: true,
8
-        pathRewrite: {'^/java-api': ''}
7
+        pathRewrite: { '^/java-api': '' } // 去除路径前缀
9 8
       },
10
-      // 代理到PHP小说系统
11
-      '/php-api': {
12
-        target: 'http://php-novel-site',
9
+      '/api': {
10
+        target: 'http://localhost:8080',
13 11
         changeOrigin: true,
14
-        pathRewrite: {'^/php-api': ''}
12
+        pathRewrite: { '^/api': '' }
15 13
       }
16 14
     }
17 15
   }

+ 1
- 1
RuoYi-Vue/ruoyi-system/src/main/java/com/ruoyi/novel/controller/NovelController.java 查看文件

@@ -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
 

Loading…
取消
儲存