feat: make gpage
This commit is contained in:
@@ -15,3 +15,10 @@ export const updateCard = async (data) => {
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const getCardTemplateList = async (page = 1) => {
|
||||
return request({
|
||||
url: "/api/blessing/card/template/list?page=" + page,
|
||||
method: "GET",
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
<view class="make-page" :style="{ paddingTop: getBavBarHeight() + 'px' }">
|
||||
<!-- 预览卡片 -->
|
||||
<view class="card-preview">
|
||||
<image class="card-bg" :src="currentTemplate.cover" mode="aspectFill" />
|
||||
<image
|
||||
class="card-bg"
|
||||
:src="currentTemplate?.imageUrl"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="card-overlay">
|
||||
<view class="title">
|
||||
<text class="main">新春快乐</text>
|
||||
@@ -31,6 +35,22 @@
|
||||
<view class="editor-panel">
|
||||
<view class="drag-handle"></view>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
<view class="bottom-actions">
|
||||
<button class="btn secondary" @tap="preview">
|
||||
<uni-icons type="cloud-download" size="20" color="#888"></uni-icons>
|
||||
<view>保存</view>
|
||||
</button>
|
||||
<button open-type="share" class="btn primary" @tap="shareOrSave">
|
||||
<uni-icons
|
||||
type="paperplane-filled"
|
||||
size="20"
|
||||
color="#fff"
|
||||
></uni-icons>
|
||||
<view>分享给好友</view>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 功能入口 -->
|
||||
<view class="tools">
|
||||
<view
|
||||
@@ -49,24 +69,34 @@
|
||||
<view v-if="activeTool === 'template'" class="section">
|
||||
<view class="section-title">
|
||||
<text>热门模板</text>
|
||||
<text class="more" @tap="showMore">查看更多 ></text>
|
||||
</view>
|
||||
<scroll-view scroll-x class="tpl-scroll" show-scrollbar="false">
|
||||
<view class="tpl-wrap">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="tpl-scroll"
|
||||
show-scrollbar="false"
|
||||
@scrolltolower="loadMoreTemplates"
|
||||
>
|
||||
<view class="tpl-grid">
|
||||
<view
|
||||
v-for="(tpl, i) in templates"
|
||||
:key="i"
|
||||
class="tpl-card"
|
||||
:class="{ selected: tpl.id === currentTemplate.id }"
|
||||
:class="{ selected: tpl?.id === currentTemplate?.id }"
|
||||
@tap="applyTemplate(tpl)"
|
||||
>
|
||||
<image :src="tpl.cover" class="tpl-cover" mode="aspectFill" />
|
||||
<image :src="tpl.imageUrl" class="tpl-cover" mode="aspectFill" />
|
||||
<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>
|
||||
</view>
|
||||
<view v-if="loadingTemplates" class="loading-more">加载中...</view>
|
||||
<view
|
||||
v-else-if="!hasMoreTemplates && templates.length > 0"
|
||||
class="no-more"
|
||||
>没有更多了</view
|
||||
>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
@@ -154,22 +184,6 @@
|
||||
<button class="btn" @tap="toggleAvatarDecor">切换挂饰</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
<view class="bottom-actions">
|
||||
<button class="btn secondary" @tap="preview">
|
||||
<uni-icons type="cloud-download" size="20" color="#888"></uni-icons>
|
||||
<view>保存</view>
|
||||
</button>
|
||||
<button open-type="share" class="btn primary" @tap="shareOrSave">
|
||||
<uni-icons
|
||||
type="paperplane-filled"
|
||||
size="20"
|
||||
color="#fff"
|
||||
></uni-icons>
|
||||
<view>分享给好友</view>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<canvas
|
||||
@@ -183,11 +197,14 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getBavBarHeight, getDeviceInfo } from "@/utils/system";
|
||||
import { createCardTmp, updateCard } from "@/api/make";
|
||||
import { createCardTmp, getCardTemplateList } from "@/api/make";
|
||||
import { createCardShareToken } from "@/api/card";
|
||||
import { onShareAppMessage, onLoad } from "@dcloudio/uni-app";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const templatePage = ref(1);
|
||||
const loadingTemplates = ref(false);
|
||||
const hasMoreTemplates = ref(true);
|
||||
const userStore = useUserStore();
|
||||
const cardId = ref("");
|
||||
|
||||
@@ -195,11 +212,11 @@ const targetName = ref("祝您");
|
||||
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
||||
const userAvatar = ref(
|
||||
userStore?.userInfo?.avatarUrl ||
|
||||
"https://file.lihailezzc.com/resource/b48c41054c2633c478463ac1b1f1ca23.png"
|
||||
"https://file.lihailezzc.com/resource/b48c41054c2633c478463ac1b1f1ca23.png",
|
||||
);
|
||||
|
||||
const blessingText = ref(
|
||||
"岁末将至,敬颂冬绥。平安喜乐,万事胜意。祝您2026年大吉大利!一马当先,前程似锦!龙马精神,阖家安康!"
|
||||
"岁末将至,敬颂冬绥。平安喜乐,万事胜意。祝您2026年大吉大利!一马当先,前程似锦!龙马精神,阖家安康!",
|
||||
);
|
||||
|
||||
const textColors = ["#ffffff", "#ff3b30", "#F5A623", "#8B572A", "#000000"];
|
||||
@@ -217,6 +234,7 @@ const greetingLib = [
|
||||
onLoad((options) => {
|
||||
cardId.value = "69674f307307beac4519025f";
|
||||
// createCard();
|
||||
getTemplateList();
|
||||
});
|
||||
|
||||
const createCard = async () => {
|
||||
@@ -230,6 +248,53 @@ const createCard = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getTemplateList = async (isLoadMore = false) => {
|
||||
if (loadingTemplates.value || (!hasMoreTemplates.value && isLoadMore)) return;
|
||||
|
||||
loadingTemplates.value = true;
|
||||
try {
|
||||
const res = await getCardTemplateList(templatePage.value);
|
||||
|
||||
// 兼容数组或对象列表格式
|
||||
const list = Array.isArray(res) ? res : res.list || [];
|
||||
|
||||
if (list.length > 0) {
|
||||
if (isLoadMore) {
|
||||
templates.value = [...templates.value, ...list];
|
||||
} else {
|
||||
templates.value = list;
|
||||
// 初始加载时设置第一个为当前选中
|
||||
if (list.length > 0 && !currentTemplate.value) {
|
||||
currentTemplate.value = list[0];
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否还有更多
|
||||
if (typeof res.hasNext !== "undefined") {
|
||||
hasMoreTemplates.value = res.hasNext;
|
||||
} else {
|
||||
// 如果没有 hasNext 字段,根据返回数量简单判断
|
||||
hasMoreTemplates.value = list.length >= 8; // 假设每页 10 条
|
||||
}
|
||||
|
||||
if (hasMoreTemplates.value) {
|
||||
templatePage.value++;
|
||||
}
|
||||
} else {
|
||||
if (!isLoadMore) templates.value = [];
|
||||
hasMoreTemplates.value = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载模板失败:", error);
|
||||
} finally {
|
||||
loadingTemplates.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadMoreTemplates = () => {
|
||||
getTemplateList(true);
|
||||
};
|
||||
|
||||
onShareAppMessage(async () => {
|
||||
const deviceInfo = getDeviceInfo();
|
||||
const shareTokenRes = await createCardShareToken({
|
||||
@@ -262,33 +327,12 @@ const selectGreeting = (text) => {
|
||||
const tools = [
|
||||
{ type: "template", text: "模板", icon: "▦" },
|
||||
{ type: "text", text: "文字", icon: "文" },
|
||||
{ type: "image", text: "图片/背景", icon: "图" },
|
||||
{ type: "avatar", text: "头像挂饰", icon: "饰" },
|
||||
// { type: "image", text: "图片/背景", icon: "图" },
|
||||
// { type: "avatar", text: "头像挂饰", icon: "饰" },
|
||||
];
|
||||
const activeTool = ref("template");
|
||||
|
||||
const templates = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: "金典红金",
|
||||
cover: "https://file.lihailezzc.com/20260109082842_666_1.jpg",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "富贵花开",
|
||||
cover: "https://file.lihailezzc.com/20260108222141_644_1.jpg",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "大气字法",
|
||||
cover: "https://file.lihailezzc.com/20260108222141_644_1.jpg",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "萌趣马年",
|
||||
cover: "https://file.lihailezzc.com/20260109082842_666_1.jpg",
|
||||
},
|
||||
]);
|
||||
const templates = ref([]);
|
||||
|
||||
const currentTemplate = ref(templates.value[0]);
|
||||
|
||||
@@ -359,7 +403,7 @@ const saveByCanvas = async (save = true) => {
|
||||
// 1️⃣ 画背景
|
||||
// ⭐ 先加载背景图
|
||||
const [bgPath, avatarPath] = await Promise.all([
|
||||
loadImage(currentTemplate.value.cover),
|
||||
loadImage(currentTemplate?.value?.imageUrl),
|
||||
loadImage(userAvatar.value),
|
||||
]);
|
||||
|
||||
@@ -552,7 +596,7 @@ function drawUserBubble(ctx, options) {
|
||||
bubbleWidth,
|
||||
bubbleHeight,
|
||||
bubbleHeight / 2,
|
||||
bubbleColor
|
||||
bubbleColor,
|
||||
);
|
||||
|
||||
// 2️⃣ 绘制头像
|
||||
@@ -566,7 +610,7 @@ function drawUserBubble(ctx, options) {
|
||||
avatarY + avatarSize / 2,
|
||||
avatarSize / 2,
|
||||
0,
|
||||
Math.PI * 2
|
||||
Math.PI * 2,
|
||||
);
|
||||
ctx.clip();
|
||||
ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize);
|
||||
@@ -767,46 +811,59 @@ function drawRoundRect(ctx, x, y, w, h, r, color) {
|
||||
}
|
||||
.tpl-scroll {
|
||||
margin-top: 12rpx;
|
||||
height: 600rpx; /* 增加高度以展示纵向列表 */
|
||||
}
|
||||
.tpl-wrap {
|
||||
display: flex;
|
||||
.tpl-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16rpx;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
.tpl-card {
|
||||
width: 180rpx;
|
||||
height: 240rpx;
|
||||
border-radius: 18rpx;
|
||||
width: 100%; /* 自适应 grid 宽度 */
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
margin-right: 16rpx;
|
||||
position: relative;
|
||||
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.06);
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.tpl-card.selected {
|
||||
outline: 4rpx solid #ff3b30;
|
||||
}
|
||||
.tpl-cover {
|
||||
width: 100%;
|
||||
height: 160rpx;
|
||||
height: 368rpx;
|
||||
}
|
||||
.tpl-name {
|
||||
font-size: 22rpx;
|
||||
font-size: 20rpx;
|
||||
color: #333;
|
||||
padding: 8rpx 12rpx;
|
||||
padding: 6rpx 8rpx;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.tpl-check {
|
||||
position: absolute;
|
||||
right: 10rpx;
|
||||
top: 10rpx;
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
right: 6rpx;
|
||||
top: 6rpx;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border-radius: 50%;
|
||||
background: #ff3b30;
|
||||
color: #fff;
|
||||
font-size: 22rpx;
|
||||
font-size: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.loading-more,
|
||||
.no-more {
|
||||
text-align: center;
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
padding: 10rpx 0;
|
||||
}
|
||||
|
||||
/* 文字编辑区 */
|
||||
.text-edit-section {
|
||||
|
||||
Reference in New Issue
Block a user