细节优化
This commit is contained in:
@@ -481,3 +481,64 @@ async function loadCanvasImage(canvas, src) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sharePractiseData = async (canvasId, data) => {
|
||||||
|
try {
|
||||||
|
const width = 375;
|
||||||
|
const height = 460;
|
||||||
|
// 获取 Canvas 2D 上下文并按 DPR 设置
|
||||||
|
const { canvas, ctx } = await getCanvas2DContext(canvasId, width, height);
|
||||||
|
|
||||||
|
// 背景填充
|
||||||
|
ctx.fillStyle = "#F5F5F5";
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
// 背景图
|
||||||
|
const bgSrc = await loadImage(
|
||||||
|
"https://static.shelingxingqiu.com/attachment/2026-01-05/dfgirwfuz5htwfd4sd.png"
|
||||||
|
);
|
||||||
|
const bgImg = await loadCanvasImage(canvas, bgSrc);
|
||||||
|
ctx.drawImage(bgImg, 0, 0, width, width);
|
||||||
|
|
||||||
|
// 头像
|
||||||
|
const avatarSrc = await loadImage(data.avatar);
|
||||||
|
const avatarImg = await loadCanvasImage(canvas, avatarSrc);
|
||||||
|
await drawRoundImage(ctx, avatarImg, 13, 13, 54, 54, 27, "#fff", 1);
|
||||||
|
|
||||||
|
renderText(ctx, data.name, 20, "#fff", 84, 50);
|
||||||
|
|
||||||
|
const bubble1Src = await loadImage(
|
||||||
|
"https://static.shelingxingqiu.com/attachment/2026-01-05/dfgirwcxugdsenlnud.png"
|
||||||
|
);
|
||||||
|
const bubble2Src = await loadImage(
|
||||||
|
"https://static.shelingxingqiu.com/attachment/2026-01-05/dfgirwcxujhysg0vfq.png"
|
||||||
|
);
|
||||||
|
const bubble3Src = await loadImage(
|
||||||
|
"https://static.shelingxingqiu.com/attachment/2026-01-05/dfgirwfa33spdori3p.png"
|
||||||
|
);
|
||||||
|
const bubble1Img = await loadCanvasImage(canvas, bubble1Src);
|
||||||
|
const bubble2Img = await loadCanvasImage(canvas, bubble2Src);
|
||||||
|
const bubble3Img = await loadCanvasImage(canvas, bubble3Src);
|
||||||
|
ctx.drawImage(bubble1Img, 10, 88, 143, 87);
|
||||||
|
renderText(ctx, "本周箭数", 14, "#FDA103", 84, 116, "center");
|
||||||
|
renderText(ctx, data.weekArrow, 36, "#FA2A2A", 84, 152, "center");
|
||||||
|
ctx.drawImage(bubble2Img, 65, 220, 143, 87);
|
||||||
|
renderText(ctx, "本周消耗", 14, "#FDA103", 139, 248, "center");
|
||||||
|
renderText(ctx, data.weekArrow * 1.6, 36, "#FA2A2A", 139, 284, "center");
|
||||||
|
ctx.drawImage(bubble3Img, 255, 52, 114, 92);
|
||||||
|
renderText(ctx, "我的名次", 14, "#FDA103", 312, 80, "center");
|
||||||
|
renderText(ctx, data.rank, 36, "#FA2A2A", 312, 116, "center");
|
||||||
|
|
||||||
|
const qrcodeSrc = await loadImage(
|
||||||
|
"https://static.shelingxingqiu.com/attachment/2025-12-04/dep7lfqhpelmerjle4.png"
|
||||||
|
);
|
||||||
|
const qrcodeImg = await loadCanvasImage(canvas, qrcodeSrc);
|
||||||
|
ctx.drawImage(qrcodeImg, 40, 383, 68, 68);
|
||||||
|
|
||||||
|
renderText(ctx, "射灵星球", 18, "#333", 120, 412);
|
||||||
|
renderText(ctx, "高效记录每一箭,快来一起打卡吧!", 13, "#999", 120, 435);
|
||||||
|
// 2D 即时绘制,无需 ctx.draw()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("generateShareImage 绘制失败:", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ const onClick = async () => {
|
|||||||
<text>{{ data.weekArrow }}</text>
|
<text>{{ data.weekArrow }}</text>
|
||||||
<text>箭</text>
|
<text>箭</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-info" :style="{ justifyContent: 'flex-end' }">
|
<view class="item-info">
|
||||||
<text>{{ Math.round(data.weekArrow * 1.6) }}</text>
|
<text>{{ Math.round(data.weekArrow * 1.6) }}</text>
|
||||||
<text>千卡</text>
|
<text>千卡</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -112,7 +112,7 @@ const onClick = async () => {
|
|||||||
margin-left: 20rpx;
|
margin-left: 20rpx;
|
||||||
}
|
}
|
||||||
.rank-item > view:nth-child(2) > view:last-child > text:first-child {
|
.rank-item > view:nth-child(2) > view:last-child > text:first-child {
|
||||||
font-size: 26rpx;
|
font-size: 30rpx;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
margin-bottom: 5rpx;
|
margin-bottom: 5rpx;
|
||||||
}
|
}
|
||||||
@@ -129,13 +129,13 @@ const onClick = async () => {
|
|||||||
.item-info {
|
.item-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: flex-end;
|
||||||
font-size: 22rpx;
|
font-size: 20rpx;
|
||||||
color: #777777;
|
color: #777777;
|
||||||
width: 18%;
|
width: 20%;
|
||||||
}
|
}
|
||||||
.item-info > text:first-child {
|
.item-info > text:first-child {
|
||||||
font-size: 26rpx;
|
font-size: 28rpx;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
margin-right: 5rpx;
|
margin-right: 5rpx;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import ScrollList from "@/components/ScrollList.vue";
|
import ScrollList from "@/components/ScrollList.vue";
|
||||||
import PointRankItem from "@/components/PointRankItem.vue";
|
import PointRankItem from "@/components/PointRankItem.vue";
|
||||||
import { getPointBookRankListAPI } from "@/apis";
|
import { getPointBookRankListAPI } from "@/apis";
|
||||||
import { capsuleHeight } from "@/util";
|
import { capsuleHeight } from "@/util";
|
||||||
|
import { wxShare } from "@/util";
|
||||||
|
import { sharePractiseData } from "@/canvas";
|
||||||
|
|
||||||
const list = ref([]);
|
const list = ref([]);
|
||||||
const mine = ref({
|
const mine = ref({
|
||||||
averageRing: 0,
|
averageRing: 0,
|
||||||
});
|
});
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
const onLoad = async (page) => {
|
const onLoad = async (page) => {
|
||||||
const result = await getPointBookRankListAPI(page);
|
const result = await getPointBookRankListAPI(page);
|
||||||
@@ -17,6 +20,20 @@ const onLoad = async (page) => {
|
|||||||
else list.value = list.value.concat(result.list);
|
else list.value = list.value.concat(result.list);
|
||||||
return result.list.length;
|
return result.list.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const shareImage = async () => {
|
||||||
|
if (loading.value || !mine.value.id) return;
|
||||||
|
loading.value = true;
|
||||||
|
await sharePractiseData("shareCanvas", mine.value);
|
||||||
|
await wxShare("shareCanvas");
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// onMounted(() => {
|
||||||
|
// setTimeout(() => {
|
||||||
|
// shareImage();
|
||||||
|
// }, 1000);
|
||||||
|
// });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -82,6 +99,15 @@ const onLoad = async (page) => {
|
|||||||
<PointRankItem v-for="item in list" :key="item.id" :data="item" />
|
<PointRankItem v-for="item in list" :key="item.id" :data="item" />
|
||||||
</ScrollList>
|
</ScrollList>
|
||||||
</view>
|
</view>
|
||||||
|
<button hover-class="none" class="share-btn" @click="shareImage">
|
||||||
|
<image src="../static/share-icon.png" mode="widthFix" />
|
||||||
|
</button>
|
||||||
|
<canvas
|
||||||
|
class="share-canvas"
|
||||||
|
id="shareCanvas"
|
||||||
|
type="2d"
|
||||||
|
style="width: 375px; height: 460px"
|
||||||
|
></canvas>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -151,7 +177,8 @@ const onLoad = async (page) => {
|
|||||||
line-height: 80rpx;
|
line-height: 80rpx;
|
||||||
}
|
}
|
||||||
.rank-title-bar > text:nth-child(1) {
|
.rank-title-bar > text:nth-child(1) {
|
||||||
width: 15%;
|
width: calc(15% - 30rpx);
|
||||||
|
padding-left: 30rpx;
|
||||||
}
|
}
|
||||||
.rank-title-bar > text:nth-child(2) {
|
.rank-title-bar > text:nth-child(2) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -167,4 +194,13 @@ const onLoad = async (page) => {
|
|||||||
border-radius: 25rpx;
|
border-radius: 25rpx;
|
||||||
margin: 0 25rpx;
|
margin: 0 25rpx;
|
||||||
}
|
}
|
||||||
|
.share-btn {
|
||||||
|
position: fixed;
|
||||||
|
right: 25rpx;
|
||||||
|
bottom: 25rpx;
|
||||||
|
}
|
||||||
|
.share-btn > image {
|
||||||
|
width: 116rpx;
|
||||||
|
height: 116rpx;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ onShareTimeline(() => {
|
|||||||
margin-right: 10rpx;
|
margin-right: 10rpx;
|
||||||
}
|
}
|
||||||
.statistics-item > text:nth-child(2) {
|
.statistics-item > text:nth-child(2) {
|
||||||
line-height: 62rpx;
|
transform: translateY(16rpx);
|
||||||
}
|
}
|
||||||
.statistics-item > text:nth-child(3) {
|
.statistics-item > text:nth-child(3) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -658,7 +658,7 @@ onShareTimeline(() => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.rank-title-bar > text:nth-child(3) {
|
.rank-title-bar > text:nth-child(3) {
|
||||||
width: 18%;
|
width: 16%;
|
||||||
}
|
}
|
||||||
.rank-title-bar > text:nth-child(4) {
|
.rank-title-bar > text:nth-child(4) {
|
||||||
width: 27%;
|
width: 27%;
|
||||||
@@ -669,8 +669,8 @@ onShareTimeline(() => {
|
|||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
border: 1rpx solid #777777;
|
border: 1rpx solid #777777;
|
||||||
height: 20rpx;
|
height: 20rpx;
|
||||||
line-height: 20rpx !important;
|
|
||||||
padding: 8rpx;
|
padding: 8rpx;
|
||||||
transform: translateY(8rpx);
|
line-height: 20rpx;
|
||||||
|
transform: translateY(6rpx) !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user