Ver Fonte

登录功能修改

Zhangbw há 4 meses atrás
pai
commit
4861dca6e8
32 ficheiros alterados com 1464 adições e 351 exclusões
  1. 2 0
      dist/dev/mp-weixin/app.js
  2. 3 1
      dist/dev/mp-weixin/app.json
  3. 8 21
      dist/dev/mp-weixin/components/UserInfoPopup.js
  4. 50 2
      dist/dev/mp-weixin/pages/login/login.js
  5. 1 1
      dist/dev/mp-weixin/pages/login/login.wxml
  6. 1 1
      dist/dev/mp-weixin/pages/login/login.wxss
  7. 8 13
      dist/dev/mp-weixin/pages/mine/mine.js
  8. 1 1
      dist/dev/mp-weixin/pages/mine/mine.wxml
  9. 36 27
      dist/dev/mp-weixin/pages/mine/mine.wxss
  10. 140 0
      dist/dev/mp-weixin/pages/points/points.js
  11. 5 0
      dist/dev/mp-weixin/pages/points/points.json
  12. 1 0
      dist/dev/mp-weixin/pages/points/points.wxml
  13. 168 0
      dist/dev/mp-weixin/pages/points/points.wxss
  14. 0 0
      dist/dev/mp-weixin/pages/pool/pool.wxml
  15. 3 0
      dist/dev/mp-weixin/pages/rank/rank.js
  16. 1 1
      dist/dev/mp-weixin/pages/rank/rank.wxml
  17. 0 0
      dist/dev/mp-weixin/pages/strong/strong.wxml
  18. 105 0
      dist/dev/mp-weixin/pages/transaction/transaction.js
  19. 5 0
      dist/dev/mp-weixin/pages/transaction/transaction.json
  20. 1 0
      dist/dev/mp-weixin/pages/transaction/transaction.wxml
  21. 172 0
      dist/dev/mp-weixin/pages/transaction/transaction.wxss
  22. 1 1
      dist/dev/mp-weixin/utils/api.js
  23. 9 26
      src/components/UserInfoPopup.vue
  24. 14 0
      src/pages.json
  25. 60 7
      src/pages/login/login.vue
  26. 59 53
      src/pages/mine/mine.vue
  27. 393 0
      src/pages/points/points.vue
  28. 0 1
      src/pages/pool/pool.vue
  29. 7 2
      src/pages/rank/rank.vue
  30. 1 2
      src/pages/strong/strong.vue
  31. 207 190
      src/pages/transaction/transaction.vue
  32. 2 1
      src/utils/api.js

+ 2 - 0
dist/dev/mp-weixin/app.js

@@ -9,6 +9,8 @@ if (!Math) {
   "./pages/rank/rank.js";
   "./pages/mine/mine.js";
   "./pages/profile/edit.js";
+  "./pages/transaction/transaction.js";
+  "./pages/points/points.js";
 }
 const _sfc_main = {
   globalData: {

+ 3 - 1
dist/dev/mp-weixin/app.json

@@ -6,7 +6,9 @@
     "pages/strong/strong",
     "pages/rank/rank",
     "pages/mine/mine",
-    "pages/profile/edit"
+    "pages/profile/edit",
+    "pages/transaction/transaction",
+    "pages/points/points"
   ],
   "window": {
     "navigationBarBackgroundColor": "#ffffff",

+ 8 - 21
dist/dev/mp-weixin/components/UserInfoPopup.js

@@ -76,26 +76,13 @@ const _sfc_main = {
         });
         return;
       }
-      try {
-        common_vendor.index.showLoading({ title: "上传中..." });
-        let uploadedAvatarUrl = this.avatarUrl;
-        if (this.tempAvatarPath) {
-          uploadedAvatarUrl = await this.uploadAvatar(this.tempAvatarPath);
-        }
-        common_vendor.index.hideLoading();
-        this.$emit("confirm", {
-          nickname: this.nickname.trim(),
-          avatarUrl: uploadedAvatarUrl
-        });
-        this.close();
-      } catch (error) {
-        common_vendor.index.hideLoading();
-        console.error("[用户信息] 上传头像失败:", error);
-        common_vendor.index.showToast({
-          title: "头像上传失败,请重试",
-          icon: "none"
-        });
-      }
+      this.$emit("confirm", {
+        nickname: this.nickname.trim(),
+        avatarUrl: this.tempAvatarPath || this.avatarUrl,
+        tempAvatarPath: this.tempAvatarPath
+        // 传递临时路径,供后续上传
+      });
+      this.close();
     },
     /**
      * 上传头像到OSS
@@ -130,7 +117,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
   return common_vendor.e({
     a: $data.visible
   }, $data.visible ? {
-    b: $data.avatarUrl || "/static/images/default-avatar.png",
+    b: $data.avatarUrl || "/static/images/head.png",
     c: common_vendor.o((...args) => $options.handleChooseAvatar && $options.handleChooseAvatar(...args)),
     d: $data.nickname,
     e: common_vendor.o(($event) => $data.nickname = $event.detail.value),

+ 50 - 2
dist/dev/mp-weixin/pages/login/login.js

@@ -1,7 +1,7 @@
 "use strict";
 const common_vendor = require("../../common/vendor.js");
 const utils_auth = require("../../utils/auth.js");
-require("../../utils/api.js");
+const utils_api = require("../../utils/api.js");
 const UserInfoPopup = () => "../../components/UserInfoPopup.js";
 const _sfc_main = {
   components: {
@@ -161,9 +161,31 @@ const _sfc_main = {
           phoneNumber: this.tempUserData.phoneNumber,
           nickname: userInfo.nickname,
           avatarUrl: userInfo.avatarUrl
+          // 微信临时URL,先存着
         };
-        console.log("[登录] 提交完整用户信息");
+        console.log("[登录] 提交用户信息");
         await utils_auth.wxCompleteUserInfo(completeInfo);
+        if (userInfo.tempAvatarPath) {
+          console.log("[登录] 开始上传头像到服务器, tempAvatarPath:", userInfo.tempAvatarPath);
+          try {
+            const uploadedUrl = await this.uploadAvatarWithToken(userInfo.tempAvatarPath);
+            console.log("[登录] 头像上传成功, uploadedUrl:", uploadedUrl);
+            if (uploadedUrl) {
+              console.log("[登录] 调用updateUserProfile更新头像");
+              const updateResult = await utils_api.updateUserProfile({ avatar: uploadedUrl });
+              console.log("[登录] updateUserProfile返回:", updateResult);
+              const userInfoLocal = common_vendor.index.getStorageSync("user_info");
+              if (userInfoLocal) {
+                const parsed = JSON.parse(userInfoLocal);
+                parsed.avatar = uploadedUrl;
+                common_vendor.index.setStorageSync("user_info", JSON.stringify(parsed));
+              }
+              console.log("[登录] 头像上传成功:", uploadedUrl);
+            }
+          } catch (uploadErr) {
+            console.warn("[登录] 头像上传失败:", uploadErr);
+          }
+        }
         common_vendor.index.hideLoading();
         console.log("[登录] 注册成功");
         this.handleLoginSuccess();
@@ -177,6 +199,32 @@ const _sfc_main = {
         });
       }
     },
+    /**
+     * 带token上传头像
+     */
+    uploadAvatarWithToken(filePath) {
+      return new Promise((resolve, reject) => {
+        common_vendor.index.uploadFile({
+          url: utils_api.uploadFile.url,
+          filePath,
+          name: "file",
+          header: {
+            "Authorization": `Bearer ${common_vendor.index.getStorageSync("user_token") || ""}`
+          },
+          success: (res) => {
+            const data = JSON.parse(res.data);
+            if (data.code === 200 && data.data && data.data.url) {
+              resolve(data.data.url);
+            } else {
+              reject(new Error(data.message || "上传失败"));
+            }
+          },
+          fail: (err) => {
+            reject(err);
+          }
+        });
+      });
+    },
     /**
      * 登录成功后的处理
      */

+ 1 - 1
dist/dev/mp-weixin/pages/login/login.wxml

@@ -1 +1 @@
-<view class="login-container data-v-cdfe2409"><view class="back-button data-v-cdfe2409" bindtap="{{a}}"><text class="back-icon data-v-cdfe2409">←</text><text class="back-text data-v-cdfe2409">返回</text></view><view class="bg-decoration data-v-cdfe2409"><view class="circle circle-1 data-v-cdfe2409"></view><view class="circle circle-2 data-v-cdfe2409"></view></view><view class="header data-v-cdfe2409"><image class="logo data-v-cdfe2409" src="/static/images/logo.png" mode="aspectFit"></image><text class="title data-v-cdfe2409">量化选股大师</text><text class="subtitle data-v-cdfe2409">专业的股票量化分析工具</text></view><view class="login-actions data-v-cdfe2409"><button wx:if="{{b}}" class="login-btn primary-btn data-v-cdfe2409" bindtap="{{c}}"><text class="btn-icon data-v-cdfe2409">📱</text><text class="btn-text data-v-cdfe2409">微信一键登录</text></button><button wx:else class="login-btn primary-btn data-v-cdfe2409" open-type="getPhoneNumber" bindgetphonenumber="{{d}}"><text class="btn-icon data-v-cdfe2409">🔐</text><text class="btn-text data-v-cdfe2409">授权手机号登录</text></button><view class="agreement data-v-cdfe2409"><checkbox-group class="data-v-cdfe2409" bindchange="{{h}}"><label class="agreement-label data-v-cdfe2409"><checkbox class="data-v-cdfe2409" checked="{{e}}" color="#5d55e8"/><text class="agreement-text data-v-cdfe2409"> 我已阅读并同意 <text class="link data-v-cdfe2409" catchtap="{{f}}">《用户协议》</text> 和 <text class="link data-v-cdfe2409" catchtap="{{g}}">《隐私政策》</text></text></label></checkbox-group></view></view><user-info-popup class="r data-v-cdfe2409" u-r="userInfoPopup" bindconfirm="{{j}}" u-i="cdfe2409-0" bind:__l="__l"/></view>
+<view class="login-container data-v-cdfe2409"><view class="back-button data-v-cdfe2409" bindtap="{{a}}"><text class="back-icon data-v-cdfe2409">←</text><text class="back-text data-v-cdfe2409">返回</text></view><view class="bg-decoration data-v-cdfe2409"><view class="circle circle-1 data-v-cdfe2409"></view><view class="circle circle-2 data-v-cdfe2409"></view></view><view class="header data-v-cdfe2409"><image class="logo data-v-cdfe2409" src="/static/images/logo.png" mode="aspectFit"></image><text class="title data-v-cdfe2409">量化选股大师</text><text class="subtitle data-v-cdfe2409">专业的股票量化分析工具</text></view><view class="login-actions data-v-cdfe2409"><button wx:if="{{b}}" class="login-btn primary-btn data-v-cdfe2409" bindtap="{{c}}"><text class="btn-text data-v-cdfe2409">微信一键登录</text></button><button wx:else class="login-btn primary-btn data-v-cdfe2409" open-type="getPhoneNumber" bindgetphonenumber="{{d}}"><text class="btn-icon data-v-cdfe2409">🔐</text><text class="btn-text data-v-cdfe2409">授权手机号登录</text></button><view class="agreement data-v-cdfe2409"><checkbox-group class="data-v-cdfe2409" bindchange="{{h}}"><label class="agreement-label data-v-cdfe2409"><checkbox class="data-v-cdfe2409" checked="{{e}}" color="#5d55e8"/><text class="agreement-text data-v-cdfe2409"> 我已阅读并同意 <text class="link data-v-cdfe2409" catchtap="{{f}}">《用户协议》</text> 和 <text class="link data-v-cdfe2409" catchtap="{{g}}">《隐私政策》</text></text></label></checkbox-group></view></view><user-info-popup class="r data-v-cdfe2409" u-r="userInfoPopup" bindconfirm="{{j}}" u-i="cdfe2409-0" bind:__l="__l"/></view>

+ 1 - 1
dist/dev/mp-weixin/pages/login/login.wxss

@@ -2,7 +2,7 @@
 /* 返回按钮 */
 .back-button.data-v-cdfe2409 {
   position: absolute;
-  top: 40rpx;
+  top: 80rpx;
   left: 30rpx;
   z-index: 10;
   display: flex;

+ 8 - 13
dist/dev/mp-weixin/pages/mine/mine.js

@@ -55,12 +55,6 @@ const _sfc_main = {
         }
       });
     };
-    const handleViewPoints = () => {
-      if (!utils_auth.checkLogin()) {
-        return;
-      }
-      common_vendor.index.showToast({ title: `当前积分: ${points.value}`, icon: "none" });
-    };
     const handleRecharge = () => {
       if (!utils_auth.checkLogin()) {
         return;
@@ -71,7 +65,9 @@ const _sfc_main = {
       if (!utils_auth.checkLogin()) {
         return;
       }
-      common_vendor.index.showToast({ title: "积分记录功能开发中", icon: "none" });
+      common_vendor.index.navigateTo({
+        url: "/pages/points/points"
+      });
     };
     const handleTransactionRecord = () => {
       if (!utils_auth.checkLogin()) {
@@ -87,13 +83,12 @@ const _sfc_main = {
         b: common_vendor.t(isLoggedIn.value ? userInfo.value.nickname || "微信用户" : "登录/注册"),
         c: common_vendor.o(handleUserCardClick),
         d: common_vendor.t(isLoggedIn.value ? points.value : 0),
-        e: common_vendor.o(handleViewPoints),
-        f: common_vendor.o(handleRecharge),
-        g: common_vendor.o(handleHistory),
-        h: common_vendor.o(handleTransactionRecord),
-        i: isLoggedIn.value
+        e: common_vendor.o(handleRecharge),
+        f: common_vendor.o(handleHistory),
+        g: common_vendor.o(handleTransactionRecord),
+        h: isLoggedIn.value
       }, isLoggedIn.value ? {
-        j: common_vendor.o(handleLogout)
+        i: common_vendor.o(handleLogout)
       } : {});
     };
   }

+ 1 - 1
dist/dev/mp-weixin/pages/mine/mine.wxml

@@ -1 +1 @@
-<view class="page-mine"><view class="page-title-card"><text class="page-title-text">量化选股大师</text></view><scroll-view class="scroll-view" scroll-y><view class="content-wrapper"><view class="user-info-card" bindtap="{{c}}"><view class="user-header"><image class="user-avatar" src="{{a}}" mode="aspectFill"></image><view class="user-details"><text class="user-name">{{b}}</text></view><view class="arrow-icon">›</view></view></view><view class="my-tasks-section"><view class="tasks-grid"><view class="task-item" bindtap="{{e}}"><view class="task-icon-wrapper points"><text class="task-icon">💰</text></view><view class="task-info"><text class="task-label">积分</text><text class="task-value">{{d}}</text></view></view><view class="task-item" bindtap="{{f}}"><view class="task-icon-wrapper recharge"><text class="task-icon">💳</text></view><view class="task-info"><text class="task-label">充值</text></view></view><view class="task-item" bindtap="{{g}}"><view class="task-icon-wrapper history"><text class="task-icon">📋</text></view><view class="task-info"><text class="task-label">积分记录</text></view></view></view></view><view class="menu-list"><view class="menu-item" bindtap="{{h}}"><view class="menu-left"><text class="menu-icon">📝</text><text class="menu-label">交易记录</text></view><text class="menu-arrow">›</text></view></view><view wx:if="{{i}}" class="logout-section"><button class="logout-btn" bindtap="{{j}}"> 退出登录 </button></view><view class="bottom-safe-area"></view></view></scroll-view></view>
+<view class="page-mine"><view class="page-title-card"><text class="page-title-text">量化选股大师</text></view><scroll-view class="scroll-view" scroll-y><view class="content-wrapper"><view class="user-info-card" bindtap="{{c}}"><view class="user-header"><image class="user-avatar" src="{{a}}" mode="aspectFill"></image><view class="user-details"><text class="user-name">{{b}}</text></view><view class="arrow-icon">›</view></view></view><view class="my-tasks-section"><view class="points-row"><view class="points-display"><view class="points-icon-wrapper"><text class="points-icon">💰</text></view><view class="points-info"><text class="points-label">我的积分</text><text class="points-value">{{d}}</text></view></view><button class="recharge-button" bindtap="{{e}}"><text class="recharge-text">充值</text></button></view></view><view class="menu-list"><view class="menu-item" bindtap="{{f}}"><view class="menu-left"><text class="menu-icon">📋</text><text class="menu-label">积分记录</text></view><text class="menu-arrow">›</text></view><view class="menu-item" bindtap="{{g}}"><view class="menu-left"><text class="menu-icon">📝</text><text class="menu-label">交易记录</text></view><text class="menu-arrow">›</text></view></view><view wx:if="{{h}}" class="logout-section"><button class="logout-btn" bindtap="{{i}}"> 退出登录 </button></view><view class="bottom-safe-area"></view></view></scroll-view></view>

+ 36 - 27
dist/dev/mp-weixin/pages/mine/mine.wxss

@@ -73,56 +73,65 @@
   margin-bottom: 32rpx;
   box-shadow: 0 16rpx 40rpx rgba(37, 52, 94, 0.08);
 }
-.tasks-grid {
+.points-row {
   display: flex;
-  flex-direction: column;
-  gap: 24rpx;
+  align-items: center;
+  justify-content: space-between;
 }
-.task-item {
+.points-display {
+  flex: 1;
   display: flex;
   align-items: center;
-  padding: 24rpx;
-  background: #f7f8fc;
-  border-radius: 16rpx;
 }
-.task-icon-wrapper {
+.points-icon-wrapper {
   width: 80rpx;
   height: 80rpx;
   border-radius: 50%;
+  background: linear-gradient(135deg, #00BFA5, #00D4B5);
   display: flex;
   align-items: center;
   justify-content: center;
   margin-right: 24rpx;
   flex-shrink: 0;
-  box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.1);
+  box-shadow: 0 8rpx 20rpx rgba(0, 191, 165, 0.3);
 }
-.task-icon-wrapper.points {
-  background: linear-gradient(135deg, #00BFA5, #00D4B5);
+.points-icon {
+  font-size: 40rpx;
 }
-.task-icon-wrapper.recharge {
-  background: linear-gradient(135deg, #5d55e8, #7568ff);
+.points-info {
+  display: flex;
+  flex-direction: column;
 }
-.task-icon-wrapper.history {
-  background: linear-gradient(135deg, #FF9800, #FFA726);
+.points-label {
+  font-size: 26rpx;
+  color: #666a7f;
+  margin-bottom: 8rpx;
 }
-.task-icon {
+.points-value {
   font-size: 40rpx;
+  font-weight: 700;
+  color: #00BFA5;
 }
-.task-info {
-  flex: 1;
+.recharge-button {
+  width: 160rpx;
+  height: 72rpx;
+  background: linear-gradient(135deg, #5d55e8, #7568ff);
+  border-radius: 36rpx;
   display: flex;
   align-items: center;
-  justify-content: space-between;
+  justify-content: center;
+  box-shadow: 0 8rpx 20rpx rgba(93, 85, 232, 0.3);
+  border: none;
+  padding: 0;
+  line-height: 1;
 }
-.task-label {
-  font-size: 28rpx;
-  color: #222222;
-  font-weight: 500;
+.recharge-button::after {
+  border: none;
 }
-.task-value {
-  font-size: 32rpx;
-  font-weight: 700;
-  color: #00BFA5;
+.recharge-text {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #ffffff;
 }
 
 /* 菜单列表 */

+ 140 - 0
dist/dev/mp-weixin/pages/points/points.js

@@ -0,0 +1,140 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {
+  __name: "points",
+  setup(__props) {
+    const records = common_vendor.ref([]);
+    const handleBack = () => {
+      const pages = getCurrentPages();
+      if (pages.length > 1) {
+        common_vendor.index.navigateBack();
+      } else {
+        common_vendor.index.switchTab({
+          url: "/pages/mine/mine"
+        });
+      }
+    };
+    const groupedRecords = common_vendor.computed(() => {
+      const groups = {};
+      records.value.forEach((item) => {
+        const dateKey = formatDate(item.timestamp);
+        if (!groups[dateKey]) {
+          groups[dateKey] = [];
+        }
+        groups[dateKey].push(item);
+      });
+      return groups;
+    });
+    const formatDate = (timestamp) => {
+      const date = new Date(timestamp);
+      const today = /* @__PURE__ */ new Date();
+      const yesterday = new Date(today);
+      yesterday.setDate(yesterday.getDate() - 1);
+      const dateStr = date.toLocaleDateString("zh-CN", {
+        year: "numeric",
+        month: "2-digit",
+        day: "2-digit"
+      });
+      const todayStr = today.toLocaleDateString("zh-CN", {
+        year: "numeric",
+        month: "2-digit",
+        day: "2-digit"
+      });
+      const yesterdayStr = yesterday.toLocaleDateString("zh-CN", {
+        year: "numeric",
+        month: "2-digit",
+        day: "2-digit"
+      });
+      if (dateStr === todayStr) {
+        return "今天";
+      } else if (dateStr === yesterdayStr) {
+        return "昨天";
+      } else {
+        return dateStr;
+      }
+    };
+    const formatTime = (timestamp) => {
+      const date = new Date(timestamp);
+      const hours = String(date.getHours()).padStart(2, "0");
+      const minutes = String(date.getMinutes()).padStart(2, "0");
+      return `${hours}:${minutes}`;
+    };
+    const loadRecords = () => {
+      try {
+        const storedRecords = common_vendor.index.getStorageSync("points_records") || [];
+        records.value = storedRecords.sort((a, b) => b.timestamp - a.timestamp);
+      } catch (e) {
+        console.error("加载积分记录失败:", e);
+        records.value = [];
+      }
+    };
+    const initMockData = () => {
+      const mockRecords = [
+        {
+          title: "每日签到",
+          points: 10,
+          type: "add",
+          timestamp: Date.now() - 1e3 * 60 * 30
+        },
+        {
+          title: "完成交易",
+          points: 5,
+          type: "add",
+          timestamp: Date.now() - 1e3 * 60 * 60 * 2
+        },
+        {
+          title: "查询股票",
+          points: 2,
+          type: "use",
+          timestamp: Date.now() - 1e3 * 60 * 60 * 5
+        },
+        {
+          title: "邀请好友",
+          points: 20,
+          type: "add",
+          timestamp: Date.now() - 1e3 * 60 * 60 * 24
+        },
+        {
+          title: "解锁超短池",
+          points: 18,
+          type: "use",
+          timestamp: Date.now() - 1e3 * 60 * 60 * 24 * 2
+        }
+      ];
+      if (records.value.length === 0) {
+        records.value = mockRecords;
+        common_vendor.index.setStorageSync("points_records", mockRecords);
+      }
+    };
+    common_vendor.onMounted(() => {
+      loadRecords();
+      initMockData();
+    });
+    return (_ctx, _cache) => {
+      return common_vendor.e({
+        a: common_vendor.o(handleBack),
+        b: common_vendor.f(common_vendor.unref(groupedRecords), (group, dateKey, i0) => {
+          return {
+            a: common_vendor.t(dateKey),
+            b: common_vendor.f(group, (item, index, i1) => {
+              return {
+                a: common_vendor.t(item.title),
+                b: common_vendor.t(formatTime(item.timestamp)),
+                c: common_vendor.t(item.type === "add" ? "+" : "-"),
+                d: common_vendor.t(item.points),
+                e: common_vendor.n(item.type === "add" ? "amount-sell" : "amount-buy"),
+                f: common_vendor.t(item.type === "add" ? "获得" : "消耗"),
+                g: common_vendor.n(item.type === "add" ? "status-sell" : "status-buy"),
+                h: index
+              };
+            }),
+            c: dateKey
+          };
+        }),
+        c: records.value.length === 0
+      }, records.value.length === 0 ? {} : {});
+    };
+  }
+};
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-9b5c2d6e"], ["__file", "D:/program/gupiao-wx/src/pages/points/points.vue"]]);
+wx.createPage(MiniProgramPage);

+ 5 - 0
dist/dev/mp-weixin/pages/points/points.json

@@ -0,0 +1,5 @@
+{
+  "navigationBarTitleText": "积分记录",
+  "navigationStyle": "custom",
+  "usingComponents": {}
+}

+ 1 - 0
dist/dev/mp-weixin/pages/points/points.wxml

@@ -0,0 +1 @@
+<view class="page-container data-v-9b5c2d6e"><view class="custom-navbar data-v-9b5c2d6e"><view class="navbar-back data-v-9b5c2d6e" bindtap="{{a}}"><text class="back-icon data-v-9b5c2d6e">←</text></view><view class="navbar-title data-v-9b5c2d6e"><text class="title-text data-v-9b5c2d6e">积分记录</text></view><view class="navbar-placeholder data-v-9b5c2d6e"></view></view><scroll-view class="scroll-view data-v-9b5c2d6e" scroll-y><view class="transaction-list data-v-9b5c2d6e"><view wx:for="{{b}}" wx:for-item="group" wx:key="c" class="date-group data-v-9b5c2d6e"><view class="date-header data-v-9b5c2d6e"><text class="date-text data-v-9b5c2d6e">{{group.a}}</text></view><view wx:for="{{group.b}}" wx:for-item="item" wx:key="h" class="transaction-item data-v-9b5c2d6e"><view class="item-left data-v-9b5c2d6e"><view class="stock-info data-v-9b5c2d6e"><text class="stock-name data-v-9b5c2d6e">{{item.a}}</text></view><text class="transaction-time data-v-9b5c2d6e">{{item.b}}</text></view><view class="item-right data-v-9b5c2d6e"><text class="{{['data-v-9b5c2d6e', 'amount-text', item.e]}}">{{item.c}}{{item.d}}积分 </text><view class="{{['data-v-9b5c2d6e', 'status-badge', item.g]}}"><text class="status-text data-v-9b5c2d6e">{{item.f}}</text></view></view></view></view><view wx:if="{{c}}" class="empty-state data-v-9b5c2d6e"><text class="empty-icon data-v-9b5c2d6e">💰</text><text class="empty-text data-v-9b5c2d6e">暂无积分记录</text><text class="empty-desc data-v-9b5c2d6e">完成任务即可获得积分</text></view><view class="bottom-safe-area data-v-9b5c2d6e"></view></view></scroll-view></view>

+ 168 - 0
dist/dev/mp-weixin/pages/points/points.wxss

@@ -0,0 +1,168 @@
+
+.page-container.data-v-9b5c2d6e {
+  min-height: 100vh;
+  background: #f5f6fb;
+  display: flex;
+  flex-direction: column;
+}
+
+/* 自定义导航栏 */
+.custom-navbar.data-v-9b5c2d6e {
+  background: #ffffff;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 80rpx 32rpx 30rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+  position: relative;
+}
+.navbar-back.data-v-9b5c2d6e {
+  width: 80rpx;
+  height: 60rpx;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+}
+.back-icon.data-v-9b5c2d6e {
+  font-size: 40rpx;
+  color: #222222;
+  font-weight: bold;
+}
+.navbar-title.data-v-9b5c2d6e {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+}
+.title-text.data-v-9b5c2d6e {
+  font-size: 36rpx;
+  font-weight: 800;
+  color: #3F51F7;
+  letter-spacing: 2rpx;
+}
+.navbar-placeholder.data-v-9b5c2d6e {
+  width: 80rpx;
+}
+
+/* 交易记录列表 */
+.scroll-view.data-v-9b5c2d6e {
+  flex: 1;
+  height: 0;
+}
+.transaction-list.data-v-9b5c2d6e {
+  padding: 0 0 32rpx;
+}
+
+/* 日期分组 */
+.date-group.data-v-9b5c2d6e {
+  margin-bottom: 32rpx;
+}
+.date-header.data-v-9b5c2d6e {
+  padding: 24rpx 32rpx 16rpx;
+}
+.date-text.data-v-9b5c2d6e {
+  font-size: 26rpx;
+  color: #9ca2b5;
+  font-weight: 500;
+}
+
+/* 交易项 */
+.transaction-item.data-v-9b5c2d6e {
+  background: #ffffff;
+  padding: 32rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1rpx solid #f5f6fb;
+}
+.transaction-item.data-v-9b5c2d6e:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.transaction-item.data-v-9b5c2d6e:last-child {
+  border-bottom: none;
+}
+.item-left.data-v-9b5c2d6e {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+.stock-info.data-v-9b5c2d6e {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8rpx;
+}
+.stock-name.data-v-9b5c2d6e {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #222222;
+  margin-right: 12rpx;
+}
+.transaction-time.data-v-9b5c2d6e {
+  font-size: 24rpx;
+  color: #9ca2b5;
+}
+.item-right.data-v-9b5c2d6e {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+}
+.amount-text.data-v-9b5c2d6e {
+  font-size: 32rpx;
+  font-weight: 700;
+  margin-bottom: 8rpx;
+}
+.amount-buy.data-v-9b5c2d6e {
+  color: #3abf81;
+}
+.amount-sell.data-v-9b5c2d6e {
+  color: #f16565;
+}
+.status-badge.data-v-9b5c2d6e {
+  padding: 4rpx 16rpx;
+  border-radius: 12rpx;
+}
+.status-buy.data-v-9b5c2d6e {
+  background: #e7f7ef;
+}
+.status-sell.data-v-9b5c2d6e {
+  background: #ffe7ee;
+}
+.status-text.data-v-9b5c2d6e {
+  font-size: 22rpx;
+  font-weight: 500;
+}
+.status-buy .status-text.data-v-9b5c2d6e {
+  color: #3abf81;
+}
+.status-sell .status-text.data-v-9b5c2d6e {
+  color: #f16565;
+}
+
+/* 空状态 */
+.empty-state.data-v-9b5c2d6e {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 120rpx 0;
+  background: #ffffff;
+  margin: 0 32rpx;
+  border-radius: 24rpx;
+}
+.empty-icon.data-v-9b5c2d6e {
+  font-size: 120rpx;
+  margin-bottom: 32rpx;
+  opacity: 0.5;
+}
+.empty-text.data-v-9b5c2d6e {
+  font-size: 32rpx;
+  color: #666666;
+  margin-bottom: 16rpx;
+  font-weight: 500;
+}
+.empty-desc.data-v-9b5c2d6e {
+  font-size: 26rpx;
+  color: #9ca2b5;
+}
+.bottom-safe-area.data-v-9b5c2d6e {
+  height: 40rpx;
+}

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
dist/dev/mp-weixin/pages/pool/pool.wxml


+ 3 - 0
dist/dev/mp-weixin/pages/rank/rank.js

@@ -77,6 +77,9 @@ const _sfc_main = {
     common_vendor.onMounted(() => {
       checkLoginAndLoadData();
     });
+    common_vendor.onShow(() => {
+      checkLoginAndLoadData();
+    });
     return (_ctx, _cache) => {
       return common_vendor.e({
         a: common_vendor.t(formatAmount(portfolio.value.balance)),

+ 1 - 1
dist/dev/mp-weixin/pages/rank/rank.wxml

@@ -1 +1 @@
-<view class="page-rank"><view class="page-title-card"><text class="page-title-text">量化选股大师</text></view><scroll-view class="scroll-view" scroll-y><view class="{{['content-wrapper', j && 'blur-content']}}"><view class="portfolio-card"><view class="portfolio-header"><view class="portfolio-icon">💼</view><text class="portfolio-title">我的模拟资产</text></view><view class="portfolio-content"><view class="portfolio-main"><view class="portfolio-label">当前账户余额 (¥)</view><view class="portfolio-amount">{{a}}</view></view><view class="portfolio-profit"><view class="profit-label">总盈亏 / 收益率</view><view class="{{['profit-value', d]}}"> ¥ {{b}} ({{c}}%) </view></view></view></view><view class="leaderboard-section"><view class="section-header"><view class="trophy-icon">🏆</view><text class="section-title">模拟交易排行榜</text></view><view class="my-rank-card"><view class="rank-number">#{{e}}</view><view class="rank-info"><text class="rank-name">您 (本期收益)</text></view><view class="{{['rank-rate', h]}}">{{f}}{{g}}% </view></view><view class="leaderboard-list"><view wx:for="{{i}}" wx:for-item="item" wx:key="g" class="leaderboard-item"><view class="{{['rank-badge', item.b]}}"> #{{item.a}}</view><view class="user-info"><text class="user-name">{{item.c}}</text></view><view class="{{['user-rate', item.f]}}">{{item.d}}{{item.e}}% </view></view></view><view class="leaderboard-note"><text class="note-text">排名每日更新,收益基于系统信号的模拟交易。</text></view></view><view class="bottom-safe-area"></view></view></scroll-view><view wx:if="{{k}}" class="login-mask"><view class="login-prompt"><view class="lock-icon">🔒</view><text class="prompt-title">登录后查看完整数据</text><text class="prompt-desc">使用微信授权快速登录</text><button class="login-button-native" bindtap="{{l}}"><text class="button-icon">📱</text><text>微信授权登录</text></button></view></view></view>
+<view class="page-rank"><view class="page-title-card"><text class="page-title-text">量化选股大师</text></view><scroll-view class="scroll-view" scroll-y><view class="{{['content-wrapper', j && 'blur-content']}}"><view class="portfolio-card"><view class="portfolio-header"><view class="portfolio-icon">💼</view><text class="portfolio-title">我的模拟资产</text></view><view class="portfolio-content"><view class="portfolio-main"><view class="portfolio-label">当前账户余额 (¥)</view><view class="portfolio-amount">{{a}}</view></view><view class="portfolio-profit"><view class="profit-label">总盈亏 / 收益率</view><view class="{{['profit-value', d]}}"> ¥ {{b}} ({{c}}%) </view></view></view></view><view class="leaderboard-section"><view class="section-header"><view class="trophy-icon">🏆</view><text class="section-title">模拟交易排行榜</text></view><view class="my-rank-card"><view class="rank-number">#{{e}}</view><view class="rank-info"><text class="rank-name">您 (本期收益)</text></view><view class="{{['rank-rate', h]}}">{{f}}{{g}}% </view></view><view class="leaderboard-list"><view wx:for="{{i}}" wx:for-item="item" wx:key="g" class="leaderboard-item"><view class="{{['rank-badge', item.b]}}"> #{{item.a}}</view><view class="user-info"><text class="user-name">{{item.c}}</text></view><view class="{{['user-rate', item.f]}}">{{item.d}}{{item.e}}% </view></view></view><view class="leaderboard-note"><text class="note-text">排名每日更新,收益基于系统信号的模拟交易。</text></view></view><view class="bottom-safe-area"></view></view></scroll-view><view wx:if="{{k}}" class="login-mask"><view class="login-prompt"><view class="lock-icon">🔒</view><text class="prompt-title">登录后查看完整数据</text><text class="prompt-desc">使用微信授权快速登录</text><button class="login-button-native" bindtap="{{l}}"><text>登录</text></button></view></view></view>

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
dist/dev/mp-weixin/pages/strong/strong.wxml


+ 105 - 0
dist/dev/mp-weixin/pages/transaction/transaction.js

@@ -0,0 +1,105 @@
+"use strict";
+const common_vendor = require("../../common/vendor.js");
+const _sfc_main = {
+  __name: "transaction",
+  setup(__props) {
+    const transactions = common_vendor.ref([]);
+    const handleBack = () => {
+      const pages = getCurrentPages();
+      if (pages.length > 1) {
+        common_vendor.index.navigateBack();
+      } else {
+        common_vendor.index.switchTab({
+          url: "/pages/mine/mine"
+        });
+      }
+    };
+    const groupedTransactions = common_vendor.computed(() => {
+      const groups = {};
+      transactions.value.forEach((item) => {
+        const dateKey = formatDate(item.timestamp);
+        if (!groups[dateKey]) {
+          groups[dateKey] = [];
+        }
+        groups[dateKey].push(item);
+      });
+      return groups;
+    });
+    const formatDate = (timestamp) => {
+      const date = new Date(timestamp);
+      const today = /* @__PURE__ */ new Date();
+      const yesterday = new Date(today);
+      yesterday.setDate(yesterday.getDate() - 1);
+      const dateStr = date.toLocaleDateString("zh-CN", {
+        year: "numeric",
+        month: "2-digit",
+        day: "2-digit"
+      });
+      const todayStr = today.toLocaleDateString("zh-CN", {
+        year: "numeric",
+        month: "2-digit",
+        day: "2-digit"
+      });
+      const yesterdayStr = yesterday.toLocaleDateString("zh-CN", {
+        year: "numeric",
+        month: "2-digit",
+        day: "2-digit"
+      });
+      if (dateStr === todayStr) {
+        return "今天";
+      } else if (dateStr === yesterdayStr) {
+        return "昨天";
+      } else {
+        return dateStr;
+      }
+    };
+    const formatAmount = (amount) => {
+      return amount.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
+    };
+    const formatTime = (timestamp) => {
+      const date = new Date(timestamp);
+      const hours = String(date.getHours()).padStart(2, "0");
+      const minutes = String(date.getMinutes()).padStart(2, "0");
+      return `${hours}:${minutes}`;
+    };
+    const loadTransactions = () => {
+      try {
+        const storedTransactions = common_vendor.index.getStorageSync("simulated_transactions") || [];
+        transactions.value = storedTransactions.sort((a, b) => b.timestamp - a.timestamp);
+      } catch (e) {
+        console.error("加载交易记录失败:", e);
+        transactions.value = [];
+      }
+    };
+    common_vendor.onMounted(() => {
+      loadTransactions();
+    });
+    return (_ctx, _cache) => {
+      return common_vendor.e({
+        a: common_vendor.o(handleBack),
+        b: common_vendor.f(common_vendor.unref(groupedTransactions), (group, dateKey, i0) => {
+          return {
+            a: common_vendor.t(dateKey),
+            b: common_vendor.f(group, (item, index, i1) => {
+              return {
+                a: common_vendor.t(item.stockName),
+                b: common_vendor.t(item.stockCode),
+                c: common_vendor.t(formatTime(item.timestamp)),
+                d: common_vendor.t(item.type === "buy" ? "-" : "+"),
+                e: common_vendor.t(formatAmount(item.totalAmount)),
+                f: common_vendor.n(item.type === "buy" ? "amount-buy" : "amount-sell"),
+                g: common_vendor.t(item.type === "buy" ? "买入" : "卖出"),
+                h: common_vendor.n(item.type === "buy" ? "status-buy" : "status-sell"),
+                i: index
+              };
+            }),
+            c: dateKey
+          };
+        }),
+        c: transactions.value.length === 0
+      }, transactions.value.length === 0 ? {} : {});
+    };
+  }
+};
+const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-a901d1cb"], ["__file", "D:/program/gupiao-wx/src/pages/transaction/transaction.vue"]]);
+wx.createPage(MiniProgramPage);

+ 5 - 0
dist/dev/mp-weixin/pages/transaction/transaction.json

@@ -0,0 +1,5 @@
+{
+  "navigationBarTitleText": "交易记录",
+  "navigationStyle": "custom",
+  "usingComponents": {}
+}

+ 1 - 0
dist/dev/mp-weixin/pages/transaction/transaction.wxml

@@ -0,0 +1 @@
+<view class="page-container data-v-a901d1cb"><view class="custom-navbar data-v-a901d1cb"><view class="navbar-back data-v-a901d1cb" bindtap="{{a}}"><text class="back-icon data-v-a901d1cb">←</text></view><view class="navbar-title data-v-a901d1cb"><text class="title-text data-v-a901d1cb">交易记录</text></view><view class="navbar-placeholder data-v-a901d1cb"></view></view><scroll-view class="scroll-view data-v-a901d1cb" scroll-y><view class="transaction-list data-v-a901d1cb"><view wx:for="{{b}}" wx:for-item="group" wx:key="c" class="date-group data-v-a901d1cb"><view class="date-header data-v-a901d1cb"><text class="date-text data-v-a901d1cb">{{group.a}}</text></view><view wx:for="{{group.b}}" wx:for-item="item" wx:key="i" class="transaction-item data-v-a901d1cb"><view class="item-left data-v-a901d1cb"><view class="stock-info data-v-a901d1cb"><text class="stock-name data-v-a901d1cb">{{item.a}}</text><text class="stock-code data-v-a901d1cb">{{item.b}}</text></view><text class="transaction-time data-v-a901d1cb">{{item.c}}</text></view><view class="item-right data-v-a901d1cb"><text class="{{['data-v-a901d1cb', 'amount-text', item.f]}}">{{item.d}}¥{{item.e}}</text><view class="{{['data-v-a901d1cb', 'status-badge', item.h]}}"><text class="status-text data-v-a901d1cb">{{item.g}}</text></view></view></view></view><view wx:if="{{c}}" class="empty-state data-v-a901d1cb"><text class="empty-icon data-v-a901d1cb">📋</text><text class="empty-text data-v-a901d1cb">暂无交易记录</text><text class="empty-desc data-v-a901d1cb">开始您的模拟交易之旅吧</text></view><view class="bottom-safe-area data-v-a901d1cb"></view></view></scroll-view></view>

+ 172 - 0
dist/dev/mp-weixin/pages/transaction/transaction.wxss

@@ -0,0 +1,172 @@
+
+.page-container.data-v-a901d1cb {
+  min-height: 100vh;
+  background: #f5f6fb;
+  display: flex;
+  flex-direction: column;
+}
+
+/* 自定义导航栏 */
+.custom-navbar.data-v-a901d1cb {
+  background: #ffffff;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 80rpx 32rpx 30rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+  position: relative;
+}
+.navbar-back.data-v-a901d1cb {
+  width: 80rpx;
+  height: 60rpx;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+}
+.back-icon.data-v-a901d1cb {
+  font-size: 40rpx;
+  color: #222222;
+  font-weight: bold;
+}
+.navbar-title.data-v-a901d1cb {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+}
+.title-text.data-v-a901d1cb {
+  font-size: 36rpx;
+  font-weight: 800;
+  color: #3F51F7;
+  letter-spacing: 2rpx;
+}
+.navbar-placeholder.data-v-a901d1cb {
+  width: 80rpx;
+}
+
+/* 交易记录列表 */
+.scroll-view.data-v-a901d1cb {
+  flex: 1;
+  height: 0;
+}
+.transaction-list.data-v-a901d1cb {
+  padding: 0 0 32rpx;
+}
+
+/* 日期分组 */
+.date-group.data-v-a901d1cb {
+  margin-bottom: 32rpx;
+}
+.date-header.data-v-a901d1cb {
+  padding: 24rpx 32rpx 16rpx;
+}
+.date-text.data-v-a901d1cb {
+  font-size: 26rpx;
+  color: #9ca2b5;
+  font-weight: 500;
+}
+
+/* 交易项 */
+.transaction-item.data-v-a901d1cb {
+  background: #ffffff;
+  padding: 32rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1rpx solid #f5f6fb;
+}
+.transaction-item.data-v-a901d1cb:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.transaction-item.data-v-a901d1cb:last-child {
+  border-bottom: none;
+}
+.item-left.data-v-a901d1cb {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+.stock-info.data-v-a901d1cb {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8rpx;
+}
+.stock-name.data-v-a901d1cb {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #222222;
+  margin-right: 12rpx;
+}
+.stock-code.data-v-a901d1cb {
+  font-size: 24rpx;
+  color: #9ca2b5;
+}
+.transaction-time.data-v-a901d1cb {
+  font-size: 24rpx;
+  color: #9ca2b5;
+}
+.item-right.data-v-a901d1cb {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+}
+.amount-text.data-v-a901d1cb {
+  font-size: 32rpx;
+  font-weight: 700;
+  margin-bottom: 8rpx;
+}
+.amount-buy.data-v-a901d1cb {
+  color: #3abf81;
+}
+.amount-sell.data-v-a901d1cb {
+  color: #f16565;
+}
+.status-badge.data-v-a901d1cb {
+  padding: 4rpx 16rpx;
+  border-radius: 12rpx;
+}
+.status-buy.data-v-a901d1cb {
+  background: #e7f7ef;
+}
+.status-sell.data-v-a901d1cb {
+  background: #ffe7ee;
+}
+.status-text.data-v-a901d1cb {
+  font-size: 22rpx;
+  font-weight: 500;
+}
+.status-buy .status-text.data-v-a901d1cb {
+  color: #3abf81;
+}
+.status-sell .status-text.data-v-a901d1cb {
+  color: #f16565;
+}
+
+/* 空状态 */
+.empty-state.data-v-a901d1cb {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 120rpx 0;
+  background: #ffffff;
+  margin: 0 32rpx;
+  border-radius: 24rpx;
+}
+.empty-icon.data-v-a901d1cb {
+  font-size: 120rpx;
+  margin-bottom: 32rpx;
+  opacity: 0.5;
+}
+.empty-text.data-v-a901d1cb {
+  font-size: 32rpx;
+  color: #666666;
+  margin-bottom: 16rpx;
+  font-weight: 500;
+}
+.empty-desc.data-v-a901d1cb {
+  font-size: 26rpx;
+  color: #9ca2b5;
+}
+.bottom-safe-area.data-v-a901d1cb {
+  height: 40rpx;
+}

+ 1 - 1
dist/dev/mp-weixin/utils/api.js

@@ -1,6 +1,6 @@
 "use strict";
 const common_vendor = require("../common/vendor.js");
-const DEV_BASE_URL = "http://192.168.1.3:8080";
+const DEV_BASE_URL = "http://localhost:8081";
 const BASE_URL = DEV_BASE_URL;
 const getToken = () => {
   return common_vendor.index.getStorageSync("user_token") || null;

+ 9 - 26
src/components/UserInfoPopup.vue

@@ -17,7 +17,7 @@
           >
             <image 
               class="avatar-img" 
-              :src="avatarUrl || '/static/images/default-avatar.png'" 
+              :src="avatarUrl || '/static/images/head.png'" 
               mode="aspectFill"
             ></image>
             <view class="avatar-tip">点击选择头像</view>
@@ -133,32 +133,15 @@ export default {
         return
       }
 
-      try {
-        uni.showLoading({ title: '上传中...' })
-
-        // 上传头像到OSS
-        let uploadedAvatarUrl = this.avatarUrl
-        if (this.tempAvatarPath) {
-          uploadedAvatarUrl = await this.uploadAvatar(this.tempAvatarPath)
-        }
-
-        uni.hideLoading()
-
-        // 返回用户信息给父组件
-        this.$emit('confirm', {
-          nickname: this.nickname.trim(),
-          avatarUrl: uploadedAvatarUrl
-        })
+      // 首次登录时,先用临时路径,注册成功后再上传
+      // 因为此时还没有 token,无法调用上传接口
+      this.$emit('confirm', {
+        nickname: this.nickname.trim(),
+        avatarUrl: this.tempAvatarPath || this.avatarUrl,
+        tempAvatarPath: this.tempAvatarPath  // 传递临时路径,供后续上传
+      })
 
-        this.close()
-      } catch (error) {
-        uni.hideLoading()
-        console.error('[用户信息] 上传头像失败:', error)
-        uni.showToast({
-          title: '头像上传失败,请重试',
-          icon: 'none'
-        })
-      }
+      this.close()
     },
 
     /**

+ 14 - 0
src/pages.json

@@ -42,6 +42,20 @@
       "style": {
         "navigationBarTitleText": "编辑资料"
       }
+    },
+    {
+      "path": "pages/transaction/transaction",
+      "style": {
+        "navigationBarTitleText": "交易记录",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/points/points",
+      "style": {
+        "navigationBarTitleText": "积分记录",
+        "navigationStyle": "custom"
+      }
     }
   ],
   "globalStyle": {

+ 60 - 7
src/pages/login/login.vue

@@ -27,7 +27,6 @@
         class="login-btn primary-btn"
         @click="handleWxLogin"
       >
-        <text class="btn-icon">📱</text>
         <text class="btn-text">微信一键登录</text>
       </button>
 
@@ -68,6 +67,7 @@
 
 <script>
 import { wxSilentLogin, wxPhoneLogin, wxCompleteUserInfo } from '@/utils/auth.js'
+import { uploadFile, updateUserProfile } from '@/utils/api.js'
 import UserInfoPopup from '@/components/UserInfoPopup.vue'
 
 export default {
@@ -259,22 +259,48 @@ export default {
       try {
         uni.showLoading({ title: '注册中...' })
         
-        // 构建完整的用户信息
+        // 构建用户信息(先用微信临时头像URL)
         const completeInfo = {
           openid: this.tempUserData.openid,
           unionid: this.tempUserData.unionid,
           phoneNumber: this.tempUserData.phoneNumber,
           nickname: userInfo.nickname,
-          avatarUrl: userInfo.avatarUrl
+          avatarUrl: userInfo.avatarUrl  // 微信临时URL,先存着
         }
         
-        console.log('[登录] 提交完整用户信息')
+        console.log('[登录] 提交用户信息')
         
-        // 调用后端接口完成注册
+        // 调用后端接口完成注册(此时会拿到token)
         await wxCompleteUserInfo(completeInfo)
         
-        uni.hideLoading()
+        // 注册成功后,有了token,上传头像到服务器
+        if (userInfo.tempAvatarPath) {
+          console.log('[登录] 开始上传头像到服务器, tempAvatarPath:', userInfo.tempAvatarPath)
+          try {
+            const uploadedUrl = await this.uploadAvatarWithToken(userInfo.tempAvatarPath)
+            console.log('[登录] 头像上传成功, uploadedUrl:', uploadedUrl)
+            if (uploadedUrl) {
+              // 更新用户头像为服务器URL
+              console.log('[登录] 调用updateUserProfile更新头像')
+              const updateResult = await updateUserProfile({ avatar: uploadedUrl })
+              console.log('[登录] updateUserProfile返回:', updateResult)
+              
+              // 更新本地存储的用户信息
+              const userInfoLocal = uni.getStorageSync('user_info')
+              if (userInfoLocal) {
+                const parsed = JSON.parse(userInfoLocal)
+                parsed.avatar = uploadedUrl
+                uni.setStorageSync('user_info', JSON.stringify(parsed))
+              }
+              console.log('[登录] 头像上传成功:', uploadedUrl)
+            }
+          } catch (uploadErr) {
+            console.warn('[登录] 头像上传失败:', uploadErr)
+            // 头像上传失败不影响登录,下次打开小程序头像可能显示不出来
+          }
+        }
         
+        uni.hideLoading()
         console.log('[登录] 注册成功')
         this.handleLoginSuccess()
       } catch (error) {
@@ -288,6 +314,33 @@ export default {
       }
     },
 
+    /**
+     * 带token上传头像
+     */
+    uploadAvatarWithToken(filePath) {
+      return new Promise((resolve, reject) => {
+        uni.uploadFile({
+          url: uploadFile.url,
+          filePath: filePath,
+          name: 'file',
+          header: {
+            'Authorization': `Bearer ${uni.getStorageSync('user_token') || ''}`
+          },
+          success: (res) => {
+            const data = JSON.parse(res.data)
+            if (data.code === 200 && data.data && data.data.url) {
+              resolve(data.data.url)
+            } else {
+              reject(new Error(data.message || '上传失败'))
+            }
+          },
+          fail: (err) => {
+            reject(err)
+          }
+        })
+      })
+    },
+
     /**
      * 登录成功后的处理
      */
@@ -355,7 +408,7 @@ export default {
 /* 返回按钮 */
 .back-button {
   position: absolute;
-  top: 40rpx;
+  top: 80rpx;
   left: 30rpx;
   z-index: 10;
   display: flex;

+ 59 - 53
src/pages/mine/mine.vue

@@ -24,39 +24,33 @@
 
         <!-- 积分区域 -->
         <view class="my-tasks-section">
-          <view class="tasks-grid">
-            <view class="task-item" @click="handleViewPoints">
-              <view class="task-icon-wrapper points">
-                <text class="task-icon">💰</text>
+          <view class="points-row">
+            <view class="points-display">
+              <view class="points-icon-wrapper">
+                <text class="points-icon">💰</text>
               </view>
-              <view class="task-info">
-                <text class="task-label">积分</text>
-                <text class="task-value">{{ isLoggedIn ? points : 0 }}</text>
-              </view>
-            </view>
-
-            <view class="task-item" @click="handleRecharge">
-              <view class="task-icon-wrapper recharge">
-                <text class="task-icon">💳</text>
-              </view>
-              <view class="task-info">
-                <text class="task-label">充值</text>
-              </view>
-            </view>
-
-            <view class="task-item" @click="handleHistory">
-              <view class="task-icon-wrapper history">
-                <text class="task-icon">📋</text>
-              </view>
-              <view class="task-info">
-                <text class="task-label">积分记录</text>
+              <view class="points-info">
+                <text class="points-label">我的积分</text>
+                <text class="points-value">{{ isLoggedIn ? points : 0 }}</text>
               </view>
             </view>
+            
+            <button class="recharge-button" @click="handleRecharge">
+              <text class="recharge-text">充值</text>
+            </button>
           </view>
         </view>
 
         <!-- 菜单列表 -->
         <view class="menu-list">
+          <view class="menu-item" @click="handleHistory">
+            <view class="menu-left">
+              <text class="menu-icon">📋</text>
+              <text class="menu-label">积分记录</text>
+            </view>
+            <text class="menu-arrow">›</text>
+          </view>
+          
           <view class="menu-item" @click="handleTransactionRecord">
             <view class="menu-left">
               <text class="menu-icon">📝</text>
@@ -198,7 +192,10 @@ const handleHistory = () => {
     return
   }
   
-  uni.showToast({ title: '积分记录功能开发中', icon: 'none' })
+  // 跳转到积分记录页面
+  uni.navigateTo({
+    url: '/pages/points/points'
+  })
 }
 
 /**
@@ -303,65 +300,74 @@ const handleTransactionRecord = () => {
   box-shadow: 0 16rpx 40rpx rgba(37, 52, 94, 0.08);
 }
 
-.tasks-grid {
+.points-row {
   display: flex;
-  flex-direction: column;
-  gap: 24rpx;
+  align-items: center;
+  justify-content: space-between;
 }
 
-.task-item {
+.points-display {
+  flex: 1;
   display: flex;
   align-items: center;
-  padding: 24rpx;
-  background: #f7f8fc;
-  border-radius: 16rpx;
 }
 
-.task-icon-wrapper {
+.points-icon-wrapper {
   width: 80rpx;
   height: 80rpx;
   border-radius: 50%;
+  background: linear-gradient(135deg, #00BFA5, #00D4B5);
   display: flex;
   align-items: center;
   justify-content: center;
   margin-right: 24rpx;
   flex-shrink: 0;
-  box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.1);
+  box-shadow: 0 8rpx 20rpx rgba(0, 191, 165, 0.3);
 }
 
-.task-icon-wrapper.points {
-  background: linear-gradient(135deg, #00BFA5, #00D4B5);
+.points-icon {
+  font-size: 40rpx;
 }
 
-.task-icon-wrapper.recharge {
-  background: linear-gradient(135deg, #5d55e8, #7568ff);
+.points-info {
+  display: flex;
+  flex-direction: column;
 }
 
-.task-icon-wrapper.history {
-  background: linear-gradient(135deg, #FF9800, #FFA726);
+.points-label {
+  font-size: 26rpx;
+  color: #666a7f;
+  margin-bottom: 8rpx;
 }
 
-.task-icon {
+.points-value {
   font-size: 40rpx;
+  font-weight: 700;
+  color: #00BFA5;
 }
 
-.task-info {
-  flex: 1;
+.recharge-button {
+  width: 160rpx;
+  height: 72rpx;
+  background: linear-gradient(135deg, #5d55e8, #7568ff);
+  border-radius: 36rpx;
   display: flex;
   align-items: center;
-  justify-content: space-between;
+  justify-content: center;
+  box-shadow: 0 8rpx 20rpx rgba(93, 85, 232, 0.3);
+  border: none;
+  padding: 0;
+  line-height: 1;
 }
 
-.task-label {
-  font-size: 28rpx;
-  color: #222222;
-  font-weight: 500;
+.recharge-button::after {
+  border: none;
 }
 
-.task-value {
-  font-size: 32rpx;
-  font-weight: 700;
-  color: #00BFA5;
+.recharge-text {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #ffffff;
 }
 
 /* 菜单列表 */

+ 393 - 0
src/pages/points/points.vue

@@ -0,0 +1,393 @@
+<template>
+  <view class="page-container">
+    <!-- 顶部导航栏 -->
+    <view class="custom-navbar">
+      <view class="navbar-back" @click="handleBack">
+        <text class="back-icon">←</text>
+      </view>
+      <view class="navbar-title">
+        <text class="title-text">积分记录</text>
+      </view>
+      <view class="navbar-placeholder"></view>
+    </view>
+
+    <!-- 积分记录列表 -->
+    <scroll-view class="scroll-view" scroll-y>
+      <view class="transaction-list">
+        <!-- 按日期分组显示 -->
+        <view v-for="(group, dateKey) in groupedRecords" :key="dateKey" class="date-group">
+          <view class="date-header">
+            <text class="date-text">{{ dateKey }}</text>
+          </view>
+          
+          <view 
+            v-for="(item, index) in group" 
+            :key="index"
+            class="transaction-item"
+          >
+            <view class="item-left">
+              <view class="stock-info">
+                <text class="stock-name">{{ item.title }}</text>
+              </view>
+              <text class="transaction-time">{{ formatTime(item.timestamp) }}</text>
+            </view>
+            
+            <view class="item-right">
+              <text :class="['amount-text', item.type === 'add' ? 'amount-sell' : 'amount-buy']">
+                {{ item.type === 'add' ? '+' : '-' }}{{ item.points }}积分
+              </text>
+              <view :class="['status-badge', item.type === 'add' ? 'status-sell' : 'status-buy']">
+                <text class="status-text">{{ item.type === 'add' ? '获得' : '消耗' }}</text>
+              </view>
+            </view>
+          </view>
+        </view>
+
+        <!-- 空状态 -->
+        <view v-if="records.length === 0" class="empty-state">
+          <text class="empty-icon">💰</text>
+          <text class="empty-text">暂无积分记录</text>
+          <text class="empty-desc">完成任务即可获得积分</text>
+        </view>
+
+        <!-- 底部安全区域 -->
+        <view class="bottom-safe-area"></view>
+      </view>
+    </scroll-view>
+  </view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue'
+
+const records = ref([])
+
+// 返回上一页
+const handleBack = () => {
+  const pages = getCurrentPages()
+  if (pages.length > 1) {
+    // 有上一页,返回
+    uni.navigateBack()
+  } else {
+    // 没有上一页,跳转到个人中心
+    uni.switchTab({
+      url: '/pages/mine/mine'
+    })
+  }
+}
+
+// 按日期分组的积分记录
+const groupedRecords = computed(() => {
+  const groups = {}
+  
+  records.value.forEach(item => {
+    const dateKey = formatDate(item.timestamp)
+    if (!groups[dateKey]) {
+      groups[dateKey] = []
+    }
+    groups[dateKey].push(item)
+  })
+  
+  return groups
+})
+
+// 格式化日期(用于分组)
+const formatDate = (timestamp) => {
+  const date = new Date(timestamp)
+  const today = new Date()
+  const yesterday = new Date(today)
+  yesterday.setDate(yesterday.getDate() - 1)
+  
+  const dateStr = date.toLocaleDateString('zh-CN', { 
+    year: 'numeric', 
+    month: '2-digit', 
+    day: '2-digit' 
+  })
+  
+  const todayStr = today.toLocaleDateString('zh-CN', { 
+    year: 'numeric', 
+    month: '2-digit', 
+    day: '2-digit' 
+  })
+  
+  const yesterdayStr = yesterday.toLocaleDateString('zh-CN', { 
+    year: 'numeric', 
+    month: '2-digit', 
+    day: '2-digit' 
+  })
+  
+  if (dateStr === todayStr) {
+    return '今天'
+  } else if (dateStr === yesterdayStr) {
+    return '昨天'
+  } else {
+    return dateStr
+  }
+}
+
+// 格式化时间(仅显示时分)
+const formatTime = (timestamp) => {
+  const date = new Date(timestamp)
+  const hours = String(date.getHours()).padStart(2, '0')
+  const minutes = String(date.getMinutes()).padStart(2, '0')
+  
+  return `${hours}:${minutes}`
+}
+
+// 加载积分记录
+const loadRecords = () => {
+  try {
+    const storedRecords = uni.getStorageSync('points_records') || []
+    // 按时间倒序排列
+    records.value = storedRecords.sort((a, b) => b.timestamp - a.timestamp)
+  } catch (e) {
+    console.error('加载积分记录失败:', e)
+    records.value = []
+  }
+}
+
+// 初始化模拟数据(仅用于演示)
+const initMockData = () => {
+  const mockRecords = [
+    {
+      title: '每日签到',
+      points: 10,
+      type: 'add',
+      timestamp: Date.now() - 1000 * 60 * 30
+    },
+    {
+      title: '完成交易',
+      points: 5,
+      type: 'add',
+      timestamp: Date.now() - 1000 * 60 * 60 * 2
+    },
+    {
+      title: '查询股票',
+      points: 2,
+      type: 'use',
+      timestamp: Date.now() - 1000 * 60 * 60 * 5
+    },
+    {
+      title: '邀请好友',
+      points: 20,
+      type: 'add',
+      timestamp: Date.now() - 1000 * 60 * 60 * 24
+    },
+    {
+      title: '解锁超短池',
+      points: 18,
+      type: 'use',
+      timestamp: Date.now() - 1000 * 60 * 60 * 24 * 2
+    }
+  ]
+  
+  // 如果没有记录,使用模拟数据
+  if (records.value.length === 0) {
+    records.value = mockRecords
+    uni.setStorageSync('points_records', mockRecords)
+  }
+}
+
+onMounted(() => {
+  loadRecords()
+  initMockData()
+})
+</script>
+
+<style scoped>
+.page-container {
+  min-height: 100vh;
+  background: #f5f6fb;
+  display: flex;
+  flex-direction: column;
+}
+
+/* 自定义导航栏 */
+.custom-navbar {
+  background: #ffffff;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 80rpx 32rpx 30rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+  position: relative;
+}
+
+.navbar-back {
+  width: 80rpx;
+  height: 60rpx;
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+}
+
+.back-icon {
+  font-size: 40rpx;
+  color: #222222;
+  font-weight: bold;
+}
+
+.navbar-title {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+}
+
+.title-text {
+  font-size: 36rpx;
+  font-weight: 800;
+  color: #3F51F7;
+  letter-spacing: 2rpx;
+}
+
+.navbar-placeholder {
+  width: 80rpx;
+}
+
+/* 交易记录列表 */
+.scroll-view {
+  flex: 1;
+  height: 0;
+}
+
+.transaction-list {
+  padding: 0 0 32rpx;
+}
+
+/* 日期分组 */
+.date-group {
+  margin-bottom: 32rpx;
+}
+
+.date-header {
+  padding: 24rpx 32rpx 16rpx;
+}
+
+.date-text {
+  font-size: 26rpx;
+  color: #9ca2b5;
+  font-weight: 500;
+}
+
+/* 交易项 */
+.transaction-item {
+  background: #ffffff;
+  padding: 32rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1rpx solid #f5f6fb;
+}
+
+.transaction-item:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+
+.transaction-item:last-child {
+  border-bottom: none;
+}
+
+.item-left {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+
+.stock-info {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8rpx;
+}
+
+.stock-name {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #222222;
+  margin-right: 12rpx;
+}
+
+.transaction-time {
+  font-size: 24rpx;
+  color: #9ca2b5;
+}
+
+.item-right {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+}
+
+.amount-text {
+  font-size: 32rpx;
+  font-weight: 700;
+  margin-bottom: 8rpx;
+}
+
+.amount-buy {
+  color: #3abf81;
+}
+
+.amount-sell {
+  color: #f16565;
+}
+
+.status-badge {
+  padding: 4rpx 16rpx;
+  border-radius: 12rpx;
+}
+
+.status-buy {
+  background: #e7f7ef;
+}
+
+.status-sell {
+  background: #ffe7ee;
+}
+
+.status-text {
+  font-size: 22rpx;
+  font-weight: 500;
+}
+
+.status-buy .status-text {
+  color: #3abf81;
+}
+
+.status-sell .status-text {
+  color: #f16565;
+}
+
+/* 空状态 */
+.empty-state {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 120rpx 0;
+  background: #ffffff;
+  margin: 0 32rpx;
+  border-radius: 24rpx;
+}
+
+.empty-icon {
+  font-size: 120rpx;
+  margin-bottom: 32rpx;
+  opacity: 0.5;
+}
+
+.empty-text {
+  font-size: 32rpx;
+  color: #666666;
+  margin-bottom: 16rpx;
+  font-weight: 500;
+}
+
+.empty-desc {
+  font-size: 26rpx;
+  color: #9ca2b5;
+}
+
+.bottom-safe-area {
+  height: 40rpx;
+}
+</style>

+ 0 - 1
src/pages/pool/pool.vue

@@ -81,7 +81,6 @@
     <!-- 手机号授权弹窗 -->
     <view v-if="showPhoneAuth" class="phone-auth-mask" @click="closePhoneAuth">
       <view class="phone-auth-prompt" @click.stop>
-        <view class="auth-icon">📱</view>
         <text class="auth-title">授权手机号</text>
         <text class="auth-desc">为了完成登录,需要获取您的手机号</text>
         

+ 7 - 2
src/pages/rank/rank.vue

@@ -87,8 +87,7 @@
           class="login-button-native" 
           @click="goToLogin"
         >
-          <text class="button-icon">📱</text>
-          <text>微信授权登录</text>
+          <text>登录</text>
         </button>
       </view>
     </view>
@@ -97,6 +96,7 @@
 
 <script setup>
 import { ref, onMounted } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
 import { getUserPortfolio, getLeaderboard } from '../../utils/api.js'
 import { isLoggedIn as checkIsLoggedIn } from '../../utils/auth.js'
 
@@ -189,6 +189,11 @@ const loadRealData = async () => {
 onMounted(() => {
   checkLoginAndLoadData()
 })
+
+// 页面显示时重新检查登录状态
+onShow(() => {
+  checkLoginAndLoadData()
+})
 </script>
 
 <style>

+ 1 - 2
src/pages/strong/strong.vue

@@ -103,8 +103,7 @@
           class="login-button-native" 
           @click="goToLogin"
         >
-          <text class="button-icon">📱</text>
-          <text>微信授权登录</text>
+          <text>登录</text>
         </button>
       </view>
     </view>

+ 207 - 190
src/pages/transaction/transaction.vue

@@ -1,73 +1,57 @@
 <template>
-  <view class="page-transaction">
-    <!-- 顶部标题卡片 -->
-    <view class="page-title-card">
-      <text class="page-title-text">交易记录</text>
+  <view class="page-container">
+    <!-- 顶部导航栏 -->
+    <view class="custom-navbar">
+      <view class="navbar-back" @click="handleBack">
+        <text class="back-icon">←</text>
+      </view>
+      <view class="navbar-title">
+        <text class="title-text">交易记录</text>
+      </view>
+      <view class="navbar-placeholder"></view>
     </view>
 
+    <!-- 交易记录列表 -->
     <scroll-view class="scroll-view" scroll-y>
-      <view class="content-wrapper">
-        <!-- 统计卡片 -->
-        <view class="stats-card">
-          <view class="stat-item">
-            <text class="stat-label">总交易次数</text>
-            <text class="stat-value">{{ totalTransactions }}</text>
-          </view>
-          <view class="stat-divider"></view>
-          <view class="stat-item">
-            <text class="stat-label">总盈亏</text>
-            <text :class="['stat-value', totalProfit >= 0 ? 'profit' : 'loss']">
-              {{ totalProfit >= 0 ? '+' : '' }}¥{{ Math.abs(totalProfit).toFixed(2) }}
-            </text>
+      <view class="transaction-list">
+        <!-- 按日期分组显示 -->
+        <view v-for="(group, dateKey) in groupedTransactions" :key="dateKey" class="date-group">
+          <view class="date-header">
+            <text class="date-text">{{ dateKey }}</text>
           </view>
-        </view>
-
-        <!-- 交易列表 -->
-        <view class="transaction-list">
-          <view v-if="transactions.length === 0" class="empty-state">
-            <text class="empty-icon">📋</text>
-            <text class="empty-text">暂无交易记录</text>
-            <text class="empty-desc">开始您的模拟交易之旅吧</text>
-          </view>
-
+          
           <view 
-            v-else
-            v-for="(item, index) in transactions" 
+            v-for="(item, index) in group" 
             :key="index"
             class="transaction-item"
           >
-            <view class="transaction-header">
+            <view class="item-left">
               <view class="stock-info">
                 <text class="stock-name">{{ item.stockName }}</text>
                 <text class="stock-code">{{ item.stockCode }}</text>
               </view>
-              <view :class="['transaction-type', item.type]">
-                <text class="type-text">{{ item.type === 'buy' ? '买入' : '卖出' }}</text>
-              </view>
+              <text class="transaction-time">{{ formatTime(item.timestamp) }}</text>
             </view>
-
-            <view class="transaction-details">
-              <view class="detail-row">
-                <text class="detail-label">价格:</text>
-                <text class="detail-value">¥{{ item.price.toFixed(2) }}</text>
-              </view>
-              <view class="detail-row">
-                <text class="detail-label">数量:</text>
-                <text class="detail-value">{{ item.quantity }}股</text>
+            
+            <view class="item-right">
+              <text :class="['amount-text', item.type === 'buy' ? 'amount-buy' : 'amount-sell']">
+                {{ item.type === 'buy' ? '-' : '+' }}¥{{ formatAmount(item.totalAmount) }}
+              </text>
+              <view :class="['status-badge', item.type === 'buy' ? 'status-buy' : 'status-sell']">
+                <text class="status-text">{{ item.type === 'buy' ? '买入' : '卖出' }}</text>
               </view>
-              <view class="detail-row">
-                <text class="detail-label">总额:</text>
-                <text class="detail-value amount">¥{{ item.totalAmount.toFixed(2) }}</text>
-              </view>
-            </view>
-
-            <view class="transaction-footer">
-              <text class="transaction-time">{{ formatTime(item.timestamp) }}</text>
             </view>
           </view>
         </view>
 
-        <!-- 预留底部空间 -->
+        <!-- 空状态 -->
+        <view v-if="transactions.length === 0" class="empty-state">
+          <text class="empty-icon">📋</text>
+          <text class="empty-text">暂无交易记录</text>
+          <text class="empty-desc">开始您的模拟交易之旅吧</text>
+        </view>
+
+        <!-- 底部安全区域 -->
         <view class="bottom-safe-area"></view>
       </view>
     </scroll-view>
@@ -79,31 +63,81 @@ import { ref, computed, onMounted } from 'vue'
 
 const transactions = ref([])
 
-// 计算总交易次数
-const totalTransactions = computed(() => {
-  return transactions.value.length
-})
+// 返回上一页
+const handleBack = () => {
+  const pages = getCurrentPages()
+  if (pages.length > 1) {
+    // 有上一页,返回
+    uni.navigateBack()
+  } else {
+    // 没有上一页,跳转到个人中心
+    uni.switchTab({
+      url: '/pages/mine/mine'
+    })
+  }
+}
 
-// 计算总盈亏(简化计算:买入为负,卖出为正)
-const totalProfit = computed(() => {
-  return transactions.value.reduce((sum, item) => {
-    if (item.type === 'buy') {
-      return sum - item.totalAmount
-    } else {
-      return sum + item.totalAmount
+// 按日期分组的交易记录
+const groupedTransactions = computed(() => {
+  const groups = {}
+  
+  transactions.value.forEach(item => {
+    const dateKey = formatDate(item.timestamp)
+    if (!groups[dateKey]) {
+      groups[dateKey] = []
     }
-  }, 0)
+    groups[dateKey].push(item)
+  })
+  
+  return groups
 })
 
-// 格式化时间
+// 格式化日期(用于分组)
+const formatDate = (timestamp) => {
+  const date = new Date(timestamp)
+  const today = new Date()
+  const yesterday = new Date(today)
+  yesterday.setDate(yesterday.getDate() - 1)
+  
+  const dateStr = date.toLocaleDateString('zh-CN', { 
+    year: 'numeric', 
+    month: '2-digit', 
+    day: '2-digit' 
+  })
+  
+  const todayStr = today.toLocaleDateString('zh-CN', { 
+    year: 'numeric', 
+    month: '2-digit', 
+    day: '2-digit' 
+  })
+  
+  const yesterdayStr = yesterday.toLocaleDateString('zh-CN', { 
+    year: 'numeric', 
+    month: '2-digit', 
+    day: '2-digit' 
+  })
+  
+  if (dateStr === todayStr) {
+    return '今天'
+  } else if (dateStr === yesterdayStr) {
+    return '昨天'
+  } else {
+    return dateStr
+  }
+}
+
+// 格式化金额
+const formatAmount = (amount) => {
+  return amount.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
+}
+
+// 格式化时间(仅显示时分秒)
 const formatTime = (timestamp) => {
   const date = new Date(timestamp)
-  const year = date.getFullYear()
-  const month = String(date.getMonth() + 1).padStart(2, '0')
-  const day = String(date.getDate()).padStart(2, '0')
   const hours = String(date.getHours()).padStart(2, '0')
   const minutes = String(date.getMinutes()).padStart(2, '0')
-  return `${year}-${month}-${day} ${hours}:${minutes}`
+  
+  return `${hours}:${minutes}`
 }
 
 // 加载交易记录
@@ -123,143 +157,117 @@ onMounted(() => {
 })
 </script>
 
-<style>
-.page-transaction {
-  height: 100vh;
+<style scoped>
+.page-container {
+  min-height: 100vh;
+  background: #f5f6fb;
   display: flex;
   flex-direction: column;
-  background: #f5f6fb;
 }
 
-.page-title-card {
+/* 自定义导航栏 */
+.custom-navbar {
   background: #ffffff;
-  padding: 30rpx 0;
-  text-align: center;
-  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
-  border-radius: 0;
-}
-
-.page-title-text {
-  font-size: 36rpx;
-  font-weight: 800;
-  color: #3F51F7;
-  letter-spacing: 2rpx;
-}
-
-.scroll-view {
-  flex: 1;
-  height: 0;
-}
-
-.content-wrapper {
-  padding: 32rpx;
-  background: #f5f6fb;
-  min-height: 100%;
-}
-
-/* 统计卡片 */
-.stats-card {
-  background: linear-gradient(135deg, #5d55e8, #7568ff);
-  border-radius: 24rpx;
-  padding: 40rpx 32rpx;
-  margin-bottom: 32rpx;
-  box-shadow: 0 16rpx 40rpx rgba(93, 85, 232, 0.3);
   display: flex;
   align-items: center;
+  justify-content: space-between;
+  padding: 80rpx 32rpx 30rpx;
+  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+  position: relative;
 }
 
-.stat-item {
-  flex: 1;
+.navbar-back {
+  width: 80rpx;
+  height: 60rpx;
   display: flex;
-  flex-direction: column;
   align-items: center;
+  justify-content: flex-start;
 }
 
-.stat-divider {
-  width: 2rpx;
-  height: 60rpx;
-  background: rgba(255, 255, 255, 0.3);
+.back-icon {
+  font-size: 40rpx;
+  color: #222222;
+  font-weight: bold;
 }
 
-.stat-label {
-  font-size: 24rpx;
-  color: rgba(255, 255, 255, 0.8);
-  margin-bottom: 12rpx;
+.navbar-title {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
 }
 
-.stat-value {
-  font-size: 40rpx;
-  font-weight: 700;
-  color: #ffffff;
+.title-text {
+  font-size: 36rpx;
+  font-weight: 800;
+  color: #3F51F7;
+  letter-spacing: 2rpx;
 }
 
-.stat-value.profit {
-  color: #4fffb0;
+.navbar-placeholder {
+  width: 80rpx;
 }
 
-.stat-value.loss {
-  color: #ff6b9d;
+/* 交易记录列表 */
+.scroll-view {
+  flex: 1;
+  height: 0;
 }
 
-/* 交易列表 */
 .transaction-list {
-  background: #ffffff;
-  border-radius: 24rpx;
-  overflow: hidden;
-  box-shadow: 0 16rpx 40rpx rgba(37, 52, 94, 0.08);
+  padding: 0 0 32rpx;
 }
 
-/* 空状态 */
-.empty-state {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  padding: 100rpx 40rpx;
-}
-
-.empty-icon {
-  font-size: 80rpx;
-  margin-bottom: 24rpx;
+/* 日期分组 */
+.date-group {
+  margin-bottom: 32rpx;
 }
 
-.empty-text {
-  font-size: 28rpx;
-  color: #666a7f;
-  margin-bottom: 12rpx;
+.date-header {
+  padding: 24rpx 32rpx 16rpx;
 }
 
-.empty-desc {
-  font-size: 24rpx;
+.date-text {
+  font-size: 26rpx;
   color: #9ca2b5;
+  font-weight: 500;
 }
 
 /* 交易项 */
 .transaction-item {
+  background: #ffffff;
   padding: 32rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
   border-bottom: 1rpx solid #f5f6fb;
 }
 
+.transaction-item:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+
 .transaction-item:last-child {
   border-bottom: none;
 }
 
-.transaction-header {
+.item-left {
+  flex: 1;
   display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 20rpx;
+  flex-direction: column;
 }
 
 .stock-info {
   display: flex;
   align-items: center;
-  gap: 16rpx;
+  margin-bottom: 8rpx;
 }
 
 .stock-name {
   font-size: 30rpx;
   font-weight: 600;
   color: #222222;
+  margin-right: 12rpx;
 }
 
 .stock-code {
@@ -267,78 +275,87 @@ onMounted(() => {
   color: #9ca2b5;
 }
 
-.transaction-type {
-  padding: 8rpx 20rpx;
-  border-radius: 20rpx;
+.transaction-time {
   font-size: 24rpx;
+  color: #9ca2b5;
 }
 
-.transaction-type.buy {
-  background: #e7f7ef;
-}
-
-.transaction-type.sell {
-  background: #ffe7e7;
+.item-right {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
 }
 
-.type-text {
-  font-weight: 600;
+.amount-text {
+  font-size: 32rpx;
+  font-weight: 700;
+  margin-bottom: 8rpx;
 }
 
-.transaction-type.buy .type-text {
+.amount-buy {
   color: #3abf81;
 }
 
-.transaction-type.sell .type-text {
+.amount-sell {
   color: #f16565;
 }
 
-.transaction-details {
-  background: #f7f8fc;
+.status-badge {
+  padding: 4rpx 16rpx;
   border-radius: 12rpx;
-  padding: 20rpx 24rpx;
-  margin-bottom: 16rpx;
 }
 
-.detail-row {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 12rpx;
+.status-buy {
+  background: #e7f7ef;
 }
 
-.detail-row:last-child {
-  margin-bottom: 0;
+.status-sell {
+  background: #ffe7ee;
 }
 
-.detail-label {
-  font-size: 24rpx;
-  color: #666a7f;
+.status-text {
+  font-size: 22rpx;
+  font-weight: 500;
 }
 
-.detail-value {
-  font-size: 26rpx;
-  color: #222222;
-  font-weight: 500;
+.status-buy .status-text {
+  color: #3abf81;
 }
 
-.detail-value.amount {
-  font-size: 28rpx;
-  font-weight: 700;
-  color: #5d55e8;
+.status-sell .status-text {
+  color: #f16565;
 }
 
-.transaction-footer {
+/* 空状态 */
+.empty-state {
   display: flex;
-  justify-content: flex-end;
+  flex-direction: column;
+  align-items: center;
+  padding: 120rpx 0;
+  background: #ffffff;
+  margin: 0 32rpx;
+  border-radius: 24rpx;
 }
 
-.transaction-time {
-  font-size: 22rpx;
+.empty-icon {
+  font-size: 120rpx;
+  margin-bottom: 32rpx;
+  opacity: 0.5;
+}
+
+.empty-text {
+  font-size: 32rpx;
+  color: #666666;
+  margin-bottom: 16rpx;
+  font-weight: 500;
+}
+
+.empty-desc {
+  font-size: 26rpx;
   color: #9ca2b5;
 }
 
 .bottom-safe-area {
-  height: 80rpx;
+  height: 40rpx;
 }
 </style>

+ 2 - 1
src/utils/api.js

@@ -6,7 +6,8 @@
 // 真机调试时,请将 DEV_BASE_URL 改为你电脑的局域网IP地址
 // 例如:const DEV_BASE_URL = 'http://192.168.1.3:8080'
 // 可以通过命令 ipconfig (Windows) 或 ifconfig (Mac/Linux) 查看IP地址
-const DEV_BASE_URL = 'http://192.168.1.3:8080'
+// const DEV_BASE_URL = 'http://192.168.1.3:8080'
+const DEV_BASE_URL = 'http://localhost:8081'
 
 // 生产环境配置(部署后的服务器地址)
 const PROD_BASE_URL = 'https://your-domain.com'

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff