feat: 小程序页面优化和新增剧本库功能

This commit is contained in:
2026-05-30 20:53:18 +08:00
parent acca1d84f3
commit 094953f1c3
7 changed files with 1672 additions and 996 deletions
+318 -118
View File
@@ -8,6 +8,8 @@
<view class="meteor meteor-one"></view>
<view class="meteor meteor-two"></view>
<view class="meteor meteor-three"></view>
<view class="meteor meteor-four"></view>
<view class="meteor meteor-five"></view>
</view>
<view v-if="viewState === 'home'" class="wish-home">
<view class="home-head">
@@ -19,11 +21,6 @@
</view>
<text>历史</text>
</view>
<view class="head-action-row">
<view class="social-import-btn" @click="openSocialImport">
<text>导入社交数据</text>
</view>
</view>
</view>
<view class="hero-copy">
@@ -73,6 +70,7 @@
<text class="voice-copy">{{ voiceCopy }}</text>
<view class="wish-input-wrap" :class="{ active: homeInputFocused, twoLine: homeInputLevel === 'two', expanded: homeInputLevel === 'multi' }">
<text v-if="!wishText" class="custom-input-placeholder home-input-placeholder">写下你的心愿AI帮你重写人生</text>
<textarea
class="wish-input"
v-model="wishText"
@@ -80,8 +78,6 @@
:show-confirm-bar="false"
confirm-type="send"
maxlength="500"
placeholder="写下你的心愿,AI帮你重写人生"
placeholder-class="placeholder"
@focus="homeInputFocused = true"
@blur="homeInputFocused = false"
@confirm="submitWish('text')"
@@ -246,21 +242,21 @@
>
<text>语音</text>
</view>
<textarea
class="result-chat-input"
:class="{ twoLine: resultInputLevel === 'two', expanded: resultInputLevel === 'multi' }"
v-model="resultChatInput"
:auto-height="resultInputLevel !== 'single'"
:show-confirm-bar="false"
:focus="resultInputFocus"
maxlength="500"
confirm-type="send"
placeholder="继续提修改建议,或确认后重新生成"
placeholder-class="placeholder"
@focus="resultInputFocused = true"
@blur="resultInputFocused = false"
@confirm="sendResultChat('text')"
/>
<view class="result-input-shell" :class="{ twoLine: resultInputLevel === 'two', expanded: resultInputLevel === 'multi' }">
<text v-if="!resultChatInput" class="custom-input-placeholder result-input-placeholder">继续提修改建议或确认后重新生成</text>
<textarea
class="result-chat-input"
v-model="resultChatInput"
:auto-height="resultInputLevel !== 'single'"
:show-confirm-bar="false"
:focus="resultInputFocus"
maxlength="500"
confirm-type="send"
@focus="resultInputFocused = true"
@blur="resultInputFocused = false"
@confirm="sendResultChat('text')"
/>
</view>
<view class="chat-send-btn" :class="{ disabled: !resultChatInput.trim() || resultChatting }" @click="sendResultChat('text')">发送</view>
</view>
</view>
@@ -546,14 +542,7 @@ const normalizeGeneratedScript = (data) => {
const openScriptLibrary = () => {
analytics.track('script_history_click', {}, { eventType: 'script', pagePath })
uni.$emit('switchTab', 'mine')
}
const openSocialImport = () => {
analytics.track('script_social_import_entry_click', {
source: 'home_head'
}, { eventType: 'social_import', pagePath })
uni.navigateTo({ url: '/pages/social-import/index' })
uni.$emit('switchTab', 'library')
}
const useRecommendation = (text) => {
@@ -1244,22 +1233,12 @@ onUnmounted(() => {
.cosmic-background {
position: absolute;
inset: -80rpx -80rpx;
inset: -120rpx -140rpx;
z-index: 0;
pointer-events: none;
overflow: hidden;
}
.cosmic-background::after {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(circle at 50% 22%, rgba(255, 216, 107, 0.06), transparent 30%),
radial-gradient(circle at 72% 6%, rgba(209, 138, 255, 0.11), transparent 24%),
linear-gradient(180deg, rgba(12, 4, 31, 0.1), rgba(5, 2, 13, 0.2));
}
.cosmic-stars {
position: absolute;
inset: 0;
@@ -1293,26 +1272,27 @@ onUnmounted(() => {
}
.planet-main {
top: 118rpx;
right: -52rpx;
width: 188rpx;
height: 188rpx;
opacity: 0.38;
top: 210rpx;
right: -120rpx;
width: 260rpx;
height: 260rpx;
opacity: 0.18;
background:
radial-gradient(circle at 36% 28%, rgba(255, 231, 163, 0.96), rgba(209, 138, 255, 0.7) 36%, rgba(93, 38, 193, 0.78) 68%, rgba(23, 9, 56, 0.9));
box-shadow: 0 0 76rpx rgba(168, 85, 247, 0.32);
radial-gradient(circle at 42% 42%, rgba(209, 138, 255, 0.5), rgba(93, 38, 193, 0.22) 42%, transparent 72%);
filter: blur(2rpx);
box-shadow: 0 0 120rpx rgba(168, 85, 247, 0.22);
animation: planetDrift 9s ease-in-out infinite;
}
.planet-main::after {
content: '';
position: absolute;
left: -24rpx;
top: 78rpx;
width: 238rpx;
height: 34rpx;
left: 14rpx;
top: 120rpx;
width: 228rpx;
height: 30rpx;
border-radius: 50%;
border: 3rpx solid rgba(255, 216, 107, 0.18);
border: 3rpx solid rgba(255, 216, 107, 0.08);
transform: rotate(-16deg);
}
@@ -1329,34 +1309,68 @@ onUnmounted(() => {
.meteor {
position: absolute;
width: 132rpx;
height: 3rpx;
width: 160rpx;
height: 4rpx;
border-radius: 999rpx;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.9), rgba(255, 216, 107, 0.18), transparent);
background: linear-gradient(90deg, transparent 0%, rgba(132, 92, 255, 0.12) 18%, rgba(255, 216, 107, 0.34) 58%, rgba(255, 255, 255, 0.95) 100%);
opacity: 0;
transform: rotate(-22deg);
animation: meteorFall 5.6s linear infinite;
transform: rotate(22deg);
animation: meteorFall 5.6s cubic-bezier(0.18, 0.65, 0.42, 1) infinite;
box-shadow: 0 0 18rpx rgba(255, 216, 107, 0.14);
}
.meteor::after {
content: '';
position: absolute;
right: -5rpx;
top: 50%;
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.96);
box-shadow:
0 0 14rpx rgba(255, 255, 255, 0.74),
0 0 28rpx rgba(255, 216, 107, 0.34);
transform: translateY(-50%);
}
.meteor-one {
top: 142rpx;
left: -160rpx;
top: 120rpx;
left: -190rpx;
}
.meteor-two {
top: 318rpx;
left: 120rpx;
width: 104rpx;
top: 260rpx;
left: 46rpx;
width: 126rpx;
animation-delay: 1.8s;
}
.meteor-three {
top: 520rpx;
right: -120rpx;
width: 88rpx;
top: 440rpx;
left: 420rpx;
width: 118rpx;
animation-delay: 3.4s;
}
.meteor-four {
top: 360rpx;
left: -210rpx;
width: 210rpx;
height: 5rpx;
opacity: 0;
animation-duration: 7.2s;
animation-delay: 4.6s;
}
.meteor-five {
top: 720rpx;
left: -180rpx;
width: 148rpx;
animation-duration: 6.4s;
animation-delay: 2.8s;
}
@keyframes starFloat {
0%, 100% {
transform: translateY(0);
@@ -1382,21 +1396,103 @@ onUnmounted(() => {
@keyframes meteorFall {
0% {
opacity: 0;
transform: translate3d(0, 0, 0) rotate(-22deg);
transform: translate3d(0, 0, 0) rotate(22deg);
}
9% {
opacity: 0.62;
8% {
opacity: 0.76;
}
34% {
32% {
opacity: 0.18;
}
38% {
opacity: 0;
transform: translate3d(520rpx, 210rpx, 0) rotate(-22deg);
transform: translate3d(660rpx, 270rpx, 0) rotate(22deg);
}
100% {
opacity: 0;
transform: translate3d(520rpx, 210rpx, 0) rotate(-22deg);
transform: translate3d(660rpx, 270rpx, 0) rotate(22deg);
}
}
@keyframes micPulse {
0%, 100% {
opacity: 0.22;
transform: scale(0.92);
}
50% {
opacity: 0.48;
transform: scale(1.02);
}
}
@keyframes micHaloBreath {
0%, 100% {
opacity: 0.76;
transform: scale(0.94);
}
50% {
opacity: 1;
transform: scale(1.04);
}
}
@keyframes micIdleBreath {
0%, 100% {
transform: translateY(0) scale(1);
}
50% {
transform: translateY(-4rpx) scale(1.015);
}
}
@keyframes micPressBreath {
0%, 100% {
transform: scale(1.055);
}
50% {
transform: scale(1.085);
}
}
@keyframes micWavePress {
0% {
opacity: 0.58;
transform: scale(0.82);
}
100% {
opacity: 0;
transform: scale(1.22);
}
}
@keyframes micScan {
0% {
background-position: -180rpx 0, 0 0, 0 0;
}
100% {
background-position: 180rpx 0, 0 0, 0 0;
}
}
@keyframes micHighlightFloat {
0%, 100% {
opacity: 0.24;
transform: translateY(0);
}
50% {
opacity: 0.42;
transform: translateY(8rpx);
}
}
@@ -1409,7 +1505,7 @@ onUnmounted(() => {
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 4rpx 0 24rpx;
padding: 4rpx 28rpx 24rpx;
}
.wish-home {
@@ -1468,30 +1564,6 @@ onUnmounted(() => {
gap: 14rpx;
}
.head-action-row {
display: flex;
align-items: center;
gap: 12rpx;
min-width: 0;
}
.social-import-btn {
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 0 22rpx;
border-radius: 999rpx;
color: #fff;
font-size: 25rpx;
font-weight: 800;
white-space: nowrap;
background:
radial-gradient(circle at 80% 10%, rgba(255, 255, 255, 0.26), transparent 26%),
linear-gradient(135deg, #b045ff, #612eff);
box-shadow: 0 14rpx 34rpx rgba(129, 66, 255, 0.34);
}
.history-button {
height: 58rpx;
display: inline-flex;
@@ -1566,8 +1638,9 @@ onUnmounted(() => {
.orb-wrap {
position: relative;
height: 320rpx;
margin-top: 4rpx;
height: 300rpx;
margin-top: 44rpx;
margin-bottom: 0;
display: flex;
align-items: center;
justify-content: center;
@@ -1581,6 +1654,7 @@ onUnmounted(() => {
border-radius: 50%;
background: radial-gradient(circle, rgba(116, 41, 210, 0.42), transparent 64%);
filter: blur(6rpx);
animation: micHaloBreath 3.8s ease-in-out infinite;
}
.mic-orb {
@@ -1596,38 +1670,108 @@ onUnmounted(() => {
0 0 72rpx rgba(169, 85, 247, 0.75),
0 0 180rpx rgba(102, 41, 201, 0.55);
transition: transform 0.18s ease, box-shadow 0.18s ease;
overflow: hidden;
animation: micIdleBreath 3.2s ease-in-out infinite;
}
.mic-orb::before {
content: '';
position: absolute;
inset: 18rpx;
border-radius: 50%;
background:
radial-gradient(circle at 35% 26%, rgba(255, 255, 255, 0.28), transparent 18%),
radial-gradient(circle at 50% 62%, rgba(39, 16, 98, 0.18), transparent 48%);
border: 1rpx solid rgba(255, 255, 255, 0.1);
}
.mic-orb::after {
content: '';
position: absolute;
inset: -18rpx;
border-radius: 50%;
border: 3rpx solid rgba(216, 180, 254, 0.12);
animation: micPulse 2.8s ease-in-out infinite;
}
.mic-orb.pressing {
animation: micPressBreath 1.1s ease-in-out infinite;
transform: scale(1.06);
box-shadow:
0 0 86rpx rgba(241, 160, 255, 0.82),
0 0 220rpx rgba(102, 41, 201, 0.68);
}
.mic-orb.pressing::after {
border-color: rgba(255, 216, 107, 0.26);
animation: micWavePress 0.95s ease-out infinite;
}
.mic-orb.recognizing {
opacity: 0.86;
}
.mic-orb.recognizing::before {
background:
linear-gradient(110deg, transparent 0 34%, rgba(255, 255, 255, 0.24) 44%, transparent 56%),
radial-gradient(circle at 35% 26%, rgba(255, 255, 255, 0.28), transparent 18%),
radial-gradient(circle at 50% 62%, rgba(39, 16, 98, 0.18), transparent 48%);
animation: micScan 1.35s linear infinite;
}
.mic-symbol {
position: relative;
width: 88rpx;
height: 118rpx;
height: 128rpx;
z-index: 2;
}
.mic-head {
position: relative;
width: 58rpx;
height: 78rpx;
margin: 0 auto;
border-radius: 30rpx;
border: 8rpx solid rgba(255, 255, 255, 0.92);
border: 8rpx solid rgba(255, 255, 255, 0.94);
box-sizing: border-box;
background:
linear-gradient(90deg, transparent 46%, rgba(255, 255, 255, 0.44) 47% 53%, transparent 54%),
repeating-linear-gradient(180deg, transparent 0 13rpx, rgba(255, 255, 255, 0.34) 14rpx 17rpx);
box-shadow:
inset 0 0 18rpx rgba(255, 255, 255, 0.18),
0 0 10rpx rgba(255, 255, 255, 0.18);
}
.mic-head::before {
content: '';
position: absolute;
left: 8rpx;
top: 10rpx;
width: 10rpx;
height: 22rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.32);
animation: micHighlightFloat 2.6s ease-in-out infinite;
}
.mic-symbol::after {
content: '';
position: absolute;
left: 14rpx;
top: 62rpx;
width: 60rpx;
height: 40rpx;
box-sizing: border-box;
border-left: 6rpx solid rgba(255, 255, 255, 0.9);
border-right: 6rpx solid rgba(255, 255, 255, 0.9);
border-bottom: 6rpx solid rgba(255, 255, 255, 0.9);
border-radius: 0 0 34rpx 34rpx;
}
.mic-stem {
width: 8rpx;
height: 34rpx;
margin: -2rpx auto 0;
height: 38rpx;
margin: 6rpx auto 0;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.92);
}
@@ -1641,6 +1785,8 @@ onUnmounted(() => {
}
.voice-copy {
margin-top: -2rpx;
margin-bottom: 46rpx;
text-align: center;
font-size: 34rpx;
font-weight: 500;
@@ -1649,8 +1795,9 @@ onUnmounted(() => {
}
.wish-input-wrap {
position: relative;
min-height: 92rpx;
margin-top: auto;
margin-top: 0;
margin-bottom: 6rpx;
display: flex;
align-items: center;
@@ -1680,26 +1827,49 @@ onUnmounted(() => {
border-radius: 36rpx;
}
.custom-input-placeholder {
position: absolute;
z-index: 1;
color: rgba(216, 180, 254, 0.48);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: none;
}
.home-input-placeholder {
left: 28rpx;
right: 138rpx;
top: 50%;
transform: translateY(-50%);
font-size: 34rpx;
line-height: 1;
}
.wish-input {
position: relative;
z-index: 2;
flex: 1;
height: 68rpx;
height: 72rpx;
min-height: 72rpx;
max-height: 150rpx;
padding: 0;
box-sizing: border-box;
color: #fff;
font-size: 34rpx;
line-height: 48rpx;
line-height: 72rpx;
}
.wish-input-wrap.twoLine .wish-input,
.wish-input-wrap.expanded .wish-input {
height: auto;
}
.placeholder {
color: rgba(216, 180, 254, 0.48);
padding: 8rpx 0;
line-height: 48rpx;
}
.send-button {
position: relative;
z-index: 2;
min-width: 104rpx;
height: 72rpx;
display: flex;
@@ -1744,7 +1914,7 @@ onUnmounted(() => {
.recommend-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14rpx;
gap: 22rpx 24rpx;
}
.recommend-card {
@@ -2385,33 +2555,63 @@ onUnmounted(() => {
box-shadow: 0 0 30rpx rgba(168, 85, 247, 0.38);
}
.result-chat-input {
.result-input-shell {
position: relative;
flex: 1;
height: 76rpx;
min-height: 76rpx;
max-height: 146rpx;
padding: 18rpx 22rpx;
box-sizing: border-box;
border-radius: 28rpx;
color: #fff;
font-size: 28rpx;
line-height: 40rpx;
background: rgba(43, 19, 83, 0.72);
border: 1rpx solid rgba(168, 85, 247, 0.36);
overflow: hidden;
}
.result-chat-input.twoLine {
.result-input-shell.twoLine {
height: auto;
min-height: 110rpx;
border-radius: 30rpx;
}
.result-chat-input.expanded {
.result-input-shell.expanded {
height: auto;
min-height: 144rpx;
border-radius: 30rpx;
}
.result-input-placeholder {
left: 22rpx;
right: 22rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
line-height: 1;
}
.result-chat-input {
position: relative;
z-index: 2;
width: 100%;
height: 76rpx;
min-height: 76rpx;
max-height: 146rpx;
padding: 0 22rpx;
box-sizing: border-box;
color: #fff;
font-size: 28rpx;
line-height: 76rpx;
background: transparent;
}
.result-input-shell.twoLine .result-chat-input,
.result-input-shell.expanded .result-chat-input {
height: auto;
min-height: 78rpx;
padding: 16rpx 22rpx;
line-height: 40rpx;
}
.chat-send-btn {
width: 92rpx;
height: 76rpx;