处理分享后的兼容问题

This commit is contained in:
kron
2025-11-04 16:49:56 +08:00
parent 3f6d8cb821
commit c7ebeaac36
5 changed files with 312 additions and 36 deletions

View File

@@ -71,7 +71,10 @@ const updateHot = (value) => {
onMounted(() => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
if (currentPage.route === "pages/point-book-edit") {
if (
currentPage.route === "pages/point-book-edit" ||
currentPage.route === "pages/point-book-detail"
) {
pointBook.value = uni.getStorageSync("point-book");
}
if (

View File

@@ -7,19 +7,26 @@ import ScreenHint2 from "@/components/ScreenHint2.vue";
import RingBarChart from "@/components/RingBarChart.vue";
import { getPointBookDetailAPI, addNoteAPI } from "@/apis";
import { generateShareCardImage } from "@/util";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user, device } = storeToRefs(store);
const selectedIndex = ref(0);
const showTip = ref(false);
const showTip2 = ref(false);
const showTip3 = ref(false);
const groups = ref([]);
const data = ref({});
const targetId = ref(0);
const targetSrc = ref("");
const arrows = ref([]);
const notes = ref("");
const draftNotes = ref("");
const recordId = ref("");
const record = ref({
groups: [],
});
const openTip = (index) => {
if (index === 1) showTip.value = true;
@@ -37,23 +44,31 @@ const saveNote = async () => {
notes.value = draftNotes.value;
draftNotes.value = "";
showTip3.value = false;
if (recordId.value) {
await addNoteAPI(recordId.value, notes.value);
if (record.value.id) {
await addNoteAPI(record.value.id, notes.value);
}
};
const onSelect = (index) => {
selectedIndex.value = index;
data.value = groups.value[index];
arrows.value = groups.value[index].list.filter((item) => item.x && item.y);
data.value = record.value.groups[index];
arrows.value = record.value.groups[index].list.filter(
(item) => item.x && item.y
);
};
const goBack = () => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 2];
uni.navigateBack({
delta: currentPage.route === "pages/point-book" ? 1 : 2,
});
if (pages.length > 1) {
const currentPage = pages[pages.length - 2];
uni.navigateBack({
delta: currentPage.route === "pages/point-book" ? 1 : 2,
});
} else {
uni.redirectTo({
url: "/pages/index",
});
}
};
const ringRates = computed(() => {
@@ -68,7 +83,7 @@ const ringRates = computed(() => {
onLoad(async (options) => {
if (options.id) {
const result = await getPointBookDetailAPI(options.id || 194);
recordId.value = result.id;
record.value = result;
notes.value = result.remark || "";
const config = uni.getStorageSync("point-book-config");
config.targetOption.some((item) => {
@@ -78,27 +93,36 @@ onLoad(async (options) => {
}
});
if (result.groups) {
groups.value = result.groups;
data.value = result.groups[0];
arrows.value = result.groups[0].list;
}
}
});
onShareAppMessage(() => {
onShareAppMessage(async () => {
const imageUrl = await generateShareCardImage(
"shareCanvas",
record.value.recordDate,
data.value.userTotalRing,
data.value.totalRing
);
return {
title: "射箭打卡,今日又精进了一些~",
path: "/pages/point-book-detail?id=" + recordId.value,
imageUrl:
"https://static.shelingxingqiu.com/attachment/2025-09-12/dcqoz26q0268wxmzjg.png",
path: "/pages/point-book-detail?id=" + record.value.id,
imageUrl,
};
});
onShareTimeline(() => {
onShareTimeline(async () => {
const imageUrl = await generateShareCardImage(
"shareCanvas",
record.value.recordDate,
data.value.userTotalRing,
data.value.totalRing
);
return {
title: "射箭打卡,今日又精进了一些~",
query: "from=timeline",
imageUrl:
"https://static.shelingxingqiu.com/attachment/2025-09-12/dcqoz26q0268wxmzjg.png",
query: "id=" + record.value.id,
imageUrl,
};
});
</script>
@@ -108,7 +132,7 @@ onShareTimeline(() => {
:bgType="2"
bgColor="#F5F5F5"
:whiteBackArrow="false"
title="分析"
title=""
:onBack="goBack"
>
<view class="container">
@@ -129,6 +153,11 @@ onShareTimeline(() => {
>
</view>
</view> -->
<canvas
class="share-canvas"
canvas-id="shareCanvas"
style="width: 375px; height: 300px"
></canvas>
<view class="detail-data">
<view>
<view
@@ -160,7 +189,11 @@ onShareTimeline(() => {
<view>总环数</view>
<text>{{ data.userTotalRing }}/{{ data.totalRing }}</text>
</view>
<button hover-class="none" @click="() => openTip(3)">
<button
hover-class="none"
@click="() => openTip(3)"
v-if="user.id === record.userId"
>
<image src="../static/edit.png" mode="widthFix" />
<text>备注</text>
</button>
@@ -199,7 +232,7 @@ onShareTimeline(() => {
}}</text>
</view> -->
<view class="ring-text-groups">
<view v-for="(item, index) in groups" :key="index">
<view v-for="(item, index) in record.groups" :key="index">
<view v-if="selectedIndex === 0 && index !== 0">
<text>{{ index }}</text>
<text>{{
@@ -231,9 +264,22 @@ onShareTimeline(() => {
</view>
</view>
</view>
<view class="btns">
<view
class="btns"
:style="{
gridTemplateColumns: `repeat(${
user.id === record.userId ? 2 : 1
}, 1fr)`,
}"
>
<button hover-class="none" @click="goBack">关闭</button>
<button hover-class="none" @click="share">分享</button>
<button
hover-class="none"
@click="share"
v-if="user.id === record.userId"
>
分享
</button>
</view>
</view>
<ScreenHint2
@@ -252,11 +298,12 @@ onShareTimeline(() => {
<text>展示用户某次练习中射箭的点位</text>
</block>
<block v-if="showTip3">
<text>笔记</text>
<text>备注</text>
<text v-if="notes">{{ notes }}</text>
<textarea
v-if="!notes"
v-model="draftNotes"
maxlength="300"
rows="4"
class="notes-input"
placeholder="写下本次射箭的补充信息与心得"
@@ -435,7 +482,7 @@ onShareTimeline(() => {
justify-content: center;
}
.ring-text-groups > view > view:first-child:nth-last-child(2) {
width: 82rpx;
width: 90rpx;
text-align: center;
font-size: 20rpx;
display: flex;
@@ -476,23 +523,25 @@ onShareTimeline(() => {
}
.btns {
margin-bottom: 40rpx;
display: flex;
display: grid;
align-items: center;
justify-content: center;
column-gap: 20rpx;
padding: 0 20rpx;
}
.btns > button {
width: 336rpx;
height: 84rpx;
line-height: 84rpx;
background: linear-gradient(180deg, #fbfbfb 0%, #f5f5f5 100%), #ffffff;
border-radius: 44rpx;
border: 2rpx solid #eeeeee;
box-sizing: border-box;
font-weight: 500;
font-size: 30rpx;
color: #000000;
margin: 0 10rpx;
}
.btns > button:last-child {
.btns > button:nth-child(2) {
background: #fed847;
border: none;
}
</style>

View File

@@ -96,9 +96,9 @@ const onSelectOption = (itemIndex, value) => {
</view>
<view class="point-records">
<ScrollList :onLoading="onListLoading">
<view v-for="item in list" :key="item.id">
<view v-for="(item, index) in list" :key="item.id">
<PointRecord :data="item" :onRemove="onRemoveRecord" />
<view :style="{ height: '25rpx' }"></view>
<view v-if="index < list.length - 1" :style="{ height: '25rpx' }"></view>
</view>
<view class="no-data" v-if="list.length === 0">暂无数据</view>
</ScrollList>

View File

@@ -332,9 +332,12 @@ onShareTimeline(() => {
<view class="title" v-if="user.id">
<image src="../static/point-book-title2.png" mode="widthFix" />
</view>
<block v-for="item in list" :key="item.id">
<block v-for="(item, index) in list" :key="item.id">
<PointRecord :data="item" :onRemove="onRemoveRecord" />
<view :style="{ height: '25rpx' }"></view>
<view
v-if="index < list.length - 1"
:style="{ height: '25rpx' }"
></view>
</block>
<view
class="see-more"

View File

@@ -454,3 +454,224 @@ export const calcRing = (bowtargetId, x, y, diameter, arrowRadius = 5) => {
}
return 0;
};
export const generateShareCardImage = (canvasId, date, actual, total) => {
try {
const ctx = uni.createCanvasContext(canvasId);
const imgUrl =
"https://static.shelingxingqiu.com/attachment/2025-11-04/ddzpm4tyh5vunyacsr.png";
const drawWidth = 375;
const drawHeight = 300;
// 兼容第三个参数传入 "actual/total" 的情况
let a = actual;
let t = total;
if (
(t === undefined || t === null) &&
typeof a === "string" &&
a.includes("/")
) {
const parts = a.split("/");
a = parts[0];
t = parts[1] || "";
}
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: imgUrl,
success: (res) => {
const path = res.path || res.tempFilePath || imgUrl;
if (typeof ctx.clearRect === "function") {
ctx.clearRect(0, 0, drawWidth, drawHeight);
}
ctx.drawImage(path, 0, 0, drawWidth, drawHeight);
// 绘制左上角日期白色22px
renderText(ctx, String(date || ""), 18, "#FFFFFF", 6, 20, "left");
// 居中绘制第三个参数为圆角黑底标签
const rectW = 200;
const rectH = 78;
const radius = 39;
const rectX = (drawWidth - rectW) / 2;
const rectY = (drawHeight - rectH) / 2;
ctx.save();
ctx.beginPath();
ctx.moveTo(rectX + radius, rectY);
ctx.lineTo(rectX + rectW - radius, rectY);
ctx.quadraticCurveTo(
rectX + rectW,
rectY,
rectX + rectW,
rectY + radius
);
ctx.lineTo(rectX + rectW, rectY + rectH - radius);
ctx.quadraticCurveTo(
rectX + rectW,
rectY + rectH,
rectX + rectW - radius,
rectY + rectH
);
ctx.lineTo(rectX + radius, rectY + rectH);
ctx.quadraticCurveTo(
rectX,
rectY + rectH,
rectX,
rectY + rectH - radius
);
ctx.lineTo(rectX, rectY + radius);
ctx.quadraticCurveTo(rectX, rectY, rectX + radius, rectY);
ctx.closePath();
ctx.setFillStyle("rgba(0,0,0,0.5)");
ctx.fill();
ctx.restore();
// 居中排版:左侧显示 actual/,右侧显示 total再追加“环”
ctx.save();
if (typeof ctx.setTextBaseline === "function")
ctx.setTextBaseline("middle");
const centerX = rectX + rectW / 2;
const centerY = rectY + rectH / 2;
// 左半部:右对齐 actual/
renderText(ctx, `${a}/`, 40, "#FFFFFF", centerX, centerY, "right");
// 右半部:左对齐 total
renderText(
ctx,
`${t || ""}`,
30,
"#FFFFFF",
centerX,
centerY,
"left"
);
// 追加单位“环”:放在 total 文本之后 16px
const totalWidth = ctx.measureText(`${t || ""}`).width || 0;
renderText(
ctx,
"环",
20,
"#FFFFFF",
centerX + totalWidth + 5,
centerY,
"left"
);
ctx.restore();
ctx.draw(false, () => {
try {
uni.canvasToTempFilePath({
canvasId,
width: drawWidth,
height: drawHeight,
destWidth: drawWidth,
destHeight: drawHeight,
fileType: "png",
quality: 1,
success: (r) => {
const path = r.tempFilePath || r.apFilePath || r.filePath;
resolve(path);
},
fail: (err) => reject(err),
});
} catch (err) {
reject(err);
}
});
},
fail: () => {
try {
ctx.drawImage(imgUrl, 0, 0, drawWidth, drawHeight);
// 绘制左上角日期白色22px
renderText(ctx, String(date || ""), 22, "#FFFFFF", 10, 22, "left");
// 居中绘制第三个参数为圆角黑底标签
const rectW = 200;
const rectH = 78;
const radius = 39;
const rectX = (drawWidth - rectW) / 2;
const rectY = (drawHeight - rectH) / 2;
ctx.save();
ctx.beginPath();
ctx.moveTo(rectX + radius, rectY);
ctx.lineTo(rectX + rectW - radius, rectY);
ctx.quadraticCurveTo(
rectX + rectW,
rectY,
rectX + rectW,
rectY + radius
);
ctx.lineTo(rectX + rectW, rectY + rectH - radius);
ctx.quadraticCurveTo(
rectX + rectW,
rectY + rectH,
rectX + rectW - radius,
rectY + rectH
);
ctx.lineTo(rectX + radius, rectY + rectH);
ctx.quadraticCurveTo(
rectX,
rectY + rectH,
rectX,
rectY + rectH - radius
);
ctx.lineTo(rectX, rectY + radius);
ctx.quadraticCurveTo(rectX, rectY, rectX + radius, rectY);
ctx.closePath();
ctx.setFillStyle("rgba(0,0,0,0.5)");
ctx.fill();
ctx.restore();
// 居中排版:左侧显示 actual/,右侧显示 total再追加“环”
ctx.save();
if (typeof ctx.setTextBaseline === "function")
ctx.setTextBaseline("middle");
const centerX = rectX + rectW / 2;
const centerY = rectY + rectH / 2;
// 左半部:右对齐 actual/
renderText(ctx, `${a}/`, 40, "#FFFFFF", centerX, centerY, "right");
// 右半部:左对齐 total
renderText(
ctx,
`${t || ""}`,
35,
"#FFFFFF",
centerX,
centerY,
"left"
);
// 追加单位“环”:放在 total 文本之后 16px
const totalWidth = ctx.measureText(`${t || ""}`).width || 0;
renderText(
ctx,
"环",
20,
"#FFFFFF",
centerX + totalWidth + 5,
centerY,
"left"
);
ctx.restore();
ctx.draw(false, () => {
try {
uni.canvasToTempFilePath({
canvasId,
width: drawWidth,
height: drawHeight,
destWidth: drawWidth,
destHeight: drawHeight,
fileType: "png",
quality: 1,
success: (r) => {
const path = r.tempFilePath || r.apFilePath || r.filePath;
resolve(path);
},
fail: (err) => reject(err),
});
} catch (err) {
reject(err);
}
});
} catch (e) {
reject(e);
}
},
});
});
} catch (e) {
console.error("generateShareCardImage 绘制失败:", e);
}
};