fix: metadata

This commit is contained in:
zzc
2026-02-03 05:14:31 +08:00
parent 7d0b79bd16
commit b2b59cb61a
3 changed files with 142 additions and 107 deletions

View File

@@ -1,6 +1,6 @@
<template> <template>
<view class="record-page"> <view class="record-page">
<NavBar title="我的运势记录" /> <NavBar title="我的运势记录" />
<scroll-view <scroll-view
scroll-y scroll-y
@@ -46,7 +46,7 @@
> >
<view class="item-image-box"> <view class="item-image-box">
<image <image
:src="item.imageUrl" :src="getThumbUrl(item.imageUrl)"
mode="aspectFill" mode="aspectFill"
class="item-image" class="item-image"
/> />
@@ -115,6 +115,10 @@ const getTagClass = (tag) => {
return map[tag] || "tag-gold"; return map[tag] || "tag-gold";
}; };
const getThumbUrl = (url) => {
return `${url}?imageView2/1/w/340/h/600/q/80`;
};
const loadData = async () => { const loadData = async () => {
if (loading.value || !hasMore.value) return; if (loading.value || !hasMore.value) return;
@@ -145,14 +149,9 @@ const loadData = async () => {
}; };
const loadMore = () => { const loadMore = () => {
console.log(666666666);
loadData(); loadData();
}; };
const goBack = () => {
uni.navigateBack();
};
const goDetail = (item) => { const goDetail = (item) => {
// 传递数据到详情页 // 传递数据到详情页
const data = encodeURIComponent(JSON.stringify(item)); const data = encodeURIComponent(JSON.stringify(item));

View File

@@ -13,7 +13,9 @@
<view class="step-num-wrap"> <view class="step-num-wrap">
<view class="step-line" v-if="idx > 0"></view> <view class="step-line" v-if="idx > 0"></view>
<view class="step-num"> <view class="step-num">
<text v-if="activeTool === tool.type && showPanel">{{ tool.icon }}</text> <text v-if="activeTool === tool.type && showPanel">{{
tool.icon
}}</text>
<text v-else>{{ tool.step }}</text> <text v-else>{{ tool.step }}</text>
</view> </view>
</view> </view>
@@ -62,12 +64,17 @@
fontSize: fontSize + 'rpx', fontSize: fontSize + 'rpx',
lineHeight: fontSize * 1.5 + 'rpx', lineHeight: fontSize * 1.5 + 'rpx',
}" }"
>{{ targetName + "\n " + blessingText.content }}</text >{{
(targetName || "") + "\n " + (blessingText.content || "")
}}</text
> >
</view> </view>
<view <view
class="user" class="user"
:style="{ left: 160 + userOffsetX + 'rpx', bottom: 40 - userOffsetY + 'rpx' }" :style="{
left: 160 + userOffsetX + 'rpx',
bottom: 40 - userOffsetY + 'rpx',
}"
@touchstart.stop="handleUserTouchStart" @touchstart.stop="handleUserTouchStart"
@touchmove.stop="handleUserTouchMove" @touchmove.stop="handleUserTouchMove"
@touchend.stop="handleUserTouchEnd" @touchend.stop="handleUserTouchEnd"
@@ -113,31 +120,45 @@
<!-- 弹出编辑面板 --> <!-- 弹出编辑面板 -->
<view class="panel-container" :class="{ show: showPanel }"> <view class="panel-container" :class="{ show: showPanel }">
<view class="panel-mask" @tap="closePanel"></view> <view class="panel-mask" @tap="closePanel"></view>
<view class="panel-content" :class="{ 'glass-effect': activeTool === 'text' || activeTool === 'position' }"> <view
class="panel-content"
:class="{
'glass-effect': activeTool === 'text' || activeTool === 'position',
}"
>
<view class="panel-handle" @tap="closePanel"></view> <view class="panel-handle" @tap="closePanel"></view>
<!-- 标题选择区 --> <!-- 标题选择区 -->
<view v-if="activeTool === 'title'" class="section"> <view v-if="activeTool === 'title'" class="section">
<view class="section-title"> <view class="section-title">
<text>选择标题</text> <text>选择标题</text>
</view> </view>
<view class="tpl-scroll"> <view class="tpl-scroll">
<view class="tpl-grid"> <view class="tpl-grid">
<view <view
v-for="(title, i) in titles" v-for="(title, i) in titles"
:key="i" :key="i"
class="tpl-card title-card" class="tpl-card title-card"
:class="{ selected: title?.id === currentTitle?.id }" :class="{ selected: title?.id === currentTitle?.id }"
@tap="selectTitle(title)" @tap="selectTitle(title)"
> >
<image :src="title.imageUrl" class="title-cover" mode="aspectFit" /> <image
<view v-if="title?.id === currentTitle?.id" class="tpl-check"></view> :src="title.imageUrl"
</view> class="title-cover"
mode="aspectFit"
/>
<view v-if="title?.id === currentTitle?.id" class="tpl-check"
></view
>
</view>
</view>
<view v-if="loadingTitles" class="loading-more">加载中...</view>
<view
v-else-if="!hasMoreTitles && titles.length > 0"
class="no-more"
>没有更多了</view
>
</view> </view>
<view v-if="loadingTitles" class="loading-more">加载中...</view>
<view v-else-if="!hasMoreTitles && titles.length > 0" class="no-more">没有更多了</view>
</view>
</view> </view>
<!-- 模板区 --> <!-- 模板区 -->
@@ -154,7 +175,11 @@
:class="{ selected: tpl?.id === currentTemplate?.id }" :class="{ selected: tpl?.id === currentTemplate?.id }"
@tap="applyTemplate(tpl)" @tap="applyTemplate(tpl)"
> >
<image :src="tpl.imageUrl" class="tpl-cover" mode="aspectFill" /> <image
:src="tpl.imageUrl"
class="tpl-cover"
mode="aspectFill"
/>
<view class="tpl-name">{{ tpl.name }}</view> <view class="tpl-name">{{ tpl.name }}</view>
<view v-if="tpl?.id === currentTemplate?.id" class="tpl-check" <view v-if="tpl?.id === currentTemplate?.id" class="tpl-check"
></view ></view
@@ -168,7 +193,6 @@
>没有更多了</view >没有更多了</view
> >
</view> </view>
</view> </view>
<!-- 文字编辑 --> <!-- 文字编辑 -->
@@ -193,7 +217,11 @@
<text class="refresh-icon"></text> 换一批 <text class="refresh-icon"></text> 换一批
</view> </view>
</view> </view>
<scroll-view scroll-x class="greeting-scroll" show-scrollbar="false"> <scroll-view
scroll-x
class="greeting-scroll"
show-scrollbar="false"
>
<view class="greeting-list"> <view class="greeting-list">
<view <view
v-for="(text, index) in displayedGreetings" v-for="(text, index) in displayedGreetings"
@@ -272,7 +300,9 @@
:style="{ background: color }" :style="{ background: color }"
@tap="selectedColor = color" @tap="selectedColor = color"
> >
<view v-if="selectedColor === color" class="color-check"></view> <view v-if="selectedColor === color" class="color-check"
></view
>
</view> </view>
</view> </view>
</view> </view>
@@ -284,7 +314,7 @@
<text>调整位置</text> <text>调整位置</text>
</view> </view>
<view class="form-item" style="margin-top: 20rpx;"> <view class="form-item" style="margin-top: 20rpx">
<text class="label">祝福语气泡 (上下)</text> <text class="label">祝福语气泡 (上下)</text>
<slider <slider
:value="bubbleOffsetY" :value="bubbleOffsetY"
@@ -342,7 +372,9 @@
:style="{ background: color }" :style="{ background: color }"
@tap="signatureColor = color" @tap="signatureColor = color"
> >
<view v-if="signatureColor === color" class="color-check"></view> <view v-if="signatureColor === color" class="color-check"
></view
>
</view> </view>
</view> </view>
</view> </view>
@@ -408,9 +440,9 @@ const titleState = ref({
const titleStyle = computed(() => { const titleStyle = computed(() => {
return { return {
transform: `translate(${titleState.value.offsetX}rpx, ${titleState.value.offsetY}rpx) scale(${titleState.value.scale})`, transform: `translate(${titleState.value.offsetX}rpx, ${titleState.value.offsetY}rpx) scale(${titleState.value.scale})`,
top: '40rpx', top: "40rpx",
pointerEvents: 'auto', pointerEvents: "auto",
transition: 'none' transition: "none",
}; };
}); });
@@ -560,7 +592,7 @@ const fontList = [
name: "中圆", name: "中圆",
family: "ZhongYuan", family: "ZhongYuan",
url: "https://file.lihailezzc.com/ddcd9621740449a29c329f573bc1d0c5.woff2", // 示例地址 url: "https://file.lihailezzc.com/ddcd9621740449a29c329f573bc1d0c5.woff2", // 示例地址
} },
]; ];
const selectedFont = ref(fontList[0]); const selectedFont = ref(fontList[0]);
const loadedFonts = ref(new Set()); // 记录已加载的字体 const loadedFonts = ref(new Set()); // 记录已加载的字体
@@ -957,69 +989,71 @@ const saveByCanvas = async (save = true) => {
}); });
}; };
// 辅助函数rpx 转 px (基于预览容器宽度 506rpx 对应 Canvas 540px) // 辅助函数rpx 转 px (基于预览容器宽度 506rpx 对应 Canvas 540px)
const r2p = (rpx) => (rpx * 540) / 506; const r2p = (rpx) => (rpx * 540) / 506;
try { try {
// 1⃣ 画背景 // 1⃣ 画背景
// ⭐ 先加载背景图 // ⭐ 先加载背景图
const [bgImg, avatarImg, titleImg] = await Promise.all([ const [bgImg, avatarImg, titleImg] = await Promise.all([
loadCanvasImage(currentTemplate?.value?.imageUrl), loadCanvasImage(currentTemplate?.value?.imageUrl),
loadCanvasImage(userAvatar.value), loadCanvasImage(userAvatar.value),
currentTitle.value ? loadCanvasImage(currentTitle.value.imageUrl) : Promise.resolve(null), currentTitle.value
]); ? loadCanvasImage(currentTitle.value.imageUrl)
: Promise.resolve(null),
]);
ctx.drawImage(bgImg, 0, 0, W, H); ctx.drawImage(bgImg, 0, 0, W, H);
// 2⃣ 半透明遮罩 // 2⃣ 半透明遮罩
ctx.fillStyle = "rgba(0,0,0,0.08)"; ctx.fillStyle = "rgba(0,0,0,0.08)";
ctx.fillRect(0, 0, W, H); ctx.fillRect(0, 0, W, H);
// 3⃣ 标题图片 // 3⃣ 标题图片
if (titleImg) { if (titleImg) {
const previewBaseWidth = 400; // rpx const previewBaseWidth = 400; // rpx
const drawWidth = r2p(previewBaseWidth) * titleState.value.scale; const drawWidth = r2p(previewBaseWidth) * titleState.value.scale;
const drawHeight = (titleImg.height / titleImg.width) * drawWidth; const drawHeight = (titleImg.height / titleImg.width) * drawWidth;
// 计算绘制起点:居中 + 偏移量 // 计算绘制起点:居中 + 偏移量
const titleX = (W - drawWidth) / 2 + r2p(titleState.value.offsetX); const titleX = (W - drawWidth) / 2 + r2p(titleState.value.offsetX);
const titleY = r2p(40) + r2p(titleState.value.offsetY); const titleY = r2p(40) + r2p(titleState.value.offsetY);
ctx.drawImage(titleImg, titleX, titleY, drawWidth, drawHeight); ctx.drawImage(titleImg, titleX, titleY, drawWidth, drawHeight);
} }
// 4⃣ 祝福语气泡 // 4⃣ 祝福语气泡
// 预览中 .bubble 有 padding: 40rpx且 .card-overlay 有 padding: 30rpx // 预览中 .bubble 有 padding: 40rpx且 .card-overlay 有 padding: 30rpx
// 意味着文字距离容器边缘至少有 70rpx // 意味着文字距离容器边缘至少有 70rpx
drawBubbleText(ctx, { drawBubbleText(ctx, {
text: targetName.value + "\n " + blessingText.value.content, text: targetName.value + "\n " + blessingText.value.content,
x: 0, x: 0,
y: r2p(230 + bubbleOffsetY.value), y: r2p(230 + bubbleOffsetY.value),
maxWidth: r2p(bubbleMaxWidth.value), // 预览中 bubble-text 的宽度 maxWidth: r2p(bubbleMaxWidth.value), // 预览中 bubble-text 的宽度
canvasWidth: W, canvasWidth: W,
fontSize: r2p(fontSize.value), fontSize: r2p(fontSize.value),
lineHeight: r2p(fontSize.value * 1.6), // 预览中是 1.6 lineHeight: r2p(fontSize.value * 1.6), // 预览中是 1.6
padding: r2p(40 + 30), // 内部 padding 40 + 容器 padding 30 padding: r2p(40 + 30), // 内部 padding 40 + 容器 padding 30
backgroundColor: "transparent", backgroundColor: "transparent",
textColor: selectedColor.value, textColor: selectedColor.value,
fontFamily: selectedFont.value.family, fontFamily: selectedFont.value.family,
}); });
// 5⃣ 用户信息 // 5⃣ 用户信息
// 预览中 user 是 absolute, left: 160 + offsetX, bottom: 40 - offsetY // 预览中 user 是 absolute, left: 160 + offsetX, bottom: 40 - offsetY
drawUserBubble(ctx, { drawUserBubble(ctx, {
x: r2p(160 + userOffsetX.value), x: r2p(160 + userOffsetX.value),
bottom: r2p(40 - userOffsetY.value), bottom: r2p(40 - userOffsetY.value),
canvasHeight: H, canvasHeight: H,
avatarImg: avatarImg, avatarImg: avatarImg,
username: signatureName.value, username: signatureName.value,
desc: "送上祝福", desc: "送上祝福",
textColor: signatureColor.value, textColor: signatureColor.value,
avatarSize: r2p(64), avatarSize: r2p(64),
padding: r2p(15), padding: r2p(15),
fontSizeName: r2p(24), fontSizeName: r2p(24),
fontSizeDesc: r2p(20), fontSizeDesc: r2p(20),
}); });
// 6⃣ 输出 // 6⃣ 输出
uni.canvasToTempFilePath({ uni.canvasToTempFilePath({
@@ -1670,7 +1704,7 @@ function drawRoundRect(ctx, x, y, w, h, r, color) {
overflow: hidden; overflow: hidden;
} }
.position-section{ .position-section {
margin-bottom: 40rpx; margin-bottom: 40rpx;
} }
.greeting-card.active .greeting-text { .greeting-card.active .greeting-text {
@@ -1783,8 +1817,9 @@ function drawRoundRect(ctx, x, y, w, h, r, color) {
.btn.secondary { .btn.secondary {
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
color: #333; color: #333;
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.05), box-shadow:
inset 0 0 0 2rpx #eee; 0 8rpx 20rpx rgba(0, 0, 0, 0.05),
inset 0 0 0 2rpx #eee;
} }
.btn.primary { .btn.primary {

View File

@@ -28,10 +28,10 @@
</view> </view>
</view> </view>
<view class="row-2" v-if="isLoggedIn"> <view class="row-2" v-if="isLoggedIn">
<text class="arrow-icon"></text> <!-- <text class="arrow-icon"></text> -->
<text class="stats-text" <!-- <text class="stats-text"
>已发送 <text class="num">3</text> 条新春祝福</text >已发送 <text class="num">3</text> 条新春祝福</text
> > -->
</view> </view>
<view class="row-2" v-else> <view class="row-2" v-else>
<text class="stats-text">点击登录解锁更多功能</text> <text class="stats-text">点击登录解锁更多功能</text>
@@ -153,6 +153,7 @@ const defaultAvatarUrl =
const userInfo = computed(() => ({ const userInfo = computed(() => ({
nickName: userStore.userInfo.nickName || "点击登录", nickName: userStore.userInfo.nickName || "点击登录",
avatarUrl: userStore.userInfo.avatarUrl || defaultAvatarUrl, avatarUrl: userStore.userInfo.avatarUrl || defaultAvatarUrl,
isVip: userStore.userInfo.isVip || false,
})); }));
const isLoggedIn = computed(() => !!userStore.userInfo.nickName); const isLoggedIn = computed(() => !!userStore.userInfo.nickName);