|
@@ -0,0 +1,269 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <appResult title="冲销成功">
|
|
|
|
|
+ <view class="forward-info">
|
|
|
|
|
+ <text class="forward-amount">已返充 ¥{{ actPrice.toFixed(2) }} 到 {{ customName || '客户' }} 的余额</text>
|
|
|
|
|
+ <text class="forward-balance">最新余额 ¥{{ Number(customBalance).toFixed(2) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <button class="admin-button-com big blue" @click="showPoster">查看/分享退款凭证</button>
|
|
|
|
|
+ <button class="admin-button-com big" style="background-color: green;border-color: green;color:white;" @click="gotoOrderDetail">订单详情</button>
|
|
|
|
|
+ <button class="admin-button-com big" @click="goBackHome">返回首页</button>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 离屏画布,用于绘制退款凭证海报,绘制完成后导出为图片再展示 -->
|
|
|
|
|
+ <canvas canvas-id="forwardPosterCanvas" style="width: 360px; height: 560px; position: fixed; left: -9999px; top: -9999px; z-index: -1;"></canvas>
|
|
|
|
|
+ <item-poster-popup ref="itemPosterPopup" :poster-url="posterUrl" @close="closePoster" @save="savePosterImg" />
|
|
|
|
|
+ </appResult>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+/**
|
|
|
|
|
+ * 冲销单退款凭证页(ssh 冲销单功能)
|
|
|
|
|
+ * 用途:affirmForward.vue 提交冲销单成功后,如果客户选择"返充到余额",跳转到本页,
|
|
|
|
|
+ * 用 Canvas 绘制一张可长按转发/保存的退款凭证海报(客户名、退款金额、最新余额、冲销单号 + 收款二维码),
|
|
|
|
|
+ * 二维码复用 CustomController::actionGetGatheringCode,扫码后跳转 hdApp 的 admin/ghs/pay 页面查看余额明细。
|
|
|
|
|
+ * 如果没有返充余额,则走通用的 /admin/billing/result 成功页,不显示本页。
|
|
|
|
|
+ */
|
|
|
|
|
+import appResult from '@/components/app-result';
|
|
|
|
|
+import ItemPosterPopup from '@/components/item-poster-popup.vue';
|
|
|
|
|
+import { getGatheringCode } from '@/api/custom';
|
|
|
|
|
+import dayjs from 'dayjs';
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: 'forwardResult',
|
|
|
|
|
+ components: {
|
|
|
|
|
+ appResult,
|
|
|
|
|
+ ItemPosterPopup
|
|
|
|
|
+ },
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ orderId: 0,
|
|
|
|
|
+ orderSn: '',
|
|
|
|
|
+ actPrice: 0,
|
|
|
|
|
+ customId: 0,
|
|
|
|
|
+ customName: '',
|
|
|
|
|
+ customBalance: 0,
|
|
|
|
|
+ posterUrl: ''
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ onLoad(option) {
|
|
|
|
|
+ this.option = option;
|
|
|
|
|
+ this.orderId = option.orderId || 0;
|
|
|
|
|
+ this.orderSn = option.orderSn || '';
|
|
|
|
|
+ this.actPrice = option.actPrice ? parseFloat(option.actPrice) : 0;
|
|
|
|
|
+ this.customId = option.customId || 0;
|
|
|
|
|
+ this.customName = option.customName || '';
|
|
|
|
|
+ this.customBalance = option.customBalance !== undefined && option.customBalance !== '' ? parseFloat(option.customBalance) : 0;
|
|
|
|
|
+ this.generatePoster();
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ /** 拉取收款二维码图片并绘制海报,绘制完成后自动弹出预览 */
|
|
|
|
|
+ generatePoster() {
|
|
|
|
|
+ if (!this.customId) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ let that = this;
|
|
|
|
|
+ uni.showLoading({ mask: true, title: '生成凭证中' });
|
|
|
|
|
+ getGatheringCode({ id: this.customId })
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ if (res.code == 1 && res.data && res.data.imgUrl) {
|
|
|
|
|
+ uni.downloadFile({
|
|
|
|
|
+ url: res.data.imgUrl,
|
|
|
|
|
+ success: (downloadRes) => {
|
|
|
|
|
+ if (downloadRes.statusCode === 200) {
|
|
|
|
|
+ that.drawPoster(downloadRes.tempFilePath);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ uni.showToast({ title: '二维码下载失败', icon: 'none' });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ fail: () => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ uni.showToast({ title: '二维码下载失败', icon: 'none' });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(() => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 用 Canvas 绘制退款凭证海报:顶部蓝色banner + 客户名,中部大号退款金额与最新余额,
|
|
|
|
|
+ * 底部收款二维码,用于客户长按识别查看资金明细
|
|
|
|
|
+ */
|
|
|
|
|
+ drawPoster(qrPath) {
|
|
|
|
|
+ let that = this;
|
|
|
|
|
+ const ctx = uni.createCanvasContext('forwardPosterCanvas', this);
|
|
|
|
|
+ const width = 360;
|
|
|
|
|
+ const height = 560;
|
|
|
|
|
+ const radius = 20;
|
|
|
|
|
+
|
|
|
|
|
+ ctx.save();
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.moveTo(radius, 0);
|
|
|
|
|
+ ctx.lineTo(width - radius, 0);
|
|
|
|
|
+ ctx.arcTo(width, 0, width, radius, radius);
|
|
|
|
|
+ ctx.lineTo(width, height - radius);
|
|
|
|
|
+ ctx.arcTo(width, height, width - radius, height, radius);
|
|
|
|
|
+ ctx.lineTo(radius, height);
|
|
|
|
|
+ ctx.arcTo(0, height, 0, height - radius, radius);
|
|
|
|
|
+ ctx.lineTo(0, radius);
|
|
|
|
|
+ ctx.arcTo(0, 0, radius, 0, radius);
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
|
+ ctx.clip();
|
|
|
|
|
+
|
|
|
|
|
+ //背景
|
|
|
|
|
+ ctx.setFillStyle('#ffffff');
|
|
|
|
|
+ ctx.fillRect(0, 0, width, height);
|
|
|
|
|
+
|
|
|
|
|
+ //顶部蓝色banner
|
|
|
|
|
+ ctx.setFillStyle('#3385ff');
|
|
|
|
|
+ ctx.fillRect(0, 0, width, 140);
|
|
|
|
|
+ ctx.setFontSize(28);
|
|
|
|
|
+ ctx.setFillStyle('#ffffff');
|
|
|
|
|
+ ctx.setTextAlign('center');
|
|
|
|
|
+ ctx.fillText('退款凭证', width / 2, 60);
|
|
|
|
|
+ ctx.setFontSize(22);
|
|
|
|
|
+ ctx.fillText(this.customName || '客户', width / 2, 100);
|
|
|
|
|
+
|
|
|
|
|
+ //退款金额
|
|
|
|
|
+ ctx.setFontSize(46);
|
|
|
|
|
+ ctx.setFillStyle('#ff2842');
|
|
|
|
|
+ ctx.setTextAlign('center');
|
|
|
|
|
+ ctx.fillText('¥' + this.actPrice.toFixed(2), width / 2, 205);
|
|
|
|
|
+ ctx.setFontSize(22);
|
|
|
|
|
+ ctx.setFillStyle('#999999');
|
|
|
|
|
+ ctx.fillText('已返充到余额', width / 2, 235);
|
|
|
|
|
+
|
|
|
|
|
+ //分隔线
|
|
|
|
|
+ ctx.setStrokeStyle('#eeeeee');
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
+ ctx.moveTo(30, 258);
|
|
|
|
|
+ ctx.lineTo(width - 30, 258);
|
|
|
|
|
+ ctx.stroke();
|
|
|
|
|
+
|
|
|
|
|
+ //信息行:最新余额
|
|
|
|
|
+ ctx.setFontSize(24);
|
|
|
|
|
+ ctx.setFillStyle('#333333');
|
|
|
|
|
+ ctx.setTextAlign('left');
|
|
|
|
|
+ ctx.fillText('最新余额', 30, 298);
|
|
|
|
|
+ ctx.setTextAlign('right');
|
|
|
|
|
+ ctx.setFillStyle('#3385ff');
|
|
|
|
|
+ ctx.fillText('¥' + Number(this.customBalance).toFixed(2), width - 30, 298);
|
|
|
|
|
+
|
|
|
|
|
+ //信息行:冲销单号
|
|
|
|
|
+ ctx.setFontSize(24);
|
|
|
|
|
+ ctx.setFillStyle('#333333');
|
|
|
|
|
+ ctx.setTextAlign('left');
|
|
|
|
|
+ ctx.fillText('冲销单号', 30, 333);
|
|
|
|
|
+ ctx.setTextAlign('right');
|
|
|
|
|
+ ctx.setFontSize(20);
|
|
|
|
|
+ ctx.setFillStyle('#666666');
|
|
|
|
|
+ ctx.fillText(this.orderSn, width - 30, 333);
|
|
|
|
|
+
|
|
|
|
|
+ //信息行:日期
|
|
|
|
|
+ ctx.setFontSize(24);
|
|
|
|
|
+ ctx.setFillStyle('#333333');
|
|
|
|
|
+ ctx.setTextAlign('left');
|
|
|
|
|
+ ctx.fillText('日期', 30, 368);
|
|
|
|
|
+ ctx.setTextAlign('right');
|
|
|
|
|
+ ctx.setFontSize(20);
|
|
|
|
|
+ ctx.setFillStyle('#666666');
|
|
|
|
|
+ ctx.fillText(dayjs().format('YYYY-MM-DD HH:mm'), width - 30, 368);
|
|
|
|
|
+
|
|
|
|
|
+ //二维码
|
|
|
|
|
+ const qrSize = 150;
|
|
|
|
|
+ const qrX = (width - qrSize) / 2;
|
|
|
|
|
+ const qrY = 390;
|
|
|
|
|
+ ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
|
|
|
|
|
+
|
|
|
|
|
+ ctx.setFontSize(20);
|
|
|
|
|
+ ctx.setFillStyle('#666666');
|
|
|
|
|
+ ctx.setTextAlign('center');
|
|
|
|
|
+ ctx.fillText('长按识别,查看余额明细', width / 2, qrY + qrSize + 30);
|
|
|
|
|
+
|
|
|
|
|
+ ctx.restore();
|
|
|
|
|
+
|
|
|
|
|
+ ctx.draw(false, () => {
|
|
|
|
|
+ //延迟确保画布已完全渲染,避免部分平台导出空白图片
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ uni.canvasToTempFilePath(
|
|
|
|
|
+ {
|
|
|
|
|
+ canvasId: 'forwardPosterCanvas',
|
|
|
|
|
+ fileType: 'jpg',
|
|
|
|
|
+ quality: 1,
|
|
|
|
|
+ success: (res) => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ that.posterUrl = res.tempFilePath;
|
|
|
|
|
+ that.$refs.itemPosterPopup.open();
|
|
|
|
|
+ },
|
|
|
|
|
+ fail: () => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ uni.showToast({ title: '生成图片失败', icon: 'none' });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ that
|
|
|
|
|
+ );
|
|
|
|
|
+ }, 300);
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ showPoster() {
|
|
|
|
|
+ if (this.posterUrl) {
|
|
|
|
|
+ this.$refs.itemPosterPopup.open();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.generatePoster();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ closePoster() {
|
|
|
|
|
+ this.$refs.itemPosterPopup.close();
|
|
|
|
|
+ },
|
|
|
|
|
+ savePosterImg() {
|
|
|
|
|
+ let that = this;
|
|
|
|
|
+ uni.showLoading({ title: '正在保存...', mask: true });
|
|
|
|
|
+ uni.saveImageToPhotosAlbum({
|
|
|
|
|
+ filePath: this.posterUrl,
|
|
|
|
|
+ success() {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ that.$refs.itemPosterPopup.close();
|
|
|
|
|
+ uni.showToast({ title: '保存成功', icon: 'success' });
|
|
|
|
|
+ },
|
|
|
|
|
+ fail() {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ uni.showToast({ title: '保存失败,请检查相册权限', icon: 'none' });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ gotoOrderDetail() {
|
|
|
|
|
+ this.$util.pageTo({ url: '/pagesOrder/detail', type: 2, query: { id: this.orderId } });
|
|
|
|
|
+ },
|
|
|
|
|
+ goBackHome() {
|
|
|
|
|
+ this.$util.pageTo({ url: '/admin/home/workbench', type: 4, query: { tabIndex: 0 } });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.admin-button-com {
|
|
|
|
|
+ margin-bottom: 30upx;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+.forward-info {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin: 25upx 0 40upx;
|
|
|
|
|
+ .forward-amount {
|
|
|
|
|
+ font-size: 30upx;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ .forward-balance {
|
|
|
|
|
+ margin-top: 12upx;
|
|
|
|
|
+ font-size: 26upx;
|
|
|
|
|
+ color: #3385ff;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|