瀏覽代碼

兼容性修改

Zhangbw 1 月之前
父節點
當前提交
802e7372da
共有 7 個文件被更改,包括 399 次插入327 次删除
  1. 2 2
      src/App.vue
  2. 2 0
      src/main.js
  3. 0 1
      src/manifest.json
  4. 1 6
      src/pages.json
  5. 254 202
      src/pages/admin/shortPool.vue
  6. 82 76
      src/utils/api.js
  7. 58 40
      src/utils/auth.js

+ 2 - 2
src/App.vue

@@ -71,9 +71,9 @@ export default {
     // #endif
   },
   onShow: function() {
-	  //fakecheck
 	  const accountInfo = wx.getAccountInfoSync();
-	  this.globalData.envVersion = accountInfo.miniProgram.envVersion
+	  //fakecheck
+	  // this.globalData.envVersion = accountInfo.miniProgram.envVersion
     console.log('App Show')
     // 确保导航栏标题正确显示
     uni.setNavigationBarTitle({

+ 2 - 0
src/main.js

@@ -1,6 +1,8 @@
 import { createSSRApp } from 'vue'
 import App from './App.vue'
+// #ifdef H5
 import VConsole from 'vconsole'
+// #endif
 
 // Polyfill for String.prototype.startsWith (for older browsers)
 if (!String.prototype.startsWith) {

+ 0 - 1
src/manifest.json

@@ -56,7 +56,6 @@
                 "desc" : "提供更好的门店体验"
             }
         },
-        "navigationBarTitleText" : "掌升科技",
         "optimization" : {
             "subPackages" : true
         }

+ 1 - 6
src/pages.json

@@ -73,12 +73,7 @@
     "navigationBarBackgroundColor": "#ffffff",
     "navigationBarTextStyle": "black",
     "navigationBarTitleText": "量化交易大师",
-    "backgroundColor": "#f5f6fb",
-    "titleNView": {
-      "titleColor": "#3F51F7",
-      "titleSize": "18",
-      "titleWeight": "800"
-    }
+    "backgroundColor": "#f5f6fb"
   },
   "tabBar": {
 	"custom": true, // 👈 关键:启用自定义 tabBar

+ 254 - 202
src/pages/admin/shortPool.vue

@@ -107,224 +107,276 @@
   </view>
 </template>
 
-<script setup>
-import { ref, onUnmounted } from 'vue'
-import { onShow, onHide } from '@dcloudio/uni-app'
+<script>
 import { refreshUserInfo } from '@/utils/auth.js'
 import { getSuggestions, BASE_URL } from '@/utils/api.js'
 
-const searchKeyword = ref('')
-const suggestions = ref([])
-const showSuggestions = ref(false)
-const searching = ref(false)
-const stockList = ref([])
-const loading = ref(false)
-const poolType = 1
-
-let searchTimer = null
-let refreshTimer = null
-
-const getToken = () => uni.getStorageSync('user_token') || null
-
-const request = (options) => {
-  return new Promise((resolve, reject) => {
-    const token = getToken()
-    const header = options.header || {}
-    if (token) header['Authorization'] = `Bearer ${token}`
-    
-    uni.request({
-      url: `${BASE_URL}${options.url}`,
-      method: options.method || 'GET',
-      data: options.data || {},
-      header,
-      success: (res) => {
-        if (res.statusCode === 200) {
-          resolve(res.data)
-        } else {
-          const errorMsg = (res.data && res.data.message) || '请求失败'
-          reject(new Error(errorMsg))
+export default {
+  data: function() {
+    return {
+      searchKeyword: '',
+      suggestions: [],
+      showSuggestions: false,
+      searching: false,
+      stockList: [],
+      loading: false,
+      poolType: 1,
+      searchTimer: null,
+      refreshTimer: null
+    }
+  },
+
+  onShow: function() {
+    this.checkAdminPermission()
+    this.loadStockList()
+    this.startAutoRefresh()
+  },
+
+  onHide: function() {
+    this.stopAutoRefresh()
+  },
+
+  unmounted: function() {
+    this.stopAutoRefresh()
+  },
+
+  methods: {
+    getToken: function() {
+      return uni.getStorageSync('user_token') || null
+    },
+
+    request: function(options) {
+      var self = this
+      return new Promise(function(resolve, reject) {
+        var token = self.getToken()
+        var header = options.header || {}
+        if (token) {
+          header['Authorization'] = 'Bearer ' + token
         }
-      },
-      fail: () => reject(new Error('网络异常'))
-    })
-  })
-}
-
-onShow(() => {
-  checkAdminPermission()
-  loadStockList()
-  startAutoRefresh()
-})
-
-onHide(() => stopAutoRefresh())
-onUnmounted(() => stopAutoRefresh())
-
-// 获取随机刷新间隔 (4500-5500ms,平均5秒)
-const getRandomInterval = () => 4500 + Math.random() * 1000
-
-const startAutoRefresh = () => {
-  stopAutoRefresh()
-
-  const scheduleNextRefresh = () => {
-    refreshTimer = setTimeout(async () => {
-      await loadStockList(true)
+        uni.request({
+          url: BASE_URL + options.url,
+          method: options.method || 'GET',
+          data: options.data || {},
+          header: header,
+          success: function(res) {
+            if (res.statusCode === 200) {
+              resolve(res.data)
+            } else {
+              var errorMsg = (res.data && res.data.message) || '请求失败'
+              reject(new Error(errorMsg))
+            }
+          },
+          fail: function() {
+            reject(new Error('网络异常'))
+          }
+        })
+      })
+    },
+
+    getRandomInterval: function() {
+      return 4500 + Math.random() * 1000
+    },
+
+    startAutoRefresh: function() {
+      this.stopAutoRefresh()
+      var self = this
+      var scheduleNextRefresh = function() {
+        self.refreshTimer = setTimeout(function() {
+          self.loadStockList(true).then(function() {
+            scheduleNextRefresh()
+          })
+        }, self.getRandomInterval())
+      }
       scheduleNextRefresh()
-    }, getRandomInterval())
-  }
-
-  scheduleNextRefresh()
-}
-
-const stopAutoRefresh = () => {
-  if (refreshTimer) {
-    clearTimeout(refreshTimer)
-    refreshTimer = null
-  }
-}
-
-// 检查管理员权限(从后端获取最新状态)
-const checkAdminPermission = async () => {
-  const userInfo = await refreshUserInfo()
-  if (!userInfo || userInfo.status !== 2) {
-    uni.showToast({ title: '无权限访问', icon: 'none' })
-    setTimeout(() => {
-      const pages = getCurrentPages()
-      pages.length > 1 ? uni.navigateBack() : uni.switchTab({ url: '/pages/mine/mine' })
-    }, 1500)
-  }
-}
-
-const loadStockList = async (silent = false) => {
-  if (!silent) loading.value = true
-  try {
-    const res = await request({ url: '/v1/stock/pool/admin/list', data: { poolType } })
-    if (res.code === 200) stockList.value = res.data || []
-  } catch (e) {
-    console.error('加载失败', e)
-  } finally {
-    if (!silent) loading.value = false
-  }
-}
-
-const getChangeClass = (changePercent) => {
-  if (!changePercent || changePercent === '-') return ''
-  return changePercent.startsWith('+') ? 'up' : changePercent.startsWith('-') ? 'down' : ''
-}
-
-// 判断是否是当天加入的股票
-const isAddedToday = (addDate) => {
-  if (!addDate) return false
-  // 使用本地时间而不是UTC时间
-  const now = new Date()
-  const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
-  return addDate === today
-}
-
-// 格式化入池日期(与历史查询页面保持一致)
-const formatAddDate = (dateStr) => {
-  if (!dateStr) return '-'
-  // 处理可能的日期格式:2025-01-10 或 数组格式 [2025, 1, 10]
-  if (Array.isArray(dateStr)) {
-    const [year, month, day] = dateStr
-    return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
-  }
-  const parts = dateStr.split('-')
-  if (parts.length >= 3) {
-    return `${parts[0]}-${parts[1].padStart(2, '0')}-${parts[2].padStart(2, '0')}`
-  }
-  return dateStr
-}
+    },
 
-const handleSearchInput = () => {
-  if (searchTimer) clearTimeout(searchTimer)
-  if (!searchKeyword.value.trim()) {
-    suggestions.value = []
-    showSuggestions.value = false
-    return
-  }
-  searching.value = true
-  showSuggestions.value = true
-  searchTimer = setTimeout(async () => {
-    try {
-      const res = await getSuggestions(searchKeyword.value.trim())
-      suggestions.value = res.code === 200 && res.data ? res.data : []
-    } catch (e) {
-      suggestions.value = []
-    } finally {
-      searching.value = false
-    }
-  }, 300)
-}
+    stopAutoRefresh: function() {
+      if (this.refreshTimer) {
+        clearTimeout(this.refreshTimer)
+        this.refreshTimer = null
+      }
+    },
+
+    checkAdminPermission: function() {
+      refreshUserInfo().then(function(userInfo) {
+        if (!userInfo || userInfo.status !== 2) {
+          uni.showToast({ title: '无权限访问', icon: 'none' })
+          setTimeout(function() {
+            var pages = getCurrentPages()
+            if (pages.length > 1) {
+              uni.navigateBack()
+            } else {
+              uni.switchTab({ url: '/pages/mine/mine' })
+            }
+          }, 1500)
+        }
+      })
+    },
 
-const clearSearch = () => {
-  searchKeyword.value = ''
-  suggestions.value = []
-  showSuggestions.value = false
-}
+    loadStockList: function(silent) {
+      var self = this
+      if (silent === undefined) {
+        silent = false
+      }
+      if (!silent) {
+        this.loading = true
+      }
+      return this.request({ url: '/v1/stock/pool/admin/list', data: { poolType: this.poolType } }).then(function(res) {
+        if (res.code === 200) {
+          self.stockList = res.data || []
+        }
+      }).catch(function(e) {
+        console.error('加载失败', e)
+      }).then(function() {
+        if (!silent) {
+          self.loading = false
+        }
+      })
+    },
 
-const closeSuggestions = () => {
-  showSuggestions.value = false
-}
+    getChangeClass: function(changePercent) {
+      if (changePercent === null || changePercent === undefined) {
+        return ''
+      }
+      var cp = String(changePercent)
+      if (!cp || cp === '-') {
+        return ''
+      }
+      if (cp.indexOf('+') === 0) {
+        return 'up'
+      } else if (cp.indexOf('-') === 0) {
+        return 'down'
+      }
+      return ''
+    },
 
-const handleAddFromSuggestion = async (item) => {
-  if (stockList.value.some(s => s.code === item.code)) {
-    uni.showToast({ title: '该股票已在超短池中', icon: 'none' })
-    return
-  }
+    formatAddDate: function(dateStr) {
+      if (!dateStr) {
+        return '-'
+      }
+      if (Array.isArray(dateStr)) {
+        var y = dateStr[0]
+        var m = dateStr[1]
+        var d = dateStr[2]
+        var ms = m < 10 ? '0' + m : String(m)
+        var ds = d < 10 ? '0' + d : String(d)
+        return y + '-' + ms + '-' + ds
+      }
+      if (typeof dateStr !== 'string') {
+        return String(dateStr)
+      }
+      var parts = dateStr.split('-')
+      if (parts.length >= 3) {
+        var monthStr = parts[1].length < 2 ? '0' + parts[1] : parts[1]
+        var dayStr = parts[2].length < 2 ? '0' + parts[2] : parts[2]
+        return parts[0] + '-' + monthStr + '-' + dayStr
+      }
+      return dateStr
+    },
 
-  // 添加确认弹窗
-  uni.showModal({
-    title: '确认添加',
-    content: `确定要将 ${item.name} (${item.code}) 添加到超短池吗?`,
-    success: async (modalRes) => {
-      if (modalRes.confirm) {
-        try {
-          const res = await request({
-            url: '/v1/stock/pool/admin/add',
-            method: 'POST',
-            header: { 'content-type': 'application/json' },
-            data: { stockCode: item.code, poolType }
-          })
-          if (res.code === 200) {
-            uni.showToast({ title: '添加成功', icon: 'success' })
-            clearSearch()
-            loadStockList()
+    handleSearchInput: function() {
+      var self = this
+      if (this.searchTimer) {
+        clearTimeout(this.searchTimer)
+      }
+      if (!this.searchKeyword.trim()) {
+        this.suggestions = []
+        this.showSuggestions = false
+        return
+      }
+      this.searching = true
+      this.showSuggestions = true
+      this.searchTimer = setTimeout(function() {
+        getSuggestions(self.searchKeyword.trim()).then(function(res) {
+          if (res.code === 200 && res.data) {
+            self.suggestions = res.data
           } else {
-            uni.showToast({ title: res.message || '添加失败', icon: 'none' })
+            self.suggestions = []
           }
-        } catch (e) {
-          uni.showToast({ title: '添加失败', icon: 'none' })
+        }).catch(function() {
+          self.suggestions = []
+        }).then(function() {
+          self.searching = false
+        })
+      }, 300)
+    },
+
+    clearSearch: function() {
+      this.searchKeyword = ''
+      this.suggestions = []
+      this.showSuggestions = false
+    },
+
+    closeSuggestions: function() {
+      this.showSuggestions = false
+    },
+
+    handleAddFromSuggestion: function(item) {
+      var self = this
+      var isDuplicate = false
+      for (var i = 0; i < this.stockList.length; i++) {
+        if (this.stockList[i].code === item.code) {
+          isDuplicate = true
+          break
         }
       }
-    }
-  })
-}
-
-const handleDeleteStock = (item) => {
-  uni.showModal({
-    title: '确认撤出',
-    content: `确定要将 ${item.name} 从超短池撤出吗?`,
-    success: async (res) => {
-      if (res.confirm) {
-        try {
-          const result = await request({
-            url: '/v1/stock/pool/admin/delete',
-            method: 'POST',
-            header: { 'content-type': 'application/json' },
-            data: { stockCode: item.code, poolType }
-          })
-          if (result.code === 200) {
-            uni.showToast({ title: '撤出成功', icon: 'success' })
-            loadStockList()
-          } else {
-            uni.showToast({ title: result.message || '撤出失败', icon: 'none' })
+      if (isDuplicate) {
+        uni.showToast({ title: '该股票已在超短池中', icon: 'none' })
+        return
+      }
+      uni.showModal({
+        title: '确认添加',
+        content: '确定要将 ' + item.name + ' (' + item.code + ') 添加到超短池吗?',
+        success: function(modalRes) {
+          if (modalRes.confirm) {
+            self.request({
+              url: '/v1/stock/pool/admin/add',
+              method: 'POST',
+              header: { 'content-type': 'application/json' },
+              data: { stockCode: item.code, poolType: self.poolType }
+            }).then(function(res) {
+              if (res.code === 200) {
+                uni.showToast({ title: '添加成功', icon: 'success' })
+                self.clearSearch()
+                self.loadStockList()
+              } else {
+                uni.showToast({ title: res.message || '添加失败', icon: 'none' })
+              }
+            }).catch(function() {
+              uni.showToast({ title: '添加失败', icon: 'none' })
+            })
           }
-        } catch (e) {
-          uni.showToast({ title: '撤出失败', icon: 'none' })
         }
-      }
+      })
+    },
+
+    handleDeleteStock: function(item) {
+      var self = this
+      uni.showModal({
+        title: '确认撤出',
+        content: '确定要将 ' + item.name + ' 从超短池撤出吗?',
+        success: function(res) {
+          if (res.confirm) {
+            self.request({
+              url: '/v1/stock/pool/admin/delete',
+              method: 'POST',
+              header: { 'content-type': 'application/json' },
+              data: { stockCode: item.code, poolType: self.poolType }
+            }).then(function(result) {
+              if (result.code === 200) {
+                uni.showToast({ title: '撤出成功', icon: 'success' })
+                self.loadStockList()
+              } else {
+                uni.showToast({ title: result.message || '撤出失败', icon: 'none' })
+              }
+            }).catch(function() {
+              uni.showToast({ title: '撤出失败', icon: 'none' })
+            })
+          }
+        }
+      })
     }
-  })
+  }
 }
 </script>
 
@@ -379,7 +431,7 @@ const handleDeleteStock = (item) => {
 /* 内容区 */
 .scroll-view {
   flex: 1;
-  height: 0;
+  height: 100vh;
 }
 
 .content-wrapper {

+ 82 - 76
src/utils/api.js

@@ -4,15 +4,15 @@
 
 // ============ 配置区域 ============
 
-const ENV = 'prod' // 'dev' | 'prod'
+var ENV = 'prod' // 'dev' | 'prod'
 
-const CONFIG = {
+var CONFIG = {
   dev: 'https://www.whzhangsheng.cn/applet-api',      // 开发环境
   local:'http://192.168.1.171:8081',
-  prod: 'https://applet.whzhangsheng.cn/applet-api',  
+  prod: 'https://applet.whzhangsheng.cn/applet-api',
 }
 
-const BASE_URL = CONFIG[ENV]
+var BASE_URL = CONFIG[ENV]
 // ============ 配置区域结束 ============
 
 /**
@@ -21,22 +21,22 @@ const BASE_URL = CONFIG[ENV]
  * @param {string} url - 图片路径(可能是相对路径或完整URL)
  * @returns {string} 完整的图片URL
  */
-export const getImageUrl = (url) => {
+export var getImageUrl = function(url) {
   if (!url) return ''
 
   // 检测微信临时路径,这些路径在真机上无法访问,返回空让前端显示默认头像
-  if (url.startsWith('wxfile://') || url.startsWith('http://tmp/') || url.includes('/tmp/wx')) {
+  if (url.indexOf('wxfile://') === 0 || url.indexOf('http://tmp/') === 0 || url.indexOf('/tmp/wx') !== -1) {
     console.warn('[getImageUrl] 检测到微信临时路径,无法显示:', url)
     return ''
   }
 
   // 已经是完整URL,直接返回
-  if (url.startsWith('http')) {
+  if (url.indexOf('http') === 0) {
     return url
   }
 
   // 本地静态资源路径,转换为服务器路径
-  if (url.startsWith('/static/images/')) {
+  if (url.indexOf('/static/images/') === 0) {
     return BASE_URL + url.replace('/static/images/', '/images/')
   }
 
@@ -50,7 +50,7 @@ export { BASE_URL }
 /**
  * 获取本地存储的token(避免循环依赖)
  */
-const getToken = () => {
+var getToken = function() {
   return uni.getStorageSync('user_token') || null
 }
 
@@ -60,32 +60,38 @@ const getToken = () => {
  * @param {object} options - 请求配置对象
  * @returns {Promise} 请求Promise
  */
-const request = (options) => {
-  return new Promise((resolve, reject) => {
+var request = function(options) {
+  return new Promise(function(resolve, reject) {
     // 获取token并添加到请求头
-    const token = getToken()
-    const header = options.header || {}
+    var token = getToken()
+    var header = options.header || {}
     if (token) {
-      header['Authorization'] = `Bearer ${token}`
+      header['Authorization'] = 'Bearer ' + token
     }
 
     // 公开接口列表(不需要登录的接口)
-    const publicApis = [
+    var publicApis = [
       '/v1/stock/pool/list',
       '/v1/order/config'
     ]
 
     // 判断是否为公开接口
-    const isPublicApi = publicApis.some(api => options.url.includes(api))
+    var isPublicApi = false
+    for (var i = 0; i < publicApis.length; i++) {
+      if (options.url.indexOf(publicApis[i]) !== -1) {
+        isPublicApi = true
+        break
+      }
+    }
 
     uni.request({
-      url: `${BASE_URL}${options.url}`,
+      url: BASE_URL + options.url,
       method: options.method || 'GET',
       data: options.data || {},
       header: header,
-      success: (res) => {
+      success: function(res) {
         // 检查是否有新token(滑动续期)
-        const newToken = res.header['New-Token'] || res.header['new-token']
+        var newToken = res.header['New-Token'] || res.header['new-token']
         if (newToken) {
           console.log('检测到新token,自动续期')
           uni.setStorageSync('user_token', newToken)
@@ -112,13 +118,13 @@ const request = (options) => {
           uni.removeStorageSync('user_info')
 
           // 延迟后显示登录弹窗
-          setTimeout(() => {
+          setTimeout(function() {
             uni.showModal({
               title: '登录提示',
               content: '登录已过期,请重新登录',
               confirmText: '去登录',
               cancelText: '取消',
-              success: (modalRes) => {
+              success: function(modalRes) {
                 if (modalRes.confirm) {
                   // 跳转到登录页面
                   uni.navigateTo({
@@ -134,7 +140,7 @@ const request = (options) => {
           reject(new Error(res.data.message || '服务暂不可用'))
         }
       },
-      fail: () => {
+      fail: function() {
         reject(new Error('网络异常'))
       }
     })
@@ -149,11 +155,11 @@ const request = (options) => {
  * @param {string} redirectUrl - 授权后的回调地址
  * @returns {Promise} 返回微信授权URL
  */
-export const getH5AuthUrl = (redirectUrl) => {
+export var getH5AuthUrl = function(redirectUrl) {
   return request({
     url: '/v1/auth/h5/auth-url',
     method: 'GET',
-    data: { redirectUrl }
+    data: { redirectUrl: redirectUrl }
   })
 }
 
@@ -162,11 +168,11 @@ export const getH5AuthUrl = (redirectUrl) => {
  * @param {string} code - 微信授权code
  * @returns {Promise} 返回用户信息
  */
-export const h5AuthCallback = (code) => {
+export var h5AuthCallback = function(code) {
   return request({
     url: '/v1/auth/h5/callback',
     method: 'GET',
-    data: { code }
+    data: { code: code }
   })
 }
 
@@ -175,11 +181,11 @@ export const h5AuthCallback = (code) => {
  * @param {string} openid - 微信openid
  * @returns {Promise} 返回 { data: boolean }
  */
-export const checkUserStatus = (openid) => {
+export var checkUserStatus = function(openid) {
   return request({
     url: '/v1/auth/h5/check-user',
     method: 'GET',
-    data: { openid }
+    data: { openid: openid }
   })
 }
 
@@ -188,7 +194,7 @@ export const checkUserStatus = (openid) => {
  * @param {object} params - { openid, code, nickname, avatarUrl, unionid }
  * @returns {Promise} 返回 { token }
  */
-export const h5PhoneLogin = (params) => {
+export var h5PhoneLogin = function(params) {
   return request({
     url: '/v1/auth/h5/phone-login',
     method: 'POST',
@@ -208,7 +214,7 @@ export const h5PhoneLogin = (params) => {
  * @param {object} params - { loginCode }
  * @returns {Promise} 返回 { isSign, token?, code? }
  */
-export const wxSilentLoginApi = (params) => {
+export var wxSilentLoginApi = function(params) {
   return request({
     url: '/v1/auth/wx/silent-login',
     method: 'POST',
@@ -224,7 +230,7 @@ export const wxSilentLoginApi = (params) => {
  * @param {object} params - { loginCode, phoneCode, encryptedData, iv }
  * @returns {Promise} 返回 { isSign, token?, openid?, unionid?, phoneNumber? }
  */
-export const wxPhoneLoginApi = (params) => {
+export var wxPhoneLoginApi = function(params) {
   return request({
     url: '/v1/auth/wx/phone-verify',
     method: 'POST',
@@ -240,7 +246,7 @@ export const wxPhoneLoginApi = (params) => {
  * @param {object} params - { openid, unionid, phoneNumber, nickname, avatarUrl }
  * @returns {Promise} 返回 { token }
  */
-export const wxCompleteUserInfoApi = (params) => {
+export var wxCompleteUserInfoApi = function(params) {
   return request({
     url: '/v1/auth/wx/register',
     method: 'POST',
@@ -256,7 +262,7 @@ export const wxCompleteUserInfoApi = (params) => {
  * 获取用户完整信息接口
  * @returns {Promise} 返回用户信息
  */
-export const getUserInfoApi = () => {
+export var getUserInfoApi = function() {
   return request({
     url: '/v1/user/info',
     method: 'GET'
@@ -266,8 +272,8 @@ export const getUserInfoApi = () => {
 /**
  * 文件上传配置
  */
-export const uploadFile = {
-  url: `${BASE_URL}/v1/file/upload`
+export var uploadFile = {
+  url: BASE_URL + '/v1/file/upload'
 }
 
 /**
@@ -277,7 +283,7 @@ export const uploadFile = {
  * @param {string} data.avatar - 头像URL
  * @returns {Promise} 返回更新结果
  */
-export const updateUserProfile = (data) => {
+export var updateUserProfile = function(data) {
   return request({
     url: '/v1/user/profile',
     method: 'PUT',
@@ -293,11 +299,11 @@ export const updateUserProfile = (data) => {
  * @param {string} keyword - 搜索关键词
  * @returns {Promise} 返回搜索建议列表
  */
-export const getSuggestions = (keyword) => {
+export var getSuggestions = function(keyword) {
   return request({
     url: '/v1/stock/suggestion',
     method: 'GET',
-    data: { keyword }
+    data: { keyword: keyword }
   })
 }
 
@@ -306,14 +312,14 @@ export const getSuggestions = (keyword) => {
  * @param {string} keyword - 股票代码或名称
  * @returns {Promise} 返回股票详情信息
  */
-export const searchStocks = (keyword) => {
+export var searchStocks = function(keyword) {
   return request({
     url: '/v1/stock/search',
     method: 'POST',
     header: {
       'content-type': 'application/json'
     },
-    data: { keyword }
+    data: { keyword: keyword }
   })
 }
 
@@ -322,11 +328,11 @@ export const searchStocks = (keyword) => {
  * @param {string} codes - 股票代码,多个用逗号分隔
  * @returns {Promise} 返回股票行情数据列表
  */
-export const getStockQuotes = (codes) => {
+export var getStockQuotes = function(codes) {
   return request({
     url: '/api/stock/fetch',
     method: 'GET',
-    data: { codes }
+    data: { codes: codes }
   })
 }
 
@@ -335,11 +341,11 @@ export const getStockQuotes = (codes) => {
  * @param {string} code - 指数代码 (000001=上证指数, 399001=深证成指, 399006=创业板指)
  * @returns {Promise} 返回指数数据
  */
-export const getIndexQuote = (code) => {
+export var getIndexQuote = function(code) {
   return request({
     url: '/api/stock/index',
     method: 'GET',
-    data: { code }
+    data: { code: code }
   })
 }
 
@@ -347,7 +353,7 @@ export const getIndexQuote = (code) => {
  * 获取用户自选股票列表
  * @returns {Promise} 返回用户自选股票列表
  */
-export const getUserStocks = () => {
+export var getUserStocks = function() {
   return request({
     url: '/v1/user/stock/list',
     method: 'GET'
@@ -359,7 +365,7 @@ export const getUserStocks = () => {
  * @param {object} data - { stockCode, stockName, poolType, currentPrice }
  * @returns {Promise} 返回添加结果
  */
-export const addUserStock = (data) => {
+export var addUserStock = function(data) {
   return request({
     url: '/v1/user/stock/add',
     method: 'POST',
@@ -375,9 +381,9 @@ export const addUserStock = (data) => {
  * @param {string} stockCode - 股票代码
  * @returns {Promise} 返回删除结果
  */
-export const deleteUserStock = (stockCode) => {
+export var deleteUserStock = function(stockCode) {
   return request({
-    url: `/v1/user/stock/delete?stockCode=${encodeURIComponent(stockCode)}`,
+    url: '/v1/user/stock/delete?stockCode=' + encodeURIComponent(stockCode),
     method: 'DELETE'
   })
 }
@@ -389,11 +395,11 @@ export const deleteUserStock = (stockCode) => {
  * @param {number} poolType - 池类型:1-超短池,2-强势池
  * @returns {Promise} 返回股票池列表
  */
-export const getStockPoolList = (poolType) => {
+export var getStockPoolList = function(poolType) {
   return request({
     url: '/v1/stock/pool/list',
     method: 'GET',
-    data: { poolType }
+    data: { poolType: poolType }
   })
 }
 
@@ -405,11 +411,11 @@ export const getStockPoolList = (poolType) => {
  * @param {number} poolType - 池类型:1-超短池,2-强势池
  * @returns {Promise} 返回 { poolType, poolName, price, description }
  */
-export const getPaymentConfig = (poolType) => {
+export var getPaymentConfig = function(poolType) {
   return request({
     url: '/v1/order/config',
     method: 'GET',
-    data: { poolType }
+    data: { poolType: poolType }
   })
 }
 
@@ -418,7 +424,7 @@ export const getPaymentConfig = (poolType) => {
  * @param {object} data - { poolType }
  * @returns {Promise} 返回微信支付参数
  */
-export const createOrder = (data) => {
+export var createOrder = function(data) {
   return request({
     url: '/v1/order/create',
     method: 'POST',
@@ -434,11 +440,11 @@ export const createOrder = (data) => {
  * @param {string} orderNo - 订单号
  * @returns {Promise} 返回订单信息
  */
-export const queryOrder = (orderNo) => {
+export var queryOrder = function(orderNo) {
   return request({
     url: '/v1/order/query',
     method: 'GET',
-    data: { orderNo }
+    data: { orderNo: orderNo }
   })
 }
 
@@ -446,7 +452,7 @@ export const queryOrder = (orderNo) => {
  * 获取用户订单列表
  * @returns {Promise} 返回订单列表
  */
-export const getUserOrders = () => {
+export var getUserOrders = function() {
   return request({
     url: '/v1/order/list',
     method: 'GET'
@@ -458,9 +464,9 @@ export const getUserOrders = () => {
  * @param {string} orderNo - 订单号
  * @returns {Promise} 返回微信支付参数
  */
-export const repayOrder = (orderNo) => {
+export var repayOrder = function(orderNo) {
   return request({
-    url: `/v1/order/repay?orderNo=${encodeURIComponent(orderNo)}`,
+    url: '/v1/order/repay?orderNo=' + encodeURIComponent(orderNo),
     method: 'POST'
   })
 }
@@ -470,11 +476,11 @@ export const repayOrder = (orderNo) => {
  * @param {number} poolType - 池类型:1-超短池,2-强势池
  * @returns {Promise} 返回 { hasSubscription: boolean, poolType: number }
  */
-export const checkSubscription = (poolType) => {
+export var checkSubscription = function(poolType) {
   return request({
     url: '/v1/order/check-subscription',
     method: 'GET',
-    data: { poolType }
+    data: { poolType: poolType }
   })
 }
 
@@ -483,16 +489,16 @@ export const checkSubscription = (poolType) => {
  * @param {object} payParams - 支付参数(从createOrder返回)
  * @returns {Promise}
  */
-export const wxPay = (payParams) => {
+export var wxPay = function(payParams) {
   // 兼容 total_fee 和 totalFee 两种命名
-  const totalFee = payParams.total_fee || payParams.totalFee
+  var totalFee = payParams.total_fee || payParams.totalFee
   console.log('调起支付,参数:', JSON.stringify(payParams), 'totalFee:', totalFee)
 
   if (!totalFee) {
     console.error('缺少 total_fee 参数,payParams:', payParams)
   }
 
-  return new Promise((resolve, reject) => {
+  return new Promise(function(resolve, reject) {
     // 优先判断小程序环境(避免在小程序中误用 WeixinJSBridge)
     if (typeof uni !== 'undefined' && uni.requestPayment) {
       // 小程序环境使用uni.requestPayment
@@ -504,12 +510,12 @@ export const wxPay = (payParams) => {
         package: payParams.packageValue,
         signType: payParams.signType,
         paySign: payParams.paySign,
-        success: (res) => {
+        success: function(res) {
           resolve(res)
         },
-        fail: (err) => {
+        fail: function(err) {
           console.log('支付失败:', err)
-          if (err.errMsg && err.errMsg.includes('cancel')) {
+          if (err.errMsg && err.errMsg.indexOf('cancel') !== -1) {
             reject(new Error('用户取消支付'))
           } else {
             reject(new Error('支付失败:' + (err.errMsg || JSON.stringify(err))))
@@ -526,7 +532,7 @@ export const wxPay = (payParams) => {
         package: payParams.packageValue,
         signType: payParams.signType,
         paySign: payParams.paySign
-      }, (res) => {
+      }, function(res) {
         if (res.err_msg === 'get_brand_wcpay_request:ok') {
           resolve(res)
         } else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
@@ -551,11 +557,11 @@ export const wxPay = (payParams) => {
  * @param {string} type - 协议类型:'user' 用户协议,'privacy' 隐私政策
  * @returns {Promise} 返回协议HTML内容
  */
-export const getAgreementContent = (type) => {
+export var getAgreementContent = function(type) {
   return request({
     url: '/v1/agreement/content',
     method: 'GET',
-    data: { type }
+    data: { type: type }
   })
 }
 
@@ -571,7 +577,7 @@ export const getAgreementContent = (type) => {
  * @param {number} params.pageSize - 每页数量
  * @returns {Promise} 返回历史数据列表和分页信息
  */
-export const getStockHistory = (params) => {
+export var getStockHistory = function(params) {
   return request({
     url: '/v1/stock/history/list',
     method: 'GET',
@@ -587,7 +593,7 @@ export const getStockHistory = (params) => {
  * @param {number} params.poolType - 池类型:1-超短池,2-强势池
  * @returns {Promise} 返回统计数据
  */
-export const getStockHistoryStats = (params) => {
+export var getStockHistoryStats = function(params) {
   return request({
     url: '/v1/stock/history/stats',
     method: 'GET',
@@ -601,8 +607,8 @@ export const getStockHistoryStats = (params) => {
  * @param {string} recordDate - 可选的记录日期 (yyyy-MM-dd)
  * @returns {Promise} 返回股票历史数据
  */
-export const searchStockHistory = (keyword, recordDate) => {
-  const data = { keyword }
+export var searchStockHistory = function(keyword, recordDate) {
+  var data = { keyword: keyword }
   if (recordDate) {
     data.recordDate = recordDate
   }
@@ -620,7 +626,7 @@ export const searchStockHistory = (keyword, recordDate) => {
  * @param {string} data.images - 图片URL列表,逗号分隔
  * @returns {Promise} 返回提交结果
  */
-export const submitFeedback = (data) => {
+export var submitFeedback = function(data) {
   console.log('[submitFeedback] 开始提交反馈,数据:', data)
   return request({
     url: '/v1/user/feedback/submit',
@@ -636,6 +642,6 @@ export const submitFeedback = (data) => {
  * 上传反馈图片
  * 注意:此函数返回上传配置,实际上传需使用 uni.uploadFile
  */
-export const uploadFeedbackImage = {
-  url: `${BASE_URL}/v1/file/upload`
+export var uploadFeedbackImage = {
+  url: BASE_URL + '/v1/file/upload'
 }

+ 58 - 40
src/utils/auth.js

@@ -21,19 +21,19 @@ import {
 } from './api.js'
 // #endif
 
-const TOKEN_KEY = 'user_token'
-const USER_INFO_KEY = 'user_info'
+var TOKEN_KEY = 'user_token'
+var USER_INFO_KEY = 'user_info'
 
 // 全局状态检查定时器
-let statusCheckTimer = null
-const STATUS_CHECK_INTERVAL = 10000 // 10秒检查一次
-let isShowingDisabledModal = false // 防止重复弹窗
+var statusCheckTimer = null
+var STATUS_CHECK_INTERVAL = 10000 // 10秒检查一次
+var isShowingDisabledModal = false // 防止重复弹窗
 
 /**
  * 保存用户token到本地存储
  * @param {string} token - 用户登录token
  */
-export const setToken = (token) => {
+export var setToken = function(token) {
   uni.setStorageSync(TOKEN_KEY, token)
 }
 
@@ -41,14 +41,14 @@ export const setToken = (token) => {
  * 获取本地存储的token
  * @returns {string|null} token或null
  */
-export const getToken = () => {
+export var getToken = function() {
   return uni.getStorageSync(TOKEN_KEY) || null
 }
 
 /**
  * 移除本地存储的token
  */
-export const removeToken = () => {
+export var removeToken = function() {
   uni.removeStorageSync(TOKEN_KEY)
 }
 
@@ -56,7 +56,7 @@ export const removeToken = () => {
  * 保存用户信息到本地存储
  * @param {object} userInfo - 用户信息对象
  */
-export const setUserInfo = (userInfo) => {
+export var setUserInfo = function(userInfo) {
   uni.setStorageSync(USER_INFO_KEY, JSON.stringify(userInfo))
 }
 
@@ -64,15 +64,33 @@ export const setUserInfo = (userInfo) => {
  * 获取本地存储的用户信息
  * @returns {object|null} 用户信息对象或null
  */
-export const getUserInfo = () => {
-  const userInfo = uni.getStorageSync(USER_INFO_KEY)
-  return userInfo ? JSON.parse(userInfo) : null
+export var getUserInfo = function() {
+  var userInfo = uni.getStorageSync(USER_INFO_KEY)
+  if (!userInfo) {
+    return null
+  }
+
+  if (typeof userInfo === 'object') {
+    return userInfo
+  }
+
+  if (typeof userInfo === 'string') {
+    try {
+      return JSON.parse(userInfo)
+    } catch (e) {
+      console.warn('[getUserInfo] JSON.parse失败,将清理损坏缓存')
+      uni.removeStorageSync(USER_INFO_KEY)
+      return null
+    }
+  }
+
+  return null
 }
 
 /**
  * 移除本地存储的用户信息
  */
-export const removeUserInfo = () => {
+export var removeUserInfo = function() {
   uni.removeStorageSync(USER_INFO_KEY)
 }
 
@@ -80,14 +98,14 @@ export const removeUserInfo = () => {
  * 检查用户是否已登录
  * @returns {boolean} 是否已登录
  */
-export const isLoggedIn = () => {
+export var isLoggedIn = function() {
   return !!getToken()
 }
 
 /**
  * 清除所有登录信息(退出登录)
  */
-export const logout = () => {
+export var logout = function() {
   stopStatusCheck() // 停止状态检查
   removeToken()
   removeUserInfo()
@@ -97,15 +115,15 @@ export const logout = () => {
  * 第一步:跳转到微信授权页面
  * H5公众号使用OAuth2.0网页授权
  */
-export const startH5Auth = async () => {
+export var startH5Auth = async function() {
   try {
     console.log('[H5授权] 开始获取授权URL')
 
     // 使用固定的HTTPS回调地址(不包含hash路由)
-    const redirectUrl = `https://${window.location.host}/`
+    var redirectUrl = 'https://' + window.location.host + '/'
     console.log('[H5授权] 回调地址:', redirectUrl)
 
-    const result = await getH5AuthUrl(redirectUrl)
+    var result = await getH5AuthUrl(redirectUrl)
 
     if (result.code === 200 && result.data) {
       console.log('[H5授权] 获取授权URL成功,准备跳转')
@@ -126,16 +144,16 @@ export const startH5Auth = async () => {
  * @param {string} code - 微信授权code
  * @returns {Promise<object>} 返回用户信息
  */
-export const handleH5AuthCallback = async (code) => {
+export var handleH5AuthCallback = async function(code) {
   try {
     console.log('[H5回调] 处理授权回调, code:', code)
 
-    const result = await h5AuthCallback(code)
+    var result = await h5AuthCallback(code)
 
     console.log('[H5回调] 后端响应:', result)
 
     if (result.code === 200 && result.data) {
-      const userInfo = result.data
+      var userInfo = result.data
 
       // 只返回微信用户信息,不自动登录
       console.log('[H5回调] 获取微信用户信息成功')
@@ -160,15 +178,15 @@ export const handleH5AuthCallback = async (code) => {
  * 如果用户被禁用(status=1),自动退出登录
  * @returns {Promise<object|null>} 最新的用户信息或null
  */
-export const refreshUserInfo = async () => {
+export var refreshUserInfo = async function() {
   if (!isLoggedIn()) {
     return null
   }
 
   try {
-    const result = await getUserInfoApi()
+    var result = await getUserInfoApi()
     if (result.code === 200 && result.data) {
-      const userInfo = {
+      var userInfo = {
         nickname: result.data.nickname || '',
         avatar: result.data.avatar || '',
         phone: result.data.phone || '',
@@ -195,7 +213,7 @@ export const refreshUserInfo = async () => {
 /**
  * 处理用户被禁用的情况
  */
-const handleUserDisabled = () => {
+var handleUserDisabled = function() {
   if (isShowingDisabledModal) {
     return // 防止重复弹窗
   }
@@ -209,7 +227,7 @@ const handleUserDisabled = () => {
     content: '您的账号已被禁用,如有疑问请联系客服',
     showCancel: false,
     confirmText: '我知道了',
-    success: () => {
+    success: function() {
       isShowingDisabledModal = false
       // 跳转到个人中心
       uni.switchTab({ url: '/pages/mine/mine' })
@@ -221,7 +239,7 @@ const handleUserDisabled = () => {
  * 启动全局用户状态定时检查
  * 每10秒检查一次用户状态,如果被禁用则自动退出
  */
-export const startStatusCheck = () => {
+export var startStatusCheck = function() {
   if (statusCheckTimer) {
     return // 已经在运行
   }
@@ -236,7 +254,7 @@ export const startStatusCheck = () => {
   checkUserStatus()
 
   // 定时检查
-  statusCheckTimer = setInterval(() => {
+  statusCheckTimer = setInterval(function() {
     checkUserStatus()
   }, STATUS_CHECK_INTERVAL)
 }
@@ -244,7 +262,7 @@ export const startStatusCheck = () => {
 /**
  * 停止全局用户状态定时检查
  */
-export const stopStatusCheck = () => {
+export var stopStatusCheck = function() {
   if (statusCheckTimer) {
     console.log('[状态检查] 停止定时检查')
     clearInterval(statusCheckTimer)
@@ -255,14 +273,14 @@ export const stopStatusCheck = () => {
 /**
  * 检查用户状态(内部方法)
  */
-const checkUserStatus = async () => {
+var checkUserStatus = async function() {
   if (!isLoggedIn()) {
     stopStatusCheck()
     return
   }
 
   try {
-    const result = await getUserInfoApi()
+    var result = await getUserInfoApi()
     if (result.code === 200 && result.data) {
       // 检查是否被禁用(status=1)
       if (result.data.status === 1) {
@@ -279,7 +297,7 @@ const checkUserStatus = async () => {
  * 检查登录状态,未登录则提示用户登录
  * @returns {boolean} 是否已登录
  */
-export const checkLogin = () => {
+export var checkLogin = function() {
   if (isLoggedIn()) {
     return true
   }
@@ -303,11 +321,11 @@ export const checkLogin = () => {
  * @param {string} loginCode - 微信登录code
  * @returns {Promise<object>} 返回 { isSign, token?, code? }
  */
-export const wxSilentLogin = async (loginCode) => {
+export var wxSilentLogin = async function(loginCode) {
   try {
     console.log('[静默登录] 开始检查用户状态, code:', loginCode)
 
-    const result = await wxSilentLoginApi({ loginCode })
+    var result = await wxSilentLoginApi({ loginCode: loginCode })
 
     console.log('[静默登录] 后端响应:', result)
 
@@ -337,11 +355,11 @@ export const wxSilentLogin = async (loginCode) => {
  * @param {object} params - 包含 loginCode, phoneCode, encryptedData, iv
  * @returns {Promise<object>} 返回 { isSign, token?, openid?, unionid?, phoneNumber? }
  */
-export const wxPhoneLogin = async (params) => {
+export var wxPhoneLogin = async function(params) {
   try {
     console.log('[手机号登录] 开始验证手机号')
 
-    const result = await wxPhoneLoginApi(params)
+    var result = await wxPhoneLoginApi(params)
 
     console.log('[手机号登录] 后端响应:', result)
 
@@ -371,11 +389,11 @@ export const wxPhoneLogin = async (params) => {
  * @param {object} userInfo - 包含 openid, unionid, phoneNumber, nickname, avatarUrl
  * @returns {Promise<boolean>} 注册是否成功
  */
-export const wxCompleteUserInfo = async (userInfo) => {
+export var wxCompleteUserInfo = async function(userInfo) {
   try {
     console.log('[完善信息] 提交用户信息')
 
-    const result = await wxCompleteUserInfoApi(userInfo)
+    var result = await wxCompleteUserInfoApi(userInfo)
 
     console.log('[完善信息] 后端响应:', result)
 
@@ -403,9 +421,9 @@ export const wxCompleteUserInfo = async (userInfo) => {
  * 获取并保存用户信息
  * 使用 token 调用后端接口获取完整用户信息
  */
-const fetchAndSaveUserInfo = async () => {
+var fetchAndSaveUserInfo = async function() {
   try {
-    const result = await getUserInfoApi()
+    var result = await getUserInfoApi()
     if (result.code === 200 && result.data) {
       setUserInfo(result.data)
       console.log('[用户信息] 保存成功')