position.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. <template>
  2. <view>
  3. <view class="p-x-md p-t-md fn-right d-flex justify-between">
  4. <view>
  5. <v-button type="green" class="rounded-lg opt-btn m-b-xs"
  6. @click="onekeyAllFlat">{{ $t("contract.k7") }}</v-button>
  7. </view>
  8. <view class="d-flex align-center" @click="
  9. checked = !checked;
  10. holdPosition();
  11. ">
  12. {{ $t("contract.g3") }}
  13. <van-checkbox class="m-l-xs" :value="checked"></van-checkbox>
  14. </view>
  15. </view>
  16. <van-empty v-if="!list.length" :description="$t('contract.d0')" />
  17. <view class="item bg-panel-4 m-md rounded-sm box-shadow" v-for="item in list" :key="item.id">
  18. <view class="head d-flex align-center border-b p-x-md p-y-xs justify-between">
  19. <view class="d-flex">
  20. <view>
  21. <view class="color-light fn-20">{{ item.pair_name }} </view>
  22. </view>
  23. </view>
  24. <text class="fn-20" :class="item.side == 1 ? 'color-success' : 'color-danger'">
  25. {{ item.side == 1 ? $t("contract.e8") : $t("contract.e9") }}
  26. </text>
  27. <view class="d-flex color-light">
  28. <span>{{ item.lever_rate }}X</span>
  29. </view>
  30. </view>
  31. <view class="p-x-md p-y-xs data-list">
  32. <view class="row d-flex m-y-xs">
  33. <view class="label fn-sm">{{ $t("contract.a1") }}/{{ $t("contract.g5") }}/{{
  34. $t("contract.g4")
  35. }}</view>
  36. <view class="color-light fn-right flex-fill">{{ item.hold_position }}/{{ item.freeze_position }}/{{
  37. item.avail_position
  38. }}</view>
  39. </view>
  40. <view class="d-flex">
  41. <view class="row w-6/12 d-flex m-y-xs justify-between">
  42. <view class="label fn-sm">{{ $t("contract.b1") }}</view>
  43. <view class="color-light">{{ item.position_margin }}</view>
  44. </view>
  45. <view class="row w-6/12 d-flex m-y-xs justify-between">
  46. <view class="label fn-sm">{{ $t("contract.h1") }}/{{ $t("contract.h2") }}</view>
  47. <view class="color-light">
  48. {{ item.tpPrice || "--" }}/{{ item.slPrice || "--" }}
  49. </view>
  50. </view>
  51. </view>
  52. <view class="d-flex">
  53. <view class="row w-6/12 d-flex m-y-xs justify-between">
  54. <view class="label fn-sm">{{ $t("contract.g6") }}</view>
  55. <view class="color-light">{{ item.avg_price }}</view>
  56. </view>
  57. <view class="row w-6/12 d-flex m-y-xs justify-between">
  58. <view class="label fn-sm">{{ $t("contract.h0") }}</view>
  59. <view class="color-light">{{ item.profitRate }}</view>
  60. </view>
  61. </view>
  62. <view class="d-flex">
  63. <view class="row w-6/12 d-flex m-y-xs justify-between">
  64. <view class="label fn-sm">{{ $t("contract.g8") }}</view>
  65. <view class="color-light">{{ item.flatPrice }}</view>
  66. </view>
  67. <view class="row w-6/12 d-flex m-y-xs justify-between">
  68. <view class="label fn-sm">{{ $t("contract.c7") }}</view>
  69. <view class="color-light">{{ item.unRealProfit }}</view>
  70. </view>
  71. </view>
  72. <!-- 买入&市场 -->
  73. <view class="d-flex">
  74. <view class="row w-6/12 d-flex m-y-xs justify-between">
  75. <view class="label fn-sm">{{ $t("exchange.d7") }}</view>
  76. <view class="color-light">{{ item.realtimePrice }}</view>
  77. </view>
  78. <!-- <view class="row w-6/12 d-flex m-y-xs justify-between">
  79. <view class="label fn-sm">{{ $t("contract.h0") }}</view>
  80. <view class="color-light">{{ item.profitRate }}</view>
  81. </view> -->
  82. </view>
  83. <view class="row d-flex m-y-xs justify-between">
  84. <!-- 平仓 -->
  85. <v-button type="green" size="small" class="opt-btn rounded-xs m-b-xs"
  86. @click="closePositionShow(item)">{{ $t("contract.h3") }}</v-button>
  87. <!-- 一建反向 -->
  88. <!-- <v-button type="green" size="small" class="opt-btn rounded-xs m-b-xs m-l-xs"
  89. @click="onekeyReverse(item)">{{ $t("contract.k8") }}</v-button> -->
  90. <!-- <v-button
  91. type="danger"
  92. class="opt-btn m-l-xs m-b-xs"
  93. plain
  94. size="small"
  95. @click="ifCloseAllPosition(item)"
  96. >{{ $t("contract.h4") }}</v-button
  97. > -->
  98. <!-- 止盈止损 -->
  99. <v-button type="blue" class="opt-btn m-l-xs m-b-xs rounded-xs" size="small"
  100. @click="toStoploss(item)">{{ $t("contract.h5") }}</v-button>
  101. <v-button type="green-plain" class="m-l-xs m-b-xs d-inline-block rounded-xs" size="small" plain :to="{
  102. path: '/pages/income/index',
  103. query: {
  104. symbol: item.symbol,
  105. side: item.side,
  106. profitRate: item.profitRate,
  107. lever_rate: item.lever_rate,
  108. pair_name: item.pair_name,
  109. avg_price: item.avg_price,
  110. newPrice: newPrice,
  111. position_side: item.side,
  112. },
  113. }">{{ $t("contract.c8") }}</v-button>
  114. </view>
  115. </view>
  116. </view>
  117. <van-popup :show="show" @close="show = false" closeable position="bottom"
  118. custom-style="height:55%;width:100%;overflow:auto;">
  119. <view>
  120. <view class="p-y-xs p-x-md border-b d-flex align-center">
  121. <view class="p-xs rounded-xs fn-bold" :class="
  122. activeItem.side != 1
  123. ? 'bg-danger-transparent color-danger'
  124. : 'bg-success-transparent color-success'
  125. ">
  126. {{ $t("contract.h6")
  127. }} {{ activeItem.side == 1 ? $t("contract.e8") : $t("contract.e9") }}
  128. </view>
  129. <view class="fn-bold m-x-sm">{{ activeItem.pair_name }}</view>
  130. <view>{{ activeItem.lever_rate }}X</view>
  131. </view>
  132. <view class="p-md">
  133. <v-input class="p-sm rounded border" :placeholder="$t('contract.h7')" type="number"
  134. v-model="form.entrust_price" v-if="activeItem.closeType == 1">
  135. <template #right>
  136. <v-button size="mini" type="theme"
  137. @click="activeItem.closeType = 2">{{ $t("contract.h8") }}</v-button>
  138. </template>
  139. </v-input>
  140. <v-input class="p-sm rounded border bg-panel-1 fn-center color-sell" disabled
  141. :value="$t('contract.d7')" v-else>
  142. <template #right>
  143. <v-button size="mini" type="theme"
  144. @click="activeItem.closeType = 1">{{ $t("contract.d7") }}</v-button>
  145. </template>
  146. </v-input>
  147. <v-input class="p-sm rounded border m-t-sm" :placeholder="$t('contract.h9')" type="number"
  148. v-model="form.amount">
  149. <template #right>
  150. <span class="color-default" style="padding-right: 10rpx;">{{ $t("contract.d8") }}</span>
  151. <v-button size="mini" type="theme" @click="toall">{{ $t("base.d4") }}</v-button>
  152. </template>
  153. </v-input>
  154. <view class="fn-sm m-y-xs">
  155. {{ $t("contract.i0") }} {{ activeItem.avail_position }}
  156. {{ $t("contract.d8") }}
  157. </view>
  158. <!-- 平仓 -->
  159. <v-button type="blue" class="rounded-lg" block @click="closePosition" ref="btn">
  160. {{ $t("contract.h3") }}
  161. </v-button>
  162. <view class="h-55"></view>
  163. </view>
  164. </view>
  165. </van-popup>
  166. <van-popup :show="stoplossShow" @close="stoplossShow = false" closeable position="bottom"
  167. custom-style="height:55%;width:100%:overflow:auto;">
  168. <view>
  169. <view class="p-y-xs p-x-md border-b d-flex align-center">
  170. <view class="p-xs rounded-sm fn-bold" :class="
  171. activeItem.side == 2
  172. ? 'bg-danger-transparent color-danger'
  173. : 'bg-success-transparent color-success'
  174. ">
  175. {{ activeItem.side == 1 ? $t("contract.e8") : $t("contract.e9") }}
  176. </view>
  177. <view class="fn-bold m-x-sm">{{ activeItem.pair_name }}</view>
  178. <view>{{ activeItem.lever_rate }}X</view>
  179. </view>
  180. <view class="p-x-md p-t-md d-flex">
  181. <view class="m-r-md">
  182. <span>{{ $t("contract.a0") }}:</span><span
  183. class="color-light">{{ activeItem.avg_price * 1 }}</span>
  184. </view>
  185. <view>
  186. <span>{{ $t("contract.i2") }}:</span><span
  187. class="color-light">{{ activeItem.realtimePrice }}</span>
  188. </view>
  189. </view>
  190. <view class="p-x-md p-t-0">
  191. <input class="p-sm rounded border m-t-sm" :placeholder="$t('contract.i3')" type="digit"
  192. v-model="strategyForm.tp_trigger_price">
  193. <template #left>
  194. <span class="color-default">{{ $t("contract.i4") }}:</span>
  195. </template>
  196. </input>
  197. <view class="p-t-xs fn-sm color-tips" v-if="strategyForm.tp_trigger_price">
  198. {{ $t("contract.i5") }}{{ strategyForm.tp_trigger_price
  199. }}{{ $t("contract.i6") }}
  200. {{
  201. activeItem.side == 1
  202. ? many(activeItem, strategyForm.tp_trigger_price)
  203. : air(activeItem, strategyForm.tp_trigger_price)
  204. }}
  205. USDT
  206. </view>
  207. <input class="p-sm rounded border m-t-sm" :placeholder="$t('contract.i3')" type="digit"
  208. v-model="strategyForm.sl_trigger_price">
  209. <template #left>
  210. <span class="color-default">{{ $t("contract.i7") }}:</span>
  211. </template>
  212. </input>
  213. <view class="p-t-xs fn-sm color-tips" v-if="strategyForm.sl_trigger_price">
  214. {{ $t("contract.i5") }}{{ strategyForm.sl_trigger_price
  215. }}{{ $t("contract.i8") }}
  216. {{
  217. activeItem.side == 1
  218. ? many(activeItem, strategyForm.sl_trigger_price)
  219. : air(activeItem, strategyForm.sl_trigger_price)
  220. }}
  221. USDT
  222. </view>
  223. <view class="h-10"></view>
  224. <v-button class="m-t-md rounded-lg" type="blue" block @click="stoploss" ref="strateBtn">
  225. {{ $t("contract.i9") }}
  226. </v-button>
  227. <view class="h-55"></view>
  228. </view>
  229. </view>
  230. </van-popup>
  231. </view>
  232. </template>
  233. <script>
  234. import Contract from "@/api/contract";
  235. import {
  236. mapState
  237. } from "vuex";
  238. import math from "@/utils/class/math";
  239. export default {
  240. name: "position",
  241. props: {
  242. symbolLeft: {
  243. default: "",
  244. type: String,
  245. required: false,
  246. },
  247. symbolDetail: {
  248. default: () => {},
  249. type: Object,
  250. },
  251. isShow: {
  252. default: false,
  253. type: Boolean,
  254. required: false,
  255. },
  256. },
  257. data() {
  258. return {
  259. list: [],
  260. checked: false,
  261. show: false,
  262. activeItem: {},
  263. newPrice: 0,
  264. form: {
  265. entrust_price: "",
  266. amount: "",
  267. },
  268. strategyForm: {
  269. symbol: "",
  270. position_side: "",
  271. tp_trigger_price: "",
  272. sl_trigger_price: "",
  273. },
  274. stoplossShow: false,
  275. dtime: null,
  276. };
  277. },
  278. watch: {
  279. symbolLeft(n) {
  280. if (n) this.holdPosition();
  281. },
  282. isShow(n) {
  283. if (n) {
  284. this.holdPosition();
  285. } else {
  286. this.ws.send({
  287. cmd: "unsub",
  288. msg: `swapTradeList_${this.symbolLeft}`,
  289. });
  290. }
  291. },
  292. },
  293. computed: {
  294. ...mapState({
  295. ws: "ws1",
  296. }),
  297. },
  298. methods: {
  299. toall() {
  300. this.form.amount = this.activeItem.avail_position
  301. },
  302. // 多仓盈亏
  303. many(item, newPrice) {
  304. let face = this.symbolDetail.unit_amount;
  305. return math.omitTo(
  306. newPrice - item.avg_price,
  307. 4
  308. );
  309. },
  310. // 空仓盈亏
  311. air(item, newPrice) {
  312. let face = this.symbolDetail.unit_amount;
  313. return math.omitTo(
  314. (item.avg_price - newPrice),
  315. 4
  316. );
  317. },
  318. holdPosition(boo) {
  319. let data = {
  320. symbol: (this.checked && this.symbolLeft) || "",
  321. };
  322. Contract.holdPosition(data, {
  323. loading: !boo
  324. }).then((res) => {
  325. this.list = res.data.filter((item) => item.hold_position);
  326. this.list = Object.assign([], this.list)
  327. if (!boo) {
  328. this.sendPrice();
  329. }
  330. });
  331. },
  332. // 限价平仓
  333. closePositionShow(item) {
  334. this.activeItem = item;
  335. this.$set(this.activeItem, "closeType", 1);
  336. this.show = true;
  337. },
  338. // 获取买卖盘
  339. getMarketInfo() {
  340. let data = {
  341. symbol: this.symbolLeft,
  342. };
  343. Contract.getMarketInfo(data).then((res) => {
  344. this.newPrice = res.data.swapTradeList[0].price;
  345. });
  346. },
  347. closePosition() {
  348. if (!this.form.amount) {
  349. return this.$toast(this.$t('contract.h9'))
  350. }
  351. let data = {
  352. entrust_id: this.activeItem.entrust_id,
  353. side: this.activeItem.side == 1 ? 2 : 1,
  354. type: this.activeItem.closeType,
  355. symbol: this.activeItem.symbol,
  356. entrust_price: this.form.entrust_price || 0,
  357. amount: this.form.amount,
  358. };
  359. // console.log(data);
  360. Contract.closePosition(data, {
  361. btn: this.$refs.btn
  362. }).then(() => {
  363. this.show = false;
  364. this.form.entrust_price = "";
  365. this.form.amount = "";
  366. this.holdPosition();
  367. this.$toast(this.$t("contract.j0"));
  368. });
  369. },
  370. // 一键平仓
  371. ifCloseAllPosition(item) {
  372. this.$dialog
  373. .confirm({
  374. title: this.$t("contract.c4"),
  375. message: `${this.$t("contract.j1")}${item.pair_name}?`,
  376. confirmButtonText: this.$t("common.confirm"),
  377. cancelButtonText: this.$t("common.cancel")
  378. })
  379. .then(() => {
  380. this.closeAllPosition(item);
  381. });
  382. },
  383. closeAllPosition(item) {
  384. let data = {
  385. symbol: item.symbol,
  386. side: item.side == 1 ? 2 : 1,
  387. };
  388. Contract.closeAllPosition(data, {
  389. loading: true,
  390. }).then(() => {
  391. this.$toast(
  392. `${this.$t("contract.j2")}${item.pair_name}${this.$t("contract.j3")}`
  393. );
  394. this.holdPosition();
  395. });
  396. },
  397. // 获取最新价格
  398. sendPrice() {
  399. this.ws.send({
  400. cmd: "sub",
  401. msg: `swapTradeList_${this.symbolLeft}`,
  402. });
  403. },
  404. socketMessage() {
  405. this.ws.on("message", (res) => {
  406. let symbol = this.symbolLeft;
  407. let {
  408. data,
  409. sub
  410. } = res;
  411. switch (sub) {
  412. case `swapTradeList_${symbol}`:
  413. this.newPrice = data.price;
  414. break;
  415. }
  416. });
  417. },
  418. // 止盈止损
  419. toStoploss(item) {
  420. this.activeItem = item;
  421. this.strategyForm.symbol = this.activeItem.symbol;
  422. this.strategyForm.position_side = this.activeItem.side;
  423. this.strategyForm.entrust_id = item.entrust_id
  424. this.stoplossShow = true;
  425. },
  426. stoploss() {
  427. Contract.setStrategy(this.strategyForm, {
  428. btn: this.$refs.strateBtn,
  429. }).then(() => {
  430. this.strategyForm.tp_trigger_price = "";
  431. this.strategyForm.sl_trigger_price = "";
  432. this.stoplossShow = false;
  433. this.$toast(this.$t("contract.j4"));
  434. });
  435. },
  436. // 一键全平
  437. onekeyAllFlat() {
  438. this.$dialog
  439. .confirm({
  440. title: this.$t("contract.c4"),
  441. message: this.$t("contract.k9") + `?`,
  442. cancelButtonText: this.$t('common.cancelButtonText'),
  443. confirmButtonText: this.$t('common.confirmButtonText')
  444. })
  445. .then(() => {
  446. Contract.onekeyAllFlat({}).then(() => {
  447. this.holdPosition(true);
  448. this.$toast(this.$t("contract.l0"));
  449. });
  450. });
  451. },
  452. // 一键反向
  453. onekeyReverse(item) {
  454. this.$dialog
  455. .confirm({
  456. title: this.$t("contract.c4"),
  457. message: this.$t("contract.l1") + `?`,
  458. cancelButtonText: this.$t('common.cancelButtonText'),
  459. confirmButtonText: this.$t('common.confirmButtonText')
  460. })
  461. .then(() => {
  462. Contract.onekeyReverse({
  463. entrust_id: item.entrust_id,
  464. symbol: item.symbol,
  465. position_side: item.side,
  466. }).then(() => {
  467. this.holdPosition(true);
  468. this.$toast(this.$t("contract.l2"));
  469. });
  470. });
  471. },
  472. },
  473. mounted() {
  474. if (this.symbolLeft) {
  475. this.getMarketInfo();
  476. this.holdPosition();
  477. }
  478. this.dtime = setInterval(() => {
  479. if (this.symbolLeft) {
  480. this.holdPosition(true);
  481. }
  482. }, 3000);
  483. },
  484. beforeDestroy() {
  485. clearInterval(this.dtime);
  486. this.ws.send({
  487. cmd: "unsub",
  488. msg: `swapTradeList_${this.symbolLeft}`,
  489. });
  490. },
  491. };
  492. </script>
  493. <style lang="scss" scoped>
  494. .data-list {
  495. .row:first-of-type {
  496. margin-right: $padding-sm;
  497. }
  498. }
  499. </style>