| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- <template>
- <view>
- <view class="d-flex p-md justify-between align-center fn-16 color-light">
- <view @click="$emit('symbol')">
- <i class="iconfont color-theme-1 fn-18"></i>
- {{ symbol }}
- </view>
- <view class="d-flex fn-20 color-theme-1">
- <!-- foucs -->
- <view class="m-r-xs" @click="$emit('option')">
- <van-icon v-if="isCoolect" name="star" />
- <van-icon v-else class="color-default" name="star-o" />
- </view>
- <v-link
- tag="div"
- v-if="symbol"
- :to="{ path: '/pages/exchange/index', query: { code: symbol } }"
- >
- <van-icon name="chart-trending-o" />
- </v-link>
- </view>
- </view>
- <view class="d-flex p-x-md p-b-md">
- <!-- 买卖表单 -->
- <view class="w-6/12">
- <view
- class="d-flex fn-center justify-between rounded-xs overflow-hidden"
- >
- <view
- class="w-6/12 h-34 d-flex justify-center align-center"
- :class="{
- 'bg-form-panel-4 ': form.direction != 'buy',
- 'bg-gradient-blue color-plain': form.direction == 'buy',
- }"
- @click="
- form.direction = 'buy';
- getDefaultPrice();
- "
- >{{ $t("exchange.c3") }}</view
- >
- <view
- class="color-gray w-6/12 h-34 d-flex justify-center align-center"
- :class="{
- 'bg-form-panel-4': form.direction != 'sell',
- 'bg-gradient-blue color-plain': form.direction == 'sell',
- }"
- @click="
- form.direction = 'sell';
- getDefaultPrice();
- "
- >{{ $t("exchange.c4") }}</view
- >
- </view>
- <v-picker :list="typeList" v-model="form.type" class="p-y-xs fn-sm">
- {{ activeType.label }}
- <i class="iconfont"></i>
- </v-picker>
- <template v-if="form.type == 1">
- <view>
- <van-stepper
- :min="0"
- :value="form.entrust_price"
- @change="form.entrust_price = $event.detail"
- input-width="61%"
- step="0.01"
- />
- <view class="tips fn-xs m-t-xs">{{ targetCoin }}</view>
- </view>
- <view class="m-t-xs">
- <v-input
- v-model="form.amount"
- class="h-30 p-x-xs rounded-xs color-light bg-form-panel-4"
- :placeholder="$t('exchange.c5')"
- >
- <template #right>
- <view class="color-default fn-10">{{
- activeCoin.coin_name
- }}</view>
- </template>
- </v-input>
- </view>
- </template>
- <template v-if="form.type == 2">
- <view>
- <v-input
- disabled
- class="h-30 p-x-xs rounded-xs color-light bg-panel-4"
- :placeholder="$t('exchange.c6')"
- ></v-input>
- </view>
- <view class="tips fn-xs m-t-xs color-panel-4">{{ targetCoin }}</view>
- <view class="m-t-xs">
- <v-input
- v-model="form.amount"
- class="h-30 p-x-xs rounded-xs color-light bg-panel-4"
- :placeholder="
- form.direction == 'buy' ? $t('exchange.c7') : $t('exchange.c5')
- "
- >
- <template #right>
- <view class="color-default" v-if="form.direction == 'sell'">{{
- currentCoin
- }}</view>
- <view class="color-default" v-if="form.direction == 'buy'">{{
- targetCoin
- }}</view>
- </template>
- </v-input>
- </view>
- </template>
- <view>
- <view class="tips fn-10 m-t-xs"
- >{{ $t("exchange.c8") }}:{{ usable }}{{ usableUnit }}</view
- >
- </view>
- <view>
- <view class="m-t-xs">
- <view class="d-flex justify-between fn-sm">
- <text>0%</text>
- <text>100%</text>
- </view>
- <view class="d-flex justify-center">
- <bing-progress
- activeColor="#79D47C"
- barBorderRadius="20px"
- handleWidth="12px"
- handleHeight="12px"
- handleColor="#79D47C"
- borderRadius="20px"
- width="150px"
- :showInfo="false"
- strokeWidth="2px"
- noActiveColor="#484859"
- @dragging="sliderChange"
- :value="activeStep"
- />
- </view>
- </view>
- </view>
- <view class="d-flex fn-sm m-b-xs color-light justify-between">
- <span>{{ $t("exchange.c9") }}:</span>
- <span v-if="form.type == 2 && form.direction == 'sell'"
- >{{ totalMoney }} {{ currentCoin }}</span
- >
- <span v-else>{{ totalMoney }} {{ targetCoin }}</span>
- </view>
- <template v-if="isLogin">
- <v-button
- size="small"
- :type="form.direction == 'buy' ? 'green' : 'red'"
- class="w-max rounded-xs"
- block
- @click="storeEntrust"
- ref="btn"
- >{{
- form.direction == "buy"
- ? this.$t("exchange.c3")
- : this.$t("exchange.c4")
- }}
- {{ activeCoin.coin_name }}</v-button
- >
- </template>
- <template v-else>
- <navigator class="d-block" url="/pages/login/index" open-type="reLaunch" hover-class="none">
- <v-button
- size="small"
- block
- :type="form.direction == 'buy' ? 'primary' : 'danger'"
- class="w-max"
- >{{ $t("exchange.d0") }}</v-button
- >
- </navigator>
- </template>
- <v-link
- :to="{ path: '/pages/exchange/index', query: { code: symbol } }"
- class="d-block m-t-md"
- >
- <view class="fn-10 p-y-xs">{{ symbol }} {{ $t("exchange.d1") }}</view>
- <view class="h-100">
- <time-sharing
- :query="query"
- ref="highChart"
- :tradeList="tradeList"
- ></time-sharing>
- </view>
- </v-link>
- </view>
- <!-- 深度列表 -->
- <view class="w-6/12 p-l-md d-flex flex-col dep-list">
- <sell-and-buy
- :buyList="buyList"
- :max="symbol == 'ABK/USDT' ? 14 : 7"
- :sellList="sellList"
- :symbol="symbol"
- >
- <view
- class="fn-md row"
- :class="newPrice.increase < 0 ? 'color-sell' : 'color-buy'"
- >
- {{ newPrice.price }}
- </view>
- <!-- <view class="fn-xs" v-if="newPrice.price">
- ≈{{ omitTo(newPrice.price * price_cny, 2) }}CNY
- </view> -->
- </sell-and-buy>
- </view>
- </view>
- <view class="h-20"></view>
- <view class="p-t-md" style="padding-bottom:60px">
- <view class="fn-lg m-b-md">{{ $t("exchange.d3") }}</view>
- <table class="w-max">
- <thead class="fn-xs">
- <tr>
- <td class="p-y-xs p-l-md">{{ $t("exchange.d4") }}</td>
- <td class="p-y-xs">{{ $t("exchange.d5") }}</td>
- <td class="p-y-xs fn-right">{{ $t("exchange.d2") }}</td>
- <td class="p-y-xs fn-right p-r-md">{{ $t("exchange.c5") }}</td>
- </tr>
- </thead>
- <tbody class="color-light trade-list">
- <!-- ||item.tradeId -->
- <tr v-for="(item, idx) in tradeList" :key="idx">
- <td class="p-y-xs p-l-md rounded-bl-xs rounded-tl-xs">
- {{ parseTime(item.ts, false, "{h}:{i}:{s}") }}
- </td>
- <td :class="`color-${item.direction}`">
- <template v-if="item.direction == 'buy'">{{
- $t("exchange.b5")
- }}</template>
- <template v-else-if="'sell'">{{ $t("exchange.b6") }}</template>
- </td>
- <td class="fn-right">{{ item.price }}</td>
- <td class="p-y-xs fn-right p-r-md rounded-br-xs rounded-tr-xs">
- {{ omitTo(item.amount, 8) * 1 }}
- </td>
- </tr>
- </tbody>
- </table>
- </view>
- </view>
- </template>
- <script>
- import timeSharing from "@/pages/exchange/time-sharing";
- import Exchange from "@/api/exchange";
- import Market from "@/api/market";
- import date from "@/utils/class/date";
- import math from "@/utils/class/math";
- import { mapState } from "vuex";
- import sellAndBuy from "@/pages/exchange/sell-and-buy";
- import bingProgress from "@/components/bing-progress/bing-progress.vue";
- export default {
- props: {
- collect: {
- default() {
- return [];
- },
- type: Array,
- required: false,
- },
- marketList: {
- defalut() {
- return [];
- },
- type: Array,
- required: false,
- },
- query: {
- default: {},
- type: Object,
- required: false,
- },
- isShow: {
- default: true,
- type: Boolean,
- required: false,
- },
- },
- components: {
- timeSharing,
- sellAndBuy,
- bingProgress,
- },
- name: "exchange-transaction",
- data() {
- return {
- buyList: [],
- sellList: [],
- tradeList: [],
- form: {
- direction: "buy",
- type: 1,
- symbol: this.symbol,
- entrust_price: "",
- amount: "",
- trigger_price: undefined,
- total: "",
- },
- balanceMap: {},
- unSymbol: "",
- newPrice: {},
- price_cny: 6.72,
- };
- },
- computed: {
- ...mapState({
- ws: "ws",
- }),
- isLogin() {
- return Boolean(uni.getStorageSync("token"));
- },
- symbol() {
- return this.query.symbol;
- },
- // 是否为自选
- isCoolect() {
- return this.collect.map((item) => item.pair_name).includes(this.symbol);
- },
- typeList() {
- return [
- {
- value: 1,
- label: this.$t("exchange.d6"),
- },
- {
- value: 2,
- label: this.$t("exchange.d7"),
- },
- ];
- },
- activeType() {
- return this.typeList.find((item) => item.value == this.form.type);
- },
- // 当前选中的coin
- activeCoin() {
- if (!this.marketList.length) return {};
- let list = [];
- this.marketList.forEach((parentItem) => {
- parentItem.marketInfoList.forEach((item) => {
- list.push(item);
- });
- });
- return list.find((item) => item.pair_name == this.symbol);
- },
- // 当前币种
- currentCoin() {
- if (!this.symbol) return "";
- return this.symbol.split("/")[0];
- },
- // 目标币种
- targetCoin() {
- if (!this.symbol) return "";
- return this.symbol.split("/")[1];
- },
- // 当前余额
- currentBalance() {
- return this.balanceMap[this.currentCoin] || {};
- },
- // 目标余额
- targetBalance() {
- return this.balanceMap[this.targetCoin] || {};
- },
- // 计算交易额
- totalMoney() {
- // todo
- let totalMoney = 0;
- if (this.form.type == 1) {
- totalMoney = math.multiple(this.form.amount, this.form.entrust_price);
- } else {
- totalMoney = this.form.amount;
- }
- return totalMoney;
- },
- // 显示百分比
- activeStep() {
- let num = 0;
- if (this.form.direction == "buy") {
- if (!this.targetBalance.usable_balance) return 0;
- num = this.totalMoney / this.targetBalance.usable_balance;
- } else if (this.form.direction == "sell") {
- if (!this.currentBalance.usable_balance) return 0;
- num = this.form.amount / this.currentBalance.usable_balance;
- }
- if (!isNaN(num)) {
- num = num.toFixed(3);
- }
- return num * 100;
- },
- // 可用数量
- usable() {
- if (this.form.direction == "buy") {
- if (!this.targetBalance.usable_balance) return 0;
- return this.omitTo(
- this.targetBalance.usable_balance,
- this.activeCoin.price_decimals
- );
- } else {
- if (!this.currentBalance.usable_balance) return 0;
- return this.omitTo(
- this.currentBalance.usable_balance,
- this.activeCoin.qty_decimals
- );
- }
- },
- // 可用单位
- usableUnit() {
- if (this.form.direction == "buy") {
- return this.targetCoin;
- } else {
- return this.currentCoin;
- }
- },
- },
- watch: {
- symbol(n, o) {
- this.getBooks();
- this.getUserBalance();
- if (o) {
- this.unLink(o.replace("/", "").toLocaleLowerCase());
- }
- },
- isShow(n) {
- if (n) {
- this.linkSocket(this.activeCoin.symbol);
- } else {
- this.unLink(this.activeCoin.symbol);
- }
- },
- },
- methods: {
- parseTime: date.parseTime,
- omitTo: math.omitTo,
- // 计算滑动出来的金额
- sliderChange($ev) {
- let num = $ev.value / 100;
- if (this.form.direction == "buy") {
- if (!this.targetBalance.usable_balance) return;
- if (this.form.type == 1) {
- this.form.amount = math.multiple(
- this.targetBalance.usable_balance / this.form.entrust_price,
- num,
- 4
- );
- } else if (this.form.type == 2) {
- this.form.amount = this.form.amount = math.multiple(
- this.targetBalance.usable_balance,
- num,
- 4
- );
- }
- } else if (this.form.direction == "sell") {
- if (!this.currentBalance.usable_balance) return;
- this.form.amount = math.multiple(
- this.currentBalance.usable_balance,
- num,
- 4
- );
- }
- },
- // 提交订单
- storeEntrust() {
- let data = this.form;
- // debugger
- if (this.form.type == 1) {
- //限价
- if (!this.form.entrust_price) {
- this.$toast(this.$t("exchange.d8"));
- return;
- }
- if (!this.form.amount) {
- this.$toast(this.$t("exchange.d9"));
- return;
- }
- } else if (this.form.type == 2) {
- //市价
- this.form.total = this.form.amount;
- if (!this.form.total) {
- if (this.form.direction == "buy") {
- this.$toast(this.$t("exchange.e0"));
- } else {
- this.$toast(this.$t("exchange.d9"));
- }
- return;
- }
- }
- this.form.symbol = this.symbol;
- Exchange.storeEntrust(data, {
- btn: this.$refs.btn,
- })
- .then(() => {
- this.form.amount = "";
- this.form.total = "";
- this.$toast.success(this.$t("exchange.e1"));
- this.getUserBalance();
- })
- .catch(() => {});
- },
- // 获取列表
- getBooks() {
- console.log(this.symbol)
- if (!this.symbol) return;
- Market.getBooks({
- symbol: this.symbol,
- }).then((res) => {
- console.log(res)
- this.buyList = res.data.buyList;
- this.sellList = res.data.sellList;
- this.tradeList = res.data.tradeList;
- this.linkSocket(this.activeCoin.symbol);
- this.setChartData(this.tradeList);
- this.getDefaultPrice();
- this.newPrice = this.tradeList[0] || {};
- });
- // this.getCurrencyExCny()
- },
- // 获取默认价格
- getDefaultPrice() {
- if (this.form.direction == "buy") {
- this.form.entrust_price = Math.min(
- ...this.tradeList.map((item) => item.price)
- );
- } else {
- this.form.entrust_price = Math.max(
- ...this.buyList.map((item) => item.price)
- );
- }
- },
- // 计算深度
- getValue(amount) {
- const arr = this.buyList.concat(this.sellList).map((item) => item.amount);
- let max = Math.max(...arr);
- return math.division(amount, max, 2) * 100;
- },
- selectType() {
- this.$picker(this.typeList, { value: this.form.type }).then((res) => {
- this.form.type = res;
- });
- },
- // 获取余额
- getUserBalance() {
- if (!this.symbol || !this.isLogin) return;
- Exchange.getUserBalance({
- symbol: this.symbol,
- }).then((res) => {
- this.balanceMap = { ...this.balanceMap, ...res.data };
- });
-
- },
- // 获取汇率
- getCurrencyExCny() {
- // console.log(123123)
- Exchange.getCurrencyExCny({
- coin_name: this.targetCoin,
- }).then((res) => {
- console.log(res.data)
- this.price_cny = res.data.price_cny;
-
- });
-
-
- },
- // 链接socket
- linkSocket(symbol) {
- console.log(symbol)
- this.unSymbol = symbol;
- // 订阅买线
- this.ws.send({
- cmd: "sub",
- msg: `buyList_${symbol}`,
- });
- // 订阅卖线
- this.ws.send({
- cmd: "sub",
- msg: `sellList_${symbol}`,
- });
- // 订阅成交
- this.ws.send({
- cmd: "sub",
- msg: `tradeList_${symbol}`,
- });
- },
- // 取消订阅
- unLink(symbol) {
- // 取消买线
- this.ws.send({
- cmd: "unsub",
- msg: `buyList_${symbol}`,
- });
- // 取消卖线
- this.ws.send({
- cmd: "unsub",
- msg: `sellList_${symbol}`,
- });
- // 取消成交
- this.ws.send({
- cmd: "unsub",
- msg: `tradeList_${symbol}`,
- });
- },
- socketMessage() {
- this.ws.on("message", (res) => {
- let symbol = this.activeCoin && this.activeCoin.symbol;
- let { data, sub } = res;
- switch (sub) {
- case `buyList_${symbol}`:
- this.buyList = data;
- break;
- case `sellList_${symbol}`:
- this.sellList = data.sort((a, b) => b.price - a.price);
- break;
- case `tradeList_${symbol}`:
- if (this.tradeList.length > 20) {
- this.tradeList.unshift(data);
- this.tradeList.pop();
- } else {
- this.tradeList.unshift(data);
- }
- this.addChartPoint(data);
- this.newPrice = data;
- break;
- }
- });
- },
- // 设置highChart
- setChartData(arr) {
- if (!this.$refs.highChart) return;
- let list = arr.map((item) => {
- return [item.ts, item.price];
- });
- this.$nextTick(() => {
- this.$refs.highChart.resetData(list);
- });
- },
- // 添加highChart点
- addChartPoint(obj) {
- if (!this.$refs.highChart) return;
- this.$refs.highChart.addPoint([obj.ts, obj.price]);
- },
- },
- mounted() {
- this.getBooks();
- this.getUserBalance();
- this.socketMessage();
- if (this.query.direction) {
- this.form.direction = this.query.direction;
- }
- },
- destroyed() {
- // this.unLink(this.unSymbol);
- },
- };
- </script>
- <style lang="scss" scoped>
- .custom-button {
- min-width: 26px;
- color: #fff;
- line-height: 18px;
- text-align: center;
- border-radius: 100px;
- }
- /deep/ .van-stepper {
- display: flex;
- justify-content: space-between;
- .minus-class,
- .input-class,
- .plus-class {
- background: $form-panel-4;
- }
- }
- .dep-list {
- height: 440px;
- .row {
- position: relative;
- .proagess {
- position: absolute;
- right: 0;
- top: 0;
- transition: width 0.3s;
- }
- }
- }
- ::v-deep .van-step--horizontal {
- .van-step__circle-container {
- background-color: transparent;
- .van-icon-checked {
- width: 14px;
- height: 14px;
- position: relative;
- background: rgba($green, 0.7);
- font-size: 0;
- display: block;
- border-radius: 20px;
- bottom: 9px;
- &::after {
- content: "";
- display: block;
- font-size: 0;
- width: 8px;
- height: 8px;
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- background: $green;
- border-radius: 20px;
- }
- }
- }
- .van-step__line {
- bottom: 8px;
- }
- }
- .trade-list {
- tr:nth-of-type(2n-1) {
- box-shadow: $shadow;
- border-radius: $border-radius-xs;
- td {
- background: $panel-3;
- }
- }
- }
- </style>
|