Compare commits
5 Commits
5a753e7822
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10dab7ee84 | ||
|
|
3212503a64 | ||
|
|
ce1f5485fe | ||
|
|
33ab46aec0 | ||
|
|
b5081afb2c |
@@ -45,10 +45,9 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
// 获取屏幕宽度,如果没有传入width则使用屏幕宽度
|
// 获取屏幕宽度,如果没有传入width则使用屏幕宽度
|
||||||
const windowWidth = Taro.getSystemInfoSync().windowWidth
|
const windowWidth = Taro.getSystemInfoSync().windowWidth
|
||||||
|
|
||||||
// 获取 DPR - 使用系统像素比确保高清显示
|
// 获取 DPR:统一与 share.ts 策略,限制上限避免内存过高
|
||||||
// const systemDpr = Taro.getSystemInfoSync().pixelRatio
|
const systemDpr = (Taro as any).getSystemInfoSync?.().pixelRatio || 1
|
||||||
const dpr = 1
|
const dpr = Math.min(Math.max(systemDpr, 1), 2)
|
||||||
// Math.min(systemDpr, 3) // 限制最大dpr为3,避免过度放大
|
|
||||||
|
|
||||||
// 2. 计算缩放比例(设备宽度 / 设计稿宽度)
|
// 2. 计算缩放比例(设备宽度 / 设计稿宽度)
|
||||||
const scale = windowWidth / designWidth
|
const scale = windowWidth / designWidth
|
||||||
@@ -105,7 +104,7 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
|
|
||||||
// 绘制边框
|
// 绘制边框
|
||||||
ctx.strokeStyle = borderColor
|
ctx.strokeStyle = borderColor
|
||||||
ctx.lineWidth = 1 * dpr
|
ctx.lineWidth = 1
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
|
|
||||||
// 绘制文字
|
// 绘制文字
|
||||||
@@ -145,14 +144,14 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
const drawSVGPathToCanvas = (ctx: any) => {
|
const drawSVGPathToCanvas = (ctx: any) => {
|
||||||
// 设置绘制样式
|
// 设置绘制样式
|
||||||
ctx.strokeStyle = '#00E5AD';
|
ctx.strokeStyle = '#00E5AD';
|
||||||
ctx.lineWidth = scale * 3 * dpr;
|
ctx.lineWidth = scale * 3;
|
||||||
ctx.lineCap = 'round';
|
ctx.lineCap = 'round';
|
||||||
ctx.lineJoin = 'round';
|
ctx.lineJoin = 'round';
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
// 移动到指定位置并缩放
|
// 移动到指定位置并缩放
|
||||||
ctx.translate(scale * 200 * dpr, scale * 90 * dpr);
|
ctx.translate(scale * 200, scale * 90);
|
||||||
const scaleValue = 0.8
|
const scaleValue = 0.8
|
||||||
ctx.scale(scaleValue, scaleValue);
|
ctx.scale(scaleValue, scaleValue);
|
||||||
|
|
||||||
@@ -382,43 +381,39 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
setIsDrawing(true)
|
setIsDrawing(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 设置Canvas的实际尺寸(使用dpr确保高清显示)
|
// 统一坐标系:先用物理像素清空,再缩放到逻辑坐标绘制
|
||||||
const canvasWidthPx = canvasWidth * dpr
|
const canvasWidthPx = canvasWidth * dpr
|
||||||
const canvasHeightPx = canvasHeight * dpr
|
const canvasHeightPx = canvasHeight * dpr
|
||||||
|
if (typeof ctx.setTransform === 'function') {
|
||||||
// 清空画布
|
ctx.setTransform(1, 0, 0, 1, 0, 0)
|
||||||
|
}
|
||||||
ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx)
|
ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx)
|
||||||
|
ctx.save()
|
||||||
|
ctx.scale(dpr, dpr)
|
||||||
console.log('画布已清空')
|
console.log('画布已清空')
|
||||||
|
|
||||||
// 如果dpr大于2,进行缩放处理以避免内容过大
|
|
||||||
if (dpr > 2) {
|
|
||||||
const scale = 2 / dpr
|
|
||||||
ctx.scale(scale, scale)
|
|
||||||
console.log('应用缩放:', scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绘制背景 - 渐变色 已完成
|
// 绘制背景 - 渐变色 已完成
|
||||||
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeightPx)
|
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight)
|
||||||
gradient.addColorStop(0, '#BFFFEF')
|
gradient.addColorStop(0, '#BFFFEF')
|
||||||
gradient.addColorStop(1, '#F2FFFC')
|
gradient.addColorStop(1, '#F2FFFC')
|
||||||
ctx.fillStyle = gradient
|
ctx.fillStyle = gradient
|
||||||
ctx.fillRect(0, 0, canvasWidthPx, canvasHeightPx)
|
ctx.fillRect(0, 0, canvasWidth, canvasHeight)
|
||||||
console.log('背景绘制完成')
|
console.log('背景绘制完成')
|
||||||
|
|
||||||
// 绘制背景条纹 已完成
|
// 绘制背景条纹 已完成
|
||||||
ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)'
|
ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)'
|
||||||
ctx.lineWidth = 2
|
ctx.lineWidth = 2
|
||||||
for (let i = 0; i < canvasWidthPx; i += 4) {
|
for (let i = 0; i < canvasWidth; i += 4) {
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(i, 0)
|
ctx.moveTo(i, 0)
|
||||||
ctx.lineTo(i, canvasHeightPx)
|
ctx.lineTo(i, canvasHeight)
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制用户头像(左上角) 已完成
|
// 绘制用户头像(左上角) 已完成
|
||||||
const avatarSize = scale * 32 * dpr // 32px * dpr
|
const avatarSize = scale * 32
|
||||||
const avatarX = scale * 35 * dpr // 距离左侧35px
|
const avatarX = scale * 35
|
||||||
const avatarY = scale * 35 * dpr // 距离顶部35px
|
const avatarY = scale * 35
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const avatarPath = await loadImage(data.userAvatar, canvasNode)
|
const avatarPath = await loadImage(data.userAvatar, canvasNode)
|
||||||
@@ -438,23 +433,23 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 绘制用户昵称 已完成
|
// 绘制用户昵称 已完成
|
||||||
const nicknameX = avatarX + avatarSize + 8 * dpr // 距离头像8px
|
const nicknameX = avatarX + avatarSize + scale * 8
|
||||||
const nicknameY = avatarY + (avatarSize - 18 * dpr) / 2 // 与头像水平居中对齐
|
const nicknameY = avatarY + (avatarSize - scale * 18) / 2
|
||||||
const nicknameFontSize = scale * 18 * dpr
|
const nicknameFontSize = scale * 18
|
||||||
// drawText(ctx, data.userNickname, nicknameX, nicknameY, 200 * dpr, nicknameFontSize, '#000000', true, 'Noto Sans SC')
|
// drawText(ctx, data.userNickname, nicknameX, nicknameY, 200 * dpr, nicknameFontSize, '#000000', true, 'Noto Sans SC')
|
||||||
drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900')
|
drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900')
|
||||||
|
|
||||||
// 绘制"邀你加入球局"文案
|
// 绘制"邀你加入球局"文案
|
||||||
const inviteX = scale * 35 * dpr // 距离画布左侧35px
|
const inviteX = scale * 35
|
||||||
const inviteY = scale * 100 * dpr // 距离画布顶部79px
|
const inviteY = scale * 100
|
||||||
const inviteFontSize = scale * 44 * dpr
|
const inviteFontSize = scale * 44
|
||||||
|
|
||||||
// 绘制"邀你加入"
|
// 绘制"邀你加入"
|
||||||
drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900')
|
drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900')
|
||||||
|
|
||||||
// 绘制"球局"特殊样式
|
// 绘制"球局"特殊样式
|
||||||
const qiuJuX = inviteX + ctx.measureText('邀你加入').width + 4 * dpr
|
const qiuJuX = inviteX + ctx.measureText('邀你加入').width + scale * 4
|
||||||
const qiuJuFontSize = scale * 44 * dpr
|
const qiuJuFontSize = scale * 44
|
||||||
drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900')
|
drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900')
|
||||||
|
|
||||||
// 测试绘制网络图片
|
// 测试绘制网络图片
|
||||||
@@ -462,12 +457,12 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
|
|
||||||
// 绘制球员图片(右上角)已完成
|
// 绘制球员图片(右上角)已完成
|
||||||
let venueBaseConfig = {
|
let venueBaseConfig = {
|
||||||
venueImgX: scale * 340 * dpr,
|
venueImgX: scale * 340,
|
||||||
venueImgY: scale * 35 * dpr,
|
venueImgY: scale * 35,
|
||||||
rotation: scale * -8, // 旋转-8度
|
rotation: scale * -8, // 旋转-8度
|
||||||
venueImgSize: scale * 124 * dpr,
|
venueImgSize: scale * 124,
|
||||||
borderRadius: scale * 24 * dpr,
|
borderRadius: scale * 24,
|
||||||
padding: scale * 4 * dpr,
|
padding: scale * 4,
|
||||||
venueImage: data.venueImages?.[0]
|
venueImage: data.venueImages?.[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,8 +471,8 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
const venueBackConfig = {
|
const venueBackConfig = {
|
||||||
...venueBaseConfig,
|
...venueBaseConfig,
|
||||||
venueImage: data.venueImages?.[1],
|
venueImage: data.venueImages?.[1],
|
||||||
venueImgX: scale * 400 * dpr,
|
venueImgX: scale * 400,
|
||||||
venueImgY: scale * 35 * dpr,
|
venueImgY: scale * 35,
|
||||||
rotation: scale * -10, // 旋转-10度
|
rotation: scale * -10, // 旋转-10度
|
||||||
}
|
}
|
||||||
await drawVenueImages(ctx, venueBackConfig, canvasNode)
|
await drawVenueImages(ctx, venueBackConfig, canvasNode)
|
||||||
@@ -512,11 +507,11 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
// 绘制"单打"标签
|
// 绘制"单打"标签
|
||||||
const danDaX = scale * 100
|
const danDaX = scale * 100
|
||||||
const danDaY = scale * 196
|
const danDaY = scale * 196
|
||||||
const danDaHeight = scale * 40 * dpr
|
const danDaHeight = scale * 40
|
||||||
const danDaRadius = scale * 20 * dpr
|
const danDaRadius = scale * 20
|
||||||
const danDaFontSize = scale * 22 * dpr
|
const danDaFontSize = scale * 22
|
||||||
// 根据内容动态计算标签宽度(左右内边距)
|
// 根据内容动态计算标签宽度(左右内边距)
|
||||||
const danDaPaddingX = scale * 16 * dpr
|
const danDaPaddingX = scale * 16
|
||||||
setFont2D(ctx, danDaFontSize)
|
setFont2D(ctx, danDaFontSize)
|
||||||
const danDaTextWidth = ctx.measureText(data.gameType).width
|
const danDaTextWidth = ctx.measureText(data.gameType).width
|
||||||
const danDaWidth = danDaTextWidth + danDaPaddingX * 2
|
const danDaWidth = danDaTextWidth + danDaPaddingX * 2
|
||||||
@@ -527,11 +522,11 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr,保持视觉间距)
|
const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr,保持视觉间距)
|
||||||
const skillX = danDaX + danDaWidth + labelGap
|
const skillX = danDaX + danDaWidth + labelGap
|
||||||
const skillY = scale * 196
|
const skillY = scale * 196
|
||||||
const skillHeight = scale * 40 * dpr
|
const skillHeight = scale * 40
|
||||||
const skillRadius = scale * 20 * dpr
|
const skillRadius = scale * 20
|
||||||
const skillFontSize = scale * 22 * dpr
|
const skillFontSize = scale * 22
|
||||||
// 根据内容动态计算技能标签宽度
|
// 根据内容动态计算技能标签宽度
|
||||||
const skillPaddingX = scale * 20 * dpr
|
const skillPaddingX = scale * 20
|
||||||
setFont2D(ctx, skillFontSize)
|
setFont2D(ctx, skillFontSize)
|
||||||
const skillTextWidth = ctx.measureText(data.skillLevel).width
|
const skillTextWidth = ctx.measureText(data.skillLevel).width
|
||||||
const skillWidth = skillTextWidth + skillPaddingX * 2
|
const skillWidth = skillTextWidth + skillPaddingX * 2
|
||||||
@@ -541,7 +536,7 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
// 绘制日期时间
|
// 绘制日期时间
|
||||||
const dateX = danDaX
|
const dateX = danDaX
|
||||||
const timeInfoY = infoStartY + infoSpacing
|
const timeInfoY = infoStartY + infoSpacing
|
||||||
const timeInfoFontSize = scale * 24 * dpr
|
const timeInfoFontSize = scale * 24
|
||||||
const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`, canvasNode)
|
const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`, canvasNode)
|
||||||
ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize)
|
ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize)
|
||||||
|
|
||||||
@@ -549,17 +544,18 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD')
|
drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD')
|
||||||
|
|
||||||
// 绘制时间(黑色)
|
// 绘制时间(黑色)
|
||||||
const timeX = textX + ctx.measureText(data.gameDate).width + 10 * dpr
|
const timeX = textX + ctx.measureText(data.gameDate).width + scale * 10
|
||||||
// drawText(ctx, data.gameTime, timeX, timeInfoY + 8, 300, timeInfoFontSize, '#000000')
|
// drawText(ctx, data.gameTime, timeX, timeInfoY + 8, 300, timeInfoFontSize, '#000000')
|
||||||
drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000')
|
drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000')
|
||||||
|
|
||||||
// 绘制地点
|
// 绘制地点
|
||||||
const locationInfoY = infoStartY + infoSpacing * 2
|
const locationInfoY = infoStartY + infoSpacing * 2
|
||||||
const locationFontSize = scale * 22 * dpr
|
const locationFontSize = scale * 22
|
||||||
const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`, canvasNode)
|
const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`, canvasNode)
|
||||||
ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize)
|
ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize)
|
||||||
drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000')
|
drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000')
|
||||||
|
|
||||||
|
ctx.restore()
|
||||||
// 绘制完成,调用draw方法
|
// 绘制完成,调用draw方法
|
||||||
console.log('开始调用ctx.draw()')
|
console.log('开始调用ctx.draw()')
|
||||||
const doExport = () => {
|
const doExport = () => {
|
||||||
@@ -649,12 +645,9 @@ const ShareCardCanvas: React.FC<ShareCardCanvasProps> = ({
|
|||||||
if (data && data.node) {
|
if (data && data.node) {
|
||||||
const canvas = data.node
|
const canvas = data.node
|
||||||
const context = canvas.getContext('2d')
|
const context = canvas.getContext('2d')
|
||||||
// DPR 缩放,提升清晰度(当前 dpr = 1 也可正常显示)
|
// 仅设置物理像素尺寸,绘制阶段统一在 drawShareCard 中做 ctx.scale(dpr, dpr)
|
||||||
const sys = (Taro as any).getSystemInfoSync?.() || {}
|
canvas.width = canvasWidth * dpr
|
||||||
const ratio = sys.pixelRatio || 1
|
canvas.height = canvasHeight * dpr
|
||||||
canvas.width = canvasWidth * ratio
|
|
||||||
canvas.height = canvasHeight * ratio
|
|
||||||
context.scale(ratio, ratio)
|
|
||||||
setCanvasNode(canvas)
|
setCanvasNode(canvas)
|
||||||
setCtx2d(context)
|
setCtx2d(context)
|
||||||
setIs2dCtx(true)
|
setIs2dCtx(true)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface UploadFromWxProps {
|
|||||||
|
|
||||||
async function convert_to_jpg_and_compress(
|
async function convert_to_jpg_and_compress(
|
||||||
src: string,
|
src: string,
|
||||||
{ width, height }
|
{ width, height, quality }: { width: number; height: number; quality: number }
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const canvas = Taro.createOffscreenCanvas({ type: "2d", width, height });
|
const canvas = Taro.createOffscreenCanvas({ type: "2d", width, height });
|
||||||
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
||||||
@@ -33,22 +33,54 @@ async function convert_to_jpg_and_compress(
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
Taro.canvasToTempFilePath({
|
Taro.canvasToTempFilePath({
|
||||||
canvas: canvas as unknown as Taro.Canvas,
|
canvas: canvas as unknown as Taro.Canvas,
|
||||||
fileType: "png",
|
fileType: "jpg",
|
||||||
quality: 0.7,
|
quality,
|
||||||
success: (res) => resolve(res.tempFilePath),
|
success: (res) => resolve(res.tempFilePath),
|
||||||
fail: reject,
|
fail: reject,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFileSize(path: string): Promise<number> {
|
||||||
|
const fs = (Taro as any).getFileSystemManager();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.stat({
|
||||||
|
path,
|
||||||
|
success: (res) => resolve(res.stats.size),
|
||||||
|
fail: reject,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function compressImage(files) {
|
async function compressImage(files) {
|
||||||
const res: string[] = [];
|
const res: string[] = [];
|
||||||
|
const qualityList = [0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6];
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const compressed_image = await convert_to_jpg_and_compress(file.path, {
|
// 小图且体积已在目标范围内时,直接上传原图,避免二次压缩变糊
|
||||||
width: file.width,
|
if (
|
||||||
height: file.height,
|
file.size <= TARGET_IMAGE_SIZE &&
|
||||||
});
|
file.width <= IMAGE_MAX_SIZE.width &&
|
||||||
res.push(compressed_image);
|
file.height <= IMAGE_MAX_SIZE.height
|
||||||
|
) {
|
||||||
|
res.push(file.path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bestImage = file.path;
|
||||||
|
for (const quality of qualityList) {
|
||||||
|
const compressedImage = await convert_to_jpg_and_compress(file.path, {
|
||||||
|
width: file.width,
|
||||||
|
height: file.height,
|
||||||
|
quality,
|
||||||
|
});
|
||||||
|
const compressedSize = await getFileSize(compressedImage);
|
||||||
|
bestImage = compressedImage;
|
||||||
|
if (compressedSize <= TARGET_IMAGE_SIZE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push(bestImage);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -58,6 +90,8 @@ const IMAGE_MAX_SIZE = {
|
|||||||
width: 1080,
|
width: 1080,
|
||||||
height: 720,
|
height: 720,
|
||||||
};
|
};
|
||||||
|
// 压缩目标体积(约 300KB)
|
||||||
|
const TARGET_IMAGE_SIZE = 800 * 1024;
|
||||||
|
|
||||||
// 标准长宽比,判断标准
|
// 标准长宽比,判断标准
|
||||||
const STANDARD_ASPECT_RATIO = IMAGE_MAX_SIZE.width / IMAGE_MAX_SIZE.height;
|
const STANDARD_ASPECT_RATIO = IMAGE_MAX_SIZE.width / IMAGE_MAX_SIZE.height;
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ export default function VenueInfo(props) {
|
|||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const {
|
const {
|
||||||
venue_description,
|
venue_description,
|
||||||
|
court_type,
|
||||||
venue_description_tag = [],
|
venue_description_tag = [],
|
||||||
venue_image_list = [],
|
venue_image_list = [],
|
||||||
} = detail;
|
} = detail;
|
||||||
|
const venue_tags = [court_type, ...venue_description_tag].filter(Boolean);
|
||||||
|
|
||||||
// 统一为 URL 数组:接口可能是 { id, url }[] 或 string[]
|
// 统一为 URL 数组:接口可能是 { id, url }[] 或 string[]
|
||||||
const screenshot_urls = (venue_image_list || []).map((item) =>
|
const screenshot_urls = (venue_image_list || []).map((item) =>
|
||||||
@@ -61,7 +63,7 @@ export default function VenueInfo(props) {
|
|||||||
<View className={styles["venue-detail-content"]}>
|
<View className={styles["venue-detail-content"]}>
|
||||||
{/* venue detail tags */}
|
{/* venue detail tags */}
|
||||||
<View className={styles["venue-detail-content-tags"]}>
|
<View className={styles["venue-detail-content-tags"]}>
|
||||||
{insertDotInTags(venue_description_tag).map((tag, index) => (
|
{insertDotInTags(venue_tags).map((tag, index) => (
|
||||||
<View
|
<View
|
||||||
key={index}
|
key={index}
|
||||||
className={styles["venue-detail-content-tags-tag"]}
|
className={styles["venue-detail-content-tags-tag"]}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import {
|
|||||||
isPhoneNumber,
|
isPhoneNumber,
|
||||||
genGameLength,
|
genGameLength,
|
||||||
} from "@/utils";
|
} from "@/utils";
|
||||||
import { getStorage, setStorage } from "@/store/storage";
|
|
||||||
import { useGlobalStore } from "@/store/global";
|
import { useGlobalStore } from "@/store/global";
|
||||||
import { useOrder } from "@/store/orderStore";
|
import { useOrder } from "@/store/orderStore";
|
||||||
import detailService, { GameData } from "@/services/detailService";
|
import detailService, { GameData } from "@/services/detailService";
|
||||||
@@ -692,35 +691,26 @@ const OrderCheck = () => {
|
|||||||
}
|
}
|
||||||
setPaying(true);
|
setPaying(true);
|
||||||
|
|
||||||
let payment_params = {};
|
let payment_params: any = {};
|
||||||
try {
|
try {
|
||||||
payment_params = await getPaymentParams();
|
payment_params = await getPaymentParams();
|
||||||
if (!id) {
|
|
||||||
setStorage("backFlag", "1");
|
|
||||||
Taro.redirectTo({
|
|
||||||
url: `/order_pages/orderDetail/index?id=${payment_params.order_id}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await payOrder(payment_params);
|
await payOrder(payment_params);
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: "支付成功",
|
title: "支付成功",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
});
|
});
|
||||||
const backFlag = getStorage("backFlag");
|
// 支付成功后再跳转,避免部分机型(如华为)在页面切换中拉起支付导致卡死
|
||||||
if (backFlag === "1") {
|
if (!id && payment_params?.order_id) {
|
||||||
setStorage("backFlag", "0");
|
Taro.redirectTo({
|
||||||
Taro.navigateBack();
|
url: `/order_pages/orderDetail/index?id=${payment_params.order_id}`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Taro.navigateBack({
|
|
||||||
// delta: 1,
|
|
||||||
// });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: error.message,
|
title: error.message,
|
||||||
icon: "none",
|
icon: "none",
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setStorage("backFlag", "0");
|
|
||||||
init();
|
init();
|
||||||
setPaying(false);
|
setPaying(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -743,9 +743,12 @@ function Result() {
|
|||||||
rid && !Number.isNaN(Number(rid))
|
rid && !Number.isNaN(Number(rid))
|
||||||
? `/other_pages/ntrp-evaluate/index?stage=${StageType.RESULT}&id=${rid}&from_share=1`
|
? `/other_pages/ntrp-evaluate/index?stage=${StageType.RESULT}&id=${rid}&from_share=1`
|
||||||
: `/other_pages/ntrp-evaluate/index?stage=${StageType.INTRO}`;
|
: `/other_pages/ntrp-evaluate/index?stage=${StageType.INTRO}`;
|
||||||
|
const shareNickname = fromShare
|
||||||
|
? result?.sharer_nickname || "好友"
|
||||||
|
: (userInfo as any)?.nickname || "好友";
|
||||||
return {
|
return {
|
||||||
title: result?.ntrp_level
|
title: result?.ntrp_level
|
||||||
? `来看看 NTRP ${formatNtrpDisplay(result.ntrp_level)} 的测评结果`
|
? `来看看 ${shareNickname} 的测评结果`
|
||||||
: "来测一测你的NTRP等级吧",
|
: "来测一测你的NTRP等级吧",
|
||||||
imageUrl: result?.level_img || undefined,
|
imageUrl: result?.level_img || undefined,
|
||||||
path: sharePath,
|
path: sharePath,
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ export class UserService {
|
|||||||
|
|
||||||
// 处理人数统计 - 兼容不同的字段名
|
// 处理人数统计 - 兼容不同的字段名
|
||||||
const registered_count =
|
const registered_count =
|
||||||
game.current_players || game.participant_count || 0;
|
game.participant_count ?? game.current_players ?? 0;
|
||||||
const max_count = game.max_players || game.max_participants || 0;
|
const max_count = game.max_players || game.max_participants || 0;
|
||||||
|
|
||||||
// 转换为 ListCard 期望的格式
|
// 转换为 ListCard 期望的格式
|
||||||
|
|||||||
@@ -319,8 +319,9 @@ export async function generatePosterImage(data: any): Promise<string> {
|
|||||||
|
|
||||||
|
|
||||||
console.log("start !!!!");
|
console.log("start !!!!");
|
||||||
// const dpr = Taro.getWindowInfo().pixelRatio;
|
const systemDpr =
|
||||||
const dpr = 1;
|
Taro.getWindowInfo?.().pixelRatio || Taro.getSystemInfoSync().pixelRatio || 1;
|
||||||
|
const dpr = Math.min(Math.max(systemDpr, 1), 2);
|
||||||
// console.log(dpr, 'dpr')
|
// console.log(dpr, 'dpr')
|
||||||
const width = 600;
|
const width = 600;
|
||||||
const height = 1000;
|
const height = 1000;
|
||||||
@@ -487,7 +488,7 @@ export async function generatePosterImage(data: any): Promise<string> {
|
|||||||
const { tempFilePath } = await Taro.canvasToTempFilePath({
|
const { tempFilePath } = await Taro.canvasToTempFilePath({
|
||||||
canvas,
|
canvas,
|
||||||
fileType: 'png',
|
fileType: 'png',
|
||||||
quality: 0.7,
|
quality: 1,
|
||||||
});
|
});
|
||||||
console.log('tempFilePath', tempFilePath)
|
console.log('tempFilePath', tempFilePath)
|
||||||
return tempFilePath;
|
return tempFilePath;
|
||||||
|
|||||||
@@ -7,14 +7,40 @@ export function delay(ms: number) {
|
|||||||
export async function payOrder(params) {
|
export async function payOrder(params) {
|
||||||
const { timeStamp, nonceStr, package: _package, signType, paySign } = params;
|
const { timeStamp, nonceStr, package: _package, signType, paySign } = params;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
Taro.requestPayment({
|
let settled = false;
|
||||||
timeStamp,
|
const timeout = setTimeout(() => {
|
||||||
nonceStr,
|
if (settled) return;
|
||||||
package: _package,
|
settled = true;
|
||||||
signType,
|
reject(new Error("支付响应超时,请在订单页确认支付结果"));
|
||||||
paySign,
|
}, 20000);
|
||||||
success: resolve,
|
|
||||||
fail: reject.bind(null, new Error("支付失败")),
|
const finish = (cb: () => void) => {
|
||||||
});
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
clearTimeout(timeout);
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
Taro.requestPayment({
|
||||||
|
timeStamp,
|
||||||
|
nonceStr,
|
||||||
|
package: _package,
|
||||||
|
signType,
|
||||||
|
paySign,
|
||||||
|
success: (res) => finish(() => resolve(res)),
|
||||||
|
fail: (err: any) =>
|
||||||
|
finish(() => {
|
||||||
|
const errMsg = String(err?.errMsg || "");
|
||||||
|
if (errMsg.includes("cancel")) {
|
||||||
|
reject(new Error("已取消支付"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(new Error("支付失败,请重试"));
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
finish(() => reject(new Error("支付拉起失败,请重试")));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,9 @@ const designHeight = 400
|
|||||||
// 获取屏幕宽度,如果没有传入width则使用屏幕宽度
|
// 获取屏幕宽度,如果没有传入width则使用屏幕宽度
|
||||||
const windowWidth = Taro.getSystemInfoSync().windowWidth
|
const windowWidth = Taro.getSystemInfoSync().windowWidth
|
||||||
|
|
||||||
// 获取 DPR - 使用系统像素比确保高清显示
|
// 获取 DPR - 使用系统像素比确保高清显示,限制上限避免内存占用过高
|
||||||
// const systemDpr = Taro.getSystemInfoSync().pixelRatio
|
const systemDpr = Taro.getSystemInfoSync().pixelRatio || 1
|
||||||
const dpr = 1
|
const dpr = Math.min(Math.max(systemDpr, 1), 2)
|
||||||
// Math.min(systemDpr, 3) // 限制最大dpr为3,避免过度放大
|
|
||||||
|
|
||||||
// 2. 计算缩放比例(设备宽度 / 设计稿宽度)
|
// 2. 计算缩放比例(设备宽度 / 设计稿宽度)
|
||||||
const scale = windowWidth / designWidth
|
const scale = windowWidth / designWidth
|
||||||
@@ -88,7 +87,7 @@ const drawLabel = (ctx: any, x: number, y: number, width: number, height: number
|
|||||||
|
|
||||||
// 绘制边框
|
// 绘制边框
|
||||||
ctx.strokeStyle = borderColor
|
ctx.strokeStyle = borderColor
|
||||||
ctx.lineWidth = 1 * dpr
|
ctx.lineWidth = 1
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
|
|
||||||
// 绘制文字
|
// 绘制文字
|
||||||
@@ -143,14 +142,14 @@ const loadImage = (src: string): Promise<any> => {
|
|||||||
const drawSVGPathToCanvas = (ctx: any) => {
|
const drawSVGPathToCanvas = (ctx: any) => {
|
||||||
// 设置绘制样式
|
// 设置绘制样式
|
||||||
ctx.strokeStyle = '#00E5AD';
|
ctx.strokeStyle = '#00E5AD';
|
||||||
ctx.lineWidth = scale * 3 * dpr;
|
ctx.lineWidth = scale * 3;
|
||||||
ctx.lineCap = 'round';
|
ctx.lineCap = 'round';
|
||||||
ctx.lineJoin = 'round';
|
ctx.lineJoin = 'round';
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
// 移动到指定位置并缩放
|
// 移动到指定位置并缩放
|
||||||
ctx.translate(scale * 200 * dpr, scale * 90 * dpr);
|
ctx.translate(scale * 200, scale * 90);
|
||||||
const scaleValue = 0.8
|
const scaleValue = 0.8
|
||||||
ctx.scale(scaleValue, scaleValue);
|
ctx.scale(scaleValue, scaleValue);
|
||||||
|
|
||||||
@@ -373,43 +372,36 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
console.log('开始绘制分享卡片...')
|
console.log('开始绘制分享卡片...')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 设置Canvas的实际尺寸(使用dpr确保高清显示)
|
// 统一逻辑坐标:先按 dpr 缩放,再使用设计坐标绘制
|
||||||
const canvasWidthPx = canvasWidth * dpr
|
const canvasWidthPx = canvasWidth * dpr
|
||||||
const canvasHeightPx = canvasHeight * dpr
|
const canvasHeightPx = canvasHeight * dpr
|
||||||
|
|
||||||
// 清空画布
|
|
||||||
ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx)
|
ctx.clearRect(0, 0, canvasWidthPx, canvasHeightPx)
|
||||||
|
ctx.save()
|
||||||
|
ctx.scale(dpr, dpr)
|
||||||
console.log('画布已清空')
|
console.log('画布已清空')
|
||||||
|
|
||||||
// 如果dpr大于2,进行缩放处理以避免内容过大
|
|
||||||
if (dpr > 2) {
|
|
||||||
const scale = 2 / dpr
|
|
||||||
ctx.scale(scale, scale)
|
|
||||||
console.log('应用缩放:', scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绘制背景 - 渐变色 已完成
|
// 绘制背景 - 渐变色 已完成
|
||||||
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeightPx)
|
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight)
|
||||||
gradient.addColorStop(0, '#BFFFEF')
|
gradient.addColorStop(0, '#BFFFEF')
|
||||||
gradient.addColorStop(1, '#F2FFFC')
|
gradient.addColorStop(1, '#F2FFFC')
|
||||||
ctx.fillStyle = gradient
|
ctx.fillStyle = gradient
|
||||||
ctx.fillRect(0, 0, canvasWidthPx, canvasHeightPx)
|
ctx.fillRect(0, 0, canvasWidth, canvasHeight)
|
||||||
console.log('背景绘制完成')
|
console.log('背景绘制完成')
|
||||||
|
|
||||||
// 绘制背景条纹 已完成
|
// 绘制背景条纹 已完成
|
||||||
ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)'
|
ctx.strokeStyle = 'rgba(0, 0, 0, 0.03)'
|
||||||
ctx.lineWidth = 2
|
ctx.lineWidth = 2
|
||||||
for (let i = 0; i < canvasWidthPx; i += 4) {
|
for (let i = 0; i < canvasWidth; i += 4) {
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
ctx.moveTo(i, 0)
|
ctx.moveTo(i, 0)
|
||||||
ctx.lineTo(i, canvasHeightPx)
|
ctx.lineTo(i, canvasHeight)
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制用户头像(左上角) 已完成
|
// 绘制用户头像(左上角) 已完成
|
||||||
const avatarSize = scale * 32 * dpr // 32px * dpr
|
const avatarSize = scale * 32
|
||||||
const avatarX = scale * 35 * dpr // 距离左侧35px
|
const avatarX = scale * 35
|
||||||
const avatarY = scale * 35 * dpr // 距离顶部35px
|
const avatarY = scale * 35
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const avatarPath = await loadImage(data.userAvatar)
|
const avatarPath = await loadImage(data.userAvatar)
|
||||||
@@ -429,22 +421,22 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 绘制用户昵称 已完成
|
// 绘制用户昵称 已完成
|
||||||
const nicknameX = avatarX + avatarSize + 8 * dpr // 距离头像8px
|
const nicknameX = avatarX + avatarSize + scale * 8
|
||||||
const nicknameY = avatarY + (avatarSize - 18 * dpr) / 2 // 与头像水平居中对齐
|
const nicknameY = avatarY + (avatarSize - scale * 18) / 2
|
||||||
const nicknameFontSize = scale * 18 * dpr
|
const nicknameFontSize = scale * 18
|
||||||
drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900')
|
drawBoldText(ctx, data.userNickname, nicknameX, nicknameY, nicknameFontSize, '#000000', 'Noto Sans SC', '900')
|
||||||
|
|
||||||
// 绘制"邀你加入球局"文案
|
// 绘制"邀你加入球局"文案
|
||||||
const inviteX = scale * 35 * dpr // 距离画布左侧35px
|
const inviteX = scale * 35
|
||||||
const inviteY = scale * 100 * dpr // 距离画布顶部79px
|
const inviteY = scale * 100
|
||||||
const inviteFontSize = scale * 44 * dpr
|
const inviteFontSize = scale * 44
|
||||||
|
|
||||||
// 绘制"邀你加入"
|
// 绘制"邀你加入"
|
||||||
drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900')
|
drawBoldText(ctx, '邀你加入', inviteX, inviteY, inviteFontSize, '#000000', 'Noto Sans SC', '900')
|
||||||
|
|
||||||
// 绘制"球局"特殊样式
|
// 绘制"球局"特殊样式
|
||||||
const qiuJuX = inviteX + ctx.measureText('邀你加入').width + 4 * dpr
|
const qiuJuX = inviteX + ctx.measureText('邀你加入').width + scale * 4
|
||||||
const qiuJuFontSize = scale * 44 * dpr
|
const qiuJuFontSize = scale * 44
|
||||||
drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900')
|
drawBoldText(ctx, '球局', qiuJuX, inviteY, qiuJuFontSize, '#00E5AD', 'Noto Sans SC', '900')
|
||||||
|
|
||||||
// 测试绘制网络图片
|
// 测试绘制网络图片
|
||||||
@@ -452,12 +444,12 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
|
|
||||||
// 绘制球员图片(右上角)已完成
|
// 绘制球员图片(右上角)已完成
|
||||||
let venueBaseConfig = {
|
let venueBaseConfig = {
|
||||||
venueImgX: scale * 340 * dpr,
|
venueImgX: scale * 340,
|
||||||
venueImgY: scale * 35 * dpr,
|
venueImgY: scale * 35,
|
||||||
rotation: scale * -8, // 旋转-8度
|
rotation: scale * -8, // 旋转-8度
|
||||||
venueImgSize: scale * 124 * dpr,
|
venueImgSize: scale * 124,
|
||||||
borderRadius: scale * 24 * dpr,
|
borderRadius: scale * 24,
|
||||||
padding: scale * 4 * dpr,
|
padding: scale * 4,
|
||||||
venueImage: data.venueImages?.[0]
|
venueImage: data.venueImages?.[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,8 +458,8 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
const venueBackConfig = {
|
const venueBackConfig = {
|
||||||
...venueBaseConfig,
|
...venueBaseConfig,
|
||||||
venueImage: data.venueImages?.[1],
|
venueImage: data.venueImages?.[1],
|
||||||
venueImgX: scale * 400 * dpr,
|
venueImgX: scale * 400,
|
||||||
venueImgY: scale * 35 * dpr,
|
venueImgY: scale * 35,
|
||||||
rotation: scale * -10, // 旋转-10度
|
rotation: scale * -10, // 旋转-10度
|
||||||
}
|
}
|
||||||
await drawVenueImages(ctx, venueBackConfig)
|
await drawVenueImages(ctx, venueBackConfig)
|
||||||
@@ -502,11 +494,11 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
// 绘制"单打"标签
|
// 绘制"单打"标签
|
||||||
const danDaX = scale * 100
|
const danDaX = scale * 100
|
||||||
const danDaY = scale * 196
|
const danDaY = scale * 196
|
||||||
const danDaHeight = scale * 40 * dpr
|
const danDaHeight = scale * 40
|
||||||
const danDaRadius = scale * 20 * dpr
|
const danDaRadius = scale * 20
|
||||||
const danDaFontSize = scale * 22 * dpr
|
const danDaFontSize = scale * 22
|
||||||
// 根据内容动态计算标签宽度(左右内边距)
|
// 根据内容动态计算标签宽度(左右内边距)
|
||||||
const danDaPaddingX = scale * 16 * dpr
|
const danDaPaddingX = scale * 16
|
||||||
setFont2D(ctx, danDaFontSize)
|
setFont2D(ctx, danDaFontSize)
|
||||||
const danDaTextWidth = ctx.measureText(data.gameType).width
|
const danDaTextWidth = ctx.measureText(data.gameType).width
|
||||||
const danDaWidth = danDaTextWidth + danDaPaddingX * 2
|
const danDaWidth = danDaTextWidth + danDaPaddingX * 2
|
||||||
@@ -517,11 +509,11 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr,保持视觉间距)
|
const labelGap = scale * 16 // 两个标签之间的间距(不乘 dpr,保持视觉间距)
|
||||||
const skillX = danDaX + danDaWidth + labelGap
|
const skillX = danDaX + danDaWidth + labelGap
|
||||||
const skillY = scale * 196
|
const skillY = scale * 196
|
||||||
const skillHeight = scale * 40 * dpr
|
const skillHeight = scale * 40
|
||||||
const skillRadius = scale * 20 * dpr
|
const skillRadius = scale * 20
|
||||||
const skillFontSize = scale * 22 * dpr
|
const skillFontSize = scale * 22
|
||||||
// 根据内容动态计算技能标签宽度
|
// 根据内容动态计算技能标签宽度
|
||||||
const skillPaddingX = scale * 20 * dpr
|
const skillPaddingX = scale * 20
|
||||||
setFont2D(ctx, skillFontSize)
|
setFont2D(ctx, skillFontSize)
|
||||||
const skillTextWidth = ctx.measureText(data.skillLevel).width
|
const skillTextWidth = ctx.measureText(data.skillLevel).width
|
||||||
const skillWidth = skillTextWidth + skillPaddingX * 2
|
const skillWidth = skillTextWidth + skillPaddingX * 2
|
||||||
@@ -531,7 +523,7 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
// 绘制日期时间
|
// 绘制日期时间
|
||||||
const dateX = danDaX
|
const dateX = danDaX
|
||||||
const timeInfoY = infoStartY + infoSpacing
|
const timeInfoY = infoStartY + infoSpacing
|
||||||
const timeInfoFontSize = scale * 24 * dpr
|
const timeInfoFontSize = scale * 24
|
||||||
const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`)
|
const calendarPath = await loadImage(`${OSS_BASE}/front/ball/images/ea792a5d-b105-4c95-bfc4-8af558f2b33b.jpg`)
|
||||||
ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize)
|
ctx.drawImage(calendarPath, iconX, timeInfoY, iconSize, iconSize)
|
||||||
|
|
||||||
@@ -539,15 +531,16 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro
|
|||||||
drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD')
|
drawBoldText(ctx, data.gameDate, dateX, timeInfoY + 8, timeInfoFontSize, '#00E5AD')
|
||||||
|
|
||||||
// 绘制时间(黑色)
|
// 绘制时间(黑色)
|
||||||
const timeX = textX + ctx.measureText(data.gameDate).width + 10 * dpr
|
const timeX = textX + ctx.measureText(data.gameDate).width + scale * 10
|
||||||
drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000')
|
drawBoldText(ctx, data.gameTime, timeX, timeInfoY + 8, timeInfoFontSize, '#000000')
|
||||||
|
|
||||||
// 绘制地点
|
// 绘制地点
|
||||||
const locationInfoY = infoStartY + infoSpacing * 2
|
const locationInfoY = infoStartY + infoSpacing * 2
|
||||||
const locationFontSize = scale * 22 * dpr
|
const locationFontSize = scale * 22
|
||||||
const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`)
|
const locationPath = await loadImage(`${OSS_BASE}/front/ball/images/adc9a167-2ea9-4e3b-b963-6a894a1fd91b.jpg`)
|
||||||
ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize)
|
ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize)
|
||||||
drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000')
|
drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000')
|
||||||
|
ctx.restore()
|
||||||
try {
|
try {
|
||||||
const wxAny: any = (typeof (globalThis as any) !== 'undefined' && (globalThis as any).wx) ? (globalThis as any).wx : null
|
const wxAny: any = (typeof (globalThis as any) !== 'undefined' && (globalThis as any).wx) ? (globalThis as any).wx : null
|
||||||
if (wxAny && typeof wxAny.canvasToTempFilePath === 'function') {
|
if (wxAny && typeof wxAny.canvasToTempFilePath === 'function') {
|
||||||
|
|||||||
Reference in New Issue
Block a user