feat: deaw
This commit is contained in:
8
api/fortune.js
Normal file
8
api/fortune.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { request } from "@/utils/request.js";
|
||||||
|
|
||||||
|
export const drawFortune = async () => {
|
||||||
|
return request({
|
||||||
|
url: "/api/blessing/fortune/draw",
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
};
|
||||||
8
api/system.js
Normal file
8
api/system.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { request } from "@/utils/request.js";
|
||||||
|
|
||||||
|
export const abilityCheck = async (scene) => {
|
||||||
|
return request({
|
||||||
|
url: "/api/blessing/ability/check?scene=" + scene,
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -46,29 +46,42 @@
|
|||||||
|
|
||||||
<!-- 结果状态:运势卡片 -->
|
<!-- 结果状态:运势卡片 -->
|
||||||
<view class="state-result" v-else>
|
<view class="state-result" v-else>
|
||||||
<view class="result-card" id="result-card">
|
<view
|
||||||
<view class="card-header">
|
class="result-card"
|
||||||
<text class="year-tag">2026 乙巳年</text>
|
id="result-card"
|
||||||
</view>
|
:class="{ 'image-mode': !!currentFortune.imageUrl }"
|
||||||
<view class="card-body">
|
>
|
||||||
<view class="icon-circle">
|
<template v-if="currentFortune.imageUrl">
|
||||||
<text class="result-icon">☀</text>
|
<image
|
||||||
|
:src="currentFortune.imageUrl"
|
||||||
|
mode="widthFix"
|
||||||
|
class="fortune-image"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<view class="card-header">
|
||||||
|
<text class="year-tag">2026 乙巳年</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="result-title">{{ currentFortune.title }}</text>
|
<view class="card-body">
|
||||||
<view class="divider"></view>
|
<view class="icon-circle">
|
||||||
<text class="result-desc">{{ currentFortune.desc }}</text>
|
<text class="result-icon">☀</text>
|
||||||
<text class="result-sub">旧岁千般皆如意,新年万事定称心。</text>
|
</view>
|
||||||
</view>
|
<text class="result-title">{{ currentFortune.title }}</text>
|
||||||
<view class="card-footer">
|
<view class="divider"></view>
|
||||||
<view class="footer-left">
|
<text class="result-desc">{{ currentFortune.desc }}</text>
|
||||||
<text class="sub-en">LUCKY CHARM</text>
|
<text class="result-sub">旧岁千般皆如意,新年万事定称心。</text>
|
||||||
<text class="sub-cn">每日运势签</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="footer-right">
|
<view class="card-footer">
|
||||||
<text class="scan-tip">长按识别\n扫码祈福</text>
|
<view class="footer-left">
|
||||||
<view class="qr-code"></view>
|
<text class="sub-en">LUCKY CHARM</text>
|
||||||
|
<text class="sub-cn">每日运势签</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-right">
|
||||||
|
<text class="scan-tip">长按识别\n扫码祈福</text>
|
||||||
|
<view class="qr-code"></view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="result-actions">
|
<view class="result-actions">
|
||||||
@@ -102,9 +115,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onUnmounted } from "vue";
|
import { ref, onUnmounted } from "vue";
|
||||||
import { getBavBarHeight } from "@/utils/system";
|
import { getBavBarHeight } from "@/utils/system";
|
||||||
|
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||||
|
import { abilityCheck } from "@/api/system.js";
|
||||||
|
import { drawFortune } from "@/api/fortune.js";
|
||||||
|
|
||||||
const status = ref("initial"); // initial, shaking, result
|
const status = ref("initial"); // initial, shaking, result
|
||||||
const remainingCount = ref(1);
|
const remainingCount = ref(0);
|
||||||
|
const canUse = ref(true);
|
||||||
|
|
||||||
// 音效控制
|
// 音效控制
|
||||||
const audioContext = uni.createInnerAudioContext();
|
const audioContext = uni.createInnerAudioContext();
|
||||||
@@ -118,6 +135,19 @@ audioContext.onEnded(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onLoad(() => {});
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
checkDrawStatus();
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkDrawStatus = async () => {
|
||||||
|
const res = await abilityCheck("fortune_draw");
|
||||||
|
if (res.canUse) {
|
||||||
|
remainingCount.value = res.remain;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
audioContext.destroy();
|
audioContext.destroy();
|
||||||
});
|
});
|
||||||
@@ -140,7 +170,7 @@ const goBack = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const startShake = () => {
|
const startShake = async () => {
|
||||||
if (remainingCount.value <= 0) {
|
if (remainingCount.value <= 0) {
|
||||||
uni.showToast({ title: "今日次数已用完", icon: "none" });
|
uni.showToast({ title: "今日次数已用完", icon: "none" });
|
||||||
return;
|
return;
|
||||||
@@ -153,12 +183,26 @@ const startShake = () => {
|
|||||||
audioContext.play();
|
audioContext.play();
|
||||||
|
|
||||||
// 模拟摇晃动画和数据请求
|
// 模拟摇晃动画和数据请求
|
||||||
setTimeout(() => {
|
const minTime = 2000;
|
||||||
const idx = Math.floor(Math.random() * fortunes.length);
|
const startT = Date.now();
|
||||||
currentFortune.value = fortunes[idx];
|
|
||||||
status.value = "result";
|
try {
|
||||||
remainingCount.value--;
|
const res = await drawFortune();
|
||||||
}, 2000);
|
|
||||||
|
const endT = Date.now();
|
||||||
|
const waitTime = Math.max(0, minTime - (endT - startT));
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
currentFortune.value = res;
|
||||||
|
status.value = "result";
|
||||||
|
remainingCount.value--;
|
||||||
|
}, waitTime);
|
||||||
|
} catch (e) {
|
||||||
|
setTimeout(() => {
|
||||||
|
status.value = "initial";
|
||||||
|
uni.showToast({ title: "网络请求失败", icon: "none" });
|
||||||
|
}, minTime);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
@@ -166,6 +210,36 @@ const reset = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveCard = () => {
|
const saveCard = () => {
|
||||||
|
if (currentFortune.value.imageUrl) {
|
||||||
|
uni.showLoading({ title: "保存中..." });
|
||||||
|
uni.downloadFile({
|
||||||
|
url: currentFortune.value.imageUrl,
|
||||||
|
success: (res) => {
|
||||||
|
if (res.statusCode === 200) {
|
||||||
|
uni.saveImageToPhotosAlbum({
|
||||||
|
filePath: res.tempFilePath,
|
||||||
|
success: () => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({ title: "已保存到相册" });
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({ title: "保存失败", icon: "none" });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({ title: "下载失败", icon: "none" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({ title: "下载失败", icon: "none" });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uni.showLoading({ title: "生成中..." });
|
uni.showLoading({ title: "生成中..." });
|
||||||
|
|
||||||
const ctx = uni.createCanvasContext("shareCanvas");
|
const ctx = uni.createCanvasContext("shareCanvas");
|
||||||
@@ -416,6 +490,16 @@ const saveCard = () => {
|
|||||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
.result-card.image-mode {
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.fortune-image {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
.card-header {
|
.card-header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
|
|||||||
Reference in New Issue
Block a user