Przeglądaj źródła

我的股票添加

Zhangbw 3 miesięcy temu
rodzic
commit
8c5c5b43a8

+ 0 - 2
dist/dev/mp-weixin/common/vendor.js

@@ -6792,7 +6792,6 @@ const createHook = (lifecycle) => (hook, target = getCurrentInstance()) => {
 const onShow = /* @__PURE__ */ createHook(ON_SHOW);
 const onLoad = /* @__PURE__ */ createHook(ON_LOAD);
 exports._export_sfc = _export_sfc;
-exports.computed = computed;
 exports.createSSRApp = createSSRApp;
 exports.e = e;
 exports.f = f;
@@ -6806,4 +6805,3 @@ exports.ref = ref;
 exports.resolveComponent = resolveComponent;
 exports.sr = sr;
 exports.t = t;
-exports.unref = unref;

+ 2 - 2
dist/dev/mp-weixin/pages/mine/mine.js

@@ -55,7 +55,7 @@ const _sfc_main = {
         }
       });
     };
-    const handleTransactionRecord = () => {
+    const handleSubscriptionRecord = () => {
       if (!utils_auth.checkLogin()) {
         return;
       }
@@ -68,7 +68,7 @@ const _sfc_main = {
         a: isLoggedIn.value && userInfo.value.avatar ? userInfo.value.avatar : "/static/images/head.png",
         b: common_vendor.t(isLoggedIn.value ? userInfo.value.nickname || "微信用户" : "登录/注册"),
         c: common_vendor.o(handleUserCardClick),
-        d: common_vendor.o(handleTransactionRecord),
+        d: common_vendor.o(handleSubscriptionRecord),
         e: isLoggedIn.value
       }, isLoggedIn.value ? {
         f: common_vendor.o(handleLogout)

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

@@ -1 +1 @@
-<view class="page-mine"><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="menu-list"><view class="menu-item" bindtap="{{d}}"><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="{{e}}" class="logout-section"><button class="logout-btn" bindtap="{{f}}"> 退出登录 </button></view><view class="bottom-safe-area"></view></view></scroll-view></view>
+<view class="page-mine"><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="menu-list"><view class="menu-item" bindtap="{{d}}"><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="{{e}}" class="logout-section"><button class="logout-btn" bindtap="{{f}}"> 退出登录 </button></view><view class="bottom-safe-area"></view></view></scroll-view></view>

+ 54 - 19
dist/dev/mp-weixin/pages/pool/pool.js

@@ -9,8 +9,15 @@ const _sfc_main = {
     const showModal = common_vendor.ref(false);
     const showPhoneAuth = common_vendor.ref(false);
     const selectedPlan = common_vendor.ref("daily");
-    const selectedDate = common_vendor.ref("2025年11月20日");
+    const startMonth = common_vendor.ref("2025-01");
+    const endMonth = common_vendor.ref("2025-11");
     const isLoggedIn = common_vendor.ref(false);
+    const formatMonth = (monthStr) => {
+      if (!monthStr)
+        return "请选择";
+      const [year, month] = monthStr.split("-");
+      return `${year}年${month}月`;
+    };
     const checkLogin = () => {
       isLoggedIn.value = utils_auth.isLoggedIn();
       console.log("[超短池] 登录状态:", isLoggedIn.value);
@@ -91,10 +98,34 @@ const _sfc_main = {
         icon: "success"
       });
     };
+    const onStartMonthChange = (e) => {
+      startMonth.value = e.detail.value;
+      console.log("[超短池] 选择开始月份:", startMonth.value);
+    };
+    const onEndMonthChange = (e) => {
+      endMonth.value = e.detail.value;
+      console.log("[超短池] 选择结束月份:", endMonth.value);
+    };
     const onHistorySearch = () => {
+      if (!startMonth.value || !endMonth.value) {
+        common_vendor.index.showToast({
+          title: "请选择开始和结束月份",
+          icon: "none"
+        });
+        return;
+      }
+      if (startMonth.value > endMonth.value) {
+        common_vendor.index.showToast({
+          title: "开始月份不能晚于结束月份",
+          icon: "none"
+        });
+        return;
+      }
+      console.log("[超短池] 查询历史数据区间:", startMonth.value, "至", endMonth.value);
       common_vendor.index.showToast({
-        title: "历史查询功能开发中",
-        icon: "none"
+        title: `查询${formatMonth(startMonth.value)}至${formatMonth(endMonth.value)}`,
+        icon: "none",
+        duration: 2e3
       });
     };
     common_vendor.onLoad(() => {
@@ -112,27 +143,31 @@ const _sfc_main = {
       }, !isPurchased.value ? {
         b: common_vendor.o(showPurchaseModal)
       } : {}, {
-        c: selectedDate.value,
-        d: common_vendor.o(($event) => selectedDate.value = $event.detail.value),
-        e: common_vendor.o(onHistorySearch),
-        f: showPhoneAuth.value
+        c: common_vendor.t(formatMonth(startMonth.value)),
+        d: startMonth.value,
+        e: common_vendor.o(onStartMonthChange),
+        f: common_vendor.t(formatMonth(endMonth.value)),
+        g: endMonth.value,
+        h: common_vendor.o(onEndMonthChange),
+        i: common_vendor.o(onHistorySearch),
+        j: showPhoneAuth.value
       }, showPhoneAuth.value ? {
-        g: common_vendor.o((...args) => _ctx.onGetPhoneNumber && _ctx.onGetPhoneNumber(...args)),
-        h: common_vendor.o(() => {
+        k: common_vendor.o((...args) => _ctx.onGetPhoneNumber && _ctx.onGetPhoneNumber(...args)),
+        l: common_vendor.o(() => {
         }),
-        i: common_vendor.o((...args) => _ctx.closePhoneAuth && _ctx.closePhoneAuth(...args))
+        m: common_vendor.o((...args) => _ctx.closePhoneAuth && _ctx.closePhoneAuth(...args))
       } : {}, {
-        j: showModal.value
+        n: showModal.value
       }, showModal.value ? {
-        k: common_vendor.o(closePurchaseModal),
-        l: selectedPlan.value === "daily" ? 1 : "",
-        m: common_vendor.o(($event) => selectedPlan.value = "daily"),
-        n: selectedPlan.value === "weekly" ? 1 : "",
-        o: common_vendor.o(($event) => selectedPlan.value = "weekly"),
-        p: common_vendor.o(handlePurchase),
-        q: common_vendor.o(() => {
+        o: common_vendor.o(closePurchaseModal),
+        p: selectedPlan.value === "daily" ? 1 : "",
+        q: common_vendor.o(($event) => selectedPlan.value = "daily"),
+        r: selectedPlan.value === "weekly" ? 1 : "",
+        s: common_vendor.o(($event) => selectedPlan.value = "weekly"),
+        t: common_vendor.o(handlePurchase),
+        v: common_vendor.o(() => {
         }),
-        r: common_vendor.o(closePurchaseModal)
+        w: common_vendor.o(closePurchaseModal)
       } : {});
     };
   }

Plik diff jest za duży
+ 0 - 0
dist/dev/mp-weixin/pages/pool/pool.wxml


+ 40 - 27
dist/dev/mp-weixin/pages/pool/pool.wxss

@@ -163,13 +163,51 @@
   display: flex;
   align-items: center;
 }
-.history-date-input {
+.date-range-row {
+  display: flex;
+  align-items: center;
+  gap: 16rpx;
+  margin-bottom: 24rpx;
+}
+.date-picker-half {
   flex: 1;
+}
+.date-separator {
+  font-size: 26rpx;
+  color: #666a7f;
+  padding: 0 8rpx;
+}
+.date-input {
   background: #f7f8fc;
   border-radius: 12rpx;
-  padding: 24rpx 24rpx;
+  padding: 24rpx;
   font-size: 26rpx;
   color: #222222;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.date-text {
+  flex: 1;
+}
+.date-icon {
+  font-size: 28rpx;
+  margin-left: 12rpx;
+}
+.history-search-button-full {
+  width: 100%;
+  background: linear-gradient(135deg, #5d55e8, #7568ff);
+  border-radius: 16rpx;
+  padding: 28rpx 0;
+  text-align: center;
+  margin-top: 12rpx;
+  margin-bottom: 24rpx;
+  box-shadow: 0 8rpx 20rpx rgba(93, 85, 232, 0.3);
+}
+.search-button-text {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #ffffff;
 }
 .history-search-button {
   width: 80rpx;
@@ -332,31 +370,6 @@
   color: #222222;
   flex: 1;
 }
-.payment-info {
-  display: flex;
-  flex-direction: column;
-  flex: 1;
-}
-.points-balance {
-  font-size: 22rpx;
-  color: #9ca2b5;
-  margin-top: 4rpx;
-}
-.points-cost {
-  display: flex;
-  align-items: baseline;
-  margin-right: 16rpx;
-}
-.points-amount {
-  font-size: 32rpx;
-  font-weight: 700;
-  color: #ff9500;
-}
-.points-unit {
-  font-size: 22rpx;
-  color: #ff9500;
-  margin-left: 4rpx;
-}
 .payment-check {
   width: 36rpx;
   height: 36rpx;

+ 125 - 1
dist/dev/mp-weixin/pages/rank/rank.js

@@ -1,13 +1,137 @@
 "use strict";
 const common_vendor = require("../../common/vendor.js");
+const utils_auth = require("../../utils/auth.js");
+const utils_api = require("../../utils/api.js");
 const _sfc_main = {
   __name: "rank",
   setup(__props) {
+    const isLoggedIn = common_vendor.ref(false);
+    const myStocks = common_vendor.ref([]);
+    const loadMyStocks = () => {
+      if (!isLoggedIn.value) {
+        myStocks.value = [];
+        return;
+      }
+      try {
+        const stocks = common_vendor.index.getStorageSync("my_stocks") || [];
+        myStocks.value = stocks;
+        console.log("[我的股票] 加载股票列表:", stocks.length, "只");
+      } catch (e) {
+        console.error("加载股票列表失败:", e);
+        myStocks.value = [];
+      }
+    };
+    const goToLogin = () => {
+      common_vendor.index.navigateTo({
+        url: "/pages/login/login"
+      });
+    };
+    const removeStock = (index) => {
+      common_vendor.index.showModal({
+        title: "确认删除",
+        content: `确定要删除 ${myStocks.value[index].name} 吗?`,
+        confirmText: "删除",
+        cancelText: "取消",
+        success: (res) => {
+          if (res.confirm) {
+            myStocks.value.splice(index, 1);
+            common_vendor.index.setStorageSync("my_stocks", myStocks.value);
+            common_vendor.index.showToast({
+              title: "删除成功",
+              icon: "success"
+            });
+          }
+        }
+      });
+    };
+    const refreshQuote = async (stock, index) => {
+      try {
+        common_vendor.index.showLoading({ title: "刷新中..." });
+        const quoteRes = await utils_api.getStockQuotes(stock.code);
+        console.log("[我的股票] 行情数据:", quoteRes);
+        if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) {
+          const quoteData = quoteRes.data[0];
+          myStocks.value[index].priceChange = quoteData.priceChange;
+          myStocks.value[index].changePercent = quoteData.changePercent;
+          common_vendor.index.setStorageSync("my_stocks", myStocks.value);
+          common_vendor.index.hideLoading();
+          common_vendor.index.showToast({
+            title: "刷新成功",
+            icon: "success"
+          });
+        } else {
+          common_vendor.index.hideLoading();
+          common_vendor.index.showToast({
+            title: "获取行情失败",
+            icon: "none"
+          });
+        }
+      } catch (e) {
+        common_vendor.index.hideLoading();
+        console.error("刷新行情失败:", e);
+        common_vendor.index.showToast({
+          title: "刷新失败",
+          icon: "none"
+        });
+      }
+    };
+    const getChangeClass = (value) => {
+      if (!value || value === "--")
+        return "";
+      if (value.startsWith("+") || value.match(/^[\d.]/) && !value.startsWith("-")) {
+        return "change-up";
+      }
+      if (value.startsWith("-")) {
+        return "change-down";
+      }
+      return "";
+    };
+    const formatDate = (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}`;
+    };
+    common_vendor.onLoad(() => {
+      isLoggedIn.value = utils_auth.isLoggedIn();
+      console.log("[我的股票] 登录状态:", isLoggedIn.value);
+      console.log("[我的股票] Token:", common_vendor.index.getStorageSync("user_token"));
+      loadMyStocks();
+    });
     common_vendor.onShow(() => {
+      isLoggedIn.value = utils_auth.isLoggedIn();
+      console.log("[我的股票] 登录状态:", isLoggedIn.value);
+      console.log("[我的股票] Token:", common_vendor.index.getStorageSync("user_token"));
+      loadMyStocks();
       common_vendor.index.setNavigationBarTitle({ title: "量化交易大师" });
     });
     return (_ctx, _cache) => {
-      return {};
+      return common_vendor.e({
+        a: myStocks.value.length > 0
+      }, myStocks.value.length > 0 ? {
+        b: common_vendor.f(myStocks.value, (stock, index, i0) => {
+          return {
+            a: common_vendor.t(stock.name),
+            b: common_vendor.t(stock.code),
+            c: common_vendor.o(($event) => removeStock(index), index),
+            d: common_vendor.t(stock.priceChange || "--"),
+            e: common_vendor.n(getChangeClass(stock.priceChange)),
+            f: common_vendor.t(stock.changePercent || "--"),
+            g: common_vendor.n(getChangeClass(stock.changePercent)),
+            h: common_vendor.t(formatDate(stock.addTime)),
+            i: common_vendor.o(($event) => refreshQuote(stock, index), index),
+            j: index
+          };
+        })
+      } : {}, {
+        c: !isLoggedIn.value ? 1 : "",
+        d: !isLoggedIn.value
+      }, !isLoggedIn.value ? {
+        e: common_vendor.o(goToLogin)
+      } : {});
     };
   }
 };

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

@@ -1 +1 @@
-<view class="page-rank"><view class="empty-content"><view class="empty-icon">🚧</view><text class="empty-text">功能开发中</text><text class="empty-desc">敬请期待</text></view></view>
+<view class="page-rank"><scroll-view class="scroll-view" scroll-y><view class="{{['content-wrapper', c && 'blur-content']}}"><view wx:if="{{a}}" class="stock-list"><view wx:for="{{b}}" wx:for-item="stock" wx:key="j" class="stock-card"><view class="stock-header"><view class="stock-title"><text class="stock-name">{{stock.a}}</text><text class="stock-code">{{stock.b}}</text></view><view class="delete-btn" bindtap="{{stock.c}}"><text class="delete-icon">×</text></view></view><view class="stock-body"><view class="quote-row"><view class="quote-item"><text class="quote-label">涨跌额</text><text class="{{['quote-value', stock.e]}}">{{stock.d}}</text></view><view class="quote-item"><text class="quote-label">涨跌幅</text><text class="{{['quote-value', stock.g]}}">{{stock.f}}</text></view></view><view class="info-item"><text class="info-label">添加时间</text><text class="info-value">{{stock.h}}</text></view><view class="refresh-row"><view class="refresh-btn" bindtap="{{stock.i}}"><text class="refresh-icon">🔄</text><text class="refresh-text">刷新行情</text></view></view></view></view></view><view wx:else class="empty-content"><view class="empty-icon">📊</view><text class="empty-text">暂无收藏股票</text><text class="empty-desc">在强势池中点击"+"按钮添加股票</text></view><view class="bottom-safe-area"></view></view></scroll-view><view wx:if="{{d}}" 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="{{e}}"><text>登录</text></button></view></view></view>

+ 215 - 3
dist/dev/mp-weixin/pages/rank/rank.wxss

@@ -2,16 +2,155 @@
 .page-rank {
   display: flex;
   flex-direction: column;
-  align-items: center;
-  justify-content: center;
   background: #f5f6fb;
   height: 100vh;
 }
+.scroll-view {
+  flex: 1;
+  height: 0;
+}
+.content-wrapper {
+  padding: 32rpx;
+  min-height: 100%;
+}
+
+/* 股票列表 */
+.stock-list {
+  display: flex;
+  flex-direction: column;
+  gap: 24rpx;
+}
+.stock-card {
+  background: #ffffff;
+  border-radius: 24rpx;
+  padding: 32rpx;
+  box-shadow: 0 8rpx 24rpx rgba(37, 52, 94, 0.08);
+}
+.stock-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 24rpx;
+  padding-bottom: 24rpx;
+  border-bottom: 1rpx solid #f1f2f6;
+}
+.stock-title {
+  display: flex;
+  flex-direction: column;
+  gap: 8rpx;
+}
+.stock-name {
+  font-size: 34rpx;
+  font-weight: 700;
+  color: #222222;
+}
+.stock-code {
+  font-size: 26rpx;
+  color: #5d55e8;
+  font-weight: 500;
+}
+.delete-btn {
+  width: 56rpx;
+  height: 56rpx;
+  background: #f16565;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 4rpx 12rpx rgba(241, 101, 101, 0.3);
+}
+.delete-icon {
+  font-size: 40rpx;
+  font-weight: 700;
+  color: #ffffff;
+  line-height: 1;
+}
+.stock-body {
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+.info-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.info-label {
+  font-size: 26rpx;
+  color: #666a7f;
+}
+.info-value {
+  font-size: 26rpx;
+  color: #222222;
+  font-weight: 500;
+}
+
+/* 涨跌信息样式 */
+.quote-row {
+  display: flex;
+  justify-content: space-between;
+  gap: 24rpx;
+  margin-bottom: 16rpx;
+  padding: 20rpx;
+  background: #f7f8fc;
+  border-radius: 16rpx;
+}
+.quote-item {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.quote-label {
+  font-size: 24rpx;
+  color: #666a7f;
+  margin-bottom: 8rpx;
+}
+.quote-value {
+  font-size: 32rpx;
+  font-weight: 700;
+  color: #222222;
+}
+
+/* 涨(红色) */
+.change-up {
+  color: #f16565 !important;
+}
+
+/* 跌(绿色) */
+.change-down {
+  color: #3abf81 !important;
+}
+
+/* 刷新按钮 */
+.refresh-row {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 16rpx;
+}
+.refresh-btn {
+  display: flex;
+  align-items: center;
+  gap: 8rpx;
+  padding: 12rpx 20rpx;
+  background: #f7f8fc;
+  border-radius: 20rpx;
+}
+.refresh-icon {
+  font-size: 24rpx;
+}
+.refresh-text {
+  font-size: 24rpx;
+  color: #666a7f;
+}
+
+/* 空状态 */
 .empty-content {
   display: flex;
   flex-direction: column;
   align-items: center;
-  padding: 100rpx 60rpx;
+  justify-content: center;
+  padding: 200rpx 60rpx;
 }
 .empty-icon {
   font-size: 120rpx;
@@ -26,4 +165,77 @@
 .empty-desc {
   font-size: 26rpx;
   color: #999999;
+  text-align: center;
+  line-height: 1.6;
+}
+.bottom-safe-area {
+  height: 80rpx;
+}
+
+/* 模糊效果 */
+.blur-content {
+  filter: blur(8rpx);
+  pointer-events: none;
+}
+
+/* 登录遮罩层 */
+.login-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.4);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 999;
+}
+.login-prompt {
+  width: 560rpx;
+  max-width: 560rpx;
+  background: #ffffff;
+  border-radius: 24rpx;
+  padding: 50rpx 40rpx;
+  margin: 0 auto;
+  text-align: center;
+  box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
+  box-sizing: border-box;
+}
+.lock-icon {
+  font-size: 72rpx;
+  margin-bottom: 20rpx;
+}
+.prompt-title {
+  display: block;
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #222222;
+  margin-bottom: 12rpx;
+}
+.prompt-desc {
+  display: block;
+  font-size: 24rpx;
+  color: #999999;
+  line-height: 1.5;
+  margin-bottom: 32rpx;
+}
+.login-button-native {
+  width: 100%;
+  height: 80rpx;
+  background: linear-gradient(135deg, #4CAF50, #66BB6A);
+  color: #ffffff;
+  border-radius: 40rpx;
+  font-size: 30rpx;
+  font-weight: 600;
+  box-shadow: 0 8rpx 24rpx rgba(76, 175, 80, 0.4);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: none;
+  padding: 0;
+  line-height: 80rpx;
+}
+.login-button-native::after {
+  border: none;
 }

+ 129 - 17
dist/dev/mp-weixin/pages/strong/strong.js

@@ -1,14 +1,13 @@
 "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 _sfc_main = {
   __name: "strong",
   setup(__props) {
-    common_vendor.ref(false);
     const isPurchased = common_vendor.ref(false);
     const showModal = common_vendor.ref(false);
-    const selectedPlan = common_vendor.ref("monthly");
+    const selectedPlan = common_vendor.ref("yearly");
     const stockList = common_vendor.ref([
       {
         name: "美的集团",
@@ -23,7 +22,14 @@ const _sfc_main = {
         score: "85.1"
       }
     ]);
-    const selectedDate = common_vendor.ref("2025年11月20日");
+    const startMonth = common_vendor.ref("2025-01");
+    const endMonth = common_vendor.ref("2025-11");
+    const formatMonth = (monthStr) => {
+      if (!monthStr)
+        return "请选择";
+      const [year, month] = monthStr.split("-");
+      return `${year}年${month}月`;
+    };
     const checkPurchaseStatus = () => {
       try {
         const purchaseInfo = common_vendor.index.getStorageSync("strong_pool_purchase");
@@ -79,8 +85,8 @@ const _sfc_main = {
       }
       const now = Date.now();
       let expireTime = now;
-      if (selectedPlan.value === "monthly") {
-        expireTime = now + 30 * 24 * 60 * 60 * 1e3;
+      if (selectedPlan.value === "yearly") {
+        expireTime = now + 365 * 24 * 60 * 60 * 1e3;
       }
       const purchaseInfo = {
         plan: selectedPlan.value,
@@ -95,16 +101,116 @@ const _sfc_main = {
         icon: "success"
       });
     };
+    const onStartMonthChange = (e) => {
+      startMonth.value = e.detail.value;
+      console.log("[强势池] 选择开始月份:", startMonth.value);
+    };
+    const onEndMonthChange = (e) => {
+      endMonth.value = e.detail.value;
+      console.log("[强势池] 选择结束月份:", endMonth.value);
+    };
     const onHistorySearch = () => {
+      if (!startMonth.value || !endMonth.value) {
+        common_vendor.index.showToast({
+          title: "请选择开始和结束月份",
+          icon: "none"
+        });
+        return;
+      }
+      if (startMonth.value > endMonth.value) {
+        common_vendor.index.showToast({
+          title: "开始月份不能晚于结束月份",
+          icon: "none"
+        });
+        return;
+      }
+      console.log("[强势池] 查询历史数据区间:", startMonth.value, "至", endMonth.value);
       common_vendor.index.showToast({
-        title: "历史查询功能开发中",
-        icon: "none"
+        title: `查询${formatMonth(startMonth.value)}至${formatMonth(endMonth.value)}`,
+        icon: "none",
+        duration: 2e3
       });
     };
+    const addToMyStocks = async (stock) => {
+      try {
+        const myStocks = common_vendor.index.getStorageSync("my_stocks") || [];
+        const exists = myStocks.some((item) => item.code === stock.code);
+        if (exists) {
+          common_vendor.index.showToast({
+            title: "该股票已在列表中",
+            icon: "none"
+          });
+          return;
+        }
+        common_vendor.index.showLoading({ title: "获取行情..." });
+        let priceChange = null;
+        let changePercent = null;
+        try {
+          const quoteRes = await utils_api.getStockQuotes(stock.code);
+          console.log("[强势池] 行情数据:", quoteRes);
+          if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) {
+            const quoteData = quoteRes.data[0];
+            priceChange = quoteData.priceChange;
+            changePercent = quoteData.changePercent;
+          }
+        } catch (e) {
+          console.error("获取行情数据失败:", e);
+        }
+        common_vendor.index.hideLoading();
+        myStocks.push({
+          name: stock.name,
+          code: stock.code,
+          priceChange,
+          changePercent,
+          addTime: Date.now()
+        });
+        common_vendor.index.setStorageSync("my_stocks", myStocks);
+        common_vendor.index.showToast({
+          title: "添加成功",
+          icon: "success"
+        });
+      } catch (e) {
+        common_vendor.index.hideLoading();
+        console.error("添加股票失败:", e);
+        common_vendor.index.showToast({
+          title: "添加失败",
+          icon: "none"
+        });
+      }
+    };
+    const removeFromMyStocks = (stock) => {
+      try {
+        let myStocks = common_vendor.index.getStorageSync("my_stocks") || [];
+        const index = myStocks.findIndex((item) => item.code === stock.code);
+        if (index === -1) {
+          common_vendor.index.showToast({
+            title: "该股票不在列表中",
+            icon: "none"
+          });
+          return;
+        }
+        myStocks.splice(index, 1);
+        common_vendor.index.setStorageSync("my_stocks", myStocks);
+        common_vendor.index.showToast({
+          title: "移除成功",
+          icon: "success"
+        });
+      } catch (e) {
+        console.error("移除股票失败:", e);
+        common_vendor.index.showToast({
+          title: "移除失败",
+          icon: "none"
+        });
+      }
+    };
     common_vendor.onLoad(() => {
+      const loginStatus = utils_auth.isLoggedIn();
+      console.log("[强势池] 登录状态:", loginStatus);
       checkPurchaseStatus();
     });
     common_vendor.onShow(() => {
+      const loginStatus = utils_auth.isLoggedIn();
+      console.log("[强势池] 登录状态:", loginStatus);
       checkPurchaseStatus();
       common_vendor.index.setNavigationBarTitle({ title: "量化交易大师" });
     });
@@ -118,20 +224,26 @@ const _sfc_main = {
           return {
             a: common_vendor.t(stock.name),
             b: common_vendor.t(stock.code),
-            c: index
+            c: common_vendor.o(($event) => addToMyStocks(stock), index),
+            d: common_vendor.o(($event) => removeFromMyStocks(stock), index),
+            e: index
           };
         })
       }, {
-        d: selectedDate.value,
-        e: common_vendor.o(($event) => selectedDate.value = $event.detail.value),
-        f: common_vendor.o(onHistorySearch),
-        g: showModal.value
+        d: common_vendor.t(formatMonth(startMonth.value)),
+        e: startMonth.value,
+        f: common_vendor.o(onStartMonthChange),
+        g: common_vendor.t(formatMonth(endMonth.value)),
+        h: endMonth.value,
+        i: common_vendor.o(onEndMonthChange),
+        j: common_vendor.o(onHistorySearch),
+        k: showModal.value
       }, showModal.value ? {
-        h: common_vendor.o(closePurchaseModal),
-        i: common_vendor.o(handlePurchase),
-        j: common_vendor.o(() => {
+        l: common_vendor.o(closePurchaseModal),
+        m: common_vendor.o(handlePurchase),
+        n: common_vendor.o(() => {
         }),
-        k: common_vendor.o(closePurchaseModal)
+        o: common_vendor.o(closePurchaseModal)
       } : {});
     };
   }

Plik diff jest za duży
+ 0 - 0
dist/dev/mp-weixin/pages/strong/strong.wxml


+ 44 - 2
dist/dev/mp-weixin/pages/strong/strong.wxss

@@ -185,13 +185,55 @@
   display: flex;
   align-items: center;
 }
-.history-date-input {
+.date-range-row {
+  display: flex;
+  align-items: center;
+  gap: 16rpx;
+  margin-bottom: 24rpx;
+}
+.date-picker-half {
   flex: 1;
+}
+.date-separator {
+  font-size: 26rpx;
+  color: #666a7f;
+  padding: 0 8rpx;
+}
+.date-input {
   background: #f7f8fc;
   border-radius: 12rpx;
-  padding: 24rpx 24rpx;
+  padding: 24rpx;
   font-size: 26rpx;
   color: #222222;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.date-text {
+  flex: 1;
+}
+.date-icon {
+  font-size: 28rpx;
+  margin-left: 12rpx;
+}
+.history-search-button-full {
+  width: 100%;
+  background: linear-gradient(135deg, #5d55e8, #7568ff);
+  border-radius: 16rpx;
+  padding: 28rpx 0;
+  text-align: center;
+  margin-top: 12rpx;
+  box-shadow: 0 8rpx 20rpx rgba(93, 85, 232, 0.3);
+}
+.search-button-text {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #ffffff;
+}
+.history-tip {
+  font-size: 24rpx;
+  color: #9ca2b5;
+  line-height: 1.6;
 }
 .history-search-button {
   width: 80rpx;

+ 63 - 69
dist/dev/mp-weixin/pages/transaction/transaction.js

@@ -1,9 +1,16 @@
 "use strict";
 const common_vendor = require("../../common/vendor.js");
+const utils_auth = require("../../utils/auth.js");
+require("../../utils/api.js");
 const _sfc_main = {
   __name: "transaction",
   setup(__props) {
-    const transactions = common_vendor.ref([]);
+    const subscriptions = common_vendor.ref([]);
+    const isLoggedIn = common_vendor.ref(false);
+    const checkLogin = () => {
+      isLoggedIn.value = utils_auth.isLoggedIn();
+      console.log("[订阅记录] 登录状态:", isLoggedIn.value);
+    };
     const handleBack = () => {
       const pages = getCurrentPages();
       if (pages.length > 1) {
@@ -14,90 +21,77 @@ const _sfc_main = {
         });
       }
     };
-    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 formatDateTime = (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 `${hours}:${minutes}`;
+      return `${year}-${month}-${day} ${hours}:${minutes}`;
     };
-    const loadTransactions = () => {
+    const loadSubscriptions = () => {
       try {
-        const storedTransactions = common_vendor.index.getStorageSync("simulated_transactions") || [];
-        transactions.value = storedTransactions.sort((a, b) => b.timestamp - a.timestamp);
+        const now = Date.now();
+        const allSubscriptions = [];
+        const poolPurchase = common_vendor.index.getStorageSync("pool_purchase");
+        if (poolPurchase) {
+          allSubscriptions.push({
+            poolType: "pool",
+            poolName: "超短精选池",
+            planName: poolPurchase.plan === "daily" ? "日订阅" : "周套餐",
+            amount: poolPurchase.plan === "daily" ? "18" : "98",
+            purchaseTime: poolPurchase.purchaseTime,
+            expireTime: poolPurchase.expireTime,
+            isActive: now < poolPurchase.expireTime
+          });
+        }
+        const strongPurchase = common_vendor.index.getStorageSync("strong_pool_purchase");
+        if (strongPurchase) {
+          allSubscriptions.push({
+            poolType: "strong",
+            poolName: "强势趋势池",
+            planName: "年订阅",
+            amount: "98",
+            purchaseTime: strongPurchase.purchaseTime,
+            expireTime: strongPurchase.expireTime,
+            isActive: now < strongPurchase.expireTime
+          });
+        }
+        subscriptions.value = allSubscriptions.sort((a, b) => b.purchaseTime - a.purchaseTime);
       } catch (e) {
-        console.error("加载交易记录失败:", e);
-        transactions.value = [];
+        console.error("加载订阅记录失败:", e);
+        subscriptions.value = [];
       }
     };
+    common_vendor.onLoad(() => {
+      checkLogin();
+    });
     common_vendor.onMounted(() => {
-      loadTransactions();
+      loadSubscriptions();
+    });
+    common_vendor.onShow(() => {
+      checkLogin();
+      loadSubscriptions();
     });
     return (_ctx, _cache) => {
       return common_vendor.e({
         a: common_vendor.o(handleBack),
-        b: common_vendor.f(common_vendor.unref(groupedTransactions), (group, dateKey, i0) => {
+        b: common_vendor.f(subscriptions.value, (item, index, 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
+            a: common_vendor.t(item.poolType === "pool" ? "⚡" : "📈"),
+            b: common_vendor.t(item.poolName),
+            c: common_vendor.t(item.isActive ? "生效中" : "已过期"),
+            d: common_vendor.n(item.isActive ? "status-active" : "status-expired"),
+            e: common_vendor.t(item.planName),
+            f: common_vendor.t(item.amount),
+            g: common_vendor.t(formatDateTime(item.purchaseTime)),
+            h: common_vendor.t(formatDateTime(item.expireTime)),
+            i: index
           };
         }),
-        c: transactions.value.length === 0
-      }, transactions.value.length === 0 ? {} : {});
+        c: subscriptions.value.length === 0
+      }, subscriptions.value.length === 0 ? {} : {});
     };
   }
 };

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

@@ -1 +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>
+<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="subscription-list data-v-a901d1cb"><view wx:for="{{b}}" wx:for-item="item" wx:key="i" class="subscription-item data-v-a901d1cb"><view class="item-header data-v-a901d1cb"><view class="pool-info data-v-a901d1cb"><text class="pool-icon data-v-a901d1cb">{{item.a}}</text><text class="pool-name data-v-a901d1cb">{{item.b}}</text></view><view class="{{['data-v-a901d1cb', 'status-badge', item.d]}}"><text class="status-text data-v-a901d1cb">{{item.c}}</text></view></view><view class="item-body data-v-a901d1cb"><view class="info-row data-v-a901d1cb"><text class="info-label data-v-a901d1cb">订阅方案:</text><text class="info-value data-v-a901d1cb">{{item.e}}</text></view><view class="info-row data-v-a901d1cb"><text class="info-label data-v-a901d1cb">订阅金额:</text><text class="info-value price data-v-a901d1cb">¥{{item.f}}</text></view><view class="info-row data-v-a901d1cb"><text class="info-label data-v-a901d1cb">购买时间:</text><text class="info-value data-v-a901d1cb">{{item.g}}</text></view><view class="info-row data-v-a901d1cb"><text class="info-label data-v-a901d1cb">到期时间:</text><text class="info-value data-v-a901d1cb">{{item.h}}</text></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>

+ 55 - 80
dist/dev/mp-weixin/pages/transaction/transaction.wxss

@@ -35,111 +35,87 @@
 }
 .title-text.data-v-a901d1cb {
   font-size: 36rpx;
-  font-weight: 800;
-  color: #3F51F7;
-  letter-spacing: 2rpx;
+  font-weight: 600;
+  color: #222222;
 }
 .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;
+.subscription-list.data-v-a901d1cb {
+  padding: 32rpx;
 }
-
-/* 交易项 */
-.transaction-item.data-v-a901d1cb {
+.subscription-item.data-v-a901d1cb {
   background: #ffffff;
+  border-radius: 24rpx;
   padding: 32rpx;
+  margin-bottom: 24rpx;
+  box-shadow: 0 8rpx 24rpx rgba(37, 52, 94, 0.08);
+}
+.item-header.data-v-a901d1cb {
   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;
+  margin-bottom: 24rpx;
+  padding-bottom: 24rpx;
+  border-bottom: 1rpx solid #f1f2f6;
 }
-.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 {
+.pool-info.data-v-a901d1cb {
   display: flex;
   align-items: center;
-  margin-bottom: 8rpx;
 }
-.stock-name.data-v-a901d1cb {
+.pool-icon.data-v-a901d1cb {
+  font-size: 32rpx;
+  margin-right: 12rpx;
+}
+.pool-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 {
+.status-badge.data-v-a901d1cb {
+  padding: 8rpx 20rpx;
+  border-radius: 20rpx;
   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 {
+.status-active.data-v-a901d1cb {
+  background: #e7f7ef;
   color: #3abf81;
 }
-.amount-sell.data-v-a901d1cb {
-  color: #f16565;
+.status-expired.data-v-a901d1cb {
+  background: #f5f5f5;
+  color: #999999;
 }
-.status-badge.data-v-a901d1cb {
-  padding: 4rpx 16rpx;
-  border-radius: 12rpx;
+.status-text.data-v-a901d1cb {
+  font-weight: 500;
 }
-.status-buy.data-v-a901d1cb {
-  background: #e7f7ef;
+.item-body.data-v-a901d1cb {
+  display: flex;
+  flex-direction: column;
+  gap: 16rpx;
 }
-.status-sell.data-v-a901d1cb {
-  background: #ffe7ee;
+.info-row.data-v-a901d1cb {
+  display: flex;
+  align-items: center;
+  font-size: 26rpx;
 }
-.status-text.data-v-a901d1cb {
-  font-size: 22rpx;
-  font-weight: 500;
+.info-label.data-v-a901d1cb {
+  color: #666a7f;
+  min-width: 160rpx;
 }
-.status-buy .status-text.data-v-a901d1cb {
-  color: #3abf81;
+.info-value.data-v-a901d1cb {
+  color: #222222;
+  font-weight: 500;
 }
-.status-sell .status-text.data-v-a901d1cb {
+.info-value.price.data-v-a901d1cb {
   color: #f16565;
+  font-weight: 700;
+  font-size: 28rpx;
 }
 
 /* 空状态 */
@@ -147,26 +123,25 @@
   display: flex;
   flex-direction: column;
   align-items: center;
-  padding: 120rpx 0;
-  background: #ffffff;
-  margin: 0 32rpx;
-  border-radius: 24rpx;
+  justify-content: center;
+  padding: 200rpx 60rpx;
 }
 .empty-icon.data-v-a901d1cb {
   font-size: 120rpx;
   margin-bottom: 32rpx;
-  opacity: 0.5;
 }
 .empty-text.data-v-a901d1cb {
   font-size: 32rpx;
-  color: #666666;
+  font-weight: 600;
+  color: #333333;
   margin-bottom: 16rpx;
-  font-weight: 500;
 }
 .empty-desc.data-v-a901d1cb {
   font-size: 26rpx;
-  color: #9ca2b5;
+  color: #999999;
+  text-align: center;
+  line-height: 1.6;
 }
 .bottom-safe-area.data-v-a901d1cb {
-  height: 40rpx;
+  height: 80rpx;
 }

+ 8 - 0
dist/dev/mp-weixin/utils/api.js

@@ -125,6 +125,14 @@ const searchStocks = (keyword) => {
     data: { keyword }
   });
 };
+const getStockQuotes = (codes) => {
+  return request({
+    url: "/api/stock/fetch",
+    method: "GET",
+    data: { codes }
+  });
+};
+exports.getStockQuotes = getStockQuotes;
 exports.getSuggestions = getSuggestions;
 exports.getUserInfoApi = getUserInfoApi;
 exports.searchStocks = searchStocks;

+ 6 - 6
src/pages/mine/mine.vue

@@ -19,10 +19,10 @@
 
         <!-- 菜单列表 -->
         <view class="menu-list">
-          <view class="menu-item" @click="handleTransactionRecord">
+          <view class="menu-item" @click="handleSubscriptionRecord">
             <view class="menu-left">
               <text class="menu-icon">📝</text>
-              <text class="menu-label">交易记录</text>
+              <text class="menu-label">订阅记录</text>
             </view>
             <text class="menu-arrow">›</text>
           </view>
@@ -126,16 +126,16 @@ const handleLogout = () => {
 }
 
 /**
- * 交易记录
+ * 订阅记录
  */
-const handleTransactionRecord = () => {
+const handleSubscriptionRecord = () => {
   if (!requireLogin(() => {
-    handleTransactionRecord()
+    handleSubscriptionRecord()
   })) {
     return
   }
   
-  // 跳转到交易记录页面
+  // 跳转到订阅记录页面
   uni.navigateTo({
     url: '/pages/transaction/transaction'
   })

+ 128 - 47
src/pages/pool/pool.vue

@@ -57,19 +57,44 @@
             <text class="history-icon">📅</text>
             <text class="history-title">历史股票池回顾</text>
           </view>
-          <view class="history-search-row">
-            <input 
-              class="history-date-input" 
-              type="text" 
-              placeholder="2025年11月20日"
-              v-model="selectedDate"
-              disabled
-            />
-            <view class="history-search-button" @click="onHistorySearch">
-              <text class="search-icon">🔍</text>
-            </view>
+          
+          <!-- 月份区间选择 -->
+          <view class="date-range-row">
+            <picker 
+              mode="date"
+              fields="month"
+              :value="startMonth"
+              @change="onStartMonthChange"
+              class="date-picker-half"
+            >
+              <view class="date-input">
+                <text class="date-text">{{ formatMonth(startMonth) }}</text>
+                <text class="date-icon">📅</text>
+              </view>
+            </picker>
+            
+            <text class="date-separator">至</text>
+            
+            <picker 
+              mode="date"
+              fields="month"
+              :value="endMonth"
+              @change="onEndMonthChange"
+              class="date-picker-half"
+            >
+              <view class="date-input">
+                <text class="date-text">{{ formatMonth(endMonth) }}</text>
+                <text class="date-icon">📅</text>
+              </view>
+            </picker>
+          </view>
+          
+          <!-- 查询按钮 -->
+          <view class="history-search-button-full" @click="onHistorySearch">
+            <text class="search-button-text">🔍 查询历史数据</text>
           </view>
-          <text class="history-tip">请选择一个历史日期,查询当日入池股及次日表现。</text>
+          
+          <text class="history-tip">选择时间区间,查询该期间的入池股票及表现。</text>
         </view>
 
         <!-- 预留底部空间 -->
@@ -161,9 +186,17 @@ const isPurchased = ref(false)
 const showModal = ref(false)
 const showPhoneAuth = ref(false)  // 是否显示手机号授权按钮
 const selectedPlan = ref('daily')
-const selectedDate = ref('2025年11月20日')
+const startMonth = ref('2025-01')  // 开始月份
+const endMonth = ref('2025-11')    // 结束月份
 const isLoggedIn = ref(false)
 
+// 格式化月份显示
+const formatMonth = (monthStr) => {
+  if (!monthStr) return '请选择'
+  const [year, month] = monthStr.split('-')
+  return `${year}年${month}月`
+}
+
 // 检查登录状态
 const checkLogin = () => {
   isLoggedIn.value = checkLoginStatus()
@@ -271,12 +304,45 @@ const handlePurchase = () => {
   })
 }
 
+// 开始月份选择变化
+const onStartMonthChange = (e) => {
+  startMonth.value = e.detail.value
+  console.log('[超短池] 选择开始月份:', startMonth.value)
+}
+
+// 结束月份选择变化
+const onEndMonthChange = (e) => {
+  endMonth.value = e.detail.value
+  console.log('[超短池] 选择结束月份:', endMonth.value)
+}
+
 // 历史查询
 const onHistorySearch = () => {
+  if (!startMonth.value || !endMonth.value) {
+    uni.showToast({
+      title: '请选择开始和结束月份',
+      icon: 'none'
+    })
+    return
+  }
+  
+  // 验证时间区间
+  if (startMonth.value > endMonth.value) {
+    uni.showToast({
+      title: '开始月份不能晚于结束月份',
+      icon: 'none'
+    })
+    return
+  }
+  
+  console.log('[超短池] 查询历史数据区间:', startMonth.value, '至', endMonth.value)
   uni.showToast({
-    title: '历史查询功能开发中',
-    icon: 'none'
+    title: `查询${formatMonth(startMonth.value)}至${formatMonth(endMonth.value)}`,
+    icon: 'none',
+    duration: 2000
   })
+  // TODO: 调用后端API查询历史数据
+  // const response = await getHistoryPoolData(startMonth.value, endMonth.value)
 }
 
 // 使用uni-app生命周期钩子
@@ -485,13 +551,58 @@ onShow(() => {
   align-items: center;
 }
 
-.history-date-input {
+.date-range-row {
+  display: flex;
+  align-items: center;
+  gap: 16rpx;
+  margin-bottom: 24rpx;
+}
+
+.date-picker-half {
   flex: 1;
+}
+
+.date-separator {
+  font-size: 26rpx;
+  color: #666a7f;
+  padding: 0 8rpx;
+}
+
+.date-input {
   background: #f7f8fc;
   border-radius: 12rpx;
-  padding: 24rpx 24rpx;
+  padding: 24rpx;
   font-size: 26rpx;
   color: #222222;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.date-text {
+  flex: 1;
+}
+
+.date-icon {
+  font-size: 28rpx;
+  margin-left: 12rpx;
+}
+
+.history-search-button-full {
+  width: 100%;
+  background: linear-gradient(135deg, #5d55e8, #7568ff);
+  border-radius: 16rpx;
+  padding: 28rpx 0;
+  text-align: center;
+  margin-top: 12rpx;
+  margin-bottom: 24rpx;
+  box-shadow: 0 8rpx 20rpx rgba(93, 85, 232, 0.3);
+}
+
+.search-button-text {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #ffffff;
 }
 
 .history-search-button {
@@ -679,36 +790,6 @@ onShow(() => {
   flex: 1;
 }
 
-.payment-info {
-  display: flex;
-  flex-direction: column;
-  flex: 1;
-}
-
-.points-balance {
-  font-size: 22rpx;
-  color: #9ca2b5;
-  margin-top: 4rpx;
-}
-
-.points-cost {
-  display: flex;
-  align-items: baseline;
-  margin-right: 16rpx;
-}
-
-.points-amount {
-  font-size: 32rpx;
-  font-weight: 700;
-  color: #ff9500;
-}
-
-.points-unit {
-  font-size: 22rpx;
-  color: #ff9500;
-  margin-left: 4rpx;
-}
-
 .payment-check {
   width: 36rpx;
   height: 36rpx;

+ 451 - 8
src/pages/rank/rank.vue

@@ -1,17 +1,223 @@
 <template>
   <view class="page-rank">
-    <view class="empty-content">
-      <view class="empty-icon">🚧</view>
-      <text class="empty-text">功能开发中</text>
-      <text class="empty-desc">敬请期待</text>
+    <scroll-view class="scroll-view" scroll-y>
+      <view class="content-wrapper" :class="{ 'blur-content': !isLoggedIn }">
+        <!-- 股票列表 -->
+        <view v-if="myStocks.length > 0" class="stock-list">
+          <view 
+            v-for="(stock, index) in myStocks" 
+            :key="index"
+            class="stock-card"
+          >
+            <view class="stock-header">
+              <view class="stock-title">
+                <text class="stock-name">{{ stock.name }}</text>
+                <text class="stock-code">{{ stock.code }}</text>
+              </view>
+              <view class="delete-btn" @click="removeStock(index)">
+                <text class="delete-icon">×</text>
+              </view>
+            </view>
+            
+            <view class="stock-body">
+              <!-- 涨跌信息 -->
+              <view class="quote-row">
+                <view class="quote-item">
+                  <text class="quote-label">涨跌额</text>
+                  <text 
+                    class="quote-value" 
+                    :class="getChangeClass(stock.priceChange)"
+                  >{{ stock.priceChange || '--' }}</text>
+                </view>
+                <view class="quote-item">
+                  <text class="quote-label">涨跌幅</text>
+                  <text 
+                    class="quote-value" 
+                    :class="getChangeClass(stock.changePercent)"
+                  >{{ stock.changePercent || '--' }}</text>
+                </view>
+              </view>
+              
+              <view class="info-item">
+                <text class="info-label">添加时间</text>
+                <text class="info-value">{{ formatDate(stock.addTime) }}</text>
+              </view>
+              
+              <!-- 刷新行情按钮 -->
+              <view class="refresh-row">
+                <view class="refresh-btn" @click="refreshQuote(stock, index)">
+                  <text class="refresh-icon">🔄</text>
+                  <text class="refresh-text">刷新行情</text>
+                </view>
+              </view>
+            </view>
+          </view>
+        </view>
+
+        <!-- 空状态 -->
+        <view v-else class="empty-content">
+          <view class="empty-icon">📊</view>
+          <text class="empty-text">暂无收藏股票</text>
+          <text class="empty-desc">在强势池中点击"+"按钮添加股票</text>
+        </view>
+
+        <!-- 底部安全区域 -->
+        <view class="bottom-safe-area"></view>
+      </view>
+    </scroll-view>
+
+    <!-- 未登录遮罩层 -->
+    <view v-if="!isLoggedIn" 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" 
+          @click="goToLogin"
+        >
+          <text>登录</text>
+        </button>
+      </view>
     </view>
   </view>
 </template>
 
 <script setup>
-import { onShow } from '@dcloudio/uni-app'
+import { ref } from 'vue'
+import { onLoad, onShow } from '@dcloudio/uni-app'
+import { isLoggedIn as checkLoginStatus } from '../../utils/auth.js'
+import { getStockQuotes } from '../../utils/api.js'
+
+const isLoggedIn = ref(false)
+const myStocks = ref([])
+
+// 加载我的股票列表
+const loadMyStocks = () => {
+  // 只有登录后才加载股票列表
+  if (!isLoggedIn.value) {
+    myStocks.value = []
+    return
+  }
+  
+  try {
+    const stocks = uni.getStorageSync('my_stocks') || []
+    myStocks.value = stocks
+    console.log('[我的股票] 加载股票列表:', stocks.length, '只')
+  } catch (e) {
+    console.error('加载股票列表失败:', e)
+    myStocks.value = []
+  }
+}
+
+// 跳转到登录页
+const goToLogin = () => {
+  uni.navigateTo({
+    url: '/pages/login/login'
+  })
+}
+
+// 删除股票
+const removeStock = (index) => {
+  uni.showModal({
+    title: '确认删除',
+    content: `确定要删除 ${myStocks.value[index].name} 吗?`,
+    confirmText: '删除',
+    cancelText: '取消',
+    success: (res) => {
+      if (res.confirm) {
+        myStocks.value.splice(index, 1)
+        // 保存到本地存储
+        uni.setStorageSync('my_stocks', myStocks.value)
+        uni.showToast({
+          title: '删除成功',
+          icon: 'success'
+        })
+      }
+    }
+  })
+}
+
+// 刷新单个股票行情
+const refreshQuote = async (stock, index) => {
+  try {
+    uni.showLoading({ title: '刷新中...' })
+    
+    const quoteRes = await getStockQuotes(stock.code)
+    console.log('[我的股票] 行情数据:', quoteRes)
+    
+    if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) {
+      const quoteData = quoteRes.data[0]
+      
+      // 更新股票数据
+      myStocks.value[index].priceChange = quoteData.priceChange
+      myStocks.value[index].changePercent = quoteData.changePercent
+      
+      // 保存到本地存储
+      uni.setStorageSync('my_stocks', myStocks.value)
+      
+      uni.hideLoading()
+      uni.showToast({
+        title: '刷新成功',
+        icon: 'success'
+      })
+    } else {
+      uni.hideLoading()
+      uni.showToast({
+        title: '获取行情失败',
+        icon: 'none'
+      })
+    }
+  } catch (e) {
+    uni.hideLoading()
+    console.error('刷新行情失败:', e)
+    uni.showToast({
+      title: '刷新失败',
+      icon: 'none'
+    })
+  }
+}
+
+// 根据涨跌值返回样式类名
+const getChangeClass = (value) => {
+  if (!value || value === '--') return ''
+  // 判断是否为正数(涨)
+  if (value.startsWith('+') || (value.match(/^[\d.]/) && !value.startsWith('-'))) {
+    return 'change-up'
+  }
+  // 判断是否为负数(跌)
+  if (value.startsWith('-')) {
+    return 'change-down'
+  }
+  return ''
+}
+
+// 格式化日期
+const formatDate = (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}`
+}
+
+onLoad(() => {
+  isLoggedIn.value = checkLoginStatus()
+  console.log('[我的股票] 登录状态:', isLoggedIn.value)
+  console.log('[我的股票] Token:', uni.getStorageSync('user_token'))
+  loadMyStocks()
+})
 
 onShow(() => {
+  isLoggedIn.value = checkLoginStatus()
+  console.log('[我的股票] 登录状态:', isLoggedIn.value)
+  console.log('[我的股票] Token:', uni.getStorageSync('user_token'))
+  loadMyStocks()
   uni.setNavigationBarTitle({ title: '量化交易大师' })
 })
 </script>
@@ -20,17 +226,174 @@ onShow(() => {
 .page-rank {
   display: flex;
   flex-direction: column;
-  align-items: center;
-  justify-content: center;
   background: #f5f6fb;
   height: 100vh;
 }
 
+.scroll-view {
+  flex: 1;
+  height: 0;
+}
+
+.content-wrapper {
+  padding: 32rpx;
+  min-height: 100%;
+}
+
+/* 股票列表 */
+.stock-list {
+  display: flex;
+  flex-direction: column;
+  gap: 24rpx;
+}
+
+.stock-card {
+  background: #ffffff;
+  border-radius: 24rpx;
+  padding: 32rpx;
+  box-shadow: 0 8rpx 24rpx rgba(37, 52, 94, 0.08);
+}
+
+.stock-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 24rpx;
+  padding-bottom: 24rpx;
+  border-bottom: 1rpx solid #f1f2f6;
+}
+
+.stock-title {
+  display: flex;
+  flex-direction: column;
+  gap: 8rpx;
+}
+
+.stock-name {
+  font-size: 34rpx;
+  font-weight: 700;
+  color: #222222;
+}
+
+.stock-code {
+  font-size: 26rpx;
+  color: #5d55e8;
+  font-weight: 500;
+}
+
+.delete-btn {
+  width: 56rpx;
+  height: 56rpx;
+  background: #f16565;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 4rpx 12rpx rgba(241, 101, 101, 0.3);
+}
+
+.delete-icon {
+  font-size: 40rpx;
+  font-weight: 700;
+  color: #ffffff;
+  line-height: 1;
+}
+
+.stock-body {
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+
+.info-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.info-label {
+  font-size: 26rpx;
+  color: #666a7f;
+}
+
+.info-value {
+  font-size: 26rpx;
+  color: #222222;
+  font-weight: 500;
+}
+
+/* 涨跌信息样式 */
+.quote-row {
+  display: flex;
+  justify-content: space-between;
+  gap: 24rpx;
+  margin-bottom: 16rpx;
+  padding: 20rpx;
+  background: #f7f8fc;
+  border-radius: 16rpx;
+}
+
+.quote-item {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.quote-label {
+  font-size: 24rpx;
+  color: #666a7f;
+  margin-bottom: 8rpx;
+}
+
+.quote-value {
+  font-size: 32rpx;
+  font-weight: 700;
+  color: #222222;
+}
+
+/* 涨(红色) */
+.change-up {
+  color: #f16565 !important;
+}
+
+/* 跌(绿色) */
+.change-down {
+  color: #3abf81 !important;
+}
+
+/* 刷新按钮 */
+.refresh-row {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 16rpx;
+}
+
+.refresh-btn {
+  display: flex;
+  align-items: center;
+  gap: 8rpx;
+  padding: 12rpx 20rpx;
+  background: #f7f8fc;
+  border-radius: 20rpx;
+}
+
+.refresh-icon {
+  font-size: 24rpx;
+}
+
+.refresh-text {
+  font-size: 24rpx;
+  color: #666a7f;
+}
+
+/* 空状态 */
 .empty-content {
   display: flex;
   flex-direction: column;
   align-items: center;
-  padding: 100rpx 60rpx;
+  justify-content: center;
+  padding: 200rpx 60rpx;
 }
 
 .empty-icon {
@@ -48,5 +411,85 @@ onShow(() => {
 .empty-desc {
   font-size: 26rpx;
   color: #999999;
+  text-align: center;
+  line-height: 1.6;
+}
+
+.bottom-safe-area {
+  height: 80rpx;
+}
+
+/* 模糊效果 */
+.blur-content {
+  filter: blur(8rpx);
+  pointer-events: none;
+}
+
+/* 登录遮罩层 */
+.login-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.4);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 999;
+}
+
+.login-prompt {
+  width: 560rpx;
+  max-width: 560rpx;
+  background: #ffffff;
+  border-radius: 24rpx;
+  padding: 50rpx 40rpx;
+  margin: 0 auto;
+  text-align: center;
+  box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
+  box-sizing: border-box;
+}
+
+.lock-icon {
+  font-size: 72rpx;
+  margin-bottom: 20rpx;
+}
+
+.prompt-title {
+  display: block;
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #222222;
+  margin-bottom: 12rpx;
+}
+
+.prompt-desc {
+  display: block;
+  font-size: 24rpx;
+  color: #999999;
+  line-height: 1.5;
+  margin-bottom: 32rpx;
+}
+
+.login-button-native {
+  width: 100%;
+  height: 80rpx;
+  background: linear-gradient(135deg, #4CAF50, #66BB6A);
+  color: #ffffff;
+  border-radius: 40rpx;
+  font-size: 30rpx;
+  font-weight: 600;
+  box-shadow: 0 8rpx 24rpx rgba(76, 175, 80, 0.4);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: none;
+  padding: 0;
+  line-height: 80rpx;
+}
+
+.login-button-native::after {
+  border: none;
 }
 </style>

+ 243 - 33
src/pages/strong/strong.vue

@@ -53,10 +53,10 @@
               </view>
               <view class="stock-right">
                 <view class="stock-actions">
-                  <view class="action-btn buy-btn">
+                  <view class="action-btn buy-btn" @click="addToMyStocks(stock)">
                     <text class="action-icon">+</text>
                   </view>
-                  <view class="action-btn sell-btn">
+                  <view class="action-btn sell-btn" @click="removeFromMyStocks(stock)">
                     <text class="action-icon">-</text>
                   </view>
                 </view>
@@ -71,18 +71,44 @@
             <text class="history-icon">📅</text>
             <text class="history-title">历史趋势池回顾</text>
           </view>
-          <view class="history-search-row">
-            <input 
-              class="history-date-input" 
-              type="text" 
-              placeholder="2025年11月20日"
-              v-model="selectedDate"
-              disabled
-            />
-            <view class="history-search-button" @click="onHistorySearch">
-              <text class="search-icon">🔍</text>
-            </view>
+          
+          <!-- 月份区间选择 -->
+          <view class="date-range-row">
+            <picker 
+              mode="date"
+              fields="month"
+              :value="startMonth"
+              @change="onStartMonthChange"
+              class="date-picker-half"
+            >
+              <view class="date-input">
+                <text class="date-text">{{ formatMonth(startMonth) }}</text>
+                <text class="date-icon">📅</text>
+              </view>
+            </picker>
+            
+            <text class="date-separator">至</text>
+            
+            <picker 
+              mode="date"
+              fields="month"
+              :value="endMonth"
+              @change="onEndMonthChange"
+              class="date-picker-half"
+            >
+              <view class="date-input">
+                <text class="date-text">{{ formatMonth(endMonth) }}</text>
+                <text class="date-icon">📅</text>
+              </view>
+            </picker>
+          </view>
+          
+          <!-- 查询按钮 -->
+          <view class="history-search-button-full" @click="onHistorySearch">
+            <text class="search-button-text">🔍 查询历史数据</text>
           </view>
+          
+          <text class="history-tip">选择时间区间,查询该期间的入池股票及表现。</text>
         </view>
 
         <!-- 预留底部空间 -->
@@ -104,7 +130,7 @@
           >
             <view class="option-info">
               <text class="option-title">年订阅</text>
-              <text class="option-desc">连续查看</text>
+              <text class="option-desc">365天连续查看</text>
             </view>
             <text class="option-price">¥98</text>
           </view>
@@ -139,13 +165,12 @@
 import { ref } from 'vue'
 import { onLoad, onShow } from '@dcloudio/uni-app'
 import { isLoggedIn as checkLoginStatus } from '../../utils/auth.js'
+import { getStockQuotes } from '../../utils/api.js'
 
-// 登录状态
-const isLoggedIn = ref(false)
 // 购买状态
 const isPurchased = ref(false)
 const showModal = ref(false)
-const selectedPlan = ref('monthly')
+const selectedPlan = ref('yearly')
 
 // 股票列表数据
 const stockList = ref([
@@ -163,16 +188,16 @@ const stockList = ref([
   }
 ])
 
-const selectedDate = ref('2025年11月20日')
+const startMonth = ref('2025-01')  // 开始月份
+const endMonth = ref('2025-11')    // 结束月份
 
-// 检查登录状态(不弹窗提示)
-const checkLogin = () => {
-  isLoggedIn.value = checkLoginStatus()
-  console.log('[强势池] 登录状态:', isLoggedIn.value)
-  return isLoggedIn.value
+// 格式化月份显示
+const formatMonth = (monthStr) => {
+  if (!monthStr) return '请选择'
+  const [year, month] = monthStr.split('-')
+  return `${year}年${month}月`
 }
 
-// 检查购买状态
 // 检查购买状态
 const checkPurchaseStatus = () => {
   try {
@@ -242,9 +267,9 @@ const handlePurchase = () => {
   const now = Date.now()
   let expireTime = now
   
-  if (selectedPlan.value === 'monthly') {
-    // 月订阅:30天后过期
-    expireTime = now + 30 * 24 * 60 * 60 * 1000
+  if (selectedPlan.value === 'yearly') {
+    // 年订阅:365天后过期
+    expireTime = now + 365 * 24 * 60 * 60 * 1000
   }
 
   // 保存购买信息
@@ -275,21 +300,156 @@ const goToLogin = () => {
   })
 }
 
+// 开始月份选择变化
+const onStartMonthChange = (e) => {
+  startMonth.value = e.detail.value
+  console.log('[强势池] 选择开始月份:', startMonth.value)
+}
+
+// 结束月份选择变化
+const onEndMonthChange = (e) => {
+  endMonth.value = e.detail.value
+  console.log('[强势池] 选择结束月份:', endMonth.value)
+}
+
 // 历史查询
 const onHistorySearch = () => {
+  if (!startMonth.value || !endMonth.value) {
+    uni.showToast({
+      title: '请选择开始和结束月份',
+      icon: 'none'
+    })
+    return
+  }
+  
+  // 验证时间区间
+  if (startMonth.value > endMonth.value) {
+    uni.showToast({
+      title: '开始月份不能晚于结束月份',
+      icon: 'none'
+    })
+    return
+  }
+  
+  console.log('[强势池] 查询历史数据区间:', startMonth.value, '至', endMonth.value)
   uni.showToast({
-    title: '历史查询功能开发中',
-    icon: 'none'
+    title: `查询${formatMonth(startMonth.value)}至${formatMonth(endMonth.value)}`,
+    icon: 'none',
+    duration: 2000
   })
+  // TODO: 调用后端API查询历史数据
+  // const response = await getHistoryPoolData(startMonth.value, endMonth.value)
+}
+
+// 添加到我的股票
+const addToMyStocks = async (stock) => {
+  try {
+    // 获取现有的股票列表
+    const myStocks = uni.getStorageSync('my_stocks') || []
+    
+    // 检查是否已存在
+    const exists = myStocks.some(item => item.code === stock.code)
+    if (exists) {
+      uni.showToast({
+        title: '该股票已在列表中',
+        icon: 'none'
+      })
+      return
+    }
+    
+    // 显示加载提示
+    uni.showLoading({ title: '获取行情...' })
+    
+    // 获取股票实时行情数据
+    let priceChange = null
+    let changePercent = null
+    try {
+      const quoteRes = await getStockQuotes(stock.code)
+      console.log('[强势池] 行情数据:', quoteRes)
+      
+      if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) {
+        const quoteData = quoteRes.data[0]
+        priceChange = quoteData.priceChange
+        changePercent = quoteData.changePercent
+      }
+    } catch (e) {
+      console.error('获取行情数据失败:', e)
+    }
+    
+    uni.hideLoading()
+    
+    // 添加新股票(包含行情数据)
+    myStocks.push({
+      name: stock.name,
+      code: stock.code,
+      priceChange: priceChange,
+      changePercent: changePercent,
+      addTime: Date.now()
+    })
+    
+    // 保存到本地存储
+    uni.setStorageSync('my_stocks', myStocks)
+    
+    uni.showToast({
+      title: '添加成功',
+      icon: 'success'
+    })
+  } catch (e) {
+    uni.hideLoading()
+    console.error('添加股票失败:', e)
+    uni.showToast({
+      title: '添加失败',
+      icon: 'none'
+    })
+  }
+}
+
+// 从我的股票中移除
+const removeFromMyStocks = (stock) => {
+  try {
+    // 获取现有的股票列表
+    let myStocks = uni.getStorageSync('my_stocks') || []
+    
+    // 查找股票
+    const index = myStocks.findIndex(item => item.code === stock.code)
+    if (index === -1) {
+      uni.showToast({
+        title: '该股票不在列表中',
+        icon: 'none'
+      })
+      return
+    }
+    
+    // 移除股票
+    myStocks.splice(index, 1)
+    
+    // 保存到本地存储
+    uni.setStorageSync('my_stocks', myStocks)
+    
+    uni.showToast({
+      title: '移除成功',
+      icon: 'success'
+    })
+  } catch (e) {
+    console.error('移除股票失败:', e)
+    uni.showToast({
+      title: '移除失败',
+      icon: 'none'
+    })
+  }
 }
 
 onLoad(() => {
-  // 页面加载时检查购买状态
+  // 页面加载时检查登录状态和购买状态
+  const loginStatus = checkLoginStatus()
+  console.log('[强势池] 登录状态:', loginStatus)
   checkPurchaseStatus()
 })
 
 onShow(() => {
-  // 页面显示时检查购买状态(从登录页返回时会触发)
+  // 页面显示时检查登录状态和购买状态(从登录页返回时会触发)
+  const loginStatus = checkLoginStatus()
+  console.log('[强势池] 登录状态:', loginStatus)
   checkPurchaseStatus()
   // 设置导航栏标题
   uni.setNavigationBarTitle({ title: '量化交易大师' })
@@ -517,13 +677,63 @@ onShow(() => {
   align-items: center;
 }
 
-.history-date-input {
+.date-range-row {
+  display: flex;
+  align-items: center;
+  gap: 16rpx;
+  margin-bottom: 24rpx;
+}
+
+.date-picker-half {
   flex: 1;
+}
+
+.date-separator {
+  font-size: 26rpx;
+  color: #666a7f;
+  padding: 0 8rpx;
+}
+
+.date-input {
   background: #f7f8fc;
   border-radius: 12rpx;
-  padding: 24rpx 24rpx;
+  padding: 24rpx;
   font-size: 26rpx;
   color: #222222;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.date-text {
+  flex: 1;
+}
+
+.date-icon {
+  font-size: 28rpx;
+  margin-left: 12rpx;
+}
+
+.history-search-button-full {
+  width: 100%;
+  background: linear-gradient(135deg, #5d55e8, #7568ff);
+  border-radius: 16rpx;
+  padding: 28rpx 0;
+  text-align: center;
+  margin-top: 12rpx;
+  box-shadow: 0 8rpx 20rpx rgba(93, 85, 232, 0.3);
+}
+
+.search-button-text {
+  font-size: 28rpx;
+  font-weight: 600;
+  color: #ffffff;
+}
+
+.history-tip {
+  font-size: 24rpx;
+  color: #9ca2b5;
+  line-height: 1.6;
 }
 
 .history-search-button {

+ 154 - 181
src/pages/transaction/transaction.vue

@@ -6,49 +6,55 @@
         <text class="back-icon">←</text>
       </view>
       <view class="navbar-title">
-        <text class="title-text">交易记录</text>
+        <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 groupedTransactions" :key="dateKey" class="date-group">
-          <view class="date-header">
-            <text class="date-text">{{ dateKey }}</text>
+      <view class="subscription-list">
+        <!-- 订阅记录项 -->
+        <view 
+          v-for="(item, index) in subscriptions" 
+          :key="index"
+          class="subscription-item"
+        >
+          <view class="item-header">
+            <view class="pool-info">
+              <text class="pool-icon">{{ item.poolType === 'pool' ? '⚡' : '📈' }}</text>
+              <text class="pool-name">{{ item.poolName }}</text>
+            </view>
+            <view :class="['status-badge', item.isActive ? 'status-active' : 'status-expired']">
+              <text class="status-text">{{ item.isActive ? '生效中' : '已过期' }}</text>
+            </view>
           </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.stockName }}</text>
-                <text class="stock-code">{{ item.stockCode }}</text>
-              </view>
-              <text class="transaction-time">{{ formatTime(item.timestamp) }}</text>
+          <view class="item-body">
+            <view class="info-row">
+              <text class="info-label">订阅方案:</text>
+              <text class="info-value">{{ item.planName }}</text>
+            </view>
+            <view class="info-row">
+              <text class="info-label">订阅金额:</text>
+              <text class="info-value price">¥{{ item.amount }}</text>
             </view>
-            
-            <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="info-row">
+              <text class="info-label">购买时间:</text>
+              <text class="info-value">{{ formatDateTime(item.purchaseTime) }}</text>
+            </view>
+            <view class="info-row">
+              <text class="info-label">到期时间:</text>
+              <text class="info-value">{{ formatDateTime(item.expireTime) }}</text>
             </view>
           </view>
         </view>
 
         <!-- 空状态 -->
-        <view v-if="transactions.length === 0" class="empty-state">
+        <view v-if="subscriptions.length === 0" class="empty-state">
           <text class="empty-icon">📋</text>
-          <text class="empty-text">暂无交易记录</text>
-          <text class="empty-desc">开始您的模拟交易之旅吧</text>
+          <text class="empty-text">暂无订阅记录</text>
+          <text class="empty-desc">前往超短池或强势池订阅服务</text>
         </view>
 
         <!-- 底部安全区域 -->
@@ -60,8 +66,17 @@
 
 <script setup>
 import { ref, computed, onMounted } from 'vue'
+import { onLoad, onShow } from '@dcloudio/uni-app'
+import { isLoggedIn as checkLoginStatus } from '../../utils/auth.js'
+
+const subscriptions = ref([])
+const isLoggedIn = ref(false)
 
-const transactions = ref([])
+// 检查登录状态
+const checkLogin = () => {
+  isLoggedIn.value = checkLoginStatus()
+  console.log('[订阅记录] 登录状态:', isLoggedIn.value)
+}
 
 // 返回上一页
 const handleBack = () => {
@@ -77,83 +92,71 @@ const handleBack = () => {
   }
 }
 
-// 按日期分组的交易记录
-const groupedTransactions = 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 = 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 formatDateTime = (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 `${hours}:${minutes}`
+  return `${year}-${month}-${day} ${hours}:${minutes}`
 }
 
-// 加载交易记录
-const loadTransactions = () => {
+// 加载订阅记录
+const loadSubscriptions = () => {
   try {
-    const storedTransactions = uni.getStorageSync('simulated_transactions') || []
-    // 按时间倒序排列
-    transactions.value = storedTransactions.sort((a, b) => b.timestamp - a.timestamp)
+    const now = Date.now()
+    const allSubscriptions = []
+    
+    // 加载超短池订阅记录
+    const poolPurchase = uni.getStorageSync('pool_purchase')
+    if (poolPurchase) {
+      allSubscriptions.push({
+        poolType: 'pool',
+        poolName: '超短精选池',
+        planName: poolPurchase.plan === 'daily' ? '日订阅' : '周套餐',
+        amount: poolPurchase.plan === 'daily' ? '18' : '98',
+        purchaseTime: poolPurchase.purchaseTime,
+        expireTime: poolPurchase.expireTime,
+        isActive: now < poolPurchase.expireTime
+      })
+    }
+    
+    // 加载强势池订阅记录
+    const strongPurchase = uni.getStorageSync('strong_pool_purchase')
+    if (strongPurchase) {
+      allSubscriptions.push({
+        poolType: 'strong',
+        poolName: '强势趋势池',
+        planName: '年订阅',
+        amount: '98',
+        purchaseTime: strongPurchase.purchaseTime,
+        expireTime: strongPurchase.expireTime,
+        isActive: now < strongPurchase.expireTime
+      })
+    }
+    
+    // 按购买时间倒序排列
+    subscriptions.value = allSubscriptions.sort((a, b) => b.purchaseTime - a.purchaseTime)
   } catch (e) {
-    console.error('加载交易记录失败:', e)
-    transactions.value = []
+    console.error('加载订阅记录失败:', e)
+    subscriptions.value = []
   }
 }
 
+onLoad(() => {
+  checkLogin()
+})
+
 onMounted(() => {
-  loadTransactions()
+  loadSubscriptions()
+})
+
+onShow(() => {
+  checkLogin()
+  loadSubscriptions()
 })
 </script>
 
@@ -198,132 +201,103 @@ onMounted(() => {
 
 .title-text {
   font-size: 36rpx;
-  font-weight: 800;
-  color: #3F51F7;
-  letter-spacing: 2rpx;
+  font-weight: 600;
+  color: #222222;
 }
 
 .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;
+.subscription-list {
+  padding: 32rpx;
 }
 
-/* 交易项 */
-.transaction-item {
+.subscription-item {
   background: #ffffff;
+  border-radius: 24rpx;
   padding: 32rpx;
+  margin-bottom: 24rpx;
+  box-shadow: 0 8rpx 24rpx rgba(37, 52, 94, 0.08);
+}
+
+.item-header {
   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;
+  margin-bottom: 24rpx;
+  padding-bottom: 24rpx;
+  border-bottom: 1rpx solid #f1f2f6;
 }
 
-.item-left {
-  flex: 1;
+.pool-info {
   display: flex;
-  flex-direction: column;
+  align-items: center;
 }
 
-.stock-info {
-  display: flex;
-  align-items: center;
-  margin-bottom: 8rpx;
+.pool-icon {
+  font-size: 32rpx;
+  margin-right: 12rpx;
 }
 
-.stock-name {
+.pool-name {
   font-size: 30rpx;
   font-weight: 600;
   color: #222222;
-  margin-right: 12rpx;
 }
 
-.stock-code {
-  font-size: 24rpx;
-  color: #9ca2b5;
-}
-
-.transaction-time {
+.status-badge {
+  padding: 8rpx 20rpx;
+  border-radius: 20rpx;
   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 {
+.status-active {
+  background: #e7f7ef;
   color: #3abf81;
 }
 
-.amount-sell {
-  color: #f16565;
+.status-expired {
+  background: #f5f5f5;
+  color: #999999;
 }
 
-.status-badge {
-  padding: 4rpx 16rpx;
-  border-radius: 12rpx;
+.status-text {
+  font-weight: 500;
 }
 
-.status-buy {
-  background: #e7f7ef;
+.item-body {
+  display: flex;
+  flex-direction: column;
+  gap: 16rpx;
 }
 
-.status-sell {
-  background: #ffe7ee;
+.info-row {
+  display: flex;
+  align-items: center;
+  font-size: 26rpx;
 }
 
-.status-text {
-  font-size: 22rpx;
-  font-weight: 500;
+.info-label {
+  color: #666a7f;
+  min-width: 160rpx;
 }
 
-.status-buy .status-text {
-  color: #3abf81;
+.info-value {
+  color: #222222;
+  font-weight: 500;
 }
 
-.status-sell .status-text {
+.info-value.price {
   color: #f16565;
+  font-weight: 700;
+  font-size: 28rpx;
 }
 
 /* 空状态 */
@@ -331,31 +305,30 @@ onMounted(() => {
   display: flex;
   flex-direction: column;
   align-items: center;
-  padding: 120rpx 0;
-  background: #ffffff;
-  margin: 0 32rpx;
-  border-radius: 24rpx;
+  justify-content: center;
+  padding: 200rpx 60rpx;
 }
 
 .empty-icon {
   font-size: 120rpx;
   margin-bottom: 32rpx;
-  opacity: 0.5;
 }
 
 .empty-text {
   font-size: 32rpx;
-  color: #666666;
+  font-weight: 600;
+  color: #333333;
   margin-bottom: 16rpx;
-  font-weight: 500;
 }
 
 .empty-desc {
   font-size: 26rpx;
-  color: #9ca2b5;
+  color: #999999;
+  text-align: center;
+  line-height: 1.6;
 }
 
 .bottom-safe-area {
-  height: 40rpx;
+  height: 80rpx;
 }
 </style>

+ 13 - 0
src/utils/api.js

@@ -230,3 +230,16 @@ export const getLeaderboard = () => {
   })
 }
 
+/**
+ * 获取股票实时行情数据(涨跌额、涨跌幅)
+ * @param {string} codes - 股票代码,多个用逗号分隔
+ * @returns {Promise} 返回股票行情数据列表
+ */
+export const getStockQuotes = (codes) => {
+  return request({
+    url: '/api/stock/fetch',
+    method: 'GET',
+    data: { codes }
+  })
+}
+

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików