| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694 |
- <template>
- <view class="withdraw">
- <view class="withdrawContent">
- <view class="tabs">
- <view
- v-for="item in tabsList"
- :key="item.key"
- class="tabs-item"
- :class="[tabsIndex === item.key ? 'active' : '']"
- @click="tabsChange(item)"
- >
- {{ item.title }}
- </view>
- </view>
- <!-- 提料克重输入模块 -->
- <view class="gold-box">
- <view class="gold-item">
- <view class="header">
- <h3 class="title">提料克重</h3>
- </view>
- <view class="input-box">
- <input
- v-model.number="extract"
- placeholder="请输入克数"
- type="digit"
- class="t-input"
- @input="onKeyInput"
- />
- </view>
- <view class="infoMoney" style="font-size: 16px">
- <view v-if="is_out">
- <text class="info-money-num" style="color: #ff1e0f">
- 输入克重超过可提现克重,账户克重{{ accountWeight }}克
- </text>
- </view>
- <view v-else-if="is_lowest">
- <text class="info-money-num" style="color: #ff1e0f">
- 最低{{ lowest }}克起兑换,账户克重{{
- accountWeight
- }}克,且最多两位小数
- </text>
- </view>
- <view v-else class="infoMoneyNum">
- <view> 手续费:{{ totalFee }}元,{{ feePerGram }}元/g </view>
- <view>账户克重:{{ accountWeight }}克</view>
- </view>
- <!-- <view class="infoTip">*默认融成小圆饼寄出</view> -->
- </view>
- <view class="remark-box">
- <view class="header">
- <h3 class="title">备注</h3>
- </view>
- <view class="input-box" style="margin-top: 20rpx">
- <input
- v-model="remark"
- placeholder="请输入备注(如特殊需求、收货说明等)"
- type="text"
- class="t-input"
- maxlength="50"
- />
- </view>
- </view>
- </view>
- </view>
- <view class="order-list" @click="gotoOrderList">
- 订单/预约列表 {{ ">" }}
- </view>
- <!-- 提交按钮 -->
- <view class="withdraw-bottom">
- <view
- :class="['submitBtn', is_post ? '' : 'submitBtnActive']"
- style="margin-top: 10px"
- :style="{
- opacity: isSubmitting ? 0.7 : 1,
- pointerEvents: isSubmitting ? 'none' : 'auto',
- }"
- >
- <button @click="handleShowModel">
- <text v-if="!isSubmitting">前往预约</text>
- <text v-if="isSubmitting">提交中...</text>
- </button>
- </view>
- </view>
- <view>
- <up-parse :content="content"></up-parse>
- </view>
- </view>
- <!-- 预约日期选择弹窗 -->
- <appointmentCalendar
- ref="calendarRef"
- :metalType="tabsIndex"
- :reservedWeight="extract"
- @confirm="onDateConfirm"
- />
- </view>
- </template>
- <script setup>
- import { ref, computed, nextTick, watch } from "vue";
- import { onLoad } from "@dcloudio/uni-app";
- import { storeToRefs } from 'pinia';
- // 导入API/组件/Store
- import { quotaByWeight, createReservation } from "@/api/vault";
- import appointmentCalendar from "@/components/appointmentCalendar";
- import { useAppStore } from "@/stores/app";
- import { agreementGetoneApi } from "@/api/user";
- import { toLogin } from "@/libs/login.js";
- // 初始化Store
- const appStore = useAppStore();
- const { wxConfig, isWxConfigReady } = storeToRefs(appStore);
- // 核心响应式数据
- const tabsList = ref([
- { key: 1, label: "gold", title: "黄金" },
- { key: 2, label: "platinum", title: "铂金" },
- { key: 3, label: "silver", title: "白银" },
- ]);
- const tabsIndex = ref(1);
- const extract = ref(0);
- const is_out = ref(false);
- const is_lowest = ref(false);
- const isSubmitting = ref(false);
- const metalConfigs = ref([]);
- const remark = ref("");
- // 日历预约数据
- const calendarRef = ref(null);
- const selectedAppointmentDate = ref(null);
- // 金属类型映射
- const typeMap = { 1: "au", 2: "pt", 3: "ag" };
- // 获取协议
- const content = ref("");
- function agreementGetoneFn() {
- // 资产说明
- agreementGetoneApi({ name: "metal_exchange_content" }).then((res) => {
- content.value = res.data?.content;
- });
- }
- // 动态计算参数
- const feePerGram = computed(() => {
- if (!metalConfigs.value.length) return "0.00";
- const currentType = typeMap[tabsIndex.value];
- const currentConfig = metalConfigs.value.find(
- (item) => item.metalType === currentType
- );
- return currentConfig?.feePerGram
- ? Number(currentConfig.feePerGram).toFixed(2)
- : "0.00";
- });
- const lowest = computed(() => {
- if (!metalConfigs.value.length) return 0;
- const currentType = typeMap[tabsIndex.value];
- const currentConfig = metalConfigs.value.find(
- (item) => item.metalType === currentType
- );
- return currentConfig?.minimumWithdrawalWeight
- ? Number(currentConfig.minimumWithdrawalWeight)
- : 0;
- });
- const totalFee = computed(() => {
- const fee = Number(feePerGram.value);
- const weight = Number(extract.value);
- return (fee * weight).toFixed(2);
- });
- const accountWeight = computed(() => {
- const weightMap = {
- 1: appStore.userInfo.goldBalance || 0,
- 2: appStore.userInfo.ptBalance || 0,
- 3: appStore.userInfo.agBalance || 0,
- };
- return Number(weightMap[tabsIndex.value]).toFixed(2);
- });
- // 页面加载
- onLoad(() => {
- if (appStore.isLogin) {
- agreementGetoneFn();
- metalConfigs.value = appStore.wxConfig?.metalConfigs || [];
- } else {
- toLogin();
- }
- });
- // 监听wxConfig就绪
- watch(
- isWxConfigReady,
- (isReady) => {
- if (isReady) {
- metalConfigs.value = appStore.wxConfig?.metalConfigs || [];
- }
- },
- { immediate: true }
- );
- // 切换金属类型
- const tabsChange = (item) => {
- tabsIndex.value = item.key;
- onKeyInput();
- };
- // 输入克重验证
- const onKeyInput = () => {
- is_lowest.value = false;
- is_out.value = false;
- if (extract.value === null || extract.value === "" || isNaN(extract.value)) {
- extract.value = 0;
- is_lowest.value = true;
- return;
- }
- const inputWeight = Number(extract.value);
- const minWeight = lowest.value;
- const accountWeightNum = Number(accountWeight.value);
- const isBelowMin = inputWeight < minWeight;
- const hasMoreDecimals = /\.\d{3,}$/.test(extract.value.toString());
- if (isBelowMin || hasMoreDecimals) is_lowest.value = true;
- if (inputWeight > accountWeightNum) is_out.value = true;
- };
- // 订单列表跳转
- const gotoOrderList = () => {
- uni.navigateTo({
- url: "/pages/users/vault/storeMetal/metalExchangeList",
- });
- };
- // 参数校验
- const validateSubmitParams = () => {
- if (!appStore.isLogin) return { valid: false, msg: "请先登录" };
- if (is_out.value || is_lowest.value || extract.value <= 0)
- return { valid: false, msg: "请输入有效克重" };
- return { valid: true };
- };
- // 点击提交按钮
- const handleShowModel = async () => {
- if (!appStore.userInfo.realNameVerified) {
- uni.showToast({ title: "请先进行实名认证", icon: "none", duration: 2000 });
- uni.navigateTo({ url: "/pages/users/face_detect/index" });
- return;
- }
- const check = validateSubmitParams();
- if (!check.valid) {
- uni.showToast({ title: check.msg, icon: "none", duration: 2000 });
- return;
- }
- calendarRef.value?.open();
- };
- // 日期确认回调
- const onDateConfirm = async (date) => {
- const params = {
- metalType: tabsIndex.value,
- reservationDate: date,
- reservedWeight: extract.value,
- remark: remark.value,
- };
- try {
- isSubmitting.value = true;
- uni.showLoading({ title: "提交预约...", mask: true });
- await createReservation(params);
- uni.hideLoading();
- uni.showToast({ title: "预约成功", icon: "success" });
- setTimeout(() => {
- gotoOrderList();
- }, 1000);
- extract.value = 0;
- } catch (err) {
- isSubmitting.value = false;
- uni.hideLoading();
- uni.showToast({ title: err || "提交失败,请重试", icon: "none" });
- } finally {
- isSubmitting.value = false;
- }
- };
- </script>
- <style lang="scss" scoped>
- $item-value-color: #dca537;
- $card-bcolor: #f8f8f8;
- page {
- min-height: 95vh;
- background-color: #f7f7f7;
- }
- .tabs {
- display: flex;
- height: 80rpx;
- border-radius: 40rpx;
- padding: 0 20rpx;
- color: #fff;
- font-size: 38rpx;
- font-weight: 300;
- .tabs-item {
- width: 50%;
- height: 100%;
- display: flex;
- justify-content: center;
- position: relative;
- color: #000000;
- }
- .active::after {
- position: absolute;
- bottom: 18rpx;
- left: 50%;
- transform: translateX(-50%);
- content: "";
- z-index: 20;
- display: block;
- width: 65rpx;
- height: 6rpx;
- background-color: #f8c007;
- }
- }
- .order-list {
- margin-top: 50rpx;
- text-align: center;
- color: #767676;
- font-size: 30rpx;
- }
- .withdraw-bottom {
- width: 100%;
- margin-top: 10rpx;
- margin-bottom: 100rpx;
- display: flex;
- justify-content: center;
- }
- .header {
- padding-left: 5px;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 10px 10px;
- border-radius: 5px;
- font-size: 18px;
- .live-gold {
- font-weight: 0;
- font-size: 30rpx;
- .price {
- color: #dcbe81;
- margin-left: 10rpx;
- }
- }
- .item {
- display: flex;
- align-items: center;
- margin-top: 15px;
- .targe {
- display: flex;
- justify-content: center;
- align-items: center;
- color: #fff;
- width: 35px;
- height: 35px;
- border-radius: 50%;
- background-color: #cc9933;
- }
- .address {
- width: 440rpx;
- margin: 0 10px;
- font-size: 28rpx;
- .receive-address {
- letter-spacing: 9px;
- }
- }
- .end {
- display: flex;
- justify-content: center;
- align-items: center;
- .copy {
- color: #888888;
- border-radius: 3px;
- border: 1px solid #888888;
- font-size: 24rpx;
- padding: 6rpx 23rpx;
- }
- }
- }
- &::before {
- position: absolute;
- top: 50%;
- transform: translatey(-50%);
- left: 0;
- content: "";
- width: 2px;
- height: 15px;
- background-color: #daa520;
- }
- .title {
- font-weight: 500;
- font-size: 32rpx;
- font-family: "黑体";
- }
- }
- .gold-box {
- padding: 30rpx 20rpx;
- }
- .gold-item {
- margin: 0 0 25rpx 0;
- }
- .input-box {
- display: flex;
- background-color: #ededed;
- border-radius: 5px;
- height: 90rpx;
- align-items: center;
- justify-content: space-around;
- font-size: 28rpx;
- padding-left: 20rpx;
- margin-top: 50rpx;
- input {
- width: 90%;
- }
- }
- .address {
- width: 690rpx;
- max-height: 180rpx;
- margin: 40rpx 0;
- padding: 28rpx;
- box-sizing: border-box;
- border-radius: 30rpx;
- .addressCon {
- width: 596rpx;
- font-size: 26rpx;
- color: #666;
- .name {
- font-size: 30rpx;
- color: #282828;
- font-weight: bold;
- margin-bottom: 10rpx;
- .phone {
- margin-left: 50rpx;
- }
- }
- .default {
- margin-right: 12rpx;
- }
- .setaddress {
- color: #333;
- font-size: 28rpx;
- }
- }
- .iconfont {
- font-size: 35rpx;
- color: #707070;
- }
- }
- .content-top {
- border-radius: 30rpx;
- background: $card-bcolor;
- margin-bottom: 20rpx;
- .section {
- .section-title {
- font-size: 32rpx;
- font-weight: bold;
- margin-bottom: 24rpx;
- position: relative;
- padding-left: 20rpx;
- &::after {
- position: absolute;
- top: 0;
- left: 0;
- height: 100%;
- width: 3px;
- background: $item-value-color;
- content: "";
- }
- }
- .courier-list {
- display: flex;
- justify-content: space-between;
- padding-bottom: 16rpx;
- .courier-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- min-width: 160rpx;
- margin-right: 24rpx;
- padding: 24rpx 20rpx;
- border: 2rpx solid #eee;
- border-radius: 12rpx;
- cursor: pointer;
- position: relative;
- .gou {
- position: absolute;
- width: 40rpx;
- height: 40rpx;
- right: -7rpx;
- bottom: -7rpx;
- border-radius: 50%;
- right: -6rpx;
- bottom: -6rpx;
- }
- &.active {
- border-color: #dbb870;
- }
- .courier-logo {
- width: 120rpx;
- height: 120rpx;
- margin-bottom: 8rpx;
- }
- .courier-name {
- font-size: 26rpx;
- }
- }
- }
- }
- }
- .withdraw {
- height: 100%;
- background-size: 100% 40%;
- background: $uni-bg-primary !important;
- .withdrawContent {
- height: 90%;
- padding: 45rpx 40rpx;
- background-color: #f7f7f7;
- top: 150rpx;
- position: relative;
- border-radius: 50rpx 50rpx 0 0;
- }
- .withdrawBody {
- background-color: #fff;
- padding: 20px 30px;
- font-size: 14px;
- .inputMoney {
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: 600;
- border-bottom: 1px solid #eaeef1;
- .rmb {
- font-size: 16px;
- }
- .tInput {
- height: 1.9em;
- font-size: 2.5em;
- border: none;
- position: relative;
- left: 3.5%;
- outline: none;
- }
- }
- }
- }
- .infoMoney {
- margin-top: 10px;
- font-size: 12px;
- margin-bottom: 20px;
- .infoMoneyNum {
- color: #b2b2b2;
- font-size: 26rpx;
- }
- .infoTip {
- color: red;
- font-size: 23rpx;
- margin-top: 10rpx;
- }
- }
- .agreement {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 10px;
- .chooseIcon {
- width: 16px;
- height: 16px;
- }
- .agreementText {
- font-size: 14px;
- margin-left: 10px;
- color: #999999;
- .agreementLink {
- color: #dca12b;
- }
- }
- }
- .submitBtn {
- button {
- background-color: #dca12b;
- color: #fff;
- width: 380rpx;
- height: 72rpx;
- display: flex;
- font-size: 30rpx;
- justify-content: center;
- align-items: center;
- border-radius: 30rpx;
- }
- }
- .submitBtnActive {
- button {
- color: #fff;
- background: #ffe079;
- box-shadow: 0 10rpx 8rpx rgba(207, 6, 6, 0.05);
- }
- }
- .signContent {
- background-color: #f8f8f8;
- padding: 20px;
- box-sizing: border-box;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-direction: column;
- border-radius: 20px 20px 0 0;
- .scrollView {
- background-color: #fff;
- padding: 4px;
- height: 300px;
- overflow-y: hidden;
- border: 1px solid #dfdfdf;
- }
- .confirmBtn {
- margin-top: 10px;
- color: #fff;
- padding: 4px 20px;
- border-radius: 20px;
- background: linear-gradient(to right, #8ed187, #5dd665);
- }
- }
- </style>
|