处理分享后的兼容问题
This commit is contained in:
@@ -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 (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
221
src/util.js
221
src/util.js
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user