add user invite

This commit is contained in:
Timi
2026-08-15 01:33:52 +08:00
parent e4d02a714f
commit c810162926
8 changed files with 764 additions and 13 deletions
+77
View File
@@ -1,4 +1,5 @@
import { BarcodeFormat, EncodeHintType, QRCodeWriter } from "@zxing/library";
import { Time } from "timi-web";
export interface QrCodePage {
pageIndex: number;
@@ -23,6 +24,13 @@ export interface QrCodeGrid {
pageSize: number;
}
export interface InvitePosterOptions {
code: string;
storeName: string;
roleName: string;
expireAt: number;
}
const pageWidth = 2480;
const pageHeight = 3508;
const pagePadding = 80;
@@ -77,6 +85,14 @@ export async function downloadQrCodeImages(options: DownloadQrCodeOptions): Prom
}
}
export async function downloadInvitePoster(options: InvitePosterOptions, fileName: string): Promise<void> {
await downloadCanvas(renderInvitePoster(options), fileName);
}
export function createInvitePosterImage(options: InvitePosterOptions): string {
return renderInvitePoster(options).toDataURL("image/png");
}
export async function printQrCodeImages(options: PrintQrCodeOptions): Promise<void> {
const printWindow = window.open("", "_blank");
if (!printWindow) {
@@ -177,6 +193,67 @@ function renderQrCodePage(codes: string[], maxCodeLength = 0): HTMLCanvasElement
return canvas;
}
function renderInvitePoster(options: InvitePosterOptions): HTMLCanvasElement {
const canvas = document.createElement("canvas");
canvas.width = 1200;
canvas.height = 1820;
const context = canvas.getContext("2d");
if (!context) {
throw new Error("当前浏览器不支持 Canvas");
}
const teal = "#0F766E";
const darkTeal = "#115E59";
context.fillStyle = "#F0FDFA";
context.fillRect(0, 0, canvas.width, canvas.height);
context.fillStyle = teal;
context.fillRect(0, 0, canvas.width, 640);
context.fillStyle = "#CCFBF1";
context.beginPath();
context.arc(1140, 40, 220, 0, Math.PI * 2);
context.fill();
context.fillStyle = "#FFF";
context.textAlign = "left";
context.textBaseline = "middle";
context.font = "700 80px Microsoft YaHei, sans-serif";
context.fillText("邀请您加入", 64, 120);
context.font = "700 110px Microsoft YaHei, sans-serif";
context.fillText(options.storeName, 64, 280);
context.font = "700 64px Microsoft YaHei, sans-serif";
context.fillText(`成为:${options.roleName}`, 64, 420);
context.fillStyle = "#FFFFFF";
context.shadowColor = "rgba(15, 118, 110, .18)";
context.shadowBlur = 36;
context.shadowOffsetY = 12;
context.beginPath();
context.roundRect(120, 520, 960, 960, 40);
context.fill();
context.shadowColor = "transparent";
context.shadowBlur = 0;
context.shadowOffsetY = 0;
const qrSize = 920;
const qrLeft = (canvas.width - qrSize) / 2;
const qrTop = 540;
drawQrCode(context, options.code, qrLeft, qrTop, qrSize);
context.textAlign = "center";
context.fillStyle = "#64748B";
context.font = "400 40px Microsoft YaHei, sans-serif";
context.fillText(`有效期至 ${Time.toDateTime(options.expireAt)}`, 600, 1430);
context.fillStyle = darkTeal;
context.font = "400 52px Microsoft YaHei, sans-serif";
context.fillText("糕店客户管理系统", 600, 1550);
context.fillStyle = "#64748B";
context.font = "400 40px Microsoft YaHei, sans-serif";
context.fillText("客户档案 | 事件登记 | 积分激励 | 门店协同 | AI 分析", 600, 1645);
context.fillStyle = "#94A3B8";
context.font = "400 40px Microsoft YaHei, sans-serif";
context.fillText("本邀请仅限本人使用,请勿转发", 600, 1760);
return canvas;
}
async function waitPrintImagesLoaded(document: Document): Promise<void> {
const imageList = Array.from(document.images);
await Promise.all(imageList.map(image => {