Files
dukang/apps/mini-user/src/components/RedeemQrCode.tsx
T
jacy cc0c0a6ef8 feat(fulfillment): 同城运费与路由修复,配送单展示商品用户地址
同城 MANUAL/ZZXFX 按小飞侠价规计费,路由查询回退仓配凭证;HQ 配送单补商品、用户和收货地址。门店核销回跳与小程序核销码一并带上。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-25 21:12:36 +08:00

77 lines
2.3 KiB
TypeScript

import { useEffect, useState } from 'react';
import { View, Canvas } from '@tarojs/components';
import Taro from '@tarojs/taro';
import {
REDEEM_QR_DISPLAY_SIZE,
buildRedeemQrDataUrl,
drawRedeemQrOnCanvas,
} from '../lib/redeem-qr';
const CANVAS_ID = 'redeem-qr-canvas';
type RedeemQrCodeProps = {
/** 二维码内容:门店 H5 落地 URL,缺省回退 token */
payload: string;
};
function drawOnWeappCanvas(payload: string) {
const page = Taro.getCurrentInstance().page;
const query = page ? Taro.createSelectorQuery().in(page) : Taro.createSelectorQuery();
query
.select(`#${CANVAS_ID}`)
.fields({ node: true, size: true })
.exec((res) => {
const item = res[0] as { node?: WechatMiniprogram.Canvas; width?: number; height?: number } | undefined;
const canvas = item?.node;
if (!canvas) return;
const layoutW = item.width || REDEEM_QR_DISPLAY_SIZE;
const layoutH = item.height || REDEEM_QR_DISPLAY_SIZE;
const drawSize = Math.min(layoutW, layoutH);
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const dpr = Taro.getSystemInfoSync().pixelRatio || 2;
canvas.width = layoutW * dpr;
canvas.height = layoutH * dpr;
ctx.scale(dpr, dpr);
drawRedeemQrOnCanvas(ctx, payload, drawSize);
});
}
export default function RedeemQrCode({ payload }: RedeemQrCodeProps) {
const [imgSrc, setImgSrc] = useState('');
const isWeapp = process.env.TARO_ENV === 'weapp';
useEffect(() => {
if (!payload) {
setImgSrc('');
return;
}
if (isWeapp) {
const timer = setTimeout(() => drawOnWeappCanvas(payload), 120);
return () => clearTimeout(timer);
}
let cancelled = false;
void buildRedeemQrDataUrl(payload).then((url) => {
if (!cancelled) setImgSrc(url);
});
return () => {
cancelled = true;
};
}, [payload, isWeapp]);
return (
<View className="redeem-qr-box">
<View className="redeem-qr-placeholder" />
{isWeapp ? (
<Canvas type="2d" id={CANVAS_ID} canvasId={CANVAS_ID} className="redeem-qr-canvas" />
) : imgSrc ? (
<View className="redeem-qr-img" style={{ backgroundImage: `url(${imgSrc})` }} />
) : null}
<View className="redeem-qr-scanline" />
</View>
);
}