Explorar o código

限价做多说明-完成
限价做空说明-完成
限价止盈止损说明 -完成
市价止盈止损说明-完成
市价说明-完成
目标价格-完成
收益-完成
强平价格-完成
可开-完成
开仓均价-完成
资金费用-完成

Hexinkui hai 1 mes
pai
achega
172464e16b

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 6 - 0
src/assets/icon/bitcoin/jisuanqicaidan.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
src/assets/icon/bitcoin/shijia.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
src/assets/icon/bitcoin/shijiazyzs.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2 - 0
src/assets/icon/bitcoin/xianjia.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2 - 0
src/assets/icon/bitcoin/xianjiak.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 22 - 0
src/assets/icon/bitcoin/xianjiazyzs.svg


+ 9 - 0
src/router/index.js

@@ -16,6 +16,7 @@ import LoanIndex from "../views/index/loan/Index.vue";
 import LoanRules from "../views/index/loan/Rules.vue";
 import LoanRules from "../views/index/loan/Rules.vue";
 import UserLoanIndex from "../views/user/loan/Index.vue";
 import UserLoanIndex from "../views/user/loan/Index.vue";
 import FootprintIndex from "../views/bitcoin/Index.vue";
 import FootprintIndex from "../views/bitcoin/Index.vue";
+import Calculator from '../views/bitcoin/Calculator.vue' // 新建的计算器页面
 
 
 
 
 const routes = [
 const routes = [
@@ -29,6 +30,11 @@ const routes = [
         name: "bitcoin",
         name: "bitcoin",
         component: FootprintIndex,
         component: FootprintIndex,
     },
     },
+    {
+      path: '/calculator',
+      name: 'calculator',
+      component: Calculator
+    },
     {
     {
         path: "/applyPermission",
         path: "/applyPermission",
         name: "applyPermission",
         name: "applyPermission",
@@ -106,9 +112,12 @@ const routes = [
     },
     },
 ];
 ];
 
 
+
 const router = createRouter({
 const router = createRouter({
     history: createWebHistory(process.env.BASE_URL),
     history: createWebHistory(process.env.BASE_URL),
     routes,
     routes,
 });
 });
 
 
+
+
 export default router;
 export default router;

+ 481 - 0
src/views/bitcoin/Calculator.vue

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

+ 13 - 2
src/views/bitcoin/Index.vue

@@ -25,7 +25,8 @@
         <div class="pf600 fs18 fc121212">BTCUSDT 永续</div>
         <div class="pf600 fs18 fc121212">BTCUSDT 永续</div>
       </div>
       </div>
       <div class="menu-right fc333333">
       <div class="menu-right fc333333">
-        <img src="../../assets/icon/bitcoin/jisuan.svg" alt="">
+
+        <img src="../../assets/icon/bitcoin/jisuan.svg" alt="" @click="$router.push('/calculator')">
         <img src="../../assets/icon/bitcoin/hangqing.svg" alt="">
         <img src="../../assets/icon/bitcoin/hangqing.svg" alt="">
         <img src="../../assets/icon/bitcoin/den.svg" alt="">
         <img src="../../assets/icon/bitcoin/den.svg" alt="">
       </div>
       </div>
@@ -130,7 +131,7 @@
 
 
         </div>
         </div>
         <div class="menu-content-rb pf400 fs14">
         <div class="menu-content-rb pf400 fs14">
-          <div class="menu-content-rb1 fs14 fc333333">
+          <div class="menu-content-rb1 fs14 fc333333" @click="showModal3 = true">
             <img src="../../assets/icon/bitcoin/quancang.svg" alt="">
             <img src="../../assets/icon/bitcoin/quancang.svg" alt="">
             <span>{{ selectedLabel2 }}</span>
             <span>{{ selectedLabel2 }}</span>
           </div>
           </div>
@@ -291,6 +292,12 @@
       ></OrderType>
       ></OrderType>
     </div>
     </div>
 
 
+    <div>
+      <LimitOrderModal
+          v-model:visible="showModal3"
+      ></LimitOrderModal>
+    </div>
+
     <!--    <div>-->
     <!--    <div>-->
     <!--      <InsufficientBalance-->
     <!--      <InsufficientBalance-->
     <!--          v-model:visible="showRechargeModal"-->
     <!--          v-model:visible="showRechargeModal"-->
@@ -320,8 +327,12 @@
         const MarginInfoSheet = defineAsyncComponent(() => import('./components/MarginInfoSheet.vue'));
         const MarginInfoSheet = defineAsyncComponent(() => import('./components/MarginInfoSheet.vue'));
         const FundingOptions = defineAsyncComponent(() => import('./components/FundingOptions.vue'));
         const FundingOptions = defineAsyncComponent(() => import('./components/FundingOptions.vue'));
         const OrderType = defineAsyncComponent(() => import('./components/OrderType.vue'));
         const OrderType = defineAsyncComponent(() => import('./components/OrderType.vue'));
+        //余额不足提示
         // const InsufficientBalance = defineAsyncComponent(() => import('./StatusComponent/InsufficientBalance.vue'));
         // const InsufficientBalance = defineAsyncComponent(() => import('./StatusComponent/InsufficientBalance.vue'));
+        const LimitOrderModal = defineAsyncComponent(() => import('./components/LimitOrderModal.vue'));
 
 
+        //市价说明
+        const showModal3 = ref(false);
 
 
         // //余额不足提示
         // //余额不足提示
         //   // 控制弹窗显示的变量
         //   // 控制弹窗显示的变量

+ 211 - 0
src/views/bitcoin/calculator/LeverageSlider.vue

@@ -0,0 +1,211 @@
+<template>
+  <div class="slider-wrapper">
+    <div
+      class="track-container"
+      ref="trackRef"
+      @mousedown.prevent="handleTrackDown"
+      @touchstart.prevent="handleTrackDown"
+    >
+      <div class="track-bg"></div>
+
+      <div
+        class="track-fill"
+        :style="{ width: percentage + '%', backgroundColor: color }"
+      ></div>
+
+      <div class="thumb anchor-thumb" :style="{ borderColor: color }"></div>
+
+      <div
+        class="thumb drag-thumb"
+        :style="{ left: percentage + '%', borderColor: color }"
+      ></div>
+    </div>
+
+    <div class="ticks">
+      <span
+        v-for="(mark, i) in marks"
+        :key="i"
+        class="tick-label"
+        :style="{ left: (i / (marks.length - 1)) * 100 + '%' }"
+      >
+        {{ mark }}x
+      </span>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, onUnmounted } from 'vue';
+
+const props = defineProps({
+  modelValue: { type: Number, default: 10 },
+  color: { type: String, default: '#f6465d' },
+  // 固定阶梯
+  marks: {
+    type: Array,
+    default: () => [10, 50, 100, 500, 1000]
+  }
+});
+
+const emit = defineEmits(['update:modelValue']);
+
+const trackRef = ref(null);
+const isDragging = ref(false);
+
+// === 核心 1: 根据当前数值,反推在轨道上的百分比位置 ===
+const percentage = computed(() => {
+  const currentVal = props.modelValue;
+  const list = props.marks;
+
+  // 找到当前数值对应数组里的第几个 (Index)
+  // 如果数值不在数组里(比如初始传入了11),则找最近的一个
+  let closestIndex = 0;
+  let minDiff = Infinity;
+
+  list.forEach((val, index) => {
+    const diff = Math.abs(val - currentVal);
+    if (diff < minDiff) {
+      minDiff = diff;
+      closestIndex = index;
+    }
+  });
+
+  // 比如有5个点,索引是0-4。第2个点位置就是 2/4 = 50%
+  return (closestIndex / (list.length - 1)) * 100;
+});
+
+const getClientX = (event) => {
+  if (event.touches && event.touches.length > 0) {
+    return event.touches[0].clientX;
+  }
+  return event.clientX;
+};
+
+// === 核心 2: 根据点击位置,吸附到最近的刻度 ===
+const updateValueByPosition = (clientX) => {
+  if (!trackRef.value) return;
+
+  const rect = trackRef.value.getBoundingClientRect();
+  const width = rect.width;
+  let offsetX = clientX - rect.left;
+
+  // 限制范围
+  if (offsetX < 0) offsetX = 0;
+  if (offsetX > width) offsetX = width;
+
+  // 计算当前触摸点占总长度的比例 (0.0 - 1.0)
+  const ratio = offsetX / width;
+
+  // 总段数 (比如5个点就是4段)
+  const segments = props.marks.length - 1;
+
+  // 四舍五入找到最近的索引
+  // 例如 ratio = 0.6,segments = 4 => 2.4 => round => 2 (即第3个点)
+  const targetIndex = Math.round(ratio * segments);
+
+  // 取出对应的值
+  const newValue = props.marks[targetIndex];
+
+  // 如果变了才发送更新
+  if (newValue !== props.modelValue) {
+    emit('update:modelValue', newValue);
+  }
+};
+
+const handleTrackDown = (e) => {
+  isDragging.value = true;
+  updateValueByPosition(getClientX(e));
+  document.addEventListener('mousemove', onDrag);
+  document.addEventListener('mouseup', stopDrag);
+  document.addEventListener('touchmove', onDrag, { passive: false });
+  document.addEventListener('touchend', stopDrag);
+};
+
+const onDrag = (e) => {
+  if (!isDragging.value) return;
+  if (e.type === 'touchmove') e.preventDefault();
+  updateValueByPosition(getClientX(e));
+};
+
+const stopDrag = () => {
+  isDragging.value = false;
+  document.removeEventListener('mousemove', onDrag);
+  document.removeEventListener('mouseup', stopDrag);
+  document.removeEventListener('touchmove', onDrag);
+  document.removeEventListener('touchend', stopDrag);
+};
+
+onUnmounted(() => stopDrag());
+</script>
+
+<style scoped>
+/* 样式保持不变,复用之前的优美样式 */
+.slider-wrapper {
+  padding: 15px 0;
+  width: 100%;
+  touch-action: none;
+  position: relative;
+  margin-bottom: 10px;
+}
+
+.track-container {
+  position: relative;
+  height: 8px;
+  width: 100%;
+  cursor: pointer;
+  padding: 10px 0;
+  margin-top: -10px;
+  margin-bottom: -10px;
+}
+
+.track-bg {
+  position: absolute;
+  top: 50%; transform: translateY(-50%);
+  width: 100%; height: 8px;
+  background: #f5f5f5;
+  border-radius: 4px;
+}
+
+.track-fill {
+  position: absolute;
+  top: 50%; transform: translateY(-50%);
+  height: 8px;
+  border-radius: 4px 0 0 4px;
+  pointer-events: none;
+  transition: width 0.1s; /* 增加一点过渡动画,让吸附效果更平滑 */
+}
+
+.thumb {
+  position: absolute;
+  top: 50%; transform: translate(-50%, -50%);
+  width: 26px; height: 26px;
+  background: #fff;
+  border: 2px solid;
+  border-radius: 50%;
+  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+  z-index: 2;
+  pointer-events: none;
+  box-sizing: border-box;
+  transition: left 0.1s; /* 增加一点过渡动画 */
+}
+
+.anchor-thumb { left: 0%; z-index: 1; }
+
+.ticks {
+  position: relative;
+  width: 100%;
+  height: 20px;
+  margin-top: 15px;
+}
+
+.tick-label {
+  position: absolute;
+  transform: translateX(-50%);
+  color: #5e6673;
+  font-size: 12px;
+  white-space: nowrap;
+}
+
+.tick-label:first-child { transform: translateX(0); }
+.tick-label:last-child { transform: translateX(-100%); }
+</style>

+ 11 - 0
src/views/bitcoin/calculator/LimitOrderModal.vue

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

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

@@ -194,7 +194,7 @@ const showModal4 = ref(false);
   border-radius: 50%;
   border-radius: 50%;
   background: #ffffff; /* 白底 */
   background: #ffffff; /* 白底 */
   //border: 2px solid var(--red); /* 红色边框 */
   //border: 2px solid var(--red); /* 红色边框 */
-  border: 2px solid red;
+  border: 2px solid #E04747;
   box-shadow: 0 1px 3px rgba(0,0,0,0.2);
   box-shadow: 0 1px 3px rgba(0,0,0,0.2);
   margin-top: -8px; /* 垂直居中轨道 */
   margin-top: -8px; /* 垂直居中轨道 */
   position: relative;
   position: relative;

+ 1 - 0
src/views/bitcoin/components/LeveragePopup.vue

@@ -256,6 +256,7 @@ const confirmSelection = () => {
   z-index: 2;
   z-index: 2;
 }
 }
 
 
+
 .inner-circle {
 .inner-circle {
   width: 0px; /* 图片中看起来是实心的或者空心的,这里做个空心白底红圈 */
   width: 0px; /* 图片中看起来是实心的或者空心的,这里做个空心白底红圈 */
   height: 0px;
   height: 0px;

+ 289 - 0
src/views/bitcoin/components/LimitOrderModal.vue

@@ -0,0 +1,289 @@
+<template>
+  <Teleport to="body">
+    <div v-if="visible" class="modal-overlay" @click="close">
+      <div class="modal-content" @click.stop>
+        <div class="drag-handle"></div>
+
+        <div class="tabs-header">
+          <div
+            v-for="(tab, index) in tabs"
+            :key="index"
+            class="tab-item"
+            :class="{ active: currentTab === index }"
+            @click="currentTab = index"
+          >
+            {{ tab }}
+            <div v-if="currentTab === index" class="active-line"></div>
+          </div>
+        </div>
+
+        <div class="tab-body">
+
+          <div v-if="currentContent.topDesc" class="top-description">
+            {{ currentContent.topDesc }}
+          </div>
+
+          <div class="control-row">
+            <span class="label">图示说明</span>
+
+            <div v-if="currentTab === 1" class="checkbox-group">
+              <div class="checkbox-item" @click="setDirection('long')">
+                <div class="custom-checkbox" :class="{ checked: direction === 'long' }">
+                  <span v-if="direction === 'long'">✓</span>
+                </div>
+                <span>做多</span>
+              </div>
+              <div class="checkbox-item" @click="setDirection('short')">
+                <div class="custom-checkbox" :class="{ checked: direction === 'short' }">
+                  <span v-if="direction === 'short'">✓</span>
+                </div>
+                <span>做空</span>
+              </div>
+            </div>
+          </div>
+          <div class="image-container">
+            <img :src="currentContent.image" alt="" />
+          </div>
+
+          <div class="description-text fs12 fc999999">
+            <h3 v-if="currentContent.title">{{ currentContent.title }}</h3>
+            <div class="desc-content" v-html="currentContent.desc"></div>
+          </div>
+        </div>
+        <div class="footer">
+          <button class="confirm-btn" @click="close">确认</button>
+        </div>
+      </div>
+    </div>
+  </Teleport>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue';
+
+const props = defineProps({
+  visible: { type: Boolean, default: false }
+});
+const emit = defineEmits(['update:visible']);
+
+// ================= 状态管理 =================
+const tabs = ['市价', '限价', '限价止盈止损', '市价止盈止损'];
+const currentTab = ref(0); // 默认为 0 (市价)
+const direction = ref('short'); // 仅用于 Tab 1 (限价) 的做多/做空
+
+// ================= 图片资源配置 =================
+// 请将此处路径替换为你项目中的实际图片路径
+const imgMap = {
+  market: require('../../../assets/icon/bitcoin/shijia.svg'),     // 市价
+  limitLong: require('../../../assets/icon/bitcoin/xianjia.svg'),   // 限价-做多
+  limitShort: require('../../../assets/icon/bitcoin/xianjiak.svg'), // 限价-做空
+  limitTpSl: require('../../../assets/icon/bitcoin/xianjiazyzs.svg'),  // 限价止盈止损
+  marketTpSl: require('../../../assets/icon/bitcoin/shijiazyzs.svg'),  // 市价止盈止损
+};
+
+// ================= 核心内容数据 =================
+// 使用 computed 动态生成当前 Tab 应显示的内容
+const currentContent = computed(() => {
+  switch (currentTab.value) {
+    case 0: // === 市价 ===
+      return {
+        topDesc: null,
+        image: imgMap.market,
+        title: '市价委托是指按照目前市场最优价格,进行快速买卖。',
+        desc: '当前价格2400,此时下单一笔市价单,它将会根据对手价直接成交,但成交均价可能不等于2400。'
+      };
+
+    case 1: // === 限价 (带做多/做空逻辑) ===
+      const isLong = direction.value === 'long';
+      return {
+        topDesc: null,
+        image: isLong ? imgMap.limitLong : imgMap.limitShort,
+        title: '限价委托是指以特定或更优价格进行买卖,限价单不能保证一定成交',
+        desc: isLong
+          ? '当前市价(A)下跌至委托限价(C)或以下,委托单将会自动执\n' +
+            '行:如果买单委托限价(B)高于或等于当前市价,委托单将会立\n' +
+            '即成交,因此当需要限价买入时,委托价格应低于当前价格。'
+          : '当价格(A)上涨至订单的限价(B)或以上,订单将会自动执行\n' +
+            '如果卖单的限价低于或等于当前价格,卖单可能会立即成交。因此,\n' +
+            '当需要限价卖出时,委托价格应高于当前价格。'
+      };
+
+    case 2: // === 限价止盈止损 ===
+      return {
+        topDesc: '限价止盈止损委托需要同时设置一个触发价格和一个委托价格。当市场最新价到达触发价时,按预先设置的委托价格和数量自动下单。',
+        image: imgMap.limitTpSl,
+        title: null,
+        // 使用 HTML 字符串来模拟截图中的红色文字高亮
+        desc: `
+          <p>当前价格为2,400 (A)。限价止盈止损单的触发价格可以设置为3,000 (B),高于当前价格;也可以设置为1,500 (C),低于当前价格。一旦价格上涨至3,000 (B),或下跌到1,500 (C),达到触发价,限价委托单将自动激活生效。</p>
+          <p style="margin-top:8px; font-weight:500;">备注:</p>
+          <ol style="padding-left: 15px; margin: 5px 0;">
+            <li>1)买入和卖出订单的限价都可以高于或低于触发价。比如,<span style="color:#dc3545">触发价B</span>可以和价格略低的<span style="color:#dc3545">委托价B1</span>组成限价止盈止损单,也可以和价格略高的<span style="color:#dc3545">委托价B2</span>组成限价止盈止损单;</li>
+            <li>2)在没有达到触发价时,限价单不会生效,即使价格达到限价的时间早于触发价也是如此。</li>
+            <li>3)当达到止损价格时,只能表明限价单将会自动激活并提交至市场,并不表示限价单将会立即成交。限价委托单被激活后,只有满足其成交条件才会最终执行。</li>
+          </ol>
+        `
+      };
+
+    case 3: // === 市价止盈止损 ===
+      return {
+        topDesc: '当触达设定的价格时,止损市价委托会自动触发。交易者需要设定一个价格去触发该类型委托。该类委托可以应用于设置市价止损和市价止盈委托。',
+        image: imgMap.marketTpSl,
+        title: null,
+        desc: '当前价格为2,400 (A)。市价止盈止损订单的触发价格可以设置为3,000 (B),高于当前价格;也可以设置为1,500(C),低于当前价格。一旦价格上涨至3,000(B),或下跌到1,500 (C),达到触发价,市价单将自动触发生效。'
+      };
+
+    default:
+      return {};
+  }
+});
+
+const setDirection = (val) => {
+  direction.value = val;
+};
+
+const close = () => {
+  emit('update:visible', false);
+};
+</script>
+
+<style scoped>
+/* 保持之前的遮罩和弹窗基础样式 */
+.modal-overlay {
+  position: fixed;
+  top: 0; left: 0; width: 100vw; height: 100vh;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex; align-items: flex-end; justify-content: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  background: white;
+  width: 100%;
+  max-width: 500px;
+  border-radius: 16px 16px 0 0;
+  padding: 10px 20px 30px;
+  box-sizing: border-box;
+  max-height: 90vh;
+  overflow-y: auto; /* 内容过长时允许滚动 */
+  animation: slideUp 0.3s ease-out;
+}
+
+.drag-handle {
+  width: 40px; height: 4px; background: #e0e0e0;
+  border-radius: 2px; margin: 5px auto 15px;
+}
+
+/* Tabs Header */
+.tabs-header {
+  display: flex;
+  justify-content: space-between;
+  border-bottom: 1px solid #f0f0f0;
+  margin-bottom: 20px;
+}
+
+.tab-item {
+  padding: 10px 0;
+  font-size: 14px; /* 字体稍微调小以容纳4个Tab */
+  color: #999;
+  cursor: pointer;
+  position: relative;
+  font-weight: 500;
+  white-space: nowrap;
+}
+
+.tab-item.active {
+  color: #000;
+  font-weight: bold;
+}
+
+.active-line {
+  position: absolute; bottom: -1px; left: 50%;
+  transform: translateX(-50%);
+  width: 20px; height: 3px; background: #000; border-radius: 2px;
+}
+
+/* Top Description (用于止盈止损页面顶部) */
+.top-description {
+  font-size: 13px;
+  color: #333;
+  line-height: 1.6;
+  margin-bottom: 20px;
+  text-align: justify;
+}
+
+/* Controls */
+.control-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 15px;
+}
+
+.label {
+  font-size: 14px; font-weight: bold; color: #333;
+}
+
+.checkbox-group {
+  display: flex; gap: 20px;
+}
+
+.checkbox-item {
+  display: flex; align-items: center; cursor: pointer;
+  font-size: 14px; color: #666;
+}
+
+.custom-checkbox {
+  width: 16px; height: 16px; border: 1px solid #ccc;
+  border-radius: 4px; margin-right: 6px;
+  display: flex; align-items: center; justify-content: center;
+  color: white; font-size: 12px;
+}
+
+.custom-checkbox.checked {
+  background-color: #dc3545; border-color: #dc3545;
+}
+
+/* Image */
+.image-container {
+  width: 100%;
+  background: #fff;
+  display: flex; justify-content: center;
+  margin-bottom: 20px;
+}
+
+.image-container img {
+  max-width: 100%; height: auto; object-fit: contain;
+}
+
+/* Description Text */
+.description-text h3 {
+  font-size: 14px; color: #333; margin-bottom: 10px; font-weight: bold;
+}
+
+/* 深度选择器用于控制 v-html 内部样式 */
+.desc-content :deep(p) {
+  font-size: 12px; color: #888; line-height: 1.6; text-align: justify; margin-bottom: 8px;
+}
+
+.desc-content :deep(ol) {
+  font-size: 12px; color: #888; line-height: 1.6;
+}
+.desc-content :deep(li) {
+  margin-bottom: 4px;
+}
+
+/* Footer */
+.footer { margin-top: 20px; }
+.confirm-btn {
+  width: 100%; padding: 12px;
+  background-color: #dc3545; color: white;
+  border: none; border-radius: 24px;
+  font-size: 16px; font-weight: bold; cursor: pointer;
+}
+
+@keyframes slideUp {
+  from { transform: translateY(100%); }
+  to { transform: translateY(0); }
+}
+</style>

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

@@ -20,7 +20,7 @@
         price: '0.215 USDT',
         price: '0.215 USDT',
         statusText: '止损',
         statusText: '止损',
         triggerPrice: '标记价格>20',
         triggerPrice: '标记价格>20',
-        time: '2025-11-04, 16:30',
+        time: '2025-11-04,16:30',
         stateText: '未触发',
         stateText: '未触发',
         canCancel: true // 显示红色撤单按钮
         canCancel: true // 显示红色撤单按钮
       },
       },
@@ -35,7 +35,7 @@
         price: '0.215 USDT',
         price: '0.215 USDT',
         statusText: '止盈',
         statusText: '止盈',
         triggerPrice: '标记价格>20',
         triggerPrice: '标记价格>20',
-        time: '2025-11-04, 16:30',
+        time: '2025-11-04,16:30',
         stateText: '未触发',
         stateText: '未触发',
         canCancel: false // 显示灰色已完成/不可操作按钮
         canCancel: false // 显示灰色已完成/不可操作按钮
       }
       }
@@ -317,7 +317,7 @@
 .card-body-grid {
 .card-body-grid {
   display: grid;
   display: grid;
   /* 定义三列,左侧和中间自动,右侧靠边 */
   /* 定义三列,左侧和中间自动,右侧靠边 */
-  grid-template-columns: 1fr 1fr 1fr;
+  grid-template-columns: 1fr 2fr 1fr;
   row-gap: 12px; /* 行间距 */
   row-gap: 12px; /* 行间距 */
 }
 }
 
 
@@ -334,6 +334,9 @@
 
 
 .align-center {
 .align-center {
   align-items: center;
   align-items: center;
+  .value:nth-child(2){
+    margin-top: 2px;
+  }
 }
 }
 
 
 .align-right {
 .align-right {
@@ -349,6 +352,7 @@
   font-size: 13px;
   font-size: 13px;
   color: #333;
   color: #333;
   font-family: Helvetica, Arial, sans-serif; /* 数字字体优化 */
   font-family: Helvetica, Arial, sans-serif; /* 数字字体优化 */
+  font-weight: 500;
 }
 }
 
 
 .bold-text {
 .bold-text {

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio