diff --git a/config/env.config.ts b/config/env.config.ts
index dc38fd9..4375a20 100644
--- a/config/env.config.ts
+++ b/config/env.config.ts
@@ -22,7 +22,7 @@ export interface EnvConfig {
const baseConfig = {
apiBaseURL: "https://tennis.bimwe.com",
- ossBaseURL: "https://bimwe-oss.oss-cn-shanghai.aliyuncs.com",
+ ossBaseURL: "https://bimwe.oss-cn-shanghai.aliyuncs.com",
appid: "wx815b533167eb7b53", // 测试号
timeout: 15000,
enableLog: true,
diff --git a/src/components/GameManagePopup/index.module.scss b/src/components/GameManagePopup/index.module.scss
index eefab2e..24b370e 100644
--- a/src/components/GameManagePopup/index.module.scss
+++ b/src/components/GameManagePopup/index.module.scss
@@ -13,7 +13,9 @@
align-items: center;
color: #000;
text-align: center;
- font-feature-settings: 'liga' off, 'clig' off;
+ font-feature-settings:
+ "liga" off,
+ "clig" off;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
@@ -32,7 +34,9 @@
padding-top: 24px;
color: #000;
text-align: center;
- font-feature-settings: 'liga' off, 'clig' off;
+ font-feature-settings:
+ "liga" off,
+ "clig" off;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
@@ -48,8 +52,10 @@
align-items: center;
.tips {
- color: rgba(60, 60, 67, 0.60);
- font-feature-settings: 'liga' off, 'clig' off;
+ color: rgba(60, 60, 67, 0.6);
+ font-feature-settings:
+ "liga" off,
+ "clig" off;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
@@ -62,13 +68,15 @@
margin-top: 8px;
padding: 8px;
border-radius: 4px;
- background: #F0F0F0;
+ background: #f0f0f0;
.input {
width: 100%;
&:placeholder-shown {
- color: rgba(60, 60, 67, 0.30);
- font-feature-settings: 'liga' off, 'clig' off;
+ color: rgba(60, 60, 67, 0.3);
+ font-feature-settings:
+ "liga" off,
+ "clig" off;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
@@ -84,11 +92,12 @@
justify-content: space-between;
align-items: center;
height: 44px;
- border-top: 0.5px solid #CECECE;
- background: #FFF;
+ border-top: 0.5px solid #cecece;
+ background: #fff;
margin-top: 2px;
- .confirm, .cancel {
+ .confirm,
+ .cancel {
width: 50%;
height: 44px;
display: flex;
@@ -96,7 +105,9 @@
align-items: center;
color: #000;
text-align: center;
- font-feature-settings: 'liga' off, 'clig' off;
+ font-feature-settings:
+ "liga" off,
+ "clig" off;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
@@ -109,4 +120,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/components/GameManagePopup/index.tsx b/src/components/GameManagePopup/index.tsx
index f03f290..1440b81 100644
--- a/src/components/GameManagePopup/index.tsx
+++ b/src/components/GameManagePopup/index.tsx
@@ -186,7 +186,7 @@ export default forwardRef(function GameManagePopup(props, ref) {
.some((item) => item.user.id === userInfo.id);
const finished = [MATCH_STATUS.FINISHED, MATCH_STATUS.CANCELED].includes(
- detail.match_status
+ detail.match_status,
);
const inTwoHours = dayjs(detail.start_time).diff(dayjs(), "hour") < 2;
@@ -207,7 +207,7 @@ export default forwardRef(function GameManagePopup(props, ref) {
style={{ minHeight: "unset" }}
>
- {!inTwoHours && !hasOtherParticiappants && (
+ {!finished && !inTwoHours && !hasOtherParticiappants && (
编辑活动
@@ -217,12 +217,12 @@ export default forwardRef(function GameManagePopup(props, ref) {
重新发布
)}
- {!inTwoHours && !hasOtherParticiappants && (
+ {!finished && !inTwoHours && !hasOtherParticiappants && (
取消活动
)}
- {hasJoin && (
+ {!finished && hasJoin && (
退出活动
diff --git a/src/components/Radar/indexV2.tsx b/src/components/Radar/indexV2.tsx
index 7d223b4..62d5e25 100644
--- a/src/components/Radar/indexV2.tsx
+++ b/src/components/Radar/indexV2.tsx
@@ -29,30 +29,36 @@ export interface RadarChartV2Ref {
}) => Promise;
}
-const RadarChartV2 = forwardRef((props, ref) => {
- const { data } = props;
+const RadarChartV2 = forwardRef(
+ (props, ref) => {
+ const { data } = props;
- const maxValue = 100;
- const levels = 5;
+ const maxValue = 100;
+ const levels = 5;
- // 在 exportCanvasV2 中绘制雷达图的函数
- function drawRadarChart(ctx: CanvasRenderingContext2D, radarX: number, radarY: number, radarSize: number) {
- // 雷达图中心点位置(radarSize 已经是2倍图尺寸)
- const center = {
- x: radarX + radarSize / 2,
- y: radarY + radarSize / 2
- };
-
- // 计算实际半径(radarSize 是直径,半径是直径的一半)
- const radius = radarSize / 2;
-
- // 启用抗锯齿
- ctx.imageSmoothingEnabled = true;
- ctx.imageSmoothingQuality = 'high';
- ctx.lineCap = 'round';
- ctx.lineJoin = 'round';
+ // 在 exportCanvasV2 中绘制雷达图的函数
+ function drawRadarChart(
+ ctx: CanvasRenderingContext2D,
+ radarX: number,
+ radarY: number,
+ radarSize: number,
+ ) {
+ // 雷达图中心点位置(radarSize 已经是2倍图尺寸)
+ const center = {
+ x: radarX + radarSize / 2,
+ y: radarY + radarSize / 2,
+ };
- // 解析数据
+ // 计算实际半径(radarSize 是直径,半径是直径的一半)
+ const radius = radarSize / 2;
+
+ // 启用抗锯齿
+ ctx.imageSmoothingEnabled = true;
+ ctx.imageSmoothingQuality = "high";
+ ctx.lineCap = "round";
+ ctx.lineJoin = "round";
+
+ // 解析数据
const { texts, vals } = data.reduce(
(res, item) => {
const [text, val] = item;
@@ -61,508 +67,583 @@ const RadarChartV2 = forwardRef((props, ref)
vals: [...res.vals, val],
};
},
- { texts: [], vals: [] }
+ { texts: [], vals: [] },
);
- // === 绘制圆形网格 ===
- for (let i = levels; i >= 1; i--) {
- const r = (radius / levels) * i;
- ctx.beginPath();
- ctx.arc(center.x, center.y, r, 0, Math.PI * 2);
- if (i % 2 === 1) {
- ctx.fillStyle = "#fff";
- ctx.fill();
- } else {
- ctx.fillStyle = "#CAFCF0";
- ctx.fill();
- }
- // 根据层级设置不同的线条颜色
- if (i === 1) {
- ctx.strokeStyle = "#E5E5E5";
- } else if (i <= 3) {
- ctx.strokeStyle = "#E0E0E0";
- } else {
- ctx.strokeStyle = "#D5D5D5";
- }
- ctx.lineWidth = 1 * (radarSize / 200); // 根据2倍图调整线宽
- ctx.stroke();
- }
-
- // === 坐标轴 & 标签 ===
- texts.forEach((label, i) => {
- const angle = ((Math.PI * 2) / texts.length) * i - Math.PI / 2;
- const x = center.x + radius * Math.cos(angle);
- const y = center.y + radius * Math.sin(angle);
-
- // 坐标轴
- ctx.beginPath();
- ctx.moveTo(center.x, center.y);
- ctx.lineTo(x, y);
- ctx.strokeStyle = "#E0E0E0";
- ctx.lineWidth = 1 * (radarSize / 200); // 根据2倍图调整线宽
- ctx.stroke();
-
- // 标签:沿轴线外侧延伸,文字中心对齐轴线端点(与 index.tsx 一致)
- const labelOffset = 28 * (radarSize / 200); // 文字距离圆圈的偏移量(2倍图)
- const textX = center.x + (radius + labelOffset) * Math.cos(angle);
- const textY = center.y + (radius + labelOffset) * Math.sin(angle);
-
- ctx.font = `${12 * (radarSize / 200)}px sans-serif`; // 根据2倍图调整字体大小
- ctx.fillStyle = "#333";
- ctx.textBaseline = "middle";
- ctx.textAlign = "center";
-
- ctx.fillText(label, textX, textY);
- });
-
- // === 数据区域 ===
- const baseRadius = (radius / levels) * 1; // 第二个环为起点
- const usableRadius = radius - baseRadius;
-
+ // === 绘制圆形网格 ===
+ for (let i = levels; i >= 1; i--) {
+ const r = (radius / levels) * i;
ctx.beginPath();
- vals.forEach((val, i) => {
- const angle = ((Math.PI * 2) / texts.length) * i - Math.PI / 2;
- const r = baseRadius + (val / maxValue) * usableRadius;
- const x = center.x + r * Math.cos(angle);
- const y = center.y + r * Math.sin(angle);
-
- if (i === 0) ctx.moveTo(x, y);
- else ctx.lineTo(x, y);
- });
- ctx.closePath();
- ctx.fillStyle = "rgba(0,200,180,0.3)";
- ctx.fill();
- ctx.strokeStyle = "#00c8b4";
- ctx.lineWidth = 3 * (radarSize / 200); // 根据2倍图调整线宽
+ ctx.arc(center.x, center.y, r, 0, Math.PI * 2);
+ if (i % 2 === 1) {
+ ctx.fillStyle = "#fff";
+ ctx.fill();
+ } else {
+ ctx.fillStyle = "#CAFCF0";
+ ctx.fill();
+ }
+ // 根据层级设置不同的线条颜色
+ if (i === 1) {
+ ctx.strokeStyle = "#E5E5E5";
+ } else if (i <= 3) {
+ ctx.strokeStyle = "#E0E0E0";
+ } else {
+ ctx.strokeStyle = "#D5D5D5";
+ }
+ ctx.lineWidth = 1 * (radarSize / 200); // 根据2倍图调整线宽
ctx.stroke();
- }
+ }
- // 加载图片工具函数
- function loadImage(canvas: any, src: string): Promise {
- return new Promise((resolve, reject) => {
- const img = canvas.createImage();
- img.onload = () => resolve(img);
- img.onerror = (err) => reject(err);
- img.src = src;
- });
- }
+ // === 坐标轴 & 标签 ===
+ texts.forEach((label, i) => {
+ const angle = ((Math.PI * 2) / texts.length) * i - Math.PI / 2;
+ const x = center.x + radius * Math.cos(angle);
+ const y = center.y + radius * Math.sin(angle);
- // 获取图片信息(宽高)
- function getImageInfo(src: string): Promise<{ width: number; height: number }> {
- return new Promise((resolve, reject) => {
- (Taro as any).getImageInfo({
- src,
- success: (res: any) => resolve({ width: res.width, height: res.height }),
- fail: reject,
+ // 坐标轴
+ ctx.beginPath();
+ ctx.moveTo(center.x, center.y);
+ ctx.lineTo(x, y);
+ ctx.strokeStyle = "#E0E0E0";
+ ctx.lineWidth = 1 * (radarSize / 200); // 根据2倍图调整线宽
+ ctx.stroke();
+
+ // 标签:沿轴线外侧延伸,文字中心对齐轴线端点(与 index.tsx 一致)
+ const labelOffset = 28 * (radarSize / 200); // 文字距离圆圈的偏移量(2倍图)
+ const textX = center.x + (radius + labelOffset) * Math.cos(angle);
+ const textY = center.y + (radius + labelOffset) * Math.sin(angle);
+
+ ctx.font = `${12 * (radarSize / 200)}px sans-serif`; // 根据2倍图调整字体大小
+ ctx.fillStyle = "#333";
+ ctx.textBaseline = "middle";
+ ctx.textAlign = "center";
+
+ ctx.fillText(label, textX, textY);
});
- });
- }
+ // === 数据区域 ===
+ const baseRadius = (radius / levels) * 1; // 第二个环为起点
+ const usableRadius = radius - baseRadius;
- // 绘制圆角矩形
- function roundRect(ctx: any, x: number, y: number, width: number, height: number, radius: number) {
- ctx.beginPath();
- ctx.moveTo(x + radius, y);
- ctx.lineTo(x + width - radius, y);
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
- ctx.lineTo(x + width, y + height - radius);
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
- ctx.lineTo(x + radius, y + height);
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
- ctx.lineTo(x, y + radius);
- ctx.quadraticCurveTo(x, y, x + radius, y);
- ctx.closePath();
- }
+ ctx.beginPath();
+ vals.forEach((val, i) => {
+ const angle = ((Math.PI * 2) / texts.length) * i - Math.PI / 2;
+ const r = baseRadius + (val / maxValue) * usableRadius;
+ const x = center.x + r * Math.cos(angle);
+ const y = center.y + r * Math.sin(angle);
- // 格式化 NTRP 显示
- function formatNtrpDisplay(level: string): string {
- if (!level) return "";
- // 检查是否包含 + 号
- const hasPlus = level.includes("+");
- const num = parseFloat(level);
- if (isNaN(num)) return level;
- const formatted = num % 1 === 0 ? num.toFixed(0) : num.toFixed(1);
- return hasPlus ? `${formatted}+` : formatted;
- }
+ if (i === 0) ctx.moveTo(x, y);
+ else ctx.lineTo(x, y);
+ });
+ ctx.closePath();
+ ctx.fillStyle = "rgba(0,200,180,0.3)";
+ ctx.fill();
+ ctx.strokeStyle = "#00c8b4";
+ ctx.lineWidth = 3 * (radarSize / 200); // 根据2倍图调整线宽
+ ctx.stroke();
+ }
- useImperativeHandle(ref, () => ({
- // 生成原始雷达图(已废弃,现在直接在 exportCanvasV2 中绘制)
- generateImage: () =>
- Promise.resolve(""),
-
- // 生成完整图片(包含标题、雷达图、底部文字和二维码)
- generateFullImage: async (options: {
- title?: string;
- ntrpLevel?: string;
- levelDescription?: string;
- avatarUrl?: string;
- qrCodeUrl?: string;
- bottomText?: string;
- width?: number;
- height?: number;
- }) => {
- return new Promise(async (resolve, reject) => {
- try {
- // 使用2倍图提高图片质量
- const scale = 2; // 2倍图
- const baseWidth = 350; // 基础宽度
- const baseHeight = 600; // 基础高度
- const width = baseWidth * scale; // 实际宽度 700
- const height = baseHeight * scale; // 实际高度 1200
+ // 加载图片工具函数
+ function loadImage(canvas: any, src: string): Promise {
+ return new Promise((resolve, reject) => {
+ const img = canvas.createImage();
+ img.onload = () => resolve(img);
+ img.onerror = (err) => reject(err);
+ img.src = src;
+ });
+ }
- // 创建导出画布
- const query = Taro.createSelectorQuery();
- query
- .select("#exportCanvasV2")
- .fields({ node: true, size: true })
- .exec(async (res) => {
- if (!res || !res[0]) {
- reject(new Error("Canvas not found"));
- return;
- }
+ // 获取图片信息(宽高)
+ function getImageInfo(
+ src: string,
+ ): Promise<{ width: number; height: number }> {
+ return new Promise((resolve, reject) => {
+ (Taro as any).getImageInfo({
+ src,
+ success: (res: any) =>
+ resolve({ width: res.width, height: res.height }),
+ fail: reject,
+ });
+ });
+ }
- const canvas = res[0].node;
- const ctx = canvas.getContext("2d");
- // 使用2倍图尺寸
- canvas.width = width;
- canvas.height = height;
+ // 绘制圆角矩形
+ function roundRect(
+ ctx: any,
+ x: number,
+ y: number,
+ width: number,
+ height: number,
+ radius: number,
+ ) {
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(
+ x + width,
+ y + height,
+ x + width - radius,
+ y + height,
+ );
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+ }
- // 启用抗锯齿
- ctx.imageSmoothingEnabled = true;
- ctx.imageSmoothingQuality = 'high';
+ // 格式化 NTRP 显示
+ function formatNtrpDisplay(level: string): string {
+ if (!level) return "";
+ // 检查是否包含 + 号
+ const hasPlus = level.includes("+");
+ const num = parseFloat(level);
+ if (isNaN(num)) return level;
+ const formatted = num % 1 === 0 ? num.toFixed(0) : num.toFixed(1);
+ return hasPlus ? `${formatted}+` : formatted;
+ }
- // 绘制背景 - 使用 share_bg.png 背景图,撑满整个画布(从 OSS 动态加载)
- try {
- const shareBgUrl = `${OSS_BASE}/front/ball/images/share_bg.png`;
- const bgImg = await loadImage(canvas, shareBgUrl);
- ctx.drawImage(bgImg, 0, 0, width, height);
- } catch (error) {
- console.error("Failed to load background image:", error);
- // 如果加载失败,使用白色背景作为兜底
- ctx.fillStyle = "#FFFFFF";
- ctx.fillRect(0, 0, width, height);
- }
+ useImperativeHandle(ref, () => ({
+ // 生成原始雷达图(已废弃,现在直接在 exportCanvasV2 中绘制)
+ generateImage: () => Promise.resolve(""),
- // 根据设计稿调整内边距和布局(2倍图)
- const topPadding = 24 * scale; // 设计稿顶部内边距
- const sidePadding = 28 * scale; // 设计稿左右内边距(Frame 1912055062 的 x: 28)
-
- let currentY = topPadding;
+ // 生成完整图片(包含标题、雷达图、底部文字和二维码)
+ generateFullImage: async (options: {
+ title?: string;
+ ntrpLevel?: string;
+ levelDescription?: string;
+ avatarUrl?: string;
+ qrCodeUrl?: string;
+ bottomText?: string;
+ width?: number;
+ height?: number;
+ }) => {
+ return new Promise(async (resolve, reject) => {
+ try {
+ // 使用2倍图提高图片质量
+ const scale = 2; // 2倍图
+ const baseWidth = 350; // 基础宽度
+ const baseHeight = 600; // 基础高度
+ const width = baseWidth * scale; // 实际宽度 700
+ const height = baseHeight * scale; // 实际高度 1200
- // 绘制用户头像和装饰图片 - 根据设计稿尺寸(2倍图)
- if (options.avatarUrl) {
+ // 创建导出画布
+ const query = Taro.createSelectorQuery();
+ query
+ .select("#exportCanvasV2")
+ .fields({ node: true, size: true })
+ .exec(async (res) => {
+ if (!res || !res[0]) {
+ reject(new Error("Canvas not found"));
+ return;
+ }
+
+ const canvas = res[0].node;
+ const ctx = canvas.getContext("2d");
+ // 使用2倍图尺寸
+ canvas.width = width;
+ canvas.height = height;
+
+ // 启用抗锯齿
+ ctx.imageSmoothingEnabled = true;
+ ctx.imageSmoothingQuality = "high";
+
+ // 绘制背景 - 使用 share_bg.png 背景图,撑满整个画布(从 OSS 动态加载)
try {
- const avatarSize = 43.46 * scale; // 设计稿头像尺寸
- const avatarImg = await loadImage(canvas, options.avatarUrl);
- const avatarInfo = await getImageInfo(options.avatarUrl);
-
- // 头像区域总宽度(头像 + 装饰图片重叠部分)
- const avatarWrapWidth = 84.7 * scale; // 设计稿 Frame 1912055063 宽度
- const avatarX = sidePadding + (294 * scale - avatarWrapWidth) / 2; // 294 是 Frame 1912055062 宽度,居中
- const avatarY = currentY;
-
- // 绘制头像圆形背景
- ctx.save();
- ctx.beginPath();
- ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
+ const shareBgUrl = `${OSS_BASE}/front/ball/images/share_bg.png`;
+ const bgImg = await loadImage(canvas, shareBgUrl);
+ ctx.drawImage(bgImg, 0, 0, width, height);
+ } catch (error) {
+ console.error("Failed to load background image:", error);
+ // 如果加载失败,使用白色背景作为兜底
ctx.fillStyle = "#FFFFFF";
- ctx.fill();
- ctx.strokeStyle = "#EFEFEF";
- ctx.lineWidth = 1 * scale;
- ctx.stroke();
-
- // 计算头像绘制尺寸,保持宽高比
- const innerSize = avatarSize - 1.94 * scale; // 内部可用尺寸
- const avatarAspectRatio = avatarInfo.width / avatarInfo.height;
- let drawWidth = innerSize;
- let drawHeight = innerSize;
- let drawX = avatarX + 0.97 * scale;
- let drawY = avatarY + 0.97 * scale;
-
- // 根据宽高比调整尺寸,保持比例不变形
- if (avatarAspectRatio > 1) {
- // 图片更宽,以高度为准
- drawWidth = innerSize * avatarAspectRatio;
- drawX = avatarX + avatarSize / 2 - drawWidth / 2;
- } else {
- // 图片更高或正方形,以宽度为准
- drawHeight = innerSize / avatarAspectRatio;
- drawY = avatarY + avatarSize / 2 - drawHeight / 2;
- }
-
- // 绘制头像(圆形裁剪)
- ctx.beginPath();
- ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2 - 0.97 * scale, 0, Math.PI * 2);
- ctx.clip();
- ctx.drawImage(avatarImg, drawX, drawY, drawWidth, drawHeight);
- ctx.restore();
-
- // 绘制装饰图片(DocCopy)- 在头像右侧
- const addonSize = 42 * scale; // 装饰图片和头像一样大
- const addonX = avatarX + avatarSize - 5 * scale; // 重叠部分
- const addonY = avatarY;
- const addonRotation = 8 * (Math.PI / 180); // 旋转 8 度
-
+ ctx.fillRect(0, 0, width, height);
+ }
+
+ // 根据设计稿调整内边距和布局(2倍图)
+ const topPadding = 24 * scale; // 设计稿顶部内边距
+ const sidePadding = 28 * scale; // 设计稿左右内边距(Frame 1912055062 的 x: 28)
+
+ let currentY = topPadding;
+
+ // 绘制用户头像和装饰图片 - 根据设计稿尺寸(2倍图)
+ if (options.avatarUrl) {
try {
- const docCopyImg = await loadImage(canvas, docCopyPng);
+ const avatarSize = 43.46 * scale; // 设计稿头像尺寸
+ const avatarImg = await loadImage(
+ canvas,
+ options.avatarUrl,
+ );
+ const avatarInfo = await getImageInfo(options.avatarUrl);
+
+ // 头像区域总宽度(头像 + 装饰图片重叠部分)
+ const avatarWrapWidth = 84.7 * scale; // 设计稿 Frame 1912055063 宽度
+ const avatarX =
+ sidePadding + (294 * scale - avatarWrapWidth) / 2; // 294 是 Frame 1912055062 宽度,居中
+ const avatarY = currentY;
+
+ // 绘制头像圆形背景
ctx.save();
-
- // 移动到旋转中心
- const centerX = addonX + addonSize / 2;
- const centerY = addonY + addonSize / 2;
- ctx.translate(centerX, centerY);
- ctx.rotate(addonRotation);
-
- // 绘制装饰图片背景(圆角矩形,带渐变)
- const borderRadius = 9.66 * scale; // 设计稿圆角
- ctx.fillStyle = "#FFFFFF";
ctx.beginPath();
- roundRect(ctx, -addonSize / 2, -addonSize / 2, addonSize, addonSize, borderRadius);
+ ctx.arc(
+ avatarX + avatarSize / 2,
+ avatarY + avatarSize / 2,
+ avatarSize / 2,
+ 0,
+ Math.PI * 2,
+ );
+ ctx.fillStyle = "#FFFFFF";
ctx.fill();
-
- // 添加渐变背景色
- ctx.globalAlpha = 0.2;
- ctx.fillStyle = "rgba(89, 255, 214, 1)";
- ctx.fill();
- ctx.globalAlpha = 1.0;
-
- ctx.strokeStyle = "#FFFFFF";
- ctx.lineWidth = 1.93 * scale; // 设计稿 strokeWeight
+ ctx.strokeStyle = "#EFEFEF";
+ ctx.lineWidth = 1 * scale;
ctx.stroke();
-
- // 绘制装饰图片
- const docSize = 26.18 * scale; // 设计稿内部图片尺寸
- const docRotation = -7 * (Math.PI / 180); // 内部旋转 -7 度
- ctx.rotate(docRotation);
- ctx.drawImage(docCopyImg, -docSize / 2, -docSize / 2, docSize, docSize);
+
+ // 计算头像绘制尺寸,保持宽高比
+ const innerSize = avatarSize - 1.94 * scale; // 内部可用尺寸
+ const avatarAspectRatio =
+ avatarInfo.width / avatarInfo.height;
+ let drawWidth = innerSize;
+ let drawHeight = innerSize;
+ let drawX = avatarX + 0.97 * scale;
+ let drawY = avatarY + 0.97 * scale;
+
+ // 根据宽高比调整尺寸,保持比例不变形
+ if (avatarAspectRatio > 1) {
+ // 图片更宽,以高度为准
+ drawWidth = innerSize * avatarAspectRatio;
+ drawX = avatarX + avatarSize / 2 - drawWidth / 2;
+ } else {
+ // 图片更高或正方形,以宽度为准
+ drawHeight = innerSize / avatarAspectRatio;
+ drawY = avatarY + avatarSize / 2 - drawHeight / 2;
+ }
+
+ // 绘制头像(圆形裁剪)
+ ctx.beginPath();
+ ctx.arc(
+ avatarX + avatarSize / 2,
+ avatarY + avatarSize / 2,
+ avatarSize / 2 - 0.97 * scale,
+ 0,
+ Math.PI * 2,
+ );
+ ctx.clip();
+ ctx.drawImage(
+ avatarImg,
+ drawX,
+ drawY,
+ drawWidth,
+ drawHeight,
+ );
+ ctx.restore();
+
+ // 绘制装饰图片(DocCopy)- 在头像右侧
+ const addonSize = 42 * scale; // 装饰图片和头像一样大
+ const addonX = avatarX + avatarSize - 5 * scale; // 重叠部分
+ const addonY = avatarY;
+ const addonRotation = 8 * (Math.PI / 180); // 旋转 8 度
+
+ try {
+ const docCopyImg = await loadImage(canvas, docCopyPng);
+ ctx.save();
+
+ // 移动到旋转中心
+ const centerX = addonX + addonSize / 2;
+ const centerY = addonY + addonSize / 2;
+ ctx.translate(centerX, centerY);
+ ctx.rotate(addonRotation);
+
+ // 绘制装饰图片背景(圆角矩形,带渐变)
+ const borderRadius = 9.66 * scale; // 设计稿圆角
+ ctx.fillStyle = "#FFFFFF";
+ ctx.beginPath();
+ roundRect(
+ ctx,
+ -addonSize / 2,
+ -addonSize / 2,
+ addonSize,
+ addonSize,
+ borderRadius,
+ );
+ ctx.fill();
+
+ // 添加渐变背景色
+ ctx.globalAlpha = 0.2;
+ ctx.fillStyle = "rgba(89, 255, 214, 1)";
+ ctx.fill();
+ ctx.globalAlpha = 1.0;
+
+ ctx.strokeStyle = "#FFFFFF";
+ ctx.lineWidth = 1.93 * scale; // 设计稿 strokeWeight
+ ctx.stroke();
+
+ // 绘制装饰图片
+ const docSize = 26.18 * scale; // 设计稿内部图片尺寸
+ const docRotation = -7 * (Math.PI / 180); // 内部旋转 -7 度
+ ctx.rotate(docRotation);
+ ctx.drawImage(
+ docCopyImg,
+ -docSize / 2,
+ -docSize / 2,
+ docSize,
+ docSize,
+ );
+ ctx.restore();
+ } catch (error) {
+ console.error("Failed to load docCopy image:", error);
+ }
+
+ currentY += (48 + 20) * scale; // 头像区域高度 + gap
+ } catch (error) {
+ console.error("Failed to load avatar image:", error);
+ }
+ }
+
+ // 绘制文字区域 - 根据设计稿样式,居中对齐(2倍图)
+ const textCenterX = sidePadding + (294 * scale) / 2; // Frame 1912055062 的中心
+ const textGap = 6 * scale; // 设计稿 gap: 6px
+
+ // 绘制标题 - 14px, font-weight: 300, line-height: 1.2(2倍图)
+ if (options.title) {
+ ctx.fillStyle = "#000000";
+ ctx.font = `300 ${14 * scale}px Noto Sans SC, sans-serif`;
+ ctx.textAlign = "center";
+ ctx.textBaseline = "top";
+ ctx.fillText(options.title, textCenterX, currentY);
+ currentY += 14 * 1.2 * scale + textGap; // line-height: 1.2 + gap
+ }
+
+ // 绘制 NTRP 等级 - 36px, font-weight: 900, "NTRP" 黑色,等级数字 #00E5AD(2倍图)
+ if (options.ntrpLevel) {
+ ctx.font = `900 ${36 * scale}px Noto Sans SC, sans-serif`;
+ ctx.textBaseline = "top";
+
+ const ntrpText = "NTRP";
+ const levelText = formatNtrpDisplay(options.ntrpLevel);
+ const ntrpWidth = ctx.measureText(ntrpText).width;
+ const levelWidth = ctx.measureText(levelText).width;
+ const totalWidth = ntrpWidth + levelWidth; // 设计稿中紧挨着
+ const startX = textCenterX - totalWidth / 2;
+
+ // 绘制 "NTRP"(黑色)
+ ctx.fillStyle = "#000000";
+ ctx.textAlign = "left";
+ ctx.fillText(ntrpText, startX, currentY);
+
+ // 绘制等级数字(#00E5AD)
+ ctx.fillStyle = "#00E5AD";
+ ctx.fillText(levelText, startX + ntrpWidth, currentY);
+
+ currentY += 36 * 1.222 * scale + textGap; // line-height: 1.222 + gap
+ }
+
+ // 绘制描述文本 - 16px, font-weight: 600, line-height: 1.4(2倍图)
+ if (options.levelDescription) {
+ ctx.fillStyle = "#000000";
+ ctx.font = `600 ${16 * scale}px PingFang SC, sans-serif`;
+ ctx.textAlign = "center";
+ ctx.textBaseline = "top";
+ ctx.fillText(options.levelDescription, textCenterX, currentY);
+ // 计算到雷达图的间距:雷达图 y: 252 - 当前 Y
+ const radarY = 252 * scale; // 设计稿雷达图位置
+ currentY = radarY; // 直接设置到雷达图位置
+ }
+
+ // 直接绘制雷达图 - 根据设计稿调整尺寸和位置(2倍图)
+ const radarSize = 200 * scale; // 固定雷达图尺寸为 200*200
+ const radarX = 75 * scale; // 设计稿雷达图 x 位置
+ const radarY = currentY;
+ // 直接在 exportCanvasV2 中绘制雷达图
+ drawRadarChart(ctx, radarX, radarY, radarSize);
+ currentY += radarSize; // 雷达图高度
+
+ // 绘制底部区域 - 根据设计稿调整(2倍图)
+ const qrSize = 64 * scale; // 设计稿二维码尺寸:64*64
+ const qrX = 276 * scale; // 设计稿二维码 x 位置
+ const qrY = 523 * scale; // 设计稿二维码 y 位置
+
+ const bottomTextContent =
+ options.bottomText ||
+ "长按识别二维码,快来加入,有你就有场!";
+
+ // 绘制底部文字 - 设计稿:fontSize: 12, fontWeight: 400, line-height: 1.5(2倍图)
+ ctx.fillStyle = "rgba(0, 0, 0, 0.45)";
+ ctx.font = `400 ${12 * scale}px Noto Sans SC, sans-serif`;
+ ctx.textAlign = "left";
+ ctx.textBaseline = "top";
+
+ const textX = 20 * scale; // 设计稿文字 x 位置
+ const maxTextWidth = qrX - textX - 10 * scale; // 到二维码的间距
+
+ // 计算文字行数
+ const bottomWords = bottomTextContent.split("");
+ let bottomLine = "";
+ let textLines: string[] = [];
+ const lineHeight = 12 * 1.5 * scale; // fontSize * line-height
+
+ for (let i = 0; i < bottomWords.length; i++) {
+ const testBottomLine = bottomLine + bottomWords[i];
+ const metrics = ctx.measureText(testBottomLine);
+ if (metrics.width > maxTextWidth && i > 0) {
+ textLines.push(bottomLine);
+ bottomLine = bottomWords[i];
+ } else {
+ bottomLine = testBottomLine;
+ }
+ }
+ if (bottomLine) {
+ textLines.push(bottomLine);
+ }
+
+ // 计算文字总高度
+ const textTotalHeight = textLines.length * lineHeight;
+ // 计算二维码底部位置
+ const qrBottomY = qrY + qrSize;
+ // 让文字底部和二维码底部对齐
+ const textY = qrBottomY - textTotalHeight;
+
+ // 绘制顶部标题和图标 - 设计稿 Frame 2036081426(2倍图)
+ // 图标应该在文字上方,gap: 4px
+ const iconGap = 4 * scale; // 图标和文字之间的间距
+ const topTitleX = textX;
+
+ // 绘制上面的标题 logo
+ try {
+ const iconSize = 28 * scale;
+ const iconImg = await loadImage(canvas, shareLogoSvg);
+ // 图标位置:文字顶部上方 iconSize + gap
+ const iconY = textY - iconSize - iconGap;
+ ctx.drawImage(
+ iconImg,
+ topTitleX,
+ iconY,
+ 235 * scale,
+ iconSize,
+ );
+ } catch (error) {
+ console.error("Failed to load icon:", error);
+ }
+
+ // 绘制底部文字
+ textLines.forEach((lineText, index) => {
+ ctx.fillText(lineText, textX, textY + index * lineHeight);
+ });
+
+ // 绘制二维码 - 设计稿位置(带白色背景、边框、阴影和圆角)
+
+ if (options.qrCodeUrl) {
+ try {
+ const qrImg = await loadImage(canvas, options.qrCodeUrl);
+
+ // 二维码样式参数(2倍图)
+ const borderWidth = 2 * scale; // 边框宽度 2px
+ const borderRadius = 10 * scale; // 圆角 10px
+ const shadowOffsetX = 0; // 阴影 X 偏移
+ const shadowOffsetY = 1.04727 * scale; // 阴影 Y 偏移 1.04727px
+ const shadowBlur = 9.42545 * scale; // 阴影模糊 9.42545px
+ const shadowColor = "rgba(0, 0, 0, 0.12)"; // 阴影颜色
+
+ // 二维码实际绘制区域(留出边框空间)
+ const qrInnerSize = qrSize - borderWidth * 2;
+ const qrInnerX = qrX + borderWidth;
+ const qrInnerY = qrY + borderWidth;
+
+ // 保存上下文状态
+ ctx.save();
+
+ // 设置阴影
+ ctx.shadowOffsetX = shadowOffsetX;
+ ctx.shadowOffsetY = shadowOffsetY;
+ ctx.shadowBlur = shadowBlur;
+ ctx.shadowColor = shadowColor;
+
+ // 绘制白色背景(圆角矩形)
+ ctx.fillStyle = "#FFFFFF";
+ roundRect(ctx, qrX, qrY, qrSize, qrSize, borderRadius);
+ ctx.fill();
+
+ // 绘制白色边框
+ ctx.strokeStyle = "#FFFFFF";
+ ctx.lineWidth = borderWidth;
+ roundRect(ctx, qrX, qrY, qrSize, qrSize, borderRadius);
+ ctx.stroke();
+
+ // 清除阴影(二维码图片不需要阴影)
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 0;
+ ctx.shadowBlur = 0;
+ ctx.shadowColor = "transparent";
+
+ // 绘制二维码图片(在圆角矩形内)
+ ctx.save();
+ // 创建圆角裁剪区域
+ roundRect(
+ ctx,
+ qrInnerX,
+ qrInnerY,
+ qrInnerSize,
+ qrInnerSize,
+ borderRadius - borderWidth,
+ );
+ ctx.clip();
+ // 绘制二维码图片
+ ctx.drawImage(
+ qrImg,
+ qrInnerX,
+ qrInnerY,
+ qrInnerSize,
+ qrInnerSize,
+ );
+ ctx.restore();
+
+ // 恢复上下文状态
ctx.restore();
} catch (error) {
- console.error("Failed to load docCopy image:", error);
+ console.error("Failed to load QR code:", error);
}
-
- currentY += (48 + 20) * scale; // 头像区域高度 + gap
- } catch (error) {
- console.error("Failed to load avatar image:", error);
}
- }
- // 绘制文字区域 - 根据设计稿样式,居中对齐(2倍图)
- const textCenterX = sidePadding + (294 * scale) / 2; // Frame 1912055062 的中心
- const textGap = 6 * scale; // 设计稿 gap: 6px
-
- // 绘制标题 - 14px, font-weight: 300, line-height: 1.2(2倍图)
- if (options.title) {
- ctx.fillStyle = "#000000";
- ctx.font = `300 ${14 * scale}px Noto Sans SC, sans-serif`;
- ctx.textAlign = "center";
- ctx.textBaseline = "top";
- ctx.fillText(options.title, textCenterX, currentY);
- currentY += 14 * 1.2 * scale + textGap; // line-height: 1.2 + gap
- }
-
- // 绘制 NTRP 等级 - 36px, font-weight: 900, "NTRP" 黑色,等级数字 #00E5AD(2倍图)
- if (options.ntrpLevel) {
- ctx.font = `900 ${36 * scale}px Noto Sans SC, sans-serif`;
- ctx.textBaseline = "top";
-
- const ntrpText = "NTRP";
- const levelText = formatNtrpDisplay(options.ntrpLevel);
- const ntrpWidth = ctx.measureText(ntrpText).width;
- const levelWidth = ctx.measureText(levelText).width;
- const totalWidth = ntrpWidth + levelWidth; // 设计稿中紧挨着
- const startX = textCenterX - totalWidth / 2;
-
- // 绘制 "NTRP"(黑色)
- ctx.fillStyle = "#000000";
- ctx.textAlign = "left";
- ctx.fillText(ntrpText, startX, currentY);
-
- // 绘制等级数字(#00E5AD)
- ctx.fillStyle = "#00E5AD";
- ctx.fillText(levelText, startX + ntrpWidth, currentY);
-
- currentY += 36 * 1.222 * scale + textGap; // line-height: 1.222 + gap
- }
-
- // 绘制描述文本 - 16px, font-weight: 600, line-height: 1.4(2倍图)
- if (options.levelDescription) {
- ctx.fillStyle = "#000000";
- ctx.font = `600 ${16 * scale}px PingFang SC, sans-serif`;
- ctx.textAlign = "center";
- ctx.textBaseline = "top";
- ctx.fillText(options.levelDescription, textCenterX, currentY);
- // 计算到雷达图的间距:雷达图 y: 252 - 当前 Y
- const radarY = 252 * scale; // 设计稿雷达图位置
- currentY = radarY; // 直接设置到雷达图位置
- }
-
- // 直接绘制雷达图 - 根据设计稿调整尺寸和位置(2倍图)
- const radarSize = 200 * scale; // 固定雷达图尺寸为 200*200
- const radarX = 75 * scale; // 设计稿雷达图 x 位置
- const radarY = currentY;
- // 直接在 exportCanvasV2 中绘制雷达图
- drawRadarChart(ctx, radarX, radarY, radarSize);
- currentY += radarSize; // 雷达图高度
-
- // 绘制底部区域 - 根据设计稿调整(2倍图)
- const qrSize = 64 * scale; // 设计稿二维码尺寸:64*64
- const qrX = 276 * scale; // 设计稿二维码 x 位置
- const qrY = 523 * scale; // 设计稿二维码 y 位置
-
- const bottomTextContent = options.bottomText || "长按识别二维码,快来加入,有你就有场!";
-
- // 绘制底部文字 - 设计稿:fontSize: 12, fontWeight: 400, line-height: 1.5(2倍图)
- ctx.fillStyle = "rgba(0, 0, 0, 0.45)";
- ctx.font = `400 ${12 * scale}px Noto Sans SC, sans-serif`;
- ctx.textAlign = "left";
- ctx.textBaseline = "top";
-
- const textX = 20 * scale; // 设计稿文字 x 位置
- const maxTextWidth = qrX - textX - 10 * scale; // 到二维码的间距
-
- // 计算文字行数
- const bottomWords = bottomTextContent.split("");
- let bottomLine = "";
- let textLines: string[] = [];
- const lineHeight = 12 * 1.5 * scale; // fontSize * line-height
-
- for (let i = 0; i < bottomWords.length; i++) {
- const testBottomLine = bottomLine + bottomWords[i];
- const metrics = ctx.measureText(testBottomLine);
- if (metrics.width > maxTextWidth && i > 0) {
- textLines.push(bottomLine);
- bottomLine = bottomWords[i];
- } else {
- bottomLine = testBottomLine;
- }
- }
- if (bottomLine) {
- textLines.push(bottomLine);
- }
-
- // 计算文字总高度
- const textTotalHeight = textLines.length * lineHeight;
- // 计算二维码底部位置
- const qrBottomY = qrY + qrSize;
- // 让文字底部和二维码底部对齐
- const textY = qrBottomY - textTotalHeight;
-
- // 绘制顶部标题和图标 - 设计稿 Frame 2036081426(2倍图)
- // 图标应该在文字上方,gap: 4px
- const iconGap = 4 * scale; // 图标和文字之间的间距
- const topTitleX = textX;
-
- // 绘制上面的标题 logo
- try {
- const iconSize = 28 * scale;
- const iconImg = await loadImage(canvas, shareLogoSvg);
- // 图标位置:文字顶部上方 iconSize + gap
- const iconY = textY - iconSize - iconGap;
- ctx.drawImage(iconImg, topTitleX, iconY, 235 * scale, iconSize);
- } catch (error) {
- console.error("Failed to load icon:", error);
- }
-
- // 绘制底部文字
- textLines.forEach((lineText, index) => {
- ctx.fillText(lineText, textX, textY + index * lineHeight);
+ // 导出图片
+ Taro.canvasToTempFilePath({
+ canvas,
+ fileType: "png",
+ quality: 0.7,
+ success: (res) => {
+ resolve(res.tempFilePath);
+ },
+ fail: (err) => {
+ reject(err);
+ },
+ });
});
-
-
- // 绘制二维码 - 设计稿位置(带白色背景、边框、阴影和圆角)
-
- if (options.qrCodeUrl) {
- try {
- const qrImg = await loadImage(canvas, options.qrCodeUrl);
-
- // 二维码样式参数(2倍图)
- const borderWidth = 2 * scale; // 边框宽度 2px
- const borderRadius = 10 * scale; // 圆角 10px
- const shadowOffsetX = 0; // 阴影 X 偏移
- const shadowOffsetY = 1.04727 * scale; // 阴影 Y 偏移 1.04727px
- const shadowBlur = 9.42545 * scale; // 阴影模糊 9.42545px
- const shadowColor = "rgba(0, 0, 0, 0.12)"; // 阴影颜色
-
- // 二维码实际绘制区域(留出边框空间)
- const qrInnerSize = qrSize - borderWidth * 2;
- const qrInnerX = qrX + borderWidth;
- const qrInnerY = qrY + borderWidth;
-
- // 保存上下文状态
- ctx.save();
-
- // 设置阴影
- ctx.shadowOffsetX = shadowOffsetX;
- ctx.shadowOffsetY = shadowOffsetY;
- ctx.shadowBlur = shadowBlur;
- ctx.shadowColor = shadowColor;
-
- // 绘制白色背景(圆角矩形)
- ctx.fillStyle = "#FFFFFF";
- roundRect(ctx, qrX, qrY, qrSize, qrSize, borderRadius);
- ctx.fill();
-
- // 绘制白色边框
- ctx.strokeStyle = "#FFFFFF";
- ctx.lineWidth = borderWidth;
- roundRect(ctx, qrX, qrY, qrSize, qrSize, borderRadius);
- ctx.stroke();
-
- // 清除阴影(二维码图片不需要阴影)
- ctx.shadowOffsetX = 0;
- ctx.shadowOffsetY = 0;
- ctx.shadowBlur = 0;
- ctx.shadowColor = "transparent";
-
- // 绘制二维码图片(在圆角矩形内)
- ctx.save();
- // 创建圆角裁剪区域
- roundRect(ctx, qrInnerX, qrInnerY, qrInnerSize, qrInnerSize, borderRadius - borderWidth);
- ctx.clip();
- // 绘制二维码图片
- ctx.drawImage(qrImg, qrInnerX, qrInnerY, qrInnerSize, qrInnerSize);
- ctx.restore();
-
- // 恢复上下文状态
- ctx.restore();
- } catch (error) {
- console.error("Failed to load QR code:", error);
- }
- }
+ } catch (error) {
+ reject(error);
+ }
+ });
+ },
+ }));
- // 导出图片
- Taro.canvasToTempFilePath({
- canvas,
- fileType: 'png',
- quality: 1,
- success: (res) => {
- resolve(res.tempFilePath);
- },
- fail: (err) => {
- reject(err);
- },
- });
- });
- } catch (error) {
- reject(error);
- }
- });
- },
- }));
-
- return (
-
- {/* 隐藏的导出画布 - 2倍图尺寸 */}
-
-
- );
-});
+ return (
+
+ {/* 隐藏的导出画布 - 2倍图尺寸 */}
+
+
+ );
+ },
+);
RadarChartV2.displayName = "RadarChartV2";
export default RadarChartV2;
-
diff --git a/src/game_pages/detail/components/Participants/index.tsx b/src/game_pages/detail/components/Participants/index.tsx
index 56e3e10..9c18c23 100644
--- a/src/game_pages/detail/components/Participants/index.tsx
+++ b/src/game_pages/detail/components/Participants/index.tsx
@@ -40,7 +40,7 @@ function isFull(counts) {
function matchNtrpRequestment(
target?: string,
min?: string,
- max?: string
+ max?: string,
): boolean {
// 目标值为空或 undefined
if (!target?.trim()) return true;
@@ -110,7 +110,7 @@ export default function Participants(props) {
user_action_status;
const showApplicationEntry =
[can_pay, can_substitute, is_substituting, waiting_start].every(
- (item) => !item
+ (item) => !item,
) &&
can_join &&
dayjs(start_time).isAfter(dayjs());
@@ -138,7 +138,7 @@ export default function Participants(props) {
Taro.navigateTo({
url: `/login_pages/index/index?redirect=${encodeURIComponent(
- fullPath
+ fullPath,
)}`,
});
}
@@ -153,7 +153,7 @@ export default function Participants(props) {
const matchNtrpReq = matchNtrpRequestment(
userInfo?.ntrp_level,
skill_level_min,
- skill_level_max
+ skill_level_max,
);
function handleSelfEvaluate() {
@@ -180,7 +180,7 @@ export default function Participants(props) {
}
function generateTextAndAction(
- user_action_status: null | { [key: string]: boolean }
+ user_action_status: null | { [key: string]: boolean },
):
| undefined
| { text: string | React.FC; action?: () => void; available?: boolean } {
@@ -259,7 +259,7 @@ export default function Participants(props) {
const res = await OrderService.getUnpaidOrder(id);
if (res.code === 0) {
navto(
- `/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`
+ `/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`,
);
}
}),
@@ -296,10 +296,11 @@ export default function Participants(props) {
const { action = () => {} } = generateTextAndAction(user_action_status)!;
const leftCount = max_participants - participant_count;
- const leftSubstituteCount = (max_substitute_players || 0) - (substitute_count || 0);
+ const leftSubstituteCount =
+ (max_substitute_players || 0) - (substitute_count || 0);
const showSubstituteApplicationEntry =
[can_pay, can_join, is_substituting, waiting_start].every(
- (item) => !item
+ (item) => !item,
) &&
can_substitute &&
dayjs(start_time).isAfter(dayjs());
@@ -336,7 +337,7 @@ export default function Participants(props) {
refresherBackground="#FAFAFA"
className={classnames(
styles["participants-list-scroll"],
- showApplicationEntry ? styles.withApplication : ""
+ showApplicationEntry ? styles.withApplication : "",
)}
scrollX
>
@@ -377,14 +378,14 @@ export default function Participants(props) {
src={avatar_url}
onClick={handleViewUserInfo.bind(
null,
- participant_user_id
+ participant_user_id,
)}
/>
{nickname || "未知"}
- {displayNtrp}
+ NTRP {displayNtrp}
{role}
@@ -400,97 +401,107 @@ export default function Participants(props) {
)}
{/* 候补区域 */}
- {max_substitute_players > 0 && (substitute_count > 0 || showSubstituteApplicationEntry) && (
-
-
- 候补
- ·
- {leftSubstituteCount > 0 ? `剩余空位 ${leftSubstituteCount}` : "已满员"}
-
-
- {/* 候补申请入口 */}
- {showSubstituteApplicationEntry && (
- {
- action?.();
- }}
- >
-
-
- 申请候补
-
-
- )}
- {/* 候补成员列表 */}
- 0 &&
+ (substitute_count > 0 || showSubstituteApplicationEntry) && (
+
+
+ 候补
+ ·
+
+ {leftSubstituteCount > 0
+ ? `剩余空位 ${leftSubstituteCount}`
+ : "已满员"}
+
+
+
+ {/* 候补申请入口 */}
+ {showSubstituteApplicationEntry && (
+ {
+ action?.();
+ }}
+ >
+
+
+ 申请候补
+
+
)}
- scrollX
- >
-
- {substitute_members.map((substitute) => {
- const {
- is_organizer,
- user: {
- avatar_url,
- nickname,
- level,
- ntrp_level,
- id: substitute_user_id,
- },
- } = substitute;
- const role = is_organizer ? "组织者" : "参与者";
- // 优先使用 ntrp_level,如果没有则使用 level
- const ntrpValue = ntrp_level || level;
- // 格式化显示 NTRP,如果没有值则显示"初学者"
- const displayNtrp = ntrpValue
- ? formatNtrpDisplay(ntrpValue)
- : "初学者";
- return (
-
-
-
- {nickname || "未知"}
-
-
- {displayNtrp}
-
-
- {role}
-
-
- );
- })}
-
-
+
+ {substitute_members.map((substitute) => {
+ const {
+ is_organizer,
+ user: {
+ avatar_url,
+ nickname,
+ level,
+ ntrp_level,
+ id: substitute_user_id,
+ },
+ } = substitute;
+ const role = is_organizer ? "组织者" : "参与者";
+ // 优先使用 ntrp_level,如果没有则使用 level
+ const ntrpValue = ntrp_level || level;
+ // 格式化显示 NTRP,如果没有值则显示"初学者"
+ const displayNtrp = ntrpValue
+ ? formatNtrpDisplay(ntrpValue)
+ : "初学者";
+ return (
+
+
+
+ {nickname || "未知"}
+
+
+ {displayNtrp}
+
+
+ {role}
+
+
+ );
+ })}
+
+
+
-
- )}
+ )}
>
);
diff --git a/src/other_pages/ntrp-evaluate/index.tsx b/src/other_pages/ntrp-evaluate/index.tsx
index 3a9d20f..3af9c91 100644
--- a/src/other_pages/ntrp-evaluate/index.tsx
+++ b/src/other_pages/ntrp-evaluate/index.tsx
@@ -16,7 +16,7 @@ import { useGlobalState } from "@/store/global";
import { delay, getCurrentFullPath } from "@/utils";
import { formatNtrpDisplay } from "@/utils/helper";
import { waitForAuthInit } from "@/utils/authInit";
-import httpService from "@/services/httpService";
+// import httpService from "@/services/httpService";
import DetailService from "@/services/detailService";
import { OSS_BASE } from "@/config/api";
import CloseIcon from "@/static/ntrp/ntrp_close_icon.svg";
diff --git a/src/utils/genPoster.ts b/src/utils/genPoster.ts
index 19fcb59..a1ec2c4 100644
--- a/src/utils/genPoster.ts
+++ b/src/utils/genPoster.ts
@@ -282,7 +282,9 @@ function drawTextWrap(
/** 核心纯函数:生成海报图片 */
export async function generatePosterImage(data: any): Promise {
console.log("start !!!!");
- const dpr = Taro.getWindowInfo().pixelRatio;
+ // const dpr = Taro.getWindowInfo().pixelRatio;
+ const dpr = 1;
+ // console.log(dpr, 'dpr')
const width = 600;
const height = 1000;
@@ -433,7 +435,7 @@ export async function generatePosterImage(data: any): Promise {
const { tempFilePath } = await Taro.canvasToTempFilePath({
canvas,
fileType: 'png',
- quality: 1,
+ quality: 0.7,
});
return tempFilePath;
}