12
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import Taro from "@tarojs/taro";
|
||||
import { View, Canvas } from "@tarojs/components";
|
||||
import { useEffect, forwardRef, useImperativeHandle } from "react";
|
||||
import shareLogoSvg from "@/static/ntrp/ntrp_share_logo.svg";
|
||||
import shareLogoSvg from "@/static/ntrp/ntrp_share_logo.png";
|
||||
import docCopySvg from "@/static/ntrp/ntrp_doc_copy.svg";
|
||||
|
||||
interface RadarChartV2Props {
|
||||
data: [string, number][];
|
||||
title?: string;
|
||||
ntrpLevel?: string;
|
||||
levelDescription?: string;
|
||||
avatarUrl?: string;
|
||||
qrCodeUrl?: string;
|
||||
bottomText?: string;
|
||||
}
|
||||
@@ -16,6 +19,8 @@ export interface RadarChartV2Ref {
|
||||
generateFullImage: (options: {
|
||||
title?: string;
|
||||
ntrpLevel?: string;
|
||||
levelDescription?: string;
|
||||
avatarUrl?: string;
|
||||
qrCodeUrl?: string;
|
||||
bottomText?: string;
|
||||
width?: number;
|
||||
@@ -24,7 +29,7 @@ export interface RadarChartV2Ref {
|
||||
}
|
||||
|
||||
const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>((props, ref) => {
|
||||
const { data, title, ntrpLevel, qrCodeUrl, bottomText } = props;
|
||||
const { data, title, ntrpLevel, levelDescription, qrCodeUrl, bottomText } = props;
|
||||
|
||||
const maxValue = 100;
|
||||
const levels = 5;
|
||||
@@ -180,6 +185,21 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>((props, ref)
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制圆角矩形
|
||||
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();
|
||||
}
|
||||
|
||||
// 格式化 NTRP 显示
|
||||
function formatNtrpDisplay(level: string): string {
|
||||
if (!level) return "";
|
||||
@@ -209,6 +229,7 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>((props, ref)
|
||||
generateFullImage: async (options: {
|
||||
title?: string;
|
||||
ntrpLevel?: string;
|
||||
levelDescription?: string;
|
||||
qrCodeUrl?: string;
|
||||
bottomText?: string;
|
||||
width?: number;
|
||||
@@ -269,22 +290,130 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>((props, ref)
|
||||
|
||||
let currentY = topPadding;
|
||||
|
||||
// 绘制标题 - 根据设计稿调整字体大小和间距
|
||||
if (options.title) {
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.font = "400 28px sans-serif"; // 设计稿字体大小
|
||||
ctx.textAlign = "left";
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillText(options.title, sidePadding, currentY);
|
||||
currentY += 44; // 标题到 NTRP 等级的间距
|
||||
// 绘制用户头像和装饰图片 - 参考 Result 组件布局,居中显示
|
||||
if (options.avatarUrl) {
|
||||
try {
|
||||
const avatarSize = 50; // Result 组件使用 0.5 倍数,所以是 50px
|
||||
const avatarImg = await loadImage(canvas, options.avatarUrl);
|
||||
|
||||
// 头像区域总宽度(头像 + 装饰图片重叠部分)
|
||||
const avatarWrapWidth = 50 + 44 - 10; // 头像宽度 + 装饰宽度 - 重叠部分
|
||||
const avatarX = (width - avatarWrapWidth) / 2 + 10; // 居中,考虑装饰图片的位置
|
||||
const avatarY = currentY;
|
||||
|
||||
// 绘制头像圆形背景
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "#FFFFFF";
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = "#EFEFEF";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
|
||||
// 绘制头像(圆形裁剪)
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2 - 1, 0, Math.PI * 2);
|
||||
ctx.clip();
|
||||
const innerAvatarSize = 45; // 头像内部尺寸 90px * 0.5
|
||||
ctx.drawImage(avatarImg, avatarX + 2.5, avatarY + 2.5, innerAvatarSize, innerAvatarSize);
|
||||
ctx.restore();
|
||||
|
||||
// 绘制装饰图片(DocCopy)- 在头像右侧
|
||||
const addonSize = 44; // 88px * 0.5
|
||||
const addonX = avatarX + avatarSize - 10; // margin-left: -10px (20px * 0.5)
|
||||
const addonY = avatarY;
|
||||
const addonRotation = 8 * (Math.PI / 180); // 旋转 8 度
|
||||
|
||||
try {
|
||||
const docCopyImg = await loadImage(canvas, docCopySvg);
|
||||
ctx.save();
|
||||
|
||||
// 移动到旋转中心
|
||||
const centerX = addonX + addonSize / 2;
|
||||
const centerY = addonY + addonSize / 2;
|
||||
ctx.translate(centerX, centerY);
|
||||
ctx.rotate(addonRotation);
|
||||
|
||||
// 绘制装饰图片背景(圆角矩形,带渐变)
|
||||
const borderRadius = 10; // 20px * 0.5
|
||||
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)"; // rgba(89, 255, 214, 0.2)
|
||||
ctx.fill();
|
||||
ctx.globalAlpha = 1.0;
|
||||
|
||||
ctx.strokeStyle = "#FFFFFF";
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// 绘制装饰图片
|
||||
const docSize = 24; // 48px * 0.5
|
||||
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 += avatarSize + 20; // 头像到底部文字区域的间距
|
||||
} catch (error) {
|
||||
console.error("Failed to load avatar image:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制 NTRP 等级 - 根据设计稿调整字体大小和颜色
|
||||
// 绘制文字区域 - 完全参考 Result 组件样式,居中对齐
|
||||
const textCenterX = width / 2;
|
||||
const textGap = 6; // gap: 6px
|
||||
|
||||
// 绘制标题 - 14px, font-weight: 300
|
||||
if (options.title) {
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.font = "300 14px PingFang SC, sans-serif";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillText(options.title, textCenterX, currentY);
|
||||
currentY += 14 + textGap; // 行高 + gap
|
||||
}
|
||||
|
||||
// 绘制 NTRP 等级 - 36px, font-weight: 900, "NTRP" 黑色,等级数字 #00e5ad, gap: 8px
|
||||
if (options.ntrpLevel) {
|
||||
ctx.font = "900 36px 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 + 8 + levelWidth; // gap: 8px
|
||||
const startX = textCenterX - totalWidth / 2;
|
||||
|
||||
// 绘制 "NTRP"(黑色)
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(ntrpText, startX, currentY);
|
||||
|
||||
// 绘制等级数字(#00e5ad)
|
||||
ctx.fillStyle = "#00E5AD";
|
||||
ctx.font = "bold 48px sans-serif"; // 设计稿字体大小
|
||||
ctx.fillText(`NTRP ${formatNtrpDisplay(options.ntrpLevel)}`, sidePadding, currentY);
|
||||
currentY += 72; // NTRP 等级到雷达图的间距
|
||||
ctx.fillText(levelText, startX + ntrpWidth + 8, currentY);
|
||||
|
||||
currentY += 44 + textGap; // line-height: 44px + gap
|
||||
}
|
||||
|
||||
// 绘制描述文本 - 16px, font-weight: 600
|
||||
if (options.levelDescription) {
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.font = "600 16px PingFang SC, sans-serif";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillText(options.levelDescription, textCenterX, currentY);
|
||||
currentY += 16 + 40; // 行高 + 到雷达图的间距
|
||||
}
|
||||
|
||||
// 绘制雷达图 - 根据设计稿调整尺寸和位置
|
||||
@@ -303,14 +432,78 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>((props, ref)
|
||||
|
||||
// 绘制底部区域 - 根据设计稿调整
|
||||
const qrSize = 100; // 设计稿二维码尺寸
|
||||
const bottomTextContent = options.bottomText || "长按识别二维码,快来加入,有你就有场!";
|
||||
|
||||
// 计算底部区域布局 - 从底部向上计算
|
||||
const bottomTextHeight = 28; // 底部文字高度
|
||||
const bottomSpacing = 30; // 底部间距
|
||||
const bottomTextLineHeight = 28; // 行高
|
||||
|
||||
// 绘制二维码 - 右下角
|
||||
// 先绘制底部文字,确定文字的实际高度
|
||||
ctx.fillStyle = "rgba(0, 0, 0, 0.45)";
|
||||
ctx.font = "400 20px sans-serif"; // 设计稿字体大小
|
||||
ctx.textAlign = "left";
|
||||
ctx.textBaseline = "bottom";
|
||||
|
||||
const textX = sidePadding;
|
||||
const textY = height - bottomPadding;
|
||||
const maxTextWidth = width - sidePadding * 2 - qrSize - 20; // 预留二维码和间距
|
||||
|
||||
// 计算文字行数
|
||||
const bottomWords = bottomTextContent.split("");
|
||||
let bottomLine = "";
|
||||
let textLines = [];
|
||||
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 actualTextHeight = textLines.length * bottomTextLineHeight;
|
||||
|
||||
// 绘制底部文字
|
||||
textLines.forEach((lineText, index) => {
|
||||
ctx.fillText(lineText, textX, textY - (textLines.length - 1 - index) * bottomTextLineHeight);
|
||||
});
|
||||
|
||||
// 绘制底部 SVG logo 图片 - 在文字上方
|
||||
const logoSvgY = height - bottomPadding - actualTextHeight - 40; // 在文字上方,间距40px
|
||||
|
||||
try {
|
||||
const logoSvgPath = shareLogoSvg;
|
||||
// 先获取图片的实际尺寸,保持宽高比
|
||||
const logoInfo = await getImageInfo(logoSvgPath);
|
||||
const logoSvgImg = await loadImage(canvas, logoSvgPath);
|
||||
|
||||
// 根据设计稿,目标宽度为 235px,按比例计算高度
|
||||
const targetWidth = 235;
|
||||
const aspectRatio = logoInfo.width / logoInfo.height;
|
||||
const targetHeight = targetWidth / aspectRatio;
|
||||
|
||||
const logoSvgX = sidePadding; // 左边对齐
|
||||
|
||||
// 按实际宽高比绘制,避免拉伸
|
||||
ctx.drawImage(
|
||||
logoSvgImg,
|
||||
logoSvgX,
|
||||
logoSvgY,
|
||||
targetWidth,
|
||||
targetHeight
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to load logo SVG:", error);
|
||||
}
|
||||
|
||||
// 绘制二维码 - 右下角,与文字底部对齐
|
||||
const qrX = width - sidePadding - qrSize;
|
||||
const qrY = height - bottomPadding - qrSize - bottomTextHeight - 20; // 在文字上方
|
||||
const qrY = height - bottomPadding - qrSize;
|
||||
|
||||
if (options.qrCodeUrl) {
|
||||
try {
|
||||
@@ -321,26 +514,6 @@ const RadarChartV2 = forwardRef<RadarChartV2Ref, RadarChartV2Props>((props, ref)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制底部 SVG logo 图片 - 根据设计稿,SVG 包含 logo 和文字
|
||||
try {
|
||||
const logoSvgPath = shareLogoSvg;
|
||||
const logoSvgImg = await loadImage(canvas, logoSvgPath);
|
||||
const logoSvgWidth = 235; // SVG 原始宽度
|
||||
const logoSvgHeight = 28; // SVG 原始高度
|
||||
const logoSvgX = sidePadding; // 左边对齐
|
||||
const logoSvgY = height - bottomPadding - logoSvgHeight; // 底部对齐
|
||||
|
||||
ctx.drawImage(
|
||||
logoSvgImg,
|
||||
logoSvgX,
|
||||
logoSvgY,
|
||||
logoSvgWidth,
|
||||
logoSvgHeight
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to load logo SVG:", error);
|
||||
}
|
||||
|
||||
// 导出图片
|
||||
Taro.canvasToTempFilePath({
|
||||
canvas,
|
||||
|
||||
@@ -23,6 +23,7 @@ import FollowUserCard from './FollowUserCard/index';
|
||||
import Comments from "./Comments";
|
||||
import GeneralNavbar from "./GeneralNavbar";
|
||||
import RadarChart from './Radar'
|
||||
import RadarChartV2 from './Radar/indexV2'
|
||||
import EmptyState from './EmptyState';
|
||||
import NTRPTestEntryCard from './NTRPTestEntryCard'
|
||||
|
||||
@@ -53,6 +54,7 @@ export {
|
||||
Comments,
|
||||
GeneralNavbar,
|
||||
RadarChart,
|
||||
RadarChartV2,
|
||||
EmptyState,
|
||||
NTRPTestEntryCard,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { View, Text, Image, Button, Canvas } from "@tarojs/components";
|
||||
import Taro, { useRouter, useShareAppMessage } from "@tarojs/taro";
|
||||
import dayjs from "dayjs";
|
||||
import classnames from "classnames";
|
||||
import { withAuth, RadarChart } from "@/components";
|
||||
import { withAuth, RadarChart, RadarChartV2 } from "@/components";
|
||||
import evaluateService, {
|
||||
LastTimeTestResult,
|
||||
Question,
|
||||
@@ -16,6 +16,9 @@ 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 DetailService from "@/services/detailService";
|
||||
import { base64ToTempFilePath } from "@/utils/genPoster";
|
||||
import CloseIcon from "@/static/ntrp/ntrp_close_icon.svg";
|
||||
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
|
||||
import ArrowRight from "@/static/ntrp/ntrp_arrow_right.svg";
|
||||
@@ -452,12 +455,14 @@ function Result() {
|
||||
const userInfo = useUserInfo();
|
||||
const { fetchUserInfo, updateUserInfo } = useUserActions();
|
||||
const { type, next, clear } = useEvaluate();
|
||||
const radarRef = useRef();
|
||||
const radarRef = useRef<any>();
|
||||
const radarV2Ref = useRef<any>();
|
||||
|
||||
const [result, setResult] = useState<TestResultData>();
|
||||
const [radarData, setRadarData] = useState<
|
||||
[propName: string, prop: number][]
|
||||
>([]);
|
||||
const [qrCodeUrl, setQrCodeUrl] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
@@ -469,10 +474,32 @@ function Result() {
|
||||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||||
await fetchUserInfo();
|
||||
}
|
||||
// 获取二维码
|
||||
await fetchQRCode();
|
||||
};
|
||||
init();
|
||||
}, [id]);
|
||||
|
||||
// 获取二维码 - 调用接口生成分享二维码
|
||||
async function fetchQRCode() {
|
||||
try {
|
||||
// 调用接口生成二维码,分享当前页面
|
||||
const qrCodeUrlRes = await DetailService.getQrCodeUrl({
|
||||
page: "other_pages/ntrp-evaluate/index",
|
||||
scene: `stage=${StageType.INTRO}`,
|
||||
});
|
||||
if (qrCodeUrlRes.code === 0 && qrCodeUrlRes.data?.qr_code_base64) {
|
||||
// 将 base64 转换为临时文件路径
|
||||
const tempFilePath = await base64ToTempFilePath(
|
||||
qrCodeUrlRes.data.qr_code_base64
|
||||
);
|
||||
setQrCodeUrl(tempFilePath);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取二维码失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function getResultById() {
|
||||
const res = await evaluateService.getTestResult({ record_id: Number(id) });
|
||||
if (res.code === 0) {
|
||||
@@ -542,51 +569,38 @@ function Result() {
|
||||
}
|
||||
|
||||
async function genCardImage() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const url = await radarRef.current.generateImage();
|
||||
const query = Taro.createSelectorQuery();
|
||||
query
|
||||
.select("#exportCanvas")
|
||||
.fields({ node: true, size: true })
|
||||
.exec((res2) => {
|
||||
const canvas = res2[0].node;
|
||||
const ctx = canvas.getContext("2d");
|
||||
const dpr = Taro.getWindowInfo().pixelRatio;
|
||||
const width = 300;
|
||||
const height = 400;
|
||||
canvas.width = width * dpr;
|
||||
canvas.height = height * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
// 背景
|
||||
ctx.fillStyle = "#e9fdf8";
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
// 标题文字
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.font = "16px sans-serif";
|
||||
ctx.fillText("你的 NTRP 测试结果为", 20, 40);
|
||||
ctx.fillStyle = "#00E5AD";
|
||||
ctx.font = "bold 22px sans-serif";
|
||||
ctx.fillText(`NTRP ${formatNtrpDisplay(result?.ntrp_level)}`, 20, 70);
|
||||
|
||||
// 绘制雷达图
|
||||
const img = canvas.createImage();
|
||||
img.src = url;
|
||||
img.onload = () => {
|
||||
ctx.drawImage(img, 20, 100, 260, 260);
|
||||
|
||||
// 第三步:导出最终卡片
|
||||
Taro.canvasToTempFilePath({
|
||||
canvas,
|
||||
success: (res3) => {
|
||||
console.log("导出成功:", res3.tempFilePath);
|
||||
resolve(res3.tempFilePath);
|
||||
},
|
||||
});
|
||||
};
|
||||
try {
|
||||
// 确保二维码已获取,如果没有则重新获取
|
||||
let finalQrCodeUrl = qrCodeUrl;
|
||||
if (!finalQrCodeUrl) {
|
||||
// 直接调用接口获取二维码
|
||||
const qrCodeUrlRes = await DetailService.getQrCodeUrl({
|
||||
page: "other_pages/ntrp-evaluate/index",
|
||||
scene: `stage=${StageType.INTRO}`,
|
||||
});
|
||||
});
|
||||
if (qrCodeUrlRes.code === 0 && qrCodeUrlRes.data?.qr_code_base64) {
|
||||
finalQrCodeUrl = await base64ToTempFilePath(
|
||||
qrCodeUrlRes.data.qr_code_base64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 RadarV2 的 generateFullImage 方法生成完整图片
|
||||
const imageUrl = await radarV2Ref.current?.generateFullImage({
|
||||
title: "你的 NTRP 测试结果为",
|
||||
ntrpLevel: result?.ntrp_level,
|
||||
levelDescription: result?.level_description,
|
||||
avatarUrl: userInfo?.avatar_url,
|
||||
qrCodeUrl: finalQrCodeUrl,
|
||||
bottomText: "长按识别二维码,快来加入,有你就有场!",
|
||||
width: 750, // 设计稿宽度
|
||||
height: 1334, // 设计稿高度
|
||||
});
|
||||
return imageUrl;
|
||||
} catch (error) {
|
||||
console.error("生成图片失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSaveImage() {
|
||||
@@ -746,6 +760,19 @@ function Result() {
|
||||
left: "-9999px",
|
||||
}}
|
||||
/>
|
||||
{/* 隐藏的 RadarV2 用于生成完整图片,不显示在界面上 */}
|
||||
<View style={{ position: "absolute", top: "-9999px", left: "-9999px", width: "0px", height: "0px", overflow: "hidden" }}>
|
||||
<RadarChartV2
|
||||
ref={radarV2Ref}
|
||||
data={radarData}
|
||||
title="你的 NTRP 测试结果为"
|
||||
ntrpLevel={result?.ntrp_level}
|
||||
levelDescription={result?.level_description}
|
||||
avatarUrl={userInfo?.avatar_url}
|
||||
qrCodeUrl={qrCodeUrl}
|
||||
bottomText="长按识别二维码,快来加入,有你就有场!"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
BIN
src/static/ntrp/ntrp_share_logo.png
Normal file
BIN
src/static/ntrp/ntrp_share_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
36
src/static/ntrp/ntrp_share_logo.svg
Normal file
36
src/static/ntrp/ntrp_share_logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.8 KiB |
Reference in New Issue
Block a user