buy.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. <template>
  2. <view class="withdraw">
  3. <view class="balance-box">
  4. <view>
  5. <view class="balance-title">可用余额</view>
  6. <view class="balance-rmb">
  7. <view style="display: flex; align-items: flex-end">¥</view>
  8. <view class="rmb">{{ appStore.userInfo.nowMoney }}</view>
  9. </view>
  10. </view>
  11. </view>
  12. <view class="tabs">
  13. <view
  14. v-for="item in tabsList"
  15. :key="item.key"
  16. class="tabs-item"
  17. :class="[tabsIndex === item.key ? 'active' : '']"
  18. @click="tabsChange(item)"
  19. >
  20. {{ item.title }}
  21. </view>
  22. </view>
  23. <view class="contanier">
  24. <view class="contaniner-top">
  25. <view class="box-title">克重</view>
  26. <view class="price-box">
  27. <view class="price">
  28. 实时金价
  29. <span class="tit">{{ realprice.toFixed(2) }}</span>
  30. </view>
  31. <view class="equity"
  32. >权益 -{{ rightsStore.userBenefits.buy || "0.00" }}</view
  33. >
  34. </view>
  35. </view>
  36. <view class="input-box">
  37. <input
  38. type="text"
  39. placeholder="请输入克重"
  40. v-model.number="weight"
  41. @input="inputHandle"
  42. />
  43. <view class="g">g</view>
  44. </view>
  45. <view class="buy-price">
  46. <view class="buy-txt">买料价格</view>
  47. <view class="buy-num">{{ buyGoldPrice }}</view>
  48. <view class="t">元</view>
  49. </view>
  50. <view class="btn-box" @click="submitHandle">
  51. <image class="btn" src="/static/images/sb_btn.png"></image>
  52. <text class="btn-text">确认</text>
  53. </view>
  54. <view class="aggregate" @click="aggregate = !aggregate">
  55. <image
  56. class="choose"
  57. :src="
  58. aggregate
  59. ? '/static/recycle/choose.png'
  60. : '/static/recycle/nochoose.png'
  61. "
  62. mode="scaleToFill"
  63. ></image>
  64. <view class="aggre">
  65. 阅读并同意
  66. <span class="aggre-text" @click.stop="showAggre">《买金协议》</span>
  67. </view>
  68. </view>
  69. <view class="white"></view>
  70. </view>
  71. <uni-popup
  72. ref="singPopup"
  73. type="bottom"
  74. borderRadius="10px 10px 0 0"
  75. maskBackgroundColor="rgba(0,0,0,0)"
  76. >
  77. <view class="signContent">
  78. <scroll-view scrollY class="scroll">
  79. <up-parse :content="content"></up-parse>
  80. </scroll-view>
  81. <view
  82. class="comfireBtn footer"
  83. @click="
  84. aggregate = true;
  85. $refs.singPopup.close();
  86. "
  87. >
  88. 我已详细知悉
  89. </view>
  90. </view>
  91. </uni-popup>
  92. </view>
  93. </template>
  94. <script setup>
  95. import { ref, computed, watch, onMounted } from "vue";
  96. import { useAppStore } from "@/stores/app";
  97. import useRealGoldPrice from "@/hooks/useRealGoldPrice";
  98. import { rechargeGoldAPI } from "@/api/functions";
  99. import { agreementGetoneApi } from "@/api/user";
  100. const appStore = useAppStore();
  101. // 响应式数据
  102. const type = ref("余额");
  103. const weight = ref("");
  104. const buyGoldPrice = ref(0);
  105. const aggregate = ref(false);
  106. const content = ref("");
  107. const tabsIndex = ref(1);
  108. const selectedGender = ref("gold");
  109. const tabsList = ref([
  110. { key: 1, label: "gold", title: "黄金" },
  111. { key: 2, label: "platinum", title: "铂金" },
  112. { key: 3, label: "silver", title: "白银" },
  113. ]);
  114. // 实时价格处理
  115. const {
  116. realGoldprice, // 黄金实时销售价(基础)
  117. realPtprice, // 铂金实时销售价(基础)
  118. realAgprice, // 白银实时销售价(基础)
  119. } = useRealGoldPrice({});
  120. import { useStoreRights } from "@/stores/rights";
  121. const rightsStore = useStoreRights();
  122. // 黄金调整价
  123. const adjustGoldprice = computed(() => {
  124. const res = rightsStore.userBenefits.nobleMeta.find(
  125. (gold) => gold.name == "黄金"
  126. );
  127. console.log(res);
  128. return res;
  129. });
  130. // 铂金调整价
  131. const adjustPtprice = computed(() => {
  132. const res = rightsStore.userBenefits.nobleMeta.find(
  133. (gold) => gold.name == "铂金"
  134. );
  135. return res;
  136. });
  137. // 白银调整价
  138. const adjustAgprice = computed(() => {
  139. const res = rightsStore.userBenefits.nobleMeta.find(
  140. (gold) => gold.name == "白银"
  141. );
  142. return res;
  143. });
  144. const viprealGoldprice = computed(
  145. () =>
  146. Number(realGoldprice.value) -
  147. Number(rightsStore.userBenefits.buy) +
  148. Number(adjustGoldprice.value.sellPriceAdjust)
  149. );
  150. const viprealPtprice = computed(
  151. () =>
  152. Number(realPtprice.value) -
  153. Number(rightsStore.userBenefits.buy) +
  154. Number(adjustPtprice.value.sellPriceAdjust)
  155. );
  156. const viprealAgprice = computed(
  157. () =>
  158. Number(realAgprice.value) -
  159. Number(rightsStore.userBenefits.buy) +
  160. Number(adjustAgprice.value.sellPriceAdjust)
  161. );
  162. const realprice = computed(() => {
  163. if (tabsIndex.value == 1) {
  164. return viprealGoldprice.value;
  165. }
  166. if (tabsIndex.value == 2) {
  167. return viprealPtprice.value;
  168. }
  169. if (tabsIndex.value == 3) {
  170. return viprealAgprice.value;
  171. }
  172. });
  173. // 监听器
  174. watch(realprice, (newData) => {
  175. buyGoldPrice.value = (weight.value * realprice.value).toFixed(2);
  176. });
  177. // 获取协议
  178. function agreementGetoneFn() {
  179. // 资产说明
  180. agreementGetoneApi({ name: "buyGold" }).then((res) => {
  181. content.value = res.data?.content;
  182. });
  183. }
  184. // 生命周期钩子 - 替代onLoad
  185. onMounted(() => {
  186. // 页面加载时执行的逻辑]
  187. agreementGetoneFn();
  188. });
  189. const inputHandle = () => {
  190. // buyGoldPrice.value = vk.myfn.accMulDecimal(this.weight, this.realprice, 2);
  191. buyGoldPrice.value = (weight.value * realprice.value).toFixed(2);
  192. };
  193. // 提交
  194. const submitHandle = async () => {
  195. if (checkInfo()) {
  196. uni.showLoading({
  197. title: "买料中",
  198. });
  199. const res = await rechargeGoldAPI({
  200. metalType: tabsIndex.value,
  201. weight: weight.value,
  202. });
  203. // console.log(res);
  204. if (res.code == 200) {
  205. uni.showToast({ title: "买料成功" });
  206. setTimeout(() => {
  207. uni.navigateTo({
  208. url: "/pages/users/vault/index",
  209. });
  210. }, 1500);
  211. }
  212. uni.hideLoading();
  213. }
  214. };
  215. const formatNumber = (num) => {
  216. if (isNaN(num)) return "0.00";
  217. const parts = num.toString().split(".");
  218. parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  219. if (parts.length > 1) {
  220. return parts[0] + "." + parts[1].padEnd(2, "0").slice(0, 2);
  221. }
  222. return parts[0] + ".00";
  223. };
  224. const checkInfo = () => {
  225. if (!weight.value) {
  226. uni.showToast({
  227. title: "请输入克重",
  228. duration: 1000,
  229. icon: "none",
  230. });
  231. return false;
  232. }
  233. if (!aggregate.value) {
  234. uni.showToast({
  235. title: "请阅读并同意协议",
  236. duration: 1000,
  237. icon: "none",
  238. });
  239. return false;
  240. }
  241. return true;
  242. };
  243. // 假设$refs.singPopup在模板中存在
  244. const singPopup = ref(null);
  245. const showAggre = () => {
  246. singPopup.value.open();
  247. };
  248. const tabsChange = (item) => {
  249. tabsIndex.value = item.key;
  250. weight.value = "";
  251. buyGoldPrice.value = 0;
  252. };
  253. const toDecimalP2 = (arg) => {};
  254. </script>
  255. <style lang="scss" scoped>
  256. .withdraw {
  257. width: 750rpx;
  258. height: 100%;
  259. // background-image: linear-gradient(180deg, #b7ad94 0%, #fcfcfc 100%);
  260. background: $uni-bg-primary !important;
  261. display: flex;
  262. flex-direction: column;
  263. // align-items: center;
  264. .balance-box {
  265. height: 300rpx;
  266. padding-left: 60rpx;
  267. color: #000;
  268. display: flex;
  269. align-items: center;
  270. flex-wrap: wrap;
  271. width: 100%;
  272. box-sizing: border-box;
  273. .balance-title {
  274. width: 100%;
  275. font-size: 30rpx;
  276. margin-bottom: 10rpx;
  277. }
  278. .balance-rmb {
  279. width: 100%;
  280. display: flex;
  281. width: 100%;
  282. font-size: 56rpx;
  283. .rmb {
  284. font-size: 56rpx;
  285. margin-left: 10rpx;
  286. }
  287. }
  288. }
  289. .tabs {
  290. display: flex;
  291. height: 80rpx;
  292. border-radius: 40rpx;
  293. padding: 0 20rpx;
  294. color: #000000;
  295. font-size: 30rpx;
  296. .tabs-item {
  297. width: 50%;
  298. height: 100%;
  299. display: flex;
  300. justify-content: center;
  301. // align-items:;
  302. position: relative;
  303. }
  304. .active::after {
  305. position: absolute;
  306. bottom: -10rpx;
  307. left: 50%;
  308. transform: translateX(-50%);
  309. content: "";
  310. z-index: 100;
  311. border-style: solid;
  312. border-width: 0 28rpx 28rpx 28rpx;
  313. border-color: transparent transparent #ffffff transparent;
  314. width: 0;
  315. height: 0;
  316. transform-origin: center top;
  317. animation: showTriangle 0.3s ease-out forwards;
  318. }
  319. }
  320. .contanier {
  321. box-sizing: border-box;
  322. padding: 70rpx 70rpx;
  323. background-color: #ffffff;
  324. border-radius: 40rpx;
  325. .contaniner-top {
  326. display: flex;
  327. justify-content: space-between;
  328. align-items: center;
  329. .price-box {
  330. // flex: 3;
  331. display: flex;
  332. align-items: center;
  333. position: relative;
  334. .price {
  335. font-size: 31rpx;
  336. color: #000000;
  337. .tit {
  338. color: #d8a235;
  339. font-size: 36rpx;
  340. margin-left: 10rpx;
  341. }
  342. }
  343. .equity {
  344. position: absolute;
  345. top: -35rpx;
  346. right: 0;
  347. padding: 2rpx 12rpx;
  348. font-size: 16rpx;
  349. color: #fff;
  350. // background: #cd9933;
  351. background: #ffd034;
  352. // border-radius: 10rpx;
  353. border-top-left-radius: 30rpx;
  354. border-bottom-right-radius: 30rpx;
  355. &::after {
  356. position: absolute;
  357. bottom: -15rpx;
  358. left: 50%;
  359. width: 0;
  360. height: 0;
  361. z-index: 0;
  362. transform: translateX(-50%);
  363. content: "";
  364. // background: red;
  365. border-style: solid;
  366. border-width: 0 10px 10px 10px;
  367. border-color: transparent transparent transparent #ffd034;
  368. }
  369. }
  370. }
  371. }
  372. .input-box {
  373. width: 610rpx;
  374. height: 89rpx;
  375. background-color: #ededed;
  376. border-radius: 10rpx;
  377. padding: 0 30rpx;
  378. box-sizing: border-box;
  379. display: flex;
  380. justify-content: space-between;
  381. align-items: center;
  382. margin: 20rpx 0;
  383. font-size: 25rpx;
  384. color: #999999;
  385. input {
  386. color: #000000;
  387. width: 99%;
  388. }
  389. .g {
  390. font-size: 32rpx;
  391. color: #cc9933;
  392. }
  393. }
  394. .buy-price {
  395. display: flex;
  396. justify-content: center;
  397. font-size: 25rpx;
  398. color: #000000;
  399. align-items: center;
  400. .buy-num {
  401. // color: #cc9933;
  402. color: $txt-color;
  403. font-size: 28rpx;
  404. margin: 0 5rpx;
  405. }
  406. }
  407. .payment-method {
  408. margin-top: 120rpx;
  409. .method-box {
  410. display: flex;
  411. justify-content: space-between;
  412. align-items: center;
  413. margin: 50rpx 0;
  414. .box-left {
  415. display: flex;
  416. justify-content: center;
  417. image {
  418. height: 48rpx;
  419. }
  420. text {
  421. margin-left: 15rpx;
  422. }
  423. }
  424. }
  425. }
  426. .btn-box {
  427. height: 100rpx;
  428. display: flex;
  429. justify-content: center;
  430. align-items: center;
  431. margin-top: 200rpx;
  432. width: 100%;
  433. box-sizing: border-box;
  434. position: relative;
  435. .btn {
  436. height: 70rpx;
  437. width: 260rpx;
  438. }
  439. .btn-text {
  440. font-size: 30rpx;
  441. color: #000;
  442. position: absolute;
  443. top: 50%;
  444. left: 50%;
  445. transform: translate(-50%, -50%);
  446. }
  447. }
  448. .aggregate {
  449. display: flex;
  450. align-items: center;
  451. justify-content: center;
  452. padding: 10px;
  453. .aggre {
  454. font-size: 14px;
  455. margin-left: 10px;
  456. .aggre-text {
  457. color: #cc9933;
  458. }
  459. }
  460. .choose {
  461. width: 16px;
  462. height: 16px;
  463. }
  464. }
  465. .white {
  466. height: 100rpx;
  467. background-color: #ffffff;
  468. }
  469. .box-title {
  470. height: 50rpx;
  471. padding-left: 19rpx;
  472. font-size: 31rpx;
  473. color: #000000;
  474. position: relative;
  475. display: flex;
  476. align-items: center;
  477. &::after {
  478. position: absolute;
  479. bottom: -10rpx;
  480. left: 5rpx;
  481. top: 23%;
  482. transform: translateX(-50%);
  483. content: "";
  484. background-color: #f8c007;
  485. width: 4rpx;
  486. height: 28rpx;
  487. }
  488. }
  489. }
  490. .signContent {
  491. background-color: #f8f8f8;
  492. padding: 20px;
  493. box-sizing: border-box;
  494. display: flex;
  495. justify-content: center;
  496. align-items: center;
  497. flex-direction: column;
  498. border-radius: 20px 20px 0 0;
  499. .scroll {
  500. background-color: #fff;
  501. padding: 4px;
  502. height: 300px;
  503. overflow-y: hidden;
  504. border: 1px solid #dfdfdf;
  505. }
  506. .footer {
  507. margin-top: 10px;
  508. color: #fff;
  509. padding: 4px 20px;
  510. border-radius: 20px;
  511. background: linear-gradient(to right, #8ed187, #5dd665);
  512. }
  513. }
  514. }
  515. </style>