Răsfoiți Sursa

杠杆首页-完成
杠杆首页-计划-完成
调整保证金 -完成
封装通用的k线图组件-完成

Hexinkui 1 lună în urmă
părinte
comite
4f0fd0ccb5

+ 7 - 0
package-lock.json

@@ -9,6 +9,7 @@
       "version": "0.1.0",
       "dependencies": {
         "axios": "^1.13.2",
+        "klinecharts": "^8.6.3",
         "vant": "^4.9.21",
         "vue": "^3.2.13",
         "vue-router": "^4.0.3",
@@ -4271,6 +4272,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/klinecharts": {
+      "version": "8.6.3",
+      "resolved": "https://registry.npmjs.org/klinecharts/-/klinecharts-8.6.3.tgz",
+      "integrity": "sha512-hGDtWiMNywEDneZFmt+vZ6tOYutCDWV5FPBcXcn7L8kGwe73Q5yJayk8UzP9pIQSBWyxswWIySKh/BVFA6GhuQ==",
+      "license": "Apache-2.0"
+    },
     "node_modules/klona": {
       "version": "2.0.6",
       "resolved": "https://registry.npmmirror.com/klona/-/klona-2.0.6.tgz",

+ 1 - 0
package.json

@@ -8,6 +8,7 @@
   },
   "dependencies": {
     "axios": "^1.13.2",
+    "klinecharts": "^8.6.3",
     "vant": "^4.9.21",
     "vue": "^3.2.13",
     "vue-router": "^4.0.3",

+ 4 - 0
src/assets/icon/bitcoin/lishidingdan.svg

@@ -0,0 +1,4 @@
+<svg width="27" height="14" viewBox="0 0 27 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="1" height="14" fill="#979797"/>
+<path d="M25.9167 0H15.0833C14.796 0 14.5205 0.114136 14.3173 0.317301C14.1141 0.520465 14 0.796015 14 1.08333V11.9167C14 12.204 14.1141 12.4795 14.3173 12.6827C14.5205 12.8859 14.796 13 15.0833 13H22.4425C22.5849 13.0004 22.7259 12.9726 22.8573 12.9181C22.9888 12.8636 23.1081 12.7835 23.2083 12.6824L26.6824 9.20833C26.7835 9.1081 26.8636 8.98878 26.9181 8.85732C26.9726 8.72585 27.0004 8.58487 27 8.44255V1.08333C27 0.796015 26.8859 0.520465 26.6827 0.317301C26.4795 0.114136 26.204 0 25.9167 0ZM15.0833 1.08333H25.9167V8.125H22.6667C22.523 8.125 22.3852 8.18207 22.2836 8.28365C22.1821 8.38523 22.125 8.523 22.125 8.66666V11.9167H15.0833V1.08333ZM25.1509 9.20833L23.2083 11.1509V9.20833H25.1509Z" fill="#979797"/>
+</svg>

+ 42 - 29
src/router/index.js

@@ -15,14 +15,17 @@ import IcoIndex from "../views/index/ico/Index.vue";
 import LoanIndex from "../views/index/loan/Index.vue";
 import LoanRules from "../views/index/loan/Rules.vue";
 import UserLoanIndex from "../views/user/loan/Index.vue";
-import FootprintIndex from "../views/bitcoin/Index.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/TradeOptions.vue'; // 期权(占位)
+import TradeMargin from '@/views/bitcoin/lever/TradeMargin.vue';
 import Calculator from '../views/bitcoin/Calculator.vue' // 新建的计算器页面
 import CommonFunctionsPopup from '@/views/bitcoin/CommonFunctionsPopup/CommonFunctionsPopup.vue' // 子组件路径
 import TradeSettings from '@/views/bitcoin/CommonFunctionsPopup/GeneralLevel2/TradeSettings.vue'// 新建
 import TradeRules from '@/views/bitcoin/CommonFunctionsPopup/GeneralLevel2/TradeRules.vue'       // 新建
 
 
-
 const routes = [
     {
         path: "/",
@@ -30,33 +33,43 @@ const routes = [
         component: HomeIndex,
     },
     {
-        path: "/bitcoin",
-        name: "bitcoin",
-        component: FootprintIndex,
-        children: [{
-            path: 'functions', // 访问地址变为 /bitcoin/functions
-            name: 'BitcoinFunctions',
-            component: CommonFunctionsPopup,
-            meta: { showTabbar: false }, // 如果有底部导航栏,可能需要隐藏
-            children: [
-                {
-                  path: 'settings', // 全屏页
-                  name: 'TradeSettings',
-                  component: TradeSettings
-                },
-                {
-                  path: 'rules',   // 二级弹窗
-                  name: 'TradeRules',
-                  component: TradeRules
-                },
-                {
-                  path: 'calculator',
-                  name: 'calculator',
-                  component: Calculator
-                },
-            ]
-            },
-        ]
+    path: "/bitcoin",
+    component: TradeLayout, // 而是布局组件
+    // 当访问 /bitcoin 时,自动重定向到 /bitcoin/contract
+    redirect: '/bitcoin/contract',
+    children: [
+      // 1. 核心交易子路由
+      {
+        path: 'contract',
+        name: 'TradeContract',
+        component: TradeFutures, // 核心交易逻辑
+        meta: { title: '合约' }
+      },
+      {
+        path: 'seconds',
+        name: 'TradeSeconds',
+        component: TradeSeconds,
+        meta: { title: '秒合约' }
+      },
+      {
+        path: 'options',
+        name: 'TradeOptions',
+        component: TradeOptions,
+        meta: { title: '期权' }
+      },
+      {
+        path: 'margin',
+        name: 'TradeMargin',
+        component: TradeMargin,
+        meta: { title: '杠杆' }
+      },
+      { path: 'settings',
+        name: 'TradeSettings',
+        component: TradeSettings },
+      { path: 'calculator',
+        name: 'calculator',
+        component: Calculator },
+     ]
     },
     {
         path: "/applyPermission",

+ 5 - 3
src/views/HomeIndex.vue

@@ -11,7 +11,7 @@
           class="item-image"
           :src="current === item.key ? item.selectedImage : item.image"
           alt="" />
-        <div class="item-text" :class="{ activeClass: current === item.key }">
+        <div class="item-text" :class="{ activeClass: current === item.key }" @click="$router.push({ path: '/bitcoin' })">
           {{ item.text }}
         </div>
       </div>
@@ -23,7 +23,9 @@
   import { ref, computed } from "vue";
   import CalendarIndex from "./index/Index.vue";
   import NoticeIndex from "./market/Index.vue";
-  import FootprintIndex from "./bitcoin/Index.vue";
+  import TradeLayout from '@/views/bitcoin/TradeLayout.vue';
+  // import TradeFutures from '@/views/bitcoin/TradeFutures.vue';
+  // import FootprintIndex from "./bitcoin/Index.vue";
   import AiIndex from "./asset/Index.vue";
   import UserIndex from "./user/Index.vue";
    import { useRouter } from "vue-router";
@@ -35,7 +37,7 @@
   const componentsMap = {
     index: CalendarIndex,
     market: NoticeIndex,
-    bitcoin: FootprintIndex,
+    bitcoin: TradeLayout,
     asset: AiIndex,
     user: UserIndex,
   };

+ 143 - 85
src/views/bitcoin/CommonFunctionsPopup/CommonFunctionsPopup.vue

@@ -1,18 +1,23 @@
 <template>
+  <!-- Teleport 确保弹窗挂载到 body,层级最高 -->
   <Teleport to="body">
+    <!-- 1. 遮罩层 -->
     <Transition name="fade">
       <div v-if="visible" class="modal-mask" @click="handleClose"></div>
     </Transition>
 
+    <!-- 2. 弹窗面板 -->
     <Transition name="slide-up">
-      <div v-if="visible" class="modal-panel" @click.stop >
+      <div v-if="visible" class="modal-panel" @click.stop>
 
+        <!-- 顶部小横条 -->
         <div class="panel-handle-wrap">
           <div class="panel-handle"></div>
         </div>
 
         <div class="panel-title">常用功能</div>
 
+        <!-- 九宫格菜单 -->
         <div class="grid-container">
           <div
             v-for="(item, index) in menuItems"
@@ -34,79 +39,65 @@
         <div class="safe-area-bottom"></div>
       </div>
     </Transition>
-    <router-view></router-view>
-<!--    <router-view v-slot="{ Component }">-->
-<!--      <transition name="fade">-->
-<!--        <component :is="Component" />-->
-<!--      </transition>-->
-<!--    </router-view>-->
+    <TradeRules
+    v-model:visible="showRules"
+    />
   </Teleport>
 </template>
 
 <script setup>
-import { ref, onMounted, watch, onUnmounted } from 'vue' // 引入 watch 和 onUnmounted
-import { useRouter,useRoute } from 'vue-router'
-
-const route = useRoute() // 获取当前路由信息
-const router = useRouter()
-// 定义一个内部变量控制显示,用于触发 Transition 动画
-const visible = ref(false)
-const lockScroll = () => {
-  // 强制隐藏 body 的滚动条
-  document.body.style.overflow = 'hidden'
-  // 如果是 iOS,有些情况需要锁 html
-  document.documentElement.style.overflow = 'hidden'
-}
-
-const unlockScroll = () => {
-  // 恢复滚动
-  document.body.style.overflow = ''
-  document.documentElement.style.overflow = ''
-}
-
-// 监听弹窗显示状态
-watch(visible, (newVal) => {
-  if (newVal) {
-    lockScroll() // 弹窗开 -> 锁死
-  } else {
-    unlockScroll() // 弹窗关 -> 解锁
+import {toRef, watch} from 'vue'
+import { useRouter } from 'vue-router'
+import { ref, defineAsyncComponent } from 'vue';
+// 引入
+import TradeRules from  './GeneralLevel2/TradeRules.vue';
+import { useBodyScrollLock } from '@/composables/useBodyScrollLock' // 2. 引入 Hook
+
+// 控制显示的变量
+const showRules = ref(false);
+
+// 1. 接收父组件 (TradeLayout) 传来的 visible 状态
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
   }
 })
+useBodyScrollLock(toRef(props, 'visible'))
+// 2. 定义事件,用于通知父组件修改 visible
+const emit = defineEmits(['update:visible'])
 
-// 1. 进场动画:组件挂载后,立即设为 true
-onMounted(() => {
-  if (route.name === 'BitcoinFunctions') {
-    visible.value = true
-  }
-})
+const router = useRouter()
 
-// 2. 离场逻辑:先关动画,等动画播完再路由回退
+// --- 关闭逻辑 ---
 const handleClose = () => {
-  visible.value = false
-  // 300ms 对应 CSS 中的 transition 时间
-  setTimeout(() => {
-    router.back()
-    // router.push({ name: 'bitcoin' })
-  }, 300)
+  // 通知父组件把 visible 设为 false
+  // 这样 TradeLayout 里的 showFunctions 就会变成 false
+  emit('update:visible', false)
 }
 
+// --- 点击菜单项逻辑 ---
 const handleItemClick = (item) => {
-  console.log('选中:', item.name)
-  if (item.name === '交易设置') {
-    router.push({ name: 'TradeSettings' })
-  } else if (item.name === '交易规则') {
-    router.push({ name: 'TradeRules' })
-
-  } else if (item.name === '计算器') {
-    router.push({ name: 'calculator' })
-  } else {
-    console.log('点击了其他:', item.name)
-  }
-  // 可以在这里处理业务逻辑,然后关闭
+  // 1. 先关闭弹窗
   // handleClose()
+
+  // 2. 再跳转路由
+  // 注意:根据我们定好的路由表,这里跳转会离开 TradeLayout,
+  // 进入全屏的设置页/计算器页,这是符合预期的。
+  setTimeout(() => {
+    if (item.name === '交易设置') {
+      router.push({ name: 'TradeSettings' })
+    } else if (item.name === '交易规则') {
+      showRules.value = true
+    } else if (item.name === '计算器') {
+      router.push({ name: 'calculator' })
+    } else {
+      console.log('点击了其他:', item.name)
+    }
+  }, 200) // 稍微延迟一点点,让关闭动画看起来更自然(可选)
 }
 
-// Webpack 图片加载逻辑
+// --- 图标加载 ---
 const getIconPath = (iconName) => {
   try {
     return require(`../../../assets/icon/bitcoin/${iconName}`)
@@ -127,42 +118,109 @@ const menuItems = [
 </script>
 
 <style scoped>
-
-/* 样式完全保持不变 */
+/* 遮罩层 */
 .modal-mask {
-  position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
-  background-color: rgba(0, 0, 0, 0.5); z-index: 199;
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  background-color: rgba(0, 0, 0, 0.5);
+  z-index: 199; /* 保证层级够高 */
 }
+
+/* 弹窗面板 */
 .modal-panel {
-  position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
-  width: 100%; max-width: 600px; background: white;
-  border-radius: 16px 16px 0 0; padding: 10px 0 0 0; z-index: 199;
-}
-.panel-handle-wrap { display: flex; justify-content: center; padding-bottom: 20px; }
-.panel-handle { width: 36px; height: 4px; background: #E0E0E0; border-radius: 2px; }
-.panel-title { font-size: 18px; font-weight: bold; color: #333; padding: 0 20px 20px 20px; }
-.safe-area-bottom { height: 30px; }
-
-/* 动画 */
-.fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease; }
-.fade-enter-from, .fade-leave-to { opacity: 0; }
-.slide-up-enter-active, .slide-up-leave-active { transition: transform 0.3s ease; }
-.slide-up-enter-from, .slide-up-leave-to { transform: translate(-50%, 100%); }
-
-/* Grid */
+  position: fixed;
+  bottom: 0;
+  left: 50%;
+  transform: translateX(-50%);
+  width: 100%;
+  max-width: 600px; /* 限制最大宽度,适配桌面端 */
+  background: white;
+  border-radius: 16px 16px 0 0;
+  padding: 10px 0 0 0;
+  z-index: 200; /* 比遮罩层高 */
+}
+
+/* 把手装饰 */
+.panel-handle-wrap {
+  display: flex;
+  justify-content: center;
+  padding-bottom: 20px;
+}
+.panel-handle {
+  width: 36px;
+  height: 4px;
+  background: #E0E0E0;
+  border-radius: 2px;
+}
+
+/* 标题 */
+.panel-title {
+  font-size: 18px;
+  font-weight: bold;
+  color: #333;
+  padding: 0 20px 20px 20px;
+}
+
+/* 底部安全区适配 */
+.safe-area-bottom {
+  height: 30px;
+  padding-bottom: env(safe-area-inset-bottom);
+}
+
+/* --- 动画相关 --- */
+/* 淡入淡出 */
+.fade-enter-active, .fade-leave-active {
+  transition: opacity 0.3s ease;
+}
+.fade-enter-from, .fade-leave-to {
+  opacity: 0;
+}
+
+/* 底部滑入滑出 */
+.slide-up-enter-active, .slide-up-leave-active {
+  transition: transform 0.3s ease;
+}
+.slide-up-enter-from, .slide-up-leave-to {
+  transform: translate(-50%, 100%);
+}
+
+/* --- Grid 布局 --- */
 .grid-container {
-  display: grid; grid-template-columns: repeat(4, 1fr);
-  row-gap: 25px; padding: 0 10px 20px 10px;
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  row-gap: 25px;
+  padding: 0 10px 20px 10px;
 }
 .grid-item {
-  display: flex; flex-direction: column; align-items: center; cursor: pointer;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  cursor: pointer;
+  /* 添加点击反馈效果 */
+  active {
+    opacity: 0.7;
+  }
 }
 .icon-box {
-  width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;
+  width: 40px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
   margin-bottom: 8px;
 }
 .grid-icon-img {
-  width: 100%; height: 100%; object-fit: contain; display: block;
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+  display: block;
+}
+.label {
+  font-size: 12px;
+  color: #666;
+  text-align: center;
 }
-.label { font-size: 12px; color: #666; text-align: center; }
 </style>

+ 133 - 66
src/views/bitcoin/CommonFunctionsPopup/GeneralLevel2/TradeRules.vue

@@ -1,110 +1,177 @@
 <template>
+  <!-- Teleport 保证弹窗挂载到 body,层级最高 -->
   <Teleport to="body">
-    <div class="mask-level-2" @click="$router.back()"></div>
-    
-    <div class="popup-level-2 slide-up-animation">
-      <div class="handle-bar-wrap">
-        <div class="handle-bar"></div>
-      </div>
-      
-      <div class="popup-title">交易规则</div>
 
-      <div class="rules-content">
-        <div class="rule-row border-bottom">
-          <span class="label">最小价格波动</span>
-          <span class="value">0.01 USDT</span>
-        </div>
-        <div class="rule-row spacer-bottom">
-          <span class="label">价格倍数</span>
-          <span class="value">0.2 - 5</span>
-        </div>
+    <!-- 1. 遮罩层 (增加淡入淡出动画) -->
+    <Transition name="fade">
+      <div
+        v-if="visible"
+        class="mask-level-2"
+        @click="handleClose"
+      ></div>
+    </Transition>
 
-        <div class="rule-row">
-          <span class="label">订单规模</span>
-          <span class="value">5 - 9000000 USDT</span>
-        </div>
-        <div class="rule-row">
-          <span class="label">交易数量</span>
-          <span class="value">00001 - 9000 BTC</span>
-        </div>
-        <div class="rule-row">
-          <span class="label">最小数量波动</span>
-          <span class="value">0.00001 BTC</span>
-        </div>
-        <div class="rule-row">
-          <span class="label">市价单单笔最大数量</span>
-          <span class="value">75.45007539 BTC</span>
-        </div>
-        <div class="rule-row">
-          <span class="label">限价单单笔挂单数量</span>
-          <span class="value">200</span>
+    <!-- 2. 弹窗主体 (增加底部滑入动画) -->
+    <Transition name="slide-up">
+      <div v-if="visible" class="popup-level-2">
+
+        <!-- 把手装饰 -->
+        <div class="handle-bar-wrap" @click="handleClose">
+          <div class="handle-bar"></div>
         </div>
-        <div class="rule-row">
-          <span class="label">最大条件单挂单数量</span>
-          <span class="value">5</span>
+
+        <div class="popup-title">交易规则</div>
+
+        <!-- 内容区域 -->
+        <div class="rules-content">
+          <div class="rule-row border-bottom">
+            <span class="label">最小价格波动</span>
+            <span class="value">0.01 USDT</span>
+          </div>
+          <div class="rule-row spacer-bottom">
+            <span class="label">价格倍数</span>
+            <span class="value">0.2 - 5</span>
+          </div>
+
+          <div class="rule-row">
+            <span class="label">订单规模</span>
+            <span class="value">5 - 9000000 USDT</span>
+          </div>
+          <div class="rule-row">
+            <span class="label">交易数量</span>
+            <span class="value">00001 - 9000 BTC</span>
+          </div>
+          <div class="rule-row">
+            <span class="label">最小数量波动</span>
+            <span class="value">0.00001 BTC</span>
+          </div>
+          <div class="rule-row">
+            <span class="label">市价单单笔最大数量</span>
+            <span class="value">75.45007539 BTC</span>
+          </div>
+          <div class="rule-row">
+            <span class="label">限价单单笔挂单数量</span>
+            <span class="value">200</span>
+          </div>
+          <div class="rule-row">
+            <span class="label">最大条件单挂单数量</span>
+            <span class="value">5</span>
+          </div>
         </div>
       </div>
-    </div>
+    </Transition>
   </Teleport>
 </template>
 
+<script setup>
+import { watch, onUnmounted } from 'vue';
+
+// 1. 接收 visible 属性
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  }
+});
+
+// 2. 定义事件
+const emit = defineEmits(['update:visible', 'close']);
+
+// --- 滚动锁定逻辑 (防止背景跟随滚动) ---
+const lockScroll = () => {
+  document.body.style.overflow = 'hidden';
+};
+const unlockScroll = () => {
+  document.body.style.overflow = '';
+};
+
+// 监听 visible 变化
+watch(() => props.visible, (val) => {
+  if (val) {
+    lockScroll();
+  } else {
+    unlockScroll();
+  }
+});
+
+// 组件卸载时确保解锁,防止异常情况卡住
+onUnmounted(() => {
+  unlockScroll();
+});
+
+// --- 关闭处理 ---
+const handleClose = () => {
+  // 通知父组件把 visible 设为 false
+  emit('update:visible', false);
+  emit('close');
+};
+</script>
+
 <style scoped>
-/* 二级遮罩:稍微深一点,或者透明,看你想不想要双重遮罩效果 */
+/* --- 遮罩层样式 --- */
 .mask-level-2 {
-  position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
-  background: rgba(0,0,0,0.2); 
-  z-index: 2001; /* 比一级高 */
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  /* 你之前的 0.2 透明度 */
+  background: rgba(0, 0, 0, 0.2);
+  z-index: 2001;
 }
 
+/* --- 弹窗主体样式 --- */
 .popup-level-2 {
-  position: fixed; bottom: 0; left: 0; width: 100%;
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  width: 100%;
   background: white;
   border-radius: 16px 16px 0 0;
-  z-index: 2002; /* 最高层级 */
+  z-index: 2002;
   padding-bottom: calc(20px + env(safe-area-inset-bottom));
+  /* 限制最大高度,防止内容溢出 */
   max-height: 85vh;
   overflow-y: auto;
 }
 
+/* --- 内容样式保持不变 --- */
 .handle-bar-wrap {
   display: flex; justify-content: center; padding: 10px 0;
 }
 .handle-bar {
   width: 36px; height: 4px; background: #E0E0E0; border-radius: 2px;
 }
-
 .popup-title {
   font-size: 18px; font-weight: bold; color: #333;
   padding: 0 20px 20px 20px;
 }
-
-.rules-content {
-  padding: 0 20px;
-}
-
+.rules-content { padding: 0 20px; }
 .rule-row {
   display: flex; justify-content: space-between;
-  margin-bottom: 16px;
-  font-size: 14px;
+  margin-bottom: 16px; font-size: 14px;
 }
 .label { color: #888; }
 .value { color: #333; font-weight: 500; text-align: right;}
-
 .border-bottom {
-  padding-bottom: 16px;
-  border-bottom: 1px solid #f5f5f5;
-  margin-bottom: 16px;
+  padding-bottom: 16px; border-bottom: 1px solid #f5f5f5; margin-bottom: 16px;
+}
+.spacer-bottom { margin-bottom: 30px; }
+
+/* --- Vue Transition 动画 --- */
+/* 1. 遮罩层淡入淡出 */
+.fade-enter-active, .fade-leave-active {
+  transition: opacity 0.3s ease;
 }
-.spacer-bottom {
-  margin-bottom: 30px; /* 两组数据之间的间距 */
+.fade-enter-from, .fade-leave-to {
+  opacity: 0;
 }
 
-/* 简单的进场动画 */
-.slide-up-animation {
-  animation: slideUp 0.3s ease-out;
+/* 2. 弹窗底部滑入滑出 */
+.slide-up-enter-active, .slide-up-leave-active {
+  transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
 }
-@keyframes slideUp {
-  from { transform: translateY(100%); }
-  to { transform: translateY(0); }
+.slide-up-enter-from, .slide-up-leave-to {
+  transform: translateY(100%);
 }
 </style>

+ 0 - 1
src/views/bitcoin/CommonFunctionsPopup/GeneralLevel2/TradeSettings.vue

@@ -286,7 +286,6 @@
         import FundingOptions from './components/PositionMode.vue'
         import SelectionSheet from './components/SelectionSheet.vue' // 引入上面的组件
         import TradeNotificationPopup from './components/TradeNotificationPopup.vue'
-        import TriggerValueSheet from './components/TriggerValueSheet.vue'
         const showNotifyPopup = ref(false)
                 // --- 状态管理 ---
         const showThemeModal = ref(false)

+ 880 - 0
src/views/bitcoin/TradeFutures.vue

@@ -0,0 +1,880 @@
+<template>
+  <div class="trade-futures-container">
+
+    <div class="menu">
+      <div class="menu-left">
+        <img class="fc333333" src="../../assets/icon/bitcoin/menu.svg" alt="">
+        <div class="pf600 fs18 fc121212">BTCUSDT 永续</div>
+      </div>
+      <div class="menu-right fc333333">
+        <img src="../../assets/icon/bitcoin/jisuanqi.svg" alt="" @click="router.push({name: 'calculator'})">
+        <img src="../../assets/icon/bitcoin/hangqing.svg" alt="">
+        <img src="../../assets/icon/bitcoin/den.svg" alt="" @click="showFunctions = true">
+      </div>
+    </div>
+
+    <div class="menu-bottom">
+      <div class="pf500 fs12 menu-leftb">
+        +2.18%
+      </div>
+      <div class="fc333333 fs12 pf400 menu-rightb">
+        <div>资金费率/倒计时</div>
+        <div>0.003%/1:57:32</div>
+      </div>
+    </div>
+    <div class="menu-content">
+      <div class="menu-content-l">
+        <div class="menu-content-lb pf400 fs14 fc666666">
+          <span>价格</span><span>数量(USDT)</span>
+        </div>
+
+        <div class="menu-content-lb1">
+          <div class="menu-content-lb1l pf400 fs14 fcFF7171">
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+          </div>
+          <div class="menu-content-lb1r pf400 fs14 fc444444">
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+          </div>
+        </div>
+
+        <div class="menu-content-lb2">
+          <p class="pf600 fs16 fcDF384C">5,678.00</p>
+          <p class="fs12 fcA8A8A8 pf400">1,678.00</p>
+        </div>
+
+        <div class="menu-content-lb1">
+          <div class="menu-content-lb1l pf400 fs14 fc333333">
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+            <span>40,166.82</span>
+          </div>
+          <div class="menu-content-lb1r pf400 fs14 fc444444">
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+            <span>37.80K</span>
+          </div>
+        </div>
+
+        <div class="menu-content-lb1">
+          <div class="menu-content-lb1l pf400 fs12 fc333333" @click="isPickerVisible = true">
+            <span class="fs12">{{ displayLabel }}</span>
+            <img src="../../assets/icon/bitcoin/shendul.svg" alt="">
+          </div>
+          <div class="menu-content-lb1r pf400 fs14 fc444444">
+            <img src="../../assets/icon/bitcoin/shendur.svg" alt="">
+            <img v-if="isassetlessState" src="../../assets/icon/bitcoin/wuzichan.svg" alt="">
+          </div>
+        </div>
+      </div>
+
+      <assetlessStateData v-if="isassetlessState"></assetlessStateData>
+      <SellTradingStatusData v-if="isassetlessState"></SellTradingStatusData>
+
+      <div class="menu-content-r">
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333" @click="showInfo = true">
+            <img src="../../assets/icon/bitcoin/quancang.svg" alt="">
+            <span>{{ selectedLabel1 }}</span>
+          </div>
+          <div @click="showModal1 = true" style="font-size: 12px; margin-right: 12px;">
+            <VanIcon :style="{ fontWeight: 'bold' }" :name="showModal1 ? 'arrow-up' : 'arrow-down'"/>
+          </div>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333" @click="showModal3 = true">
+            <img src="../../assets/icon/bitcoin/quancang.svg" alt="">
+            <span>{{ selectedLabel2 }}</span>
+          </div>
+          <div @click="showModal2 = true" style="font-size: 12px; margin-right: 12px;">
+            <VanIcon :style="{ fontWeight: 'bold' }" :name="showModal2 ? 'arrow-up' : 'arrow-down'"/>
+          </div>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span>125000</span>
+          </div>
+          <span>最优价</span>
+        </div>
+        <div class="menu-content-rb pf400 fs14 fc333333">≈25.2250 USDT</div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span class="menu-content-rb1s fc999999">数量</span>
+          </div>
+          <span>USDT</span>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span class="menu-content-rb1s fc333333">可用</span>
+          </div>
+          <div class="menu-content-rb1">
+            <span>0</span>
+            <span>USDT</span>
+            <img class="fs16" src="../../assets/icon/bitcoin/qianbao1.svg" alt="">
+          </div>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span class="menu-content-rb1s fc333333">倍数</span>
+          </div>
+          <div class="menu-content-rb1" @click="showLeverageModal = true">
+            <span></span>
+            <span>{{ selectedLeverage }}X</span>
+            <span>更多</span>
+          </div>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <van-checkbox
+                v-model="isEnabled"
+                shape="square"
+                checked-color="#DC4653"
+                icon-size="16px"
+            >
+            </van-checkbox>
+            <span class="menu-content-rb1s fc333333">只减仓</span>
+          </div>
+          <div class="menu-content-rb1" @click="showModal = true">
+            <span></span>
+            <span>{{ currentType }}</span>
+            <div style="font-size: 12px;">
+              <VanIcon :style="{ fontWeight: 'bold' }" :name="showModal ? 'arrow-up' : 'arrow-down'"/>
+            </div>
+          </div>
+        </div>
+
+        <TakeProfitsTopLoss v-show="!isEnabled"></TakeProfitsTopLoss>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span class="menu-content-rb1s fc333333">可用</span>
+          </div>
+          <div class="menu-content-rb1">
+            <span>0</span>
+            <span>USDT</span>
+          </div>
+        </div>
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span class="menu-content-rb1s fc333333">保证金</span>
+          </div>
+          <div class="menu-content-rb1">
+            <span>0</span>
+            <span>USDT</span>
+          </div>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14" @click="showConfirm = true">
+          <div class="pf400 fs16 fcFFFFFF">买入(做多)</div>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span class="menu-content-rb1s fc333333">可用</span>
+          </div>
+          <div class="menu-content-rb1">
+            <span>0</span>
+            <span>USDT</span>
+          </div>
+        </div>
+        <div class="menu-content-rb pf400 fs14">
+          <div class="menu-content-rb1 fs14 fc333333">
+            <span class="menu-content-rb1s fc333333">保证金</span>
+          </div>
+          <div class="menu-content-rb1">
+            <span>0</span>
+            <span>USDT</span>
+          </div>
+        </div>
+
+        <div class="menu-content-rb pf400 fs14">
+          <div class="pf400 fs16 fcFFFFFF" @click="showConfirm = true">卖出(做空)</div>
+        </div>
+      </div>
+    </div>
+
+    <sellOrder></sellOrder>
+
+    <div v-if="isassetlessState">
+      <assetlessState></assetlessState>
+    </div>
+
+    <ChooseThisDepth
+        v-model:show="isPickerVisible"
+        v-model="currentDepth"
+    ></ChooseThisDepth>
+
+    <LeveragePopup
+        v-model:visible="showLeverageModal"
+        :initial-value="selectedLeverage"
+        @confirm="handleConfirm">
+    </LeveragePopup>
+
+    <OrderConfirmPopup
+        v-model:visible="showConfirm"
+        @confirm="onOrderConfirmed">
+    </OrderConfirmPopup>
+
+    <OrderTimeSheet
+        v-model:visible="showModal"
+        v-model="currentType"
+    ></OrderTimeSheet>
+
+    <MarginInfoSheet
+        v-model:visible="showInfo"
+    ></MarginInfoSheet>
+
+    <FundingOptions
+        v-model:visible="showModal1"
+        :selected-id="currentId1"
+        @confirm="handleConfirm1">
+    </FundingOptions>
+
+    <OrderType
+        v-model:visible="showModal2"
+        :selected-id="currentId2"
+        @confirm="handleConfirm2"
+    ></OrderType>
+
+    <LimitOrderModal
+        v-model:visible="showModal3"
+    ></LimitOrderModal>
+    <CommonFunctionsPopup
+      v-model:visible="showFunctions"
+    ></CommonFunctionsPopup>
+  </div>
+</template>
+
+<script setup>
+import {Checkbox as VanCheckbox, Icon as VanIcon} from 'vant';
+import {computed, defineAsyncComponent, ref} from 'vue';
+import { useRouter } from 'vue-router'; // 【新增】 引入路由
+
+const router = useRouter(); // 【新增】 实例化路由
+
+// --- 异步组件引入 ---
+const priceLimit = defineAsyncComponent(() => import("./components/priceLimit.vue"));
+const assetlessState = defineAsyncComponent(() => import("./components/assetlessState.vue"));
+const assetlessStateData = defineAsyncComponent(() => import("./components/assetlessStateData.vue"));
+const sellOrder = defineAsyncComponent(() => import('./components/sellOrder.vue'));
+const SellTradingStatusData = defineAsyncComponent(() => import('./components/SellTradingStatusData.vue'));
+const TakeProfitsTopLoss = defineAsyncComponent(() => import('./components/TakeProfitsTopLoss.vue'));
+const ChooseThisDepth = defineAsyncComponent(() => import('./components/ChooseThisDepth.vue'));
+const LeveragePopup = defineAsyncComponent(() => import('./components/LeveragePopup.vue'));
+const OrderConfirmPopup = defineAsyncComponent(() => import('./components/OrderConfirmPopup.vue'));
+const OrderTimeSheet = defineAsyncComponent(() => import('./components/OrderTimeSheet.vue'));
+const MarginInfoSheet = defineAsyncComponent(() => import('./components/MarginInfoSheet.vue'));
+const FundingOptions = defineAsyncComponent(() => import('./components/FundingOptions.vue'));
+const OrderType = defineAsyncComponent(() => import('./components/OrderType.vue'));
+const LimitOrderModal = defineAsyncComponent(() => import('./components/LimitOrderModal.vue'));
+// 假设您的组件在 @/components/CommonFunctionsPopup.vue (请根据实际路径修改)
+const CommonFunctionsPopup = defineAsyncComponent(() => import('./CommonFunctionsPopup/CommonFunctionsPopup.vue'));
+
+// 控制弹窗显示的变量
+const showFunctions = ref(false);
+
+// --- 状态定义 ---
+const isassetlessState = ref(false);
+
+const isPickerVisible = ref(false);
+const currentDepth = ref('depth1');
+const depthMap = {
+  'depth1': '深度1',
+  'depth2': '深度2',
+  'depth3': '深度3',
+};
+const displayLabel = computed(() => depthMap[currentDepth.value] || '请选择');
+
+/* 市价说明 */
+const showModal3 = ref(false);
+
+/* 订单类型选项 */
+const showModal2 = ref(false);
+const currentId2 = ref(1);
+const selectedLabel2 = ref('市价');
+const selectedUnit2 = ref('%');
+const handleConfirm2 = (item) => {
+  currentId2.value = item.id;
+  selectedLabel2.value = item.label.slice(0, 2);
+  selectedUnit2.value = item.unit;
+};
+
+/* 全仓逐仓选项 */
+const showModal1 = ref(false);
+const currentId1 = ref(1);
+const selectedLabel1 = ref('全仓');
+const selectedUnit1 = ref('%');
+const handleConfirm1 = (item) => {
+  currentId1.value = item.id;
+  selectedLabel1.value = item.label.slice(0, 2);
+  selectedUnit1.value = item.unit;
+};
+
+/* 全仓逐仓说明 */
+const showInfo = ref(false);
+
+/* GTC 弹框 */
+const showModal = ref(false);
+const currentType = ref('GTC');
+
+/* 控制止盈止损显隐 */
+const isEnabled = ref(false);
+
+/* 控制倍数 */
+const showLeverageModal = ref(false);
+const selectedLeverage = ref(100);
+const handleConfirm = (value) => {
+  selectedLeverage.value = value;
+};
+
+/* 交易确认 */
+const showConfirm = ref(false);
+const onOrderConfirmed = () => {
+  // console.log('订单已提交');
+};
+</script>
+
+<style lang="less" scoped>
+:deep(.van-checkbox__icon--square .van-icon) {
+  border-radius: 2px !important;
+}
+
+.trade-futures-container {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+  margin-bottom: 100px;
+  width: 100%;
+}
+
+/* --- 【新增】 头部行情的样式 --- */
+.menu {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+  /* 既然Layout底部给了margin,这里如果不想要间距可以调整,或者保留 */
+  /* margin-top: 21px; */
+  width: 345px;
+  height: 24px;
+
+  .menu-left {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-start;
+    align-items: center;
+    line-height: 0px;
+
+    img {
+      margin: 0px 10px 0 0;
+    }
+  }
+
+  .menu-right {
+    img {
+      margin-left: 14px;
+    }
+  }
+}
+
+.menu-bottom {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+  margin-top: 8px;
+  width: 345px;
+
+  .menu-leftb {
+    width: 61px;
+    height: 25px;
+    background-color: #45b26b;
+    border-radius: 5px;
+    color: #ffffff;
+    text-align: center;
+    line-height: 25px;
+  }
+
+  .menu-rightb {
+    text-align: right;
+  }
+}
+/* --- 【新增】 头部样式结束 --- */
+
+.menu-content {
+    width: 100%;
+    max-width: 345px;
+    display: flex;
+    flex-direction: row;
+    margin-top: 8px;
+
+    .menu-content-l {
+      flex: 1;
+
+      .menu-content-lb {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        padding-right: 14px;
+      }
+
+      .menu-content-lb1 {
+        margin-top: 11px;
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        padding-right: 14px;
+
+        .menu-content-lb1l {
+          display: flex;
+          flex-direction: column;
+          line-height: 22px;
+        }
+
+        .menu-content-lb1r {
+          display: flex;
+          flex-direction: column;
+          line-height: 22px;
+        }
+      }
+
+      .menu-content-lb1:nth-child(4) {
+        .menu-content-lb1l {
+          color: #45b26b;
+        }
+      }
+
+      .menu-content-lb1:nth-child(5) {
+        .menu-content-lb1l {
+          width: 100%;
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          background-color: #f5f5f5;
+          border-radius: 6px;
+          height: 24px;
+          padding: 0 5px 0 13px;
+
+
+        }
+
+        .menu-content-lb1r {
+          margin-left: 15px;
+        }
+      }
+
+      .menu-content-lb2 {
+        margin-top: 8px;
+        line-height: 16px;
+        //span:nth-child(2){
+        //  //border-style: dashed;
+        //}
+      }
+    }
+
+    .menu-content-r {
+      flex: 1;
+      flex-basis: 63.5px;
+      max-width: 204.25px;
+
+      .menu-content-rb:nth-of-type(4) {
+        background-color: transparent;
+        height: 20px;
+
+      }
+
+      .menu-content-rb {
+        width: 100%;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        background-color: #f5f5f5;
+        border-radius: 6px;
+        margin-bottom: 8px;
+        height: 38px;
+
+        span {
+          padding-right: 12px;
+
+        }
+
+        img {
+          padding-right: 12px;
+          //height: 16px;
+          //width: 16px;
+        }
+
+        .menu-content-rb1 {
+          text-align: center;
+          margin-left: 12px;
+          display: flex;
+          align-content: center;
+          justify-content: center;
+          align-items: center;
+
+          img {
+            padding-right: 6px;
+
+          }
+
+        }
+      }
+
+      .menu-content-rb:nth-of-type(6) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          margin-left: 0;
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(1) {
+
+            font-size: 12px;
+          }
+
+          span:nth-child(2) {
+            margin: 0 9px 0 9px;
+            font-size: 12px;
+          }
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(7) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          margin-left: 0;
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(2) {
+            margin: 0 9px 0 9px;
+            font-size: 12px;
+          }
+
+          span:nth-child(3) {
+            color: #df384c;
+          }
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(8) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          display: flex;
+          align-items: center;
+          height: 24px;
+          margin-left: 0;
+          align-content: center;
+
+          input {
+            width: 16px;
+            height: 16px;
+            margin-right: 5px;
+          }
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(2) {
+            margin: 0 9px 0 9px;
+          }
+        }
+
+        .menu-content-rb1s {
+          margin-left: 6px;
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(9) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          display: flex;
+          align-items: center;
+          height: 24px;
+          margin-left: 0;
+          align-content: center;
+
+          input {
+            width: 16px;
+            height: 16px;
+            margin-right: 5px;
+          }
+
+          img {
+            padding-left: 5px;
+            font-size: 16px;
+            padding-top: 2px;
+          }
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(2) {
+            margin: 0 9px 0 9px;
+          }
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(10) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          display: flex;
+          align-items: center;
+          height: 24px;
+          margin-left: 0;
+          align-content: center;
+
+          input {
+            width: 16px;
+            height: 16px;
+            margin-right: 5px;
+          }
+
+          img {
+            padding-left: 5px;
+            font-size: 16px;
+            padding-top: 2px;
+          }
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(2) {
+            margin: 0 0px 0 5px;
+          }
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(11) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          display: flex;
+          align-items: center;
+          height: 24px;
+          margin-left: 0;
+          align-content: center;
+
+          input {
+            width: 16px;
+            height: 16px;
+            margin-right: 5px;
+          }
+
+          img {
+            padding-left: 5px;
+            font-size: 16px;
+            padding-top: 2px;
+          }
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(2) {
+            margin: 0 0px 0 5px;
+          }
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(12) {
+        background-color: #45b26b;
+
+        div {
+          margin: auto;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(13) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          display: flex;
+          align-items: center;
+          height: 24px;
+          margin-left: 0;
+          align-content: center;
+
+          input {
+            width: 16px;
+            height: 16px;
+            margin-right: 5px;
+          }
+
+          img {
+            padding-left: 5px;
+            font-size: 16px;
+            padding-top: 2px;
+          }
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(2) {
+            margin: 0 0px 0 5px;
+          }
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(14) {
+        background-color: transparent;
+        height: 20px;
+
+        .menu-content-rb1 {
+          display: flex;
+          align-items: center;
+          height: 24px;
+          margin-left: 0;
+          align-content: center;
+
+          input {
+            width: 16px;
+            height: 16px;
+            margin-right: 5px;
+          }
+
+          img {
+            padding-left: 5px;
+            font-size: 16px;
+            padding-top: 2px;
+          }
+        }
+
+        .menu-content-rb1:nth-child(2) {
+          span:nth-child(2) {
+            margin: 0 0px 0 5px;
+          }
+        }
+
+        span {
+          padding-right: 0;
+        }
+
+        img {
+          padding-right: 0;
+        }
+
+      }
+
+      .menu-content-rb:nth-of-type(15) {
+        background-color: #df384c;
+
+        div {
+          margin: auto;
+        }
+
+      }
+
+      //.van-dropdown-menu__bar{
+      //  width: 214px;
+      //}
+
+    }
+  }
+
+</style>

+ 113 - 0
src/views/bitcoin/TradeLayout.vue

@@ -0,0 +1,113 @@
+<template>
+  <div class="market-layout">
+    <div class="market-nav">
+      <div class="nav-left">
+        <div
+          class="nav-item pf600"
+          :class="isCurrent('TradeContract') ? 'fs18 fc121212' : 'fs14 fcA8A8A8'"
+          @click="switchTab('TradeContract')"
+        >
+          合约
+          <div v-if="isCurrent('TradeContract')" class="active-line"></div>
+        </div>
+
+        <div
+          class="nav-item pf600 sys-notifi"
+          :class="isCurrent('TradeSeconds') ? 'fs18 fc121212' : 'fs14 fcA8A8A8'"
+          @click="switchTab('TradeSeconds')"
+        >
+          秒合约
+          <div v-if="isCurrent('TradeSeconds')" class="active-line"></div>
+        </div>
+
+        <div
+          class="nav-item pf600 sys-notifi"
+          :class="isCurrent('TradeOptions') ? 'fs18 fc121212' : 'fs14 fcA8A8A8'"
+          @click="switchTab('TradeOptions')"
+        >
+          期权
+          <div v-if="isCurrent('TradeOptions')" class="active-line"></div>
+        </div>
+
+        <div
+          class="nav-item pf600 sys-notifi"
+          :class="isCurrent('TradeMargin') ? 'fs18 fc121212' : 'fs14 fcA8A8A8'"
+          @click="switchTab('TradeMargin')"
+        >
+          杠杆
+          <div v-if="isCurrent('TradeMargin')" class="active-line"></div>
+        </div>
+      </div>
+    </div>
+
+    <router-view></router-view>
+  </div>
+</template>
+
+<script setup>
+import { useRouter, useRoute } from 'vue-router';
+
+const router = useRouter();
+const route = useRoute();
+
+const switchTab = (name) => {
+  router.push({ name });
+};
+
+const isCurrent = (name) => {
+  return route.name === name;
+};
+</script>
+
+<style lang="less" scoped>
+.market-layout {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+  width: 100%;
+
+  /* 确保导航栏样式正常 */
+  .market-nav {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-top: 21px;
+    width: 345px;
+    height: 24px;
+    /* 既然只放Tabs,可能需要一点底部间距,以免紧贴着下面的内容 */
+    margin-bottom: 18px;
+
+    .nav-left {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: flex-end;
+      width: 349px;
+      height: 24px;
+
+      .nav-item {
+        position: relative;
+        cursor: pointer;
+        transition: all 0.2s;
+
+        .active-line {
+          position: absolute;
+          bottom: -6px;
+          left: 50%;
+          transform: translateX(-50%);
+          width: 20px;
+          height: 3px;
+          background-color: #323233;
+          border-radius: 2px;
+        }
+      }
+
+      .sys-notifi {
+        margin-left: 35px;
+      }
+    }
+  }
+}
+</style>

+ 11 - 0
src/views/bitcoin/TradeOptions.vue

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

+ 1 - 1
src/views/bitcoin/components/position.vue

@@ -376,7 +376,7 @@
 .container {
   background-color: #fff;
   //min-height: 100vh;
-  padding: 15px;
+  padding: 15px 15px;
   font-family: sans-serif;
 }
 

+ 6 - 3
src/views/bitcoin/components/sellOrder.vue

@@ -43,7 +43,7 @@
 
     // 当前选中的 Tab,默认选中 index 1 (当前委托)
     const currentTab = ref(0);
-    const tabs = ['持有仓位(2)', '当前委托(2)'];
+    const tabs = ['持有仓位(0)', '当前委托(2)'];
 
     // 按钮操作
     const handleCancel = (id) => {
@@ -78,8 +78,10 @@
           <img src="../../../assets/icon/bitcoin/shizhong.svg" alt=""> 全部</span>
       </div>
     </div>
-    <position v-if="currentTab==0"></position>
-
+    <position v-if="currentTab==0.9"></position>
+    <div >
+      <assetlessState v-if="isassetlessState"></assetlessState>
+    </div>
     <div v-if="currentTab==1" class="order-list">
       <div
           v-for="item in orders"
@@ -148,6 +150,7 @@
       </div>
     </div>
 
+
   </div>
 </template>
 

+ 367 - 0
src/views/bitcoin/lever/TradeMargin.vue

@@ -0,0 +1,367 @@
+<template>
+  <div class="page-container">
+    <header class="header">
+      <div class="left" style="display: flex; align-items: center;">
+        <img class="fc333333" src="@/assets/icon/bitcoin/menu.svg" alt="">
+        <h1 class="title">BTCUSDT</h1>
+      </div>
+      <div class="right">
+        <img src="@/assets/icon/bitcoin/den.svg" alt="" @click="showFunctions = true">
+      </div>
+    </header>
+
+    <section class="market-info">
+      <div class="price-block">
+        <div class="fs16" style="margin-bottom: 2px;">实时价格</div>
+        <div class="current-price">1,125,158.00</div>
+        <div class="sub-info ">
+          <span class="fiat fs14 ">≈35,458.00</span>
+          <span class="percent up fs14">+1.42%</span>
+        </div>
+      </div>
+
+      <div class="stat-grid">
+        <div class="stat-item">
+          <span class="label">24h 最高价</span>
+          <span class="value">78,776.76</span>
+        </div>
+        <div class="stat-item">
+          <span class="label">24h 成交量 (BTC)</span>
+          <span class="value">78,776.76</span>
+        </div>
+        <div class="stat-item">
+          <span class="label">24h 最低价</span>
+          <span class="value">78,776.76</span>
+        </div>
+        <div class="stat-item">
+          <span class="label">24h 成交额 (BTC)</span>
+          <span class="value">78,776.76</span>
+        </div>
+      </div>
+    </section>
+
+    <nav class="time-tabs">
+      <div
+        v-for="tab in tabs"
+        :key="tab"
+        class="tab-item"
+        :class="{ active: currentTab === tab }"
+        @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="chart-wrapper">
+      <div id="k-line-chart" class="kline-container"></div>
+    </div>
+    <MarketPriceAndPlan></MarketPriceAndPlan>
+    <div style="margin-bottom: 20px">
+      <sellOrder  ></sellOrder>
+    </div>
+
+  </div>
+</template>
+
+<script setup>
+import { onMounted, onUnmounted, ref } from 'vue'
+// ✅ 使用 namespace 引入,防止报错
+import * as klinecharts from 'klinecharts'
+import MarketPriceAndPlan from'./components/MarketPriceAndPlan.vue'
+import sellOrder from '@/views/bitcoin/components/sellOrder.vue';
+
+
+// --- 状态管理 ---
+const currentTab = ref('24h')
+const tabs = ['1h', '6h', '24h', '1w', '1m']
+let chartInstance = null
+
+// --- 数据生成逻辑 ---
+const generateData = (baseVal = 3812.74) => {
+  const data = []
+  let baseTime = new Date().getTime()
+  let basePrice = baseVal
+  for (let i = 0; i < 80; i++) {
+    const change = (Math.random() - 0.5) * 30
+    const close = basePrice + change
+    const open = basePrice + (Math.random() - 0.5) * 10
+    const high = Math.max(open, close) + Math.random() * 10
+    const low = Math.min(open, close) - Math.random() * 10
+    const volume = Math.random() * 100 + 50
+
+    data.push({ timestamp: baseTime, open, high, low, close, volume })
+    baseTime += 60 * 60 * 1000 // 1h 间隔
+    basePrice = close + (Math.random() * 2) // 稍微向上的趋势
+  }
+  return data
+}
+
+// --- 切换周期逻辑 ---
+const switchPeriod = (period) => {
+  currentTab.value = period
+  if (chartInstance) {
+    // 模拟数据刷新
+    const randomStart = 3800 + Math.random() * 100
+    chartInstance.applyNewData(generateData(randomStart))
+  }
+}
+
+// --- 初始化与配置 ---
+onMounted(() => {
+  const chartDOM = document.getElementById('k-line-chart')
+  if (!chartDOM) return
+
+  // 1. 初始化图表
+  chartInstance = klinecharts.init(chartDOM)
+  if (!chartInstance) return
+
+  // 2. 样式常量
+  const targetBlue = '#4A6EF5' // 截图中的蓝色虚线颜色
+  const gridColor = '#F2F4F6'  // 极淡的网格线
+  const textColor = '#929AA5'  // 灰色文字
+
+  // 3. 核心配置 (setStyleOptions)
+  chartInstance.setStyleOptions({
+    grid: {
+      show: true,
+      horizontal: {
+        show: true,
+        size: 1,
+        color: gridColor,
+        style: 'dash',
+        dashValue: [5, 5]
+      },
+      vertical: { show: false }
+    },
+    candle: {
+      type: 'candle_solid',
+      bar: {
+        upColor: '#2EBD85',
+        downColor: '#F6465D',
+        noChangeColor: '#2EBD85'
+      },
+      // ✅ 重点:蓝色价格指示线配置
+      priceMark: {
+        show: true,
+        high: { show: false },
+        low: { show: false },
+        last: {
+          show: true,
+          // 强制无论涨跌都显示蓝色
+          upColor: targetBlue,
+          downColor: targetBlue,
+          line: { show: true, style: 'dash', dashValue: [4, 3] },
+          text: {
+            show: true,
+            color: '#FFFFFF',
+            size: 11,
+            paddingLeft: 4,
+            paddingRight: 4,
+            borderRadius: 2
+          }
+        }
+      },
+      tooltip: {
+        // 只有按压时才显示十字光标
+        showRule: 'follow_cross',
+        showType: 'rect',
+        dataSource: 'none', // 隐藏浮层数据,保持清爽
+        crosshair: {
+          show: true,
+          horizontal: { line: { style: 'dash', color: textColor } },
+          vertical: { line: { style: 'dash', color: textColor } }
+        }
+      }
+    },
+    // ✅ 重点:技术指标(VOL)颜色
+    technicalIndicator: {
+      bar: {
+        upColor: '#2EBD85',
+        downColor: '#F6465D',
+        noChangeColor: '#2EBD85'
+      }
+    },
+    // ✅ 重点:隐藏坐标轴线,只保留文字
+    xAxis: {
+      axisLine: { show: false },
+      tickLine: { show: false },
+      tickText: { color: textColor, size: 10, paddingTop: 8 }
+    },
+    yAxis: {
+      type: 'normal',
+      position: 'right',
+      inside: true,
+      axisLine: { show: false },
+      tickLine: { show: false },
+      tickText: { color: textColor, size: 10, paddingLeft: 8 }
+    },
+    separator: { size: 0 } // 去掉指标和K线之间的分割线
+  })
+
+  // 4. 创建副图指标 (VOL)
+  chartInstance.createTechnicalIndicator('VOL', false, { id: 'pane_1', heightRatio: 0.2 })
+
+  // 5. 加载数据并设置缩放
+  chartInstance.applyNewData(generateData())
+  if (chartInstance.setDataSpace) {
+  chartInstance.setDataSpace(7)
+}
+  // chartInstance.setBarSpace(7) // 设置蜡烛宽度
+})
+
+onUnmounted(() => {
+  if (chartInstance) {
+    klinecharts.dispose('k-line-chart')
+  }
+})
+</script>
+
+<style scoped>
+/* --- 布局容器 --- */
+.page-container {
+  width: 100%;
+  max-width: 375px;
+  margin: 0 auto;
+  background-color: #fff;
+  /* 使用系统字体,还原原生质感 */
+  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto, Arial, sans-serif;
+  color: #333;
+  /* 防止横向滚动条 */
+  overflow-x: hidden;
+}
+
+/* 🔥🔥 核心修改:定义一个公共的左右内边距
+   给 header, market-info, time-tabs, chart-wrapper 都加上
+*/
+.header,
+.market-info,
+.time-tabs,
+.chart-wrapper {
+  padding-left: 15px;
+  padding-right: 15px;
+  /* 关键:确保 padding 不会撑大 width: 100% */
+  box-sizing: border-box;
+}
+
+/* --- 1. 头部 --- */
+.header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+ /* padding-top: 12px;*/
+  padding-bottom: 12px;
+}
+.title {
+  font-size: 18px;
+  font-weight: 600;
+  display: inline-block;
+  margin-left: 10px;
+}
+.icon-menu, .icon-more {
+  font-size: 18px;
+  cursor: pointer;
+}
+
+/* --- 2. 行情信息 --- */
+.market-info {
+  display: flex;
+  justify-content: space-between;
+  padding-bottom: 10px;
+}
+
+.price-block .current-price {
+  font-size: 20px;
+  font-weight: 600;
+  line-height: 1.2;
+  color: #111;
+  /* 稍微调整一下字间距,防止数字太紧 */
+  letter-spacing: -0.5px;
+}
+.sub-info {
+  font-size: 12px;
+  margin-top: 4px;
+  font-weight: 500;
+}
+.sub-info .fiat {
+  color: #999;
+  margin-right: 8px;
+}
+.sub-info .percent.up {
+  color: #2EBD85;
+}
+
+/* 统计网格 */
+.stat-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr; /* 保持两列 */
+  column-gap: 12px;
+  row-gap: 6px;
+  text-align: right;
+
+}
+.stat-item {
+  display: flex;
+  flex-direction: column;
+
+}
+.stat-item .label {
+  font-size: 11px;
+  color: #999;
+  /* 稍微缩小字体 */
+  transform: scale(0.9);
+  transform-origin: right bottom;
+  white-space: nowrap; /* 防止文字换行 */
+}
+.stat-item .value {
+  font-size: 11px;
+  color: #333;
+  font-family: "DIN", -apple-system, sans-serif; /* 如果有数字字体更好 */
+}
+
+/* --- 3. Tabs --- */
+.time-tabs {
+  display: flex;
+  align-items: center;
+  /*gap: 5px;*/
+  justify-content: space-between;
+  /*//padding-top: 8px;*/
+  /*padding-bottom: 8px;*/
+  /* 你的截图中似乎没有底边框,这里保持干净 */
+}
+.tab-item {
+  font-size: 14px;
+  color: #929AA5;
+  padding: 4px 10px; /* 稍微减小内边距,适应 15px 的两侧挤压 */
+  border-radius: 6px;
+  cursor: pointer;
+  font-weight: 500;
+  transition: all 0.2s;
+}
+.tab-item.active {
+  background-color: #F6465D;
+  color: #fff;
+}
+.tab-item.icon {
+  color: #929AA5;
+  font-size: 12px;
+}
+.triangle {
+  font-size: 8px;
+}
+
+/* --- 4. 图表容器 --- */
+.chart-wrapper {
+  width: 100%;
+  height: 275px;
+  /*margin-top: 5px;*/
+  /* 🔥 这里加了 padding 后,K线图就会自动往里缩,左右留出白边 */
+}
+.kline-container {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 368 - 0
src/views/bitcoin/lever/TradeSeconds.vue

@@ -0,0 +1,368 @@
+<template>
+  <div class="page-container">
+    <header class="header">
+      <div class="left" style="display: flex; align-items: center;">
+        <img class="fc333333" src="@/assets/icon/bitcoin/menu.svg" alt="">
+        <h1 class="title">BTCUSDT</h1>
+      </div>
+      <div class="right">
+        <img src="@/assets/icon/bitcoin/den.svg" alt="" @click="showFunctions = true">
+      </div>
+    </header>
+
+    <section class="market-info">
+      <div class="price-block">
+        <div class="fs16" style="margin-bottom: 2px;">实时价格</div>
+        <div class="current-price">1,125,158.00</div>
+        <div class="sub-info ">
+          <span class="fiat fs14 ">≈35,458.00</span>
+          <span class="percent up fs14">+1.42%</span>
+        </div>
+      </div>
+
+      <div class="stat-grid">
+        <div class="stat-item">
+          <span class="label">24h 最高价</span>
+          <span class="value">78,776.76</span>
+        </div>
+        <div class="stat-item">
+          <span class="label">24h 成交量 (BTC)</span>
+          <span class="value">78,776.76</span>
+        </div>
+        <div class="stat-item">
+          <span class="label">24h 最低价</span>
+          <span class="value">78,776.76</span>
+        </div>
+        <div class="stat-item">
+          <span class="label">24h 成交额 (BTC)</span>
+          <span class="value">78,776.76</span>
+        </div>
+      </div>
+    </section>
+
+    <nav class="time-tabs">
+      <div
+        v-for="tab in tabs"
+        :key="tab"
+        class="tab-item"
+        :class="{ active: currentTab === tab }"
+        @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="chart-wrapper">
+      <div id="k-line-chart" class="kline-container"></div>
+    </div>
+    <ChooseThisCycle></ChooseThisCycle>
+<!--    <MarketPriceAndPlan></MarketPriceAndPlan>-->
+    <div style="margin-bottom: 20px">
+      <sellOrder  ></sellOrder>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, onUnmounted, ref } from 'vue'
+// ✅ 使用 namespace 引入,防止报错
+import * as klinecharts from 'klinecharts'
+import MarketPriceAndPlan from'./components/MarketPriceAndPlan.vue'
+import ChooseThisCycle from'./components/ChooseThisCycle.vue'
+import sellOrder from '@/views/bitcoin/components/sellOrder.vue';
+
+
+// --- 状态管理 ---
+const currentTab = ref('24h')
+const tabs = ['1h', '6h', '24h', '1w', '1m']
+let chartInstance = null
+
+// --- 数据生成逻辑 ---
+const generateData = (baseVal = 3812.74) => {
+  const data = []
+  let baseTime = new Date().getTime()
+  let basePrice = baseVal
+  for (let i = 0; i < 80; i++) {
+    const change = (Math.random() - 0.5) * 30
+    const close = basePrice + change
+    const open = basePrice + (Math.random() - 0.5) * 10
+    const high = Math.max(open, close) + Math.random() * 10
+    const low = Math.min(open, close) - Math.random() * 10
+    const volume = Math.random() * 100 + 50
+
+    data.push({ timestamp: baseTime, open, high, low, close, volume })
+    baseTime += 60 * 60 * 1000 // 1h 间隔
+    basePrice = close + (Math.random() * 2) // 稍微向上的趋势
+  }
+  return data
+}
+
+// --- 切换周期逻辑 ---
+const switchPeriod = (period) => {
+  currentTab.value = period
+  if (chartInstance) {
+    // 模拟数据刷新
+    const randomStart = 3800 + Math.random() * 100
+    chartInstance.applyNewData(generateData(randomStart))
+  }
+}
+
+// --- 初始化与配置 ---
+onMounted(() => {
+  const chartDOM = document.getElementById('k-line-chart')
+  if (!chartDOM) return
+
+  // 1. 初始化图表
+  chartInstance = klinecharts.init(chartDOM)
+  if (!chartInstance) return
+
+  // 2. 样式常量
+  const targetBlue = '#4A6EF5' // 截图中的蓝色虚线颜色
+  const gridColor = '#F2F4F6'  // 极淡的网格线
+  const textColor = '#929AA5'  // 灰色文字
+
+  // 3. 核心配置 (setStyleOptions)
+  chartInstance.setStyleOptions({
+    grid: {
+      show: true,
+      horizontal: {
+        show: true,
+        size: 1,
+        color: gridColor,
+        style: 'dash',
+        dashValue: [5, 5]
+      },
+      vertical: { show: false }
+    },
+    candle: {
+      type: 'candle_solid',
+      bar: {
+        upColor: '#2EBD85',
+        downColor: '#F6465D',
+        noChangeColor: '#2EBD85'
+      },
+      // ✅ 重点:蓝色价格指示线配置
+      priceMark: {
+        show: true,
+        high: { show: false },
+        low: { show: false },
+        last: {
+          show: true,
+          // 强制无论涨跌都显示蓝色
+          upColor: targetBlue,
+          downColor: targetBlue,
+          line: { show: true, style: 'dash', dashValue: [4, 3] },
+          text: {
+            show: true,
+            color: '#FFFFFF',
+            size: 11,
+            paddingLeft: 4,
+            paddingRight: 4,
+            borderRadius: 2
+          }
+        }
+      },
+      tooltip: {
+        // 只有按压时才显示十字光标
+        showRule: 'follow_cross',
+        showType: 'rect',
+        dataSource: 'none', // 隐藏浮层数据,保持清爽
+        crosshair: {
+          show: true,
+          horizontal: { line: { style: 'dash', color: textColor } },
+          vertical: { line: { style: 'dash', color: textColor } }
+        }
+      }
+    },
+    // ✅ 重点:技术指标(VOL)颜色
+    technicalIndicator: {
+      bar: {
+        upColor: '#2EBD85',
+        downColor: '#F6465D',
+        noChangeColor: '#2EBD85'
+      }
+    },
+    // ✅ 重点:隐藏坐标轴线,只保留文字
+    xAxis: {
+      axisLine: { show: false },
+      tickLine: { show: false },
+      tickText: { color: textColor, size: 10, paddingTop: 8 }
+    },
+    yAxis: {
+      type: 'normal',
+      position: 'right',
+      inside: true,
+      axisLine: { show: false },
+      tickLine: { show: false },
+      tickText: { color: textColor, size: 10, paddingLeft: 8 }
+    },
+    separator: { size: 0 } // 去掉指标和K线之间的分割线
+  })
+
+  // 4. 创建副图指标 (VOL)
+  chartInstance.createTechnicalIndicator('VOL', false, { id: 'pane_1', heightRatio: 0.2 })
+
+  // 5. 加载数据并设置缩放
+  chartInstance.applyNewData(generateData())
+  if (chartInstance.setDataSpace) {
+  chartInstance.setDataSpace(7)
+}
+  // chartInstance.setBarSpace(7) // 设置蜡烛宽度
+})
+
+onUnmounted(() => {
+  if (chartInstance) {
+    klinecharts.dispose('k-line-chart')
+  }
+})
+</script>
+
+<style scoped>
+/* --- 布局容器 --- */
+.page-container {
+  width: 100%;
+  max-width: 375px;
+  margin: 0 auto;
+  background-color: #fff;
+  /* 使用系统字体,还原原生质感 */
+  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto, Arial, sans-serif;
+  color: #333;
+  /* 防止横向滚动条 */
+  overflow-x: hidden;
+}
+
+/* 🔥🔥 核心修改:定义一个公共的左右内边距
+   给 header, market-info, time-tabs, chart-wrapper 都加上
+*/
+.header,
+.market-info,
+.time-tabs,
+.chart-wrapper {
+  padding-left: 15px;
+  padding-right: 15px;
+  /* 关键:确保 padding 不会撑大 width: 100% */
+  box-sizing: border-box;
+}
+
+/* --- 1. 头部 --- */
+.header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+ /* padding-top: 12px;*/
+  padding-bottom: 12px;
+}
+.title {
+  font-size: 18px;
+  font-weight: 600;
+  display: inline-block;
+  margin-left: 10px;
+}
+.icon-menu, .icon-more {
+  font-size: 18px;
+  cursor: pointer;
+}
+
+/* --- 2. 行情信息 --- */
+.market-info {
+  display: flex;
+  justify-content: space-between;
+  padding-bottom: 10px;
+}
+
+.price-block .current-price {
+  font-size: 20px;
+  font-weight: 600;
+  line-height: 1.2;
+  color: #111;
+  /* 稍微调整一下字间距,防止数字太紧 */
+  letter-spacing: -0.5px;
+}
+.sub-info {
+  font-size: 12px;
+  margin-top: 4px;
+  font-weight: 500;
+}
+.sub-info .fiat {
+  color: #999;
+  margin-right: 8px;
+}
+.sub-info .percent.up {
+  color: #2EBD85;
+}
+
+/* 统计网格 */
+.stat-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr; /* 保持两列 */
+  column-gap: 12px;
+  row-gap: 6px;
+  text-align: right;
+
+}
+.stat-item {
+  display: flex;
+  flex-direction: column;
+
+}
+.stat-item .label {
+  font-size: 11px;
+  color: #999;
+  /* 稍微缩小字体 */
+  transform: scale(0.9);
+  transform-origin: right bottom;
+  white-space: nowrap; /* 防止文字换行 */
+}
+.stat-item .value {
+  font-size: 11px;
+  color: #333;
+  font-family: "DIN", -apple-system, sans-serif; /* 如果有数字字体更好 */
+}
+
+/* --- 3. Tabs --- */
+.time-tabs {
+  display: flex;
+  align-items: center;
+  /*gap: 5px;*/
+  justify-content: space-between;
+  /*//padding-top: 8px;*/
+  /*padding-bottom: 8px;*/
+  /* 你的截图中似乎没有底边框,这里保持干净 */
+}
+.tab-item {
+  font-size: 14px;
+  color: #929AA5;
+  padding: 4px 10px; /* 稍微减小内边距,适应 15px 的两侧挤压 */
+  border-radius: 6px;
+  cursor: pointer;
+  font-weight: 500;
+  transition: all 0.2s;
+}
+.tab-item.active {
+  background-color: #F6465D;
+  color: #fff;
+}
+.tab-item.icon {
+  color: #929AA5;
+  font-size: 12px;
+}
+.triangle {
+  font-size: 8px;
+}
+
+/* --- 4. 图表容器 --- */
+.chart-wrapper {
+  width: 100%;
+  height: 275px;
+  /*margin-top: 5px;*/
+  /* 🔥 这里加了 padding 后,K线图就会自动往里缩,左右留出白边 */
+}
+.kline-container {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 272 - 0
src/views/bitcoin/lever/components/ChooseThisCycle.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="trade-panel">
+    <h3 class="section-title">选择周期</h3>
+
+    <div class="cycle-grid">
+      <div
+        v-for="(item, index) in cycles"
+        :key="index"
+        class="cycle-card"
+        :class="{ active: selectedCycleIndex === index }"
+        @click="selectedCycleIndex = index"
+      >
+        <div class="card-inner">
+          <div class="time">{{ item.time }}</div>
+          <div class="rate">{{ item.rate }}</div>
+        </div>
+      </div>
+    </div>
+
+    <div class="amount-input-box">
+      <span class="label">数量</span>
+      <div class="input-wrapper">
+        <input
+          type="number"
+          v-model="amount"
+          placeholder="请输入数量"
+        />
+        <span class="unit">USDT</span>
+      </div>
+    </div>
+
+    <div class="quick-amount-grid">
+      <div
+        v-for="val in quickAmounts"
+        :key="val"
+        class="amount-btn"
+        :class="{ active: Number(amount) === val }"
+        @click="amount = val"
+      >
+        {{ val }}
+      </div>
+    </div>
+
+    <div class="balance-row">
+      可用 215.0508 USDT <span class="wallet-icon"><img src="@/assets/icon/bitcoin/qianbao1.svg" alt="" class="fs12"></span>
+    </div>
+
+    <button class="buy-btn" @click="handleBuy">
+      购买
+    </button>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+// --- 数据配置 ---
+const selectedCycleIndex = ref(0)
+const amount = ref(1000) // 默认金额
+
+const cycles = [
+  { time: '20秒', rate: '12%' },
+  { time: '180秒', rate: '20%' },
+  { time: '360秒', rate: '30%' },
+  { time: '900秒', rate: '40%' },
+  { time: '1800秒', rate: '60%' },
+  { time: '3600秒', rate: '90%' },
+]
+
+const quickAmounts = [50, 100, 500, 1000, 10000, 50000, 100000]
+
+// --- 方法 ---
+const handleBuy = () => {
+  const cycle = cycles[selectedCycleIndex.value]
+  console.log(`下单: 周期=${cycle.time}, 金额=${amount.value}`)
+}
+</script>
+
+<style scoped>
+/* 基础容器配置 */
+.trade-panel {
+  width: 100%;
+  max-width: 375px; /* 设计稿宽度 */
+  margin: 0 auto;
+  padding: 15px;
+  box-sizing: border-box;
+  background-color: #fff;
+  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto, Arial, sans-serif;
+  color: #333;
+}
+
+/* 1. 标题 */
+.section-title {
+  font-size: 16px;
+  font-weight: 600;
+  margin: 0 0 12px 0;
+  color: #333;
+}
+
+/* 2. 周期选择网格 */
+.cycle-grid {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr); /* 4列等宽 */
+  gap: 8px;
+  margin-bottom: 20px;
+}
+
+.cycle-card {
+  /* 基础样式 (未选中) */
+  background-color: #F7F8FA;
+  border-radius: 6px;
+  overflow: hidden; /* 确保圆角生效 */
+  cursor: pointer;
+  text-align: center;
+  height: 64px;
+  display: flex;
+  flex-direction: column;
+  /* 预留边框位置,防止选中时跳动 */
+  border: 1px solid transparent;
+  box-sizing: border-box;
+}
+
+.card-inner {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  width: 100%;
+}
+
+.cycle-card .time {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 13px;
+  color: #666;
+  /* 未选中时上下背景色一致 */
+}
+
+.cycle-card .rate {
+  height: 26px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 12px;
+  color: #999;
+  background-color: rgba(0,0,0,0.02); /* 微微深一点的底色 */
+}
+
+/* 🔥 周期选中态 (核心还原) */
+.cycle-card.active {
+  border-color: #2979FF; /* 外部蓝色边框 */
+  background-color: #fff; /* 边框内的白色间隙(如果需要) */
+}
+
+.cycle-card.active .time {
+  background-color: #DC3545; /* 上半部分深红 */
+  color: #fff;
+  font-weight: 500;
+}
+
+.cycle-card.active .rate {
+  background-color: #F5848E; /* 下半部分浅红 */
+  color: #fff;
+}
+
+/* 3. 数量输入框 */
+.amount-input-box {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background-color: #F7F8FA;
+  height: 44px;
+  padding: 0 12px;
+  border-radius: 4px;
+  margin-bottom: 12px;
+}
+
+.amount-input-box .label {
+  font-size: 14px;
+  font-weight: 600;
+  color: #333;
+}
+
+.input-wrapper {
+  display: flex;
+  align-items: center;
+  flex: 1;
+  justify-content: flex-end;
+}
+
+.input-wrapper input {
+  border: none;
+  background: transparent;
+  outline: none;
+  text-align: right;
+  font-size: 14px;
+  color: #999; /* 这里模仿截图的灰色数字 1000 */
+  width: 100%;
+  padding-right: 6px;
+  font-family: inherit;
+}
+/* 聚焦时文字变黑 */
+.input-wrapper input:focus {
+  color: #333;
+}
+
+.input-wrapper .unit {
+  font-size: 14px;
+  color: #111;
+  font-weight: 500;
+}
+
+/* 4. 快捷金额网格 */
+.quick-amount-grid {
+  display: grid;
+  grid-template-columns: repeat(5, 1fr); /* 5列等宽 */
+  gap: 8px;
+  margin-bottom: 15px;
+}
+
+.amount-btn {
+  height: 32px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #F7F8FA;
+  border-radius: 4px;
+  font-size: 12px;
+  color: #333;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+/* 金额选中态 */
+.amount-btn.active {
+  background-color: #DC3545; /* 红色背景 */
+  color: #fff;
+}
+
+/* 5. 余额 */
+.balance-row {
+  font-size: 12px;
+  color: #333;
+  display: flex;
+  align-items: center;
+  margin-bottom: 15px;
+}
+.wallet-icon {
+  margin-left: 4px;
+  color: #DC3545;
+  font-size: 14px;
+}
+
+/* 6. 购买按钮 */
+.buy-btn {
+  width: 100%;
+  height: 40px;
+  background-color: #DC3545;
+  color: #fff;
+  border: none;
+  border-radius: 24px;
+  font-size: 16px;
+  font-weight: 500;
+  cursor: pointer;
+  box-shadow: 0 4px 10px rgba(220, 53, 69, 0.2);
+  margin: 0 auto;
+}
+.buy-btn:active {
+  opacity: 0.9;
+}
+</style>

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

@@ -0,0 +1,126 @@
+<template>
+  <div class="kline-wrapper">
+    <!-- 时间周期 -->
+    <div class="chart-header">
+      <div class="time-intervals">
+        <span class="active">15分</span>
+        <span>1小时</span>
+        <span>4小时</span>
+        <span>日线</span>
+      </div>
+    </div>
+
+    <div ref="chartContainer" class="chart-container"></div>
+
+    <!-- 指标切换 -->
+    <div class="chart-footer">
+      <span class="indicator-btn" @click="setMainIndicator('MA')">MA</span>
+      <span class="indicator-btn" @click="setMainIndicator('BOLL')">BOLL</span>
+      <span class="divider">|</span>
+      <span class="indicator-btn" @click="setSubIndicator('VOL')">VOL</span>
+      <span class="indicator-btn" @click="setSubIndicator('MACD')">MACD</span>
+      <span class="indicator-btn" @click="setSubIndicator('KDJ')">KDJ</span>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, onUnmounted, ref } from 'vue'
+import { init, dispose } from 'klinecharts'
+
+const chartContainer = ref(null)
+let chartObj = null
+
+// 生成 mock 数据
+function getMockDataList() {
+  const dataList = []
+  let ts = Date.now()
+  let price = 40000
+
+  for (let i = 0; i < 500; i++) {
+    const timestamp = ts - (500 - i) * 60 * 1000 * 15
+    const random = (Math.random() - 0.5) * 200
+    const open = price
+    const close = price + random
+    const high = Math.max(open, close) + Math.random() * 50
+    const low = Math.min(open, close) - Math.random() * 50
+    const volume = Math.random() * 1000 + 500
+
+    dataList.push({ timestamp, open, high, low, close, volume })
+    price = close
+  }
+
+  return dataList
+}
+
+onMounted(() => {
+  if (!chartContainer.value) {
+    console.error('找不到图表容器')
+    return
+  }
+
+  // 初始化 v8 图表
+  chartObj = init(chartContainer.value)
+
+  console.log('chartObj 实例:', chartObj)
+
+  if (!chartObj) {
+    console.error('图表初始化失败')
+    return
+  }
+
+  // 设置主图 & 副图指标(v8 用 createIndicator)
+  chartObj.createIndicator('MA', false, { id: 'candle_pane' })
+  chartObj.createIndicator('VOL', false, { id: 'pane_1' })
+
+  // v8 的方法是 applyNewData(不是 applyData)
+  const data = getMockDataList()
+  chartObj.applyNewData(data)
+})
+
+onUnmounted(() => {
+  if (chartObj) dispose(chartContainer.value)
+})
+
+// 切换主图指标
+function setMainIndicator(name) {
+  chartObj.createIndicator(name, false, { id: 'candle_pane' })
+}
+
+// 切换副图指标
+function setSubIndicator(name) {
+  chartObj.createIndicator(name, false, { id: 'pane_1' })
+}
+</script>
+
+<style scoped>
+.kline-wrapper {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+}
+
+.chart-header, .chart-footer {
+  display: flex;
+  padding: 10px 15px;
+  background: #fff;
+}
+
+.time-intervals span, .indicator-btn {
+  font-size: 12px;
+  color: #666;
+  margin-right: 15px;
+  cursor: pointer;
+}
+
+.time-intervals span.active {
+  font-weight: bold;
+  color: #333;
+}
+
+.chart-container {
+  width: 100%;
+  height: 450px;
+  background: #fff;
+}
+</style>

+ 483 - 0
src/views/bitcoin/lever/components/MarketPriceAndPlan.vue

@@ -0,0 +1,483 @@
+<template>
+  <div class="trade-container">
+    <div class="trade-tabs">
+      <span
+        class="tab"
+        :class="{ active: tradeType === 'market' }"
+        @click="tradeType = 'market'"
+      >
+        市价
+      </span>
+      <span
+        class="tab"
+        :class="{ active: tradeType === 'plan' }"
+        @click="tradeType = 'plan'"
+      >
+        计划
+      </span>
+    </div>
+
+    <div v-if="tradeType === 'plan'" class="plan-price-input">
+      <input type="number" placeholder="请输入价格" />
+    </div>
+
+    <div class="section-container" :class="{ 'mt-20': tradeType === 'plan' }">
+      <div class="section-label" v-if="tradeType === 'market'">杠杆倍数</div>
+      <div class="grid-row">
+        <div
+          v-for="lev in leverages"
+          :key="lev"
+          class="tag-btn"
+          :class="{ active: currentLeverage === lev }"
+          @click="selectLeverage(lev)"
+        >
+          {{ lev }}X
+        </div>
+
+        <div class="tag-btn" @click="openLeverageModal">更多</div>
+      </div>
+    </div>
+
+    <div class="input-group" :class="{ focused: isInputFocused }">
+      <span class="prefix">本金</span>
+      <input
+        type="number"
+        placeholder="1000"
+        v-model="amount"
+        @focus="isInputFocused = true"
+        @blur="isInputFocused = false"
+      />
+      <span class="suffix">USDT</span>
+    </div>
+
+    <div class="grid-row mt-10">
+      <div
+        v-for="amt in quickAmounts"
+        :key="amt"
+        class="tag-btn light"
+        :class="{ active: Number(amount) === amt }"
+        @click="amount = amt"
+      >
+        {{ amt }}
+      </div>
+      <div class="tag-btn light">更多</div>
+    </div>
+
+    <div class="balance-row">
+      可用 215.0508 USDT <span class="wallet-icon"><img src="@/assets/icon/bitcoin/qianbao1.svg" alt=""></span>
+    </div>
+
+    <div class="action-buttons">
+      <button class="btn-long">
+        <div class="main-text">买入(做多)</div>
+        <div class="sub-text">预计开仓 0.008 BTC</div>
+      </button>
+      <button class="btn-short">
+        <div class="main-text">卖出(做空)</div>
+        <div class="sub-text">预计开仓 0.008 BTC</div>
+      </button>
+    </div>
+
+    <sellOrder v-bind:tradeType="'plan'" ></sellOrder>
+
+    <div >
+      <assetlessState v-if="isassetlessState"></assetlessState>
+    </div>
+
+    <div v-if="showModal" class="modal-mask" @click="showModal = false">
+      <div class="modal-content" @click.stop>
+        <div class="drag-handle"></div>
+        <h3 class="modal-title">调整保证金</h3>
+
+        <div class="stepper-box">
+          <button class="step-btn" @click="adjustIndex(-1)">—</button>
+          <div class="step-value">{{ leverageMarks[sliderIndex] }}x</div>
+          <button class="step-btn" @click="adjustIndex(1)">+</button>
+        </div>
+
+        <div class="slider-container">
+          <div class="start-marker"></div>
+
+          <input
+            type="range"
+            min="0"
+            :max="leverageMarks.length - 1"
+            step="1"
+            v-model="sliderIndex"
+            class="custom-range"
+            :style="sliderStyle"
+          />
+
+          <div class="slider-marks">
+            <span
+              v-for="(mark, index) in leverageMarks"
+              :key="mark"
+              :class="{ active: index === Number(sliderIndex) }"
+            >
+              {{ mark }}
+            </span>
+          </div>
+        </div>
+
+        <button class="confirm-btn" @click="confirmLeverage">确认</button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import {ref, computed, defineAsyncComponent} from 'vue'
+
+const assetlessState = defineAsyncComponent(() => import("@/views/bitcoin/components/assetlessState.vue"));
+
+
+// --- 状态管理 ---
+const tradeType = ref('market')
+const currentLeverage = ref(50) // 当前实际生效的杠杆
+const amount = ref('')
+const isInputFocused = ref(false)
+const showModal = ref(false)
+
+// 首页显示的固定选项
+const leverages = [20, 50, 100, 1000]
+// 快捷金额
+const quickAmounts = [50, 100, 500, 1000]
+
+// 🔥🔥 修改点3:弹窗内的固定阶梯数组 (1, 50, 100, 500, 1000)
+const leverageMarks = [1, 50, 100, 500, 1000]
+
+// 弹窗内的滑块索引 (0 ~ 4)
+const sliderIndex = ref(0)
+
+// --- 方法 ---
+
+// 1. 直接选择杠杆 (不弹窗)
+const selectLeverage = (val) => {
+  currentLeverage.value = val
+}
+
+// 2. 打开更多弹窗
+const openLeverageModal = () => {
+  // 尝试在阶梯数组中找到当前杠杆的位置
+  const idx = leverageMarks.indexOf(currentLeverage.value)
+
+  // 如果当前杠杆(比如20x)不在弹窗数组里,默认让滑块停在第1个(索引0,即1x)或者第2个
+  // 这里逻辑设定为:如果找不到,就默认归零
+  sliderIndex.value = idx !== -1 ? idx : 0
+
+  showModal.value = true
+}
+
+// 步进器调整
+const adjustIndex = (delta) => {
+  let newIndex = Number(sliderIndex.value) + delta
+  if (newIndex < 0) newIndex = 0
+  if (newIndex > leverageMarks.length - 1) newIndex = leverageMarks.length - 1
+  sliderIndex.value = newIndex
+}
+
+// 确认选择
+const confirmLeverage = () => {
+  currentLeverage.value = leverageMarks[sliderIndex.value]
+  showModal.value = false
+}
+
+// 进度条背景颜色计算
+const sliderStyle = computed(() => {
+  const maxIndex = leverageMarks.length - 1
+  const val = Number(sliderIndex.value)
+  const percentage = (val / maxIndex) * 100
+  return {
+    background: `linear-gradient(to right, #F6465D 0%, #F6465D ${percentage}%, #F2F4F6 ${percentage}%, #F2F4F6 100%)`
+  }
+})
+</script>
+
+<style scoped>
+/* 样式部分保持不变,直接复用之前的 CSS 即可 */
+/* 全局容器配置 */
+.trade-container {
+  width: 100%;
+  max-width: 375px;
+  margin: 0 auto;
+  padding: 15px;
+  box-sizing: border-box;
+  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto, sans-serif;
+  color: #333;
+  background-color: #fff;
+  position: relative;
+}
+
+/* Tabs */
+.trade-tabs {
+  display: flex;
+  gap: 20px;
+  margin-bottom: 15px;
+}
+.tab {
+  font-size: 16px;
+  color: #999;
+  font-weight: 500;
+  cursor: pointer;
+  padding-bottom: 4px;
+  transition: all 0.2s;
+}
+.tab.active {
+  color: #111;
+  font-weight: 600;
+}
+
+/* 计划委托输入框 */
+.plan-price-input {
+  width: 100%;
+  height: 44px;
+  background-color: #F7F8FA;
+  border-radius: 4px;
+  display: flex;
+  align-items: center;
+  padding: 0 12px;
+  box-sizing: border-box;
+  margin-bottom: 12px;
+}
+.plan-price-input input {
+  width: 100%;
+  border: none;
+  background: transparent;
+  outline: none;
+  font-size: 14px;
+  color: #333;
+}
+
+/* 间距与布局 */
+.mt-20 { margin-top: 12px; }
+.mt-10 { margin-top: 10px; }
+.section-label {
+  font-size: 12px;
+  color: #999;
+  margin-bottom: 8px;
+}
+.grid-row {
+  display: grid;
+  grid-template-columns: repeat(5, 1fr);
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+/* 按钮样式 */
+.tag-btn {
+  height: 32px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #F7F8FA;
+  border-radius: 4px;
+  font-size: 12px;
+  color: #333;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+.tag-btn.active {
+  background-color: #F6465D !important;
+  color: #fff !important;
+  font-weight: 500;
+}
+.tag-btn.light {
+  background-color: #F7F8FA;
+  color: #333;
+}
+
+/* 输入框组 */
+.input-group {
+  display: flex;
+  align-items: center;
+  height: 44px;
+  background-color: #F7F8FA;
+  border-radius: 4px;
+  padding: 0 12px;
+  border: 1px solid transparent;
+  transition: all 0.2s;
+}
+.input-group.focused {
+  background-color: #fff;
+  border-color: #2979FF;
+  box-shadow: 0 0 0 1px rgba(41, 121, 255, 0.1);
+}
+.prefix, .suffix { font-size: 14px; color: #111; font-weight: 500; }
+.suffix { font-size: 12px; }
+.input-group input {
+  flex: 1;
+  border: none;
+  background: transparent;
+  outline: none;
+  text-align: right;
+  padding: 0 10px;
+  font-size: 14px;
+  color: #333;
+}
+
+/* 余额与操作按钮 */
+.balance-row {
+  margin-top: 15px;
+  font-size: 12px;
+  color: #666;
+  display: flex;
+  align-items: center;
+}
+.wallet-icon { margin-left: 4px; color: #F6465D; }
+
+.action-buttons { display: flex; gap: 12px; margin-top: 15px; }
+.btn-long, .btn-short {
+  flex: 1;
+  border: none;
+  height: 60px;
+  border-radius: 6px;
+  color: #fff;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+}
+.btn-long { background-color: #2EBD85; }
+.btn-short { background-color: #F6465D; }
+.main-text { font-size: 16px; font-weight: 600; margin-bottom: 2px; }
+.sub-text { font-size: 10px; opacity: 0.9; font-weight: 400; }
+
+/* Modal 弹窗 */
+.modal-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  background-color: rgba(0, 0, 0, 0.4);
+  z-index: 999;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-end;
+}
+.modal-content {
+  background-color: #fff;
+  width: 100%;
+  max-width: 375px;
+  margin: 0 auto;
+  border-radius: 16px 16px 0 0;
+  padding: 10px 20px 30px;
+  box-sizing: border-box;
+  animation: slideUp 0.3s ease-out;
+}
+@keyframes slideUp {
+  from { transform: translateY(100%); }
+  to { transform: translateY(0); }
+}
+.drag-handle {
+  width: 40px;
+  height: 4px;
+  background-color: #E0E0E0;
+  border-radius: 2px;
+  margin: 0 auto 15px;
+}
+.modal-title {
+  font-size: 16px;
+  font-weight: 600;
+  margin-bottom: 20px;
+}
+
+/* 步进器 */
+.stepper-box {
+  display: flex;
+  align-items: center;
+  background-color: #F7F8FA;
+  border-radius: 8px;
+  height: 48px;
+  margin-bottom: 30px;
+}
+.step-btn {
+  width: 60px;
+  height: 100%;
+  border: none;
+  background: transparent;
+  font-size: 24px;
+  color: #999;
+  cursor: pointer;
+}
+.step-value {
+  flex: 1;
+  text-align: center;
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+}
+
+/* Slider 容器与样式 */
+.slider-container {
+  position: relative;
+  margin-bottom: 40px;
+  padding: 0 12px;
+}
+
+/* 起始点的固定圆圈 */
+.start-marker {
+  position: absolute;
+  left: 12px;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 24px;
+  height: 24px;
+  background: #fff;
+  border: 2px solid #F6465D;
+  border-radius: 50%;
+  z-index: 1;
+  box-sizing: border-box;
+}
+
+.custom-range {
+  -webkit-appearance: none;
+  width: 100%;
+  height: 6px;
+  border-radius: 3px;
+  outline: none;
+  position: relative;
+  z-index: 2;
+  background: transparent;
+}
+
+.custom-range::-webkit-slider-thumb {
+  -webkit-appearance: none;
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  background: #fff;
+  border: 2px solid #F6465D;
+  cursor: pointer;
+  box-shadow: 0 2px 6px rgba(0,0,0,0.15);
+  margin-top: -1px;
+  box-sizing: border-box;
+}
+
+/* 刻度文字 */
+.slider-marks {
+  display: flex;
+  justify-content: space-between;
+  margin-top: 10px;
+  color: #999;
+  font-size: 12px;
+}
+.slider-marks span.active {
+  color: #333;
+  font-weight: 600;
+}
+
+.confirm-btn {
+  width: 100%;
+  height: 48px;
+  background-color: #F6465D;
+  color: #fff;
+  border: none;
+  border-radius: 24px;
+  font-size: 16px;
+  font-weight: 600;
+  cursor: pointer;
+}
+</style>

+ 425 - 0
src/views/bitcoin/lever/yii.vue

@@ -0,0 +1,425 @@
+<template>
+  <div class="trade-container">
+    <div class="trade-tabs">
+      <span class="tab active">市价</span>
+      <span class="tab">计划</span>
+    </div>
+
+    <div class="section-label">杠杆倍数</div>
+    <div class="grid-row">
+      <div
+        v-for="lev in leverages"
+        :key="lev"
+        class="tag-btn"
+        :class="{ active: currentLeverage === lev }"
+        @click="selectLeverage(lev)"
+      >
+        {{ lev }}X
+      </div>
+      <div class="tag-btn" @click="showModal = true">更多</div>
+    </div>
+
+    <div class="input-group" :class="{ focused: isInputFocused }">
+      <span class="prefix">本金</span>
+      <input
+        type="number"
+        placeholder="请输入价格"
+        v-model="amount"
+        @focus="isInputFocused = true"
+        @blur="isInputFocused = false"
+      />
+      <span class="suffix">USDT</span>
+    </div>
+
+    <div class="grid-row mt-10">
+      <div
+        v-for="amt in quickAmounts"
+        :key="amt"
+        class="tag-btn light"
+        @click="amount = amt"
+      >
+        {{ amt }}
+      </div>
+      <div class="tag-btn light">更多</div>
+    </div>
+
+    <div class="balance-row">
+      可用 215.0508 USDT <span class="wallet-icon">👛</span>
+    </div>
+
+    <div class="action-buttons">
+      <button class="btn-long">
+        <div class="main-text">买入(做多)</div>
+        <div class="sub-text">预计开仓 0.008 BTC</div>
+      </button>
+      <button class="btn-short">
+        <div class="main-text">卖出(做空)</div>
+        <div class="sub-text">预计开仓 0.008 BTC</div>
+      </button>
+    </div>
+
+    <div v-if="showModal" class="modal-mask" @click="showModal = false">
+      <div class="modal-content" @click.stop>
+        <div class="drag-handle"></div>
+
+        <h3 class="modal-title">调整保证金</h3>
+
+        <div class="stepper-box">
+          <button class="step-btn" @click="adjustLeverage(-1)">—</button>
+          <div class="step-value">{{ tempLeverage }}x</div>
+          <button class="step-btn" @click="adjustLeverage(1)">+</button>
+        </div>
+
+        <div class="slider-container">
+          <input
+            type="range"
+            min="1"
+            max="1000"
+            v-model="tempLeverage"
+            class="custom-range"
+            :style="sliderStyle"
+          />
+          <div class="slider-marks">
+            <span>1</span>
+            <span>50</span>
+            <span>100</span>
+            <span>500</span>
+            <span>1000</span>
+          </div>
+        </div>
+
+        <button class="confirm-btn" @click="confirmLeverage">确认</button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue'
+
+// --- 状态管理 ---
+const currentLeverage = ref(50) // 当前选中的杠杆
+const tempLeverage = ref(20)    // 弹窗中临时的杠杆
+const amount = ref('')          // 输入金额
+const isInputFocused = ref(false)
+const showModal = ref(false)
+
+const leverages = [20, 50, 100, 1000]
+const quickAmounts = [50, 100, 500, 1000]
+
+// --- 方法 ---
+const selectLeverage = (val) => {
+  currentLeverage.value = val
+  tempLeverage.value = val // 同步到弹窗
+}
+
+const adjustLeverage = (delta) => {
+  let val = parseInt(tempLeverage.value) + delta
+  if (val < 1) val = 1
+  if (val > 1000) val = 1000
+  tempLeverage.value = val
+}
+
+const confirmLeverage = () => {
+  currentLeverage.value = tempLeverage.value
+  showModal.value = false
+}
+
+// --- 计算属性:动态生成 Slider 的红色进度条背景 ---
+const sliderStyle = computed(() => {
+  const min = 1
+  const max = 1000
+  const val = tempLeverage.value
+  // 计算百分比: (val - min) / (max - min) * 100
+  const percentage = ((val - min) / (max - min)) * 100
+  return {
+    background: `linear-gradient(to right, #F6465D 0%, #F6465D ${percentage}%, #F2F4F6 ${percentage}%, #F2F4F6 100%)`
+  }
+})
+</script>
+
+<style scoped>
+/* 全局容器配置 */
+.trade-container {
+  width: 100%;
+  max-width: 375px;
+  margin: 0 auto;
+  padding: 15px; /* 这里的 padding 对应之前要求的安全距离 */
+  box-sizing: border-box;
+  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Roboto, sans-serif;
+  color: #333;
+  background-color: #fff;
+  position: relative; /* 为弹窗定位做准备 */
+}
+
+/* 1. Tabs */
+.trade-tabs {
+  display: flex;
+  gap: 20px;
+  margin-bottom: 15px;
+}
+.tab {
+  font-size: 16px;
+  color: #999;
+  font-weight: 500;
+  cursor: pointer;
+}
+.tab.active {
+  color: #111;
+  font-weight: 600;
+}
+
+/* 2. Grid 按钮组 */
+.section-label {
+  font-size: 12px;
+  color: #999;
+  margin-bottom: 8px;
+}
+.grid-row {
+  display: grid;
+  grid-template-columns: repeat(5, 1fr); /* 5列等分 */
+  gap: 8px;
+  margin-bottom: 15px;
+}
+.mt-10 {
+  margin-top: 10px;
+}
+
+.tag-btn {
+  height: 32px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #F7F8FA;
+  border-radius: 4px;
+  font-size: 12px;
+  color: #333;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+/* 选中状态 - 红色 (还原图1) */
+.tag-btn.active {
+  background-color: #F6465D; /* 截图中的红 */
+  color: #fff;
+  font-weight: 500;
+}
+/* 浅色按钮 (还原图2下方的金额按钮) */
+.tag-btn.light {
+  background-color: #F7F8FA;
+  color: #333;
+}
+
+/* 3. 输入框组 (还原图2的蓝色边框) */
+.input-group {
+  display: flex;
+  align-items: center;
+  height: 44px;
+  background-color: #F7F8FA; /* 默认灰色背景 */
+  border-radius: 4px;
+  padding: 0 12px;
+  border: 1px solid transparent; /* 预留边框位置 */
+  transition: all 0.2s;
+}
+/* 聚焦时的样式 - 还原图2 */
+.input-group.focused {
+  background-color: #fff;
+  border-color: #2979FF; /* 截图中的亮蓝色 */
+  box-shadow: 0 0 0 1px rgba(41, 121, 255, 0.1); /* 可选:微弱的光晕 */
+}
+
+.prefix, .suffix {
+  font-size: 14px;
+  color: #111;
+  font-weight: 500;
+  white-space: nowrap;
+}
+.suffix {
+  font-size: 12px;
+}
+
+.input-group input {
+  flex: 1;
+  border: none;
+  background: transparent;
+  outline: none;
+  text-align: right;
+  padding: 0 10px;
+  font-size: 14px;
+  color: #333;
+}
+.input-group input::placeholder {
+  color: #CCC;
+  text-align: left; /* placeholder靠左,输入内容靠右 */
+}
+
+/* 5. 余额行 */
+.balance-row {
+  margin-top: 15px;
+  font-size: 12px;
+  color: #666;
+  display: flex;
+  align-items: center;
+}
+.wallet-icon {
+  margin-left: 4px;
+  color: #F6465D;
+}
+
+/* 6. 底部大按钮 */
+.action-buttons {
+  display: flex;
+  gap: 12px;
+  margin-top: 15px;
+}
+.btn-long, .btn-short {
+  flex: 1;
+  border: none;
+  height: 60px; /* 增加高度以容纳两行字 */
+  border-radius: 6px;
+  color: #fff;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+}
+.btn-long { background-color: #2EBD85; }
+.btn-short { background-color: #F6465D; }
+
+.main-text {
+  font-size: 16px;
+  font-weight: 600;
+  margin-bottom: 2px;
+}
+.sub-text {
+  font-size: 10px;
+  opacity: 0.9;
+  font-weight: 400;
+}
+
+/* ========================================= */
+/* 7. Modal 弹窗样式 (核心还原) */
+/* ========================================= */
+.modal-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  background-color: rgba(0, 0, 0, 0.4);
+  z-index: 999;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-end; /* 底部对齐 */
+}
+
+.modal-content {
+  background-color: #fff;
+  width: 100%;
+  max-width: 375px;
+  margin: 0 auto; /* 适配 PC 居中 */
+  border-radius: 16px 16px 0 0;
+  padding: 10px 20px 30px;
+  box-sizing: border-box;
+  animation: slideUp 0.3s ease-out;
+}
+
+@keyframes slideUp {
+  from { transform: translateY(100%); }
+  to { transform: translateY(0); }
+}
+
+.drag-handle {
+  width: 40px;
+  height: 4px;
+  background-color: #E0E0E0;
+  border-radius: 2px;
+  margin: 0 auto 15px;
+}
+
+.modal-title {
+  font-size: 16px;
+  font-weight: 600;
+  margin-bottom: 20px;
+}
+
+/* 步进器 */
+.stepper-box {
+  display: flex;
+  align-items: center;
+  background-color: #F7F8FA;
+  border-radius: 8px;
+  height: 48px;
+  margin-bottom: 30px;
+}
+.step-btn {
+  width: 60px;
+  height: 100%;
+  border: none;
+  background: transparent;
+  font-size: 24px;
+  color: #999;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.step-value {
+  flex: 1;
+  text-align: center;
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+}
+
+/* 自定义 Slider (核心难点) */
+.slider-container {
+  position: relative;
+  margin-bottom: 40px;
+  padding: 0 10px;
+}
+
+.custom-range {
+  -webkit-appearance: none;
+  width: 100%;
+  height: 6px;
+  border-radius: 3px;
+  outline: none;
+  /* 背景色通过 inline-style 动态设置渐变 */
+}
+
+/* 滑块样式 (Thumb) */
+.custom-range::-webkit-slider-thumb {
+  -webkit-appearance: none;
+  appearance: none;
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  background: #fff;
+  border: 2px solid #F6465D; /* 截图中的红圈白底滑块 */
+  cursor: pointer;
+  box-shadow: 0 2px 6px rgba(0,0,0,0.1);
+  margin-top: -1px; /* 微调对齐 */
+}
+
+/* 刻度标签 */
+.slider-marks {
+  display: flex;
+  justify-content: space-between;
+  margin-top: 10px;
+  color: #666;
+  font-size: 12px;
+}
+
+.confirm-btn {
+  width: 100%;
+  height: 48px;
+  background-color: #F6465D;
+  color: #fff;
+  border: none;
+  border-radius: 24px;
+  font-size: 16px;
+  font-weight: 600;
+  cursor: pointer;
+}
+</style>