qs_xinchun2026_h5/pages/ai-spring/ai-spring.vue

406 lines
8.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="spring-couple-container">
<!-- 背景图 -->
<div class="background">
<img
v-lazy="backgroundImage"
alt="四合院背景"
@error="handleImageError"
/>
</div>
<!-- 春联展示区 -->
<div class="couplet-display" v-if="couplet">
<div class="couplet-item top-couplet">{{ couplet.top }}</div>
<div class="couplet-item bottom-couplet">{{ couplet.bottom }}</div>
<div class="couplet-item横批">{{ couplet.横批 }}</div>
</div>
<!-- 输入区域 -->
<div class="input-section">
<h2 class="title">AI春联生成</h2>
<p class="subtitle">输入两个字的关键词,生成个性化春联</p>
<div class="input-container">
<input
v-model="keyword"
type="text"
placeholder="请输入关键词(如:吉祥、如意)"
maxlength="2"
@input="handleKeywordInput"
class="keyword-input"
/>
<button
@click="generateCouple"
:disabled="loading || keyword.length < 2"
class="generate-btn"
>
<span v-if="loading">生成中...</span>
<span v-else>生成春联</span>
</button>
</div>
<!-- 推荐关键词 -->
<div class="recommended-keywords">
<span
v-for="word in recommendedWords"
:key="word"
@click="selectKeyword(word)"
class="keyword-tag"
>
{{ word }}
</span>
</div>
</div>
<!-- 分享按钮 -->
<div class="share-section" v-if="couplet">
<button @click="shareCouple" class="share-btn">
📤 分享春联
</button>
</div>
<!-- 加载动画 -->
<div v-if="loading" class="loading-overlay">
<uni-spinner type="circle" size="48" color="#fff"></uni-spinner>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { generateSpringCouple } from '../api/ai';
import { share } from '../utils/share';
// 响应式数据
const keyword = ref('');
const couplet = ref(null);
const loading = ref(false);
const backgroundImage = ref('https://placeholder.pics/svg/640x1136/E8F5E9/4CAF50/四合院背景');
// 推荐关键词
const recommendedWords = [
'吉祥', '如意', '幸福', '安康', '财源', '富贵', '团圆', '快乐',
'平安', '健康', '顺利', '成功', '美满', '和谐', '兴旺', '发达'
];
// 处理关键词输入
const handleKeywordInput = () => {
// 限制关键词长度为2个字符
if (keyword.value.length > 2) {
keyword.value = keyword.value.slice(0, 2);
}
};
// 选择推荐关键词
const selectKeyword = (word) => {
keyword.value = word;
generateCouple();
};
// 生成春联
const generateCouple = async () => {
if (!keyword.value || keyword.value.length < 2) {
uni.uni.showToast({title: '请输入两个字的关键词', duration: 2000});
return;
}
loading.value = true;
try {
const result = await generateSpringCouple(keyword.value);
if (result.code === 200) {
couplet.value = result.data;
uni.uni.showToast({title: '春联生成成功', duration: 2000});
// 添加生成动画效果
setTimeout(() => {
const coupletElements = document.querySelectorAll('.couplet-item');
coupletElements.forEach((el, index) => {
el.style.opacity = '0';
el.style.transform = 'translateY(20px)';
setTimeout(() => {
el.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
el.style.opacity = '1';
el.style.transform = 'translateY(0)';
}, index * 200);
});
}, 100);
} else {
uni.uni.showToast({title: '生成失败,请重试', duration: 2000});
}
} catch (error) {
console.error('生成春联失败:', error);
uni.uni.showToast({title: '网络异常,请稍后重试', duration: 2000});
} finally {
loading.value = false;
}
};
// 分享春联
const shareCouple = () => {
if (!couplet.value) {
uni.uni.showToast({title: '请先生成春联', duration: 2000});
return;
}
const shareText = `
我用AI生成了一副春联
${couplet.value.top}
${couplet.value.bottom}
${couplet.value.横批}
#2026新春东城商圈#
`;
// 调用分享工具函数
share({
title: 'AI春联生成',
text: shareText,
image: backgroundImage.value
});
};
// 处理图片加载错误
const handleImageError = (event) => {
event.target.src = 'https://placeholder.pics/svg/640x1136/E8F5E9/4CAF50/四合院背景';
};
</script>
<style scoped>
.spring-couple-container {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
overflow: hidden;
}
.background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
overflow: hidden;
}
.background img {
width: 100%;
height: 100%;
object-fit: cover;
}
.couplet-display {
position: relative;
width: 100%;
max-width: 600px;
margin: 40px 0;
padding: 60px 20px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 1;
}
.couplet-item {
font-family: 'STKaiti', 'Kaiti SC', serif;
font-size: 24px;
font-weight: bold;
color: #e67e22;
text-align: center;
line-height: 1.8;
writing-mode: vertical-rl;
text-orientation: upright;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
opacity: 0;
}
.top-couplet,
.bottom-couplet {
width: 60px;
height: 240px;
display: flex;
align-items: center;
justify-content: center;
}
.横批 {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
writing-mode: horizontal-tb;
font-size: 32px;
width: 200px;
}
.input-section {
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 30px;
width: 100%;
max-width: 500px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
z-index: 2;
margin-top: auto;
}
.title {
font-size: 28px;
color: #e67e22;
margin-bottom: 10px;
text-align: center;
font-weight: bold;
}
.subtitle {
font-size: 16px;
color: #666;
margin-bottom: 25px;
text-align: center;
}
.input-container {
display: flex;
gap: 10px;
margin-bottom: 25px;
}
.keyword-input {
flex: 1;
padding: 15px;
border: 2px solid #ddd;
border-radius: 10px;
font-size: 18px;
text-align: center;
transition: border-color 0.3s ease;
}
.keyword-input:focus {
outline: none;
border-color: #e67e22;
}
.generate-btn {
padding: 15px 25px;
background: linear-gradient(135deg, #e67e22, #d35400);
color: white;
border: none;
border-radius: 10px;
font-size: 18px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.generate-btn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(230, 126, 34, 0.4);
}
.generate-btn:disabled {
background: #ddd;
cursor: not-allowed;
}
.recommended-keywords {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
}
.keyword-tag {
padding: 8px 16px;
background: #f39c12;
color: white;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
}
.keyword-tag:hover {
background: #e67e22;
transform: translateY(-2px);
}
.share-section {
margin-top: 20px;
margin-bottom: 20px;
z-index: 2;
}
.share-btn {
padding: 15px 30px;
background: linear-gradient(135deg, #3498db, #2980b9);
color: white;
border: none;
border-radius: 25px;
font-size: 18px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
}
.share-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.4);
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
/* 响应式设计 */
@media (max-width: 480px) {
.spring-couple-container {
padding: 10px;
}
.couplet-item {
font-size: 20px;
}
.top-couplet,
.bottom-couplet {
height: 200px;
}
.input-section {
padding: 20px;
}
.title {
font-size: 24px;
}
.keyword-input,
.generate-btn {
font-size: 16px;
padding: 12px;
}
.input-container {
flex-direction: column;
}
}
</style>