Compare commits
15 Commits
526e2aad70
...
239db8e609
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
239db8e609 | ||
|
|
72ebb8253d | ||
|
|
fcc728465b | ||
|
|
9c1382c503 | ||
|
|
e664356a5f | ||
|
|
ad40704642 | ||
|
|
82fc0f80a5 | ||
|
|
b2e41c9a7b | ||
|
|
b6091de037 | ||
|
|
7c80f9a6a6 | ||
|
|
b2b59cb61a | ||
|
|
7d0b79bd16 | ||
|
|
13d1ea604e | ||
|
|
bd45082544 | ||
|
|
52af2aad8f |
@@ -22,3 +22,10 @@ export const updateUserInfo = async (body) => {
|
|||||||
data: body,
|
data: body,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reportPrivacy = async () => {
|
||||||
|
// return request({
|
||||||
|
// url: "/api/common/privacy/report",
|
||||||
|
// method: "POST",
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|||||||
@@ -52,3 +52,10 @@ export const getRecommendList = async (page = 1) => {
|
|||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const msgCheckApi = async (content) => {
|
||||||
|
return request({
|
||||||
|
url: "/api/common/msg-check?content=" + content,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,32 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<uni-popup ref="popupRef" type="bottom" :safe-area="false">
|
<view>
|
||||||
<view class="popup-container">
|
<uni-popup ref="popupRef" type="bottom" :safe-area="false">
|
||||||
<view class="popup-header">
|
<view class="popup-container">
|
||||||
<text class="popup-title">登录授权</text>
|
<view class="popup-header">
|
||||||
</view>
|
<text class="popup-title">登录授权</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="avatar-nickname">
|
<view class="avatar-nickname">
|
||||||
<button
|
<button
|
||||||
open-type="chooseAvatar"
|
open-type="chooseAvatar"
|
||||||
@chooseavatar="onChooseAvatar"
|
@chooseavatar="onChooseAvatar"
|
||||||
class="avatar-selector custom-button"
|
class="avatar-selector custom-button"
|
||||||
>
|
>
|
||||||
<image v-if="avatarUrl" :src="avatarUrl" class="avatar-preview" />
|
<image v-if="avatarUrl" :src="avatarUrl" class="avatar-preview" />
|
||||||
<text v-else>点击获取头像</text>
|
<text v-else>点击获取头像</text>
|
||||||
|
</button>
|
||||||
|
<input
|
||||||
|
class="nickname-input"
|
||||||
|
type="nickname"
|
||||||
|
v-model="nickname"
|
||||||
|
placeholder="请输入昵称"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<button class="confirm-btn custom-button" @tap="confirmLogin">
|
||||||
|
确认登录
|
||||||
</button>
|
</button>
|
||||||
<input
|
|
||||||
class="nickname-input"
|
|
||||||
type="nickname"
|
|
||||||
v-model="nickname"
|
|
||||||
placeholder="请输入昵称"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
|
</uni-popup>
|
||||||
|
|
||||||
<button class="confirm-btn custom-button" @tap="confirmLogin">
|
<!-- 隐私协议弹窗 -->
|
||||||
确认登录
|
<PrivacyPopup ref="privacyRef" @agree="onPrivacyAgree" />
|
||||||
</button>
|
</view>
|
||||||
</view>
|
|
||||||
</uni-popup>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -36,8 +41,10 @@ import { getPlatformProvider } from "@/utils/system";
|
|||||||
import { uploadImage } from "@/utils/common";
|
import { uploadImage } from "@/utils/common";
|
||||||
import { apiLogin } from "@/api/auth.js";
|
import { apiLogin } from "@/api/auth.js";
|
||||||
import { wxLogin } from "@/utils/login.js";
|
import { wxLogin } from "@/utils/login.js";
|
||||||
|
import PrivacyPopup from "@/components/PrivacyPopup/PrivacyPopup.vue";
|
||||||
|
|
||||||
const popupRef = ref(null);
|
const popupRef = ref(null);
|
||||||
|
const privacyRef = ref(null);
|
||||||
const avatarUrl = ref("");
|
const avatarUrl = ref("");
|
||||||
const nickname = ref("");
|
const nickname = ref("");
|
||||||
|
|
||||||
@@ -46,19 +53,65 @@ const userStore = useUserStore();
|
|||||||
const emit = defineEmits(["logind"]);
|
const emit = defineEmits(["logind"]);
|
||||||
|
|
||||||
const festivalNames = [
|
const festivalNames = [
|
||||||
'春意','福星','小福','新禧','瑞雪','花灯','喜乐','元宝','春芽','年年',
|
"春意",
|
||||||
'花灯','月圆','灯影','小灯','星灯','彩灯',
|
"福星",
|
||||||
'清风','微风','小晴','碧波','流泉',
|
"小福",
|
||||||
'月光','玉轮','桂香','秋叶','星河','小月','露华','秋水',
|
"新禧",
|
||||||
'雪落','冰晶','暖阳','小雪','冬影','雪花','松影'
|
"瑞雪",
|
||||||
|
"花灯",
|
||||||
|
"喜乐",
|
||||||
|
"元宝",
|
||||||
|
"春芽",
|
||||||
|
"年年",
|
||||||
|
"花灯",
|
||||||
|
"月圆",
|
||||||
|
"灯影",
|
||||||
|
"小灯",
|
||||||
|
"星灯",
|
||||||
|
"彩灯",
|
||||||
|
"清风",
|
||||||
|
"微风",
|
||||||
|
"小晴",
|
||||||
|
"碧波",
|
||||||
|
"流泉",
|
||||||
|
"月光",
|
||||||
|
"玉轮",
|
||||||
|
"桂香",
|
||||||
|
"秋叶",
|
||||||
|
"星河",
|
||||||
|
"小月",
|
||||||
|
"露华",
|
||||||
|
"秋水",
|
||||||
|
"雪落",
|
||||||
|
"冰晶",
|
||||||
|
"暖阳",
|
||||||
|
"小雪",
|
||||||
|
"冬影",
|
||||||
|
"雪花",
|
||||||
|
"松影",
|
||||||
];
|
];
|
||||||
|
|
||||||
const getFestivalName = () => {
|
const getFestivalName = () => {
|
||||||
const idx = Math.floor(Math.random() * festivalNames.length);
|
const idx = Math.floor(Math.random() * festivalNames.length);
|
||||||
return festivalNames[idx];
|
return festivalNames[idx];
|
||||||
}
|
};
|
||||||
|
|
||||||
const open = () => {
|
const open = async () => {
|
||||||
|
console.log(22223333);
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const isAgreed = await privacyRef.value.check();
|
||||||
|
console.log(1111, isAgreed);
|
||||||
|
if (isAgreed) {
|
||||||
|
popupRef.value.open();
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
popupRef.value.open();
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPrivacyAgree = () => {
|
||||||
popupRef.value.open();
|
popupRef.value.open();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,7 +128,9 @@ const confirmLogin = async () => {
|
|||||||
const platform = getPlatformProvider();
|
const platform = getPlatformProvider();
|
||||||
if (platform === "mp-weixin") {
|
if (platform === "mp-weixin") {
|
||||||
const code = await wxLogin();
|
const code = await wxLogin();
|
||||||
const imageUrl = avatarUrl.value ? await uploadImage(avatarUrl.value) : "";
|
const imageUrl = avatarUrl.value
|
||||||
|
? await uploadImage(avatarUrl.value)
|
||||||
|
: "";
|
||||||
|
|
||||||
const loginRes = await apiLogin({
|
const loginRes = await apiLogin({
|
||||||
code,
|
code,
|
||||||
|
|||||||
205
components/PrivacyPopup/PrivacyPopup.vue
Normal file
205
components/PrivacyPopup/PrivacyPopup.vue
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<view v-if="show" class="privacy-popup">
|
||||||
|
<view class="mask"></view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="title">用户隐私保护指引</view>
|
||||||
|
<view class="desc">
|
||||||
|
感谢您使用本小程序。在使用前,请您仔细阅读
|
||||||
|
<text class="link" @click="openPrivacyContract">{{
|
||||||
|
privacyContractName
|
||||||
|
}}</text>
|
||||||
|
。当您点击“同意”并开始使用产品服务时,即表示您已理解并同意该条款内容,该条款将对您产生法律约束力。如您拒绝,将无法进入小程序。
|
||||||
|
</view>
|
||||||
|
<view class="btns">
|
||||||
|
<button class="btn refuse" @click="handleDisagree">拒绝</button>
|
||||||
|
<button
|
||||||
|
id="agree-btn"
|
||||||
|
class="btn agree"
|
||||||
|
open-type="agreePrivacyAuthorization"
|
||||||
|
@agreeprivacyauthorization="handleAgree"
|
||||||
|
>
|
||||||
|
同意
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { reportPrivacy } from "@/api/auth.js";
|
||||||
|
|
||||||
|
const show = ref(false);
|
||||||
|
const privacyContractName = ref("《用户隐私保护指引》");
|
||||||
|
|
||||||
|
const emit = defineEmits(["agree"]);
|
||||||
|
let resolveCheck = null;
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const check = () => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (uni.getPrivacySetting) {
|
||||||
|
uni.getPrivacySetting({
|
||||||
|
success: (res) => {
|
||||||
|
if (res.needAuthorization) {
|
||||||
|
privacyContractName.value =
|
||||||
|
res.privacyContractName || "《用户隐私保护指引》";
|
||||||
|
show.value = true;
|
||||||
|
resolveCheck = resolve;
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error("getPrivacySetting fail:", err);
|
||||||
|
resolve(true);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// Only for WeChat Mini Program
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
// onMounted(() => {
|
||||||
|
// check();
|
||||||
|
// });
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
const openPrivacyContract = () => {
|
||||||
|
uni.openPrivacyContract({
|
||||||
|
success: () => {},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error("openPrivacyContract fail", err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAgree = async (e) => {
|
||||||
|
if (!show.value) return; // Prevent double execution
|
||||||
|
console.log("handleAgree triggered", e);
|
||||||
|
// 1. Save to local storage
|
||||||
|
uni.setStorageSync("hasAgreedPrivacy", true);
|
||||||
|
|
||||||
|
// 2. Hide popup
|
||||||
|
show.value = false;
|
||||||
|
|
||||||
|
emit("agree");
|
||||||
|
|
||||||
|
// 3. Resolve the check promise
|
||||||
|
if (resolveCheck) {
|
||||||
|
resolveCheck(true);
|
||||||
|
resolveCheck = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Call server API
|
||||||
|
try {
|
||||||
|
await reportPrivacy();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Report privacy failed", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDisagree = () => {
|
||||||
|
// Exit mini program
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.exitMiniProgram({
|
||||||
|
success: () => {
|
||||||
|
console.log("Exit success");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
check,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.privacy-popup {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.mask {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
width: 600rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 48rpx 40rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 48rpx;
|
||||||
|
text-align: justify;
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: #576b95;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 240rpx;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.refuse {
|
||||||
|
background: #f2f2f2;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.agree {
|
||||||
|
background: #07c160;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
/* 小程序特有相关 */
|
/* 小程序特有相关 */
|
||||||
"mp-weixin": {
|
"mp-weixin": {
|
||||||
"appid": "wx3fcc07a061af049a",
|
"appid": "wx3fcc07a061af049a",
|
||||||
|
"__usePrivacyCheck__": true,
|
||||||
"setting": {
|
"setting": {
|
||||||
"urlCheck": false
|
"urlCheck": false
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -48,9 +48,15 @@
|
|||||||
</view>
|
</view>
|
||||||
<scroll-view scroll-x class="avatar-scroll" show-scrollbar="false">
|
<scroll-view scroll-x class="avatar-scroll" show-scrollbar="false">
|
||||||
<view class="avatar-list">
|
<view class="avatar-list">
|
||||||
<view class="avatar-card upload-card" @tap="useWeChatAvatar">
|
<view class="avatar-card upload-card">
|
||||||
<view class="upload-icon">📷</view>
|
<button
|
||||||
<text class="upload-text">微信头像</text>
|
class="wechat-avatar-btn"
|
||||||
|
open-type="chooseAvatar"
|
||||||
|
@chooseavatar="onChooseAvatar"
|
||||||
|
>
|
||||||
|
<view class="upload-icon">📷</view>
|
||||||
|
<text class="upload-text">微信头像</text>
|
||||||
|
</button>
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
v-for="(item, i) in systemAvatars"
|
v-for="(item, i) in systemAvatars"
|
||||||
@@ -465,6 +471,26 @@ const handleLogind = async () => {
|
|||||||
// Logic after successful login if needed
|
// Logic after successful login if needed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onChooseAvatar = async (e) => {
|
||||||
|
const avatarUrl = e.detail.avatarUrl;
|
||||||
|
if (!avatarUrl) return;
|
||||||
|
|
||||||
|
uni.showLoading({ title: "上传中...", mask: true });
|
||||||
|
try {
|
||||||
|
const imageUrl = await uploadImage(avatarUrl);
|
||||||
|
|
||||||
|
currentAvatar.value = {
|
||||||
|
id: "wechat_" + Date.now(),
|
||||||
|
imageUrl: imageUrl,
|
||||||
|
};
|
||||||
|
uni.hideLoading();
|
||||||
|
} catch (e) {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({ title: e || "上传失败", icon: "none" });
|
||||||
|
console.error("Upload avatar error", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const useWeChatAvatar = () => {
|
const useWeChatAvatar = () => {
|
||||||
if (!isLoggedIn.value) {
|
if (!isLoggedIn.value) {
|
||||||
loginPopupRef.value.open();
|
loginPopupRef.value.open();
|
||||||
@@ -832,28 +858,49 @@ const loadImage = (url) => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.06);
|
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||||
}
|
|
||||||
.avatar-card.active {
|
|
||||||
outline: 4rpx solid #ff3b30;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upload-card {
|
&.active {
|
||||||
display: flex;
|
outline: 4rpx solid #ff3b30;
|
||||||
flex-direction: column;
|
}
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
&.upload-card {
|
||||||
background: #fff5f5;
|
background: #fff5f5;
|
||||||
border: 2rpx dashed #ffccc7;
|
display: flex;
|
||||||
box-sizing: border-box;
|
flex-direction: column;
|
||||||
}
|
align-items: center;
|
||||||
.upload-icon {
|
justify-content: center;
|
||||||
font-size: 48rpx;
|
border: 2rpx dashed #ffccc7;
|
||||||
margin-bottom: 8rpx;
|
box-sizing: border-box;
|
||||||
}
|
|
||||||
.upload-text {
|
.wechat-avatar-btn {
|
||||||
font-size: 22rpx;
|
width: 100%;
|
||||||
color: #ff3b30;
|
height: 100%;
|
||||||
font-weight: 500;
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: normal;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-icon {
|
||||||
|
font-size: 48rpx;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-text {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #ff3b30;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-thumb {
|
.avatar-thumb {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="detail-page" >
|
<view class="detail-page">
|
||||||
<NavBar title="祝福贺卡" />
|
<NavBar title="祝福贺卡" />
|
||||||
|
|
||||||
<scroll-view scroll-y class="content-scroll">
|
<scroll-view scroll-y class="content-scroll">
|
||||||
<view class="content-wrap">
|
<view class="content-wrap">
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- Recommendations -->
|
<!-- Recommendations -->
|
||||||
<view class="recommend-section">
|
<!-- <view class="recommend-section">
|
||||||
<view class="section-header">
|
<view class="section-header">
|
||||||
<text class="section-title">大家都在玩的头像挂饰</text>
|
<text class="section-title">大家都在玩的头像挂饰</text>
|
||||||
<text class="more-link">查看更多</text>
|
<text class="more-link">查看更多</text>
|
||||||
@@ -65,24 +65,38 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view> -->
|
||||||
|
|
||||||
<!-- Banner -->
|
<!-- Banner -->
|
||||||
<view class="banner-card">
|
<view class="wallpaper-banner" @tap="goToFortune">
|
||||||
<view class="banner-icon">
|
<view class="banner-icon">
|
||||||
<image
|
<text>🏮</text>
|
||||||
src="/static/logo.png"
|
|
||||||
mode="aspectFit"
|
|
||||||
style="width: 100%; height: 100%"
|
|
||||||
v-if="false"
|
|
||||||
/>
|
|
||||||
<view class="placeholder-icon">☺</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="banner-content">
|
<view class="banner-content">
|
||||||
<view class="banner-title">领取我的马年头像框</view>
|
<text class="banner-title">去抽取新年运势</text>
|
||||||
<view class="banner-desc">定制专属新春社交形象</view>
|
<text class="banner-desc">每日一签,开启你的新年好运</text>
|
||||||
</view>
|
</view>
|
||||||
<button class="banner-btn">去领取</button>
|
<text class="banner-arrow">›</text>
|
||||||
|
</view>
|
||||||
|
<view class="wallpaper-banner" @tap="goToGreeting">
|
||||||
|
<view class="banner-icon">
|
||||||
|
<text>🧧</text>
|
||||||
|
</view>
|
||||||
|
<view class="banner-content">
|
||||||
|
<text class="banner-title">去制作新年头像</text>
|
||||||
|
<text class="banner-desc">定制专属头像,传递浓浓年味</text>
|
||||||
|
</view>
|
||||||
|
<text class="banner-arrow">›</text>
|
||||||
|
</view>
|
||||||
|
<view class="wallpaper-banner" @tap="goToWallpaper">
|
||||||
|
<view class="banner-icon">
|
||||||
|
<text>🖼</text>
|
||||||
|
</view>
|
||||||
|
<view class="banner-content">
|
||||||
|
<text class="banner-title">去挑选新年壁纸</text>
|
||||||
|
<text class="banner-desc">精选新年壁纸,让手机也过年</text>
|
||||||
|
</view>
|
||||||
|
<text class="banner-arrow">›</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
@@ -170,6 +184,29 @@ const decorList = ref([
|
|||||||
img: "https://file.lihailezzc.com/resource/1463f294244c11cf274a5eaae115872a.jpeg",
|
img: "https://file.lihailezzc.com/resource/1463f294244c11cf274a5eaae115872a.jpeg",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
const goToMake = () => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: "/pages/avatar/index",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToFortune = () => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: "/pages/fortune/index",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToGreeting = () => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: "/pages/avatar/index",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToWallpaper = () => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: "/pages/wallpaper/index",
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -229,6 +266,53 @@ const decorList = ref([
|
|||||||
margin-right: 6rpx;
|
margin-right: 6rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wallpaper-banner {
|
||||||
|
background: #f8f8f8;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-icon {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-icon text {
|
||||||
|
font-size: 40rpx;
|
||||||
|
color: #ff3b30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-desc {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-arrow {
|
||||||
|
font-size: 36rpx;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Card Container */
|
/* Card Container */
|
||||||
.card-container {
|
.card-container {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="fortune-detail-page">
|
<view class="fortune-detail-page">
|
||||||
<NavBar title="2026 灵马贺岁" :transparent="true"/>
|
<NavBar title="" :transparent="true" color="#ffd700" />
|
||||||
|
|
||||||
<!-- 顶部提示条 -->
|
<!-- 顶部提示条 -->
|
||||||
<!-- <view class="top-banner" v-if="inviterName">
|
<!-- <view class="top-banner" v-if="inviterName">
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
}}</view>
|
}}</view>
|
||||||
<view class="content-desc">
|
<view class="content-desc">
|
||||||
{{
|
{{
|
||||||
fortuneData.desc ||
|
fortuneData.content ||
|
||||||
"灵马奔腾,瑞气盈门。此签预示您在2026年如同千里骏马,不仅拥有敏锐的洞察力,更有贵人暗中相助。事业将如破竹之势,学业更有意外惊喜,心之所向,皆能圆满。"
|
"灵马奔腾,瑞气盈门。此签预示您在2026年如同千里骏马,不仅拥有敏锐的洞察力,更有贵人暗中相助。事业将如破竹之势,学业更有意外惊喜,心之所向,皆能圆满。"
|
||||||
}}
|
}}
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="fortune-page" >
|
<view class="fortune-page">
|
||||||
<NavBar title="2026 新年运势" :transparent="true" color="#ffd700"/>
|
<NavBar title="2026 新年运势" :transparent="true" color="#ffd700" />
|
||||||
|
|
||||||
<!-- 初始状态:签筒 -->
|
<!-- 初始状态:签筒 -->
|
||||||
<view class="state-initial" v-if="status !== 'result'">
|
<view class="state-initial" v-if="status !== 'result'">
|
||||||
@@ -166,9 +166,10 @@ onShareAppMessage(async () => {
|
|||||||
});
|
});
|
||||||
getRewardByShare();
|
getRewardByShare();
|
||||||
return {
|
return {
|
||||||
title: "新春祝福",
|
title: "马年运势我已经抽过了,你的会是什么?",
|
||||||
path: `${cardId.value ? `/pages/fortune/detail?shareToken=${shareTokenRes.shareToken}` : `/pages/fortune/index?shareToken=${shareTokenRes.shareToken}`}`,
|
path: `${cardId.value ? `/pages/fortune/detail?shareToken=${shareTokenRes.shareToken}` : `/pages/fortune/index?shareToken=${shareTokenRes.shareToken}`}`,
|
||||||
imageUrl: "/static/images/bg.jpg",
|
imageUrl:
|
||||||
|
"https://file.lihailezzc.com/resource/cfed2edbfa19250b836a87a4bbf0d5ad.png",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -592,7 +593,7 @@ const saveCard = () => {
|
|||||||
/* 结果状态 */
|
/* 结果状态 */
|
||||||
.state-result {
|
.state-result {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20px 30px;
|
padding: 130px 30px 20px;
|
||||||
animation: fadeIn 0.8s ease-out;
|
animation: fadeIn 0.8s ease-out;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<view class="stats-body">
|
<view class="stats-body">
|
||||||
<view class="stats-row">
|
<view class="stats-row">
|
||||||
<text class="stats-label">已收集</text>
|
<text class="stats-label">已收集</text>
|
||||||
<text class="stats-num">{{ records.length }}</text>
|
<text class="stats-num">{{ totalCount }}</text>
|
||||||
<text class="stats-label">张好运卡</text>
|
<text class="stats-label">张好运卡</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="progress-bar">
|
<view class="progress-bar">
|
||||||
@@ -46,22 +46,20 @@
|
|||||||
>
|
>
|
||||||
<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"
|
||||||
/>
|
/>
|
||||||
<view class="item-tag" :class="getTagClass(item.tag)">
|
<view class="item-tag" :class="getTagClass(item.fortuneLevel)">
|
||||||
{{ item.tag || "大吉" }}
|
{{ getFortuneName(item.fortuneLevel) }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-info">
|
<view class="item-info">
|
||||||
<text class="item-title">{{ item.title }}</text>
|
<text class="item-title">{{ item.title }}</text>
|
||||||
<view class="item-footer">
|
<view class="item-footer">
|
||||||
<text class="item-date">{{ item.date }}</text>
|
<text class="item-date">{{
|
||||||
<view class="item-link">
|
formatDate(item.day, "YYYY-MM-DD")
|
||||||
<text>详情</text>
|
}}</text>
|
||||||
<text class="arrow">→</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -90,11 +88,11 @@ import { ref, computed } from "vue";
|
|||||||
import { onLoad } from "@dcloudio/uni-app";
|
import { onLoad } from "@dcloudio/uni-app";
|
||||||
import { getList } from "@/api/fortune.js";
|
import { getList } from "@/api/fortune.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
import { formatDate } from "@/utils/date.js";
|
||||||
// 状态管理
|
// 状态管理
|
||||||
const records = ref([]);
|
const records = ref([]);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const curCount = ref(0);
|
const totalCount = ref(0);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const hasMore = ref(true);
|
const hasMore = ref(true);
|
||||||
|
|
||||||
@@ -105,14 +103,30 @@ const progressWidth = computed(() => {
|
|||||||
return `${percentage}%`;
|
return `${percentage}%`;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getTagClass = (tag) => {
|
const getFortuneName = (level) => {
|
||||||
const map = {
|
const map = {
|
||||||
大吉: "tag-gold",
|
1: "吉签",
|
||||||
安康: "tag-green",
|
2: "中吉签",
|
||||||
顺遂: "tag-red",
|
3: "上吉签",
|
||||||
上吉: "tag-orange",
|
4: "上上签",
|
||||||
|
5: "大吉签",
|
||||||
};
|
};
|
||||||
return map[tag] || "tag-gold";
|
return map[level] || "吉签";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTagClass = (level) => {
|
||||||
|
const map = {
|
||||||
|
1: "tag-blue",
|
||||||
|
2: "tag-green",
|
||||||
|
3: "tag-orange",
|
||||||
|
4: "tag-red",
|
||||||
|
5: "tag-gold",
|
||||||
|
};
|
||||||
|
return map[level] || "tag-blue";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getThumbUrl = (url) => {
|
||||||
|
return `${url}?imageView2/1/w/360/h/480/q/80`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
@@ -129,7 +143,7 @@ const loadData = async () => {
|
|||||||
page.value++;
|
page.value++;
|
||||||
// 简单判断是否还有更多数据
|
// 简单判断是否还有更多数据
|
||||||
hasMore.value = res.hasNext;
|
hasMore.value = res.hasNext;
|
||||||
curCount.value = res.totalCount || 0;
|
totalCount.value = res.totalCount || 0;
|
||||||
} else {
|
} else {
|
||||||
hasMore.value = false;
|
hasMore.value = false;
|
||||||
}
|
}
|
||||||
@@ -145,19 +159,13 @@ const loadData = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
console.log(666666666);
|
|
||||||
loadData();
|
loadData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const goBack = () => {
|
|
||||||
uni.navigateBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
const goDetail = (item) => {
|
const goDetail = (item) => {
|
||||||
// 传递数据到详情页
|
uni.previewImage({
|
||||||
const data = encodeURIComponent(JSON.stringify(item));
|
current: item.imageUrl,
|
||||||
uni.navigateTo({
|
urls: records.value.map((r) => r.imageUrl),
|
||||||
url: `/pages/fortune/detail?data=${data}`,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -307,17 +315,22 @@ onLoad(() => {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
backdrop-filter: blur(4px);
|
backdrop-filter: blur(4px);
|
||||||
}
|
}
|
||||||
.tag-gold {
|
.tag-blue {
|
||||||
background: rgba(212, 175, 55, 0.9);
|
background: rgba(0, 122, 255, 0.9);
|
||||||
}
|
}
|
||||||
.tag-green {
|
.tag-green {
|
||||||
background: rgba(46, 139, 87, 0.9);
|
background: rgba(52, 199, 89, 0.9);
|
||||||
}
|
|
||||||
.tag-red {
|
|
||||||
background: rgba(178, 34, 34, 0.9);
|
|
||||||
}
|
}
|
||||||
.tag-orange {
|
.tag-orange {
|
||||||
background: rgba(255, 140, 0, 0.9);
|
background: rgba(255, 149, 0, 0.9);
|
||||||
|
}
|
||||||
|
.tag-red {
|
||||||
|
background: rgba(255, 59, 48, 0.9);
|
||||||
|
}
|
||||||
|
.tag-gold {
|
||||||
|
background: rgba(212, 175, 55, 0.9);
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-info {
|
.item-info {
|
||||||
|
|||||||
@@ -358,7 +358,8 @@ onShareAppMessage(() => {
|
|||||||
return {
|
return {
|
||||||
title: "新春祝福",
|
title: "新春祝福",
|
||||||
path: "/pages/detail/index",
|
path: "/pages/detail/index",
|
||||||
imageUrl: "/static/images/bg.jpg",
|
imageUrl:
|
||||||
|
"https://file.lihailezzc.com/resource/cfed2edbfa19250b836a87a4bbf0d5ad.png",
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
uni.showToast({ title: "分享成功", icon: "success" });
|
uni.showToast({ title: "分享成功", icon: "success" });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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,12 +193,10 @@
|
|||||||
>没有更多了</view
|
>没有更多了</view
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 文字编辑 -->
|
<!-- 文字编辑 -->
|
||||||
<view v-if="activeTool === 'text'" class="section text-edit-section">
|
<view v-if="activeTool === 'text'" class="section text-edit-section">
|
||||||
<!-- 祝贺对象 -->
|
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="label">祝福对象</text>
|
<text class="label">祝福对象</text>
|
||||||
<input
|
<input
|
||||||
@@ -182,6 +205,7 @@
|
|||||||
placeholder="请输入称呼"
|
placeholder="请输入称呼"
|
||||||
placeholder-style="color:#ccc"
|
placeholder-style="color:#ccc"
|
||||||
maxlength="10"
|
maxlength="10"
|
||||||
|
@blur="handleTargetNameBlur"
|
||||||
/>
|
/>
|
||||||
</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"
|
||||||
@@ -222,7 +250,8 @@
|
|||||||
v-model="signatureName"
|
v-model="signatureName"
|
||||||
placeholder="请输入署名"
|
placeholder="请输入署名"
|
||||||
placeholder-style="color:#ccc"
|
placeholder-style="color:#ccc"
|
||||||
maxlength="5"
|
maxlength="10"
|
||||||
|
@blur="handleSignatureBlur"
|
||||||
/>
|
/>
|
||||||
<text class="edit-icon">✎</text>
|
<text class="edit-icon">✎</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -272,7 +301,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 +315,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 +373,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>
|
||||||
@@ -364,7 +397,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { getBavBarHeight, getDeviceInfo } from "@/utils/system";
|
import { getBavBarHeight, getDeviceInfo } from "@/utils/system";
|
||||||
import { generateObjectId } from "@/utils/common";
|
import { generateObjectId, getShareToken } from "@/utils/common";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createCardTmp,
|
createCardTmp,
|
||||||
@@ -373,7 +406,12 @@ import {
|
|||||||
getCardTemplateContentList,
|
getCardTemplateContentList,
|
||||||
getCardTemplateTitleList,
|
getCardTemplateTitleList,
|
||||||
} from "@/api/make";
|
} from "@/api/make";
|
||||||
import { createShareToken, abilityCheck, getShareReward } from "@/api/system";
|
import {
|
||||||
|
createShareToken,
|
||||||
|
abilityCheck,
|
||||||
|
getShareReward,
|
||||||
|
msgCheckApi,
|
||||||
|
} from "@/api/system";
|
||||||
import {
|
import {
|
||||||
onShareAppMessage,
|
onShareAppMessage,
|
||||||
onLoad,
|
onLoad,
|
||||||
@@ -395,7 +433,7 @@ const cardId = ref("");
|
|||||||
|
|
||||||
// 标题相关
|
// 标题相关
|
||||||
const titles = ref([]);
|
const titles = ref([]);
|
||||||
const currentTitle = ref(null);
|
const currentTitle = ref(titles.value[0]);
|
||||||
const titlePage = ref(1);
|
const titlePage = ref(1);
|
||||||
const loadingTitles = ref(false);
|
const loadingTitles = ref(false);
|
||||||
const hasMoreTitles = ref(true);
|
const hasMoreTitles = ref(true);
|
||||||
@@ -408,9 +446,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",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -514,7 +552,38 @@ const handleTitleTouchMove = (e) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const targetName = ref("祝您");
|
const targetName = ref("祝您");
|
||||||
|
const oldTargetName = ref("祝您");
|
||||||
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
||||||
|
const oldSignatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
||||||
|
|
||||||
|
const handleTargetNameBlur = async () => {
|
||||||
|
if (!targetName.value || targetName.value === oldTargetName.value) return;
|
||||||
|
const res = await msgCheckApi(targetName.value);
|
||||||
|
if (!res.success) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.message || "消息不符合发布规范,请稍作修改后再试",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
targetName.value = oldTargetName.value;
|
||||||
|
} else {
|
||||||
|
oldTargetName.value = targetName.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSignatureBlur = async () => {
|
||||||
|
if (!signatureName.value || signatureName.value === oldSignatureName.value)
|
||||||
|
return;
|
||||||
|
const res = await msgCheckApi(signatureName.value);
|
||||||
|
if (!res.success) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.message || "消息不符合发布规范,请稍作修改后再试",
|
||||||
|
icon: "none",
|
||||||
|
});
|
||||||
|
signatureName.value = oldSignatureName.value;
|
||||||
|
} else {
|
||||||
|
oldSignatureName.value = signatureName.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
const userAvatar = ref(
|
const userAvatar = ref(
|
||||||
userStore?.userInfo?.avatarUrl ||
|
userStore?.userInfo?.avatarUrl ||
|
||||||
"https://file.lihailezzc.com/resource/96023631c6ab9c3496b7620097af3d6f.png",
|
"https://file.lihailezzc.com/resource/96023631c6ab9c3496b7620097af3d6f.png",
|
||||||
@@ -560,7 +629,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()); // 记录已加载的字体
|
||||||
@@ -756,35 +825,46 @@ const loadMoreTemplates = () => {
|
|||||||
getTemplateList(true);
|
getTemplateList(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
onShareAppMessage(async () => {
|
onShareAppMessage(async (options) => {
|
||||||
getShareReward({ scene: "card_generate" });
|
getShareReward({ scene: "card_generate" });
|
||||||
if (!isLoggedIn.value) {
|
if (options.from === "button") {
|
||||||
return {
|
if (!isLoggedIn.value) {
|
||||||
title: "新春祝福",
|
return {
|
||||||
path: "/pages/index/index",
|
title: "新春祝福",
|
||||||
};
|
path: "/pages/index/index",
|
||||||
}
|
};
|
||||||
// 1. 确保有 cardId (如果内容有变动,最好是新建)
|
}
|
||||||
const id = createCard();
|
// 1. 确保有 cardId (如果内容有变动,最好是新建)
|
||||||
if (!id) {
|
const id = createCard();
|
||||||
return {
|
if (!id) {
|
||||||
title: "新春祝福",
|
return {
|
||||||
path: "/pages/index/index",
|
title: "新春祝福",
|
||||||
};
|
path: "/pages/index/index",
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const deviceInfo = getDeviceInfo();
|
const deviceInfo = getDeviceInfo();
|
||||||
const shareTokenRes = await createShareToken({
|
const shareTokenRes = await createShareToken({
|
||||||
scene: "card_generate",
|
scene: "card_generate",
|
||||||
targetId: id,
|
targetId: id,
|
||||||
...deviceInfo,
|
...deviceInfo,
|
||||||
});
|
});
|
||||||
shareOrSave(id);
|
shareOrSave(id);
|
||||||
return {
|
return {
|
||||||
title: "我刚做了一张祝福卡片,送给你",
|
title: "我刚做了一张祝福卡片,送给你",
|
||||||
path: "/pages/detail/index?shareToken=" + shareTokenRes.shareToken,
|
path: "/pages/detail/index?shareToken=" + shareTokenRes.shareToken,
|
||||||
imageUrl: "/static/images/share.jpg",
|
imageUrl:
|
||||||
};
|
"https://file.lihailezzc.com/resource/13ec1134e6614feadeeaaa9ef21ea96e.png",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const shareTokenRes = await getShareToken("card_generate_index", "");
|
||||||
|
return {
|
||||||
|
title: "新春祝福",
|
||||||
|
path: `/pages/index/index?shareToken=${shareTokenRes.shareToken}`,
|
||||||
|
imageUrl:
|
||||||
|
"https://file.lihailezzc.com/resource/cfed2edbfa19250b836a87a4bbf0d5ad.png",
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayedGreetings = ref([]);
|
const displayedGreetings = ref([]);
|
||||||
@@ -838,6 +918,7 @@ const selectTitle = (title) => {
|
|||||||
currentTitle.value = null;
|
currentTitle.value = null;
|
||||||
} else {
|
} else {
|
||||||
currentTitle.value = title;
|
currentTitle.value = title;
|
||||||
|
|
||||||
// 切换标题时重置位置和缩放
|
// 切换标题时重置位置和缩放
|
||||||
titleState.value = {
|
titleState.value = {
|
||||||
offsetX: 0,
|
offsetX: 0,
|
||||||
@@ -912,6 +993,7 @@ const shareOrSave = async (id) => {
|
|||||||
blessingTo: targetName.value,
|
blessingTo: targetName.value,
|
||||||
blessingFrom: signatureName.value,
|
blessingFrom: signatureName.value,
|
||||||
templateId: currentTemplate.value?.id || "",
|
templateId: currentTemplate.value?.id || "",
|
||||||
|
titleId: currentTitle?.value?.id || "",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -957,69 +1039,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 titleY = r2p(40) + r2p(titleState.value.offsetY);
|
|
||||||
|
|
||||||
ctx.drawImage(titleImg, titleX, titleY, drawWidth, drawHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4️⃣ 祝福语气泡
|
// 计算绘制起点:居中 + 偏移量
|
||||||
// 预览中 .bubble 有 padding: 40rpx,且 .card-overlay 有 padding: 30rpx
|
const titleX = (W - drawWidth) / 2 + r2p(titleState.value.offsetX);
|
||||||
// 意味着文字距离容器边缘至少有 70rpx
|
const titleY = r2p(40) + r2p(titleState.value.offsetY);
|
||||||
drawBubbleText(ctx, {
|
|
||||||
text: targetName.value + "\n " + blessingText.value.content,
|
|
||||||
x: 0,
|
|
||||||
y: r2p(230 + bubbleOffsetY.value),
|
|
||||||
maxWidth: r2p(bubbleMaxWidth.value), // 预览中 bubble-text 的宽度
|
|
||||||
canvasWidth: W,
|
|
||||||
fontSize: r2p(fontSize.value),
|
|
||||||
lineHeight: r2p(fontSize.value * 1.6), // 预览中是 1.6
|
|
||||||
padding: r2p(40 + 30), // 内部 padding 40 + 容器 padding 30
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
textColor: selectedColor.value,
|
|
||||||
fontFamily: selectedFont.value.family,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 5️⃣ 用户信息
|
ctx.drawImage(titleImg, titleX, titleY, drawWidth, drawHeight);
|
||||||
// 预览中 user 是 absolute, left: 160 + offsetX, bottom: 40 - offsetY
|
}
|
||||||
drawUserBubble(ctx, {
|
|
||||||
x: r2p(160 + userOffsetX.value),
|
// 4️⃣ 祝福语气泡
|
||||||
bottom: r2p(40 - userOffsetY.value),
|
// 预览中 .bubble 有 padding: 40rpx,且 .card-overlay 有 padding: 30rpx
|
||||||
canvasHeight: H,
|
// 意味着文字距离容器边缘至少有 70rpx
|
||||||
avatarImg: avatarImg,
|
drawBubbleText(ctx, {
|
||||||
username: signatureName.value,
|
text: targetName.value + "\n " + blessingText.value.content,
|
||||||
desc: "送上祝福",
|
x: 0,
|
||||||
textColor: signatureColor.value,
|
y: r2p(230 + bubbleOffsetY.value),
|
||||||
avatarSize: r2p(64),
|
maxWidth: r2p(bubbleMaxWidth.value), // 预览中 bubble-text 的宽度
|
||||||
padding: r2p(15),
|
canvasWidth: W,
|
||||||
fontSizeName: r2p(24),
|
fontSize: r2p(fontSize.value),
|
||||||
fontSizeDesc: r2p(20),
|
lineHeight: r2p(fontSize.value * 1.6), // 预览中是 1.6
|
||||||
});
|
padding: r2p(40 + 30), // 内部 padding 40 + 容器 padding 30
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
textColor: selectedColor.value,
|
||||||
|
fontFamily: selectedFont.value.family,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 5️⃣ 用户信息
|
||||||
|
// 预览中 user 是 absolute, left: 160 + offsetX, bottom: 40 - offsetY
|
||||||
|
drawUserBubble(ctx, {
|
||||||
|
x: r2p(160 + userOffsetX.value),
|
||||||
|
bottom: r2p(40 - userOffsetY.value),
|
||||||
|
canvasHeight: H,
|
||||||
|
avatarImg: avatarImg,
|
||||||
|
username: signatureName.value,
|
||||||
|
desc: "送上祝福",
|
||||||
|
textColor: signatureColor.value,
|
||||||
|
avatarSize: r2p(64),
|
||||||
|
padding: r2p(15),
|
||||||
|
fontSizeName: r2p(24),
|
||||||
|
fontSizeDesc: r2p(20),
|
||||||
|
});
|
||||||
|
|
||||||
// 6️⃣ 输出
|
// 6️⃣ 输出
|
||||||
uni.canvasToTempFilePath({
|
uni.canvasToTempFilePath({
|
||||||
@@ -1209,11 +1293,11 @@ function drawUserBubble(ctx, options) {
|
|||||||
const textX = avatarX + avatarSize + padding;
|
const textX = avatarX + avatarSize + padding;
|
||||||
const totalTextHeight = fontSizeName + fontSizeDesc + 4;
|
const totalTextHeight = fontSizeName + fontSizeDesc + 4;
|
||||||
const textStartY = drawY + (bubbleHeight - totalTextHeight) / 2;
|
const textStartY = drawY + (bubbleHeight - totalTextHeight) / 2;
|
||||||
|
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
ctx.font = `${fontSizeName}px 'PingFang SC'`;
|
ctx.font = `${fontSizeName}px 'PingFang SC'`;
|
||||||
ctx.fillText(username, textX, textStartY);
|
ctx.fillText(username, textX, textStartY);
|
||||||
|
|
||||||
ctx.font = `${fontSizeDesc}px 'PingFang SC'`;
|
ctx.font = `${fontSizeDesc}px 'PingFang SC'`;
|
||||||
ctx.globalAlpha = 0.6;
|
ctx.globalAlpha = 0.6;
|
||||||
ctx.fillText(desc, textX, textStartY + fontSizeName + 4);
|
ctx.fillText(desc, textX, textStartY + fontSizeName + 4);
|
||||||
@@ -1670,7 +1754,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 +1867,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 {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="avatar-page" >
|
<view class="avatar-page">
|
||||||
<!-- Navbar -->
|
<!-- Navbar -->
|
||||||
<NavBar title="我的头像制作" />
|
<NavBar title="我的头像制作" />
|
||||||
|
|
||||||
@@ -57,9 +57,9 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="item-info">
|
<view class="item-info">
|
||||||
<text class="item-name">{{
|
<!-- <text class="item-name">{{
|
||||||
item.decorName || getDefaultName(item)
|
item.decorName || getDefaultName(item)
|
||||||
}}</text>
|
}}</text> -->
|
||||||
<text class="item-date">{{ formatDate(item.createdAt) }} 制作</text>
|
<text class="item-date">{{ formatDate(item.createdAt) }} 制作</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="greeting-page" >
|
<view class="greeting-page">
|
||||||
<NavBar title="我的祝福" />
|
<NavBar title="我的新春祝福" background="transparent" />
|
||||||
|
|
||||||
<!-- Header Stats -->
|
<!-- Header Stats -->
|
||||||
<view class="header-stats">
|
<view class="header-stats">
|
||||||
<view class="stats-card">
|
<view class="stats-card">
|
||||||
<view class="stats-left">
|
<view class="stats-left">
|
||||||
<view class="icon-circle">
|
<view class="icon-circle">
|
||||||
<text>✨</text>
|
<text class="sparkle-emoji">✨</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="stats-info">
|
<view class="stats-info">
|
||||||
<text class="label">已累计创作</text>
|
<text class="label">已累计创作</text>
|
||||||
@@ -28,69 +28,66 @@
|
|||||||
<!-- List Section -->
|
<!-- List Section -->
|
||||||
<view class="list-section">
|
<view class="list-section">
|
||||||
<view class="section-header">
|
<view class="section-header">
|
||||||
<text class="section-title">祝福列表</text>
|
<text class="section-title">祝福库</text>
|
||||||
<text class="section-tip">左滑删除记录</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="list-container">
|
<view class="list-grid">
|
||||||
<view v-for="item in list" :key="item.id" class="list-item-wrap">
|
<view
|
||||||
<view class="swipe-container">
|
v-for="item in list"
|
||||||
<!-- Delete Action (Behind) -->
|
:key="item.id"
|
||||||
<view class="delete-action" @tap.stop="onDelete(item)">
|
class="card-item"
|
||||||
<text>删除</text>
|
@tap="onPreview(item)"
|
||||||
|
>
|
||||||
|
<view class="card-image-wrap">
|
||||||
|
<image :src="item.imageUrl" mode="aspectFill" class="card-img" />
|
||||||
|
<view class="year-badge" v-if="item.year">{{ item.year }}</view>
|
||||||
|
<view class="draft-overlay" v-if="item.status === 'draft'">
|
||||||
|
<text class="lock-icon">🔒</text>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<!-- Card Content (Front) -->
|
<view class="card-info">
|
||||||
<view
|
<view class="card-title">{{ getTitle(item) }}</view>
|
||||||
class="card-item"
|
<view class="card-date">{{ formatDate(item.updatedAt) }}</view>
|
||||||
:style="{
|
<view class="card-footer">
|
||||||
transform: `translateX(${item.translateX || 0}px)`,
|
<view class="tag" :class="getTagClass(item)">{{
|
||||||
transition: item.useTransition ? 'transform 0.3s' : 'none',
|
getTagText(item)
|
||||||
}"
|
}}</view>
|
||||||
@touchstart="onTouchStart($event, item)"
|
<view class="actions">
|
||||||
@touchmove="onTouchMove($event, item)"
|
<button
|
||||||
@touchend="onTouchEnd($event, item)"
|
class="action-btn"
|
||||||
>
|
open-type="share"
|
||||||
<image :src="item.imageUrl" mode="aspectFill" class="card-img" />
|
:data-item="item"
|
||||||
<view class="card-content">
|
@tap.stop
|
||||||
<view class="card-title"
|
|
||||||
>{{ item.blessingTo
|
|
||||||
}}{{
|
|
||||||
item.blessingFrom ? item.blessingFrom : "好友"
|
|
||||||
}}身体健康</view
|
|
||||||
>
|
>
|
||||||
<view class="card-date"
|
<text class="action-emoji">🔗</text>
|
||||||
>更新时间:{{ formatDate(item.updatedAt) }}</view
|
</button>
|
||||||
>
|
<!-- <view class="action-btn" @tap.stop="onMore(item)">
|
||||||
<view class="tags">
|
<text class="action-emoji">⋯</text>
|
||||||
<view class="tag yellow" v-if="item.festival">{{
|
</view> -->
|
||||||
item.festival
|
|
||||||
}}</view>
|
|
||||||
<view class="tag red" v-if="item.year">{{ item.year }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-actions">
|
|
||||||
<view class="action-btn" @tap.stop="onShare(item)">
|
|
||||||
<text class="icon">🔗</text>
|
|
||||||
</view>
|
|
||||||
<view class="action-btn" @tap.stop="onEdit(item)">
|
|
||||||
<text class="icon">✎</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<view class="loading-state" v-if="loading">
|
<view class="loading-state" v-if="loading">
|
||||||
<text>加载中...</text>
|
<text>加载中...</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="empty-state" v-if="!loading && list.length === 0">
|
<view class="empty-state" v-if="!loading && list.length === 0">
|
||||||
<text>暂无祝福记录</text>
|
<text>暂无祝福记录</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="no-more" v-if="!loading && !hasMore && list.length > 0">
|
|
||||||
<text>没有更多了</text>
|
<view class="footer-note" v-if="!loading && list.length > 0">
|
||||||
</view>
|
<text>2026 丙午马年 · 祝福管理助手</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- FAB -->
|
||||||
|
<view class="fab-btn" @tap="onMake">
|
||||||
|
<view class="fab-content">
|
||||||
|
<text class="fab-emoji">✍️</text>
|
||||||
|
<text>新春制作</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -98,96 +95,56 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
|
import {
|
||||||
|
onPullDownRefresh,
|
||||||
|
onReachBottom,
|
||||||
|
onShareAppMessage,
|
||||||
|
} from "@dcloudio/uni-app";
|
||||||
import { getMyCard } from "@/api/mine.js";
|
import { getMyCard } from "@/api/mine.js";
|
||||||
import NavBar from "@/components/NavBar/NavBar.vue";
|
import NavBar from "@/components/NavBar/NavBar.vue";
|
||||||
|
import { getShareToken } from "@/utils/common.js";
|
||||||
|
|
||||||
const navBarTop = ref(0);
|
|
||||||
const navBarHeight = ref(44);
|
|
||||||
const list = ref([]);
|
const list = ref([]);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const hasMore = ref(true);
|
const hasMore = ref(true);
|
||||||
const isRefreshing = ref(false);
|
|
||||||
const totalCount = ref(0);
|
const totalCount = ref(0);
|
||||||
|
|
||||||
const deleteOptions = ref([
|
|
||||||
{
|
|
||||||
text: "删除",
|
|
||||||
style: {
|
|
||||||
backgroundColor: "#ff3b30",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Swipe Logic
|
|
||||||
const startX = ref(0);
|
|
||||||
const activeItem = ref(null);
|
|
||||||
const MAX_SWIPE_WIDTH = 80;
|
|
||||||
|
|
||||||
const onTouchStart = (e, item) => {
|
|
||||||
if (e.touches.length > 1) return;
|
|
||||||
// Close other items
|
|
||||||
if (activeItem.value && activeItem.value.id !== item.id) {
|
|
||||||
activeItem.value.translateX = 0;
|
|
||||||
activeItem.value.useTransition = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
startX.value = e.touches[0].clientX;
|
|
||||||
item.useTransition = false;
|
|
||||||
activeItem.value = item;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTouchMove = (e, item) => {
|
|
||||||
if (e.touches.length > 1) return;
|
|
||||||
const currentX = e.touches[0].clientX;
|
|
||||||
const deltaX = currentX - startX.value;
|
|
||||||
|
|
||||||
// Allow swiping left (negative) up to -MAX_SWIPE_WIDTH
|
|
||||||
// If already open (translateX = -80), deltaX needs to be adjusted
|
|
||||||
// But simpler: just use delta from 0 position.
|
|
||||||
// Actually, standard swipe logic needs to account for current position.
|
|
||||||
// For simplicity: assume always starting from 0 (closed) or -80 (open).
|
|
||||||
// But if we start drag from open state, we need to handle it.
|
|
||||||
|
|
||||||
// Let's stick to "start from 0" logic for now, assuming auto-close.
|
|
||||||
// If item is already open, and we swipe right, we close it.
|
|
||||||
|
|
||||||
// Re-calculate based on initial offset if we want to support dragging from open.
|
|
||||||
// For now: simple close-on-touch-other logic covers most cases.
|
|
||||||
// We assume startX is from a state where it is either 0 or -80.
|
|
||||||
// But `item.translateX` might be -80.
|
|
||||||
|
|
||||||
let targetX = deltaX;
|
|
||||||
if (item.translateX === -MAX_SWIPE_WIDTH) {
|
|
||||||
targetX = -MAX_SWIPE_WIDTH + deltaX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetX < -MAX_SWIPE_WIDTH) targetX = -MAX_SWIPE_WIDTH;
|
|
||||||
if (targetX > 0) targetX = 0;
|
|
||||||
|
|
||||||
item.translateX = targetX;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTouchEnd = (e, item) => {
|
|
||||||
item.useTransition = true;
|
|
||||||
if (item.translateX < -30) {
|
|
||||||
item.translateX = -MAX_SWIPE_WIDTH;
|
|
||||||
} else {
|
|
||||||
item.translateX = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchList(true);
|
fetchList(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
onPullDownRefresh(() => {
|
onPullDownRefresh(() => {
|
||||||
onRefresh();
|
fetchList(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
onReachBottom(() => {
|
onReachBottom(() => {
|
||||||
loadMore();
|
if (hasMore.value && !loading.value) {
|
||||||
|
fetchList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onShareAppMessage(async (options) => {
|
||||||
|
if (options.from === "button") {
|
||||||
|
const shareTokenRes = await getShareToken(
|
||||||
|
"card_generate",
|
||||||
|
options?.target?.dataset?.item?.id,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
title: "我刚做了一张祝福卡片,送给你",
|
||||||
|
path: "/pages/detail/index?shareToken=" + shareTokenRes.shareToken,
|
||||||
|
imageUrl:
|
||||||
|
"https://file.lihailezzc.com/resource/13ec1134e6614feadeeaaa9ef21ea96e.png",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const shareTokenRes = await getShareToken("greeting_page", "");
|
||||||
|
return {
|
||||||
|
title: "新春祝福",
|
||||||
|
path: `/pages/index/index?shareToken=${shareTokenRes.shareToken}`,
|
||||||
|
imageUrl:
|
||||||
|
"https://file.lihailezzc.com/resource/cfed2edbfa19250b836a87a4bbf0d5ad.png",
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchList = async (reset = false) => {
|
const fetchList = async (reset = false) => {
|
||||||
@@ -216,27 +173,12 @@ const fetchList = async (reset = false) => {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to fetch greeting list", e);
|
console.error("Failed to fetch greeting list", e);
|
||||||
uni.showToast({ title: "加载失败", icon: "none" });
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
isRefreshing.value = false;
|
|
||||||
uni.stopPullDownRefresh();
|
uni.stopPullDownRefresh();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMore = () => {
|
|
||||||
fetchList();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onRefresh = () => {
|
|
||||||
isRefreshing.value = true;
|
|
||||||
fetchList(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const goBack = () => {
|
|
||||||
uni.navigateBack();
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatDate = (dateStr) => {
|
const formatDate = (dateStr) => {
|
||||||
if (!dateStr) return "";
|
if (!dateStr) return "";
|
||||||
const date = new Date(dateStr);
|
const date = new Date(dateStr);
|
||||||
@@ -246,75 +188,115 @@ const formatDate = (dateStr) => {
|
|||||||
return `${y}-${m}-${d}`;
|
return `${y}-${m}-${d}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getTagText = (item) => {
|
||||||
|
// if (item.status === "draft") return "草稿";
|
||||||
|
return item?.title?.name || item.festival || "新春快乐";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTitle = (item) => {
|
||||||
|
const title =
|
||||||
|
(item?.blessingTo || "祝您") + (item?.content?.content || "新春快乐");
|
||||||
|
return title.length > 10 ? title.substring(0, 10) + "..." : title;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTagClass = (item) => {
|
||||||
|
if (item.status === "draft") return "tag-draft";
|
||||||
|
const tagMap = {
|
||||||
|
万事如意: "tag-spring",
|
||||||
|
新春快乐: "tag-gold",
|
||||||
|
新春大吉: "tag-horse",
|
||||||
|
钱包鼓鼓: "tag-ink",
|
||||||
|
福气旺旺: "tag-spring",
|
||||||
|
龙马精神: "tag-horse",
|
||||||
|
马年纳祥: "tag-horse",
|
||||||
|
福马迎春: "tag-horse",
|
||||||
|
};
|
||||||
|
return tagMap[item?.title?.name || item.festival] || "tag-gold";
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPreview = (item) => {
|
||||||
|
if (!item.imageUrl) return;
|
||||||
|
uni.previewImage({
|
||||||
|
urls: [item.imageUrl],
|
||||||
|
current: item.imageUrl,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMake = () => {
|
||||||
|
uni.switchTab({
|
||||||
|
url: "/pages/make/index",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// const onShare = (item) => {
|
||||||
|
// uni.showToast({ title: "分享功能开发中", icon: "none" });
|
||||||
|
// };
|
||||||
|
|
||||||
|
const onMore = (item) => {
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: ["编辑", "删除"],
|
||||||
|
success: (res) => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
// Edit
|
||||||
|
} else if (res.tapIndex === 1) {
|
||||||
|
onDelete(item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const onDelete = (item) => {
|
const onDelete = (item) => {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: "提示",
|
title: "提示",
|
||||||
content: "确定要删除这条祝福吗?",
|
content: "确定要删除这条祝福吗?",
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
// Implement delete API call here
|
|
||||||
// For now just remove from list locally
|
|
||||||
list.value = list.value.filter((i) => i.id !== item.id);
|
list.value = list.value.filter((i) => i.id !== item.id);
|
||||||
totalCount.value = Math.max(0, totalCount.value - 1);
|
totalCount.value = Math.max(0, totalCount.value - 1);
|
||||||
uni.showToast({ title: "删除成功", icon: "none" });
|
uni.showToast({ title: "删除成功", icon: "none" });
|
||||||
} else {
|
|
||||||
// Reset swipe state if cancelled
|
|
||||||
item.translateX = 0;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onShare = (item) => {
|
|
||||||
// Implement share logic
|
|
||||||
uni.showToast({ title: "分享功能开发中", icon: "none" });
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEdit = (item) => {
|
|
||||||
// Implement edit logic
|
|
||||||
uni.showToast({ title: "编辑功能开发中", icon: "none" });
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.greeting-page {
|
.greeting-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f9f9f9;
|
background: #fbf9f2;
|
||||||
display: flex;
|
padding-bottom: 120rpx;
|
||||||
flex-direction: column;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-stats {
|
.header-stats {
|
||||||
padding: 20px;
|
padding: 30rpx 40rpx;
|
||||||
background: #f9f9f9;
|
margin-top: 20rpx;
|
||||||
margin-top: 44px; // Initial offset for fixed nav
|
|
||||||
|
|
||||||
.stats-card {
|
.stats-card {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 20px;
|
border-radius: 40rpx;
|
||||||
padding: 24px;
|
padding: 40rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.02);
|
||||||
|
|
||||||
.stats-left {
|
.stats-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.icon-circle {
|
.icon-circle {
|
||||||
width: 48px;
|
width: 100rpx;
|
||||||
height: 48px;
|
height: 100rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #fff0f0;
|
background: #fff5f5;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-right: 16px;
|
margin-right: 24rpx;
|
||||||
|
|
||||||
text {
|
.sparkle-emoji {
|
||||||
font-size: 24px;
|
font-size: 50rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,9 +305,9 @@ const onEdit = (item) => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-size: 12px;
|
font-size: 24rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.value-wrap {
|
.value-wrap {
|
||||||
@@ -333,14 +315,14 @@ const onEdit = (item) => {
|
|||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
font-size: 24px;
|
font-size: 40rpx;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #333;
|
color: #333;
|
||||||
margin-right: 4px;
|
margin-right: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unit {
|
.unit {
|
||||||
font-size: 12px;
|
font-size: 24rpx;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,30 +330,29 @@ const onEdit = (item) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
width: 1px;
|
width: 1rpx;
|
||||||
height: 40px;
|
height: 80rpx;
|
||||||
background: #eee;
|
background: #f0f0f0;
|
||||||
margin: 0 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-right {
|
.stats-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 80px;
|
padding-left: 20rpx;
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
font-size: 12px;
|
font-size: 24rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 12rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
font-size: 16px;
|
font-size: 32rpx;
|
||||||
font-weight: 600;
|
font-weight: bold;
|
||||||
|
|
||||||
&.red-text {
|
&.red-text {
|
||||||
color: #ff3b30;
|
color: #ff4d4f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,89 +360,86 @@ const onEdit = (item) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-section {
|
.list-section {
|
||||||
flex: 1;
|
padding: 0 40rpx;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 0 20px;
|
|
||||||
|
|
||||||
.section-header {
|
.section-header {
|
||||||
display: flex;
|
margin: 40rpx 0 24rpx;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: 16px;
|
font-size: 32rpx;
|
||||||
font-weight: 600;
|
font-weight: bold;
|
||||||
color: #666;
|
color: #7c6d5d;
|
||||||
}
|
|
||||||
|
|
||||||
.section-tip {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-container {
|
.list-grid {
|
||||||
padding-bottom: 40px;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 30rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-item-wrap {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border-radius: 16px;
|
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
|
|
||||||
}
|
|
||||||
|
|
||||||
.swipe-container {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
background: #ff3b30; // Delete background color
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-action {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 80px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background-color: #ff3b30;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 14px;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-item {
|
.card-item {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 16px;
|
border-radius: 48rpx;
|
||||||
display: flex;
|
overflow: hidden;
|
||||||
align-items: center;
|
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.03);
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.card-img {
|
.card-image-wrap {
|
||||||
width: 80px;
|
position: relative;
|
||||||
height: 80px;
|
width: 100%;
|
||||||
border-radius: 12px;
|
padding-bottom: 133%; // 3:4 aspect ratio
|
||||||
margin-right: 16px;
|
background: #fdf3e7;
|
||||||
background: #f5f5f5;
|
|
||||||
|
.card-img {
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
left: 20rpx;
|
||||||
|
right: 20rpx;
|
||||||
|
bottom: 20rpx;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
left: 20rpx;
|
||||||
|
background: #ff4d4f;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 20rpx;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draft-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 40rpx;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-content {
|
.card-info {
|
||||||
flex: 1;
|
padding: 24rpx;
|
||||||
margin-right: 12px;
|
|
||||||
|
|
||||||
.card-title {
|
.card-title {
|
||||||
font-size: 16px;
|
font-size: 28rpx;
|
||||||
font-weight: 600;
|
font-weight: bold;
|
||||||
color: #333;
|
color: #333;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8rpx;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-webkit-line-clamp: 1;
|
-webkit-line-clamp: 1;
|
||||||
@@ -469,68 +447,117 @@ const onEdit = (item) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card-date {
|
.card-date {
|
||||||
font-size: 12px;
|
font-size: 22rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags {
|
.card-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
font-size: 10px;
|
font-size: 20rpx;
|
||||||
padding: 2px 8px;
|
padding: 4rpx 16rpx;
|
||||||
border-radius: 8px;
|
border-radius: 20rpx;
|
||||||
|
|
||||||
&.yellow {
|
&.tag-gold {
|
||||||
background: #fff8e1;
|
background: #fff8e6;
|
||||||
color: #ffb300;
|
color: #ffb800;
|
||||||
}
|
}
|
||||||
|
&.tag-horse {
|
||||||
&.red {
|
background: #fff1f0;
|
||||||
background: #ffebee;
|
color: #ff4d4f;
|
||||||
color: #ff3b30;
|
|
||||||
}
|
}
|
||||||
|
&.tag-ink {
|
||||||
|
background: #f0f5ff;
|
||||||
|
color: #2f54eb;
|
||||||
|
}
|
||||||
|
&.tag-draft {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #bfbfbf;
|
||||||
|
}
|
||||||
|
&.tag-spring {
|
||||||
|
background: #fff1f0;
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.blue {
|
.actions {
|
||||||
background: #e3f2fd;
|
display: flex;
|
||||||
color: #2196f3;
|
gap: 16rpx;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
outline: none;
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-emoji {
|
||||||
|
font-size: 32rpx;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.card-actions {
|
.fab-btn {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 60rpx;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
.fab-content {
|
||||||
|
background: #ff4d4f;
|
||||||
|
padding: 20rpx 48rpx;
|
||||||
|
border-radius: 100rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
gap: 16px;
|
box-shadow: 0 10rpx 30rpx rgba(255, 77, 79, 0.3);
|
||||||
|
|
||||||
.action-btn {
|
.fab-emoji {
|
||||||
width: 32px;
|
font-size: 36rpx;
|
||||||
height: 32px;
|
margin-right: 12rpx;
|
||||||
display: flex;
|
}
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.icon {
|
text {
|
||||||
font-size: 20px;
|
color: #fff;
|
||||||
color: #666;
|
font-size: 32rpx;
|
||||||
}
|
font-weight: bold;
|
||||||
|
|
||||||
&:active {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.9;
|
||||||
|
transform: translateX(-50%) scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-note {
|
||||||
|
text-align: center;
|
||||||
|
padding: 60rpx 0 40rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-state,
|
.loading-state,
|
||||||
.empty-state,
|
.empty-state {
|
||||||
.no-more {
|
grid-column: span 2;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 20px;
|
padding: 100rpx 0;
|
||||||
color: #999;
|
color: #999;
|
||||||
font-size: 12px;
|
font-size: 28rpx;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -136,9 +136,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import {
|
import { onShareAppMessage } from "@dcloudio/uni-app";
|
||||||
onShareAppMessage,
|
|
||||||
} from "@dcloudio/uni-app";
|
|
||||||
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@@ -155,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);
|
||||||
@@ -166,11 +165,11 @@ onMounted(() => {
|
|||||||
navBarHeight.value = 44;
|
navBarHeight.value = 44;
|
||||||
});
|
});
|
||||||
|
|
||||||
onShareAppMessage( () => {
|
onShareAppMessage(() => {
|
||||||
return {
|
return {
|
||||||
title: "新年好运已送达 🎊|祝福卡·头像·壁纸",
|
title: "新年好运已送达 🎊|祝福卡·头像·壁纸",
|
||||||
path: "/pages/index/index",
|
path: "/pages/index/index",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleUserClick = () => {
|
const handleUserClick = () => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="vip-page" >
|
<view class="vip-page">
|
||||||
<NavBar title="会员中心" />
|
<NavBar title="会员中心" />
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
@@ -120,10 +120,20 @@ const selectedPlanIndex = ref(1);
|
|||||||
const plans = ref([]);
|
const plans = ref([]);
|
||||||
|
|
||||||
const benefits = [
|
const benefits = [
|
||||||
{ name: "高级模板", icon: "star-filled", color: "#ff3b30", bg: "#fff0f0" },
|
{ name: "纯净无广", icon: "star-filled", color: "#ff3b30", bg: "#fff0f0" },
|
||||||
{ name: "无限制下载", icon: "image-filled", color: "#ff6b00", bg: "#fff7e6" },
|
{ name: "多次下载", icon: "image-filled", color: "#ff6b00", bg: "#fff7e6" },
|
||||||
{ name: "马年头像框", icon: "medal-filled", color: "#bfa46f", bg: "#fffbe6" },
|
{
|
||||||
{ name: "高速渲染", icon: "upload-filled", color: "#ff3b30", bg: "#fff0f0" },
|
name: "会员精选头像",
|
||||||
|
icon: "medal-filled",
|
||||||
|
color: "#bfa46f",
|
||||||
|
bg: "#fffbe6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "会员精选模版",
|
||||||
|
icon: "upload-filled",
|
||||||
|
color: "#ff3b30",
|
||||||
|
bg: "#fff0f0",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "数据永久保存",
|
name: "数据永久保存",
|
||||||
icon: "paperplane-filled",
|
icon: "paperplane-filled",
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view
|
<view class="wallpaper-page">
|
||||||
class="wallpaper-page"
|
<NavBar title="新春精美壁纸" />
|
||||||
>
|
|
||||||
<NavBar title="精美壁纸" />
|
|
||||||
|
|
||||||
<!-- Category Tabs -->
|
<!-- Category Tabs -->
|
||||||
<view class="category-tabs">
|
<view class="category-tabs">
|
||||||
@@ -37,18 +35,12 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
:src="getThumbUrl(item.imageUrl)"
|
:src="getThumbUrl(item.imageUrl)"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
class="wallpaper-img"
|
class="wallpaper-img"
|
||||||
@tap="previewImage(index)"
|
@tap="previewImage(index)"
|
||||||
/>
|
/>
|
||||||
<view class="action-overlay">
|
<view class="action-overlay">
|
||||||
<view
|
|
||||||
class="action-btn download"
|
|
||||||
@tap.stop="downloadWallpaper(item)"
|
|
||||||
>
|
|
||||||
<text class="icon">↓</text>
|
|
||||||
</view>
|
|
||||||
<button
|
<button
|
||||||
class="action-btn share"
|
class="action-btn share"
|
||||||
open-type="share"
|
open-type="share"
|
||||||
@@ -57,6 +49,12 @@
|
|||||||
>
|
>
|
||||||
<text class="icon">➦</text>
|
<text class="icon">➦</text>
|
||||||
</button>
|
</button>
|
||||||
|
<view
|
||||||
|
class="action-btn download"
|
||||||
|
@tap.stop="downloadWallpaper(item)"
|
||||||
|
>
|
||||||
|
<text class="icon">↓</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -82,7 +80,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from "vue";
|
import { ref, onMounted, computed } from "vue";
|
||||||
import { getBavBarHeight } from "@/utils/system";
|
|
||||||
import { getWallpaperList, getWallpaperCategoryList } from "@/api/wallpaper.js";
|
import { getWallpaperList, getWallpaperCategoryList } from "@/api/wallpaper.js";
|
||||||
import {
|
import {
|
||||||
saveRemoteImageToLocal,
|
saveRemoteImageToLocal,
|
||||||
@@ -122,6 +119,8 @@ onShareAppMessage(async (options) => {
|
|||||||
return {
|
return {
|
||||||
title: "新春祝福",
|
title: "新春祝福",
|
||||||
path: `/pages/index/index?shareToken=${shareTokenRes.shareToken}`,
|
path: `/pages/index/index?shareToken=${shareTokenRes.shareToken}`,
|
||||||
|
imageUrl:
|
||||||
|
"https://file.lihailezzc.com/resource/cfed2edbfa19250b836a87a4bbf0d5ad.png",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -131,7 +130,7 @@ onMounted(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const getThumbUrl = (url) => {
|
const getThumbUrl = (url) => {
|
||||||
return `${url}?imageView2/1/w/340/h/600/q/80`;
|
return `${url}?imageView2/1/w/340/h/600/q/80`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchCategories = async () => {
|
const fetchCategories = async () => {
|
||||||
@@ -245,46 +244,21 @@ const shareWallpaper = (item) => {};
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.wallpaper-page {
|
.wallpaper-page {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background-color: #7a0909; /* Dark Red Background */
|
background-color: #ffffff;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-bar {
|
.category-tabs {
|
||||||
display: flex;
|
padding: 0;
|
||||||
align-items: center;
|
background-color: #ffffff;
|
||||||
padding: 16rpx 24rpx;
|
border-bottom: 1rpx solid #eeeeee;
|
||||||
/* background: #7A0909; */
|
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back {
|
|
||||||
font-size: 50rpx;
|
|
||||||
margin-right: 24rpx;
|
|
||||||
line-height: 1;
|
|
||||||
color: #ffd700; /* Gold */
|
|
||||||
/* 增大点击区域 */
|
|
||||||
padding: 20rpx;
|
|
||||||
margin-left: -20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-title {
|
|
||||||
font-size: 34rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #ffd700; /* Gold */
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
margin-right: 50rpx; /* Balance back button */
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-tabs {
|
|
||||||
padding: 20rpx 0;
|
|
||||||
/* background-color: #7A0909; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabs-scroll {
|
.tabs-scroll {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -292,51 +266,54 @@ const shareWallpaper = (item) => {};
|
|||||||
|
|
||||||
.tabs-content {
|
.tabs-content {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
padding: 0 24rpx;
|
padding: 0 30rpx;
|
||||||
gap: 20rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
padding: 12rpx 32rpx;
|
padding: 24rpx 30rpx;
|
||||||
border-radius: 999rpx;
|
font-size: 30rpx;
|
||||||
font-size: 28rpx;
|
color: #999999;
|
||||||
color: #ffd700;
|
position: relative;
|
||||||
background: rgba(0, 0, 0, 0.3);
|
|
||||||
border: 2rpx solid transparent;
|
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item.active {
|
.tab-item.active {
|
||||||
background: linear-gradient(90deg, #ff3b30 0%, #ff9500 100%);
|
color: #e60012;
|
||||||
color: #fff;
|
font-weight: bold;
|
||||||
border-color: #ffd700;
|
|
||||||
font-weight: 600;
|
&::after {
|
||||||
box-shadow: 0 4rpx 12rpx rgba(255, 215, 0, 0.3);
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 80rpx;
|
||||||
|
height: 4rpx;
|
||||||
|
background-color: #e60012;
|
||||||
|
border-radius: 2rpx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wallpaper-scroll {
|
.wallpaper-scroll {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
/* padding: 24rpx; */
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-container {
|
.grid-container {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: repeat(2, 1fr);
|
||||||
padding: 24rpx;
|
gap: 30rpx;
|
||||||
justify-content: space-between;
|
padding: 30rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-item {
|
.grid-item {
|
||||||
width: 340rpx;
|
|
||||||
height: 600rpx;
|
height: 600rpx;
|
||||||
border-radius: 24rpx;
|
border-radius: 32rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-bottom: 24rpx;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.3);
|
background: #f5f5f5;
|
||||||
background: #333;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.wallpaper-img {
|
.wallpaper-img {
|
||||||
@@ -357,22 +334,29 @@ const shareWallpaper = (item) => {};
|
|||||||
width: 64rpx;
|
width: 64rpx;
|
||||||
height: 64rpx;
|
height: 64rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
backdrop-filter: blur(4px);
|
backdrop-filter: blur(4px);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
border: 1rpx solid rgba(255, 255, 255, 0.2);
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.share .icon {
|
||||||
|
font-size: 30rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn .icon {
|
.action-btn .icon {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 32rpx;
|
font-size: 36rpx;
|
||||||
font-weight: bold;
|
font-weight: normal;
|
||||||
}
|
|
||||||
|
|
||||||
.action-btn.share .icon {
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-state,
|
.loading-state,
|
||||||
@@ -380,7 +364,7 @@ const shareWallpaper = (item) => {};
|
|||||||
.no-more {
|
.no-more {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 40rpx;
|
padding: 40rpx;
|
||||||
color: rgba(255, 255, 255, 0.6);
|
color: #999999;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
BIN
static/.DS_Store
vendored
Normal file
BIN
static/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
static/images/.DS_Store
vendored
Normal file
BIN
static/images/.DS_Store
vendored
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB |
@@ -21,8 +21,12 @@ export const uploadImage = (filePath) => {
|
|||||||
if (res.statusCode < 400) {
|
if (res.statusCode < 400) {
|
||||||
try {
|
try {
|
||||||
const keyJson = JSON.parse(res.data);
|
const keyJson = JSON.parse(res.data);
|
||||||
const url = `https://file.lihailezzc.com/${keyJson?.data.key}`;
|
if (keyJson?.data?.result === "auditFailed") {
|
||||||
resolve(url);
|
reject("图片不符合发布规范,请稍作修改后再试");
|
||||||
|
} else {
|
||||||
|
const url = `https://file.lihailezzc.com/${keyJson?.data.key}`;
|
||||||
|
resolve(url);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user