| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- <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>
|