Selaa lähdekoodia

今日工作12.9 接口联调 1,邀请中心及邀请好友分享页面 2,首页-热门理财 3,ICO,认购,配售 4,C2C,商家列表 页面修改 1,邀请中心 2,交易-币币

jhaoG 3 viikkoa sitten
vanhempi
sitoutus
8e8724faab

+ 17 - 0
src/api/index.js

@@ -41,3 +41,20 @@ export function TradingPair(id) {
     },
   });
 }
+
+// 获取理财产品
+export function GetWealthProducts(params) {
+  return request({
+    url: "/wealth/products/",
+    method: "get",
+    params,
+  });
+}
+
+// ICO
+export function GetIcoIco() {
+  return request({
+    url: "/ico/ico/",
+    method: "get",
+  });
+}

+ 19 - 0
src/api/otc.js

@@ -0,0 +1,19 @@
+import request from "@/utils/request";
+
+// 挂单列表
+export function GetOTCPendingOrder(params) {
+  return request({
+    url: "/otc/otc_pending_order/",
+    method: "get",
+    params,
+  });
+}
+
+// 添加银行卡
+export function AddBankManager(params) {
+  return request({
+    url: "/custom/bank_manager/",
+    method: "post",
+    params,
+  });
+}

+ 10 - 0
src/api/user.js

@@ -0,0 +1,10 @@
+import request from "@/utils/request";
+
+// 邀请推广
+export function getInviteInfo(data) {
+  return request({
+    url: "/custom/custom/get_invite_info",
+    method: "post",
+    data,
+  });
+}

BIN
src/assets/icon/user/copy.png


BIN
src/assets/icon/user/gift.png


+ 1 - 1
src/router/index.js

@@ -224,7 +224,7 @@ const routes = [
     component: () => import("@/views/user/InviteCenter.vue"), // 上面的组件
   },
   {
-    path: "/invite/poster",
+    path: "/invite/poster/:code",
     name: "InvitePoster",
     component: () => import("@/views/user/InvitePoster.vue"),
   },

+ 43 - 43
src/utils/request.js

@@ -1,83 +1,83 @@
 /* src/utils/request.js */
-import axios from 'axios'
+import axios from "axios";
 // 如果你用了 Vant UI,可以把下面这行解开,用来弹窗提示错误
-import { showToast, showFailToast } from 'vant';
-import 'vant/es/toast/style';
+import { showToast, showFailToast } from "vant";
+import "vant/es/toast/style";
 
 // 1. 创建 axios 实例
 const service = axios.create({
   // 基础 URL,通常在 .env 文件中配置 VUE_APP_BASE_API
-  baseURL: process.env.VUE_APP_BASE_API || '/api', 
+  baseURL: process.env.VUE_APP_BASE_API || "/api",
   // 请求超时时间 (毫秒),交易类应用建议设置短一点,比如 10秒
-  timeout: 10000, 
+  timeout: 10000,
   headers: {
-    'Content-Type': 'application/json;charset=utf-8'
-  }
-})
+    "Content-Type": "application/json;charset=utf-8",
+  },
+});
 
 // 2. 请求拦截器 (Request Interceptor)
 // 在发送请求之前做些什么,比如加 Token
 service.interceptors.request.use(
-  config => {
+  (config) => {
     // 假设你的 token 存在 localStorage 里
-    const token = localStorage.getItem('token')
-    
+    const token = localStorage.getItem("token");
+
     if (token) {
       // 让每个请求携带自定义 token 请根据实际情况修改
-      // 例如:config.headers['Authorization'] = 'Bearer ' + token
-      config.headers['token'] = token 
+      config.headers["Authorization"] = "JWT " + token;
+      // config.headers["token"] = token;
     }
-    return config
+    return config;
   },
-  error => {
+  (error) => {
     // 对请求错误做些什么
-    console.log(error) 
-    return Promise.reject(error)
+    console.log(error);
+    return Promise.reject(error);
   }
-)
+);
 
 // 3. 响应拦截器 (Response Interceptor)
 // 对响应数据做点什么
 service.interceptors.response.use(
-  response => {
-    const res = response.data
-    
+  (response) => {
+    const res = response.data;
+
     // 这里根据后端返回的状态码来判断请求是否成功
     // 假设后端约定 code === 00000 为成功
     if (res.code !== "00000") {
       // 如果不是 200,说明业务逻辑有错,比如“余额不足”
-      
+
       // showFailToast(res.msg || 'Error') // 如果用了 Vant,可以用这个提示
-      console.error('业务报错:', res.msg)
+      console.error("业务报错:", res.msg);
 
       // 特殊处理:比如 401 表示 Token 过期,需要跳回登录页
       if (res.code === 401) {
         //以此处逻辑为准:清除本地数据,强制刷新或跳转
-        localStorage.removeItem('token')
-        location.reload()
+        localStorage.removeItem("token");
+        location.reload();
       }
-      
-      return Promise.reject(new Error(res.msg || 'Error'))
+
+      return Promise.reject(new Error(res.msg || "Error"));
     } else {
       // 成功,直接把数据剥离出来
-      return res.data
+      return res.data;
     }
   },
-  error => {
-    console.log('网络报错' + error) // for debug
-    let message = error.message
-    
-    if (message === 'Network Error') {
-      message = '后端接口连接异常'
-    } else if (message.includes('timeout')) {
-      message = '系统接口请求超时'
-    } else if (message.includes('Request failed with status code')) {
-      message = '系统接口' + message.substr(message.length - 3) + '异常'
+  (error) => {
+    console.log("网络报错" + error); // for debug
+    let message = error.message;
+
+    if (message === "Network Error") {
+      message = "后端接口连接异常";
+    } else if (message.includes("timeout")) {
+      message = "系统接口请求超时";
+    } else if (message.includes("Request failed with status code")) {
+      message = "系统接口" + message.substr(message.length - 3) + "异常";
     }
-    
-    showFailToast(message)
-    return Promise.reject(error)
+
+    showFailToast(message);
+    return Promise.reject(error);
   }
-)
+);
 
-export default service
+export default service;

+ 4 - 4
src/views/asset/Index.vue

@@ -28,21 +28,21 @@
     <div class="asset-money">
       <div class="money-item" @click="goRecharge">
         <div class="item-img">
-          <img src="../../assets/img/index/Rectangle 8.svg" />
+          <img src="@/assets/icon/usercenter/chongbi.png" />
         </div>
         <div class="pf400 fs14 fc666666">充币</div>
         <img src="../../assets/icon/asset/divider.svg" alt="" class="divider-img" />
       </div>
       <div class="money-item" @click="goWithdraw">
         <div class="item-img">
-          <img src="../../assets/img/index/Rectangle 9.svg" />
+          <img src="@/assets/icon/usercenter/tibi.png" />
         </div>
         <div class="pf400 fs14 fc666666">提币</div>
         <img src="../../assets/icon/asset/divider.svg" alt="" class="divider-img" />
       </div>
       <div class="money-item" @click="goTransfer">
         <div class="item-img">
-          <img src="../../assets/img/index/user/huazhuan.svg" />
+          <img src="@/assets/icon/usercenter/huazhuan.png" />
         </div>
         <div class="pf400 fs14 fc666666">划转</div>
       </div>
@@ -74,7 +74,7 @@
         <div class="details-item" v-for="(item, index) in 2" :key="index">
           <div class="item-name">
             <div class="name-left">
-              <img src="../../assets/icon/coin/bnb.svg" alt="" class="left-coin" />
+              <img src="../../assets/icon/coin/Ethereum.png" alt="" class="left-coin" />
               <div class="name-area">
                 <div class="pf500 fs16 fc121212">BTC/USDT 永续</div>
                 <div class="name-flag">

+ 1 - 1
src/views/asset/otc/Index.vue

@@ -63,7 +63,7 @@
     .footer-tabbar {
       position: fixed;
       left: 15px;
-      bottom: 37px;
+      bottom: 10px;
       z-index: 99;
       display: flex;
       justify-content: space-around;

+ 0 - 1
src/views/asset/otc/order/All.vue

@@ -180,7 +180,6 @@
       flex-direction: row;
       justify-content: space-between;
       margin-top: 10px;
-      width: 345px;
       height: 38px;
 
       .kefu {

+ 41 - 4
src/views/asset/otc/transaction/AddBankAccount.vue

@@ -4,25 +4,41 @@
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">持卡人姓名</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="name" />
       </div>
     </div>
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">手机号</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="phone" />
       </div>
     </div>
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">开户行</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="bankOfDeposit" />
       </div>
     </div>
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">银行卡号</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="bankNumber" />
       </div>
     </div>
     <div class="submit pf600 fs14 fcFFFFFF" @click="submit">提交</div>
@@ -30,6 +46,27 @@
 </template>
 <script setup>
   import HeaderNav from "../../../index/components/HeaderNav.vue";
+  import { AddBankManager } from "@/api/otc";
+  import { ref } from "vue";
+
+  const name = ref();
+  const phone = ref();
+  const bankOfDeposit = ref();
+  const bankNumber = ref();
+
+  const submit = async () => {
+    const params = {
+      name: name.value,
+      phone: phone.value,
+      open_bank: bankOfDeposit.value,
+      card_number: bankNumber.value,
+    };
+    const data = await AddBankManager(params);
+    if (data) {
+      // 差一个跳转到购买的页面
+      console.log(data);
+    }
+  };
 </script>
 <style lang="less" scoped>
   .add-zfb-account {

+ 49 - 11
src/views/asset/otc/transaction/C2C.vue

@@ -31,42 +31,53 @@
     </div>
   </div>
   <div class="goods-area">
-    <div class="goods-item" v-for="(item, index) in 2" :key="index">
+    <div class="goods-item" v-for="(item, index) in OTCPendingOrderData" :key="index">
       <div class="item-merchant">
         <div class="merchant-left" @click="goMerchantDetails">
           <img src="@/assets/img/index/user/default-head.png" alt="" />
-          <div class="left-name pf500 fs14 fc2C3131">商家昵称</div>
-          <div class="vip-flag pf500 fs10 fcDF384C">V2</div>
+          <div class="left-name pf500 fs14 fc2C3131">{{ item.otc_name }}</div>
+          <div class="vip-flag pf500 fs10 fcDF384C">{{ item.otc_level }}</div>
         </div>
         <div class="merchant-right pf400 fs10 fc999999">
-          入驻时间: 2025-11-07 12:25:10
+          入驻时间: {{ item.otc_create_time }}
         </div>
       </div>
       <div class="item-chengjiao-number pf400 fs10 fc999999">
-        成交量 12550 · 98.95% 成交率
+        成交量 {{ item.order_info.total }} · {{ item.order_info.rate }} 成交率
       </div>
       <div class="item-price">
         <div class="price-area">
           <div class="text pf400 fs10 fc999999">单价</div>
           <div class="price-number pf400 fs10 fc999999">
-            <span class="pf500 fs16 fc333333">6.58</span>
+            <span class="pf500 fs16 fc333333">{{ Number(item.price).toFixed(2) }}</span>
             /USDT
           </div>
           <div class="number pf400 fs10 fc999999">
-            数量 <span class="pf400 fs12 fc666666">1000.05 USDT</span>
+            数量
+            <span class="pf400 fs12 fc666666"
+              >{{ Number(item.left_count).toFixed(2) }} USDT</span
+            >
           </div>
           <div class="number pf400 fs10 fc999999">
-            限额 <span class="pf400 fs12 fc666666">20000 - 1000.05 CNY</span>
+            限额
+            <span class="pf400 fs12 fc666666">
+              {{ Number(item.min_limit).toFixed(2) }} -
+              {{ Number(item.max_limit).toFixed(2) }} CNY</span
+            >
           </div>
         </div>
         <div class="price-func">
           <div class="func-time pf400 fs10 fc999999">
-            <img src="@/assets/icon/asset/clock-gray.svg" alt="" />0m 45s
+            <img src="@/assets/icon/asset/clock-gray.svg" alt="" />
+            {{ item.order_info.avg_time }}
           </div>
           <div class="func-pay-way pf400 fs10 fc999999">
             <div class="color"></div>
-            银行卡
+            <!-- 1.银行卡 2.支付宝 3.微信 -->
+            <div v-if="item.pay_type == 1">银行卡</div>
+            <div v-if="item.pay_type == 2">支付宝</div>
+            <div v-if="item.pay_type == 3">微信</div>
           </div>
           <div class="func-main">
             <div class="func-chat pf500 fs12 fcDF384C">聊天</div>
@@ -100,8 +111,9 @@
   </div>
 </template>
 <script setup>
-  import { ref } from "vue";
+  import { ref, onMounted } from "vue";
   import { useRoute, useRouter } from "vue-router";
+  import { GetOTCPendingOrder } from "@/api/otc";
   import PaymentWay from "../../dialog/NotPaymentWay.vue";
   import Amount from "../../dialog/Amount.vue";
   import Filter from "../../dialog/Filter.vue";
@@ -117,6 +129,30 @@
     router.push("/OTCMerchantDetails");
   };
 
+  const OTCPendingOrderData = ref();
+  const GetOTCPendingOrderData = async () => {
+    const params = {
+      order_type: "1",
+      trans_type: "1",
+      coin_type: "",
+      price: "",
+      count: "",
+      min_limit: "",
+      min_amount: "",
+      pay_type: "",
+      left_count: "",
+    };
+    const data = await GetOTCPendingOrder(params);
+    if (data) {
+      OTCPendingOrderData.value = data.list;
+      console.log(1, data.list);
+    }
+  };
+
+  onMounted(() => {
+    GetOTCPendingOrderData();
+  });
+
   const completePaymentFlag = ref(false);
   const completePaymentClose = () => {
     completePaymentFlag.value = false;
@@ -303,6 +339,8 @@
   }
 
   .goods-area {
+    margin-top: 10px;
+    margin-bottom: 30px;
     width: 345px;
 
     .goods-item {

+ 520 - 288
src/views/bitcoin/Calculator.vue

@@ -3,7 +3,7 @@
     <div class="nav-bar">
       <div class="nav-left" @click="$router.back()">
         <div>
-          <VanIcon size="18" name="arrow-left"/>
+          <VanIcon size="18" name="arrow-left" />
         </div>
       </div>
       <div class="nav-title">计算器</div>
@@ -24,8 +24,7 @@
           :key="index"
           class="tab-item"
           :class="{ active: currentTab === index }"
-          @click="currentTab = index"
-        >
+          @click="currentTab = index">
           {{ tab }}
           <div class="active-bar" v-if="currentTab === index"></div>
         </div>
@@ -41,22 +40,21 @@
       <button
         class="dir-btn long"
         :class="{ active: direction === 'long' }"
-        @click="direction = 'long'"
-      >
-        买入(做多)
+        @click="direction = 'long'">
+        买入
       </button>
       <button
         class="dir-btn short"
         :class="{ active: direction === 'short' }"
-        @click="direction = 'short'"
-      >
-        卖出(做空)
+        @click="direction = 'short'">
+        卖出
       </button>
     </div>
 
     <div v-if="currentTab === 5" class="funding-rate-display">
       <div class="rate-value">0.0030%</div>
-      <div class="rate-label" @click="hyu">当前资金费率
+      <div class="rate-label" @click="hyu">
+        当前资金费率
         <VanIcon name="question-o" />
       </div>
     </div>
@@ -71,16 +69,10 @@
       </div>
 
       <div class="slider-area">
-        <LeverageSlider
-          v-model="leverage"
-          :marks="leverageMarks"
-          :color="themeColor"
-        />
+        <LeverageSlider v-model="leverage" :marks="leverageMarks" :color="themeColor" />
       </div>
 
-      <div class="leverage-tip">
-        当前杠杆倍数最高可持有头寸 1,800,000,000 USDT
-      </div>
+      <div class="leverage-tip">当前杠杆倍数最高可持有头寸 1,800,000,000 USDT</div>
     </div>
 
     <div class="form-group">
@@ -165,8 +157,11 @@
           <div class="input-container half">
             <input type="number" v-model="item.amount" placeholder="0.00" />
           </div>
-          <div style="display: flex; align-items: center;">
-            <div class="remove-btn" @click="removeRow(idx)" v-if="avgPriceList.length > 1">
+          <div style="display: flex; align-items: center">
+            <div
+              class="remove-btn"
+              @click="removeRow(idx)"
+              v-if="avgPriceList.length > 1">
               <span>-</span>
             </div>
           </div>
@@ -197,9 +192,15 @@
       <p class="sub-text">实际市场存在变动,计算价格仅供参考</p>
 
       <div v-if="currentTab === 0">
-        <div class="res-row"><span>保证金</span><span>{{ result.margin }} USDT</span></div>
-        <div class="res-row"><span>收益</span><span :class="resultClass">{{ result.pnl }} USDT</span></div>
-        <div class="res-row"><span>收益率</span><span :class="resultClass">{{ result.roe }}%</span></div>
+        <div class="res-row">
+          <span>保证金</span><span>{{ result.margin }} USDT</span>
+        </div>
+        <div class="res-row">
+          <span>收益</span><span :class="resultClass">{{ result.pnl }} USDT</span>
+        </div>
+        <div class="res-row">
+          <span>收益率</span><span :class="resultClass">{{ result.roe }}%</span>
+        </div>
       </div>
 
       <div v-if="currentTab === 1">
@@ -227,280 +228,511 @@
 
     <div class="footer-btns">
       <button class="btn-reset" @click="reset">重置</button>
-      <button class="btn-calc" :style="{ background: themeColor }" @click="calculate">计算</button>
+      <button class="btn-calc" :style="{ background: themeColor }" @click="calculate">
+        计算
+      </button>
     </div>
     <div>
-      <ProfitAndLossPrompt
-          v-model:visible="showModal"
-      ></ProfitAndLossPrompt>
+      <ProfitAndLossPrompt v-model:visible="showModal"></ProfitAndLossPrompt>
     </div>
   </div>
 </template>
 
 <script setup>
-import { Icon as VanIcon } from 'vant';
-import {ref, computed, defineAsyncComponent} from 'vue';
-// 请确保路径正确,指向刚才那个更新过的子组件
-const LeverageSlider = defineAsyncComponent(()=>import('./calculator/LeverageSlider.vue'));
-const ProfitAndLossPrompt = defineAsyncComponent(() => import('./calculator/FundingRateReminder.vue'));
-
-//资金费率提示
-const showModal = ref(false);
-const hyu = () => {
-  console.log("kkkkkkk")
-  showModal.value = true;
-}
-
-// 状态定义
-const tabs = ['收益', '目标价格', '强平价格', '可开', '开仓均价', '资金费用'];
-const currentTab = ref(0);
-const direction = ref('long');
-const leverage = ref(10); // 默认从 10x 开始
-
-// ★ 固定阶梯数组 (10, 50, 100, 500, 1000)
-const leverageMarks = [10, 50, 100, 500, 1000];
-
-const form = ref({
-  entryPrice: '',
-  closePrice: '',
-  amount: '',
-  margin: '',
-  balance: '',
-  pnl: ''
-});
-
-const avgPriceList = ref([{ price: '', amount: '' }, { price: '', amount: '' }]);
-const result = ref({ margin: '--', pnl: '--', roe: '--' });
-
-// 计算属性
-const themeColor = computed(() => direction.value === 'long' ? '#2ebd85' : '#f6465d');
-const resultClass = computed(() => {
-  if (parseFloat(result.value.pnl) > 0) return 'text-green';
-  if (parseFloat(result.value.pnl) < 0) return 'text-red';
-  return '';
-});
-
-// ★ 核心修改:步进式调整杠杆 (点击加减号时)
-const stepLeverage = (dir) => {
-  // 1. 找到当前值在数组中的索引
-  let currentIndex = leverageMarks.indexOf(leverage.value);
-
-  // 如果当前值不在数组里(比如手动改成了20),就找一个最近的索引
-  if (currentIndex === -1) {
-    // 简单逻辑:默认归位到 0
-    currentIndex = 0;
-  }
-
-  // 2. 计算下一个索引
-  let nextIndex = currentIndex + dir;
-
-  // 3. 边界限制
-  if (nextIndex < 0) nextIndex = 0;
-  if (nextIndex >= leverageMarks.length) nextIndex = leverageMarks.length - 1;
-
-  // 4. 更新值
-  leverage.value = leverageMarks[nextIndex];
-};
-
-// 简单计算逻辑 (Tab 0 收益)
-const calculate = () => {
-  if (currentTab.value === 0) {
-    const entry = parseFloat(form.value.entryPrice);
-    const close = parseFloat(form.value.closePrice);
-    const amt = parseFloat(form.value.amount);
-    const lev = leverage.value;
-
-    if (entry && close && amt && lev) {
-      const margin = (entry * amt) / lev;
-      let pnl = 0;
-      if (direction.value === 'long') {
-        pnl = (close - entry) * amt;
-      } else {
-        pnl = (entry - close) * amt;
-      }
-      const roe = (pnl / margin) * 100;
-
-      result.value = {
-        margin: margin.toFixed(2),
-        pnl: pnl.toFixed(2),
-        roe: roe.toFixed(2)
-      };
+  import { Icon as VanIcon } from "vant";
+  import { ref, computed, defineAsyncComponent } from "vue";
+  // 请确保路径正确,指向刚才那个更新过的子组件
+  const LeverageSlider = defineAsyncComponent(() =>
+    import("./calculator/LeverageSlider.vue")
+  );
+  const ProfitAndLossPrompt = defineAsyncComponent(() =>
+    import("./calculator/FundingRateReminder.vue")
+  );
+
+  //资金费率提示
+  const showModal = ref(false);
+  const hyu = () => {
+    console.log("kkkkkkk");
+    showModal.value = true;
+  };
+
+  // 状态定义
+  const tabs = ["收益", "目标价格", "强平价格", "可开", "开仓均价", "资金费用"];
+  const currentTab = ref(0);
+  const direction = ref("long");
+  const leverage = ref(10); // 默认从 10x 开始
+
+  // ★ 固定阶梯数组 (10, 50, 100, 500, 1000)
+  const leverageMarks = [10, 50, 100, 500, 1000];
+
+  const form = ref({
+    entryPrice: "",
+    closePrice: "",
+    amount: "",
+    margin: "",
+    balance: "",
+    pnl: "",
+  });
+
+  const avgPriceList = ref([
+    { price: "", amount: "" },
+    { price: "", amount: "" },
+  ]);
+  const result = ref({ margin: "--", pnl: "--", roe: "--" });
+
+  // 计算属性
+  const themeColor = computed(() => (direction.value === "long" ? "#2ebd85" : "#f6465d"));
+  const resultClass = computed(() => {
+    if (parseFloat(result.value.pnl) > 0) return "text-green";
+    if (parseFloat(result.value.pnl) < 0) return "text-red";
+    return "";
+  });
+
+  // ★ 核心修改:步进式调整杠杆 (点击加减号时)
+  const stepLeverage = (dir) => {
+    // 1. 找到当前值在数组中的索引
+    let currentIndex = leverageMarks.indexOf(leverage.value);
+
+    // 如果当前值不在数组里(比如手动改成了20),就找一个最近的索引
+    if (currentIndex === -1) {
+      // 简单逻辑:默认归位到 0
+      currentIndex = 0;
     }
-  }
-};
 
-// 其他辅助函数
-const addRow = () => avgPriceList.value.push({ price: '', amount: '' });
-const removeRow = (idx) => avgPriceList.value.splice(idx, 1);
-const reset = () => {
-  form.value = { entryPrice: '', closePrice: '', amount: '', margin: '', balance: '', pnl: '' };
-  result.value = { margin: '--', pnl: '--', roe: '--' };
-  leverage.value = 10;
-};
+    // 2. 计算下一个索引
+    let nextIndex = currentIndex + dir;
+
+    // 3. 边界限制
+    if (nextIndex < 0) nextIndex = 0;
+    if (nextIndex >= leverageMarks.length) nextIndex = leverageMarks.length - 1;
+
+    // 4. 更新值
+    leverage.value = leverageMarks[nextIndex];
+  };
+
+  // 简单计算逻辑 (Tab 0 收益)
+  const calculate = () => {
+    if (currentTab.value === 0) {
+      const entry = parseFloat(form.value.entryPrice);
+      const close = parseFloat(form.value.closePrice);
+      const amt = parseFloat(form.value.amount);
+      const lev = leverage.value;
+
+      if (entry && close && amt && lev) {
+        const margin = (entry * amt) / lev;
+        let pnl = 0;
+        if (direction.value === "long") {
+          pnl = (close - entry) * amt;
+        } else {
+          pnl = (entry - close) * amt;
+        }
+        const roe = (pnl / margin) * 100;
+
+        result.value = {
+          margin: margin.toFixed(2),
+          pnl: pnl.toFixed(2),
+          roe: roe.toFixed(2),
+        };
+      }
+    }
+  };
+
+  // 其他辅助函数
+  const addRow = () => avgPriceList.value.push({ price: "", amount: "" });
+  const removeRow = (idx) => avgPriceList.value.splice(idx, 1);
+  const reset = () => {
+    form.value = {
+      entryPrice: "",
+      closePrice: "",
+      amount: "",
+      margin: "",
+      balance: "",
+      pnl: "",
+    };
+    result.value = { margin: "--", pnl: "--", roe: "--" };
+    leverage.value = 10;
+  };
 </script>
 
 <style scoped>
-* {
-  box-sizing: border-box;
-}
-
-.calculator-page {
-  font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
-  background: #fff;
-  min-height: 100vh;
-  /* 这里的 padding-bottom: 90px 很重要,为了防止底部内容被固定的 footer 遮挡,保留它 */
-  padding-bottom: 90px;
-  color: #333;
-  z-index: 200;
-
-  /* 删掉了 position: fixed/top/left */
-
-  display: flex;
-  flex-direction: column;
-  width: 100%;
-}
-/* 导航 & 头部 */
-.nav-bar { display: flex; justify-content: space-between; align-items: center;
-  height: 44px; padding: 0 16px;
-  /* 新增以下 3 行,实现吸顶效果 */
-  position: sticky;
-  top: 0;
-  background: #fff; /* 防止透明背景导致内容重叠 */
-  z-index: 100;
-}
-.nav-left { font-size: 24px; cursor: pointer; }
-.nav-title { font-size: 18px; font-weight: 600; }
-.nav-right { width: 20px; }
-
-.header-info {
-  display: flex;
-  align-items: center;
-  padding: 0px 15px;
-  background-color: #fff;
-  width: 100%;
-}
-
-.icon-wrapper {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 24px;
-  height: 24px;
-  margin-bottom: 1px;
-}
-
-.pair-name {
-  margin: 0;
-  font-size: 18px;
-  font-weight: bold;
-  color: #333;
-  line-height: 1;
-}
-
-/* Tabs */
-.tabs-wrapper { overflow-x: auto; scrollbar-width: none; margin-bottom: 15px; }
-.tabs-content { display: flex; justify-content: space-between; padding: 0 15px;
-  border-bottom: 1px solid #f5f5f5; }
-.tab-item { white-space: nowrap; padding: 12px 0; font-size: 14px; color: #999; position: relative;
-  cursor: pointer; }
-.tab-item.active { color: #111; font-weight: 600; }
-.active-bar { position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 20px;
-  height: 3px; background: #111; border-radius: 2px; }
-
-/* 模式选择 */
-.mode-selectors { display: flex; gap: 10px; padding: 0 16px; margin-bottom: 15px; }
-.select-box { flex: 1; background: #f5f5f5; height: 36px; display: flex; align-items: center;
-  padding: 0 12px; border-radius: 4px; font-size: 14px; color: #333; }
-
-/* 做多做空 */
-.trade-direction { display: flex; gap: 10px; padding: 0 16px; margin-bottom: 20px; }
-.dir-btn { flex: 1; padding: 10px 0; border: none; border-radius: 4px; font-size: 14px;
-  cursor: pointer; background: #f5f5f5; color: #999; transition: all 0.2s; }
-.dir-btn.long.active { background: #2ebd85; color: #fff; font-weight: 600; }
-.dir-btn.short.active { background: #f6465d; color: #fff; font-weight: 600; }
-
-/* 资金费率 */
-.funding-rate-display { text-align: center; padding: 20px 0; }
-.rate-value { font-size: 32px; color: #666; font-weight: 500; }
-.rate-label { font-size: 12px; color: #999; margin-top: 5px; }
-
-/* 杠杆区域 */
-.leverage-section { padding: 0 16px; margin-bottom: 20px; }
-.label { font-size: 12px; color: #666; margin-bottom: 8px; }
-
-/* 蓝色边框输入框 */
-.leverage-control {
-  display: flex;
-  align-items: center;
-  background: #f7f8fa;
-  border-radius: 6px;
-  height: 44px;
-  margin-bottom: 10px;
-  overflow: hidden;
-}
-.ctrl-btn {
-  width: 50px;
-  height: 100%;
-  border: none;
-  background: transparent;
-  font-size: 22px;
-  color: #999;
-  cursor: pointer;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  padding-bottom: 4px;
-}
-.leverage-val {
-  flex: 1;
-  text-align: center;
-  font-size: 16px;
-  font-weight: 500;
-  color: #333;
-}
-.slider-area { padding: 0 10px; }
-.leverage-tip { font-size: 12px; color: #333; margin-top: 10px; }
-
-/* 表单 */
-.form-group { padding: 0 16px; }
-.input-row { margin-bottom: 12px; }
-.input-container { position: relative; display: flex; align-items: center; background: #f5f5f5;
-  height: 44px; border-radius: 4px; padding: 0 12px; }
-.placeholder { position: absolute; color: #bbb; font-size: 14px; pointer-events: none; }
-.input-container input { flex: 1; border: none; background: transparent; outline: none;
-  font-size: 14px; z-index: 1; height: 100%; width: 100%; }
-.suffix { font-size: 14px; color: #666; margin-left: 8px; z-index: 2; white-space: nowrap; }
-.tag-latest { color: #f6465d; margin-left: 4px; }
-
-/* 表格布局 */
-.grid-header { display: flex; font-size: 12px; color: #333; margin-bottom: 8px; }
-.grid-header span { flex: 1; }
-.dynamic-row { display: flex; gap: 10px; margin-bottom: 10px; align-items: center; }
-.input-container.half { flex: 1; }
-.remove-btn { width: 24px; height: 24px; border: 1px solid #f6465d; color: #f6465d;
-  border-radius: 50%; display: flex; align-items: center; justify-content: center;
-  font-size: 18px; cursor: pointer; margin-left: 5px; }
-.remove-btn span { margin-bottom: 5px; }
-.add-position-btn { width: 100%; height: 44px; background: #f6465d; color: white;
-  border: none; border-radius: 22px; margin-top: 10px; font-size: 14px; }
-
-/* 结果 */
-.result-section { padding: 20px 16px; }
-.result-section h3 { margin: 0 0 5px; font-size: 16px; font-weight: 600; }
-.sub-text { font-size: 12px; color: #999; margin-bottom: 15px; }
-.res-row { display: flex; justify-content: space-between; margin-bottom: 12px; font-size: 14px; }
-.res-row span:first-child { color: #666; }
-.res-row span:last-child { color: #333; font-weight: 500; }
-.text-green { color: #2ebd85; }
-.text-red { color: #f6465d; }
-.small-tip { font-size: 12px; color: #999; margin-top: 5px; }
-
-/* 底部按钮 */
-.footer-btns { position: fixed; bottom: 0; left: 0; width: 100%; background: #fff;
-  padding: 10px 16px 20px; display: flex; gap: 15px; box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
-  box-sizing: border-box; z-index: 100; }
-.btn-reset { flex: 1; height: 44px; border: none; background: #bbb; color: #fff;
-  font-size: 16px; border-radius: 4px; }
-.btn-calc { flex: 2; height: 44px; border: none; color: #fff; font-size: 16px;
-  border-radius: 4px; font-weight: 600; transition: background 0.3s; }
-</style>
+  * {
+    box-sizing: border-box;
+  }
+
+  .calculator-page {
+    font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
+    background: #fff;
+    min-height: 100vh;
+    /* 这里的 padding-bottom: 90px 很重要,为了防止底部内容被固定的 footer 遮挡,保留它 */
+    padding-bottom: 90px;
+    color: #333;
+    z-index: 200;
+
+    /* 删掉了 position: fixed/top/left */
+
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+  }
+  /* 导航 & 头部 */
+  .nav-bar {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 44px;
+    padding: 0 16px;
+    /* 新增以下 3 行,实现吸顶效果 */
+    position: sticky;
+    top: 0;
+    background: #fff; /* 防止透明背景导致内容重叠 */
+    z-index: 100;
+  }
+  .nav-left {
+    font-size: 24px;
+    cursor: pointer;
+  }
+  .nav-title {
+    font-size: 18px;
+    font-weight: 600;
+  }
+  .nav-right {
+    width: 20px;
+  }
+
+  .header-info {
+    display: flex;
+    align-items: center;
+    padding: 0px 15px;
+    background-color: #fff;
+    width: 100%;
+  }
+
+  .icon-wrapper {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 24px;
+    height: 24px;
+    margin-bottom: 1px;
+  }
+
+  .pair-name {
+    margin: 0;
+    font-size: 18px;
+    font-weight: bold;
+    color: #333;
+    line-height: 1;
+  }
+
+  /* Tabs */
+  .tabs-wrapper {
+    overflow-x: auto;
+    scrollbar-width: none;
+    margin-bottom: 15px;
+  }
+  .tabs-content {
+    display: flex;
+    justify-content: space-between;
+    padding: 0 15px;
+    border-bottom: 1px solid #f5f5f5;
+  }
+  .tab-item {
+    white-space: nowrap;
+    padding: 12px 0;
+    font-size: 14px;
+    color: #999;
+    position: relative;
+    cursor: pointer;
+  }
+  .tab-item.active {
+    color: #111;
+    font-weight: 600;
+  }
+  .active-bar {
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 20px;
+    height: 3px;
+    background: #111;
+    border-radius: 2px;
+  }
+
+  /* 模式选择 */
+  .mode-selectors {
+    display: flex;
+    gap: 10px;
+    padding: 0 16px;
+    margin-bottom: 15px;
+  }
+  .select-box {
+    flex: 1;
+    background: #f5f5f5;
+    height: 36px;
+    display: flex;
+    align-items: center;
+    padding: 0 12px;
+    border-radius: 4px;
+    font-size: 14px;
+    color: #333;
+  }
+
+  /* 做多做空 */
+  .trade-direction {
+    display: flex;
+    gap: 10px;
+    padding: 0 16px;
+    margin-bottom: 20px;
+  }
+  .dir-btn {
+    flex: 1;
+    padding: 10px 0;
+    border: none;
+    border-radius: 4px;
+    font-size: 14px;
+    cursor: pointer;
+    background: #f5f5f5;
+    color: #999;
+    transition: all 0.2s;
+  }
+  .dir-btn.long.active {
+    background: #2ebd85;
+    color: #fff;
+    font-weight: 600;
+  }
+  .dir-btn.short.active {
+    background: #f6465d;
+    color: #fff;
+    font-weight: 600;
+  }
+
+  /* 资金费率 */
+  .funding-rate-display {
+    text-align: center;
+    padding: 20px 0;
+  }
+  .rate-value {
+    font-size: 32px;
+    color: #666;
+    font-weight: 500;
+  }
+  .rate-label {
+    font-size: 12px;
+    color: #999;
+    margin-top: 5px;
+  }
+
+  /* 杠杆区域 */
+  .leverage-section {
+    padding: 0 16px;
+    margin-bottom: 20px;
+  }
+  .label {
+    font-size: 12px;
+    color: #666;
+    margin-bottom: 8px;
+  }
+
+  /* 蓝色边框输入框 */
+  .leverage-control {
+    display: flex;
+    align-items: center;
+    background: #f7f8fa;
+    border-radius: 6px;
+    height: 44px;
+    margin-bottom: 10px;
+    overflow: hidden;
+  }
+  .ctrl-btn {
+    width: 50px;
+    height: 100%;
+    border: none;
+    background: transparent;
+    font-size: 22px;
+    color: #999;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding-bottom: 4px;
+  }
+  .leverage-val {
+    flex: 1;
+    text-align: center;
+    font-size: 16px;
+    font-weight: 500;
+    color: #333;
+  }
+  .slider-area {
+    padding: 0 10px;
+  }
+  .leverage-tip {
+    font-size: 12px;
+    color: #333;
+    margin-top: 10px;
+  }
+
+  /* 表单 */
+  .form-group {
+    padding: 0 16px;
+  }
+  .input-row {
+    margin-bottom: 12px;
+  }
+  .input-container {
+    position: relative;
+    display: flex;
+    align-items: center;
+    background: #f5f5f5;
+    height: 44px;
+    border-radius: 4px;
+    padding: 0 12px;
+  }
+  .placeholder {
+    position: absolute;
+    color: #bbb;
+    font-size: 14px;
+    pointer-events: none;
+  }
+  .input-container input {
+    flex: 1;
+    border: none;
+    background: transparent;
+    outline: none;
+    font-size: 14px;
+    z-index: 1;
+    height: 100%;
+    width: 100%;
+  }
+  .suffix {
+    font-size: 14px;
+    color: #666;
+    margin-left: 8px;
+    z-index: 2;
+    white-space: nowrap;
+  }
+  .tag-latest {
+    color: #f6465d;
+    margin-left: 4px;
+  }
+
+  /* 表格布局 */
+  .grid-header {
+    display: flex;
+    font-size: 12px;
+    color: #333;
+    margin-bottom: 8px;
+  }
+  .grid-header span {
+    flex: 1;
+  }
+  .dynamic-row {
+    display: flex;
+    gap: 10px;
+    margin-bottom: 10px;
+    align-items: center;
+  }
+  .input-container.half {
+    flex: 1;
+  }
+  .remove-btn {
+    width: 24px;
+    height: 24px;
+    border: 1px solid #f6465d;
+    color: #f6465d;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 18px;
+    cursor: pointer;
+    margin-left: 5px;
+  }
+  .remove-btn span {
+    margin-bottom: 5px;
+  }
+  .add-position-btn {
+    width: 100%;
+    height: 44px;
+    background: #f6465d;
+    color: white;
+    border: none;
+    border-radius: 22px;
+    margin-top: 10px;
+    font-size: 14px;
+  }
+
+  /* 结果 */
+  .result-section {
+    padding: 20px 16px;
+  }
+  .result-section h3 {
+    margin: 0 0 5px;
+    font-size: 16px;
+    font-weight: 600;
+  }
+  .sub-text {
+    font-size: 12px;
+    color: #999;
+    margin-bottom: 15px;
+  }
+  .res-row {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 12px;
+    font-size: 14px;
+  }
+  .res-row span:first-child {
+    color: #666;
+  }
+  .res-row span:last-child {
+    color: #333;
+    font-weight: 500;
+  }
+  .text-green {
+    color: #2ebd85;
+  }
+  .text-red {
+    color: #f6465d;
+  }
+  .small-tip {
+    font-size: 12px;
+    color: #999;
+    margin-top: 5px;
+  }
+
+  /* 底部按钮 */
+  .footer-btns {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    background: #fff;
+    padding: 10px 16px 20px;
+    display: flex;
+    gap: 15px;
+    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
+    box-sizing: border-box;
+    z-index: 100;
+  }
+  .btn-reset {
+    flex: 1;
+    height: 44px;
+    border: none;
+    background: #bbb;
+    color: #fff;
+    font-size: 16px;
+    border-radius: 4px;
+  }
+  .btn-calc {
+    flex: 2;
+    height: 44px;
+    border: none;
+    color: #fff;
+    font-size: 16px;
+    border-radius: 4px;
+    font-weight: 600;
+    transition: background 0.3s;
+  }
+</style>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 8
src/views/bitcoin/lever/CryptocurrencyTrading.vue


+ 348 - 306
src/views/bitcoin/lever/components/UserAssetsPanel.vue

@@ -5,38 +5,47 @@
         <div
           class="tab-item"
           :class="{ active: activeTab === 'assets' }"
-          @click="activeTab = 'assets'"
-        >
+          @click="activeTab = 'assets'">
           币种资产
         </div>
         <div
           class="tab-item"
           :class="{ active: activeTab === 'positions' }"
-          @click="activeTab = 'positions'"
-        >
-          持有仓位({{ positionsList.length }})
+          @click="activeTab = 'positions'">
+          <!-- 持有仓位({{ positionsList.length }}) -->
+          持有仓位
         </div>
         <div
           class="tab-item"
           :class="{ active: activeTab === 'orders' }"
-          @click="activeTab = 'orders'"
-        >
-          当前委托({{ ordersList.length }})
+          @click="activeTab = 'orders'">
+          <!-- 当前委托({{ ordersList.length }}) -->
+          当前委托
         </div>
       </div>
       <div class="tabs-right" @click="router.push('/historyIndex')">
         <span class="history-icon">
-          <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
-          <path d="M17.025 10.125L15.5254 8.625L14.025 10.125M15.75 9C15.75 12.7279 12.7279 15.75 9 15.75C5.27208 15.75 2.25 12.7279 2.25 9C2.25 5.27208 5.27208 2.25 9 2.25C11.4764 2.25 13.6414 3.5836 14.8159 5.57182M9 5.25V9L11.25 10.5" stroke="#A8A8A8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+          <svg
+            width="18"
+            height="18"
+            viewBox="0 0 18 18"
+            fill="none"
+            xmlns="http://www.w3.org/2000/svg">
+            <path
+              d="M17.025 10.125L15.5254 8.625L14.025 10.125M15.75 9C15.75 12.7279 12.7279 15.75 9 15.75C5.27208 15.75 2.25 12.7279 2.25 9C2.25 5.27208 5.27208 2.25 9 2.25C11.4764 2.25 13.6414 3.5836 14.8159 5.57182M9 5.25V9L11.25 10.5"
+              stroke="#A8A8A8"
+              stroke-width="1.5"
+              stroke-linecap="round"
+              stroke-linejoin="round" />
           </svg>
-        </span> 全部
+        </span>
+        全部
       </div>
     </div>
 
     <div class="panel-content">
-
       <div v-if="activeTab === 'assets'" class="list-container">
-        <div v-for="(item, index) in assetsList" :key="index" class="card asset-card">
+        <!-- <div v-for="(item, index) in assetsList" :key="index" class="card asset-card">
           <div class="card-header">
             <div class="coin-info">
               <div class="coin-icon icon-btc">₿</div>
@@ -59,11 +68,11 @@
             <span class="label">冻结</span>
             <span class="value red-text">{{ item.frozen }}</span>
           </div>
-        </div>
+        </div> -->
       </div>
 
       <div v-else-if="activeTab === 'positions'" class="list-container">
-        <div v-for="(item, index) in positionsList" :key="index" class="card position-card">
+        <!-- <div v-for="(item, index) in positionsList" :key="index" class="card position-card">
           <div class="card-header">
             <div class="coin-info">
               <div class="coin-icon icon-btc">₿</div>
@@ -98,11 +107,11 @@
             </div>
           </div>
           <button class="btn-block-red">平仓</button>
-        </div>
+        </div> -->
       </div>
 
       <div v-else-if="activeTab === 'orders'" class="list-container">
-        <div v-for="(item, index) in ordersList" :key="index" class="card order-card">
+        <!-- <div v-for="(item, index) in ordersList" :key="index" class="card order-card">
           <div class="card-header">
             <div class="coin-info">
               <div class="coin-icon icon-btc">₿</div>
@@ -134,319 +143,352 @@
               <div class="val">{{ item.price }} {{ item.unit }}</div>
             </div>
           </div>
-        </div>
+        </div> -->
       </div>
-
     </div>
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
-import { useRouter } from 'vue-router'; // 【新增】 引入路由
-
-const router = useRouter(); // 【新增】 实例化路由
-
-// 当前选中的 Tab:'assets', 'positions', 'orders'
-const activeTab = ref('orders');
-
-// 模拟数据 - 委托
-const ordersList = ref([
-  {
-    pair: 'BTC/USDT',
-    type: 'buy',
-    leverage: 20,
-    amount: '0.215',
-    unit: 'USDT',
-    price: '0.215',
-    time: '2025-11-04, 16:30'
-  },
-  {
-    pair: 'BTC/USDT',
-    type: 'sell',
-    leverage: 20,
-    amount: '0.215',
-    unit: 'USDT',
-    price: '0.215',
-    time: '2025-11-04, 16:30'
-  }
-]);
-
-// 模拟数据 - 仓位
-const positionsList = ref([
-  {
-    pair: 'BTC/USDT',
-    type: 'buy',
-    leverage: 200,
-    amount: '0.215',
-    unit: 'USDT',
-    price: '0.215',
-    time: '2025-11-04, 16:30'
-  },
-  {
-    pair: 'ETH/USDT',
-    type: 'sell',
-    leverage: 50,
-    amount: '1.5',
-    unit: 'USDT',
-    price: '1800.00',
-    time: '2025-11-04, 14:20'
-  }
-]);
-
-// 模拟数据 - 资产
-const assetsList = ref([
-  {
-    symbol: 'BTC',
-    nameCn: '比特币',
-    totalValue: '1,125,158.00',
-    cnyValue: '2150508',
-    available: '18802.0850',
-    frozen: '151.2050'
-  },
-  {
-    symbol: 'BTC', // 重复模拟图3效果
-    nameCn: '比特币',
-    totalValue: '1,125,158.00',
-    cnyValue: '2150508',
-    available: '18802.0850',
-    frozen: '151.2050'
-  }
-]);
+  import { ref } from "vue";
+  import { useRouter } from "vue-router"; // 【新增】 引入路由
+
+  const router = useRouter(); // 【新增】 实例化路由
+
+  // 当前选中的 Tab:'assets', 'positions', 'orders'
+  const activeTab = ref("orders");
+
+  // 模拟数据 - 委托
+  const ordersList = ref([
+    {
+      pair: "BTC/USDT",
+      type: "buy",
+      leverage: 20,
+      amount: "0.215",
+      unit: "USDT",
+      price: "0.215",
+      time: "2025-11-04, 16:30",
+    },
+    {
+      pair: "BTC/USDT",
+      type: "sell",
+      leverage: 20,
+      amount: "0.215",
+      unit: "USDT",
+      price: "0.215",
+      time: "2025-11-04, 16:30",
+    },
+  ]);
+
+  // 模拟数据 - 仓位
+  const positionsList = ref([
+    {
+      pair: "BTC/USDT",
+      type: "buy",
+      leverage: 200,
+      amount: "0.215",
+      unit: "USDT",
+      price: "0.215",
+      time: "2025-11-04, 16:30",
+    },
+    {
+      pair: "ETH/USDT",
+      type: "sell",
+      leverage: 50,
+      amount: "1.5",
+      unit: "USDT",
+      price: "1800.00",
+      time: "2025-11-04, 14:20",
+    },
+  ]);
+
+  // 模拟数据 - 资产
+  const assetsList = ref([
+    {
+      symbol: "BTC",
+      nameCn: "比特币",
+      totalValue: "1,125,158.00",
+      cnyValue: "2150508",
+      available: "18802.0850",
+      frozen: "151.2050",
+    },
+    {
+      symbol: "BTC", // 重复模拟图3效果
+      nameCn: "比特币",
+      totalValue: "1,125,158.00",
+      cnyValue: "2150508",
+      available: "18802.0850",
+      frozen: "151.2050",
+    },
+  ]);
 </script>
 
 <style scoped lang="scss">
-/* 基础变量 */
-$c-bg: #fff;
-$c-white: #ffffff;
-$c-text-main: #333333;
-$c-text-sub: #969799;
-$c-green: #00b86b; /* 买入绿 */
-$c-red: #dc3545;   /* 卖出/撤单红 */
-$c-line: #f5f5f5;
-$c-orange: #f7931a; /* BTC颜色 */
-
-.panel-container {
-  width: 100%;
-  background-color: $c-bg;
-  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Segoe UI, Arial, Roboto, "PingFang SC", "miui", "Hiragino Sans GB", "Microsoft Yahei", sans-serif;
-  padding-bottom: 20px;
-}
-
-/* Tab 头部样式 */
-.tabs-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  background: $c-white;
-  padding: 12px 16px;
-  position: sticky;
-  top: 0;
-  z-index: 10;
-}
-
-.tabs-left {
-  display: flex;
-  gap: 20px;
-}
-
-.tab-item {
-  font-size: 15px;
-  color: $c-text-sub;
-  font-weight: 400;
-  position: relative;
-  cursor: pointer;
-  padding-bottom: 4px;
-  transition: all 0.2s;
-
-  &.active {
-    color: $c-text-main;
-    font-weight: 600;
-    font-size: 16px;
+  /* 基础变量 */
+  $c-bg: #fff;
+  $c-white: #ffffff;
+  $c-text-main: #333333;
+  $c-text-sub: #969799;
+  $c-green: #00b86b; /* 买入绿 */
+  $c-red: #dc3545; /* 卖出/撤单红 */
+  $c-line: #f5f5f5;
+  $c-orange: #f7931a; /* BTC颜色 */
+
+  .panel-container {
+    width: 100%;
+    background-color: $c-bg;
+    font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Segoe UI,
+      Arial, Roboto, "PingFang SC", "miui", "Hiragino Sans GB", "Microsoft Yahei",
+      sans-serif;
+    padding-bottom: 20px;
+  }
+
+  /* Tab 头部样式 */
+  .tabs-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background: $c-white;
+    padding: 12px 16px;
+    position: sticky;
+    top: 0;
+    z-index: 10;
+  }
+
+  .tabs-left {
+    display: flex;
+    gap: 20px;
+  }
 
-    &::after {
-      content: '';
-      position: absolute;
-      bottom: -2px;
-      left: 50%;
-      transform: translateX(-50%);
-      width: 20px;
-      height: 3px;
-      background-color: #000;
-      border-radius: 2px;
+  .tab-item {
+    font-size: 15px;
+    color: $c-text-sub;
+    font-weight: 400;
+    position: relative;
+    cursor: pointer;
+    padding-bottom: 4px;
+    transition: all 0.2s;
+
+    &.active {
+      color: $c-text-main;
+      font-weight: 600;
+      font-size: 16px;
+
+      &::after {
+        content: "";
+        position: absolute;
+        bottom: -2px;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 20px;
+        height: 3px;
+        background-color: #000;
+        border-radius: 2px;
+      }
     }
   }
-}
-
-.tabs-right {
-  font-size: 13px;
-  color: $c-text-sub;
-  display: flex;
-  align-items: flex-start;
-  gap: 4px;
-  margin-top: 2px;
-}
-
-/* 列表容器 */
-.list-container {
-  padding: 10px 16px;
-}
-
-/* 卡片通用样式 */
-.card {
-  background: $c-white;
-  border-radius: 8px;
-  padding: 12px 12px;
-  margin-bottom: 12px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.02);
-  border: 1px solid #ebedf0;
-}
-
-.card-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: flex-start;
-  margin-bottom: 12px;
-}
-
-.coin-info {
-  display: flex;
-  align-items: flex-start;
-}
-
-.coin-icon {
-  width: 36px;
-  height: 36px;
-  border-radius: 50%;
-  background: $c-orange;
-  color: #fff;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 20px;
-  font-weight: bold;
-  margin-right: 10px;
-}
-
-.coin-name-block {
-  display: flex;
-  flex-direction: column;
-  gap: 4px;
-}
-
-.symbol {
-  font-size: 16px;
-  font-weight: 600;
-  color: $c-text-main;
-}
-
-/* 标签样式 */
-.tags-row {
-  display: flex;
-  gap: 4px;
-}
-
-.tag {
-  font-size: 10px;
-  padding: 1px 4px;
-  border-radius: 2px;
-  color: #fff;
-  display: inline-block;
-  line-height: 1.4;
-}
-
-.tag-green { background: $c-green; }
-.tag-red { background: $c-red; }
-.tag-grey { background: #c8c9cc; color: #fff; }
-
-/* 分割线 */
-.divider {
-  height: 1px;
-  background: $c-line;
-  margin: 0 0 12px 0;
-}
-
-/* 数据网格 (三列) */
-.data-grid {
-  display: flex;
-  justify-content: space-between;
-  margin-bottom: 8px;
-}
-
-.data-col {
-  text-align: left;
-
-
-  &.center { text-align: center; width: 50%; }
-  &.right { text-align: right; }
-
-  .label {
-    font-size: 12px;
+
+  .tabs-right {
+    font-size: 13px;
     color: $c-text-sub;
-    margin-bottom: 4px;
+    display: flex;
+    align-items: flex-start;
+    gap: 4px;
+    margin-top: 2px;
   }
-  .val {
-    font-size: 14px;
-    color: $c-text-main;
-    font-weight: 500;
+
+  /* 列表容器 */
+  .list-container {
+    padding: 10px 16px;
+  }
+
+  /* 卡片通用样式 */
+  .card {
+    background: $c-white;
+    border-radius: 8px;
+    padding: 12px 12px;
+    margin-bottom: 12px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
+    border: 1px solid #ebedf0;
   }
-}
-
-/* 按钮样式 */
-.btn-small-red {
-  background: $c-red;
-  color: #fff;
-  border: none;
-  padding: 6px 16px;
-  border-radius: 4px;
-  font-size: 13px;
-}
-
-.btn-block-red {
-  width: 100%;
-  background: $c-red;
-  color: #fff;
-  border: none;
-  padding: 10px 0;
-  border-radius: 20px; /* 圆角按钮 */
-  font-size: 15px;
-  margin-top: 8px;
-  font-weight: 500;
-}
-
-/* 特殊样式:Position 页面的时间 */
-.header-right-time {
-  text-align: right;
-  font-size: 12px;
-  color: $c-text-sub;
-  line-height: 1.4;
-}
-
-/* 特殊样式:Asset 页面 */
-.asset-card {
+
   .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    margin-bottom: 12px;
+  }
+
+  .coin-info {
+    display: flex;
+    align-items: flex-start;
+  }
+
+  .coin-icon {
+    width: 36px;
+    height: 36px;
+    border-radius: 50%;
+    background: $c-orange;
+    color: #fff;
+    display: flex;
     align-items: center;
+    justify-content: center;
+    font-size: 20px;
+    font-weight: bold;
+    margin-right: 10px;
   }
-  .coin-name {
+
+  .coin-name-block {
     display: flex;
     flex-direction: column;
-    .name-cn { font-size: 12px; color: $c-text-sub; }
+    gap: 4px;
   }
-  .asset-total {
-    text-align: right;
-    .main-val { font-size: 18px; font-weight: bold; color: $c-text-main; }
-    .sub-val { font-size: 12px; color: $c-text-sub; margin-top: 2px; }
+
+  .symbol {
+    font-size: 16px;
+    font-weight: 600;
+    color: $c-text-main;
+  }
+
+  /* 标签样式 */
+  .tags-row {
+    display: flex;
+    gap: 4px;
+  }
+
+  .tag {
+    font-size: 10px;
+    padding: 1px 4px;
+    border-radius: 2px;
+    color: #fff;
+    display: inline-block;
+    line-height: 1.4;
   }
-  .card-row {
+
+  .tag-green {
+    background: $c-green;
+  }
+  .tag-red {
+    background: $c-red;
+  }
+  .tag-grey {
+    background: #c8c9cc;
+    color: #fff;
+  }
+
+  /* 分割线 */
+  .divider {
+    height: 1px;
+    background: $c-line;
+    margin: 0 0 12px 0;
+  }
+
+  /* 数据网格 (三列) */
+  .data-grid {
     display: flex;
     justify-content: space-between;
+    margin-bottom: 8px;
+  }
+
+  .data-col {
+    text-align: left;
+
+    &.center {
+      text-align: center;
+      width: 50%;
+    }
+    &.right {
+      text-align: right;
+    }
+
+    .label {
+      font-size: 12px;
+      color: $c-text-sub;
+      margin-bottom: 4px;
+    }
+    .val {
+      font-size: 14px;
+      color: $c-text-main;
+      font-weight: 500;
+    }
+  }
+
+  /* 按钮样式 */
+  .btn-small-red {
+    background: $c-red;
+    color: #fff;
+    border: none;
+    padding: 6px 16px;
+    border-radius: 4px;
     font-size: 13px;
-    margin-bottom: 6px;
-    &:last-child { margin-bottom: 0; }
+  }
+
+  .btn-block-red {
+    width: 100%;
+    background: $c-red;
+    color: #fff;
+    border: none;
+    padding: 10px 0;
+    border-radius: 20px; /* 圆角按钮 */
+    font-size: 15px;
+    margin-top: 8px;
+    font-weight: 500;
+  }
+
+  /* 特殊样式:Position 页面的时间 */
+  .header-right-time {
+    text-align: right;
+    font-size: 12px;
+    color: $c-text-sub;
+    line-height: 1.4;
+  }
 
-    .label { color: $c-text-sub; }
-    .value { color: $c-text-sub; font-family: sans-serif; }
-    .red-text { color: $c-red; font-weight: 500; }
+  /* 特殊样式:Asset 页面 */
+  .asset-card {
+    .card-header {
+      align-items: center;
+    }
+    .coin-name {
+      display: flex;
+      flex-direction: column;
+      .name-cn {
+        font-size: 12px;
+        color: $c-text-sub;
+      }
+    }
+    .asset-total {
+      text-align: right;
+      .main-val {
+        font-size: 18px;
+        font-weight: bold;
+        color: $c-text-main;
+      }
+      .sub-val {
+        font-size: 12px;
+        color: $c-text-sub;
+        margin-top: 2px;
+      }
+    }
+    .card-row {
+      display: flex;
+      justify-content: space-between;
+      font-size: 13px;
+      margin-bottom: 6px;
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .label {
+        color: $c-text-sub;
+      }
+      .value {
+        color: $c-text-sub;
+        font-family: sans-serif;
+      }
+      .red-text {
+        color: $c-red;
+        font-weight: 500;
+      }
+    }
   }
-}
-</style>
+</style>

+ 40 - 6
src/views/index/components/HotFinancial.vue

@@ -3,31 +3,65 @@
   <div class="hot-financial">
     <div class="financial-title pf600 fs18 fc121212">热门理财</div>
     <div class="financial-main">
-      <div class="financial-item" v-for="(item, index) in 2" :key="index">
+      <div
+        class="financial-item"
+        v-for="(item, index) in WealthProductsData"
+        :key="index">
         <div class="item-name pf400 fs12 fc2C3131">
-          <img src="@/assets/icon/coin/bnb.svg" alt="" />理财产品名称
+          <img :src="item.icon" alt="" />
+          {{ item.title }}
         </div>
         <div class="item-info">
           <div class="info-left">
-            <div class="pf400 fs10 fcDF384C">0.23%</div>
+            <div class="pf400 fs10 fcDF384C">
+              {{ Number(item.details[0].daily_rate * 100).toFixed(2) }}%
+            </div>
             <div class="margin-top2 pf400 fs10 fcA8A8A8">收益率</div>
           </div>
           <div class="info-right">
-            <div class="pf400 fs10 fcDF384C">10天</div>
+            <div class="pf400 fs10 fcDF384C">{{ item.details[0].duration_days }}</div>
             <div class="margin-top2 pf400 fs10 fcA8A8A8">理财周期</div>
           </div>
         </div>
         <div class="item-line"></div>
         <div class="item-shouyi pf400 fs10 fcA8A8A8">
           <div>预估每日收益</div>
-          <div>0.2150天</div>
+          <div>
+            <!-- 总数 / 天数 * 日利率 -->
+            {{
+              Number(
+                (item.details[0].amount / item.details[0].duration_days) *
+                  item.details[0].daily_rate
+              ).toFixed(4)
+            }}天
+          </div>
         </div>
         <div class="item-buy pf500 fs10 fcFFFFFF">立即购买</div>
       </div>
     </div>
   </div>
 </template>
-<script setup></script>
+<script setup>
+  import { ref, onMounted } from "vue";
+  import { GetWealthProducts } from "@/api/index";
+
+  const WealthProductsData = ref();
+
+  const getWealthProductsData = async () => {
+    // 是否首页
+    const params = {
+      is_visible: true,
+    };
+    const data = await GetWealthProducts(params);
+    if (data) {
+      WealthProductsData.value = data.list;
+    }
+  };
+
+  onMounted(() => {
+    getWealthProductsData();
+  });
+</script>
 <style lang="less" scoped>
   .hot-financial {
     margin-top: 30px;

+ 27 - 10
src/views/index/ico/Placement.vue

@@ -8,12 +8,11 @@
         <div class="head-operate">操作</div>
       </div>
       <div class="subscription-body">
-        <div
-          class="subscription-item"
-          v-for="(item, index) in subscriptionData"
-          :key="index">
-          <div class="item-name pf400 fs14 fc2C3131">MFEIANS</div>
-          <div class="item-price pf400 fs14 fc2C3131">13.3156</div>
+        <div class="subscription-item" v-for="(item, index) in icoData" :key="index">
+          <div class="item-name pf400 fs14 fc2C3131">{{ item.asset_name }}</div>
+          <div class="item-price pf400 fs14 fc2C3131">
+            {{ Number(item.issue_price).toFixed(2) }}
+          </div>
           <div class="item-operate">
             <div class="text pf500 fs12 fcFFFFFF">配售</div>
           </div>
@@ -29,9 +28,27 @@
   </div>
 </template>
 <script setup>
-  import { ref } from "vue";
+  import { ref, onMounted } from "vue";
+  import { GetIcoIco } from "@/api/index";
+
+  const icoData = ref();
+  const subscriptionData = ref();
+
+  const GetIcoIcoData = async () => {
+    // 1,认购 2,配售
+    const params = {
+      asset_type: "2",
+    };
+    const data = await GetIcoIco(params);
+    if (data) {
+      icoData.value = data.list;
+      subscriptionData.value = data.total;
+    }
+  };
 
-  const subscriptionData = ref(6);
+  onMounted(() => {
+    GetIcoIcoData();
+  });
 </script>
 <style lang="less" scoped>
   .placement {
@@ -80,8 +97,8 @@
           display: flex;
           flex-direction: row;
           justify-content: flex-start;
-          margin-top: 13px;
-          padding-bottom: 13px;
+          margin-top: 8px;
+          padding-bottom: 8px;
           width: 100%;
           border-bottom: 1px solid #f5f5f5;
 

+ 28 - 11
src/views/index/ico/Subscription.vue

@@ -8,12 +8,11 @@
         <div class="head-operate">操作</div>
       </div>
       <div class="subscription-body">
-        <div
-          class="subscription-item"
-          v-for="(item, index) in subscriptionData"
-          :key="index">
-          <div class="item-name pf400 fs14 fc2C3131">Bitcoin</div>
-          <div class="item-price pf400 fs14 fc2C3131">15.3156</div>
+        <div class="subscription-item" v-for="(item, index) in icoData" :key="index">
+          <div class="item-name pf400 fs14 fc2C3131">{{ item.asset_name }}</div>
+          <div class="item-price pf400 fs14 fc2C3131">
+            {{ Number(item.issue_price).toFixed(2) }}
+          </div>
           <div class="item-operate">
             <div class="text pf500 fs12 fcFFFFFF">认购</div>
           </div>
@@ -29,16 +28,34 @@
   </div>
 </template>
 <script setup>
-  import { ref } from "vue";
+  import { ref, onMounted } from "vue";
+  import { GetIcoIco } from "@/api/index";
+
+  const icoData = ref();
+  const subscriptionData = ref();
+
+  const GetIcoIcoData = async () => {
+    // 1,认购 2,配售
+    const params = {
+      asset_type: "1",
+    };
+    const data = await GetIcoIco(params);
+    if (data) {
+      icoData.value = data.list;
+      subscriptionData.value = data.total;
+    }
+  };
 
-  const subscriptionData = ref(6);
+  onMounted(() => {
+    GetIcoIcoData();
+  });
 </script>
 <style lang="less" scoped>
   .subscription {
     width: 349px;
 
     .subscription-content {
-      margin-top: 10px;
+      margin-top: 15px;
       width: 100%;
 
       .subscription-head {
@@ -80,8 +97,8 @@
           display: flex;
           flex-direction: row;
           justify-content: flex-start;
-          margin-top: 13px;
-          padding-bottom: 13px;
+          margin-top: 8px;
+          padding-bottom: 8px;
           width: 100%;
           border-bottom: 1px solid #f5f5f5;
 

+ 197 - 113
src/views/user/InviteCenter.vue

@@ -12,9 +12,7 @@
     <!-- 顶部礼物图标 -->
     <div class="gift-section">
       <div class="gift-circle">
-        <svg viewBox="0 0 1024 1024" width="80" height="80" fill="#DE3545">
-          <path d="M880 305H632c6.2-11.4 11-23.6 14.2-36.4 8.6-34 1.8-70.6-19-100.8-23.4-34-62-54.2-103.2-54.2-27.6 0-54.2 9-76 25.8-21.8-16.8-48.4-25.8-76-25.8-41.2 0-79.8 20.2-103.2 54.2-20.8 30.2-27.6 66.8-19 100.8 3.2 12.8 8 25 14.2 36.4H144c-17.6 0-32 14.4-32 32v152c0 17.6 14.4 32 32 32h24.8v344c0 17.6 14.4 32 32 32h622.4c17.6 0 32-14.4 32-32V497H880c17.6 0 32-14.4 32-32V337c0-17.6-14.4-32-32-32zM524 179.6c17.6 0 33.6 11 42.4 28.4 6 12 7.2 25.6 3.4 38.6-4 13.6-13.4 25.8-26.6 34.4-12.8 8.4-26.4 13-39.6 13-3.8 0-7.6-0.4-11.2-1.2-12.4-2.6-22.8-11.6-26.4-23.8-3.4-11.6 0-25.2 7-38.4 11.4-21.4 30.2-51 51-51zM293.6 208c8.8-17.4 24.8-28.4 42.4-28.4 20.8 0 39.6 29.6 51 51 7 13.2 10.4 26.8 7 38.4-3.6 12.2-14 21.2-26.4 23.8-3.6 0.8-7.4 1.2-11.2 1.2-13.2 0-26.8-4.6-39.6-13-13.2-8.6-22.6-20.8-26.6-34.4-3.8-13-2.6-26.6 3.4-38.6z m-65.6 161h228v128h-228V369z m228 365H232.8V561h223.2v173z m267.2 0H520V561h223.2v173z m0-237H520V369h203.2v128z"/>
-        </svg>
+        <img src="@/assets/icon/user/gift.png" alt="" />
       </div>
       <h2 class="invite-title">邀请好友赚取更多福利</h2>
     </div>
@@ -23,12 +21,13 @@
     <div class="code-section">
       <div class="code-label">邀请码</div>
       <div class="code-box">
-        <span class="code-text">{{ inviteCode }}</span>
+        <span class="code-text">{{ inviteData.code }}</span>
         <!-- 点击复制图标 -->
-        <svg @click="copyCode" class="copy-icon" viewBox="0 0 1024 1024" width="20" height="20">
-          <path d="M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32z" fill="#DE3545"/>
-          <path d="M704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c6 6 14.1 9.4 22.6 9.4h338.7c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM352 853.3V704h-149.3L352 853.3z m320-32V256H224v384h160c17.7 0 32 14.3 32 32v149.3h256z" fill="#DE3545"/>
-        </svg>
+        <img
+          src="@/assets/icon/user/copy.png"
+          @click="copyCode"
+          class="copy-icon"
+          alt="" />
       </div>
 
       <button class="share-btn" @click="handleShare">分享邀请</button>
@@ -38,11 +37,11 @@
     <div class="stats-row">
       <div class="stats-item">
         <div class="stats-label">累计返佣</div>
-        <div class="stats-num">158.00 USDT</div>
+        <div class="stats-num">{{ inviteData.reward }} USDT</div>
       </div>
       <div class="stats-item">
         <div class="stats-label">邀请人数</div>
-        <div class="stats-num">1515</div>
+        <div class="stats-num">{{ inviteData.inv_cnt }}</div>
       </div>
     </div>
 
@@ -58,116 +57,201 @@
 </template>
 
 <script setup>
-import { ref } from 'vue';
-import { useRouter } from "vue-router";
-// 引入 Vant 的 Toast
-import { showToast } from 'vant';
-// 如果项目中没有全局引入样式,可能需要取消下面这行的注释
-// import 'vant/es/toast/style';
-
-const router = useRouter();
-const inviteCode = ref('LANDCOIN444');
-
-// --- 核心:兼容性极强的复制功能 ---
-const copyCode = async () => {
-  const text = inviteCode.value;
-
-  // 1. 优先尝试标准 API (需要 HTTPS)
-  if (navigator.clipboard && navigator.clipboard.writeText) {
+  import { ref, onMounted } from "vue";
+  import { useRouter } from "vue-router";
+  // 引入 Vant 的 Toast
+  import { showToast } from "vant";
+  // 如果项目中没有全局引入样式,可能需要取消下面这行的注释
+  // import 'vant/es/toast/style';
+  import { getInviteInfo } from "@/api/user";
+
+  const router = useRouter();
+
+  const inviteData = ref({});
+
+  const getInviteInfoData = async () => {
+    const data = await getInviteInfo();
+    if (data) {
+      inviteData.value = data;
+    }
+  };
+
+  // --- 核心:兼容性极强的复制功能 ---
+  const copyCode = async () => {
+    const text = inviteCode.value;
+
+    // 1. 优先尝试标准 API (需要 HTTPS)
+    if (navigator.clipboard && navigator.clipboard.writeText) {
+      try {
+        await navigator.clipboard.writeText(text);
+        showToast({ type: "success", message: "复制成功" });
+        return;
+      } catch (err) {
+        console.warn("标准API复制失败,尝试降级方案", err);
+      }
+    }
+
+    // 2. 降级方案 (兼容所有浏览器/Webview)
     try {
-      await navigator.clipboard.writeText(text);
-      showToast({ type: 'success', message: '复制成功' });
-      return;
-    } catch (err) {
-      console.warn('标准API复制失败,尝试降级方案', err);
+      const input = document.createElement("input");
+      input.setAttribute("readonly", "readonly"); // 防止 iOS 拉起键盘
+      input.setAttribute("value", text);
+      input.style.position = "fixed";
+      input.style.left = "-9999px";
+      document.body.appendChild(input);
+
+      input.select();
+      input.setSelectionRange(0, 9999); // 兼容 iOS
+
+      if (document.execCommand("copy")) {
+        showToast({ type: "success", message: "复制成功" });
+      } else {
+        showToast({ type: "fail", message: "复制失败" });
+      }
+
+      document.body.removeChild(input);
+    } catch (e) {
+      showToast({ type: "fail", message: "浏览器不支持自动复制" });
     }
-  }
+  };
 
-  // 2. 降级方案 (兼容所有浏览器/Webview)
-  try {
-    const input = document.createElement('input');
-    input.setAttribute('readonly', 'readonly'); // 防止 iOS 拉起键盘
-    input.setAttribute('value', text);
-    input.style.position = 'fixed';
-    input.style.left = '-9999px';
-    document.body.appendChild(input);
+  // 点击分享,跳转到新的海报页面
+  const handleShare = () => {
+    router.push({ name: "InvitePoster", params: { code: inviteData.value.code } });
+  };
+
+  onMounted(() => {
+    getInviteInfoData();
+  });
+</script>
+
+<style scoped lang="less">
+  /* ========== 基础页面样式 ========== */
+  .invite-page {
+    min-height: 100vh;
+    background: #fff;
+  }
+  .nav-bar {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 44px;
+    padding: 0 16px;
+  }
+  .nav-title {
+    font-size: 18px;
+    font-weight: 500;
+  }
+  .nav-left,
+  .nav-right {
+    width: 30px;
+    display: flex;
+    align-items: center;
+  }
 
-    input.select();
-    input.setSelectionRange(0, 9999); // 兼容 iOS
+  .gift-section {
+    text-align: center;
+    padding: 30px 0 20px;
+  }
+  .gift-circle {
+    width: 200px;
+    height: 200px;
+    background: #fff0f0; /* 浅粉色圆底 */
+    border-radius: 50%;
+    margin: 0 auto 20px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
 
-    if (document.execCommand('copy')) {
-      showToast({ type: 'success', message: '复制成功' });
-    } else {
-      showToast({ type: 'fail', message: '复制失败' });
+    img {
+      width: 100px;
+      height: 116px;
     }
+  }
+  .invite-title {
+    height: 32px;
+    line-height: 32px;
+    font-size: 22px;
+    font-weight: 600;
+    color: #333;
+  }
 
-    document.body.removeChild(input);
-  } catch (e) {
-    showToast({ type: 'fail', message: '浏览器不支持自动复制' });
+  .code-section {
+    padding: 0 20px;
+  }
+  .code-label {
+    font-size: 16px;
+    font-weight: 400;
+    color: #333;
+    margin-bottom: 10px;
+  }
+  .code-box {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background: #fff;
+    border: 1px dashed #eee; /* 虚线边框 */
+    padding: 12px 16px;
+    border-radius: 8px;
+    margin-bottom: 10px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
+  }
+  .code-text {
+    font-size: 16px;
+    font-weight: 700;
+    color: #333;
+  }
+  .share-btn {
+    width: 100%;
+    height: 40px;
+    background: #de3545; /* 红色按钮 */
+    color: #fff;
+    border: none;
+    border-radius: 20px;
+    font-size: 14px;
+    font-weight: 600;
+  }
+  /* 点击反馈 */
+  .share-btn:active {
+    opacity: 0.9;
+  }
+  .copy-icon {
+    width: 24px;
+    height: 24px;
+    cursor: pointer;
+  }
+  .copy-icon:active {
+    opacity: 0.6;
   }
-};
 
-// 点击分享,跳转到新的海报页面
-const handleShare = () => {
-  router.push('/invite/poster');
-};
-</script>
+  .stats-row {
+    display: flex;
+    margin: 28px 0 15px 20px;
+  }
+  .stats-item {
+    flex: 1;
+    text-align: center;
+  }
+  .stats-label {
+    color: #666;
+    font-size: 12px;
+    margin-bottom: 6px;
+  }
+  .stats-num {
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
+  }
 
-<style scoped>
-/* ========== 基础页面样式 ========== */
-.invite-page {
-  min-height: 100vh;
-  background: #fff;
-}
-.nav-bar {
-  display: flex; justify-content: space-between; align-items: center;
-  height: 44px; padding: 0 16px;
-}
-.nav-title { font-size: 18px; font-weight: 500; }
-.nav-left, .nav-right { width: 30px; display: flex; align-items: center; }
-
-.gift-section {
-  text-align: center;
-  padding: 30px 0 20px;
-}
-.gift-circle {
-  width: 120px; height: 120px;
-  background: #FFF0F0; /* 浅粉色圆底 */
-  border-radius: 50%;
-  margin: 0 auto 20px;
-  display: flex; align-items: center; justify-content: center;
-}
-.invite-title {
-  font-size: 18px; font-weight: 400; color: #333;
-}
-
-.code-section { padding: 0 20px; }
-.code-label { font-size: 14px; font-weight: 500; color: #333; margin-bottom: 10px; }
-.code-box {
-  display: flex; justify-content: space-between; align-items: center;
-  background: #fff; border: 1px dashed #eee; /* 虚线边框 */
-  padding: 12px 16px; border-radius: 8px; margin-bottom: 20px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.03);
-}
-.code-text { font-size: 14px; font-weight: 500; color: #333; }
-.share-btn {
-  width: 100%; height: 40px;
-  background: #DE3545; /* 红色按钮 */
-  color: #fff; border: none; border-radius: 20px;
-  font-size: 14px; font-weight: 600;
-}
-/* 点击反馈 */
-.share-btn:active { opacity: 0.9; }
-.copy-icon { cursor: pointer; }
-.copy-icon:active { opacity: 0.6; }
-
-.stats-row {
-  display: flex; margin: 11px 20px;
-}
-.stats-item { flex: 1; text-align: center; }
-.stats-label { color: #666; font-size: 12px; margin-bottom: 6px; }
-.stats-num { font-size: 18px; font-weight: 600; color: #333; }
-
-.rules-section { padding: 0 20px; color: #999; font-size: 12px; line-height: 1.8; }
-.rules-section h3 { color: #333; font-size: 14px; margin-bottom: 10px; }
-</style>
+  .rules-section {
+    margin-top: 30px;
+    padding: 0 20px;
+    color: #999;
+    font-size: 12px;
+    line-height: 1.8;
+  }
+  .rules-section h3 {
+    color: #333;
+    font-size: 14px;
+  }
+</style>

+ 145 - 111
src/views/user/InvitePoster.vue

@@ -1,147 +1,181 @@
 <template>
   <div class="poster-container">
-
     <div class="poster-content" ref="posterRef">
-
       <div class="header-section">
         <h1 class="brand-name">BitWiseWorld</h1>
-        <div class="main-title">邀请好友<br>赚取更多福利</div>
+        <div class="main-title">邀请好友<br />赚取更多福利</div>
       </div>
-
       <div class="illustration-section">
-        <img src="@/assets/icon/bitcoin/yaoqing.svg" class="main-img" alt="Illustration" />
+        <img
+          src="@/assets/icon/bitcoin/yaoqing.svg"
+          class="main-img"
+          alt="Illustration" />
       </div>
-
       <div class="footer-info">
         <div class="info-left">
           <div class="label">邀请码</div>
-          <div class="code">LANDCOIN444</div>
+          <div class="code">{{ inviteCode }}</div>
         </div>
         <div class="info-right">
           <img src="@/assets/icon/bitcoin/erweima.svg" class="qr-img" alt="QR Code" />
         </div>
       </div>
-
       <div class="bg-pattern"></div>
     </div>
-
     <div class="action-area">
       <button class="save-btn" @click="handleSave">保存图片</button>
     </div>
-
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
-import html2canvas from 'html2canvas';
-
-const posterRef = ref(null);
-
-const handleSave = async () => {
-  if (!posterRef.value) return;
-  try {
-    const canvas = await html2canvas(posterRef.value, {
-      useCORS: true,
-      scale: 3, // 稍微提高一点清晰度
-      backgroundColor: '#D91E2D',
-    });
-    const imgUrl = canvas.toDataURL('image/png');
-
-    const link = document.createElement('a');
-    link.href = imgUrl;
-    link.download = 'invite_poster.png';
-    document.body.appendChild(link);
-    link.click();
-    document.body.removeChild(link);
-  } catch (error) {
-    console.error(error);
-  }
-};
+  import { ref, onMounted } from "vue";
+  import { useRoute } from "vue-router";
+  import html2canvas from "html2canvas";
+
+  const route = useRoute();
+  const posterRef = ref(null);
+  const inviteCode = ref();
+
+  const handleSave = async () => {
+    if (!posterRef.value) return;
+    try {
+      const canvas = await html2canvas(posterRef.value, {
+        useCORS: true,
+        scale: 3, // 稍微提高一点清晰度
+        backgroundColor: "#D91E2D",
+      });
+      const imgUrl = canvas.toDataURL("image/png");
+
+      const link = document.createElement("a");
+      link.href = imgUrl;
+      link.download = "invite_poster.png";
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+    } catch (error) {
+      console.error(error);
+    }
+  };
+
+  onMounted(() => {
+    inviteCode.value = route.params.code;
+  });
 </script>
 
 <style scoped>
-/* 页面容器:红色背景铺满全屏 */
-.poster-container {
-  min-height: 100vh;
-  background-color: #D91E2D;
-  display: flex;
-  flex-direction: column;
-  /* 如果内容很少,可以加这个让内容整体垂直居中,或者去掉它让内容顶对齐 */
-  /* justify-content: center; */
-}
+  /* 页面容器:红色背景铺满全屏 */
+  .poster-container {
+    min-height: 100vh;
+    background-color: #d91e2d;
+    display: flex;
+    flex-direction: column;
+    /* 如果内容很少,可以加这个让内容整体垂直居中,或者去掉它让内容顶对齐 */
+    /* justify-content: center; */
+  }
 
-/* 核心海报内容区:这里决定了截图的高度 */
-.poster-content {
-  position: relative;
-  background-color: #D91E2D; /* 截图需要背景色 */
-  padding: 30px 24px 10px;    /* 减少底部 padding */
-  overflow: hidden;           /* 防止装饰溢出 */
-}
+  /* 核心海报内容区:这里决定了截图的高度 */
+  .poster-content {
+    position: relative;
+    background-color: #d91e2d; /* 截图需要背景色 */
+    padding: 30px 24px 10px; /* 减少底部 padding */
+    overflow: hidden; /* 防止装饰溢出 */
+  }
 
-.header-section {
-  position: relative; z-index: 1;
-  margin-bottom: 20px; /* 减小间距 */
-}
-.brand-name {
-  font-size: 18px; font-weight: 800; color: #fff; opacity: 0.9;
-  margin-bottom: 10px;
-}
-.main-title {
-  font-size: 32px; font-weight: 600; color: #fff; line-height: 1.2;
-}
+  .header-section {
+    position: relative;
+    z-index: 1;
+    margin-bottom: 20px; /* 减小间距 */
+  }
+  .brand-name {
+    font-size: 18px;
+    font-weight: 800;
+    color: #fff;
+    opacity: 0.9;
+    margin-bottom: 10px;
+  }
+  .main-title {
+    font-size: 32px;
+    font-weight: 600;
+    color: #fff;
+    line-height: 1.2;
+  }
 
-/* 插画区:关键修改 */
-.illustration-section {
-  position: relative; z-index: 1;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  margin: 10px 0 20px; /* 上下留一点紧凑的间距 */
-}
+  /* 插画区:关键修改 */
+  .illustration-section {
+    position: relative;
+    z-index: 1;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin: 10px 0 20px; /* 上下留一点紧凑的间距 */
+  }
 
-.main-img {
-  width: 100%;
-  max-width: 280px; /* 限制最大宽度 */
-  height: auto;
-  /* 如果图还是很长,可以强制限制高度,用 object-fit 保持比例 */
-  max-height: 320px;
-  object-fit: contain;
-}
+  .main-img {
+    width: 100%;
+    max-width: 280px; /* 限制最大宽度 */
+    height: auto;
+    /* 如果图还是很长,可以强制限制高度,用 object-fit 保持比例 */
+    max-height: 320px;
+    object-fit: contain;
+  }
 
-/* 底部信息区 */
-.footer-info {
-  position: relative; z-index: 1;
-  display: flex;
-  justify-content: space-between;
-  align-items: flex-end;
-  padding-bottom: 20px;
-}
-.label { font-size: 14px; color: rgba(255,255,255,0.8); margin-bottom: 4px; }
-.code { font-size: 20px; font-weight: 700; color: #fff; letter-spacing: 0.5px; }
-.qr-img {
-  width: 72px; height: 72px;
-  background: #fff; padding: 3px; border-radius: 4px;
-}
+  /* 底部信息区 */
+  .footer-info {
+    position: relative;
+    z-index: 1;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-end;
+    padding-bottom: 20px;
+  }
+  .label {
+    font-size: 14px;
+    color: rgba(255, 255, 255, 0.8);
+    margin-bottom: 4px;
+  }
+  .code {
+    font-size: 20px;
+    font-weight: 700;
+    color: #fff;
+    letter-spacing: 0.5px;
+  }
+  .qr-img {
+    width: 72px;
+    height: 72px;
+    background: #fff;
+    padding: 3px;
+    border-radius: 4px;
+  }
 
-/* 背景装饰 */
-.bg-pattern {
-  position: absolute; top: 0; left: 0; right: 0; bottom: 0;
-  background-image: radial-gradient(rgba(255,255,255,0.1) 2px, transparent 2px);
-  background-size: 18px 18px;
-  pointer-events: none; z-index: 0;
-}
+  /* 背景装饰 */
+  .bg-pattern {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-image: radial-gradient(rgba(255, 255, 255, 0.1) 2px, transparent 2px);
+    background-size: 18px 18px;
+    pointer-events: none;
+    z-index: 0;
+  }
 
-/* 底部按钮区:脱离海报流,固定在底部或者紧跟内容 */
-.action-area {
-  padding: 0px 24px 30px;
-  margin-top: auto; /* 把按钮推到屏幕最底部,如果不想推到底部,去掉这行 */
-}
+  /* 底部按钮区:脱离海报流,固定在底部或者紧跟内容 */
+  .action-area {
+    padding: 0px 24px 30px;
+    margin-top: auto; /* 把按钮推到屏幕最底部,如果不想推到底部,去掉这行 */
+  }
 
-.save-btn {
-  width: 100%; height: 48px;
-  background: #fff; color: #D91E2D;
-  font-size: 16px; font-weight: 600; border: none; border-radius: 24px;
-  box-shadow: 0 4px 12px rgba(0,0,0,0.15);
-}
-</style>
+  .save-btn {
+    width: 100%;
+    height: 48px;
+    background: #fff;
+    color: #d91e2d;
+    font-size: 16px;
+    font-weight: 600;
+    border: none;
+    border-radius: 24px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  }
+</style>

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä