index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. <template>
  2. <v-page>
  3. <v-header
  4. :leftClick="() =>back()"
  5. :left-arrow="false"
  6. >
  7. <template #left>
  8. <view>
  9. <van-icon name="arrow-left" />
  10. </view>
  11. <view
  12. class="fn-20 color-light m-l-xs"
  13. @click.stop="symbolListShow = true"
  14. >
  15. <i class="iconfont color-theme-1">&#xe655;</i>
  16. {{ query.code }}
  17. </view>
  18. </template>
  19. <template #right>
  20. <view class="fn-lg" @click="option">
  21. <van-icon v-if="isCoolect" class="color-theme-1" name="star" />
  22. <van-icon v-else name="star-o" />
  23. </view>
  24. </template>
  25. </v-header>
  26. <view class="layout-main" :style="this.clientHeigth">
  27. <view
  28. class="price-data d-flex p-t-xs p-x-md justify-between bg-panel-3 m-x-md rounded-xs"
  29. >
  30. <view class="col">
  31. <view class="num fn-20 color-light">
  32. {{ activeCoin.price }}
  33. </view>
  34. <view class="d-flex">
  35. <view
  36. class="m-l-xs fn-20"
  37. :class="activeCoin.increase < 0 ? 'color-sell' : 'color-buy'"
  38. >
  39. {{ activeCoin.increaseStr }}
  40. </view>
  41. </view>
  42. </view>
  43. <view class="col fn-right justify-center d-flex flex-col">
  44. <table>
  45. <tr>
  46. <td>24H {{ $t("exchange.e3") }}</td>
  47. <td class="color-light">{{ activeCoin.high }}</td>
  48. </tr>
  49. <tr>
  50. <td>24H {{ $t("exchange.e4") }}</td>
  51. <td class="color-light">{{ activeCoin.low }}</td>
  52. </tr>
  53. <tr v-if="!query.contract">
  54. <td>24H {{ $t("exchange.e5") }}</td>
  55. <td class="color-light">{{ activeCoin.vol }}</td>
  56. </tr>
  57. </table>
  58. </view>
  59. </view>
  60. <van-tabs
  61. :border="false"
  62. :active="activeTime"
  63. animated
  64. :ellipsis="false"
  65. @change="tabInterval($event.detail.name)"
  66. >
  67. <van-tab
  68. v-for="item in resolutions"
  69. :name="item.value"
  70. :title="item.label"
  71. :key="item.label"
  72. >
  73. </van-tab>
  74. </van-tabs>
  75. <view class="chart-box">
  76. <iframe
  77. class="chart-tradingview"
  78. :src="`${mobileBase}static/tradingview.html?${setQuery(iframeQuery)}`"
  79. frameborder="0"
  80. ></iframe>
  81. </view>
  82. <van-tabs
  83. animated
  84. swipeable
  85. v-model="active"
  86. sticky
  87. :ellipsis="false"
  88. offset-top="1.22667rem"
  89. >
  90. <van-tab
  91. v-if="this.query.code !== 'ABK/USDT'"
  92. :title="$t('exchange.e6')"
  93. >
  94. <sale :buyList="buyList" :sellList="sellList" />
  95. </van-tab>
  96. <van-tab :title="$t('exchange.d3')">
  97. <latest-transaction :tradeList="tradeList" />
  98. </van-tab>
  99. <van-tab :title="$t('exchange.e7')">
  100. <coin-info :query="query" />
  101. </van-tab>
  102. </van-tabs>
  103. </view>
  104. <!-- 左侧的弹窗 -->
  105. <van-popup
  106. class="bg-panel-4"
  107. :show="symbolListShow"
  108. @close="symbolListShow = false"
  109. close-on-popstate
  110. position="left"
  111. custom-style="height:100%;width:70%"
  112. >
  113. <symbol-list
  114. :collect="collect"
  115. :marketList="marketList"
  116. :title="query.contract ? $t('contract.a4') : ''"
  117. @check-symbol="checkSymbol"
  118. />
  119. </van-popup>
  120. <view class="btn-group footer d-flex p-md">
  121. <view class="buyBtn jybtn" @click="buyFunc">{{ $t("exchange.c3") }}</view>
  122. <view class="sellBtn jybtn" @click="sellFunc">{{
  123. $t("exchange.c4")
  124. }}</view>
  125. <!-- <v-button
  126. block
  127. class="flex-fill m-r-md rounded-lg pjwidth"
  128. type="green"
  129. replace
  130. :to="{
  131. path: '/pages/base/index',
  132. query: {
  133. symbol: query.code,
  134. direction: 'buy',
  135. tel: query.contract ? 'contract' : 'exchange-operation',
  136. },
  137. }"
  138. >{{ $t("exchange.c3") }}</v-button
  139. >
  140. <v-button
  141. block
  142. class="flex-fill rounded-lg pjwidth"
  143. type="blue"
  144. replace
  145. :to="{
  146. path: '/pages/base/index',
  147. query: {
  148. symbol: query.code,
  149. direction: 'sell',
  150. tel: query.contract ? 'contract' : 'exchange-operation',
  151. },
  152. }"
  153. >{{ $t("exchange.c4") }}</v-button
  154. > -->
  155. </view>
  156. <van-toast id="van-toast" />
  157. </v-page>
  158. </template>
  159. <script>
  160. import sale from "./sale";
  161. import symbolList from "./symbol-list";
  162. import latestTransaction from "./latest-transaction";
  163. import coinInfo from "./coin-info";
  164. import Market from "@/api/market";
  165. import Contract from "@/api/contract";
  166. import Home from "@/api/home";
  167. import { mapState } from "vuex";
  168. import math from "@/utils/class/math";
  169. import Exchange from "@/api/exchange";
  170. import qs from "qs";
  171. import app from "app.js";
  172. // 所使用的请求
  173. let ajaxExchangeMap = {
  174. getMarketList: Market.getMarketList,
  175. getBooks: Market.getBooks,
  176. sell: "sellList_",
  177. sellList: "sellList",
  178. buy: "buyList_",
  179. buyList: "buyList",
  180. trade: "tradeList_",
  181. tradeList: "tradeList",
  182. market: "exchangeMarketList",
  183. getSymbol(name) {
  184. return name;
  185. },
  186. };
  187. let contractExchangeMap = {
  188. getMarketList: Contract.getMarketList,
  189. getBooks: Contract.getMarketInfo,
  190. sell: "swapSellList_",
  191. sellList: "swapSellList",
  192. buy: "swapBuyList_",
  193. buyList: "swapBuyList",
  194. trade: "swapTradeList_",
  195. tradeList: "swapTradeList",
  196. market: "swapMarketList",
  197. getSymbol(name) {
  198. return name.split("/")[0];
  199. },
  200. };
  201. export default {
  202. components: {
  203. sale,
  204. symbolList,
  205. latestTransaction,
  206. coinInfo,
  207. },
  208. data() {
  209. return {
  210. timeFilter: false,
  211. indexFilter: false,
  212. symbolListShow: false,
  213. active: 0,
  214. buyList: [],
  215. sellList: [],
  216. tradeList: [],
  217. activeTime: "5",
  218. index: "",
  219. marketList: [],
  220. collect: [],
  221. unSymbol: "",
  222. query: {},
  223. isLoad: false,
  224. isShow: true,
  225. price_cny: 0,
  226. app,
  227. clientHeigth: "",
  228. };
  229. },
  230. watch: {
  231. timeFilter(n) {
  232. if (n) this.indexFilter = false;
  233. },
  234. indexFilter(n) {
  235. if (n) this.timeFilter = false;
  236. },
  237. },
  238. computed: {
  239. resolutions() {
  240. let arr = [
  241. {
  242. label: "1 " + this.$t("exchange.e10"),
  243. value: "1",
  244. },
  245. {
  246. label: "5 " + this.$t("exchange.e8"),
  247. value: "5",
  248. },
  249. {
  250. label: "15 " + this.$t("exchange.e8"),
  251. value: "15",
  252. },
  253. {
  254. label: "30 " + this.$t("exchange.e8"),
  255. value: "30",
  256. },
  257. {
  258. label: "1 " + this.$t("exchange.e9"),
  259. value: "60",
  260. },
  261. {
  262. label: "1 " + this.$t("exchange.f0"),
  263. value: "1D",
  264. },
  265. {
  266. label: "1 " + this.$t("exchange.f1"),
  267. value: "1W",
  268. },
  269. {
  270. label: "1 " + this.$t("exchange.f2"),
  271. value: "1M",
  272. },
  273. ];
  274. return arr;
  275. },
  276. activeTimeObj() {
  277. return this.resolutions.find((item) => item.value == this.activeTime);
  278. },
  279. isLogin() {
  280. return Boolean(uni.getStorageSync("token"));
  281. },
  282. // 当前选中的coin
  283. activeCoin() {
  284. if (!this.marketList.length) return {};
  285. let list = [];
  286. this.marketList.forEach((parentItem) => {
  287. parentItem.marketInfoList.forEach((item) => {
  288. list.push(item);
  289. });
  290. });
  291. let bb = list.find((item) => item.pair_name == this.query.code)
  292. console.log(bb.price)
  293. return bb
  294. // return list.find((item) => item.pair_name == this.query.code);
  295. },
  296. // 是否为自选
  297. isCoolect() {
  298. return this.collect
  299. .map((item) => item.pair_name)
  300. .includes(this.query.code);
  301. },
  302. ...mapState({
  303. socket: "ws",
  304. socket1: "ws1",
  305. theme: "theme",
  306. }),
  307. ajax() {
  308. return this.query.contract ? contractExchangeMap : ajaxExchangeMap;
  309. },
  310. ws() {
  311. return this.query.contract ? this.socket1 : this.socket;
  312. },
  313. iframeQuery() {
  314. if (this.query.contract) {
  315. return {
  316. getLinkUrl: this.app.baseUrl + "/api/app/contract/getKline",
  317. symbol: this.query.code.split("/")[0],
  318. theme: this.theme,
  319. ws: this.app.socketUrl1,
  320. interval: this.activeTime,
  321. resolutions: this.resolutions.map((item) => item.value),
  322. contract: 1,
  323. };
  324. } else {
  325. return {
  326. getLinkUrl: this.app.baseUrl + "/api/app/option/getKline",
  327. symbol: this.query.code,
  328. theme: this.theme,
  329. ws: this.app.socketUrl,
  330. interval: this.activeTime,
  331. resolutions: this.resolutions.map((item) => item.value),
  332. };
  333. }
  334. },
  335. mobileBase() {
  336. // #ifdef APP-PLUS
  337. if (plus.os.name == "Android") {
  338. return "";
  339. //return this.app.mobile+'/';
  340. } else {
  341. return this.app.mobile + "/";
  342. }
  343. // #endif
  344. // #ifdef H5
  345. return "/";
  346. // #endif
  347. },
  348. },
  349. methods: {
  350. setQuery: qs.stringify,
  351. omitTo: math.omitTo,
  352. // 页面通知图形
  353. tabInterval(idx) {
  354. // if (this.isLoad) return;
  355. // this.isLoad = true;
  356. this.activeTime = idx;
  357. },
  358. // 图形通知页面
  359. changeInterval($ev) {
  360. this.activeTime = $ev;
  361. setTimeout(() => {
  362. this.isLoad = false;
  363. }, 300);
  364. },
  365. getBooks() {
  366. this.ajax
  367. .getBooks({
  368. symbol: this.ajax.getSymbol(this.query.code),
  369. })
  370. .then((res) => {
  371. this.buyList = res.data[this.ajax.buyList];
  372. this.sellList = res.data[this.ajax.sellList];
  373. this.tradeList = res.data[this.ajax.tradeList];
  374. });
  375. },
  376. // 获取市场行情
  377. getMarketList() {
  378. this.ajax.getMarketList().then((res) => {
  379. this.marketList = res.data.filter(item => {
  380. return item.coin_name != 'BTC' && item.coin_name != 'ETH'
  381. });
  382. this.linkSocket(this.activeCoin.symbol);
  383. this.symbolListSocket();
  384. });
  385. },
  386. // 获取自选列表
  387. getCollect() {
  388. if (!this.isLogin) return;
  389. Home.getCollect()
  390. .then((res) => {
  391. this.collect = res.data || [];
  392. })
  393. .catch(() => {});
  394. },
  395. // 切换币种
  396. checkSymbol(obj) {
  397. this.symbolListShow = false;
  398. if (obj.pair_name == this.query.code) return;
  399. this._router.replace({
  400. path: "/pages/exchange/index",
  401. query: { code: obj.pair_name, contract: this.query.contract },
  402. });
  403. this.getBooks();
  404. },
  405. // 添加自选
  406. option() {
  407. let data = {
  408. pair_name: this.query.code,
  409. };
  410. Home.option(data)
  411. .then((res) => {
  412. this.getCollect();
  413. if (res.data) {
  414. this.$toast(this.$t("exchange.a6"));
  415. } else {
  416. this.$toast(this.$t("exchange.a7"));
  417. }
  418. })
  419. .catch(() => {});
  420. },
  421. // 获取汇率
  422. getCurrencyExCny() {
  423. Exchange.getCurrencyExCny({
  424. coin_name: this.query.code.split("/")[1],
  425. }).then((res) => {
  426. this.price_cny = res.data.price_cny;
  427. });
  428. },
  429. // 链接socket
  430. linkSocket(symbol) {
  431. console.log(this.query.contract,'this.query.contract')
  432. this.unSymbol = symbol;
  433. console.log(this.ws,'this.ws','this.unSymbol',this.unSymbol);
  434. // 订阅买线
  435. this.ws.send({
  436. cmd: "sub",
  437. msg: `${this.ajax.buy}${symbol}`,
  438. });
  439. // 订阅卖线
  440. this.ws.send({
  441. cmd: "sub",
  442. msg: `${this.ajax.sell}${symbol}`,
  443. });
  444. // 订阅成交
  445. this.ws.send({
  446. cmd: "sub",
  447. msg: `${this.ajax.trade}${symbol}`,
  448. });
  449. },
  450. // 取消订阅
  451. unLink(symbol) {
  452. // 取消买线
  453. this.ws.send({
  454. cmd: "unsub",
  455. msg: `${this.ajax.buy}${symbol}`,
  456. });
  457. // 取消卖线
  458. this.ws.send({
  459. cmd: "unsub",
  460. msg: `${this.ajax.sell}${symbol}`,
  461. });
  462. // 取消成交
  463. this.ws.send({
  464. cmd: "unsub",
  465. msg: `${this.ajax.trade}${symbol}`,
  466. });
  467. },
  468. // 左侧的socket 不做切换要单独开来
  469. symbolListSocket() {
  470. this.ws.send({
  471. cmd: "sub",
  472. msg: this.ajax.market,
  473. });
  474. },
  475. // 接受socket
  476. socketMessage() {
  477. this.ws.on("message", (res) => {
  478. if (!this.isShow) return;
  479. let { data, sub } = res;
  480. let symbol = ''
  481. if(this.query.contract){
  482. symbol = this.activeCoin.symbol;
  483. }else{
  484. symbol = this.query.code.replace("/", "").toLocaleLowerCase();
  485. }
  486. if (sub == this.ajax.market) {
  487. this.marketList = data.filter(item => {
  488. return item.coin_name != 'BTC' && item.coin_name != 'ETH'
  489. });
  490. }
  491. if (sub == `${this.ajax.buy}${symbol}`) {
  492. this.buyList = data;
  493. }
  494. if (sub == `${this.ajax.sell}${symbol}`) {
  495. this.sellList = data;
  496. }
  497. if (sub == `${this.ajax.trade}${symbol}`) {
  498. console.log(data,'data')
  499. this.tradeList.unshift(data);
  500. this.tradeList.pop();
  501. }
  502. });
  503. },
  504. getHeightScreen() {
  505. //改动的mmmm
  506. // #ifdef H5
  507. var oMeta = document.createElement("meta");
  508. oMeta.content = "yes";
  509. oMeta.name = "apple-mobile-web-app-capable";
  510. document.getElementsByTagName("head")[0].appendChild(oMeta);
  511. // #endif
  512. // let clientHieght = document.documentElement.clientHeight;
  513. let clientHieght = '100px';
  514. console.log(clientHieght);
  515. let mainHeight = clientHieght - 100;
  516. this.clientHeigth = 'max-height:'+mainHeight+'px';
  517. },
  518. buyFunc() {
  519. // this._router.replace({
  520. // path: "/pages/base/index",
  521. // query: {
  522. // symbol: this.query.code,
  523. // direction: "buy",
  524. // tel: this.query.contract ? "contract" : "exchange-operation",
  525. // },
  526. // });
  527. let symbol= this.query.code
  528. let direction = "buy"
  529. let tel = this.query.contract ? "contract" : "exchange-operation"
  530. // console.log(this.query)
  531. uni.setStorageSync('bbsymbol',symbol)
  532. uni.setStorageSync('bbdirection',direction)
  533. uni.switchTab({
  534. url:`/pages/base/exchange-operation?symbol=${symbol}&direction=${direction}&tel=${tel}`
  535. })
  536. // if(this.query.type && this.query.type == 'bb') {
  537. // uni.setStorageSync('bbsymbol',symbol)
  538. // uni.setStorageSync('bbdirection',direction)
  539. // uni.switchTab({
  540. // url:`/pages/base/exchange-operation?symbol=${symbol}&direction=${direction}&tel=${tel}`
  541. // })
  542. // }else {
  543. // uni.switchTab({
  544. // url:`/pages/base/contract?symbol=${symbol}&direction=${direction}&tel=${tel}`
  545. // })
  546. // }
  547. },
  548. sellFunc() {
  549. // this._router.replace({
  550. // path: "/pages/base/index",
  551. // query: {
  552. // symbol: this.query.code,
  553. // direction: "sell",
  554. // tel: this.query.contract ? "contract" : "exchange-operation",
  555. // },
  556. // });
  557. let symbol= this.query.code
  558. let direction = "sell"
  559. let tel = this.query.contract ? "contract" : "exchange-operation"
  560. if(this.query.type && this.query.type == 'bb') {
  561. uni.setStorageSync('bbsymbol',symbol)
  562. uni.setStorageSync('bbdirection',direction)
  563. uni.switchTab({
  564. url:`/pages/base/exchange-operation?symbol=${symbol}&direction=${direction}&tel=${tel}`
  565. })
  566. }else {
  567. uni.switchTab({
  568. url:`/pages/base/contract?symbol=${symbol}&direction=${direction}&tel=${tel}`
  569. })
  570. }
  571. },
  572. back(){
  573. uni.switchTab({
  574. url:'/pages/base/option-list'
  575. })
  576. // uni.navigateBack()
  577. }
  578. },
  579. onUnload() {
  580. this.isShow = false;
  581. this.unLink(this.unSymbol);
  582. },
  583. onLoad(query) {
  584. this.getHeightScreen();
  585. this.query = query;
  586. this.isShow = true;
  587. this.getBooks();
  588. this.getMarketList();
  589. this.getCollect();
  590. this.socketMessage();
  591. // this.getCurrencyExCny();
  592. },
  593. destroyed() {
  594. this.ws.send({
  595. cmd: "unsub",
  596. msg: this.ajax.market,
  597. });
  598. this.unLink(this.unSymbol);
  599. },
  600. };
  601. </script>
  602. <style lang="scss" scoped>
  603. .price-data {
  604. position: relative;
  605. .filter {
  606. label {
  607. .button {
  608. border: none;
  609. background: none;
  610. &:active {
  611. color: $theme-1;
  612. }
  613. }
  614. input {
  615. display: none;
  616. }
  617. .filter-panel {
  618. position: absolute;
  619. top: 103%;
  620. left: $padding-md;
  621. right: $padding-md;
  622. overflow: hidden;
  623. button {
  624. background: none;
  625. border: none;
  626. &.active,
  627. &:active {
  628. color: $theme-1;
  629. }
  630. }
  631. }
  632. }
  633. }
  634. }
  635. .chart-tradingview {
  636. height: 450px;
  637. width: 100%;
  638. }
  639. .footer {
  640. box-shadow: var(--tab-nav-shadow, 0 -7px 20px 0 rgba(37, 37, 48, 0.83));
  641. position: fixed;
  642. bottom: 0;
  643. width: 100%;
  644. z-index: 99;
  645. background: var(--ronqi);
  646. }
  647. .pjwidth {
  648. width: 250upx !important;
  649. overflow: hidden;
  650. }
  651. .buyBtn {
  652. background: linear-gradient(328deg, #2fad66 0%, #9de686 100%);
  653. }
  654. .sellBtn {
  655. background: linear-gradient(315deg, #4048ef 0%, #5a7bef 100%);
  656. }
  657. .jybtn {
  658. width: 300upx;
  659. color: var(--dd);
  660. border-radius: 60upx;
  661. padding: 20upx;
  662. text-align: center;
  663. display: inline-block;
  664. margin-right: 10upx;
  665. }
  666. </style>