| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- <template>
- <div class="sponsors-wrap">
- <h1 class="txt">
- 截止至{{ onMountedTime }},已收到:{{ receiveMoney / 100 }}元赞助~
- </h1>
- <div class="pay-list">
- <div
- v-for="(item, index) in payList"
- :key="index"
- class="item"
- >
- <div class="time">发起时间:{{ item.created_at }},</div>
- <div class="user">
- <template v-if="item.user">
- <img
- :src="item.user.avatar"
- class="avatar"
- alt=""
- />
- <span class="username">{{ item.user.username }}</span>
- </template>
- <span v-else>游客</span>,
- </div>
- <div class="account">支付宝账号:{{ item.buyer_logon_id }},</div>
- <div class="gift">
- 赞助了:{{ item.subject }}({{ item.total_amount }}元),
- </div>
- <div class="status">
- 状态:{{
- item.trade_status === PayStatusEnum.WAIT_BUYER_PAY
- ? '支付中'
- : '已支付'
- }},
- </div>
- <div class="time">支付时间:{{ item.send_pay_date || '-' }}</div>
- </div>
- </div>
- <h2>开始赞助(支付宝)</h2>
- <div class="gift-list">
- <div
- v-for="(item, index) in giftList"
- :key="index"
- class="item"
- @click="startPay(item)"
- >
- {{ item.subject }}({{ item.total_amount }}元)
- </div>
- </div>
- <div class="qrcode-wrap">
- <img
- v-if="aliPayBase64 !== ''"
- class="qrcode"
- :src="aliPayBase64"
- alt=""
- />
- <template v-if="currentPayStatus !== PayStatusEnum.error">
- <div class="mask">
- <div class="txt">
- {{
- currentPayStatus === PayStatusEnum.TRADE_SUCCESS
- ? '支付成功'
- : '等待支付'
- }}
- </div>
- </div>
- </template>
- </div>
- <div v-if="aliPayBase64 !== ''">
- <div class="bottom">
- <div class="sao">打开支付宝扫一扫</div>
- <div class="expr">有效期5分钟({{ formatDownTime(downTime) }})</div>
- </div>
- </div>
- <h3 v-if="currentPayStatus === PayStatusEnum.WAIT_BUYER_PAY">
- ps:支付宝标题显示:东圃牛杂档,是正常的~
- </h3>
- <div
- v-if="payOk"
- class="bottom"
- >
- <h2>感谢您的赞助~</h2>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import { hrefToTarget, isMobile } from 'billd-utils';
- import QRCode from 'qrcode';
- import { onMounted, onUnmounted, ref } from 'vue';
- import { fetchAliPay, fetchAliPayStatus, fetchOrderList } from '@/api/order';
- import { IOrder, PayStatusEnum } from '@/interface';
- const payOk = ref(false);
- const onMountedTime = ref('');
- const aliPayBase64 = ref('');
- const payStatusTimer = ref();
- const downTimer = ref();
- const receiveMoney = ref(0);
- const downTime = ref();
- const downTimeEnd = ref();
- const payList = ref<IOrder[]>([]);
- const currentPayStatus = ref(PayStatusEnum.error);
- const giftList = ref([
- {
- total_amount: '0.10',
- subject: '一根辣条',
- body: 'aaa',
- },
- {
- total_amount: '1.00',
- subject: '一根烤肠',
- body: 'bbb',
- },
- {
- total_amount: '5.00',
- subject: '一瓶奶茶',
- body: 'ccc',
- },
- {
- total_amount: '10.00',
- subject: '一杯咖啡',
- body: 'ddd',
- },
- {
- total_amount: '50.00',
- subject: '一顿麦当劳',
- body: 'eee',
- },
- {
- total_amount: '100.00',
- subject: '一顿海底捞',
- body: 'fff',
- },
- ]);
- onUnmounted(() => {
- clearInterval(payStatusTimer.value);
- clearInterval(downTimer.value);
- });
- onMounted(() => {
- onMountedTime.value = new Date().toLocaleString();
- getPayList();
- });
- function formatDownTime(startTime: number) {
- const time2 = downTimeEnd.value - startTime;
- const ms = 1;
- const second = ms * 1000;
- const minute = second * 60;
- const hour = minute * 60;
- const day = hour * 24;
- if (time2 > day) {
- const res = (time2 / day).toFixed(4).split('.');
- return `${res[0]}天${Math.ceil(Number(`0.${res[1]}`) * 24)}时`;
- } else if (time2 > hour) {
- const res = (time2 / hour).toFixed(4).split('.');
- return `${res[0]}时${Math.ceil(Number(`0.${res[1]}`) * 60)}分`;
- } else if (time2 > minute) {
- const res = (time2 / minute).toFixed(4).split('.');
- return `${res[0]}分${Math.ceil(Number(`0.${res[1]}`) * 60)}秒`;
- } else {
- const res = (time2 / second).toFixed(4).split('.');
- return `${res[0]}秒`;
- }
- }
- async function generateQR(text) {
- let base64 = '';
- try {
- base64 = await QRCode.toDataURL(text, {
- margin: 1,
- });
- } catch (err) {
- console.error('生成二维码失败!', err);
- }
- return base64;
- }
- function handleDownTime() {
- clearInterval(downTimer.value);
- downTimeEnd.value = +new Date() + 1000 * 60 * 5;
- downTime.value = +new Date();
- downTimer.value = setInterval(() => {
- downTime.value = +new Date();
- }, 1000);
- }
- async function getPayList() {
- try {
- const res = await fetchOrderList({
- trade_status: PayStatusEnum.TRADE_SUCCESS,
- });
- if (res.code === 200) {
- payList.value = res.data.rows;
- receiveMoney.value = payList.value.reduce(
- (pre, item) => pre + Number(item.total_amount) * 100,
- 0
- );
- }
- } catch (error) {
- console.log(error);
- }
- }
- async function startPay(item) {
- currentPayStatus.value = PayStatusEnum.error;
- payOk.value = false;
- clearInterval(payStatusTimer.value);
- clearInterval(downTimer.value);
- try {
- const res = await fetchAliPay({
- total_amount: item.total_amount,
- subject: item.subject,
- body: item.body,
- });
- if (res.code === 200) {
- if (isMobile()) {
- hrefToTarget(res.data.qr_code);
- return;
- }
- const base64 = await generateQR(res.data.qr_code);
- aliPayBase64.value = base64;
- getPayStatus(res.data.out_trade_no);
- handleDownTime();
- }
- } catch (error) {
- console.log(error);
- }
- }
- function getPayStatus(outTradeNo: string) {
- clearInterval(payStatusTimer.value);
- payStatusTimer.value = setInterval(async () => {
- try {
- const res = await fetchAliPayStatus({
- out_trade_no: outTradeNo,
- });
- if (res.data.tradeStatus === PayStatusEnum.WAIT_BUYER_PAY) {
- currentPayStatus.value = PayStatusEnum.WAIT_BUYER_PAY;
- console.log('等待支付');
- }
- if (res.data.tradeStatus === PayStatusEnum.TRADE_SUCCESS) {
- currentPayStatus.value = PayStatusEnum.TRADE_SUCCESS;
- clearInterval(downTimer.value);
- clearInterval(payStatusTimer.value);
- console.log('支付成功!');
- payOk.value = true;
- getPayList();
- }
- } catch (error) {
- console.log(error);
- }
- }, 1000);
- }
- </script>
- <style lang="scss" scoped>
- .sponsors-wrap {
- text-align: center;
- .pay-list {
- display: flex;
- overflow: scroll;
- align-items: center;
- flex-direction: column;
- box-sizing: border-box;
- margin-bottom: 20px;
- padding: 10px;
- width: 100%;
- height: 200px;
- background-color: papayawhip;
- .item {
- display: inline-flex;
- flex-wrap: wrap;
- justify-content: center;
- margin-bottom: 4px;
- width: 100%;
- text-align: left;
- .user {
- width: 120px;
- padding: 0 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- .avatar {
- width: 30px;
- height: 30px;
- border-radius: 50%;
- }
- .username {
- @extend %singleEllipsis;
- }
- }
- .account {
- width: 250px;
- }
- .gift {
- width: 260px;
- }
- .status {
- width: 120px;
- text-align: left;
- }
- .time {
- width: 280px;
- }
- }
- }
- .gift-list {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- justify-content: center;
- .item {
- margin: 5px;
- padding: 5px 10px;
- border-radius: 4px;
- background-color: skyblue;
- cursor: pointer;
- }
- }
- .qrcode-wrap {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- box-sizing: border-box;
- margin: 20px auto 0;
- width: 140px;
- height: 140px;
- .mask {
- position: absolute !important;
- display: flex;
- align-items: center;
- justify-content: center;
- @extend %maskBg;
- .txt {
- color: white;
- font-weight: bold;
- }
- }
- }
- .bottom {
- margin-top: 2px;
- width: 100%;
- text-align: center;
- font-size: 14px;
- }
- }
- </style>
|