0510航天交易所ui仿制,代码使用的jiem
lxf
2025-07-16 fcb00a66b4053550b473a29d7299c7a4737eea75
src/components/trade-order-area/index.vue
@@ -1,47 +1,101 @@
<template>
  <div class="flex flex-col flex-1">
    <div class="flex items-center h-66 tabBackground text-grey">
      <p class="font-28 flex-1 flex items-center justify-center h-66 buy-item"
        :class="currentType == 'open' ? 'open' : ''" @click="changeTab('open')">{{ $t('买入') }}</p>
      <p class="font-28 flex-1 flex items-center justify-center h-66 buy-item"
        :class="currentType == 'close' ? 'close' : ''" @click="changeTab('close')">{{ $t('卖出') }}</p>
      <p
        class="font-28 flex-1 flex items-center justify-center h-66 buy-item"
        :class="currentType == 'open' ? 'open' : ''"
        @click="changeTab('open')"
      >
        {{ $t("买入") }}
      </p>
      <p
        class="font-28 flex-1 flex items-center justify-center h-66 buy-item"
        :class="currentType == 'close' ? 'close' : ''"
        @click="changeTab('close')"
      >
        {{ $t("卖出") }}
      </p>
    </div>
    <div class="mt-22 mb-22 inputBackground" style="position:relative;">
      <div class=" flex justify-between  items-center w-full h-70" @click="selectBtn">
    <div class="mt-22 mb-22 inputBackground" style="position: relative">
      <div
        class="flex justify-between items-center w-full h-70"
        @click="selectBtn"
      >
        <!-- <img src="@/assets/image/public/warn.png" alt="warn-icon" class="w-25 h-25 pl-20"/> -->
        <div class="pl-16 textColor" style="width:80%;">{{ title }}</div>
        <img src="@/assets/image/public/grey-select.png" alt="select-icon" class="w-22 h-11 pr-20" />
        <div class="pl-16 textColor" style="width: 80%">{{ title }}</div>
        <img
          src="@/assets/image/public/grey-select.png"
          alt="select-icon"
          class="w-22 h-11 pr-20"
        />
      </div>
      <div class="option-box" v-if="isShow">
        <div class="font-30" v-for="item in selectData" :key="item.type" @click="selectItem(item)">{{ item.title }}
        <div
          class="font-30"
          v-for="item in selectData"
          :key="item.type"
          @click="selectItem(item)"
        >
          {{ item.title }}
        </div>
      </div>
    </div>
    <div class="h-70 lh-70  inputBackground mb-25 flex justify-center px-16 textColor2">
      <input placeholder="" class="targetPrice  w-full  h-70 border-none" v-model="form.price"
        :disabled="type / 1 === 1" />
    <div
      class="h-70 lh-70 inputBackground mb-25 flex justify-center px-16 textColor2"
    >
      <input
        placeholder=""
        class="targetPrice w-full h-70 border-none"
        v-model="form.price"
        :disabled="type / 1 === 1"
      />
      <span>USDT</span>
    </div>
    <div class="h-70 lh-70  inputBackground mb-25 flex justify-center px-16 textColor2">
    <div
      class="h-70 lh-70 inputBackground mb-25 flex justify-center px-16 textColor2"
    >
      <span>{{ title }}</span>
    </div>
    <div class="flex total-list">
      <div class="total-div" :class="[!isTotal ? 'active-bg' : '']" @click="checkIsTotal(false)">
        {{ $t('数量') }}
      <div
        class="total-div"
        :class="[!isTotal ? 'active-bg' : '']"
        @click="checkIsTotal(false)"
      >
        {{ $t("数量") }}
      </div>
      <div class="total-div" :class="[isTotal ? 'active-bg' : '']" @click="checkIsTotal(true)">
        {{ $t('总额') }}
      <div
        class="total-div"
        :class="[isTotal ? 'active-bg' : '']"
        @click="checkIsTotal(true)"
      >
        {{ $t("总额") }}
      </div>
    </div>
    <div v-if="!isTotal" class="h-70 lh-70 inputBackground mb-36 flex justify-center px-16">
      <input :placeholder="$t('数量')" class=" w-full h-70 border-none textColor" v-model="form.volume" @input="onInput" />
    <div
      v-if="!isTotal"
      class="h-70 lh-70 inputBackground mb-36 flex justify-center px-16"
    >
      <input
        :placeholder="$t('数量')"
        class="w-full h-70 border-none textColor"
        v-model="form.volume"
        @input="onInput"
      />
      <span class="textColor">{{ symbolname }}</span>
    </div>
    <div v-if="isTotal" class="h-70 lh-70 inputBackground  mb-36 flex justify-center px-16">
      <input :placeholder="$t('总额')" class=" w-full h-70 border-none textColor" v-model="form.total"
        @input="onInputTotal" />
      <span class="textColor">{{ 'USDT' }}</span>
    <div
      v-if="isTotal"
      class="h-70 lh-70 inputBackground mb-36 flex justify-center px-16"
    >
      <input
        :placeholder="$t('总额')"
        class="w-full h-70 border-none textColor"
        v-model="form.total"
        @input="onInputTotal"
      />
      <span class="textColor">{{ "USDT" }}</span>
    </div>
    <!-- <vue-slider v-bind="options" v-model="form.volume"  :interval="interval"></vue-slider> -->
    <!-- <vue-slider class="mainBox"  v-bind="options" :interval="interval"  v-model="form.volume" :hide-label="true"  :railStyle="{ background: '#404040', height: '10px' }"
@@ -50,42 +104,75 @@
        <div :class="['custom-step', { active }]"></div>
      </template>
    </vue-slider> -->
    <div style="color: #868D9A" class="font-24 w-full flex justify-between items-center">
    <div
      style="color: #868d9a"
      class="font-24 w-full flex justify-between items-center"
    >
      <!-- <span class="flex-1 text-left">0%</span> -->
      <span class="flex-1 tab-item" :class="[percentageVal == 25 ? 'select-active' : '']"
        @click="exchangeVal(25)">25%</span>
      <span class="flex-1 tab-item" :class="[percentageVal == 50 ? 'select-active' : '']"
        @click="exchangeVal(50)">50%</span>
      <span class="flex-1 tab-item" :class="[percentageVal == 75 ? 'select-active' : '']"
        @click="exchangeVal(75)">75%</span>
      <span class="flex-1 tab-item" :class="[percentageVal == 100 ? 'select-active' : '']"
        @click="exchangeVal(100)">100%</span>
      <span
        class="flex-1 tab-item"
        :class="[percentageVal == 25 ? 'select-active' : '']"
        @click="exchangeVal(25)"
        >25%</span
      >
      <span
        class="flex-1 tab-item"
        :class="[percentageVal == 50 ? 'select-active' : '']"
        @click="exchangeVal(50)"
        >50%</span
      >
      <span
        class="flex-1 tab-item"
        :class="[percentageVal == 75 ? 'select-active' : '']"
        @click="exchangeVal(75)"
        >75%</span
      >
      <span
        class="flex-1 tab-item"
        :class="[percentageVal == 100 ? 'select-active' : '']"
        @click="exchangeVal(100)"
        >100%</span
      >
    </div>
    <div class="flex justify-between items-center mt-40">
      <div class="flex flex-col font-24">
        <p class="text-grey" v-if="this.currentType === 'open'">{{ $t('可用') }}<span class="textColor ml-8">
            {{ initOpen.volume | nan }}&nbsp;USDT</span>
        <p class="text-grey" v-if="this.currentType === 'open'">
          {{ $t("可用")
          }}<span class="textColor ml-8">
            {{ initOpen.volume | nan }}&nbsp;USDT</span
          >
        </p>
        <p class="text-grey" v-else>{{ $t('可卖') }}<span class="textColor ml-8">{{ initClose.volume | nan }}&nbsp;{{
          symbolname }}</span></p>
        <p class="text-grey" v-else>
          {{ $t("可卖")
          }}<span class="textColor ml-8"
            >{{ initClose.volume | nan }}&nbsp;{{ symbolname }}</span
          >
        </p>
      </div>
      <van-icon name="add-o" @click="$router.push('/exchange/exchangePage')" class="font-30 add-icon" />
      <van-icon
        name="add-o"
        @click="$router.push('/exchange/exchangePage')"
        class="font-30 add-icon"
      />
      <!-- <img @click="$router.push('/exchange/exchangePage')" src="@/assets/image/public/switch.png" class="w-24 h-24" /> -->
    </div>
    <div style="" class="w-full h-90 lh-90 flex justify-center text-white text-center rounded buyandSell mt-70"
      :class="currentType === 'open' ? 'bg-green' : 'bg-red'" @click="order()">
      {{ currentType == 'open' ? $t('买入') : $t('卖出') }}
    <div
      style=""
      class="w-full h-90 lh-90 flex justify-center text-white text-center rounded buyandSell mt-70"
      :class="currentType === 'open' ? 'bg-green' : 'bg-red'"
      @click="order()"
    >
      {{ currentType == "open" ? $t("买入") : $t("卖出") }}
    </div>
  </div>
</template>
<script>
import config from "@/config";
import { Popup, Tabs, Tab } from 'vant';
import VueSlider from 'vue-slider-component'
import 'vue-slider-component/theme/default.css'
import { _getBalance } from '@/API/trade.api'
import { Popup, Tabs, Tab } from "vant";
import VueSlider from "vue-slider-component";
import "vue-slider-component/theme/default.css";
import { _getBalance } from "@/API/trade.api";
import TradeApi from "@/API/trading.js";
import { mapGetters } from "vuex";
// import PopupConfirmOrder from '@/components/popup-confirm-order'
@@ -95,170 +182,187 @@
    VueSlider,
    [Popup.name]: Popup,
    [Tabs.name]: Tabs,
    [Tab.name]: Tab
    [Tab.name]: Tab,
  },
  props: {
    symbol: {
      type: String,
      default: ''
      default: "",
    },
   symbolname: {
     type: String,
     default: '--'
   },
    symbolname: {
      type: String,
      default: "--",
    },
    price: {
      type: [Number, String],
      default: '0.00'
      default: "0.00",
    },
    initOpen: {
      type: Object,
      default() {
        return {}
      }
        return {};
      },
    },
    initClose: {
      type: Object,
      default() {
        return {}
      }
        return {};
      },
    },
  },
  computed: {
    ...mapGetters('user', ['userInfo'])
    ...mapGetters("user", ["userInfo"]),
  },
  activated() {
    this.selectData = [
      { title: this.$t('市价委托'), type: '1' },
      { title: this.$t('限价委托'), type: '2' },
    ]
    this.title = this.selectData[0].title
    this.type = this.selectData[0].type
      { title: this.$t("市价委托"), type: "1" },
      { title: this.$t("限价委托"), type: "2" },
    ];
    this.title = this.selectData[0].title;
    this.type = this.selectData[0].type;
  },
  watch: {
    initOpen: { // 处理滚动条初始值
    initOpen: {
      // 处理滚动条初始值
      deep: true,
      handler(val) {
        console.log(val)
        console.log(val);
        if (val.volume / 1 > 0) {
          this.handleInitSliderOption()
          this.handleInitSliderOption();
        }
      }
      },
    },
    initClose: { // 处理滚动条初始值
    initClose: {
      // 处理滚动条初始值
      deep: true,
      handler(newVal, oldVal) {
        if (newVal.volume / 1 > 0) {
          this.handleInitSliderOption(true)
          this.handleInitSliderOption(true);
        }
      }
      },
    },
    price(val) {
      if (this.type === '1') { // !this.focus &&
        this.form.price = val
      if (this.type === "1") {
        // !this.focus &&
        this.form.price = val;
      }
    },
  },
  filters: {
    nan(val) {
      return isNaN(val) ? '--' : val
    }
      return isNaN(val) ? "--" : val;
    },
  },
  data() {
    return {
      options: config.sliderOptions,
      value: 0,
      isShow: false,
      title: this.$t('市价委托'),
      title: this.$t("市价委托"),
      selectData: [],
      form: {
        volume: '',
        session_token: '',
        symbol: '', // 币种
        price: '',
        total: '',
        order_price_type: 'opponent', // 市价or限价
        volume: "",
        session_token: "",
        symbol: "", // 币种
        price: "",
        total: "",
        order_price_type: "opponent", // 市价or限价
      },
      type: "1",//选中市价或限价类型
      type: "1", //选中市价或限价类型
      currentType: "open", //开仓类型
      interval: 0.001,
      marks: (val) => val % 25 === 0,
      isTotal: false,
      percentageVal: 0
    }
      percentageVal: 0,
    };
  },
  mounted() {
  },
  mounted() {},
  methods: {
    checkIsTotal(val) {
      this.isTotal = val
      this.percentageVal = 0
      this.form.total = ''
      this.form.volume = ''
      this.isTotal = val;
      this.percentageVal = 0;
      this.form.total = "";
      this.form.volume = "";
    },
    exchangeVal(val) {
      this.percentageVal = val
      this.percentageVal = val;
      if (!this.isTotal) {
        if (this.currentType == 'open') {
          let sum = (parseFloat(this.initOpen.volume) * (val / 100) / parseFloat(this.form.price))
          this.form.volume = Math.floor(sum * 100000) / 100000
        if (this.currentType == "open") {
          let sum =
            (parseFloat(this.initOpen.volume) * (val / 100)) /
            parseFloat(this.form.price);
          this.form.volume = Math.floor(sum * 100000) / 100000;
        } else {
          let sum = parseFloat(this.initClose.volume)
          this.form.volume = (Math.floor(sum * (val / 100) * 100000)) / 100000
          let sum = parseFloat(this.initClose.volume);
          this.form.volume = Math.floor(sum * (val / 100) * 100000) / 100000;
        }
      } else {
        if (this.currentType == 'open') {
          this.form.total = this.initOpen.volume * (val / 100)
        if (this.currentType == "open") {
          this.form.total = this.initOpen.volume * (val / 100);
        } else {
          this.form.total = Math.floor((this.initClose.volume * (val / 100) * parseFloat(this.form.price)) * 1000) / 1000
          this.form.total =
            Math.floor(
              this.initClose.volume *
                (val / 100) *
                parseFloat(this.form.price) *
                1000
            ) / 1000;
        }
      }
    },
    handleInitSliderOption(volume) {
      if (!volume) { // 金额是否需要变动
        this.form.volume = ''
      if (!volume) {
        // 金额是否需要变动
        this.form.volume = "";
      }
      console.log(this.initOpen.volume)
      let vol
      if (this.currentType === 'open') {
        vol = this.initOpen.volume / 1
      console.log(this.initOpen.volume);
      let vol;
      if (this.currentType === "open") {
        vol = this.initOpen.volume / 1;
      } else {
        vol = this.initClose.volume / 1
        vol = this.initClose.volume / 1;
      }
      this.options.max = Number(vol.toFixed(3))
      this.options.max = Number(vol.toFixed(3));
      if (this.options.max > 0) {
        this.options.disabled = false
        this.options.disabled = false;
      } else {
        this.options.disabled = true
        this.options.disabled = true;
      }
    },
    onInput() { // 数量变化
      if (this.currentType === 'open') {
        let maxSum = (parseFloat(this.initOpen.volume) / parseFloat(this.form.price))
        console.log(this.initOpen.volume)
        console.log(this.form.price)
        console.log(maxSum)
    onInput() {
      // 数量变化
      if (this.currentType === "open") {
        let maxSum =
          parseFloat(this.initOpen.volume) / parseFloat(this.form.price);
        console.log(this.initOpen.volume);
        console.log(this.form.price);
        console.log(maxSum);
        if (this.form.volume * 1 > maxSum / 1) {
          this.form.volume = maxSum
          this.form.volume = maxSum;
        }
      } else {
        if (this.form.volume * 1 / 1 > this.options.max / 1) {
          this.form.volume = this.options.max / 1
        if ((this.form.volume * 1) / 1 > this.options.max / 1) {
          this.form.volume = this.options.max / 1;
        }
      }
    },
    onInputTotal() { //总额变化
    onInputTotal() {
      //总额变化
      //最大额度
      if (this.form.total > 0) {
        if (this.currentType === 'open') {
          console.log(this.initOpen.volume)
        if (this.currentType === "open") {
          console.log(this.initOpen.volume);
          if (this.form.total * 1 > this.initOpen.volume * 1) {
            this.form.total = this.initOpen.volume
            this.form.total = this.initOpen.volume;
          }
        } else {
          let sum = (parseFloat(this.form.total) / parseFloat(this.form.price)).toFixed(5)
          let sum = (
            parseFloat(this.form.total) / parseFloat(this.form.price)
          ).toFixed(5);
          if (parseFloat(sum) > parseFloat(this.initClose.volume)) {
            this.form.total = (parseFloat(this.initClose.volume) * parseFloat(this.form.price)).toFixed(5)
            this.form.total = (
              parseFloat(this.initClose.volume) * parseFloat(this.form.price)
            ).toFixed(5);
          }
        }
      }
@@ -270,72 +374,75 @@
    //选择价格类型
    selectItem(item) {
      if (item.type == 1) {
        this.form.price = this.price
        this.form.price = this.price;
      }
      this.form.order_price_type = item.type === '1' ? 'opponent' : 'limit'
      this.form.order_price_type = item.type === "1" ? "opponent" : "limit";
      this.title = item.title;
      this.type = item.type;
      this.isShow = false;
    },
    //选择开仓类型
    changeTab(type) { // 开仓和
      this.percentageVal = 0
      this.isTotal = false
      this.form.total = ''
      console.log('changeTab', type)
    changeTab(type) {
      // 开仓和
      this.percentageVal = 0;
      this.isTotal = false;
      this.form.total = "";
      console.log("changeTab", type);
      // TODO: 这里应该是换函数
      // this.form.direction = type === 'open' ? 'buy' : 'sell'
      if (this.currentType === type) {
        return
        return;
      }
      this.currentType = type;
      if (this.currentType === 'close') {
        this.$emit('ordered', 'close') // 更新平仓初始化参数
      if (this.currentType === "close") {
        this.$emit("ordered", "close"); // 更新平仓初始化参数
      } else {
        this.$emit('ordered', 'open') // 更新平仓初始化参数
        this.$emit("ordered", "open"); // 更新平仓初始化参数
      }
      this.handleInitSliderOption()
      this.handleInitSliderOption();
    },
    order() {
      if (!this.userInfo.token) {
        this.$router.push('/login')
        return
        this.$router.push("/login");
        return;
      }
      let volume = ''
      let volume = "";
      if (this.isTotal) {
        if (!this.form.total) {
          this.$toast.fail(this.$t('请输入总额'))
          return
          this.$toast.fail(this.$t("请输入总额"));
          return;
        }
        if (this.currentType === 'open') {
          this.form.volume = parseFloat(this.form.total).toFixed(5)
        if (this.currentType === "open") {
          this.form.volume = parseFloat(this.form.total).toFixed(5);
        } else {
          this.form.volume = (parseFloat(this.form.total) / parseFloat(this.form.price))
          this.form.volume = this.form.volume.toFixed(5)
          this.form.volume =
            parseFloat(this.form.total) / parseFloat(this.form.price);
          this.form.volume = this.form.volume.toFixed(5);
        }
        volume = this.form.volume
        volume = this.form.volume;
      } else {
        if (!this.form.volume) {
          this.$toast.fail(this.$t('请输入数量'))
          return
          this.$toast.fail(this.$t("请输入数量"));
          return;
        }
        if (this.currentType === 'open') {
          volume = (parseFloat(this.form.volume) * parseFloat(this.form.price))
        if (this.currentType === "open") {
          volume = parseFloat(this.form.volume) * parseFloat(this.form.price);
        } else {
          volume = this.form.volume
          volume = this.form.volume;
        }
      }
      this.form.symbol = this.$route.params.symbol
      let _order = null // api
      let emitFunc = null // 触发函数
      this.form.symbol = this.$route.params.symbol;
      let _order = null; // api
      let emitFunc = null; // 触发函数
      if (this.currentType === 'open') {
        this.form.session_token = this.initOpen.session_token
      if (this.currentType === "open") {
        this.form.session_token = this.initOpen.session_token;
      } else {
        this.form.session_token = this.initClose.session_token
        this.form.session_token = this.initClose.session_token;
      }
      _order = this.currentType === 'open' ? TradeApi.tradeBuy : TradeApi.tradeSell
      emitFunc = this.currentType
      _order =
        this.currentType === "open" ? TradeApi.tradeBuy : TradeApi.tradeSell;
      emitFunc = this.currentType;
      _order({
        volume: volume,
        session_token: this.form.session_token,
@@ -343,21 +450,24 @@
        price: this.form.price,
        total: this.form.total,
        order_price_type: this.form.order_price_type, // 市价or限价
      }).then((res) => {
        this.$toast(this.$t('操作成功'))
        this.form.volume = ''
        this.form.total = ''
        _getBalance().then(data => { // 刷新余额
          this.$store.commit('user/SET_USERINFO', { balance: data.money })
        })
        this.$emit('ordered', emitFunc)
      }).catch(() => { // 也需要重新初始化
        this.$emit('ordered', emitFunc)
      })
        .then((res) => {
          this.$toast(this.$t("操作成功"));
          this.form.volume = "";
          this.form.total = "";
          _getBalance().then((data) => {
            // 刷新余额
            this.$store.commit("user/SET_USERINFO", { balance: data.money });
          });
          this.$emit("ordered", emitFunc);
        })
        .catch(() => {
          // 也需要重新初始化
          this.$emit("ordered", emitFunc);
        });
    },
  }
}
  },
};
</script>
<style lang="scss" scoped>
@@ -383,7 +493,7 @@
    line-height: 60px;
    &.option-active {
      background-color: #F5F5F5;
      background-color: #f5f5f5;
    }
  }
}
@@ -404,7 +514,6 @@
.vue-slider-dot {
  width: 28px !important;
  height: 28px !important;
}
.vue-slider-mark-label {
@@ -413,11 +522,11 @@
}
.vue-slider-mark-label-active {
  color: #868D9A !important;
  color: #868d9a !important;
}
.vue-slider-dot-handle {
  border: 3px solid #2C78F8;
  border: 3px solid #2c78f8;
}
.vue-slider-mark {
@@ -457,16 +566,16 @@
  overflow: hidden;
}
.tab>* {
.tab > * {
  height: 100%;
}
.tab>img {
.tab > img {
  margin-left: -2px;
  margin-right: -2px;
}
.tab>a {
.tab > a {
  flex-grow: 1;
  display: flex;
  justify-content: center;
@@ -514,16 +623,16 @@
  }
}
.option-box>div {
.option-box > div {
  padding: 30px 0;
}
.option-box>div:hover {
.option-box > div:hover {
  // background-color: #F5F5F5;
}
.num-text-color {
  color: #4C4A54;
  color: #4c4a54;
}
select {
@@ -534,7 +643,8 @@
  -webkit-appearance: none;
  /* Safari and Chrome */
  padding: 0 20px 0 20px;
  background: url("../../assets/image/public/grey-select.png") no-repeat scroll right center transparent;
  background: url("../../assets/image/public/grey-select.png") no-repeat scroll
    right center transparent;
  /* 自己的图*/
  background-size: 20px 11px;
}
@@ -548,7 +658,6 @@
}
.targetPrice {
  opacity: 1;
}
@@ -558,19 +667,18 @@
  }
}
.custom-step {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: fff;
  border: solid 1px #2256F7;
  border: solid 1px #2256f7;
  background: #fff;
}
.custom-step.active {
  box-shadow: 0 0 0 2px #2256F7;
  background-color: #2256F7;
  box-shadow: 0 0 0 2px #2256f7;
  background-color: #2256f7;
}
.tab-item {
@@ -623,7 +731,7 @@
}
.add-icon {
  color: #1194F7;
  color: #1194f7;
}
.active-bg {
@@ -633,7 +741,7 @@
}
.select-active {
  background: #2EBD85;
  background: #2ebd85;
  @include themify() {
    color: themed("text_color") !important;