20 Incheckningar ac70e00907 ... 9c2526bc87

Upphovsman SHA1 Meddelande Datum
  Hexinkui 9c2526bc87 11111 3 veckor sedan
  Hexinkui ba3d19938f Merge branch 'main' into web3_transection 3 veckor sedan
  jhaoG 47d8511c4d 今日工作12.5 页面增加Tab选项动画 1,消息通知 2,OTC-C2C交易 3,OTC-订单列表 4,ICO 页面美化 1,行情详情 2,贷款-提交信息 实现功能 1,解决行情详情-切换币种弹窗,弹窗显示bug问题 2,熟悉行情模块代码 3,行情委托挂单功能实现 4,行情最新成交功能实现 5,数据监视,做到实时更新 3 veckor sedan
  jhaoG 3a1f44dda2 Merge branch 'main' into jiahao 4 veckor sedan
  jhaoG 19f7d20e33 以下页面增加Tab选项动画 1,消息通知 4 veckor sedan
  Hexinkui 9d3abdcd73 12/4完成工作 4 veckor sedan
  Hexinkui 9c884b01d3 15555 4 veckor sedan
  jhaoG 3e93eab7fb 首页优化 4 veckor sedan
  jhaoG bc9d53a418 Merge branch 'main' into jiahao 4 veckor sedan
  Hexinkui 6f88579108 1 4 veckor sedan
  jhaoG f854f80ec3 Update Index.vue 4 veckor sedan
  Hexinkui 55f2c962b7 Merge branch 'web3_transection' 4 veckor sedan
  jhaoG 7c7dd10f32 所有页面完成 4 veckor sedan
  jhaoG 9a1f09852e download 1 månad sedan
  jhaoG 769bbee15c 今日工作12.2 1,C2C-筛选 完成 2,C2C-购买 完成 3,C2C-出售 完成 4,C2C-暂无收款方式 完成 5,C2C-选择收款方式-无 完成 6,C2C-选择收款方式-有 完成 7,C2C-添加支付宝账号 完成 8,C2C-添加银行卡账号 完成 9,C2C-取消订单 完成 10,OTC-我的 10% 11,首页常用功能图标svg替换png 1 månad sedan
  Hexinkui a29ea89dbd Stop tracking update.js 1 månad sedan
  Hexinkui d71d318c35 今日工作: 1 månad sedan
  Hexinkui 89440154b8 Merge branch 'web3_transection' 1 månad sedan
  jhaoG 6407689944 今日工作12.1 1,解决代码合并导致的代码缺失问题 2,解决刷新页面后提示cannot get问题 3,C2C购买 完成 4,C2C出售 完成 5,快捷交易-购买 完成 6,快捷交易-出售 完成 7,大宗交易-购买 完成 8,大宗交易-出售 完成 9,C2C-支付方式 完成 10,C2C-金额 完成 11,C2C-出售 30% 12,底部我的去掉 完成 1 månad sedan
  jhaoG d53233b309 C2C购买完成 1 månad sedan
100 ändrade filer med 5798 tillägg och 1280 borttagningar
  1. 265 161
      package-lock.json
  2. 4 2
      package.json
  3. 14 1
      src/api/index.js
  4. 11 0
      src/assets/icon/asset/Checkbox Only.svg
  5. 100 0
      src/assets/icon/asset/Digital_currency_2_.svg
  6. 3 0
      src/assets/icon/asset/bottom-arrow-black.svg
  7. 1 0
      src/assets/icon/asset/clock-gray.svg
  8. 6 0
      src/assets/icon/asset/dazong-sell-banner.svg
  9. BIN
      src/assets/icon/asset/dengji.png
  10. BIN
      src/assets/icon/asset/duihao.png
  11. 3 0
      src/assets/icon/asset/duihao.svg
  12. 3 0
      src/assets/icon/asset/filter.svg
  13. BIN
      src/assets/icon/asset/guanzhu.png
  14. 4 0
      src/assets/icon/asset/ic_check_blue.svg
  15. BIN
      src/assets/icon/asset/kefu.png
  16. 2 0
      src/assets/icon/asset/not-payment-way.svg
  17. 3 0
      src/assets/icon/asset/right-arrow-black.svg
  18. BIN
      src/assets/icon/asset/rili.png
  19. BIN
      src/assets/icon/asset/zhinan.png
  20. BIN
      src/assets/icon/coin/Cardano.png
  21. BIN
      src/assets/icon/coin/Dogecoin.png
  22. BIN
      src/assets/icon/coin/Ethereum.png
  23. BIN
      src/assets/icon/coin/Solana.png
  24. BIN
      src/assets/icon/coin/Tezos.png
  25. BIN
      src/assets/icon/index/Rectangle 2.png
  26. BIN
      src/assets/icon/index/Rectangle 3.png
  27. BIN
      src/assets/icon/index/Rectangle 4.png
  28. BIN
      src/assets/icon/index/Rectangle 5.png
  29. BIN
      src/assets/icon/index/Rectangle 6.png
  30. BIN
      src/assets/icon/index/Rectangle 7.png
  31. BIN
      src/assets/icon/index/Rectangle 8.png
  32. BIN
      src/assets/icon/index/Rectangle 9.png
  33. BIN
      src/assets/icon/index/aboutus.png
  34. BIN
      src/assets/icon/index/anquanshezhi.png
  35. BIN
      src/assets/icon/index/bibi.png
  36. 11 0
      src/assets/icon/index/eye-open.svg
  37. BIN
      src/assets/icon/index/yuyan.png
  38. BIN
      src/assets/icon/index/zichan.png
  39. BIN
      src/assets/img/asset/Bank_transfer_2_.png
  40. BIN
      src/assets/img/index/Rectangle 1.png
  41. BIN
      src/assets/img/index/default-img.png
  42. 0 15
      src/assets/img/index/default-img.svg
  43. 4 5
      src/components/ui/CheckBox.vue
  44. 273 108
      src/router/index.js
  45. 11 0
      src/store/ff.vue
  46. 39 38
      src/utils/time.js
  47. 1 1
      src/views/asset/UserAsset.vue
  48. 107 0
      src/views/asset/dialog/Amount.vue
  49. 94 0
      src/views/asset/dialog/CancelOrder.vue
  50. 94 0
      src/views/asset/dialog/CompletePayment.vue
  51. 143 0
      src/views/asset/dialog/Filter.vue
  52. 77 0
      src/views/asset/dialog/NotPaymentWay.vue
  53. 150 0
      src/views/asset/dialog/PaymentAccount.vue
  54. 111 0
      src/views/asset/dialog/PaymentWay.vue
  55. 262 0
      src/views/asset/dialog/SellAndBuy.vue
  56. 2 2
      src/views/asset/history/Index.vue
  57. 205 0
      src/views/asset/otc/order/All.vue
  58. 205 0
      src/views/asset/otc/order/Buy.vue
  59. 142 3
      src/views/asset/otc/order/Index.vue
  60. 205 0
      src/views/asset/otc/order/Sell.vue
  61. 76 0
      src/views/asset/otc/transaction/AddBankAccount.vue
  62. 76 0
      src/views/asset/otc/transaction/AddzfbAccount.vue
  63. 365 2
      src/views/asset/otc/transaction/Bulk.vue
  64. 437 1
      src/views/asset/otc/transaction/C2C.vue
  65. 161 2
      src/views/asset/otc/transaction/Fast.vue
  66. 51 5
      src/views/asset/otc/transaction/Index.vue
  67. 259 3
      src/views/asset/otc/user/Index.vue
  68. 25 0
      src/views/asset/otc/user/LevelLimit.vue
  69. 419 0
      src/views/asset/otc/user/MerchantDetails.vue
  70. 90 0
      src/views/asset/otc/user/MyFollow.vue
  71. 49 0
      src/views/asset/otc/user/TransactionGuide.vue
  72. 10 9
      src/views/bitcoin/TradeLayout.vue
  73. 7 7
      src/views/bitcoin/lever/CryptocurrencyTrading.vue
  74. 2 2
      src/views/bitcoin/lever/TradeSeconds.vue
  75. 0 133
      src/views/bitcoin/lever/components/KLineChart.vue
  76. 0 0
      src/views/bitcoin/lever/components/TradeChart.vue
  77. 1 1
      src/views/index/ApplyPermission.vue
  78. 81 34
      src/views/index/Index.vue
  79. 1 1
      src/views/index/RiskTips.vue
  80. 29 6
      src/views/index/SearchIcon.vue
  81. 4 1
      src/views/index/SplashScreen.vue
  82. 53 8
      src/views/index/User.vue
  83. 12 1
      src/views/index/cloudComputingPower/Index.vue
  84. 24 80
      src/views/index/components/HotCoin.vue
  85. 1 1
      src/views/index/financial/Buy.vue
  86. 55 5
      src/views/index/ico/Index.vue
  87. 3 3
      src/views/index/loan/CommitMessage.vue
  88. 2 3
      src/views/index/loan/Index.vue
  89. 0 1
      src/views/index/recharge/RechargeIndex.vue
  90. 0 13
      src/views/index/user/UserInfo.vue
  91. 203 0
      src/views/market/Bibi.vue
  92. 606 69
      src/views/market/Index.vue
  93. 41 6
      src/views/market/details/EntrustingOrder.vue
  94. 7 4
      src/views/market/details/Index.vue
  95. 46 7
      src/views/market/details/LatestTransactions.vue
  96. 0 526
      src/views/market/details/MarketConditions.vue
  97. 2 2
      src/views/market/dialog/ChangeIcon.vue
  98. 40 5
      src/views/notification/Index.vue
  99. 4 2
      src/views/notification/SysMessage.vue
  100. 1 1
      vue.config.js

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 265 - 161
package-lock.json


+ 4 - 2
package.json

@@ -7,12 +7,14 @@
     "build": "vue-cli-service build"
   },
   "dependencies": {
+    "amfe-flexible": "^2.2.1",
     "axios": "^1.13.2",
     "html2canvas": "^1.4.1",
-    "klinecharts": "^8.6.3",
+    "klinecharts": "^9.7.1",
+    "postcss-pxtorem": "^6.1.0",
     "vant": "^4.9.21",
     "vue": "^3.2.13",
-    "vue-i18n": "^11.2.2",
+    "vue-i18n": "^12.0.0-alpha.3",
     "vue-router": "^4.0.3",
     "vuex": "^4.0.0"
   },

+ 14 - 1
src/api/index.js

@@ -20,11 +20,24 @@ export function GetCoins() {
 //获取K线
 export function GetCandlestickChart(id) {
   return request({
-    url: `/finance/trading_pair/${id.symbol}/get_kline/`,
+    url: `/finance/trading_pair/${id?.symbol}/get_kline/`,
     method: 'get',
     params: {
         interval: id.period,
         limit: 150
     }
   })
+}
+
+
+//交易对
+export function TradingPair(id) {
+    return request({
+    url: `/finance/trading_pair/`,
+    method: 'get',
+    params: {
+        pageSize: id.pageSize,
+        pageNum: id.pageNum,
+    }
+  })
 }

+ 11 - 0
src/assets/icon/asset/Checkbox Only.svg

@@ -0,0 +1,11 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z" fill="#DF384C"/>
+<g clip-path="url(#clip0_322_18648)">
+<path d="M6.5 13L10 16.5L18 8.5" stroke="white" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_322_18648">
+<rect width="16" height="16" fill="white" transform="translate(4 4)"/>
+</clipPath>
+</defs>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 100 - 0
src/assets/icon/asset/Digital_currency_2_.svg


+ 3 - 0
src/assets/icon/asset/bottom-arrow-black.svg

@@ -0,0 +1,3 @@
+<svg width="9" height="5" viewBox="0 0 9 5" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.75 0.75L4.25 4.25L7.75 0.75" stroke="#333333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
src/assets/icon/asset/clock-gray.svg


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 0
src/assets/icon/asset/dazong-sell-banner.svg


BIN
src/assets/icon/asset/dengji.png


BIN
src/assets/icon/asset/duihao.png


+ 3 - 0
src/assets/icon/asset/duihao.svg

@@ -0,0 +1,3 @@
+<svg width="12" height="9" viewBox="0 0 12 9" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1 4.33333L4.33333 7.66667L11 1" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 3 - 0
src/assets/icon/asset/filter.svg

@@ -0,0 +1,3 @@
+<svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.5243 0.670096C14.4378 0.470065 14.2943 0.299898 14.1118 0.18076C13.9293 0.0616213 13.7157 -0.00123158 13.4978 1.82845e-05H1.12278C0.905048 0.000447303 0.692116 0.064052 0.509817 0.183117C0.327519 0.302181 0.183689 0.471589 0.0957766 0.670788C0.00786385 0.869988 -0.0203539 1.09042 0.0145464 1.30534C0.0494468 1.52026 0.145965 1.72044 0.292393 1.88158L0.298018 1.88791L5.06028 6.97291V12.375C5.06024 12.5786 5.11545 12.7784 5.22003 12.9531C5.32461 13.1278 5.47465 13.2709 5.65414 13.367C5.83362 13.4631 6.03583 13.5087 6.23921 13.499C6.44258 13.4892 6.6395 13.4245 6.80896 13.3116L9.05896 11.8111C9.2132 11.7084 9.33967 11.5691 9.42713 11.4057C9.51459 11.2423 9.56033 11.0599 9.56029 10.8745V6.97291L14.3233 1.88791L14.3289 1.88158C14.4769 1.72117 14.5743 1.52073 14.6091 1.30528C14.6438 1.08982 14.6144 0.868906 14.5243 0.670096ZM8.58857 6.36892C8.49126 6.47209 8.43651 6.60821 8.43528 6.75002V10.8745L6.18528 12.375V6.75002C6.18533 6.60718 6.13103 6.46968 6.03341 6.36541L1.12278 1.12502H13.4978L8.58857 6.36892Z" fill="#1F2937"/>
+</svg>

BIN
src/assets/icon/asset/guanzhu.png


+ 4 - 0
src/assets/icon/asset/ic_check_blue.svg

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="20" height="20" rx="10" fill="#DF384C"/>
+<path d="M5.3335 10.0003L8.66683 13.3337L15.3335 6.66699" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

BIN
src/assets/icon/asset/kefu.png


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 0
src/assets/icon/asset/not-payment-way.svg


+ 3 - 0
src/assets/icon/asset/right-arrow-black.svg

@@ -0,0 +1,3 @@
+<svg width="6" height="10" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.75 8.75L4.75 4.75L0.75 0.75" stroke="#333333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

BIN
src/assets/icon/asset/rili.png


BIN
src/assets/icon/asset/zhinan.png


BIN
src/assets/icon/coin/Cardano.png


BIN
src/assets/icon/coin/Dogecoin.png


BIN
src/assets/icon/coin/Ethereum.png


BIN
src/assets/icon/coin/Solana.png


BIN
src/assets/icon/coin/Tezos.png


BIN
src/assets/icon/index/Rectangle 2.png


BIN
src/assets/icon/index/Rectangle 3.png


BIN
src/assets/icon/index/Rectangle 4.png


BIN
src/assets/icon/index/Rectangle 5.png


BIN
src/assets/icon/index/Rectangle 6.png


BIN
src/assets/icon/index/Rectangle 7.png


BIN
src/assets/icon/index/Rectangle 8.png


BIN
src/assets/icon/index/Rectangle 9.png


BIN
src/assets/icon/index/aboutus.png


BIN
src/assets/icon/index/anquanshezhi.png


BIN
src/assets/icon/index/bibi.png


+ 11 - 0
src/assets/icon/index/eye-open.svg

@@ -0,0 +1,11 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="eye" clip-path="url(#clip0_96_7646)">
+<path id="Vector" d="M3.27489 8.70433C2.42496 9.80853 2 10.3606 2 12C2 13.6394 2.42496 14.1915 3.27489 15.2957C4.97196 17.5004 7.81811 20 12 20C16.1819 20 19.028 17.5004 20.7251 15.2957C21.575 14.1915 22 13.6394 22 12C22 10.3606 21.575 9.80853 20.7251 8.70433C19.028 6.49956 16.1819 4 12 4C7.81811 4 4.97196 6.49956 3.27489 8.70433Z" stroke="#1E1C27" stroke-width="1.5"/>
+<path id="Vector_2" d="M15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15C13.6569 15 15 13.6569 15 12Z" stroke="#1E1C27" stroke-width="1.5"/>
+</g>
+<defs>
+<clipPath id="clip0_96_7646">
+<rect width="24" height="24" fill="white" transform="matrix(1 0 0 -1 0 24)"/>
+</clipPath>
+</defs>
+</svg>

BIN
src/assets/icon/index/yuyan.png


BIN
src/assets/icon/index/zichan.png


BIN
src/assets/img/asset/Bank_transfer_2_.png


BIN
src/assets/img/index/Rectangle 1.png


BIN
src/assets/img/index/default-img.png


+ 0 - 15
src/assets/img/index/default-img.svg

@@ -1,15 +0,0 @@
-<svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg">
-<mask id="mask0_5_480" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="38" height="38">
-<rect width="38" height="38" rx="12" fill="white"/>
-</mask>
-<g mask="url(#mask0_5_480)">
-<rect width="38" height="38" fill="#F5F5F5"/>
-</g>
-<path d="M19 20C21.67 20 27 21.33 27 24V27H11V24C11 21.33 16.33 20 19 20ZM19 21.9004C16.03 21.9004 12.9004 23.36 12.9004 24V25.0996H25.0996V24C25.0996 23.36 21.97 21.9004 19 21.9004ZM19 11C21.2091 11 23 12.7909 23 15C23 17.2091 21.2091 19 19 19C16.7909 19 15 17.2091 15 15C15 12.7909 16.7909 11 19 11ZM19 13C17.8954 13 17 13.8954 17 15C17 16.1046 17.8954 17 19 17C20.1046 17 21 16.1046 21 15C21 13.8954 20.1046 13 19 13Z" fill="black"/>
-<mask id="mask1_5_480" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="11" y="11" width="16" height="16">
-<path d="M19 20C21.67 20 27 21.33 27 24V27H11V24C11 21.33 16.33 20 19 20ZM19 21.9004C16.03 21.9004 12.9004 23.36 12.9004 24V25.0996H25.0996V24C25.0996 23.36 21.97 21.9004 19 21.9004ZM19 11C21.2091 11 23 12.7909 23 15C23 17.2091 21.2091 19 19 19C16.7909 19 15 17.2091 15 15C15 12.7909 16.7909 11 19 11ZM19 13C17.8954 13 17 13.8954 17 15C17 16.1046 17.8954 17 19 17C20.1046 17 21 16.1046 21 15C21 13.8954 20.1046 13 19 13Z" fill="white"/>
-</mask>
-<g mask="url(#mask1_5_480)">
-<rect x="10" y="10" width="18" height="18" fill="#A8A8A8"/>
-</g>
-</svg>

+ 4 - 5
src/components/ui/CheckBox.vue.vue → src/components/ui/CheckBox.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="checkbox" :class="{ checked: modelValue }" @click="toggle">
-    <span v-if="modelValue" class="checkmark">✔</span>
+    <img src="@/assets/icon/asset/duihao.png" v-if="modelValue" alt="" />
   </div>
 </template>
 
@@ -34,9 +34,8 @@
     background: #df384c; /* 选中仍为红色背景 */
   }
 
-  .checkmark {
-    font-size: 12px;
-    color: white;
-    line-height: 1;
+  img {
+    width: 10px;
+    height: 7px;
   }
 </style>

+ 273 - 108
src/router/index.js

@@ -29,22 +29,48 @@ import RechargeChangeCoin from "../views/index/recharge/ChangeCoin.vue";
 import Transfer from "../views/index/recharge/Transfer.vue";
 import TransferHistory from "../views/index/recharge/TransferHistory.vue";
 import UserAsset from "../views/asset/UserAsset.vue";
-
+import OTCMessageIndex from "@/views/asset/otc/message/Index.vue";
+import OTCOrderIndex from "@/views/asset/otc/order/Index.vue";
+import OTCTransactionIndex from "@/views/asset/otc/transaction/Index.vue";
+import OTCUserIndex from "@/views/asset/otc/user/Index.vue";
+import CloudCalculator from "@/views/index/cloudComputingPower/Calculator.vue";
+import StakingIndex from "@/views/index/staking/Index.vue";
+import StakingRules from "@/views/index/staking/Rules.vue";
+import StakingRecord from "@/views/index/staking/Record.vue";
+import OTCIndex from "@/views/asset/otc/Index.vue";
+import MyPower from "@/views/index/cloudComputingPower/MyPower.vue";
+import MiningOutput from "@/views/index/cloudComputingPower/MiningOutput.vue";
+import ElectricityRecharge from "@/views/index/cloudComputingPower/ElectricityRecharge.vue";
+import ElectricitySetting from "@/views/index/cloudComputingPower/ElectricitySetting.vue";
+import ElectricityBill from "@/views/index/cloudComputingPower/ElectricityBill.vue";
+import CloudMyOrder from "@/views/index/cloudComputingPower/MyOrder.vue";
+import CloudComPowerIndex from "@/views/index/cloudComputingPower/Index.vue";
+import ComboDetails from "@/views/index/cloudComputingPower/ComboDetails.vue";
+import RechargeHistory from "../views/index/recharge/RechargeHistory.vue";
+import WithdrawHistory from "../views/index/recharge/WithdrawHistory.vue";
+import FinancialIndex from "../views/index/financial/Index.vue";
+import FinancialBuy from "../views/index/financial/Buy.vue";
+import MyFinancial from "../views/index/financial/MyFinancial.vue";
+import AddzfbAccount from "@/views/asset/otc/transaction/AddzfbAccount.vue";
+import AddBankAccount from "@/views/asset/otc/transaction/AddBankAccount.vue";
+import OTCMerchantDetails from "@/views/asset/otc/user/MerchantDetails.vue";
+import MyFollow from "@/views/asset/otc/user/MyFollow.vue";
+import LevelLimit from "@/views/asset/otc/user/LevelLimit.vue";
+import TransactionGuide from "@/views/asset/otc/user/TransactionGuide.vue";
 
 import CommonFunctionsPopup from "@/views/bitcoin/CommonFunctionsPopup/CommonFunctionsPopup.vue"; // 子组件路径
 import TradeRules from "@/views/bitcoin/CommonFunctionsPopup/GeneralLevel2/TradeRules.vue"; // 新建
-import TradeLayout from '@/views/bitcoin/TradeLayout.vue'; // 新建的公共父组件
-import TradeFutures from '@/views/bitcoin/TradeFutures.vue'; // (合约)
-import TradeSeconds from '@/views/bitcoin/lever/TradeSeconds.vue'; // 秒合约(占位)
-import TradeOptions from '@/views/bitcoin/lever/TradeOptions.vue'; // 期权(占位)
-import TradeMargin from '@/views/bitcoin/lever/TradeMargin.vue';
-import Calculator from '../views/bitcoin/Calculator.vue' // 新建的计算器页面
-import TradeSettings from '@/views/bitcoin/CommonFunctionsPopup/GeneralLevel2/TradeSettings.vue'// 新建
-import OptionTrading from '@/views/bitcoin/lever/OptionTrading.vue'
-import AddressAuth from '@/views/user/AddressAuth.vue'
-import RelativeAuth from '@/views/user/RelativeAuth.vue'
-import LanguageSwitch from '@/views/user/LanguageSwitch.vue'//语言国际化
-
+import TradeLayout from "@/views/bitcoin/TradeLayout.vue"; // 新建的公共父组件
+import TradeFutures from "@/views/bitcoin/TradeFutures.vue"; // (合约)
+import TradeSeconds from "@/views/bitcoin/lever/TradeSeconds.vue"; // 秒合约(占位)
+import TradeOptions from "@/views/bitcoin/lever/TradeOptions.vue"; // 期权(占位)
+import TradeMargin from "@/views/bitcoin/lever/TradeMargin.vue";
+import Calculator from "../views/bitcoin/Calculator.vue"; // 新建的计算器页面
+import TradeSettings from "@/views/bitcoin/CommonFunctionsPopup/GeneralLevel2/TradeSettings.vue"; // 新建
+import OptionTrading from "@/views/bitcoin/lever/OptionTrading.vue";
+import AddressAuth from "@/views/user/AddressAuth.vue";
+import RelativeAuth from "@/views/user/RelativeAuth.vue";
+import LanguageSwitch from "@/views/user/LanguageSwitch.vue"; //语言国际化
 
 const routes = [
   {
@@ -66,7 +92,7 @@ const routes = [
         path: "/bitcoin",
         component: TradeLayout, // 而是布局组件
         // 当访问 /bitcoin 时,自动重定向到 /bitcoin/contract
-        redirect: "/bitcoin/contract",
+        redirect: "/bitcoin/CryptocurrencyTrading",
         children: [
           // 1. 核心交易子路由
           {
@@ -82,40 +108,37 @@ const routes = [
             meta: { title: "秒合约" },
           },
           {
-            path: 'options',
-            name: 'TradeOptions',
+            path: "options",
+            name: "TradeOptions",
             component: TradeOptions,
-            meta: { title: '期权' },
+            meta: { title: "期权" },
           },
           {
-            path: 'CryptocurrencyTrading',
-            name: 'Cryptocurrency',
-            component: () =>import('@/views/bitcoin/lever/CryptocurrencyTrading.vue'),
-            meta: { title: '币币交易' },
+            path: "CryptocurrencyTrading",
+            name: "Cryptocurrency",
+            component: () => import("@/views/bitcoin/lever/CryptocurrencyTrading.vue"),
+            meta: { title: "币币交易" },
           },
 
-            {
-                path: "margin",
-                name: "TradeMargin",
-                component: TradeMargin,
-                meta: {title: "杠杆"},
-            },
-            {
-                path: 'settings',
-                name: 'TradeSettings',
-                component: TradeSettings
-            },
-
-         ]
-        },
-      { path: 'calculator',
-            name: 'calculator',
-            component: Calculator },
+          {
+            path: "margin",
+            name: "TradeMargin",
+            component: TradeMargin,
+            meta: { title: "杠杆" },
+          },
+          {
+            path: "settings",
+            name: "TradeSettings",
+            component: TradeSettings,
+          },
+        ],
+      },
+      { path: "calculator", name: "calculator", component: Calculator },
       {
-            path: 'OptionTrading',
-            name: 'OptionTrading',
-            component: OptionTrading,
-            meta: { title: '' }
+        path: "OptionTrading",
+        name: "OptionTrading",
+        component: OptionTrading,
+        meta: { title: "" },
       },
       {
         path: "/assetIndex",
@@ -130,113 +153,140 @@ const routes = [
     ],
   },
   {
-    path: '/AdvancedCertification',
-    name: 'AdvancedCertification',
-    component: () => import('@/views/user/AdvancedCertification.vue'),
-    meta: { title: '' }
-   },
+    path: "/AdvancedCertification",
+    name: "AdvancedCertification",
+    component: () => import("@/views/user/AdvancedCertification.vue"),
+    meta: { title: "" },
+  },
   {
-            path: '/PnLAnalysis',
-            name: 'PnLAnalysis',
-            component: () => import('@/views/bitcoin/lever/PnLAnalysis.vue'),
-            meta: { title: '' }
+    path: "/PnLAnalysis",
+    name: "PnLAnalysis",
+    component: () => import("@/views/bitcoin/lever/PnLAnalysis.vue"),
+    meta: { title: "" },
   },
   {
-    path: '/detail',
-    name: 'HelpCenter',
+    path: "/otcIndex",
+    name: "otcIndex",
+    component: OTCIndex,
+    children: [
+      {
+        path: "",
+        name: "otcTransactionIndex",
+        component: OTCTransactionIndex,
+      },
+      {
+        path: "/otcMessageIndex",
+        name: "otcMessageIndex",
+        component: OTCMessageIndex,
+      },
+      {
+        path: "/otcOrderIndex",
+        name: "otcOrderIndex",
+        component: OTCOrderIndex,
+      },
+      {
+        path: "/otcUserIndex",
+        name: "otcUserIndex",
+        component: OTCUserIndex,
+      },
+    ],
+  },
+  {
+    path: "/detail",
+    name: "HelpCenter",
     // 记得创建这个 Detail.vue 文件
-    component: () => import('@/views/user/HelpCenter.vue')
+    component: () => import("@/views/user/HelpCenter.vue"),
   },
   {
     // 动态路由,接收一个 id 参数
-    path: '/help/detail',
-    name: 'HelpDetail',
-    component: () => import('@/views/user/HelpDetail.vue')
+    path: "/help/detail",
+    name: "HelpDetail",
+    component: () => import("@/views/user/HelpDetail.vue"),
   },
   {
-    path: '/about',
-    name: 'AboutUs',
-    component: () => import('@/views/user/AboutUs.vue')
+    path: "/about",
+    name: "AboutUs",
+    component: () => import("@/views/user/AboutUs.vue"),
   },
   {
-    path: '/about/privacy',
-    name: 'PrivacyPolicy',
-    component: () => import('@/views/user/PrivacyPolicy.vue')
+    path: "/about/privacy",
+    name: "PrivacyPolicy",
+    component: () => import("@/views/user/PrivacyPolicy.vue"),
   },
   {
-    path: '/about/agreement',
-    name: 'UserAgreement',
-    component: () => import('@/views/user/UserAgreement.vue')
+    path: "/about/agreement",
+    name: "UserAgreement",
+    component: () => import("@/views/user/UserAgreement.vue"),
   },
   {
-    path: '/invite',
-    name: 'InviteCenter',
-    component: () => import('@/views/user/InviteCenter.vue') // 上面的组件
+    path: "/invite",
+    name: "InviteCenter",
+    component: () => import("@/views/user/InviteCenter.vue"), // 上面的组件
   },
   {
-      path: '/invite/poster',
-      name: 'InvitePoster',
-      component: () => import('@/views/user/InvitePoster.vue')
+    path: "/invite/poster",
+    name: "InvitePoster",
+    component: () => import("@/views/user/InvitePoster.vue"),
   },
   {
-    path: '/vip',
-    name: 'VipCenter',
-    component: () => import('@/views/user/VipCenter.vue')
+    path: "/vip",
+    name: "VipCenter",
+    component: () => import("@/views/user/VipCenter.vue"),
   },
   {
-    path: '/vip/rules',
-    name: 'VipRules',
-    component: () => import('@/views/user/VipRules.vue')
+    path: "/vip/rules",
+    name: "VipRules",
+    component: () => import("@/views/user/VipRules.vue"),
   },
   {
-    path: '/kyc/step1',
-    name: 'KycForm',
-    component: () => import('@/views/user/KycForm.vue') // 填写表单
+    path: "/kyc/step1",
+    name: "KycForm",
+    component: () => import("@/views/user/KycForm.vue"), // 填写表单
   },
   {
-    path: '/kyc/step2',
-    name: 'KycUpload',
-    component: () => import('@/views/user/KycUpload.vue') // 上传证件
+    path: "/kyc/step2",
+    name: "KycUpload",
+    component: () => import("@/views/user/KycUpload.vue"), // 上传证件
   },
   {
-    path: '/security',
-    name: 'SecuritySettings',
-    component: () => import('@/views/user/SecuritySettings.vue') // 核心页面
+    path: "/security",
+    name: "SecuritySettings",
+    component: () => import("@/views/user/SecuritySettings.vue"), // 核心页面
   },
   {
-    path: '/set-password',
-    name: 'SetPassword',
-    component: () => import('@/views/user/SetPassword.vue') // 新页面
+    path: "/set-password",
+    name: "SetPassword",
+    component: () => import("@/views/user/SetPassword.vue"), // 新页面
   },
   {
-    path: '/delete-account',
-    name: 'DeleteAccount',
-    component: () => import('@/views/user/DeleteAccount.vue') // 新页面
+    path: "/delete-account",
+    name: "DeleteAccount",
+    component: () => import("@/views/user/DeleteAccount.vue"), // 新页面
   },
   {
     // 地址认证:复用同一个组件,通过 query 参数 type 来区分是 "home" 还是 "work"
-    path: '/auth/address',
-    name: 'address-auth',
-    component: AddressAuth
+    path: "/auth/address",
+    name: "address-auth",
+    component: AddressAuth,
   },
   {
     // 亲属认证
-    path: '/auth/relative',
-    name: 'relative-auth',
-    component: RelativeAuth
+    path: "/auth/relative",
+    name: "relative-auth",
+    component: RelativeAuth,
   },
   {
-    path: '/language',
-    name: 'LanguageSwitch',
+    path: "/language",
+    name: "LanguageSwitch",
     component: LanguageSwitch,
-    meta: { title: '切换语言' }
+    meta: { title: "切换语言" },
   },
   {
-      path: '/basic-verify',
-      name: 'BasicVerify',
-      component: () => import('@/views/user/BasicVerify.vue'),
-      meta: { title: '基础认证' }
-   },
+    path: "/basic-verify",
+    name: "BasicVerify",
+    component: () => import("@/views/user/BasicVerify.vue"),
+    meta: { title: "基础认证" },
+  },
 
   {
     path: "/applyPermission",
@@ -438,10 +488,125 @@ const routes = [
     name: "userLoanIndex",
     component: UserLoanIndex,
   },
+  {
+    path: "/rechargeHistory",
+    name: "rechargeHistory",
+    component: RechargeHistory,
+  },
+  {
+    path: "/withdrawHistory",
+    name: "withdrawHistory",
+    component: WithdrawHistory,
+  },
+  {
+    path: "/financialIndex",
+    name: "financialIndex",
+    component: FinancialIndex,
+  },
+  {
+    path: "/financialBuy",
+    name: "financialBuy",
+    component: FinancialBuy,
+  },
+  {
+    path: "/myFinancial",
+    name: "myFinancial",
+    component: MyFinancial,
+  },
+  {
+    path: "/cloudComPowerIndex",
+    name: "cloudComPowerIndex",
+    component: CloudComPowerIndex,
+  },
+  {
+    path: "/comboDetails",
+    name: "comboDetails",
+    component: ComboDetails,
+  },
+  {
+    path: "/myPower",
+    name: "myPower",
+    component: MyPower,
+  },
+  {
+    path: "/miningOutput",
+    name: "miningOutput",
+    component: MiningOutput,
+  },
+  {
+    path: "/electricityRecharge",
+    name: "electricityRecharge",
+    component: ElectricityRecharge,
+  },
+  {
+    path: "/electricitySetting",
+    name: "electricitySetting",
+    component: ElectricitySetting,
+  },
+  {
+    path: "/electricityBill",
+    name: "electricityBill",
+    component: ElectricityBill,
+  },
+  {
+    path: "/cloudMyOrder",
+    name: "cloudMyOrder",
+    component: CloudMyOrder,
+  },
+  {
+    path: "/cloudCalculator",
+    name: "cloudCalculator",
+    component: CloudCalculator,
+  },
+  {
+    path: "/stakingIndex",
+    name: "stakingIndex",
+    component: StakingIndex,
+  },
+  {
+    path: "/stakingRules",
+    name: "stakingRules",
+    component: StakingRules,
+  },
+  {
+    path: "/stakingRecord",
+    name: "stakingRecord",
+    component: StakingRecord,
+  },
+  {
+    path: "/addzfbAccount",
+    name: "addzfbAccount",
+    component: AddzfbAccount,
+  },
+  {
+    path: "/addBankAccount",
+    name: "addBankAccount",
+    component: AddBankAccount,
+  },
+  {
+    path: "/OTCMerchantDetails",
+    name: "OTCMerchantDetails",
+    component: OTCMerchantDetails,
+  },
+  {
+    path: "/myFollow",
+    name: "myFollow",
+    component: MyFollow,
+  },
+  {
+    path: "/levelLimit",
+    name: "levelLimit",
+    component: LevelLimit,
+  },
+  {
+    path: "/transactionGuide",
+    name: "transactionGuide",
+    component: TransactionGuide,
+  },
 ];
 
 const router = createRouter({
-    history: createWebHashHistory(),
+  history: createWebHashHistory(),
   routes,
 });
 

+ 11 - 0
src/store/ff.vue

@@ -0,0 +1,11 @@
+<script setup>
+
+</script>
+
+<template>
+
+</template>
+
+<style scoped lang="less">
+
+</style>

+ 39 - 38
src/utils/time.js

@@ -5,19 +5,20 @@
  * @returns '1970-01-01 08:00:00'
  */
 export function timestampToTime(time) {
-  var date = new Date(time * 1000)
-  let y = date.getFullYear()
-  let MM = date.getMonth() + 1
-  MM = MM < 10 ? ('0' + MM) : MM
-  let d = date.getDate()
-  d = d < 10 ? ('0' + d) : d
-  let h = date.getHours()
-  h = h < 10 ? ('0' + h) : h
-  let m = date.getMinutes()
-  m = m < 10 ? ('0' + m) : m
-  let s = date.getSeconds()
-  s = s < 10 ? ('0' + s) : s
-  return y + '-' + MM + '-' + d + ' ' + h + ':' + m + ':' + s
+  var date = new Date(time * 1000);
+  let y = date.getFullYear();
+  let MM = date.getMonth() + 1;
+  MM = MM < 10 ? "0" + MM : MM;
+  let d = date.getDate();
+  d = d < 10 ? "0" + d : d;
+  let h = date.getHours();
+  h = h < 10 ? "0" + h : h;
+  let m = date.getMinutes();
+  m = m < 10 ? "0" + m : m;
+  let s = date.getSeconds();
+  s = s < 10 ? "0" + s : s;
+  return h + ":" + m + ":" + s;
+  // return y + '-' + MM + '-' + d + ' ' + h + ':' + m + ':' + s
 }
 
 /**
@@ -26,29 +27,29 @@ export function timestampToTime(time) {
  * @returns Jan
  */
 export function monthChangeEnglish(month) {
-  if (month == '1' || month == '01') {
-    return 'Jan'
-  } else if (month == '2' || month == '02') {
-    return 'Feb'
-  } else if (month == '3' || month == '03') {
-    return 'Mar'
-  } else if (month == '4' || month == '04') {
-    return 'Apr'
-  } else if (month == '5' || month == '05') {
-    return 'May'
-  } else if (month == '6' || month == '06') {
-    return 'Jun'
-  } else if (month == '7' || month == '07') {
-    return 'Jul'
-  } else if (month == '8' || month == '08') {
-    return 'Aug'
-  } else if (month == '9' || month == '09') {
-    return 'Sept'
-  } else if (month == '10' || month == '10') {
-    return 'Oct'
-  } else if (month == '11') {
-    return 'Nov'
-  } else if (month == '12') {
-    return 'Dec'
+  if (month == "1" || month == "01") {
+    return "Jan";
+  } else if (month == "2" || month == "02") {
+    return "Feb";
+  } else if (month == "3" || month == "03") {
+    return "Mar";
+  } else if (month == "4" || month == "04") {
+    return "Apr";
+  } else if (month == "5" || month == "05") {
+    return "May";
+  } else if (month == "6" || month == "06") {
+    return "Jun";
+  } else if (month == "7" || month == "07") {
+    return "Jul";
+  } else if (month == "8" || month == "08") {
+    return "Aug";
+  } else if (month == "9" || month == "09") {
+    return "Sept";
+  } else if (month == "10" || month == "10") {
+    return "Oct";
+  } else if (month == "11") {
+    return "Nov";
+  } else if (month == "12") {
+    return "Dec";
   }
-}
+}

+ 1 - 1
src/views/asset/UserAsset.vue

@@ -9,7 +9,7 @@
       <div class="fcA8A8A8" @click="messageChange('financialManagement')">理财</div>
       <div class="fcA8A8A8" @click="messageChange('option')">期权</div>
       <div class="fcA8A8A8" @click="messageChange('miaoContract')">秒合约</div>
-      <div class="fcA8A8A8" @click="messageChange('lever')">杠杆</div>
+      <div class="fcA8A8A8" @click="messageChange('lever')">币币</div>
     </div>
     <component :is="currentComponent" />
   </div>

+ 107 - 0
src/views/asset/dialog/Amount.vue

@@ -0,0 +1,107 @@
+<template>
+  <div class="amount">
+    <div class="apply-mask" @click="emits('amountClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="apply-text pf600 fs18 fc121212">金额</div>
+      <div class="loan-price">
+        <input type="text" class="input pf500 fs14 fc333333" placeholder="0.00 " />
+        <div class="pf500 fs14 fc333333">CNY</div>
+      </div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF">确认</div>
+      <div class="reset pf500 fs14 fcDF384C">重置</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  const emits = defineEmits(["amountClose"]);
+</script>
+<style lang="less" scoped>
+  .amount {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 273px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .apply-text {
+        margin-top: 21px;
+        width: 345px;
+        height: 24px;
+        line-height: 24px;
+        letter-spacing: 0.2px;
+      }
+
+      .loan-price {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 14px;
+        padding-right: 11px;
+        width: 345px;
+        height: 45px;
+        background: #f5f5f5;
+        box-sizing: border-box;
+
+        .input {
+          padding-left: 11px;
+          width: 80%;
+          height: 100%;
+          box-sizing: border-box;
+          outline: none;
+          border: none;
+          border-radius: 6px;
+          background: #f5f5f5;
+        }
+      }
+
+      .sure-btn {
+        margin-top: 41px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+
+      .reset {
+        margin-top: 15px;
+      }
+    }
+  }
+</style>

+ 94 - 0
src/views/asset/dialog/CancelOrder.vue

@@ -0,0 +1,94 @@
+<template>
+  <div class="cancel-order">
+    <div class="apply-mask" @click="emits('cancelOrderClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="order-title pf600 fs18 fc333333">您是否确定取消订单?</div>
+      <img src="@/assets/icon/asset/Digital_currency_2_.svg" alt="" />
+      <div class="text pf500 fs14 fc333333">
+        如果您已向卖家付款 <br />
+        请不要取消订单
+      </div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF">确认</div>
+      <div class="cancel pf500 fs14 fcDF384C">取消</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  const emits = defineEmits(["cancelOrderClose"]);
+</script>
+<style lang="less" scoped>
+  .cancel-order {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 337px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .order-title {
+        margin-top: 20px;
+        height: 24px;
+        line-height: 24px;
+      }
+
+      img {
+        margin-top: 19px;
+        width: 110px;
+        height: 70px;
+      }
+
+      .text {
+        margin-top: 20px;
+        line-height: 25px;
+        text-align: center;
+      }
+
+      .sure-btn {
+        margin-top: 10px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+
+      .cancel {
+        margin-top: 11px;
+      }
+    }
+  }
+</style>

+ 94 - 0
src/views/asset/dialog/CompletePayment.vue

@@ -0,0 +1,94 @@
+<template>
+  <div class="complete-payment">
+    <div class="apply-mask" @click="emits('completePaymentClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="order-title pf600 fs18 fc333333">您是否已完成付款?</div>
+      <img src="@/assets/img/asset/Bank_transfer_2_.png" alt="" />
+      <div class="text pf500 fs14 fc333333">
+        请确保您已向卖家付款 <br />
+        恶意操作不付款可能会被冻结账户
+      </div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF">确认</div>
+      <div class="cancel pf500 fs14 fcDF384C">取消</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  const emits = defineEmits(["completePaymentClose"]);
+</script>
+<style lang="less" scoped>
+  .complete-payment {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 337px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .order-title {
+        margin-top: 20px;
+        height: 24px;
+        line-height: 24px;
+      }
+
+      img {
+        margin-top: 19px;
+        width: 72px;
+        height: 74.5px;
+      }
+
+      .text {
+        margin-top: 20px;
+        line-height: 25px;
+        text-align: center;
+      }
+
+      .sure-btn {
+        margin-top: 10px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+
+      .cancel {
+        margin-top: 11px;
+      }
+    }
+  }
+</style>

+ 143 - 0
src/views/asset/dialog/Filter.vue

@@ -0,0 +1,143 @@
+<template>
+  <div class="filter">
+    <div class="apply-mask" @click="emits('filterClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="apply-text pf600 fs18 fc121212">支付方式</div>
+      <div class="payment-main">
+        <div
+          class="payment-item"
+          v-for="(item, index) in paymentWayData"
+          :key="index"
+          @click="paymentChoice(index)">
+          <div class="pf500 fs16 fc121212">{{ item }}</div>
+          <div class="item-selected">
+            <div class="selected" v-if="currentChoice == index">
+              <img src="@/assets/icon/asset/duihao.svg" alt="" />
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF">确认</div>
+      <div class="reset pf500 fs14 fcDF384C">重置</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  import { ref } from "vue";
+  const emits = defineEmits(["filterClose"]);
+
+  const paymentWayData = ["全部", "交易过", "我的关注", "仅展示可交易单"];
+  const currentChoice = ref(0);
+
+  const paymentChoice = (index) => {
+    currentChoice.value = index;
+  };
+</script>
+<style lang="less" scoped>
+  .filter {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 400px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .apply-text {
+        margin-top: 21px;
+        width: 345px;
+        height: 24px;
+        line-height: 24px;
+        letter-spacing: 0.2px;
+      }
+
+      .payment-main {
+        margin-top: 15px;
+        width: 345px;
+
+        .payment-item {
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          margin-top: 15px;
+          width: 345px;
+          height: 25px;
+
+          &:first-child {
+            margin-top: 0px;
+          }
+
+          .item-selected {
+            width: 20px;
+            height: 20px;
+            border: 1px solid #a8a8a8;
+            border-radius: 50%;
+
+            .selected {
+              display: flex;
+              flex-direction: row;
+              justify-content: center;
+              align-items: center;
+              width: 20px;
+              height: 20px;
+              background: #df384c;
+              border-radius: 50%;
+
+              img {
+                width: 10px;
+                height: 6.67px;
+              }
+            }
+          }
+        }
+      }
+
+      .sure-btn {
+        margin-top: 65px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+
+      .reset {
+        margin-top: 15px;
+      }
+    }
+  }
+</style>

+ 77 - 0
src/views/asset/dialog/NotPaymentWay.vue

@@ -0,0 +1,77 @@
+<template>
+  <div class="payment-way">
+    <div class="apply-mask" @click="emits('notPaymentWayClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <img src="@/assets/icon/asset/not-payment-way.svg" alt="" />
+      <div class="text pf500 fs20 fc333333">暂无收款方式</div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF">添加</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  const emits = defineEmits(["notPaymentWayClose"]);
+</script>
+<style lang="less" scoped>
+  .payment-way {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 350px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      img {
+        margin-top: 42px;
+        width: 189px;
+        height: 130px;
+      }
+
+      .text {
+        margin-top: 20px;
+      }
+
+      .sure-btn {
+        margin-top: 23px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+    }
+  }
+</style>

+ 150 - 0
src/views/asset/dialog/PaymentAccount.vue

@@ -0,0 +1,150 @@
+<template>
+  <div class="not-account">
+    <div class="apply-mask" @click="emits('paymentAccountClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="account-not" v-if="current == 0">
+        <div class="not-item pf600 fs16 fc333333" v-for="(item, index) in 2" :key="index">
+          暂无银行卡账号
+          <div class="add pf500 fs12 fcFFFFFF">添加</div>
+        </div>
+      </div>
+      <div class="account-have" v-else>
+        <div class="have-item" v-for="(item, index) in 2" :key="index">
+          <div class="have-left">
+            <div class="left-text pf600 fs16 fcDF384C">
+              银行卡&nbsp;&nbsp;<span class="pf500 fs12 fcA8A8A8">删除</span>
+            </div>
+            <div class="left-bumber pf400 fs14 fcDF384C">1502 0802 0802 0820 252</div>
+          </div>
+          <div class="have-right">
+            <img src="@/assets/icon/asset/Checkbox Only.svg" alt="" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup>
+  import { ref } from "vue";
+
+  const emits = defineEmits(["paymentAccountClose"]);
+
+  const current = ref(0);
+</script>
+<style lang="less" scoped>
+  .not-account {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 300px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .account-not {
+        margin-top: 29px;
+
+        .not-item {
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          padding: 0 16px;
+          margin-top: 12px;
+          width: 345px;
+          height: 80px;
+          border-radius: 16px;
+          border: 1px solid #a8a8a8;
+          box-sizing: border-box;
+
+          &:first-child {
+            margin-top: 0;
+          }
+
+          .add {
+            width: 76px;
+            height: 24px;
+            line-height: 24px;
+            text-align: center;
+            border-radius: 5px;
+            background: #df384c;
+          }
+        }
+      }
+
+      .account-have {
+        margin-top: 29px;
+
+        .have-item {
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          margin-top: 12px;
+          padding: 0 16px;
+          width: 345px;
+          height: 80px;
+          border-radius: 16px;
+          border: 1px solid #a8a8a8;
+          box-sizing: border-box;
+
+          &:first-child {
+            margin-top: 0;
+          }
+        }
+
+        .have-left {
+          .left-text {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            height: 22px;
+          }
+
+          .left-bumber {
+            height: 22px;
+            line-height: 22px;
+          }
+        }
+
+        .have-right {
+          width: 24px;
+          height: 24px;
+        }
+      }
+    }
+  }
+</style>

+ 111 - 0
src/views/asset/dialog/PaymentWay.vue

@@ -0,0 +1,111 @@
+<template>
+  <div class="payment-way">
+    <div class="apply-mask" @click="emits('paymentWayClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="apply-text pf600 fs18 fc121212">支付方式</div>
+      <div class="payment-main">
+        <div class="payment-item" v-for="(item, index) in paymentWayData" :key="index">
+          <div class="pf500 fs16 fc121212">{{ item }}</div>
+          <img src="@/assets/icon/asset/ic_check_blue.svg" alt="" />
+        </div>
+      </div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF">确认</div>
+      <div class="reset pf500 fs14 fcDF384C">重置</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  const emits = defineEmits(["paymentWayClose"]);
+
+  const paymentWayData = ["全部", "支付宝", "银行卡"];
+</script>
+<style lang="less" scoped>
+  .payment-way {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 313px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .apply-text {
+        margin-top: 21px;
+        width: 345px;
+        height: 24px;
+        line-height: 24px;
+        letter-spacing: 0.2px;
+      }
+
+      .payment-main {
+        margin-top: 15px;
+        width: 345px;
+
+        .payment-item {
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          margin-top: 15px;
+          width: 345px;
+          height: 25px;
+
+          &:first-child {
+            margin-top: 0px;
+          }
+
+          img {
+            width: 20px;
+            height: 20px;
+          }
+        }
+      }
+
+      .sure-btn {
+        margin-top: 24px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+
+      .reset {
+        margin-top: 15px;
+      }
+    }
+  }
+</style>

+ 262 - 0
src/views/asset/dialog/SellAndBuy.vue

@@ -0,0 +1,262 @@
+<template>
+  <div class="sell-and-buy">
+    <div class="apply-mask" @click="emits('sellAndBuyClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="apply-text pf600 fs18 fc121212">出售</div>
+      <div class="goods-info">
+        <div class="info-left">
+          <div class="shangjia">
+            <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>
+          <div class="chengjiao pf400 fs10 fc999999">成交量 12550 · 98.95% 成交率</div>
+        </div>
+        <div class="info-right">
+          <div class="text pf400 fs10 fc999999">单价</div>
+          <div class="price-number pf400 fs10 fc999999">
+            ¥
+            <span class="pf500 fs16 fc333333">6.58</span>
+            /USDT
+          </div>
+        </div>
+      </div>
+      <div class="required-quantity pf500 fs14 fc999999">
+        <div>需求数量</div>
+        <div>150200.00 USDT</div>
+      </div>
+      <div class="required-quantity pf500 fs14 fc999999">
+        <div>单笔限额</div>
+        <div>100.00 - 252020.00 USDT</div>
+      </div>
+      <div class="number-input">
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入卖出数量" />
+        <div class="all pf400 fs14 fc333333">USDT <span class="fcDF384C">全部</span></div>
+      </div>
+      <div class="use-number pf400 fs12 fc333333">可卖&nbsp; 215.0508 USDT</div>
+      <div class="account pf500 fs14 fc999999">
+        <div>收款方式</div>
+        <div class="account-right">
+          <div class="color"></div>
+          银行卡
+        </div>
+      </div>
+      <div class="account pf500 fs14 fc999999">
+        <div>收款账号</div>
+        <div class="account-right fcDF384C" @click="goAddBankAccount">
+          请选择
+          <img src="@/assets/icon/asset/right-arrow-black.svg" alt="" />
+        </div>
+      </div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF" @click="goAddzfbAccount">确定出售</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  import { useRoute, useRouter } from "vue-router";
+
+  const router = useRouter();
+
+  const emits = defineEmits(["sellAndBuyClose"]);
+
+  const goAddzfbAccount = () => {
+    router.push("/addzfbAccount");
+  };
+
+  const goAddBankAccount = () => {
+    router.push("/addBankAccount");
+  };
+</script>
+<style lang="less" scoped>
+  .sell-and-buy {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .apply-text {
+        margin-top: 20px;
+        height: 24px;
+        line-height: 24px;
+        letter-spacing: 0.2px;
+      }
+
+      .goods-info {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        margin-top: 11px;
+        width: 345px;
+
+        .info-left {
+          .shangjia {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            height: 24px;
+
+            img {
+              width: 24px;
+              height: 24px;
+            }
+
+            .left-name {
+              margin-left: 4px;
+            }
+
+            .vip-flag {
+              margin-left: 4px;
+              width: 18px;
+              height: 15px;
+              line-height: 15px;
+              text-align: center;
+              border-radius: 3px;
+              background: #df384c1a;
+            }
+          }
+
+          .chengjiao {
+            margin-top: 3px;
+          }
+        }
+
+        .info-right {
+          display: flex;
+          flex-direction: column;
+          justify-content: flex-start;
+          align-items: flex-end;
+
+          .text {
+            height: 24px;
+            line-height: 24px;
+          }
+
+          .price-number {
+            margin-top: -6px;
+          }
+        }
+      }
+
+      .required-quantity {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 10px;
+        width: 345px;
+        height: 18px;
+      }
+
+      .number-input {
+        position: relative;
+        margin-top: 18px;
+        width: 345px;
+        height: 45px;
+
+        .input {
+          padding-left: 11px;
+          width: 100%;
+          height: 100%;
+          box-sizing: border-box;
+          border-radius: 6px;
+          border: none;
+          outline: none;
+          background: #f5f5f5;
+        }
+
+        .all {
+          position: absolute;
+          top: 13px;
+          right: 11px;
+        }
+      }
+
+      .use-number {
+        margin-top: 7px;
+        width: 345px;
+        height: 18px;
+        line-height: 18px;
+      }
+
+      .account {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 8px;
+        width: 345px;
+        height: 18px;
+
+        .account-right {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          margin-top: 5px;
+          height: 12px;
+
+          .color {
+            margin-right: 3px;
+            width: 3px;
+            height: 10px;
+            border-radius: 2px;
+            background: #df384c;
+          }
+
+          img {
+            margin-left: 5px;
+          }
+        }
+      }
+
+      .sure-btn {
+        margin-top: 47px;
+        margin-bottom: 40px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+    }
+  }
+</style>

+ 2 - 2
src/views/asset/history/Index.vue

@@ -2,10 +2,10 @@
   <HeaderNav headerText="交易历史"></HeaderNav>
   <div class="history-index">
     <div class="notifi-classifi">
-      <div class="pf600 fs18 fc121212">合约</div>
+      <div class="pf600 fs18 fc121212">币币</div>
+      <div class="sys-notifi pf600 fs14 fcA8A8A8">合约</div>
       <div class="sys-notifi pf600 fs14 fcA8A8A8">秒合约</div>
       <div class="sys-notifi pf600 fs14 fcA8A8A8">期权</div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8">杠杆</div>
     </div>
     <div class="history-menu">
       <div class="pf600 fs14 fc121212" @click="messageChange('currentEntrustment')">

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

@@ -0,0 +1,205 @@
+<template>
+  <div class="order-all">
+    <div class="order-item">
+      <div class="user-info">
+        <div class="info-left">
+          <div class="info-shangjia">
+            <img src="@/assets/img/index/user/default-head.png" alt="" />
+            <div class="pf500 fs14 fc2C3131">商家昵称</div>
+            <div class="vip pf500 fs10 fcDF384C">V2</div>
+          </div>
+          <div class="number pf400 fs10 fc999999">成交量 12550 · 98.95% 成交率</div>
+        </div>
+        <div class="info-right pf500 fs12 fcFFFFFF">待放行</div>
+      </div>
+      <div class="pay-way pf500 fs12 fcA8A8A8">
+        <div>付款方式</div>
+        <div class="way-right">
+          <div class="color"></div>
+          银行卡
+        </div>
+      </div>
+      <div class="order-number pf500 fs12 fcA8A8A8">
+        <div>订单号</div>
+        <div class="number-right">
+          2508050505052008502060
+          <img src="@/assets/icon/index/CopySimple.svg" alt="" />
+        </div>
+      </div>
+      <div class="goods-info">
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买单价</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">6.95 USDT</div>
+        </div>
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买数量</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">0.215 USDT</div>
+        </div>
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买金额</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">1250 CNY</div>
+        </div>
+      </div>
+      <div class="order-func pf500 fs16 fcFFFFFF">
+        <div class="kefu">联系客服</div>
+        <div class="order">取消订单</div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup></script>
+<style lang="less" scoped>
+  .order-all {
+    margin: 0 auto;
+    margin-top: 15px;
+    padding: 15px 10px;
+    width: 345px;
+    border: 1px solid #ebebeb;
+    border-radius: 8px;
+    box-sizing: border-box;
+
+    .user-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+
+      .info-left {
+        .info-shangjia {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+
+          img {
+            margin-right: 4px;
+            width: 24px;
+            height: 24px;
+          }
+
+          .vip {
+            margin-left: 4px;
+            width: 18px;
+            height: 15px;
+            line-height: 15px;
+            text-align: center;
+            border-radius: 3px;
+            background: #df384c1a;
+          }
+        }
+
+        .number {
+          margin-top: 4px;
+        }
+      }
+
+      .info-right {
+        width: 76px;
+        height: 24px;
+        line-height: 24px;
+        text-align: center;
+        border-radius: 5px;
+        background: #df384c;
+      }
+    }
+
+    .pay-way {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 7px;
+      height: 18px;
+
+      .way-right {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+      }
+
+      .color {
+        margin-right: 4px;
+        width: 3px;
+        height: 10px;
+        border-radius: 2px;
+        background: #df384c;
+      }
+    }
+
+    .order-number {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 3px;
+      height: 18px;
+
+      .number-right {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        img {
+          margin-left: 4px;
+        }
+      }
+    }
+
+    .goods-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      margin-top: 3px;
+      width: 345px;
+      height: 38px;
+
+      .info-item {
+        display: flex;
+        flex-direction: column;
+        justify-content: flex-start;
+        align-items: center;
+        width: 30%;
+        height: 100%;
+
+        .item-top {
+          height: 18px;
+          line-height: 18px;
+        }
+
+        .item-bottom {
+          height: 20px;
+          line-height: 20px;
+        }
+      }
+    }
+
+    .order-func {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      margin-top: 10px;
+      width: 345px;
+      height: 38px;
+
+      .kefu {
+        width: 150px;
+        height: 38px;
+        line-height: 38px;
+        text-align: center;
+        border-radius: 6px;
+        background: #45b26b;
+      }
+
+      .order {
+        width: 150px;
+        height: 38px;
+        line-height: 38px;
+        text-align: center;
+        border-radius: 6px;
+        background: #df384c;
+      }
+    }
+  }
+</style>

+ 205 - 0
src/views/asset/otc/order/Buy.vue

@@ -0,0 +1,205 @@
+<template>
+  <div class="order-buy">
+    <div class="order-item">
+      <div class="user-info">
+        <div class="info-left">
+          <div class="info-shangjia">
+            <img src="@/assets/img/index/user/default-head.png" alt="" />
+            <div class="pf500 fs14 fc2C3131">商家昵称2</div>
+            <div class="vip pf500 fs10 fcDF384C">V2</div>
+          </div>
+          <div class="number pf400 fs10 fc999999">成交量 12550 · 98.95% 成交率</div>
+        </div>
+        <div class="info-right pf500 fs12 fcFFFFFF">待放行</div>
+      </div>
+      <div class="pay-way pf500 fs12 fcA8A8A8">
+        <div>付款方式</div>
+        <div class="way-right">
+          <div class="color"></div>
+          银行卡
+        </div>
+      </div>
+      <div class="order-number pf500 fs12 fcA8A8A8">
+        <div>订单号</div>
+        <div class="number-right">
+          2508050505052008502060
+          <img src="@/assets/icon/index/CopySimple.svg" alt="" />
+        </div>
+      </div>
+      <div class="goods-info">
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买单价</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">6.95 USDT</div>
+        </div>
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买数量</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">0.215 USDT</div>
+        </div>
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买金额</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">1250 CNY</div>
+        </div>
+      </div>
+      <div class="order-func pf500 fs16 fcFFFFFF">
+        <div class="kefu">联系客服</div>
+        <div class="order">取消订单</div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup></script>
+<style lang="less" scoped>
+  .order-buy {
+    margin: 0 auto;
+    margin-top: 15px;
+    padding: 15px 10px;
+    width: 345px;
+    border: 1px solid #ebebeb;
+    border-radius: 8px;
+    box-sizing: border-box;
+
+    .user-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+
+      .info-left {
+        .info-shangjia {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+
+          img {
+            margin-right: 4px;
+            width: 24px;
+            height: 24px;
+          }
+
+          .vip {
+            margin-left: 4px;
+            width: 18px;
+            height: 15px;
+            line-height: 15px;
+            text-align: center;
+            border-radius: 3px;
+            background: #df384c1a;
+          }
+        }
+
+        .number {
+          margin-top: 4px;
+        }
+      }
+
+      .info-right {
+        width: 76px;
+        height: 24px;
+        line-height: 24px;
+        text-align: center;
+        border-radius: 5px;
+        background: #df384c;
+      }
+    }
+
+    .pay-way {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 7px;
+      height: 18px;
+
+      .way-right {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+      }
+
+      .color {
+        margin-right: 4px;
+        width: 3px;
+        height: 10px;
+        border-radius: 2px;
+        background: #df384c;
+      }
+    }
+
+    .order-number {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 3px;
+      height: 18px;
+
+      .number-right {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        img {
+          margin-left: 4px;
+        }
+      }
+    }
+
+    .goods-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      margin-top: 3px;
+      width: 345px;
+      height: 38px;
+
+      .info-item {
+        display: flex;
+        flex-direction: column;
+        justify-content: flex-start;
+        align-items: center;
+        width: 30%;
+        height: 100%;
+
+        .item-top {
+          height: 18px;
+          line-height: 18px;
+        }
+
+        .item-bottom {
+          height: 20px;
+          line-height: 20px;
+        }
+      }
+    }
+
+    .order-func {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      margin-top: 10px;
+      width: 345px;
+      height: 38px;
+
+      .kefu {
+        width: 150px;
+        height: 38px;
+        line-height: 38px;
+        text-align: center;
+        border-radius: 6px;
+        background: #45b26b;
+      }
+
+      .order {
+        width: 150px;
+        height: 38px;
+        line-height: 38px;
+        text-align: center;
+        border-radius: 6px;
+        background: #df384c;
+      }
+    }
+  }
+</style>

+ 142 - 3
src/views/asset/otc/order/Index.vue

@@ -1,5 +1,144 @@
 <template>
-  <div>2</div>
+  <div class="loan-header">
+    <div class="header-content pf600 fs16 fc1F2937">
+      <img
+        class="left-arrow-image"
+        src="@/assets/icon/index/left-arrow.svg"
+        @click="toPath()" />
+      订单列表
+      <div class="save">
+        <img src="@/assets/icon/asset/rili.png" alt="" />
+      </div>
+    </div>
+  </div>
+  <div class="notifi-classifi">
+    <div
+      class="classifi-item pf600 fs18 fc121212"
+      :class="current == 'all' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+      @click="messageChange('all')">
+      全部
+      <div class="active-line" v-if="current == 'all'"></div>
+    </div>
+    <div
+      class="classifi-item pf600 fs14 fcA8A8A8"
+      :class="current == 'buy' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+      @click="messageChange('buy')">
+      购买
+      <div class="active-line" v-if="current == 'buy'"></div>
+    </div>
+    <div
+      class="classifi-item pf600 fs14 fcA8A8A8"
+      :class="current == 'sell' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+      @click="messageChange('sell')">
+      出售
+      <div class="active-line" v-if="current == 'sell'"></div>
+    </div>
+  </div>
+  <component :is="currentComponent" />
 </template>
-<script setup></script>
-<style lang="less" scoped></style>
+<script setup>
+  import All from "./All.vue";
+  import Buy from "./Buy.vue";
+  import Sell from "./Sell.vue";
+  import { ref, computed } from "vue";
+  import { useRoute, useRouter } from "vue-router";
+
+  const router = useRouter();
+
+  const current = ref("all");
+  const componentsMap = {
+    all: All,
+    buy: Buy,
+    sell: Sell,
+  };
+  const currentComponent = computed(() => componentsMap[current.value]);
+
+  const messageChange = (key) => {
+    current.value = key;
+  };
+
+  const toPath = () => {
+    router.back();
+  };
+</script>
+<style lang="less" scoped>
+  .loan-header {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1;
+    width: 100%;
+    height: 48px;
+    background: #ffffff;
+    overflow: hidden;
+
+    .header-content {
+      display: flex;
+      flex-direction: row;
+      justify-content: center;
+      align-items: center;
+      position: relative;
+      width: 100%;
+      height: 48px;
+
+      .left-arrow-image {
+        position: absolute;
+        left: 14px;
+        top: 16px;
+        width: 9px;
+        height: 16px;
+      }
+
+      .save {
+        position: absolute;
+        top: 15px;
+        right: 16px;
+
+        img {
+          width: 15px;
+          height: 16px;
+        }
+      }
+    }
+  }
+
+  .notifi-classifi {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-start;
+    align-items: flex-end;
+    margin: 0 auto;
+    margin-top: 48px;
+    width: 345px;
+    height: 24px;
+
+    .classifi-item {
+      position: relative;
+      margin-left: 43px;
+
+      .active-line {
+        position: absolute;
+        bottom: -6px;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 20px;
+        height: 3px;
+        background-color: #323233;
+        border-radius: 2px;
+      }
+
+      &:first-child {
+        margin-left: 0;
+      }
+    }
+
+    .current-classifi {
+      font-family: "PingFang SC";
+      font-style: normal;
+      font-weight: 600;
+      font-size: 18px;
+      color: #121212;
+      transition: color 0.3s, font-size 0.3s;
+    }
+  }
+</style>

+ 205 - 0
src/views/asset/otc/order/Sell.vue

@@ -0,0 +1,205 @@
+<template>
+  <div class="order-sell">
+    <div class="order-item">
+      <div class="user-info">
+        <div class="info-left">
+          <div class="info-shangjia">
+            <img src="@/assets/img/index/user/default-head.png" alt="" />
+            <div class="pf500 fs14 fc2C3131">商家昵称3</div>
+            <div class="vip pf500 fs10 fcDF384C">V2</div>
+          </div>
+          <div class="number pf400 fs10 fc999999">成交量 12550 · 98.95% 成交率</div>
+        </div>
+        <div class="info-right pf500 fs12 fcFFFFFF">待放行</div>
+      </div>
+      <div class="pay-way pf500 fs12 fcA8A8A8">
+        <div>付款方式</div>
+        <div class="way-right">
+          <div class="color"></div>
+          银行卡
+        </div>
+      </div>
+      <div class="order-number pf500 fs12 fcA8A8A8">
+        <div>订单号</div>
+        <div class="number-right">
+          2508050505052008502060
+          <img src="@/assets/icon/index/CopySimple.svg" alt="" />
+        </div>
+      </div>
+      <div class="goods-info">
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买单价</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">6.95 USDT</div>
+        </div>
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买数量</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">0.215 USDT</div>
+        </div>
+        <div class="info-item">
+          <div class="item-top pf500 fs12 fcA8A8A8">购买金额</div>
+          <div class="item-bottom pf500 fs12 fc2C3131">1250 CNY</div>
+        </div>
+      </div>
+      <div class="order-func pf500 fs16 fcFFFFFF">
+        <div class="kefu">联系客服</div>
+        <div class="order">取消订单</div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup></script>
+<style lang="less" scoped>
+  .order-sell {
+    margin: 0 auto;
+    margin-top: 15px;
+    padding: 15px 10px;
+    width: 345px;
+    border: 1px solid #ebebeb;
+    border-radius: 8px;
+    box-sizing: border-box;
+
+    .user-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+
+      .info-left {
+        .info-shangjia {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+
+          img {
+            margin-right: 4px;
+            width: 24px;
+            height: 24px;
+          }
+
+          .vip {
+            margin-left: 4px;
+            width: 18px;
+            height: 15px;
+            line-height: 15px;
+            text-align: center;
+            border-radius: 3px;
+            background: #df384c1a;
+          }
+        }
+
+        .number {
+          margin-top: 4px;
+        }
+      }
+
+      .info-right {
+        width: 76px;
+        height: 24px;
+        line-height: 24px;
+        text-align: center;
+        border-radius: 5px;
+        background: #df384c;
+      }
+    }
+
+    .pay-way {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 7px;
+      height: 18px;
+
+      .way-right {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+      }
+
+      .color {
+        margin-right: 4px;
+        width: 3px;
+        height: 10px;
+        border-radius: 2px;
+        background: #df384c;
+      }
+    }
+
+    .order-number {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 3px;
+      height: 18px;
+
+      .number-right {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        img {
+          margin-left: 4px;
+        }
+      }
+    }
+
+    .goods-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      margin-top: 3px;
+      width: 345px;
+      height: 38px;
+
+      .info-item {
+        display: flex;
+        flex-direction: column;
+        justify-content: flex-start;
+        align-items: center;
+        width: 30%;
+        height: 100%;
+
+        .item-top {
+          height: 18px;
+          line-height: 18px;
+        }
+
+        .item-bottom {
+          height: 20px;
+          line-height: 20px;
+        }
+      }
+    }
+
+    .order-func {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      margin-top: 10px;
+      width: 345px;
+      height: 38px;
+
+      .kefu {
+        width: 150px;
+        height: 38px;
+        line-height: 38px;
+        text-align: center;
+        border-radius: 6px;
+        background: #45b26b;
+      }
+
+      .order {
+        width: 150px;
+        height: 38px;
+        line-height: 38px;
+        text-align: center;
+        border-radius: 6px;
+        background: #df384c;
+      }
+    }
+  }
+</style>

+ 76 - 0
src/views/asset/otc/transaction/AddBankAccount.vue

@@ -0,0 +1,76 @@
+<template>
+  <HeaderNav headerText="添加银行卡账号"></HeaderNav>
+  <div class="add-zfb-account">
+    <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="请输入" />
+      </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="请输入" />
+      </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="请输入" />
+      </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="请输入" />
+      </div>
+    </div>
+    <div class="submit pf600 fs14 fcFFFFFF" @click="submit">提交</div>
+  </div>
+</template>
+<script setup>
+  import HeaderNav from "../../../index/components/HeaderNav.vue";
+</script>
+<style lang="less" scoped>
+  .add-zfb-account {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 48px;
+    width: 100%;
+
+    .account-item {
+      margin-top: 14px;
+      width: 345px;
+
+      .left-input {
+        width: 345px;
+        height: 45px;
+
+        .input {
+          padding-left: 11px;
+          margin-top: 5px;
+          width: 100%;
+          height: 100%;
+          box-sizing: border-box;
+          border-radius: 6px;
+          border: none;
+          outline: none;
+          background: #f5f5f5;
+        }
+      }
+    }
+
+    .submit {
+      margin-top: 264px;
+      width: 311px;
+      height: 40px;
+      line-height: 40px;
+      text-align: center;
+      border-radius: 100px;
+      background: #df384c;
+      letter-spacing: 0.2px;
+    }
+  }
+</style>

+ 76 - 0
src/views/asset/otc/transaction/AddzfbAccount.vue

@@ -0,0 +1,76 @@
+<template>
+  <HeaderNav headerText="添加支付宝账号"></HeaderNav>
+  <div class="add-zfb-account">
+    <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="请输入" />
+      </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="请输入" />
+      </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="请输入" />
+      </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="请输入" />
+      </div>
+    </div>
+    <div class="submit pf600 fs14 fcFFFFFF" @click="submit">提交</div>
+  </div>
+</template>
+<script setup>
+  import HeaderNav from "../../../index/components/HeaderNav.vue";
+</script>
+<style lang="less" scoped>
+  .add-zfb-account {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 48px;
+    width: 100%;
+
+    .account-item {
+      margin-top: 14px;
+      width: 345px;
+
+      .left-input {
+        width: 345px;
+        height: 45px;
+
+        .input {
+          padding-left: 11px;
+          margin-top: 5px;
+          width: 100%;
+          height: 100%;
+          box-sizing: border-box;
+          border-radius: 6px;
+          border: none;
+          outline: none;
+          background: #f5f5f5;
+        }
+      }
+    }
+
+    .submit {
+      margin-top: 264px;
+      width: 311px;
+      height: 40px;
+      line-height: 40px;
+      text-align: center;
+      border-radius: 100px;
+      background: #df384c;
+      letter-spacing: 0.2px;
+    }
+  }
+</style>

+ 365 - 2
src/views/asset/otc/transaction/Bulk.vue

@@ -1,5 +1,368 @@
 <template>
-  <div>3</div>
+  <img src="@/assets/icon/asset/dazong-sell-banner.svg" class="c2c" alt="" />
+  <div class="buy-sell">
+    <div class="buy-left">
+      <div class="buy-btn pf500 fs14 fcFFFFFF">购买</div>
+      <div class="sell-btn pf500 fs14 fc999999">出售</div>
+    </div>
+    <div class="buy-right">
+      <div class="text pf400 fs14 fc333333">CNY</div>
+      <img src="@/assets/icon/asset/bottom-arrow-black.svg" alt="" />
+    </div>
+  </div>
+  <div class="filter-area">
+    <div class="filter-left">
+      <div class="left-coin">
+        <img src="@/assets/icon/coin/bnb.svg" class="coin" alt="" />
+        <div class="text pf400 fs14 fc333333">BTC</div>
+        <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
+      </div>
+      <div class="left-money">
+        <div class="text pf400 fs14 fc333333">金额</div>
+        <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
+      </div>
+      <div class="left-pay-way">
+        <div class="text pf400 fs14 fc333333">支付方式</div>
+        <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
+      </div>
+    </div>
+    <div class="filter-right">
+      <img src="@/assets/icon/asset/filter.svg" alt="" />
+    </div>
+  </div>
+  <div class="goods-area">
+    <div class="goods-item" v-for="(item, index) in 2" :key="index">
+      <div class="item-merchant">
+        <div class="merchant-left">
+          <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>
+        <div class="merchant-right pf400 fs10 fc999999">
+          入驻时间: 2025-11-07 12:25:10
+        </div>
+      </div>
+      <div class="item-chengjiao-number pf400 fs10 fc999999">
+        成交量 12550 · 98.95% 成交率
+      </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>
+            /USDT
+          </div>
+          <div class="number pf400 fs10 fc999999">
+            数量 <span class="pf400 fs12 fc666666">1000.05 USDT</span>
+          </div>
+          <div class="number pf400 fs10 fc999999">
+            限额 <span class="pf400 fs12 fc666666">20000 - 1000.05 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
+          </div>
+          <div class="func-pay-way pf400 fs10 fc999999">
+            <div class="color"></div>
+            银行卡
+          </div>
+          <div class="func-main">
+            <div class="func-chat pf500 fs12 fcDF384C">聊天</div>
+            <div class="func-buy pf500 fs12 fcFFFFFF">验证购买</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
 </template>
 <script setup></script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+  .c2c {
+    margin-top: 13px;
+    width: 345px;
+    height: 100px;
+  }
+
+  .buy-sell {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    margin-top: 13px;
+    width: 345px;
+    height: 35px;
+
+    .buy-left {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      height: 100%;
+
+      .buy-btn {
+        width: 85px;
+        height: 35px;
+        line-height: 35px;
+        text-align: center;
+        border-radius: 6px;
+        background: #45b26b;
+      }
+
+      .sell-btn {
+        margin-left: 14px;
+        width: 85px;
+        height: 35px;
+        line-height: 35px;
+        text-align: center;
+        border-radius: 6px;
+        background: #f5f5f5;
+      }
+    }
+
+    .buy-right {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      width: 75px;
+      height: 35px;
+      line-height: 35px;
+      text-align: center;
+      border-radius: 6px;
+      background: #f5f5f5;
+
+      .text {
+        margin-left: 15px;
+      }
+
+      img {
+        margin-left: 12px;
+      }
+    }
+  }
+
+  .filter-area {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    padding-left: 6px;
+    margin-top: 13px;
+    width: 345px;
+    height: 18px;
+    box-sizing: border-box;
+
+    .filter-left {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      height: 18px;
+
+      .left-coin {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        height: 18px;
+
+        .coin {
+          width: 18px;
+          height: 18px;
+        }
+
+        .text {
+          margin-left: 3px;
+        }
+
+        .bottom-arrow {
+          margin-left: 5px;
+        }
+      }
+
+      .left-money {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 34px;
+        height: 18px;
+
+        .text {
+          margin-left: 3px;
+        }
+
+        .bottom-arrow {
+          margin-left: 5px;
+        }
+      }
+
+      .left-pay-way {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 34px;
+        height: 18px;
+
+        .text {
+          margin-left: 3px;
+        }
+
+        .bottom-arrow {
+          margin-left: 5px;
+        }
+      }
+    }
+
+    .filter-right {
+      display: flex;
+      flex-direction: row;
+      justify-content: center;
+      align-items: center;
+      height: 18px;
+    }
+  }
+
+  .goods-area {
+    width: 345px;
+
+    .goods-item {
+      padding: 0 10px;
+      margin-top: 10px;
+      width: 345px;
+      height: 150px;
+      border-radius: 8px;
+      border: 1px solid #ebebeb;
+      box-sizing: border-box;
+
+      .item-merchant {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 15px;
+        width: 100%;
+        height: 24px;
+
+        .merchant-left {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          height: 24px;
+
+          img {
+            width: 24px;
+            height: 24px;
+          }
+
+          .left-name {
+            margin-left: 4px;
+          }
+
+          .vip-flag {
+            margin-left: 4px;
+            width: 18px;
+            height: 15px;
+            line-height: 15px;
+            text-align: center;
+            border-radius: 3px;
+            background: #df384c1a;
+          }
+        }
+      }
+
+      .item-chengjiao-number {
+        margin-top: 6px;
+      }
+
+      .item-price {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        margin-top: 10px;
+
+        .price-area {
+          .price-number {
+            margin-top: 3px;
+          }
+
+          .number {
+            margin-top: 5px;
+            height: 13px;
+            line-height: 13px;
+
+            span {
+              margin-left: 1px;
+            }
+          }
+        }
+
+        .price-func {
+          display: flex;
+          flex-direction: column;
+          justify-content: flex-start;
+          align-items: flex-end;
+
+          .func-time {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            height: 12px;
+
+            img {
+              margin-right: 3px;
+              width: 9px;
+              height: 9px;
+            }
+          }
+
+          .func-pay-way {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            margin-top: 5px;
+            height: 12px;
+
+            .color {
+              margin-right: 3px;
+              width: 3px;
+              height: 10px;
+              border-radius: 2px;
+              background: #df384c;
+            }
+          }
+
+          .func-main {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            margin-top: 15px;
+            height: 24px;
+
+            .func-chat {
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #df384c1a;
+            }
+
+            .func-buy {
+              margin-left: 8px;
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #45b26b;
+            }
+          }
+        }
+      }
+    }
+  }
+</style>

+ 437 - 1
src/views/asset/otc/transaction/C2C.vue

@@ -1,11 +1,447 @@
 <template>
   <img src="@/assets/icon/asset/c2c.svg" class="c2c" alt="" />
+  <div class="buy-sell">
+    <div class="buy-left">
+      <div class="buy-btn pf500 fs14 fcFFFFFF">购买</div>
+      <div class="sell-btn pf500 fs14 fc999999">出售</div>
+    </div>
+    <div class="buy-right">
+      <div class="text pf400 fs14 fc333333">CNY</div>
+      <img src="@/assets/icon/asset/bottom-arrow-black.svg" alt="" />
+    </div>
+  </div>
+  <div class="filter-area">
+    <div class="filter-left">
+      <div class="left-coin">
+        <img src="@/assets/icon/coin/bnb.svg" class="coin" alt="" />
+        <div class="text pf400 fs14 fc333333">BTC</div>
+        <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
+      </div>
+      <div class="left-money" @click="amountFlag = true">
+        <div class="text pf400 fs14 fc333333">金额</div>
+        <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
+      </div>
+      <div class="left-pay-way" @click="paymentWayFlag = true">
+        <div class="text pf400 fs14 fc333333">支付方式</div>
+        <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
+      </div>
+    </div>
+    <div class="filter-right" @click="filterFlag = true">
+      <img src="@/assets/icon/asset/filter.svg" alt="" />
+    </div>
+  </div>
+  <div class="goods-area">
+    <div class="goods-item" v-for="(item, index) in 2" :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>
+        <div class="merchant-right pf400 fs10 fc999999">
+          入驻时间: 2025-11-07 12:25:10
+        </div>
+      </div>
+      <div class="item-chengjiao-number pf400 fs10 fc999999">
+        成交量 12550 · 98.95% 成交率
+      </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>
+            /USDT
+          </div>
+          <div class="number pf400 fs10 fc999999">
+            数量 <span class="pf400 fs12 fc666666">1000.05 USDT</span>
+          </div>
+          <div class="number pf400 fs10 fc999999">
+            限额 <span class="pf400 fs12 fc666666">20000 - 1000.05 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
+          </div>
+          <div class="func-pay-way pf400 fs10 fc999999">
+            <div class="color"></div>
+            银行卡
+          </div>
+          <div class="func-main">
+            <div class="func-chat pf500 fs12 fcDF384C">聊天</div>
+            <div class="func-buy pf500 fs12 fcFFFFFF" @click="sellAndBuyFlag = true">
+              购买
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <PaymentWay v-show="paymentWayFlag" @paymentWayClose="paymentWayClose"></PaymentWay>
+    <Amount v-show="amountFlag" @amountClose="amountClose"></Amount>
+    <Filter v-show="filterFlag" @filterClose="filterClose"></Filter>
+    <SellAndBuy v-show="sellAndBuyFlag" @sellAndBuyClose="sellAndBuyClose"></SellAndBuy>
+    <!-- 暂无收款方式,还没点击的地方 -->
+    <NotPaymentWay
+      v-show="notPaymnetWayFlag"
+      @notPaymentWayClose="notPaymentWayClose"></NotPaymentWay>
+    <!-- 添加收款方式,还没点击的地方 -->
+    <PaymentAccount
+      v-show="paymentAccountFlag"
+      @paymentAccountClose="paymentAccountClose"></PaymentAccount>
+    <!-- 取消订单,还没点击的地方 -->
+    <CancelOrder
+      v-show="cancelOrderFlag"
+      @cancelOrderClose="cancelOrderClose"></CancelOrder>
+    <!-- 是否完成付款,还没点击的地方 -->
+    <CompletePayment
+      v-show="completePaymentFlag"
+      @completePaymentClose="completePaymentClose"></CompletePayment>
+  </div>
 </template>
-<script setup></script>
+<script setup>
+  import { ref } from "vue";
+  import { useRoute, useRouter } from "vue-router";
+  import PaymentWay from "../../dialog/NotPaymentWay.vue";
+  import Amount from "../../dialog/Amount.vue";
+  import Filter from "../../dialog/Filter.vue";
+  import SellAndBuy from "../../dialog/SellAndBuy.vue";
+  import NotPaymentWay from "../../dialog/NotPaymentWay.vue";
+  import PaymentAccount from "../../dialog/PaymentAccount.vue";
+  import CancelOrder from "../../dialog/CancelOrder.vue";
+  import CompletePayment from "../../dialog/CompletePayment.vue";
+
+  const router = useRouter();
+
+  const goMerchantDetails = () => {
+    router.push("/OTCMerchantDetails");
+  };
+
+  const completePaymentFlag = ref(false);
+  const completePaymentClose = () => {
+    completePaymentFlag.value = false;
+  };
+
+  const cancelOrderFlag = ref(false);
+  const cancelOrderClose = () => {
+    cancelOrderFlag.value = false;
+  };
+
+  const paymentAccountFlag = ref(false);
+  const paymentAccountClose = () => {
+    paymentAccountFlag.value = false;
+  };
+
+  const notPaymnetWayFlag = ref(false);
+  const notPaymentWayClose = () => {
+    notPaymnetWayFlag.value = false;
+  };
+
+  const sellAndBuyFlag = ref(false);
+  const sellAndBuyClose = () => {
+    sellAndBuyFlag.value = false;
+  };
+
+  const filterFlag = ref(false);
+  const filterClose = () => {
+    filterFlag.value = false;
+  };
+
+  const amountFlag = ref(false);
+  const amountClose = () => {
+    amountFlag.value = false;
+  };
+
+  const paymentWayFlag = ref(false);
+  const paymentWayClose = () => {
+    paymentWayFlag.value = false;
+  };
+</script>
 <style lang="less" scoped>
   .c2c {
     margin-top: 13px;
     width: 345px;
     height: 100px;
   }
+
+  .buy-sell {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    margin-top: 13px;
+    width: 345px;
+    height: 35px;
+
+    .buy-left {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      height: 100%;
+
+      .buy-btn {
+        width: 85px;
+        height: 35px;
+        line-height: 35px;
+        text-align: center;
+        border-radius: 6px;
+        background: #45b26b;
+      }
+
+      .sell-btn {
+        margin-left: 14px;
+        width: 85px;
+        height: 35px;
+        line-height: 35px;
+        text-align: center;
+        border-radius: 6px;
+        background: #f5f5f5;
+      }
+    }
+
+    .buy-right {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      width: 75px;
+      height: 35px;
+      line-height: 35px;
+      text-align: center;
+      border-radius: 6px;
+      background: #f5f5f5;
+
+      .text {
+        margin-left: 15px;
+      }
+
+      img {
+        margin-left: 12px;
+      }
+    }
+  }
+
+  .filter-area {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    padding-left: 6px;
+    margin-top: 13px;
+    width: 345px;
+    height: 18px;
+    box-sizing: border-box;
+
+    .filter-left {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      height: 18px;
+
+      .left-coin {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        height: 18px;
+
+        .coin {
+          width: 18px;
+          height: 18px;
+        }
+
+        .text {
+          margin-left: 3px;
+        }
+
+        .bottom-arrow {
+          margin-left: 5px;
+        }
+      }
+
+      .left-money {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 34px;
+        height: 18px;
+
+        .text {
+          margin-left: 3px;
+        }
+
+        .bottom-arrow {
+          margin-left: 5px;
+        }
+      }
+
+      .left-pay-way {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 34px;
+        height: 18px;
+
+        .text {
+          margin-left: 3px;
+        }
+
+        .bottom-arrow {
+          margin-left: 5px;
+        }
+      }
+    }
+
+    .filter-right {
+      display: flex;
+      flex-direction: row;
+      justify-content: center;
+      align-items: center;
+      height: 18px;
+    }
+  }
+
+  .goods-area {
+    width: 345px;
+
+    .goods-item {
+      padding: 0 10px;
+      margin-top: 10px;
+      width: 345px;
+      height: 150px;
+      border-radius: 8px;
+      border: 1px solid #ebebeb;
+      box-sizing: border-box;
+
+      .item-merchant {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 15px;
+        width: 100%;
+        height: 24px;
+
+        .merchant-left {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          height: 24px;
+
+          img {
+            width: 24px;
+            height: 24px;
+          }
+
+          .left-name {
+            margin-left: 4px;
+          }
+
+          .vip-flag {
+            margin-left: 4px;
+            width: 18px;
+            height: 15px;
+            line-height: 15px;
+            text-align: center;
+            border-radius: 3px;
+            background: #df384c1a;
+          }
+        }
+      }
+
+      .item-chengjiao-number {
+        margin-top: 6px;
+      }
+
+      .item-price {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        margin-top: 10px;
+
+        .price-area {
+          .price-number {
+            margin-top: 3px;
+          }
+
+          .number {
+            margin-top: 5px;
+            height: 13px;
+            line-height: 13px;
+
+            span {
+              margin-left: 1px;
+            }
+          }
+        }
+
+        .price-func {
+          display: flex;
+          flex-direction: column;
+          justify-content: flex-start;
+          align-items: flex-end;
+
+          .func-time {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            height: 12px;
+
+            img {
+              margin-right: 3px;
+              width: 9px;
+              height: 9px;
+            }
+          }
+
+          .func-pay-way {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            margin-top: 5px;
+            height: 12px;
+
+            .color {
+              margin-right: 3px;
+              width: 3px;
+              height: 10px;
+              border-radius: 2px;
+              background: #df384c;
+            }
+          }
+
+          .func-main {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            margin-top: 15px;
+            height: 24px;
+
+            .func-chat {
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #df384c1a;
+            }
+
+            .func-buy {
+              margin-left: 8px;
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #45b26b;
+            }
+          }
+        }
+      }
+    }
+  }
 </style>

+ 161 - 2
src/views/asset/otc/transaction/Fast.vue

@@ -1,5 +1,164 @@
 <template>
-  <div>2</div>
+  <div class="buy-left">
+    <div class="buy-btn pf500 fs14 fcFFFFFF">购买</div>
+    <div class="sell-btn pf500 fs14 fc999999">出售</div>
+  </div>
+  <div class="user-staking margin-top43">
+    <div class="user-staking-title pf500 fs14 fc2C3131">我要支付</div>
+    <div class="user-staking-number">
+      <input
+        type="text"
+        class="user-staking-number-input pf400 fs26 fc333333"
+        placeholder="0" />
+      <div class="user-staking-number-coin pf500 fs18 fc1F2937">
+        <img src="@/assets/icon/coin/bnb.svg" class="coin" alt="" />BTC
+        <img src="@/assets/icon/index/bottom-arrow.svg" class="bottom-arrow" alt="" />
+      </div>
+    </div>
+    <div class="user-staking-line"></div>
+    <div class="tips pf400 fs12 fc999999">10 - 5000.000</div>
+  </div>
+  <div class="user-staking margin-top15">
+    <div class="user-staking-title pf500 fs14 fc2C3131">我将收到</div>
+    <div class="user-staking-number">
+      <input
+        type="text"
+        class="user-staking-number-input pf400 fs26 fc333333"
+        placeholder="0" />
+      <div class="user-staking-number-coin pf500 fs18 fc1F2937">
+        <img src="@/assets/icon/coin/bnb.svg" class="coin" alt="" />BTC
+        <img src="@/assets/icon/index/bottom-arrow.svg" class="bottom-arrow" alt="" />
+      </div>
+    </div>
+    <div class="user-staking-line"></div>
+    <div class="tips pf400 fs12 fc999999">1 CNY ≈ 0.1684258 BTC</div>
+  </div>
+  <div class="buy-sell-btn pf600 fs14 fcFFFFFF">购买</div>
 </template>
 <script setup></script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+  .buy-left {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-start;
+    margin-top: 15px;
+    width: 345px;
+    height: 35px;
+
+    .buy-btn {
+      width: 85px;
+      height: 35px;
+      line-height: 35px;
+      text-align: center;
+      border-radius: 6px;
+      background: #45b26b;
+    }
+
+    .sell-btn {
+      margin-left: 14px;
+      width: 85px;
+      height: 35px;
+      line-height: 35px;
+      text-align: center;
+      border-radius: 6px;
+      background: #f5f5f5;
+    }
+  }
+
+  .margin-top15 {
+    margin-top: 15px;
+  }
+
+  .margin-top43 {
+    margin-top: 43px;
+  }
+
+  .user-staking {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    width: 345px;
+
+    .user-staking-title {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      width: 345px;
+      height: 24px;
+
+      img {
+        margin-left: 6px;
+        width: 13px;
+        height: 13px;
+      }
+    }
+
+    .user-staking-number {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      width: 311px;
+      height: 40px;
+
+      .user-staking-number-input {
+        width: 191px;
+        height: 100%;
+        box-sizing: border-box;
+        border-radius: 6px;
+        border: none;
+        outline: none;
+      }
+
+      .user-staking-number-coin {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        width: 105px;
+        height: 40px;
+        border-radius: 30px;
+        border: 1px solid #ebebeb;
+        box-sizing: border-box;
+
+        .coin {
+          margin-left: 8px;
+          margin-right: 6px;
+          width: 24px;
+          height: 24px;
+        }
+
+        .bottom-arrow {
+          margin-left: 6px;
+          width: 12px;
+          height: 12px;
+        }
+      }
+    }
+
+    .user-staking-line {
+      margin-top: 22px;
+      width: 311px;
+      height: 1px;
+      background: #e2e8f0;
+    }
+
+    .tips {
+      margin-top: 3px;
+      width: 311px;
+      height: 24px;
+      line-height: 24px;
+    }
+  }
+
+  .buy-sell-btn {
+    margin-top: 50px;
+    width: 311px;
+    height: 40px;
+    line-height: 40px;
+    text-align: center;
+    border-radius: 100px;
+    background: #df384c;
+  }
+</style>

+ 51 - 5
src/views/asset/otc/transaction/Index.vue

@@ -14,12 +14,26 @@
   </div>
   <div class="index">
     <div class="notifi-classifi">
-      <div class="pf600 fs18 fc121212" @click="messageChange('c2c')">C2C</div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('fast')">
+      <div
+        class="classifi-item pf600 fs18 fc121212"
+        :class="current == 'c2c' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('c2c')">
+        C2C
+        <div class="active-line" v-if="current == 'c2c'"></div>
+      </div>
+      <div
+        class="classifi-item pf600 fs14 fcA8A8A8"
+        :class="current == 'fast' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('fast')">
         快捷交易
+        <div class="active-line" v-if="current == 'fast'"></div>
       </div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('bulk')">
+      <div
+        class="classifi-item pf600 fs14 fcA8A8A8"
+        :class="current == 'bulk' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('bulk')">
         大宗交易
+        <div class="active-line" v-if="current == 'bulk'"></div>
       </div>
     </div>
     <component :is="currentComponent" />
@@ -27,10 +41,13 @@
 </template>
 <script setup>
   import { ref, computed } from "vue";
+  import { useRoute, useRouter } from "vue-router";
   import C2C from "./C2C.vue";
   import Fast from "./Fast.vue";
   import Bulk from "./Bulk.vue";
 
+  const router = useRouter();
+
   const current = ref("c2c");
   const componentsMap = {
     c2c: C2C,
@@ -42,6 +59,10 @@
   const messageChange = (key) => {
     current.value = key;
   };
+
+  const toPath = () => {
+    router.back();
+  };
 </script>
 <style lang="less" scoped>
   .otc-header {
@@ -111,8 +132,33 @@
       width: 349px;
       height: 24px;
 
-      .sys-notifi {
-        margin-left: 42px;
+      .classifi-item {
+        position: relative;
+        margin-left: 43px;
+
+        .active-line {
+          position: absolute;
+          bottom: -6px;
+          left: 50%;
+          transform: translateX(-50%);
+          width: 20px;
+          height: 3px;
+          background-color: #323233;
+          border-radius: 2px;
+        }
+
+        &:first-child {
+          margin-left: 0;
+        }
+      }
+
+      .current-classifi {
+        font-family: "PingFang SC";
+        font-style: normal;
+        font-weight: 600;
+        font-size: 18px;
+        color: #121212;
+        transition: color 0.3s, font-size 0.3s;
       }
     }
   }

+ 259 - 3
src/views/asset/otc/user/Index.vue

@@ -1,5 +1,261 @@
 <template>
-  <div>4</div>
+  <HeaderNav headerText="我的"></HeaderNav>
+  <div class="otc-user">
+    <div class="user-info">
+      <img src="@/assets/img/index/user/default-head.png" alt="" />
+      <div class="info-name">
+        <div class="pf500 fs18 fc2C3131">用户昵称</div>
+        <div class="time pf500 fs12 fc999999">注册时间: 2025-11-07</div>
+      </div>
+    </div>
+    <div class="chengjiao-number pf500 fs10 fc999999">成交量 12550 · 98.95% 成交率</div>
+    <div class="certification-center">
+      <div class="certification-item pf500 fs10 fcDF384C">
+        <CheckBox v-model="baseFlag"></CheckBox>
+        <div class="text">基础认证</div>
+      </div>
+      <div class="certification-item pf500 fs10 fcDF384C">
+        <CheckBox v-model="baseFlag"></CheckBox>
+        <div class="text">身份认证</div>
+      </div>
+      <div class="certification-item pf500 fs10 fcDF384C">
+        <CheckBox v-model="baseFlag"></CheckBox>
+        <div class="text">高级认证</div>
+      </div>
+    </div>
+    <div class="user-details">
+      <div class="details-title pf600 fs18 fc2C3131">详情</div>
+      <div class="details-item margin-top10">
+        <div class="pf500 fs14 fc2C3131">成交单数</div>
+        <div class="pf500 fs12 fc2C3131">15020</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">购买</div>
+        <div class="pf500 fs12 fc999999">520</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">出售</div>
+        <div class="pf500 fs12 fc999999">12500</div>
+      </div>
+      <div class="line"></div>
+      <div class="details-item margin-top10">
+        <div class="pf500 fs14 fc2C3131">成交率</div>
+        <div class="pf500 fs12 fc2C3131">100.00%</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">购买</div>
+        <div class="pf500 fs12 fc999999">50.20%</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">出售</div>
+        <div class="pf500 fs12 fc999999">25.05%</div>
+      </div>
+      <div class="details-item margin-top13">
+        <div class="pf500 fs14 fc2C3131">交易对手数</div>
+        <div class="pf500 fs12 fc2C3131">894820</div>
+      </div>
+      <div class="details-item margin-top13">
+        <div class="pf500 fs14 fc2C3131">平均付款时间</div>
+        <div class="pf500 fs12 fc2C3131">1m15s</div>
+      </div>
+    </div>
+    <div class="kongbai"></div>
+    <div class="user-func">
+      <div
+        class="func-item"
+        v-for="(item, index) in userMenu"
+        :key="index"
+        @click="goMenuRouter(index)">
+        <div class="item-left pf500 fs14 fc333333">
+          <img :src="item.img" class="anquan-set" alt="" />
+          <div class="text">{{ item.name }}</div>
+        </div>
+        <img src="@/assets/icon/user/right-arrow.svg" class="right-arrow" alt="" />
+      </div>
+    </div>
+  </div>
 </template>
-<script setup></script>
-<style lang="less" scoped></style>
+<script setup>
+  import { ref } from "vue";
+  import { useRoute, useRouter } from "vue-router";
+  import HeaderNav from "../../../index/components/HeaderNav.vue";
+  import CheckBox from "../../../../components/ui/CheckBox.vue";
+
+  const router = useRouter();
+  const baseFlag = ref(true);
+
+  const userMenu = [
+    {
+      name: "我的关注",
+      img: require("@/assets/icon/asset/guanzhu.png"),
+    },
+    {
+      name: "联系客服",
+      img: require("@/assets/icon/asset/kefu.png"),
+    },
+    {
+      name: "交易指南",
+      img: require("@/assets/icon/asset/zhinan.png"),
+    },
+    {
+      name: "等级限额说明",
+      img: require("@/assets/icon/asset/dengji.png"),
+    },
+  ];
+
+  const goMenuRouter = (index) => {
+    if (index == 0) {
+      router.push("/myFollow");
+    } else if (index == 2) {
+      router.push("/transactionGuide");
+    } else if (index == 3) {
+      router.push("/levelLimit");
+    }
+  };
+</script>
+<style lang="less" scoped>
+  .otc-user {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 48px;
+    width: 100%;
+
+    .user-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      margin-top: 10px;
+      width: 345px;
+      height: 56px;
+
+      img {
+        width: 56px;
+        height: 56px;
+      }
+
+      .info-name {
+        margin-left: 16px;
+
+        .time {
+          margin-top: 3px;
+        }
+      }
+    }
+
+    .chengjiao-number {
+      margin-top: 2px;
+      width: 345px;
+      height: 24px;
+      line-height: 24px;
+    }
+
+    .certification-center {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      margin-top: 2px;
+      width: 345px;
+      height: 16px;
+
+      .certification-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 8px;
+
+        &:first-child {
+          margin-left: 0;
+        }
+
+        .text {
+          margin-left: 4px;
+        }
+      }
+    }
+
+    .user-details {
+      margin-top: 11px;
+      width: 345px;
+
+      .margin-top10 {
+        margin-top: 10px;
+      }
+
+      .margin-top7 {
+        margin-top: 7px;
+      }
+
+      .margin-top13 {
+        margin-top: 13px;
+      }
+
+      .details-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        width: 345px;
+        height: 18px;
+      }
+    }
+
+    .line {
+      margin-top: 15px;
+      width: 335px;
+      height: 1px;
+      background: #f5f5f5;
+    }
+
+    .kongbai {
+      margin-top: 12px;
+      width: 375px;
+      height: 8px;
+      background: #f5f5f5;
+    }
+
+    .user-func {
+      width: 345px;
+
+      .func-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 26.5px;
+        width: 345px;
+        height: 24px;
+
+        &:first-child {
+          margin-top: 18px;
+        }
+
+        .item-left {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          height: 24px;
+
+          .anquan-set {
+            width: 19px;
+            height: 19px;
+          }
+
+          .text {
+            margin-left: 8px;
+          }
+        }
+
+        .right-arrow {
+          width: 7px;
+          height: 15px;
+        }
+      }
+    }
+  }
+</style>

+ 25 - 0
src/views/asset/otc/user/LevelLimit.vue

@@ -0,0 +1,25 @@
+<template>
+  <HeaderNav headerText="等级限额消费说明"></HeaderNav>
+  <div class="level-limit pf500 fs14 fc666666">
+    随着区块链技术的不断发展和监管政策的逐步完善,交易限额的设定和调整不仅影响着投资者的交易策略,也预示着整个行业的未来走向。本文将深入探讨虚拟币交易所交易限额的现状、未来趋势以及其对投资者和行业的影响。<br />
+    虚拟币交易所交易限额的现状 <br />
+    目前,各大虚拟币交易所为了应对监管要求和市场风险,普遍设置了交易限额。这些限额通常包括单笔交易限额、每日交易限额和每月交易限额等。例如,某些交易所可能规定单笔交易不得超过10个比特币,每日交易总额不得超过100个比特币。这些限额的设定,一方面是为了防止市场操纵和洗钱等非法行为,另一方面也是为了保护投资者免受过度交易的风险。<br />
+    然而,随着虚拟货币市场的不断成熟和投资者需求的多样化,这些限额是否合理、是否能够满足市场需求,成为了业界和投资者关注的焦点。一些投资者认为,过低的交易限额限制了他们的投资策略,而一些交易所则担心过高的限额会增加市场风险<br />
+  </div>
+</template>
+<script setup>
+  import HeaderNav from "../../../index/components/HeaderNav.vue";
+</script>
+<style lang="less" scoped>
+  .level-limit {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin: 0 auto;
+    margin-top: 48px;
+    width: 345px;
+    line-height: 24px;
+    letter-spacing: 0.2px;
+  }
+</style>

+ 419 - 0
src/views/asset/otc/user/MerchantDetails.vue

@@ -0,0 +1,419 @@
+<template>
+  <HeaderNav headerText="详情"></HeaderNav>
+  <div class="merchant-details">
+    <div class="user-info">
+      <div class="info-left">
+        <img src="@/assets/img/index/user/default-head.png" alt="" />
+        <div class="info-name">
+          <div class="name-area pf500 fs18 fc2C3131">
+            用户昵称
+            <div class="vip pf500 fs10 fcDF384C">V2</div>
+          </div>
+          <div class="time pf500 fs12 fc999999">入驻时间: 2025-11-07</div>
+        </div>
+      </div>
+      <div class="info-right pf500 fs12 fcFFFFFF">关注</div>
+    </div>
+    <div class="chengjiao-number pf500 fs10 fc999999">成交量 12550 · 98.95% 成交率</div>
+    <div class="money-item pf500 fs10 fcDF384C">
+      <div class="checkbox">
+        <img src="@/assets/icon/asset/duihao.png" alt="" />
+      </div>
+      <div class="text">保证金 1000.00 USDT</div>
+    </div>
+    <div class="certification-center">
+      <div class="certification-item pf500 fs10 fcDF384C">
+        <div class="checkbox">
+          <img src="@/assets/icon/asset/duihao.png" alt="" />
+        </div>
+        <div class="text">视频认证</div>
+      </div>
+      <div class="certification-item pf500 fs10 fcDF384C">
+        <div class="checkbox">
+          <img src="@/assets/icon/asset/duihao.png" alt="" />
+        </div>
+        <div class="text">身份认证</div>
+      </div>
+      <div class="certification-item pf500 fs10 fcDF384C">
+        <div class="checkbox">
+          <img src="@/assets/icon/asset/duihao.png" alt="" />
+        </div>
+        <div class="text">电子邮件</div>
+      </div>
+      <div class="certification-item pf500 fs10 fcDF384C">
+        <div class="checkbox">
+          <img src="@/assets/icon/asset/duihao.png" alt="" />
+        </div>
+        <div class="text">手机</div>
+      </div>
+    </div>
+    <div class="send-message pf600 fs14 fcDF384C">发消息</div>
+    <div class="notifi-classifi">
+      <div class="pf600 fs18 fc121212" @click="current = 0">详情</div>
+      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="current = 1">委托单</div>
+    </div>
+    <div class="user-details" v-if="current == 0">
+      <div class="details-item margin-top10">
+        <div class="pf500 fs14 fc2C3131">成交单数</div>
+        <div class="pf500 fs12 fc2C3131">15020</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">购买</div>
+        <div class="pf500 fs12 fc999999">520</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">出售</div>
+        <div class="pf500 fs12 fc999999">12500</div>
+      </div>
+      <div class="line"></div>
+      <div class="details-item margin-top10">
+        <div class="pf500 fs14 fc2C3131">成交率</div>
+        <div class="pf500 fs12 fc2C3131">100.00%</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">购买</div>
+        <div class="pf500 fs12 fc999999">50.20%</div>
+      </div>
+      <div class="details-item margin-top7">
+        <div class="pf500 fs14 fc999999">出售</div>
+        <div class="pf500 fs12 fc999999">25.05%</div>
+      </div>
+      <div class="details-item margin-top13">
+        <div class="pf500 fs14 fc2C3131">交易对手数</div>
+        <div class="pf500 fs12 fc2C3131">894820</div>
+      </div>
+      <div class="details-item margin-top13">
+        <div class="pf500 fs14 fc2C3131">平均放币时间</div>
+        <div class="pf500 fs12 fc2C3131">1m15s</div>
+      </div>
+    </div>
+    <div class="user-order" v-else>
+      <div class="order-item" v-for="(item, index) in 2" :key="index">
+        <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>
+            /USDT
+          </div>
+          <div class="number pf400 fs10 fc999999">
+            数量 <span class="pf400 fs12 fc666666">1000.05 USDT</span>
+          </div>
+          <div class="number pf400 fs10 fc999999">
+            限额 <span class="pf400 fs12 fc666666">20000 - 1000.05 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
+          </div>
+          <div class="func-pay-way pf400 fs10 fc999999">
+            <div class="color"></div>
+            银行卡
+          </div>
+          <div class="func-main">
+            <div class="func-buy pf500 fs12 fcFFFFFF">购买</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup>
+  import { ref } from "vue";
+  import HeaderNav from "../../../index/components/HeaderNav.vue";
+
+  const baseFlag = ref(true);
+  const current = ref(1);
+</script>
+<style lang="less" scoped>
+  .merchant-details {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 48px;
+    width: 100%;
+
+    .user-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 10px;
+      width: 345px;
+      height: 56px;
+
+      .info-left {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        img {
+          width: 56px;
+          height: 56px;
+        }
+
+        .info-name {
+          margin-left: 16px;
+
+          .name-area {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+          }
+
+          .vip {
+            margin-left: 5px;
+            width: 18px;
+            height: 15px;
+            line-height: 15px;
+            text-align: center;
+            border-radius: 3px;
+            background: #df384c1a;
+          }
+
+          .time {
+            margin-top: 3px;
+          }
+        }
+      }
+
+      .info-right {
+        width: 60px;
+        height: 24px;
+        line-height: 24px;
+        text-align: center;
+        border-radius: 5px;
+        background: #df384c;
+      }
+    }
+
+    .chengjiao-number {
+      margin-top: 2px;
+      width: 345px;
+      height: 24px;
+      line-height: 24px;
+    }
+
+    .checkbox {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 16px;
+      height: 16px;
+      border-radius: 4px;
+      background: #df384c; /* 红色背景 */
+
+      img {
+        width: 10px;
+        height: 7px;
+      }
+    }
+
+    .money-item {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      width: 345px;
+
+      &:first-child {
+        margin-left: 0;
+      }
+
+      .text {
+        margin-left: 4px;
+      }
+    }
+
+    .certification-center {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      margin-top: 7px;
+      width: 345px;
+      height: 16px;
+
+      .certification-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-left: 8px;
+
+        &:first-child {
+          margin-left: 0;
+        }
+
+        .text {
+          margin-left: 4px;
+        }
+      }
+    }
+
+    .send-message {
+      margin-top: 21px;
+      width: 311px;
+      height: 40px;
+      line-height: 40px;
+      text-align: center;
+      border-radius: 100px;
+      background: #df384c1a;
+    }
+
+    .notifi-classifi {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: flex-end;
+      margin-top: 14px;
+      width: 349px;
+      height: 24px;
+
+      .sys-notifi {
+        margin-left: 67px;
+      }
+    }
+
+    .user-details {
+      width: 345px;
+
+      .margin-top10 {
+        margin-top: 10px;
+      }
+
+      .margin-top7 {
+        margin-top: 7px;
+      }
+
+      .margin-top13 {
+        margin-top: 13px;
+      }
+
+      .line {
+        margin-top: 15px;
+        width: 335px;
+        height: 1px;
+        background: #f5f5f5;
+      }
+
+      .details-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        width: 345px;
+        height: 18px;
+      }
+    }
+
+    .user-order {
+      margin-top: 10px;
+
+      .order-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        margin-top: 10px;
+        padding: 0 10px;
+        width: 345px;
+        height: 92px;
+        border-radius: 8px;
+        border: 1px solid #ebebeb;
+        box-sizing: border-box;
+
+        &:first-child {
+          margin-top: 0;
+        }
+
+        .price-area {
+          margin-top: 10px;
+
+          .price-number {
+            margin-top: 3px;
+          }
+
+          .number {
+            margin-top: 5px;
+            height: 13px;
+            line-height: 13px;
+
+            span {
+              margin-left: 1px;
+            }
+          }
+        }
+
+        .price-func {
+          display: flex;
+          flex-direction: column;
+          justify-content: flex-start;
+          align-items: flex-end;
+          margin-top: 10px;
+
+          .func-time {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            height: 12px;
+
+            img {
+              margin-right: 3px;
+              width: 9px;
+              height: 9px;
+            }
+          }
+
+          .func-pay-way {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            margin-top: 5px;
+            height: 12px;
+
+            .color {
+              margin-right: 3px;
+              width: 3px;
+              height: 10px;
+              border-radius: 2px;
+              background: #df384c;
+            }
+          }
+
+          .func-main {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            margin-top: 15px;
+            height: 24px;
+
+            .func-chat {
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #df384c1a;
+            }
+
+            .func-buy {
+              margin-left: 8px;
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #45b26b;
+            }
+          }
+        }
+      }
+    }
+  }
+</style>

+ 90 - 0
src/views/asset/otc/user/MyFollow.vue

@@ -0,0 +1,90 @@
+<template>
+  <HeaderNav headerText="我的关注"></HeaderNav>
+  <div class="user-area">
+    <div class="user-info" v-for="(item, index) in 3" :key="index">
+      <div class="info-left">
+        <img src="@/assets/img/index/user/default-head.png" alt="" />
+        <div class="info-name">
+          <div class="name-area pf500 fs18 fc2C3131">
+            用户昵称
+            <div class="vip pf500 fs10 fcDF384C">V2</div>
+          </div>
+          <div class="time pf500 fs12 fc999999">入驻时间: 2025-11-07</div>
+        </div>
+      </div>
+      <div class="info-right pf500 fs12 fcFFFFFF">关注</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  import HeaderNav from "../../../index/components/HeaderNav.vue";
+</script>
+<style lang="less" scoped>
+  .user-area {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 48px;
+  }
+
+  .user-info {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-top: 20px;
+    width: 345px;
+    height: 56px;
+
+    &:first-child {
+      margin-top: 0px;
+    }
+
+    .info-left {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+
+      img {
+        width: 56px;
+        height: 56px;
+      }
+
+      .info-name {
+        margin-left: 16px;
+
+        .name-area {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+        }
+
+        .vip {
+          margin-left: 5px;
+          width: 18px;
+          height: 15px;
+          line-height: 15px;
+          text-align: center;
+          border-radius: 3px;
+          background: #df384c1a;
+        }
+
+        .time {
+          margin-top: 3px;
+        }
+      }
+    }
+
+    .info-right {
+      width: 60px;
+      height: 24px;
+      line-height: 24px;
+      text-align: center;
+      border-radius: 5px;
+      background: #df384c;
+    }
+  }
+</style>

+ 49 - 0
src/views/asset/otc/user/TransactionGuide.vue

@@ -0,0 +1,49 @@
+<template>
+  <HeaderNav headerText="交易指南"></HeaderNav>
+  <div class="transaction-guide">
+    <div class="guide-title pf500 fs18 fc333333">交易指南</div>
+    <div class="guide-desc">
+      <div class="desc-item" v-for="(item, index) in 4" :key="index">
+        <img src="@/assets/icon/asset/right-arrow-black.svg" alt="" />
+        <div class="item-text pf500 fs14 fc666666">
+          交易指南文本内容标题交易指南文本内容标题交易指南文本内容标题交易指南文本内容标题
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup>
+  import HeaderNav from "../../../index/components/HeaderNav.vue";
+</script>
+<style lang="less" scoped>
+  .transaction-guide {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
+    margin-top: 48px;
+    width: 100%;
+
+    .guide-title {
+      width: 345px;
+    }
+
+    .guide-desc {
+      width: 327px;
+
+      .desc-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        padding: 16px 0;
+        width: 100%;
+        border-bottom: 1px solid #f5f5f5;
+
+        .item-text {
+          margin-left: 14px;
+        }
+      }
+    }
+  }
+</style>

+ 10 - 9
src/views/bitcoin/TradeLayout.vue

@@ -3,7 +3,15 @@
     <div class="market-nav">
       <div class="nav-left">
         <div
-          class="nav-item pf600"
+          class="nav-item pf600 "
+          :class="isCurrent('Cryptocurrency') ? 'fs18 fc121212' : 'fs14 fcA8A8A8'"
+          @click="switchTab('Cryptocurrency')"
+        >
+          币币
+          <div v-if="isCurrent('Cryptocurrency')" class="active-line"></div>
+        </div>
+        <div
+          class="nav-item pf600 sys-notifi"
           :class="isCurrent('TradeContract') ? 'fs18 fc121212' : 'fs14 fcA8A8A8'"
           @click="switchTab('TradeContract')"
         >
@@ -29,14 +37,7 @@
           <div v-if="isCurrent('TradeOptions')" class="active-line"></div>
         </div>
 
-        <div
-          class="nav-item pf600 sys-notifi"
-          :class="isCurrent('Cryptocurrency') ? 'fs18 fc121212' : 'fs14 fcA8A8A8'"
-          @click="switchTab('Cryptocurrency')"
-        >
-          币币交易
-          <div v-if="isCurrent('Cryptocurrency')" class="active-line"></div>
-        </div>
+
       </div>
     </div>
 

+ 7 - 7
src/views/bitcoin/lever/CryptocurrencyTrading.vue

@@ -1,12 +1,12 @@
-<script setup>
-
-</script>
-
 <template>
-  <div style="margin-top: 60px">开发中</div>
-
+  <div class="trade-page">
+    <h2>BTC/USDT 永续</h2>
+  </div>
 </template>
 
-<style scoped lang="less">
+<script setup>
+</script>
+
+<style>
 
 </style>

+ 2 - 2
src/views/bitcoin/lever/TradeSeconds.vue

@@ -63,7 +63,7 @@
     <!-- 这里的 chart-wrapper 负责控制 padding 和高度 -->
     <div class="chart-wrapper">
       <!-- 引入封装好的组件,只需传数据和高度 -->
-      <KlineChart
+      <TradeChart
         :data="kLineData"
         height="100%"
       />
@@ -83,7 +83,7 @@ import ChooseThisCycle from './components/ChooseThisCycle.vue'
 import sellOrder from '@/views/bitcoin/components/sellOrder.vue'
 
 // 1. 引入新封装的组件 (请确保路径正确)
-import KlineChart from '@/views/bitcoin/lever/components/KLineChart.vue'
+import TradeChart from '@/views/bitcoin/lever/components/TradeChart.vue'
 
 const route = useRoute()
 const symbolTitle = ref(route.params.id || 'BTCUSDT')

+ 0 - 133
src/views/bitcoin/lever/components/KLineChart.vue

@@ -1,133 +0,0 @@
-<template>
-  <div class="kline-wrapper" :style="{ height: height }">
-    <div ref="chartContainer" class="kline-chart"></div>
-  </div>
-</template>
-
-<script setup>
-import { onMounted, onBeforeUnmount, ref, watch, nextTick, toRaw } from 'vue'
-import * as klinecharts from 'klinecharts'
-
-const props = defineProps({
-  data: { type: Array, default: () => [] },
-  height: { type: String, default: '100%' },
-  precision: { type: Object, default: () => ({ price: 2, volume: 2 }) },
-  colors: {
-    type: Object,
-    default: () => ({
-      up: '#2EBD85',
-      down: '#F6465D',
-      grid: '#F2F4F6',
-      text: '#929AA5',
-      targetLine: '#4A6EF5'
-    })
-  }
-})
-
-const chartContainer = ref(null)
-let chartInstance = null
-
-const initChart = () => {
-  if (!chartContainer.value) return
-  if (chartInstance) klinecharts.dispose(chartContainer.value)
-
-  chartInstance = klinecharts.init(chartContainer.value)
-
-  // 设置精度
-  const { price, volume } = props.precision
-  if (chartInstance.setPriceVolumePrecision) {
-    chartInstance.setPriceVolumePrecision(price, volume)
-  } else if (chartInstance.setPrecision) {
-    chartInstance.setPrecision(price, volume)
-  }
-
-  // 样式配置
-  const { up, down, grid, text, targetLine } = props.colors
-  chartInstance.setStyleOptions({
-    grid: { show: true, horizontal: { show: true, size: 1, color: grid, style: 'dash', dashValue: [5, 5] }, vertical: { show: false } },
-    candle: {
-      type: 'candle_solid',
-      bar: { upColor: up, downColor: down, noChangeColor: up },
-      priceMark: {
-        show: true,
-        last: { show: true, upColor: up, downColor: down, line: { show: true, style: 'dash' }, text: { show: true, color: '#FFF', paddingLeft: 4, paddingRight: 4, borderRadius: 2 } }
-      },
-      tooltip: { showRule: 'follow_cross', showType: 'rect', dataSource: 'none' }
-    },
-    xAxis: { axisLine: { show: false }, tickLine: { show: false }, tickText: { color: text, size: 10, paddingTop: 8 } },
-    yAxis: { inside: true, axisLine: { show: false }, tickLine: { show: false }, tickText: { color: text, size: 10, paddingLeft: 8 } },
-  })
-
-  chartInstance.createTechnicalIndicator('VOL', false, { id: 'pane_1', heightRatio: 0.2 })
-
-  // 初始加载
-  if (props.data && props.data.length > 0) {
-    chartInstance.applyNewData(toRaw(props.data))
-  }
-}
-
-// --- 🔥 核心修复:智能判断是“更新”还是“重置” ---
-watch(() => props.data, (newData) => {
-  if (!chartInstance) return
-
-  const rawData = toRaw(newData)
-  const currentList = chartInstance.getDataList()
-
-  // 1. 如果新数据为空,清空图表
-  if (rawData.length === 0) {
-    chartInstance.clearData()
-    return
-  }
-
-  // 2. 如果当前图表为空,直接加载
-  if (currentList.length === 0) {
-    chartInstance.applyNewData(rawData)
-    return
-  }
-
-  // 3. 🔥 关键判断:
-  // 如果第一根 K 线的时间戳变了,说明切换了周期或币种 -> 全量重置
-  const firstOld = currentList[0]
-  const firstNew = rawData[0]
-  if (firstOld.timestamp !== firstNew.timestamp) {
-    chartInstance.applyNewData(rawData)
-    return
-  }
-
-  // 4. 如果第一根时间没变,说明是实时跳动或追加 -> 增量更新
-  if (rawData.length > 0) {
-    const lastData = rawData[rawData.length - 1]
-    chartInstance.updateData(lastData)
-  }
-}, { deep: true })
-
-// 监听精度
-watch(() => props.precision, (val) => {
-  if (chartInstance) {
-    if (chartInstance.setPriceVolumePrecision) chartInstance.setPriceVolumePrecision(val.price, val.volume)
-    else if (chartInstance.setPrecision) chartInstance.setPrecision(val.price, val.volume)
-  }
-}, { deep: true })
-
-onMounted(() => {
-  nextTick(() => initChart())
-  window.addEventListener('resize', handleResize)
-})
-
-onBeforeUnmount(() => {
-  window.removeEventListener('resize', handleResize)
-  if (chartInstance) {
-    klinecharts.dispose(chartContainer.value)
-    chartInstance = null
-  }
-})
-
-const handleResize = () => {
-  if (chartInstance) chartInstance.resize()
-}
-</script>
-
-<style scoped>
-.kline-wrapper { width: 100%; position: relative; }
-.kline-chart { width: 100%; height: 100%; }
-</style>

+ 0 - 0
src/views/bitcoin/lever/components/TradeChart.vue


+ 1 - 1
src/views/index/ApplyPermission.vue

@@ -39,7 +39,7 @@
       z-index: -1;
       width: 100%;
       min-height: 100vh;
-      background: #b3b3b3;
+      background: rgba(0, 0, 0, 0.5);
     }
 
     .apply-content {

+ 81 - 34
src/views/index/Index.vue

@@ -2,13 +2,13 @@
   <div class="index">
     <div class="index-func">
       <div class="func-head">
-        <img src="../../assets/img/index/default-img.svg" alt="" @click="goUser" />
+        <img src="@/assets/img/index/default-img.png" alt="" @click="goUser" />
       </div>
       <div class="search-currency pf400 fs14 fcA9A9A9" @click="goSearch">
         <img src="../../assets/icon/index/search-gray.svg" class="search-img" alt="" />
         搜索您关心的币种
       </div>
-      <div class="qr-code">
+      <div class="qr-code" @click="goQrCode">
         <img src="../../assets/icon/index/ic_qrcode_bk.svg" alt="" />
       </div>
       <div class="notification" @click="goNotifi">
@@ -18,18 +18,28 @@
     <div class="asset-total">
       <div class="asset-title pf400 fs16 fc1F2937">
         理财总资产(USDT)
-        <img src="../../assets/icon/index/EyeClosed.svg" class="eye-close" alt="" />
+        <img :src="isHide ? eyeOpen : eyeClose" class="eye-close" @click="toggleEye" />
+      </div>
+      <div class="asset-number pf600 fs32 fc1F2937" :class="{ 'mask-style': isHide }">
+        {{ isHide ? "···········" : "1,125,158.00" }}
+      </div>
+      <div
+        class="asset-approximately pf400 fs16 fcDF384C"
+        :class="{ 'mask-style': isHide }">
+        {{ isHide ? "·········" : "≈35,458.00" }}
       </div>
-      <div class="asset-number pf600 fs32 fc1F2937">1,125,158.00</div>
-      <div class="asset-approximately pf400 fs16 fcDF384C">≈35,458.00</div>
       <div class="asset-revenue">
         <div class="asset-left">
           <div class="text pf400 fs12 fc6A7187">昨日收益(USDT)</div>
-          <div class="number pf400 fs16 fc061237">5,678.00</div>
+          <div class="number pf400 fs16 fc061237" :class="{ 'mask-style': isHide }">
+            {{ isHide ? "·········" : "5,678.00" }}
+          </div>
         </div>
         <div class="asset-right">
           <div class="text pf400 fs12 fc6A7187">累计收益(USDT)</div>
-          <div class="number pf400 fs16 fc061237">5,678.00</div>
+          <div class="number pf400 fs16 fc061237" :class="{ 'mask-style': isHide }">
+            {{ isHide ? "·········" : "5,678.00" }}
+          </div>
         </div>
       </div>
     </div>
@@ -52,57 +62,72 @@
 </template>
 <script setup>
   import { useRoute, useRouter } from "vue-router";
+  import { ref } from "vue";
   import HotCoin from "./components/HotCoin.vue";
   import HotFinancial from "./components/HotFinancial.vue";
 
   const router = useRouter();
 
+  const isHide = ref(false);
+
+  const toggleEye = () => {
+    isHide.value = !isHide.value;
+  };
+
+  const eyeClose = require("@/assets/icon/index/EyeClosed.svg");
+  const eyeOpen = require("@/assets/icon/index/eye-open.svg");
+
   const indexMenu = [
     {
-      name: "ICO功能",
-      image: require("@/assets/img/index/Rectangle 2.svg"),
+      name: "秒合约",
+      image: require("@/assets/icon/index/Rectangle 6.png"),
     },
     {
-      name: "质押理财",
-      image: require("@/assets/img/index/Rectangle 3.svg"),
+      name: "充币",
+      image: require("@/assets/icon/index/Rectangle 8.png"),
     },
     {
-      name: "贷款",
-      image: require("@/assets/img/index/Rectangle 4.svg"),
+      name: "质押理财",
+      image: require("@/assets/icon/index/Rectangle 3.png"),
     },
     {
-      name: "邀请推广",
-      image: require("@/assets/img/index/Rectangle 5.svg"),
+      name: "贷款",
+      image: require("@/assets/icon/index/Rectangle 4.png"),
     },
     {
-      name: "秒合约",
-      image: require("@/assets/img/index/Rectangle 6.svg"),
+      name: "OTC",
+      image: require("@/assets/icon/index/Rectangle 9.png"),
     },
     {
-      name: "客服",
-      image: require("@/assets/img/index/Rectangle 7.svg"),
+      name: "ICO",
+      image: require("@/assets/icon/index/Rectangle 2.png"),
     },
     {
-      name: "充币",
-      image: require("@/assets/img/index/Rectangle 8.svg"),
+      name: "邀请推广",
+      image: require("@/assets/icon/index/Rectangle 5.png"),
     },
     {
-      name: "OTC交易",
-      image: require("@/assets/img/index/user/otc.svg"),
+      name: "客服",
+      image: require("@/assets/icon/index/Rectangle 7.png"),
     },
   ];
 
   const goMenu = (index) => {
     if (index == 0) {
-      router.push("/icoIndex");
+      router.push("/bitcoin/seconds");
     } else if (index == 1) {
-      router.push("/financialIndex");
+      router.push("/rechargeIndex");
     } else if (index == 2) {
+      router.push("/financialIndex");
+    } else if (index == 3) {
       router.push("/loanIndex");
+    } else if (index == 4) {
+      router.push("/otcIndex");
+    } else if (index == 5) {
+      router.push("/icoIndex");
     } else if (index == 6) {
-      router.push("/rechargeIndex");
+      router.push("/invite");
     } else if (index == 7) {
-      router.push("/otcIndex");
     }
   };
 
@@ -117,6 +142,10 @@
   const goUser = () => {
     router.push("/indexUser");
   };
+
+  const goQrCode = () => {
+    // router.push("/splashScreen");
+  };
 </script>
 <style lang="less" scoped>
   .index {
@@ -124,25 +153,36 @@
     flex-direction: column;
     justify-content: flex-start;
     align-items: center;
-    margin-bottom: 40px;
+    margin-bottom: 80px;
     width: 100%;
 
     .index-func {
+      position: fixed;
+      left: 0px;
+      top: 0px;
+      z-index: 10;
       display: flex;
       flex-direction: row;
       justify-content: space-between;
       align-items: center;
-      margin-top: 21px;
-      width: 345px;
-      height: 38px;
+      padding: 20px 15px 0 15px;
+      width: 100%;
+      background: #ffffff;
+      box-sizing: border-box;
 
       .func-head {
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        align-items: center;
         width: 38px;
         height: 38px;
+        border-radius: 12px;
+        background: #f5f5f5;
 
         img {
-          width: 38px;
-          height: 38px;
+          width: 18px;
+          height: 18px;
         }
       }
 
@@ -200,9 +240,16 @@
       display: flex;
       flex-direction: column;
       justify-content: flex-start;
-      margin-top: 17px;
+      margin-top: 70px;
       width: 343px;
 
+      .mask-style {
+        font-size: 24px !important;
+        letter-spacing: -4px;
+        font-weight: 600;
+        opacity: 0.9;
+      }
+
       .asset-title {
         display: flex;
         flex-direction: row;

+ 1 - 1
src/views/index/RiskTips.vue

@@ -29,7 +29,7 @@
   </div>
 </template>
 <script setup>
-  import CheckBox from "../../components/ui/CheckBox.vue.vue";
+  import CheckBox from "../../components/ui/CheckBox.vue";
   import { ref } from "vue";
 
   const tipsFlag = ref(false);

+ 29 - 6
src/views/index/SearchIcon.vue

@@ -9,11 +9,11 @@
       <img src="../../assets/icon/index/search-input.svg" alt="" />
     </div>
     <div class="icon-list">
-      <div class="icon-item" v-for="(item, index) in 5" :key="index">
-        <img src="../../assets/img/index/Frame 7.svg" class="icon-img" alt="" />
+      <div class="icon-item" v-for="(item, index) in iconData" :key="index">
+        <img :src="item.img" class="icon-img" alt="" />
         <div class="icon-name">
-          <div class="upper-name pc600 fs16 fc1F2937">Ethereum</div>
-          <div class="letter-name pc400 fs14 fc4B5563">ETH</div>
+          <div class="upper-name pc600 fs16 fc1F2937">{{ item.fullName }}</div>
+          <div class="letter-name pc400 fs14 fc4B5563">{{ item.abbreviation }}</div>
         </div>
         <div class="icon-love">
           <img src="../../assets/icon/index/Star.svg" alt="" />
@@ -24,6 +24,29 @@
 </template>
 <script setup>
   import HeaderNav from "./components/HeaderNav.vue";
+
+  const iconData = [
+    {
+      img: require("@/assets/icon/coin/Ethereum.png"),
+      fullName: "Ethereum",
+      abbreviation: "ETH",
+    },
+    {
+      img: require("@/assets/icon/coin/CardanoBadge.svg"),
+      fullName: "Cardano",
+      abbreviation: "CAR",
+    },
+    {
+      img: require("@/assets/icon/coin/Dogecoin.png"),
+      fullName: "Dogecoin",
+      abbreviation: "DOGE",
+    },
+    {
+      img: require("@/assets/icon/coin/Solana.png"),
+      fullName: "Solana",
+      abbreviation: "SOL",
+    },
+  ];
 </script>
 <style lang="less" scoped>
   .search-icon {
@@ -35,7 +58,7 @@
 
     .search-input {
       position: relative;
-      margin-top: 72px;
+      margin-top: 50px;
       width: 343px;
       height: 48px;
 
@@ -51,7 +74,7 @@
 
       img {
         position: absolute;
-        top: 15px;
+        top: 26px;
         left: 14px;
         width: 17px;
         height: 17px;

+ 4 - 1
src/views/index/SplashScreen.vue

@@ -2,8 +2,11 @@
   <div class="splash-screen">
     <img src="../../assets/img/index/SplashScreen.png" alt="" />
   </div>
+  <ApplyPermission></ApplyPermission>
 </template>
-<script setup></script>
+<script setup>
+  import ApplyPermission from "./ApplyPermission.vue";
+</script>
 <style lang="less" scoped>
   .splash-screen {
     width: 100%;

+ 53 - 8
src/views/index/User.vue

@@ -82,6 +82,14 @@
       name: "划转",
       image: require("@/assets/img/index/user/huazhuan.svg"),
     },
+    {
+      name: "我的贷款",
+      image: require("@/assets/icon/index/Rectangle 4.png"),
+    },
+    {
+      name: "我的资产",
+      image: require("@/assets/icon/index/zichan.png"),
+    },
   ];
 
   const transactionMenu = [
@@ -98,8 +106,8 @@
       image: require("@/assets/img/index/user/qiquan.svg"),
     },
     {
-      name: "杠杆",
-      image: require("@/assets/img/index/user/ganggan.svg"),
+      name: "币币",
+      image: require("@/assets/icon/index/bibi.png"),
     },
     {
       name: "质押理财",
@@ -128,10 +136,22 @@
       name: "KYC认证",
       image: require("@/assets/img/index/user/kyc.svg"),
     },
+    {
+      name: "切换语言",
+      image: require("@/assets/icon/index/yuyan.png"),
+    },
     {
       name: "帮助中心",
       image: require("@/assets/img/index/user/help.svg"),
     },
+    {
+      name: "安全设置",
+      image: require("@/assets/icon/index/anquanshezhi.png"),
+    },
+    {
+      name: "关于我们",
+      image: require("@/assets/icon/index/aboutus.png"),
+    },
   ];
 </script>
 <style lang="less" scoped>
@@ -209,9 +229,8 @@
       flex-direction: column;
       justify-content: flex-start;
       align-items: center;
-      margin-top: 25px;
+      margin-top: 23px;
       width: 345px;
-      height: 96px;
 
       .asset-title {
         width: 345px;
@@ -223,19 +242,32 @@
       .index-menu {
         display: flex;
         flex-direction: row;
-        justify-content: space-between;
+        justify-content: flex-start;
+        flex-wrap: wrap;
         margin-top: 15px;
         width: 317px;
-        height: 139px;
 
         .menu-item {
           display: flex;
           flex-direction: column;
           justify-content: flex-start;
           align-items: center;
+          margin-left: 29.6px;
           width: 57px;
           height: 57px;
 
+          &:nth-child(1),
+          &:nth-child(5) {
+            margin-left: 0px;
+          }
+
+          &:nth-child(5),
+          &:nth-child(6),
+          &:nth-child(7),
+          &:nth-child(8) {
+            margin-top: 25px;
+          }
+
           img {
             width: 32px;
             height: 32px;
@@ -328,19 +360,32 @@
       .index-menu {
         display: flex;
         flex-direction: row;
-        justify-content: space-between;
+        justify-content: flex-start;
+        flex-wrap: wrap;
         margin-top: 15px;
         width: 317px;
-        height: 139px;
 
         .menu-item {
           display: flex;
           flex-direction: column;
           justify-content: flex-start;
           align-items: center;
+          margin-left: 29.6px;
           width: 57px;
           height: 57px;
 
+          &:nth-child(1),
+          &:nth-child(5) {
+            margin-left: 0px;
+          }
+
+          &:nth-child(5),
+          &:nth-child(6),
+          &:nth-child(7),
+          &:nth-child(8) {
+            margin-top: 25px;
+          }
+
           img {
             width: 32px;
             height: 32px;

+ 12 - 1
src/views/index/cloudComputingPower/Index.vue

@@ -23,7 +23,7 @@
                 <div>0.0176/T/天</div>
               </div>
               <div class="info-bottom">
-                <div class="pf500 fs10 fc121212">
+                <div class="bottom-coin pf500 fs10 fc121212">
                   <img src="@/assets/icon/coin/bnb.svg" alt="" />
                   BTC
                 </div>
@@ -183,6 +183,17 @@
                 width: 100%;
                 height: 15px;
 
+                .bottom-coin {
+                  display: flex;
+                  flex-direction: row;
+                  justify-content: flex-start;
+                  align-items: center;
+
+                  img {
+                    margin-right: 2px;
+                  }
+                }
+
                 .start-time {
                   display: flex;
                   flex-direction: row;

+ 24 - 80
src/views/index/components/HotCoin.vue

@@ -37,8 +37,8 @@
       </div>
     </div>
     <div class="coin-body" >
-     <div v-show="item.change_rate" class="body-item" v-for="(item, index) in coinList" :key="index">
-      <div class="item-left" @click="router.push({ path: '/marketDetails', query: { id: item.id,type: item.symbol.toLowerCase()} })">
+     <div class="body-item" v-for="(item, index) in coinList" :key="item.id || index">
+      <div  class="item-left" @click="router.push({ path: '/marketDetails', query: { id: item.id, type: item.symbol.toLowerCase()} })">
         <div class="coin-img" >
           <img :src="item.logo" alt="" />
         </div>
@@ -48,19 +48,20 @@
         </div>
         <div class="coin-echars"></div>
         <div class="coin-price">
-          <div class="upper-price pf500 fs14 fc2C3131">{{ formatPrice(item.price) }}</div>
-          <div class="letter-price pf400 fs10 fcA9A9A9">≈ ${{ formatPrice(item.price) }}</div>
+          <div class="upper-price pf500 fs14 fc2C3131">{{ formatPrice(item.current_price) }}</div>
+          <div class="letter-price pf400 fs10 fcA9A9A9">≈ ${{ formatPrice(item.current_price) }}</div>
         </div>
       </div>
-      <div class="item-right pf500 fs12 fcFFFFFF" :class="getChangeColor(item.change_rate)">{{ formatChange(item.change_rate) }}</div>
+      <div  class="item-right pf500 fs12 fcFFFFFF" :class="getChangeColor(item.trend)">{{ formatChange(item.trend) }}</div>
     </div>
     </div>
   </div>
 </template>
+
 <script setup>
 import { GetCoins } from '@/api/index'
 import { ref, onMounted, onUnmounted } from 'vue'
- import { useRoute, useRouter } from "vue-router";
+import { useRoute, useRouter } from "vue-router";
 
 const router = useRouter();
 
@@ -74,24 +75,22 @@ let isUnmounted = false
 const formatSymbol = (symbol) => symbol ? symbol.replace('USDT', '') : ''
 const formatPrice = (price) => price ? parseFloat(price).toFixed(2) : '0.00'
 
-// 格式化涨跌幅:+9.01%
+// 格式化涨跌幅
 const formatChange = (val) => {
   if (!val) return '+0.00%'
   const num = parseFloat(val)
-  // 正数加 + 号,负数自带 - 号
   return (num > 0 ? '+' : '') + num.toFixed(2) + '%'
 }
 
-// 获取颜色:涨绿跌红
+// 获取颜色
 const getChangeColor = (val) => {
-  if (!val) return 'bg-gray' // 没有数据时显示灰色
+  if (!val) return 'bg-gray'
   return parseFloat(val) >= 0 ? 'bg-green' : 'bg-red'
 }
 
 // --- 1. WebSocket 核心逻辑 ---
 
 const initWebSocket = () => {
-  // 🔒【防死循环】清理旧连接
   if (socket) {
     socket.onclose = null
     socket.close()
@@ -100,37 +99,25 @@ const initWebSocket = () => {
 
   if (coinList.value.length === 0) return
 
-  // 🔒【参数生成】
-  // 列表里是 BTCUSDT (大写) -> 转成 btcusdt (小写) -> 用 / 拼接
-  // 结果: "btcusdt/ethusdt/bnbusdt..."
   const symbolsParam = coinList.value
     .map(item => item.symbol.toLowerCase())
     .join('/')
 
   const query = `?symbol=${symbolsParam}`
 
-  // 2. 确定地址
-  // 暂时直连真实 IP,排除本地代理干扰
-  // const host = '63.141.230.43:57676'
-  // const host = 'http://localhost:8080'
-  // 等调试通了,以后上线前可以改回这样:
   const host = process.env.NODE_ENV === 'production'
     ? 'backend.66linknow.com'
-    : 'localhost:8080' // 开发环境走代理
-    const wsUrl = `ws://${host}/ws/kline/${query}`
-
-  // console.log('🚀 开始连接:', wsUrl)
+    : 'localhost:8080'
+  const wsUrl = `ws://${host}/ws/kline/${query}`
 
   try {
     socket = new WebSocket(wsUrl)
   } catch (err) {
-    // console.error('WS 初始化失败:', err)
     reconnect()
     return
   }
 
   socket.onopen = () => {
-    // console.log('✅ 连接成功')
     startHeartbeat()
     if (reconnectTimer) clearTimeout(reconnectTimer)
   }
@@ -139,8 +126,6 @@ const initWebSocket = () => {
     if (event.data === 'pong' || event.data === 'ping') return
     try {
       const msg = JSON.parse(event.data)
-
-      // 兼容两种数据结构 (有时候后端会包一层 data)
       if (msg.data) {
         updateCoinData(msg.data)
       } else {
@@ -154,9 +139,6 @@ const initWebSocket = () => {
   }
 
   socket.onclose = (e) => {
-    // console.log(`⚠️ 断开 (Code: ${e.code})`)
-    // console.log('关闭原因:', e)
-    // console.log('是否正常关闭:', e.wasClean)
     if (e.code === 1000) return
     socket = null
     reconnect()
@@ -165,25 +147,21 @@ const initWebSocket = () => {
 
 // --- 2. 更新数据 (核心适配) ---
 const updateCoinData = (ticker) => {
-  // ticker 是 WS 推送的数据:
-  // { s: "ASTERUSDT", c: "1.016", P: "9.013", ... }
+  // WS 推送格式: { s: "XRPUSDT", c: "2.18", P: "9.01" }
 
   if (!ticker || !ticker.s) return
 
-  // 1. 找到列表里对应的币
-  // 列表里是 "BTCUSDT",WS 推送里 s 也是 "BTCUSDT"
-  // 统一转大写对比,确保匹配
   const targetCoin = coinList.value.find(item =>
     item.symbol.toUpperCase() === ticker.s.toUpperCase()
   )
 
   if (targetCoin) {
-    // 2. 更新价格 (c = current price)
-    if (ticker.c) targetCoin.price = ticker.c
+    // 【修改点4】: WebSocket 更新时,赋值给新的字段名
+    // c = current price -> 赋值给 current_price
+    if (ticker.c) targetCoin.current_price = ticker.c
 
-    // 3. 更新涨跌幅 (P = percentage change)
-    // 把 WS 里的 P 字段赋值给列表项的 change_rate
-    if (ticker.P) targetCoin.change_rate = ticker.P
+    // P = percentage change -> 赋值给 trend
+    if (ticker.P) {targetCoin.trend = ticker.P; targetCoin.p = ticker.P}
   }
 }
 
@@ -211,11 +189,10 @@ const startHeartbeat = () => {
 
 onMounted(async () => {
   try {
-    // 1. 先拿列表 (只有价格,没有涨跌幅)
     const res = await GetCoins()
+    // 注意:确保 res 已经是数组,或者取 res.data
     coinList.value = Array.isArray(res) ? res : (res.data || [])
 
-    // 2. 再连 WS (获取实时数据)
     if (coinList.value.length > 0) {
       initWebSocket()
     }
@@ -235,7 +212,9 @@ onUnmounted(() => {
   }
 })
 </script>
+
 <style lang="less" scoped>
+/* 样式保持不变,省略以节省空间 */
   .hot-coin {
     margin-top: 20px;
     width: 346px;
@@ -383,43 +362,8 @@ onUnmounted(() => {
     }
   }
 
-//
-//  //xin
-//.body-item {
-//  display: flex;
-//  justify-content: space-between;
-//  align-items: center;
-//  padding: 10px 15px;
-//  border-bottom: 1px solid #f5f5f5;
-//}
-//.item-left {
-//  display: flex;
-//  align-items: center;
-//  gap: 10px;
-//}
-//.coin-img img {
-//  width: 32px;
-//  height: 32px;
-//  border-radius: 50%;
-//  object-fit: cover;
-//}
-///* .upper-name { font-weight: bold; font-size: 15px; color: #333; }
-//.letter-name { font-size: 12px; color: #999; }
-//.upper-price { font-weight: bold; font-size: 15px; margin-left: 10px; color: #333; } */
-//
-///* 右侧涨跌幅按钮 */
-//.item-right {
-//  padding: 6px 12px;
-//  border-radius: 4px;
-//  /* color: white; */
-//  /* font-weight: 500;
-//  font-size: 13px; */
-//  min-width: 75px;
-//  text-align: center;
-//  transition: background-color 0.3s;
-//}
 /* 颜色配置 */
-.bg-green { background-color: #2EBD85; }
-.bg-red { background-color: #F6465D; }
+.bg-green { background-color: #2EBD85!important; }
+.bg-red { background-color: #F6465D!important; }
 .bg-gray { background-color: #C0C0C0; }
-</style>
+</style>

+ 1 - 1
src/views/index/financial/Buy.vue

@@ -57,7 +57,7 @@
 </template>
 <script setup>
   import HeaderNav from "../components/HeaderNav.vue";
-  import CheckBox from "../../../components/ui/CheckBox.vue.vue";
+  import CheckBox from "../../../components/ui/CheckBox.vue";
   import { ref } from "vue";
 
   const autoBuyFlag = ref(true);

+ 55 - 5
src/views/index/ico/Index.vue

@@ -3,18 +3,40 @@
   <HeaderNav headerText="ICO"></HeaderNav>
   <div class="ico-index">
     <div class="index-classifi">
-      <div class="pf600 fs18 fc121212" @click="messageChange('subscription')">认购</div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('placement')">
+      <div
+        class="classifi-item pf600 fs18 fc121212"
+        :class="current == 'subscription' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('subscription')">
+        认购
+        <div class="active-line" v-if="current == 'subscription'"></div>
+      </div>
+      <div
+        class="classifi-item pf600 fs14 fcA8A8A8"
+        :class="current == 'placement' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('placement')">
         配售
+        <div class="active-line" v-if="current == 'placement'"></div>
       </div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('lotteryResult')">
+      <div
+        class="classifi-item pf600 fs14 fcA8A8A8"
+        :class="current == 'lotteryResult' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('lotteryResult')">
         中签结果
+        <div class="active-line" v-if="current == 'lotteryResult'"></div>
       </div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('coinPreview')">
+      <div
+        class="classifi-item pf600 fs14 fcA8A8A8"
+        :class="current == 'coinPreview' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('coinPreview')">
         新币预览
+        <div class="active-line" v-if="current == 'coinPreview'"></div>
       </div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('relus')">
+      <div
+        class="classifi-item pf600 fs14 fcA8A8A8"
+        :class="current == 'relus' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('relus')">
         ICO规则
+        <div class="active-line" v-if="current == 'relus'"></div>
       </div>
     </div>
     <component :is="currentComponent" />
@@ -59,6 +81,34 @@
       margin-top: 48px;
       width: 349px;
       height: 24px;
+
+      .classifi-item {
+        position: relative;
+
+        .active-line {
+          position: absolute;
+          bottom: -6px;
+          left: 50%;
+          transform: translateX(-50%);
+          width: 20px;
+          height: 3px;
+          background-color: #323233;
+          border-radius: 2px;
+        }
+
+        &:first-child {
+          margin-left: 0;
+        }
+      }
+
+      .current-classifi {
+        font-family: "PingFang SC";
+        font-style: normal;
+        font-weight: 600;
+        font-size: 18px;
+        color: #121212;
+        transition: color 0.3s, font-size 0.3s;
+      }
     }
   }
 </style>

+ 3 - 3
src/views/index/loan/CommitMessage.vue

@@ -93,7 +93,6 @@
     flex-direction: column;
     justify-content: flex-start;
     align-items: center;
-    margin-bottom: 100px;
     margin-top: 48px;
     width: 100%;
 
@@ -133,7 +132,7 @@
     }
 
     .card-type {
-      margin-top: 10px;
+      margin-top: 20px;
       width: 345px;
 
       .type-select {
@@ -161,7 +160,7 @@
       width: 345px;
 
       .number-input {
-        margin-top: 5px;
+        margin-top: -10px;
         width: 345px;
         height: 45px;
 
@@ -268,6 +267,7 @@
 
     .submit {
       margin-top: 21px;
+      margin-bottom: 50px;
       width: 311px;
       height: 40px;
       line-height: 40px;

+ 2 - 3
src/views/index/loan/Index.vue

@@ -4,11 +4,11 @@
     <div class="header-content pf600 fs16 fc1F2937">
       <img
         class="left-arrow-image"
-        src="../../../assets/icon/index/left-arrow.svg"
+        src="@/assets/icon/index/left-arrow.svg"
         @click="toPath()" />
       贷款
       <div class="save pf500 fs14 fcDF384C">
-        <img src="../../../assets/icon/index/Headphones.svg" alt="" />
+        <img src="@/assets/icon/index/Headphones.svg" alt="" />
       </div>
     </div>
   </div>
@@ -172,7 +172,6 @@
       .info-right {
         width: 90px;
         height: 90px;
-        background: pink;
       }
     }
 

+ 0 - 1
src/views/index/recharge/RechargeIndex.vue

@@ -83,7 +83,6 @@
         margin-top: 20px;
         width: 152px;
         height: 152px;
-        background: pink;
       }
 
       .save-code {

+ 0 - 13
src/views/index/user/UserInfo.vue

@@ -32,7 +32,6 @@
         </div>
       </div>
     </div>
-    <div class="logout pf600 fs14 fcFFFFFF">退出登录</div>
   </div>
 </template>
 <script setup></script>
@@ -140,17 +139,5 @@
         box-sizing: border-box;
       }
     }
-
-    .logout {
-      margin: 0 auto;
-      margin-top: 55px;
-      width: 311px;
-      height: 40px;
-      line-height: 40px;
-      text-align: center;
-      border-radius: 100px;
-      background: #df384c;
-      letter-spacing: 0.2px;
-    }
   }
 </style>

+ 203 - 0
src/views/market/Bibi.vue

@@ -0,0 +1,203 @@
+<template>
+  <div class="contract">
+    <div class="coin-head">
+      <div class="name">
+        <div class="name-text pf400 fs12 fc666666">交易对</div>
+        <div class="list-sort">
+          <div class="sort-up">
+            <img src="../../assets/icon/index/Triangle.svg" alt="" />
+          </div>
+          <div class="sort-bottom">
+            <img src="../../assets/icon/index/Triangle 2.svg" alt="" />
+          </div>
+        </div>
+      </div>
+      <div class="name price">
+        <div class="name-text pf400 fs12 fc666666">最新价</div>
+        <div class="list-sort">
+          <div class="sort-up">
+            <img src="../../assets/icon/index/Triangle.svg" alt="" />
+          </div>
+          <div class="sort-bottom">
+            <img src="../../assets/icon/index/Triangle 2.svg" alt="" />
+          </div>
+        </div>
+      </div>
+      <div class="name today">
+        <div class="name-text pf400 fs12 fc666666">今日涨跌幅</div>
+        <div class="list-sort">
+          <div class="sort-up">
+            <img src="../../assets/icon/index/Triangle.svg" alt="" />
+          </div>
+          <div class="sort-bottom">
+            <img src="../../assets/icon/index/Triangle 2.svg" alt="" />
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="coin-body">
+      <div class="body-item" v-for="(item, index) in 10" :key="index">
+        <div class="item-left">
+          <div class="coin-img">
+            <img src="../../assets/img/index/Frame 7.svg" alt="" />
+          </div>
+          <div class="coin-name">
+            <div class="upper-name pf500 fs14 fc2C3131">Bitcoin</div>
+            <div class="letter-name pf400 fs10 fcA9A9A9">BTC</div>
+          </div>
+          <div class="coin-echars"></div>
+          <div class="coin-price">
+            <div class="upper-price pf500 fs14 fc2C3131">48.503.12</div>
+            <div class="letter-price pf400 fs10 fcA9A9A9">¥ 4250.00</div>
+          </div>
+        </div>
+        <div class="item-right pf500 fs12 fcFFFFFF">+2.18%</div>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup>
+
+</script>
+<style lang="less" scoped>
+  .contract {
+    margin-top: 11px;
+
+    .coin-head {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      margin-top: 6px;
+      width: 100%;
+      height: 24px;
+
+      .name {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        height: 24px;
+
+        .list-sort {
+          display: flex;
+          flex-direction: column;
+          justify-content: flex-start;
+          margin-left: 4px;
+          width: 8px;
+          height: 16px;
+
+          .sort-up,
+          .sort-bottom {
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+            width: 8px;
+            height: 8px;
+
+            img {
+              width: 8px;
+              height: 4px;
+            }
+          }
+        }
+      }
+
+      .price {
+        margin-left: 128px;
+      }
+
+      .today {
+        margin-left: 47px;
+      }
+    }
+
+    .coin-body {
+      margin-top: 9px;
+      width: 100%;
+
+      .body-item {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-top: 23.5px;
+        width: 100%;
+        height: 38px;
+
+        &:nth-child(1) {
+          margin-top: 0;
+        }
+
+        .item-left {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          width: 276px;
+          height: 100%;
+
+          .coin-img {
+            width: 32px;
+            height: 32px;
+
+            img {
+              width: 32px;
+              height: 32px;
+            }
+          }
+
+          .coin-name {
+            margin-left: 10px;
+            width: 85px;
+            height: 34px;
+
+            .upper-name {
+              height: 20px;
+              line-height: 20px;
+            }
+
+            .letter-name {
+              height: 14px;
+              line-height: 14px;
+            }
+          }
+
+          .coin-echars {
+            width: 60px;
+            height: 35px;
+          }
+
+          .coin-price {
+            margin-left: 13px;
+            width: 75px;
+            height: 38px;
+
+            .upper-price {
+              height: 20px;
+              line-height: 20px;
+              text-align: right;
+            }
+
+            .letter-price {
+              height: 16px;
+              line-height: 16px;
+              text-align: right;
+            }
+          }
+        }
+
+        .item-right {
+          margin-left: 8px;
+          width: 61px;
+          height: 25px;
+          line-height: 25px;
+          text-align: center;
+          background: #45b26b;
+          border-radius: 5px;
+        }
+      }
+    }
+  }
+</style>

+ 606 - 69
src/views/market/Index.vue

@@ -1,78 +1,615 @@
+<script setup>
+import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
+// 引入您的真实接口函数
+import { TradingPair } from '@/api/index.js';
+import { useRoute, useRouter } from "vue-router";
+
+const router = useRouter();
+
+// --- 1. 状态管理 ---
+const tabs = [
+  { key: 'fav', label: '自选' },
+  { key: 'spot', label: '币币' },
+  { key: 'futures', label: '合约' },
+  { key: 'seconds', label: '秒合约' }
+];
+
+const currentTab = ref('spot');
+const listData = ref([]);
+const page = ref(1);
+const loading = ref(false);
+const finished = ref(false);
+const scrollContainer = ref(null);
+const PAGE_SIZE = 15; // 定义分页大小
+
+// --- 2. WebSocket 核心变量 ---
+const socket = ref(null);
+let reconnectTimer = null; // 重连定时器
+let heartbeatTimer = null; // 心跳定时器
+let isManualClose = false; // 标记是否为手动关闭(切换Tab时),避免触发重连
+let lastSymbols = [];      // 记录最后一次订阅的币种,用于重连
+
+// --- 3. 图表与图标工具函数 ---
+const generateChartPaths = (isUp) => {
+  const width = 60; const height = 24; const pointCount = 15; const step = width / (pointCount - 1);
+  let points = []; let y = isUp ? (height * 0.8) : (height * 0.2);
+  for(let i=0; i<pointCount; i++) {
+    const x = i * step;
+    y += (Math.random() - 0.5) * (height * 0.4) + (isUp ? -(height * 0.05) : (height * 0.05));
+    y = Math.max(2, Math.min(height - 2, y));
+    points.push({x, y});
+  }
+  const linePath = `M ${points.map(p => `${p.x},${p.y}`).join(' L ')}`;
+  const fillPath = `${linePath} L ${width},${height + 5} L 0,${height + 5} Z`;
+  return { linePath, fillPath };
+};
+
+// 本地 SVG 图标映射 (作为兜底备用)
+const localIcons = {
+  BTC: '<path fill="#F7931A" d="M22.6 13.4c.4-2.6-1.6-4-4.3-4.9l.9-3.5-2.1-.5-.9 3.5c-.5-.1-1.1-.3-1.7-.4l.9-3.5-2.1-.5-.9 3.5c-.4-.1-1-.2-1.5-.3l-3-.7-.6 2.4s1.6.4 1.6.4c.9.2 1 .8 1 1.2l-1 4c.1 0 .1 0 .1.1l-1.4 5.6c0 .3-.3.8-1 .6 0 0-1.6-.4-1.6-.4l-1.1 2.6 2.8.7c.5.1 1 .3 1.5.4l-.9 3.6 2.1.5.9-3.6c.6.2 1.1.3 1.7.5l-.9 3.6 2.1.5.9-3.5c3.7.7 6.4.4 7.6-2.9.9-2.6-.1-4.1-1.9-5.1 1.4-.3 2.4-1.2 2.7-3z"/>',
+  ETH: '<path fill="#627EEA" d="M11.9 20.3L6.1 16.9l5.8-2.6 5.8 2.6-5.8 3.4zm0-9.6l5.8 2.6-5.8 8.1-5.8-8.1 5.8-2.6zM12 2l5.8 9.6L12 14 6.2 11.6 12 2z"/>',
+  BNB: '<path fill="#F3BA2F" d="M4.6 12l2.3-2.3L9.2 12l-2.3 2.3L4.6 12zM12 4.6l2.3 2.3-2.3 2.3-2.3-2.3L12 4.6zm7.4 7.4l-2.3 2.3 2.3 2.3 2.3-2.3-2.3-2.3zm-7.4 7.4l-2.3-2.3 2.3-2.3 2.3 2.3-2.3 2.3zm4.6-7.4l2.3-2.3-2.3-2.3-2.3 2.3 2.3 2.3zM12 14.8l-2.3-2.3 2.3-2.3 2.3 2.3L12 14.8zM9.7 7.4L12 5.1l2.3 2.3L12 9.7 9.7 7.4z"/>',
+  USDT: '<path fill="#26A17B" d="M14.5 10.4c.2-.2.3-.3.3-.3s-.1 0-.3 0c-.5.1-1.2.1-1.9.1-.1-2.9 0-2.9 0-2.9h3.1V5.7h-3.1V3H11v2.7H8V7.3h3v2.9c0 .1 0 .2-.1.2-2.8 0-5.1.8-5.1 1.7 0 1 2.3 1.7 5.2 1.7s5.2-.8 5.2-1.7c0-.7-1.3-1.2-3.4-1.5z"/>',
+  XRP: '<path fill="#23292F" d="M12 24c6.627 0 12-5.373 12-12S18.627 0 12 0 0 5.373 0 12s5.373 12 12 12z" /><path fill="#FFF" d="M9.82 12.01L4.65 6.84a.856.856 0 011.21-1.21l5.17 5.17a1.14 1.14 0 010 1.62L5.86 17.59a.856.856 0 01-1.21-1.21l5.17-4.37zM14.18 12.01l5.17 5.17a.856.856 0 01-1.21 1.21l-5.17-5.17a1.14 1.14 0 010-1.62l5.17-5.17a.856.856 0 011.21 1.21l-5.17 4.37z"/>',
+  SOL: '<path fill="#00FFA3" d="M3.5 16.5l2.1-3.6 14.9 0L18.4 16.5 3.5 16.5zM5.6 7.5L3.5 11.1 18.4 11.1 20.5 7.5 5.6 7.5zM20.5 20.1l-2.1 3.6L3.5 23.7 5.6 20.1 20.5 20.1z"/>',
+  DOGE: '<path fill="#C2A633" d="M12,2C6.48,2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,18c-3.31,0-6-2.69-6-6s2.69-6,6-6s6,2.69,6,6S15.31,18,12,18z"/>'
+};
+
+// --- 4. 生产级 WebSocket 管理 ---
+
+// 启动心跳:防止连接因长时间无数据而被断开
+const startHeartbeat = () => {
+  clearInterval(heartbeatTimer);
+  heartbeatTimer = setInterval(() => {
+    if (socket.value && socket.value.readyState === WebSocket.OPEN) {
+      // 发送 ping 消息,具体内容看后端要求,通常是字符串 'ping' 或 JSON '{ "op": "ping" }'
+      socket.value.send("ping");
+    }
+  }, 15000); // 建议 15-30 秒一次
+};
+
+const stopHeartbeat = () => {
+  clearInterval(heartbeatTimer);
+};
+
+const connectWebSocket = (symbols) => {
+  // 如果是重连调用(不传参数),则使用上次的币种
+  if (!symbols && lastSymbols.length > 0) {
+    symbols = lastSymbols;
+  } else if (symbols) {
+    lastSymbols = symbols;
+  } else {
+    return; // 无币种可订阅
+  }
+
+  // 关闭旧连接
+  isManualClose = true; // 标记为手动关闭,防止立刻触发 onclose 重连
+  if (socket.value) {
+    socket.value.close();
+  }
+  clearTimeout(reconnectTimer);
+  stopHeartbeat();
+
+  // 构造参数
+  const symbolStr = symbols.map(s => s.toLowerCase()).join('/');
+  if (!symbolStr) return;
+
+  const wsUrl = `ws://localhost:8080/ws/kline/?symbol=${symbolStr}`;
+  console.log('Connecting WS:', wsUrl);
+
+  try {
+    isManualClose = false; // 重置标记,准备开始新连接
+    socket.value = new WebSocket(wsUrl);
+
+    socket.value.onopen = () => {
+      console.log('WS Connected');
+      startHeartbeat(); // 连接成功,开启心跳
+    };
+
+    socket.value.onmessage = (event) => {
+      try {
+        const msg = JSON.parse(event.data);
+        // 如果收到 pong 消息,可以忽略
+        if (msg === 'pong' || msg.op === 'pong') return;
+
+        const data = msg.data || msg;
+        const symbol = data.s || data.symbol;
+        if (!symbol) return;
+
+        const item = listData.value.find(i =>
+          i.name && i.name.toUpperCase() === symbol.toUpperCase()
+        );
+
+        if (item) {
+          // 1. 实时更新价格
+          let newPrice = data.c || data.p || (data.k ? data.k.c : null);
+          if (newPrice) {
+            item.price = newPrice;
+            item.cny = (parseFloat(newPrice) * 7.25).toFixed(2);
+          }
+
+          // 2. 实时更新涨跌幅
+          let newChange = data.P || data.trend;
+          if (newChange) {
+            item.change = parseFloat(newChange).toFixed(2);
+            const isUp = parseFloat(newChange) >= 0;
+            item.btnClass = isUp ? 'btn-green' : 'btn-red';
+            item.chartColor = isUp ? '#2EBD85' : '#F6465D';
+          }
+        }
+      } catch (e) {
+        // console.error("WS Message Error:", e);
+      }
+    };
+
+    socket.value.onclose = (e) => {
+      stopHeartbeat();
+      // 如果不是手动切换Tab导致的关闭,则尝试重连
+      if (!isManualClose) {
+        console.log('WS Disconnected unexpectedly. Reconnecting in 3s...');
+        reconnectTimer = setTimeout(() => {
+          connectWebSocket(); // 尝试重连
+        }, 3000);
+      }
+    };
+
+    socket.value.onerror = (err) => {
+      console.warn("WS Connection Error:", err);
+      // error 后通常会自动触发 close,逻辑交给 onclose 处理
+    };
+  } catch (e) {
+    console.error("WS Create Error:", e);
+    // 创建失败也尝试重连
+    reconnectTimer = setTimeout(() => {
+      connectWebSocket();
+    }, 5000);
+  }
+};
+
+// --- 5. 真实接口请求封装 ---
+const fetchData = async (tab, pageNum) => {
+  try {
+    if (tab !== 'spot') return [];
+    const res = await TradingPair({
+      type: tab,
+      pageNum: pageNum,
+      pageSize: PAGE_SIZE
+    });
+
+    if (!res || !res.list) return [];
+
+    return res.list.map(item => {
+      const trendVal = parseFloat(item.trend || 0);
+      const isUp = trendVal >= 0;
+      const paths = generateChartPaths(isUp);
+      const iconKey = item.base_coin;
+
+      return {
+        id: item.id,
+        name: item.symbol,
+        symbol: item.name,
+        price: item.current_price,
+        cny: (parseFloat(item.current_price) * 7.25).toFixed(2),
+        change: trendVal.toFixed(2),
+        iconUrl: item.logo,
+        svgIcon: localIcons[iconKey] || null,
+        base_coin_char: item.base_coin ? item.base_coin[0] : '?',
+        chartLine: paths.linePath,
+        chartFill: paths.fillPath,
+        chartColor: isUp ? '#2EBD85' : '#F6465D',
+        btnClass: isUp ? 'btn-green' : 'btn-red'
+      };
+    });
+  } catch (error) {
+    console.error("加载数据失败:", error);
+    return [];
+  }
+};
+
+// --- 6. 核心逻辑:数据加载 ---
+const onLoad = async () => {
+  if (loading.value || finished.value) return;
+
+  loading.value = true;
+
+  const data = await fetchData(currentTab.value, page.value);
+
+  // console.log(`Tab: ${currentTab.value}, Page: ${page.value}, Loaded: ${data.length}`);
+
+  if (data.length === 0) {
+    finished.value = true;
+  } else {
+    listData.value.push(...data);
+    page.value++;
+
+    if (data.length < PAGE_SIZE) {
+      finished.value = true;
+    }
+    console.log(listData.value,'llll');
+    const allSymbols = listData.value.map(item => item.name);
+    if (allSymbols.length > 0) {
+      connectWebSocket(allSymbols);
+    }
+  }
+  loading.value = false;
+};
+
+// 监听 Tab 切换
+watch(currentTab, () => {
+  isManualClose = true; // 切换前标记手动关闭
+  if (socket.value) {
+    socket.value.close();
+    socket.value = null;
+  }
+  // 清理重连定时器,避免在切换Tab期间触发上一个Tab的重连
+  clearTimeout(reconnectTimer);
+
+  listData.value = [];
+  page.value = 1;
+  finished.value = false;
+  loading.value = false;
+  if (scrollContainer.value) scrollContainer.value.scrollTop = 0;
+  onLoad();
+});
+
+const handleScroll = (e) => {
+  const { scrollTop, clientHeight, scrollHeight } = e.target;
+  if (scrollTop + clientHeight >= scrollHeight - 100) {
+    onLoad();
+  }
+};
+
+// 处理页面可见性变化(切后台再回来)
+const handleVisibilityChange = () => {
+  if (document.visibilityState === 'visible') {
+    // 如果回来发现连接断了,立即重连
+    if (!socket.value || socket.value.readyState === WebSocket.CLOSED) {
+      console.log('Page visible, checking WS connection...');
+      connectWebSocket();
+    }
+  }
+};
+
+onMounted(() => {
+  onLoad();
+  document.addEventListener('visibilitychange', handleVisibilityChange);
+});
+
+onUnmounted(() => {
+  document.removeEventListener('visibilitychange', handleVisibilityChange);
+  isManualClose = true;
+  if (socket.value) socket.value.close();
+  clearTimeout(reconnectTimer);
+  stopHeartbeat();
+});
+
+// 格式化工具函数
+const formatPrice = (val) => {
+  if(!val) return '0.00';
+  const num = parseFloat(val);
+  return num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 8 });
+};
+const formatCNY = (val) => {
+  if(!val) return '0.00';
+  const num = parseFloat(val);
+  return num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
+};
+</script>
+
 <template>
-  <div class="market">
-    <div class="market-nav">
-      <div class="nav-left">
-        <div class="pf600 fs18 fc121212" @click="messageChange('selfSelected')">自选</div>
-        <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('contract')">
-          合约
+  <div class="market-page">
+    <svg width="0" height="0" style="position:absolute;">
+      <defs>
+        <linearGradient id="chart-grad-up" x1="0%" y1="0%" x2="0%" y2="100%">
+          <stop offset="0%" style="stop-color:#2EBD85;stop-opacity:0.2" />
+          <stop offset="100%" style="stop-color:#2EBD85;stop-opacity:0" />
+        </linearGradient>
+        <linearGradient id="chart-grad-down" x1="0%" y1="0%" x2="0%" y2="100%">
+          <stop offset="0%" style="stop-color:#F6465D;stop-opacity:0.2" />
+          <stop offset="100%" style="stop-color:#F6465D;stop-opacity:0" />
+        </linearGradient>
+      </defs>
+    </svg>
+
+    <div class="sticky-header">
+      <div class="top-bar">
+        <div class="tabs-wrapper">
+          <div
+            v-for="tab in tabs"
+            :key="tab.key"
+            @click="currentTab = tab.key"
+            class="tab-item"
+            :class="{ active: currentTab === tab.key }"
+          >
+            {{ tab.label }}
+            <div v-if="currentTab === tab.key" class="active-indicator"></div>
+          </div>
         </div>
-        <div
-          class="sys-notifi pf600 fs14 fcA8A8A8"
-          @click="messageChange('secondContract')">
-          秒合约
+        <div class="search-icon">
+          <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#707A8A" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
         </div>
       </div>
-      <div class="nav-right">
-        <img src="../../assets/icon/market/search.svg" alt="" />
+
+      <!-- 表头增加排序图标 -->
+      <div class="table-header">
+        <div class="col col-left">
+          交易对
+          <div class="sort-box">
+             <div class="sort-up"></div>
+             <div class="sort-down"></div>
+          </div>
+        </div>
+        <div class="col col-center">
+          最新价
+          <div class="sort-box">
+             <div class="sort-up"></div>
+             <div class="sort-down"></div>
+          </div>
+        </div>
+        <div class="col col-right">
+          今日涨跌幅
+          <div class="sort-box">
+             <div class="sort-up"></div>
+             <div class="sort-down"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div
+      class="list-container"
+      ref="scrollContainer"
+      @scroll="handleScroll"
+    >
+      <div
+        v-for="coin in listData"
+        :key="coin.id"
+        class="list-item"
+        @click="router.push({ path: '/marketDetails', query: { id: coin.id, type: coin.name.toLowerCase()} })"
+      >
+        <div class="col col-left coin-info">
+          <div class="coin-icon-wrapper">
+            <img v-if="coin.iconUrl" :src="coin.iconUrl" class="real-icon-img" alt="icon" />
+            <svg v-else-if="coin.svgIcon" viewBox="0 0 32 32" class="real-icon" v-html="coin.svgIcon"></svg>
+            <div v-else class="placeholder-icon">{{ coin.base_coin_char }}</div>
+          </div>
+          <div class="text-group">
+            <div class="name-row">{{ coin.name }}</div>
+            <div class="symbol-row">{{ coin.symbol }}</div>
+          </div>
+        </div>
+
+        <div class="col col-center chart-box">
+          <svg width="60" height="24" viewBox="0 0 60 24">
+            <path :d="coin.chartFill" :fill="coin.change >= 0 ? 'url(#chart-grad-up)' : 'url(#chart-grad-down)'" />
+            <path :d="coin.chartLine" fill="none" :stroke="coin.chartColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
+          </svg>
+        </div>
+
+        <div class="col col-right price-info">
+          <div class="price transition-colors duration-300" :class="coin.change >= 0 ? 'text-[#2EBD85]' : 'text-[#F6465D]'">
+            {{ formatPrice(coin.price) }}
+          </div>
+          <div class="cny">¥ {{ formatCNY(coin.cny) }}</div>
+        </div>
+        <div>
+          <button class="change-btn transition-colors duration-300" :class="coin.btnClass">
+            {{ coin.change >= 0 ? '+' : '' }}{{ coin.change }}%
+          </button>
+        </div>
+      </div>
+
+      <!-- 底部状态区 -->
+      <div class="loading-state">
+        <div v-if="loading" class="spinner-container">
+          <div class="spinner"></div>
+          <span class="loading-text">加载中...</span>
+        </div>
+        <div v-else-if="finished && listData.length > 0" class="no-more-text">
+          - 没有更多了 -
+        </div>
+        <div v-else-if="finished && listData.length === 0" class="empty-state">
+          暂无数据
+        </div>
       </div>
     </div>
-    <component :is="currentComponent" />
   </div>
 </template>
-<script setup>
-  import Contract from "./Contract.vue";
-  import SecondContract from "./SecondContract.vue";
-  import SelfSelected from "./SelfSelected.vue";
-  import { ref, computed } from "vue";
-
-  const current = ref("selfSelected");
-  const componentsMap = {
-    contract: Contract,
-    secondContract: SecondContract,
-    selfSelected: SelfSelected,
-  };
-  const currentComponent = computed(() => componentsMap[current.value]);
-
-  const messageChange = (key) => {
-    current.value = key;
-  };
-</script>
-<style lang="less" scoped>
-  .market {
-    display: flex;
-    flex-direction: column;
-    justify-content: flex-start;
-    align-items: center;
-    margin-bottom: 100px;
-    width: 100%;
-
-    .market-nav {
-      display: flex;
-      flex-direction: row;
-      justify-content: space-between;
-      align-items: center;
-      margin-top: 21px;
-      width: 345px;
-      height: 24px;
-
-      .nav-left {
-        display: flex;
-        flex-direction: row;
-        justify-content: flex-start;
-        align-items: flex-end;
-        width: 345px;
-        height: 24px;
-
-
-        .sys-notifi {
-          margin-left: 35px;
-        }
-      }
 
-      .nav-right {
-        width: 20px;
-        height: 20px;
-      }
-    }
-  }
-</style>
+<style scoped>
+/* 基础重置 */
+* { box-sizing: border-box; }
+
+.market-page {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  background-color: #fff;
+  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", sans-serif;
+  color: #1E2329;
+}
+
+.sticky-header {
+  position: sticky;
+  top: 0;
+  background-color: #fff;
+  z-index: 10;
+  padding: 12px 16px 0;
+}
+
+.top-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 16px;
+}
+
+.tabs-wrapper {
+  display: flex;
+  gap: 28px;
+  align-items: flex-end;
+}
+
+.tab-item {
+  position: relative;
+  font-size: 16px;
+  color: #707A8A;
+  font-weight: 500;
+  padding-bottom: 8px;
+  cursor: pointer;
+  transition: all 0.2s;
+  line-height: 24px;
+}
+
+.tab-item.active {
+  font-size: 20px;
+  font-weight: 600;
+  color: #1E2329;
+}
+
+.active-indicator {
+  position: absolute;
+  bottom: 0;
+  left: 50%;
+  transform: translateX(-50%);
+  width: 16px;
+  height: 3px;
+  background-color: #1E2329;
+  border-radius: 2px;
+}
+
+.table-header {
+  display: flex;
+  font-size: 12px;
+  color: #707A8A;
+  padding-bottom: 8px;
+}
+
+.col { display: flex; }
+.col-left { width: 38%; justify-content: flex-start; align-items: center; }
+.col-center { width: 25%; justify-content: center; align-items: center; margin-left: 10px; }
+/* 修正右侧列样式,支持排序图标 */
+.col-right { width: 37%; justify-content: flex-end; align-items: center; }
+
+/* 排序小三角 */
+.sort-box {
+  display: flex;
+  flex-direction: column;
+  margin-left: 4px;
+  gap: 2px;
+  cursor: pointer;
+}
+.sort-up {
+  width: 0;
+  height: 0;
+  border-left: 3px solid transparent;
+  border-right: 3px solid transparent;
+  border-bottom: 4px solid #B7BDC6;
+}
+.sort-down {
+  width: 0;
+  height: 0;
+  border-left: 3px solid transparent;
+  border-right: 3px solid transparent;
+  border-top: 4px solid #B7BDC6;
+}
+
+.list-container {
+  flex: 1;
+  overflow-y: auto;
+  padding: 0 15px 80px;
+}
+
+.list-item {
+  display: flex;
+  padding: 16px 0;
+  border-bottom: 1px solid #F0F3F5;
+  align-items: center;
+}
+
+.coin-icon-wrapper {
+  width: 28px; height: 28px; margin-right: 8px; flex-shrink: 0;
+  display: flex; align-items: center; justify-content: center;
+}
+.real-icon { width: 100%; height: 100%; }
+.real-icon-img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
+.placeholder-icon {
+  width: 100%; height: 100%; background: #F0F3F5; border-radius: 50%;
+  color: #707A8A; display: flex; align-items: center; justify-content: center;
+  font-size: 12px; font-weight: bold;
+}
+
+.text-group { display: flex; flex-direction: column; }
+.name-row { font-size: 14px; font-weight: 600; color: #1E2329; margin-bottom: 2px; }
+.symbol-row { font-size: 12px; color: #707A8A; }
+
+.chart-box svg { overflow: visible; }
+
+.price-info.col-right {
+  display: inline-block; text-align: right; margin-right: 8px;
+}
+.price { font-size: 14px; font-weight: 600; }
+.cny { font-size: 11px; color: #707A8A; margin-bottom: 4px; transform: scale(0.95); transform-origin: right center; }
+
+.change-btn {
+  width: 72px; height: 32px; border: none; border-radius: 4px;
+  color: #fff; font-size: 13px; font-weight: 500;
+  display: flex; align-items: center; justify-content: center; margin-top: 2px;
+}
+.btn-green { background-color: #2EBD85; }
+.btn-red { background-color: #F6465D; }
+
+.loading-state {
+  text-align: center;
+  padding: 20px 0;
+  color: #999;
+  font-size: 12px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 80px;
+  width: 100%;
+}
+
+.spinner-container {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.spinner {
+  width: 16px;
+  height: 16px;
+  border: 2px solid #e0e0e0;
+  border-top-color: #707A8A;
+  border-radius: 50%;
+  animation: spin 0.8s linear infinite;
+}
+
+.loading-text {
+  font-size: 12px;
+  color: #999;
+}
+
+.no-more-text {
+  color: #555;
+  font-size: 13px;
+  padding: 8px 16px;
+  background-color: #f0f0f0;
+  border-radius: 20px;
+}
+
+.empty-state {
+  color: #999;
+  font-size: 14px;
+  padding-top: 40px;
+}
+
+@keyframes spin {
+  from { transform: rotate(0deg); }
+  to { transform: rotate(360deg); }
+}
+
+.text-[#2EBD85] { color: #2EBD85; }
+.text-[#F6465D] { color: #F6465D; }
+</style>

+ 41 - 6
src/views/market/details/EntrustingOrder.vue

@@ -8,14 +8,21 @@
       <div class="header-sell">卖盘</div>
     </div>
     <div class="order-body">
-      <div class="order-item" v-for="(item, index) in 15" :key="index">
+      <!-- ⭐ 正确循环 newOrderPlacement -->
+      <div class="order-item" v-for="(item, index) in newOrderPlacement" :key="index">
         <div class="item-buy fs400 fs12 fcA8A8A8">{{ index + 1 }}</div>
-        <div class="item-number fs400 fs12 fc444444">37.80K</div>
+        <!-- 买价 -->
+        <div class="item-number fs400 fs12 fc444444">
+          {{ Number(item[0][0]).toFixed(2) }}
+        </div>
         <div class="item-price fs400 fs12">
-          <div class="fc45B26B">40,166.82</div>
-          <div class="price-second fcFF7171">39,962.74</div>
+          <div class="fc45B26B">{{ Number(item[0][1]).toFixed(2) }}</div>
+          <div class="price-second fcFF7171">{{ Number(item[1][1]).toFixed(2) }}</div>
+        </div>
+        <!-- 卖价 -->
+        <div class="item-number2 fs400 fs12 fc444444">
+          {{ Number(item[1][0]).toFixed(2) }}
         </div>
-        <div class="item-number2 fs400 fs12 fc444444">37.80K</div>
         <div class="item-sell fs400 fs12 fcA8A8A8">{{ index + 1 }}</div>
       </div>
     </div>
@@ -25,7 +32,35 @@
     </div>
   </div>
 </template>
-<script setup></script>
+<script setup>
+  import { toRef, watch, defineProps, ref } from "vue";
+
+  const props = defineProps({
+    orderPlacement: {
+      type: [String, Number, Object, Array, Boolean],
+      default: null,
+    },
+  });
+
+  const valueFromParent = toRef(props, "orderPlacement");
+
+  // ⭐ 作为展示用的新数组
+  const newOrderPlacement = ref([]);
+
+  // ⭐ 监听父组件传来的 orderPlacement,自动转换
+  watch(
+    valueFromParent,
+    (newVal) => {
+      if (!newVal || !newVal.bids || !newVal.asks) return;
+
+      // ⭐ 正确转换 bids + asks → newOrderPlacement
+      newOrderPlacement.value = newVal.bids.map((bid, index) => {
+        return [bid, newVal.asks[index]];
+      });
+    },
+    { immediate: true }
+  );
+</script>
 <style lang="less" scoped>
   .entrusting-order {
     width: 100%;

+ 7 - 4
src/views/market/details/Index.vue

@@ -5,7 +5,7 @@
         <img src="../../../assets/icon/market/left-arrow.svg" alt="" />
       </div>
       <div class="header-icon pf600 fs18 fc121212" @click="changeIconFlag = true">
-        BTCUSDT
+        {{ title }}
         <img src="../../../assets/icon/market/btn_triangle_down_bk.svg" alt="" />
       </div>
       <div class="header-func">
@@ -17,14 +17,14 @@
       <div class="pf600 fs18 fc121212" @click="messageChange('marketConditions')">
         行情
       </div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('info')">
+      <!-- <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('info')">
         信息
       </div>
       <div
         class="sys-notifi pf600 fs14 fcA8A8A8"
         @click="messageChange('transactionData')">
         交易数据
-      </div>
+      </div> -->
     </div>
     <component :is="currentComponent" />
     <ChangeIcon v-show="changeIconFlag" @changeIconClose="changeIconClose"></ChangeIcon>
@@ -36,9 +36,12 @@
   import TransactionData from "./TransactionData.vue";
   import ChangeIcon from "../dialog/ChangeIcon.vue";
   import { ref, computed } from "vue";
-  import { useRouter } from "vue-router";
+  import { useRouter, useRoute } from "vue-router";
 
   const router = useRouter();
+  const route = useRoute();
+
+  const title = route.query.type ? route.query.type.toUpperCase() : "";
 
   const changeIconFlag = ref(false);
   const changeIconClose = () => {

+ 46 - 7
src/views/market/details/LatestTransactions.vue

@@ -7,13 +7,17 @@
       <div class="header-number2">数量(AVAX)</div>
     </div>
     <div class="order-body">
-      <div class="order-item" v-for="(item, index) in 15" :key="index">
-        <div class="item-buy fs400 fs12 fcA8A8A8">13:44:25</div>
-        <div class="item-number fs400 fs12 fc45B26B">买入</div>
+      <div class="order-item" v-for="(item, index) in transactions" :key="index">
+        <div class="item-buy fs400 fs12 fcA8A8A8">{{ timestampToTime(item.T) }}</div>
+        <div
+          class="item-number fs400 fs12"
+          :class="item.m == true ? 'fcDF384C' : 'fc45B26B'">
+          {{ item.m == true ? "卖出" : "买入" }}
+        </div>
         <div class="item-price fs400 fs12">
-          <div class="fc444444">1.2505</div>
+          <div class="fc444444">{{ Number(item.p).toFixed(2) }}</div>
         </div>
-        <div class="item-number2 fs400 fs12 fc444444">40,166.82</div>
+        <div class="item-number2 fs400 fs12 fc444444">{{ item.q }}</div>
       </div>
     </div>
     <div class="buy-sell pf500 fs16 fcFFFFFF">
@@ -22,9 +26,43 @@
     </div>
   </div>
 </template>
-<script setup></script>
+<script setup>
+  import { toRef, watch, defineProps, ref } from "vue";
+  import { timestampToTime } from "../../../utils/time";
+
+  const props = defineProps({
+    latestTransactionData: {
+      type: [Object, Array],
+      default: () => [],
+    },
+  });
+
+  const transactions = ref([]);
+
+  // 处理最新交易数据,始终保留20条
+  watch(
+    () => props.latestTransactionData,
+    (newVal) => {
+      if (Array.isArray(newVal)) {
+        // 如果是数组,直接取最后20条
+        transactions.value = newVal.slice(-20);
+      } else if (newVal && typeof newVal === "object") {
+        // 如果是单条对象
+        transactions.value.push(newVal);
+        if (transactions.value.length > 20) {
+          transactions.value.shift();
+        }
+      }
+    },
+    { immediate: true, deep: true }
+  );
+</script>
 <style lang="less" scoped>
   .latest-order {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start;
+    align-items: center;
     width: 100%;
 
     .order-header {
@@ -32,7 +70,7 @@
       flex-direction: row;
       justify-content: flex-start;
       margin-top: 6px;
-      width: 100%;
+      width: 345px;
       height: 24px;
 
       .header-buy {
@@ -68,6 +106,7 @@
       display: flex;
       flex-direction: column;
       justify-content: flex-start;
+      width: 345px;
 
       .order-item {
         display: flex;

+ 0 - 526
src/views/market/details/MarketConditions.vue

@@ -1,526 +0,0 @@
-<template>
-  <div class="market-conditions">
-    <div class="market-price">
-      <div class="price-left">
-        <div class="left-price pf400 fs14 fc333333">
-          实时价格
-        </div>
-        <div class="left-number pf600 fs20 fc1F2937" :class="getPriceColor(marketInfo.change)">
-          {{ formatNumber(marketInfo.price) }}
-        </div>
-        <div class="left-appro pf500 fs14 fcA8A8A8">
-          ≈{{ formatNumber(marketInfo.fiatPrice) }}
-          <span class="appro pf500 fs14" :class="getUpDownClass(marketInfo.change)">
-            {{ marketInfo.change > 0 ? '+' : '' }}{{ marketInfo.change }}%
-          </span>
-        </div>
-      </div>
-
-      <div class="price-right">
-        <div class="right-number-top">
-          <div class="right-number-top-price">
-            <div class="pf400 fs10 fcA8A8A8">24h 最高价</div>
-            <div class="pf400 fs10 fc2C3131">{{ formatNumber(marketInfo.high) }}</div>
-          </div>
-          <div class="right-number-top-number">
-            <div class="pf400 fs10 fcA8A8A8">24h 成交量</div>
-            <div class="pf400 fs10 fc2C3131">{{ abbreviateNumber(marketInfo.vol) }}</div>
-          </div>
-        </div>
-        <div class="right-number-bottom">
-          <div class="right-number-top-price">
-            <div class="pf400 fs10 fcA8A8A8">24h 最低价</div>
-            <div class="pf400 fs10 fc2C3131">{{ formatNumber(marketInfo.low) }}</div>
-          </div>
-          <div class="right-number-top-number">
-            <div class="pf400 fs10 fcA8A8A8">24h 成交额</div>
-            <div class="pf400 fs10 fc2C3131">{{ abbreviateNumber(marketInfo.amount) }}</div>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <!-- 周期切换 Tab -->
-    <nav class="time-tabs">
-      <div
-        v-for="tab in tabs"
-        :key="tab"
-        class="tab-item"
-        :style="currentTab === tab ? { backgroundColor: '#F6465D', color: '#fff' } : {}"
-        @click="switchPeriod(tab)"
-      >
-        {{ tab }}
-      </div>
-      <div class="tab-item icon">更多 <span class="triangle">◢</span></div>
-      <div class="tab-item icon">
-        <img src="@/assets/icon/bitcoin/lishidingdan.svg" alt="">
-      </div>
-    </nav>
-
-    <div class="k-line-main">
-      <KlineChart
-        ref="klineRef"
-        :data="kLineData"
-        height="100%"
-        :precision="{ price: getPricePrecision(marketInfo.price), volume: 2 }"
-      />
-    </div>
-
-    <div class="notifi-classifi">
-      <div class="pf600 fs14" :class="current === 'entrustingOrder' ? 'fc121212' : 'fcA8A8A8'" @click="messageChange('entrustingOrder')">委托挂单</div>
-      <div class="sys-notifi pf600 fs14" :class="current === 'latestTransactions' ? 'fc121212' : 'fcA8A8A8'" @click="messageChange('latestTransactions')">最新成交</div>
-    </div>
-
-    <component :is="currentComponent" :symbol-id="symbolId" />
-  </div>
-</template>
-
-<script setup>
-import { ref, computed, onMounted, onUnmounted, watch, onBeforeUnmount } from "vue";
-import { useRoute } from "vue-router";
-import { GetCandlestickChart } from "@/api/index.js";
-import EntrustingOrder from "./EntrustingOrder.vue";
-import LatestTransactions from "./LatestTransactions.vue";
-import KlineChart from "@/views/bitcoin/lever/components/KLineChart.vue";
-
-const route = useRoute();
-const symbolId = computed(() => route.query.id || '6');
-
-const currentTab = ref('1d');
-const tabs = ['1h', '6h', '1d', '1w', '1m'];
-const kLineData = ref([]);
-const socket = ref(null);
-const WS_BASE_URL = 'ws://backend.66linknow.com/ws/kline/';
-
-// --- 生产级配置 ---
-const HEARTBEAT_INTERVAL = 15000; // 心跳间隔 15s
-const RECONNECT_DELAY = 3000;     // 重连延迟 3s
-let heartbeatTimer = null;
-let reconnectTimer = null;
-let isUnmounted = false;
-
-const marketInfo = ref({
-  price: '0.00', fiatPrice: '0.00', change: 0.00, high: '0.00', low: '0.00', vol: '0', amount: '0'
-});
-
-const current = ref("entrustingOrder");
-const componentsMap = { entrustingOrder: EntrustingOrder, latestTransactions: LatestTransactions };
-const currentComponent = computed(() => componentsMap[current.value]);
-
-// --- 1. 切换周期 ---
-const switchPeriod = (period) => {
-  if (currentTab.value === period) return;
-
-  currentTab.value = period;
-
-  // 清空数据,触发子组件重置,并重新请求
-  kLineData.value = [];
-  getKlineData();
-};
-
-// --- 2. HTTP 获取历史数据 ---
-const getKlineData = async () => {
-  if (typeof GetCandlestickChart !== 'function') return;
-
-  try {
-    const res = await GetCandlestickChart({
-      symbol: symbolId.value,
-      period: currentTab.value
-    });
-
-    let rawList = [];
-    if (Array.isArray(res)) rawList = res;
-    else if (res && Array.isArray(res.data)) rawList = res.data;
-
-    if (rawList.length > 0) {
-      const formattedData = rawList.map(item => ({
-        timestamp: Number(item[0]),
-        open: parseFloat(item[1]),
-        high: parseFloat(item[2]),
-        low: parseFloat(item[3]),
-        close: parseFloat(item[4]),
-        volume: parseFloat(item[5])
-      }));
-      formattedData.sort((a, b) => a.timestamp - b.timestamp);
-      kLineData.value = formattedData;
-
-      // 同步合并:如果 WS 已经有最新价,立即修正历史数据最后一根,防止回跳
-      if (marketInfo.value.price !== '0.00') {
-        const lastBar = formattedData[formattedData.length - 1];
-        const realTimePrice = parseFloat(marketInfo.value.price);
-        lastBar.close = realTimePrice;
-        // 修正高低
-        if (realTimePrice > lastBar.high) lastBar.high = realTimePrice;
-        if (realTimePrice < lastBar.low) lastBar.low = realTimePrice;
-      }
-
-      updateMarketInfoFromKline(formattedData);
-    }
-  } catch (error) { console.error("API Error", error); }
-};
-
-const updateMarketInfoFromKline = (data) => {
-  if (!data.length) return;
-  const lastBar = data[data.length - 1];
-
-  // 仅当没数据或 WS 未连接时使用历史数据兜底
-  if (marketInfo.value.price === '0.00' || !socket.value || socket.value.readyState !== 1) {
-    const firstBar = data[0];
-    let maxHigh = -Infinity, minLow = Infinity, totalVol = 0;
-    data.forEach(item => {
-      if (item.high > maxHigh) maxHigh = item.high;
-      if (item.low < minLow) minLow = item.low;
-      totalVol += item.volume;
-    });
-    const changeRate = firstBar.open ? ((lastBar.close - firstBar.open) / firstBar.open) * 100 : 0;
-
-    marketInfo.value = {
-      price: lastBar.close,
-      change: changeRate.toFixed(2),
-      high: maxHigh, low: minLow, vol: totalVol, amount: totalVol * lastBar.close,
-      fiatPrice: lastBar.close
-    };
-  }
-};
-
-// --- 3. WS 连接 (含心跳设计) ---
-const connectWebSocket = () => {
-  // 清理旧资源
-  closeWebSocket();
-
-  const symbolStr = String(route.query.type || 'btcusdt').toLowerCase();
-  const url = `${WS_BASE_URL}?symbol=${symbolStr}`;
-
-  console.log('WS 连接:', url);
-
-  try {
-    socket.value = new WebSocket(url);
-
-    socket.value.onopen = () => {
-      console.log('✅ WS Connected');
-      startHeartbeat(); // 启动心跳
-    };
-
-    socket.value.onmessage = (event) => {
-      handleSocketMessage(event.data);
-    };
-
-    socket.value.onclose = () => {
-      stopHeartbeat(); // 停止心跳
-      if (!isUnmounted) {
-        console.log('⚠️ WS Closed, reconnecting...');
-        clearTimeout(reconnectTimer);
-        reconnectTimer = setTimeout(() => connectWebSocket(), RECONNECT_DELAY);
-      }
-    };
-
-    socket.value.onerror = (err) => {
-      // onerror 通常会触发 onclose,由 onclose 处理重连
-      console.error('❌ WS Error', err);
-    };
-  } catch (e) {
-    if (!isUnmounted) {
-      reconnectTimer = setTimeout(() => connectWebSocket(), RECONNECT_DELAY);
-    }
-  }
-};
-
-const closeWebSocket = () => {
-  if (socket.value) {
-    socket.value.close();
-    socket.value = null;
-  }
-  stopHeartbeat();
-  clearTimeout(reconnectTimer);
-};
-
-// --- 心跳逻辑 ---
-const startHeartbeat = () => {
-  stopHeartbeat();
-  heartbeatTimer = setInterval(() => {
-    if (socket.value && socket.value.readyState === WebSocket.OPEN) {
-      // 发送 ping,具体格式看后端要求,一般是字符串 'ping' 或 JSON
-      socket.value.send("ping");
-    }
-  }, HEARTBEAT_INTERVAL);
-};
-
-const stopHeartbeat = () => {
-  if (heartbeatTimer) {
-    clearInterval(heartbeatTimer);
-    heartbeatTimer = null;
-  }
-};
-
-// --- 辅助:获取周期对应的毫秒数 ---
-const getPeriodMs = (period) => {
-  const map = {
-    '1m': 60 * 1000,
-    '5m': 5 * 60 * 1000,
-    '15m': 15 * 60 * 1000,
-    '30m': 30 * 60 * 1000,
-    '1h': 60 * 60 * 1000,
-    '4h': 4 * 60 * 60 * 1000,
-    '6h': 6 * 60 * 60 * 1000,
-    '1d': 24 * 60 * 60 * 1000,
-    '1w': 7 * 24 * 60 * 60 * 1000,
-    '1M': 30 * 24 * 60 * 60 * 1000
-  };
-  return map[period] || 60 * 60 * 1000;
-}
-
-// --- 4. 核心:处理实时消息 (24hrTicker) ---
-const handleSocketMessage = (msgStr) => {
-  try {
-    // 忽略心跳响应
-    if (msgStr === 'pong') return;
-
-    const rawData = JSON.parse(msgStr);
-    const msg = rawData.data || rawData;
-
-    if (msg.e === "24hrTicker") {
-      marketInfo.value = {
-        price: msg.c, change: parseFloat(msg.P), high: msg.h, low: msg.l, vol: msg.v, amount: msg.q, fiatPrice: msg.c
-      };
-
-      if (kLineData.value.length > 0) {
-        const lastIndex = kLineData.value.length - 1;
-        const lastBar = kLineData.value[lastIndex];
-        const newPrice = parseFloat(msg.c);
-        const currentTime = Number(msg.E); // 事件时间
-        const periodMs = getPeriodMs(currentTab.value);
-
-        // 标准时间戳对齐算法: (当前时间 / 周期) * 周期
-        const currentBarStart = Math.floor(currentTime / periodMs) * periodMs;
-
-        // 如果计算出的起始时间 > 最后一根的起始时间,说明跨周期了,生成新 K 线
-        if (currentBarStart > lastBar.timestamp) {
-          const newBar = {
-            timestamp: currentBarStart,
-            open: newPrice,
-            high: newPrice,
-            low: newPrice,
-            close: newPrice,
-            volume: 0
-          };
-          // 扩展运算符触发更新
-          kLineData.value = [...kLineData.value, newBar];
-
-        } else {
-          // 还在当前周期内,更新最后一根
-          const updatedBar = {
-            ...lastBar,
-            close: newPrice,
-            high: Math.max(lastBar.high, newPrice),
-            low: Math.min(lastBar.low, newPrice)
-          };
-          kLineData.value.splice(lastIndex, 1, updatedBar);
-        }
-      }
-    }
-  } catch (e) {}
-};
-
-// --- 页面可见性监听 (切屏回来自动重连) ---
-const handleVisibilityChange = () => {
-  if (document.visibilityState === 'visible') {
-    if (!socket.value || socket.value.readyState !== WebSocket.OPEN) {
-      console.log('👀 Page Visible, reconnecting...');
-      connectWebSocket();
-    }
-  }
-};
-
-onMounted(() => {
-  isUnmounted = false;
-  getKlineData();
-  connectWebSocket();
-  document.addEventListener('visibilitychange', handleVisibilityChange);
-});
-
-onBeforeUnmount(() => {
-  isUnmounted = true;
-  closeWebSocket();
-  document.removeEventListener('visibilitychange', handleVisibilityChange);
-});
-
-watch(symbolId, () => {
-  kLineData.value = [];
-  getKlineData();
-  connectWebSocket();
-}, { immediate: false });
-
-const messageChange = (key) => { current.value = key; };
-const formatNumber = (num) => {
-  if (!num) return '0.00';
-  const n = Number(num);
-  return n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 6 });
-};
-const abbreviateNumber = (value) => {
-  if (!value) return '0.00';
-  let num = parseFloat(value);
-  if (isNaN(num)) return '0.00';
-  if (num >= 1e9) return (num / 1e9).toFixed(2) + 'B';
-  if (num >= 1e6) return (num / 1e6).toFixed(2) + 'M';
-  if (num >= 1e3) return (num / 1e3).toFixed(2) + 'K';
-  return num.toFixed(2);
-};
-const getPricePrecision = (price) => price < 1 ? 6 : (price < 10 ? 4 : 2);
-const getPriceColor = (change) => change >= 0 ? 'fc45B26B' : 'fcF6465D';
-const getUpDownClass = (change) => change >= 0 ? 'fc45B26B' : 'fcF6465D';
-</script>
-
-<style lang="less" scoped>
-.fc45B26B { color: #2EBD85 !important; }
-.fcF6465D { color: #F6465D !important; }
-.fc1F2937 { color: #1F2937; }
-
-/* 保持之前的样式布局 */
-.time-tabs {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  width: 100%;
-  box-sizing: border-box;
-  padding-top: 10px;
-  padding-bottom: 0px;
-}
-
-.tab-item {
-  font-size: 14px;
-  color: #929AA5;
-  padding: 4px 10px;
-  border-radius: 6px;
-  cursor: pointer;
-  font-weight: 500;
-  transition: all 0.2s;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.tab-item.icon {
-  color: #929AA5;
-  font-size: 12px;
-  padding: 4px 4px;
-}
-
-.triangle {
-  font-size: 8px;
-  margin-left: 2px;
-  transform: scale(0.9);
-}
-
-.tab-item img {
-  display: block;
-  height: 16px;
-  width: auto;
-}
-
-.market-conditions {
-  display: flex;
-  flex-direction: column;
-  justify-content: flex-start;
-  align-items: center;
-  width: 100%;
-
-  .market-price {
-    display: flex;
-    flex-direction: row;
-    justify-content: space-between;
-    margin-top: 8px;
-    width: 100%;
-    height: 73px;
-    padding: 0 15px;
-    box-sizing: border-box;
-
-    .price-left {
-      display: flex;
-      flex-direction: column;
-      justify-content: flex-start;
-      width: 144px;
-      height: 69px;
-
-      .left-price {
-        display: flex;
-        flex-direction: row;
-        justify-content: flex-start;
-        align-items: center;
-        height: 18px;
-
-        img {
-          margin-left: 5px;
-          width: 8px;
-          height: 4px;
-        }
-      }
-
-      .left-number {
-        margin-top: 5px;
-      }
-
-      .left-appro {
-        display: flex;
-        flex-direction: row;
-        justify-content: flex-start;
-        align-items: center;
-        margin-top: 3px;
-
-        .appro {
-          margin-left: 9px;
-        }
-      }
-    }
-
-    .price-right {
-      display: flex;
-      flex-direction: column;
-      justify-content: flex-start;
-      height: 100%;
-
-      .right-number-top, .right-number-bottom {
-        display: flex;
-        flex-direction: row;
-        justify-content: flex-end;
-        width: 100%;
-        height: 32px;
-
-        .right-number-top-price, .right-number-top-number {
-           margin-left: 10px;
-           text-align: right;
-            div {
-              height: 16px;
-              line-height: 16px;
-              text-align: end;
-            }
-        }
-      }
-      .right-number-bottom {
-        margin-top: 9px;
-      }
-    }
-  }
-
-  .k-line-main {
-    height: 50vh;
-    min-height: 350px;
-    width: 100%;
-  }
-
-  .notifi-classifi {
-    display: flex;
-    flex-direction: row;
-    justify-content: flex-start;
-    align-items: flex-end;
-    margin-top: 15px;
-    width: 100%;
-    padding: 0 15px;
-    box-sizing: border-box;
-    height: 24px;
-
-    .sys-notifi {
-      margin-left: 47px;
-    }
-  }
-}
-</style>

+ 2 - 2
src/views/market/dialog/ChangeIcon.vue

@@ -83,7 +83,7 @@
     position: fixed;
     left: 0;
     top: 0;
-    z-index: 1;
+    z-index: 10;
     display: flex;
     flex-direction: column;
     justify-content: flex-end;
@@ -151,7 +151,7 @@
 
         img {
           position: absolute;
-          top: 15px;
+          top: 26.5px;
           left: 14px;
           width: 17px;
           height: 17px;

+ 40 - 5
src/views/notification/Index.vue

@@ -1,10 +1,20 @@
 <template>
   <HeaderNav headerText="消息通知"></HeaderNav>
   <div class="notifi-index">
-    <div class="notifi-classifi">
-      <div class="pf600 fs18 fc121212" @click="messageChange('insite')">站内信</div>
-      <div class="sys-notifi pf600 fs14 fcA8A8A8" @click="messageChange('sys')">
+    <div class="notifi-classifi pf600 fs18 fc121212">
+      <div
+        class="classifi-item"
+        :class="current == 'insite' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('insite')">
+        站内信
+        <div class="active-line" v-if="current == 'insite'"></div>
+      </div>
+      <div
+        class="classifi-item pf600 fs14 fcA8A8A8"
+        :class="current == 'sys' ? 'current-classifi' : 'pf600 fs14 fcA8A8A8'"
+        @click="messageChange('sys')">
         系统通知
+        <div class="active-line" v-if="current == 'sys'"></div>
       </div>
     </div>
     <component :is="currentComponent" />
@@ -40,12 +50,37 @@
       flex-direction: row;
       justify-content: flex-start;
       align-items: flex-end;
-      margin-top: 63px;
+      margin-top: 48px;
       width: 345px;
       height: 24px;
 
-      .sys-notifi {
+      .classifi-item {
+        position: relative;
         margin-left: 43px;
+
+        .active-line {
+          position: absolute;
+          bottom: -6px;
+          left: 50%;
+          transform: translateX(-50%);
+          width: 20px;
+          height: 3px;
+          background-color: #323233;
+          border-radius: 2px;
+        }
+
+        &:first-child {
+          margin-left: 0;
+        }
+      }
+
+      .current-classifi {
+        font-family: "PingFang SC";
+        font-style: normal;
+        font-weight: 600;
+        font-size: 18px;
+        color: #121212;
+        transition: color 0.3s, font-size 0.3s;
       }
     }
   }

+ 4 - 2
src/views/notification/SysMessage.vue

@@ -1,9 +1,11 @@
 <template>
   <div class="insite-message">
     <div class="message-item" v-for="(item, index) in 3" :key="index">
-      <div class="title pf600 fs14 fc333333">标题信息内容标题信息内容11111111111111</div>
+      <div class="title pf600 fs14 fc333333">
+        系统通知系统通知系统通知系统通知系统通知
+      </div>
       <div class="desc pf500 fs12 fc999999">
-        文字内容信息文字内容信息文字内容信息文字内容信息文字内容信息文字内容信息文字内容信息文字内容信息文字内容信息
+        系统通知系统通知系统通知系统通知系统通知知系统通知系统通知系统通知知系统通知系统通知系统通知知系统通知系统通知系统通知
       </div>
       <div class="time pf300 fs12 fc999999">2025-11-06 12:25:10</div>
     </div>

+ 1 - 1
vue.config.js

@@ -19,7 +19,7 @@ module.exports = defineConfig({
       },
       // 2.【新增】WebSocket 代理配置
       '/ws/kline': {
-        target: 'ws://backend.66linknow.com', // 后端 IP
+        target: 'http://backend.66linknow.com', // 后端 IP
         changeOrigin: true,
         ws: true // ⚠️ 开启 WebSocket 支持
         // 这里是否需要 pathRewrite 取决于后端路径有没有 /ws

Vissa filer visades inte eftersom för många filer har ändrats