feat: 小程序页面优化和新增剧本库功能
This commit is contained in:
@@ -1,8 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="music-player" :style="{ bottom: bottomPosition }">
|
<view
|
||||||
|
v-if="positionReady"
|
||||||
|
class="music-player"
|
||||||
|
:style="playerStyle"
|
||||||
|
@touchstart.stop="handleTouchStart"
|
||||||
|
@touchmove.stop.prevent="handleTouchMove"
|
||||||
|
@touchend.stop="handleTouchEnd"
|
||||||
|
@touchcancel.stop="handleTouchEnd"
|
||||||
|
>
|
||||||
<view
|
<view
|
||||||
class="music-toggle"
|
class="music-toggle"
|
||||||
:class="{ playing: isPlaying }"
|
:class="{ playing: isPlaying, dragging: isDragging }"
|
||||||
@click="toggleMusic"
|
@click="toggleMusic"
|
||||||
>
|
>
|
||||||
<view class="music-disc" :class="{ spinning: isPlaying }"></view>
|
<view class="music-disc" :class="{ spinning: isPlaying }"></view>
|
||||||
@@ -12,14 +20,62 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
|
||||||
const isPlaying = ref(false)
|
const isPlaying = ref(false)
|
||||||
const bottomPosition = ref('180rpx')
|
const positionReady = ref(false)
|
||||||
|
const isDragging = ref(false)
|
||||||
|
const playerPosition = ref({ x: 0, y: 0 })
|
||||||
let audioInstance = null
|
let audioInstance = null
|
||||||
|
let windowMetrics = {
|
||||||
|
width: 375,
|
||||||
|
height: 667,
|
||||||
|
statusBarHeight: 20,
|
||||||
|
safeAreaBottom: 0,
|
||||||
|
buttonSize: 44
|
||||||
|
}
|
||||||
|
let dragStart = null
|
||||||
|
let suppressNextClick = false
|
||||||
|
|
||||||
// 背景音乐 URL - 使用原型中的音乐
|
// 背景音乐 URL - 使用原型中的音乐
|
||||||
const MUSIC_URL = 'https://v3b.fal.media/files/b/0a8c9a0b/rStj8V-2tCe6bVYpCCcLN_output.mp3'
|
const MUSIC_URL = 'https://v3b.fal.media/files/b/0a8c9a0b/rStj8V-2tCe6bVYpCCcLN_output.mp3'
|
||||||
|
const STORAGE_KEY = 'music_player_position'
|
||||||
|
|
||||||
|
const playerStyle = computed(() => ({
|
||||||
|
left: `${playerPosition.value.x}px`,
|
||||||
|
top: `${playerPosition.value.y}px`
|
||||||
|
}))
|
||||||
|
|
||||||
|
const rpxToPx = (rpx, windowWidth = windowMetrics.width) => windowWidth * rpx / 750
|
||||||
|
|
||||||
|
const clamp = (value, min, max) => Math.max(min, Math.min(max, value))
|
||||||
|
|
||||||
|
const clampPosition = (position) => {
|
||||||
|
const margin = 8
|
||||||
|
const minY = Math.max(margin, windowMetrics.statusBarHeight + 8)
|
||||||
|
const maxX = windowMetrics.width - windowMetrics.buttonSize - margin
|
||||||
|
const maxY = windowMetrics.height - windowMetrics.safeAreaBottom - windowMetrics.buttonSize - margin
|
||||||
|
return {
|
||||||
|
x: clamp(Number(position?.x) || margin, margin, Math.max(margin, maxX)),
|
||||||
|
y: clamp(Number(position?.y) || minY, minY, Math.max(minY, maxY))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const savePosition = () => {
|
||||||
|
uni.setStorageSync(STORAGE_KEY, playerPosition.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const restorePosition = () => {
|
||||||
|
const saved = uni.getStorageSync(STORAGE_KEY)
|
||||||
|
if (saved && typeof saved === 'object') {
|
||||||
|
playerPosition.value = clampPosition(saved)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
playerPosition.value = clampPosition({
|
||||||
|
x: windowMetrics.width - windowMetrics.buttonSize - rpxToPx(16),
|
||||||
|
y: windowMetrics.height - windowMetrics.safeAreaBottom - windowMetrics.buttonSize - 96
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const initAudio = () => {
|
const initAudio = () => {
|
||||||
if (!audioInstance) {
|
if (!audioInstance) {
|
||||||
@@ -49,6 +105,7 @@ const initAudio = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toggleMusic = async () => {
|
const toggleMusic = async () => {
|
||||||
|
if (suppressNextClick || isDragging.value) return
|
||||||
initAudio()
|
initAudio()
|
||||||
|
|
||||||
if (isPlaying.value) {
|
if (isPlaying.value) {
|
||||||
@@ -63,11 +120,58 @@ const toggleMusic = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleTouchStart = (event) => {
|
||||||
|
const touch = event.touches?.[0]
|
||||||
|
if (!touch) return
|
||||||
|
dragStart = {
|
||||||
|
x: touch.clientX,
|
||||||
|
y: touch.clientY,
|
||||||
|
originX: playerPosition.value.x,
|
||||||
|
originY: playerPosition.value.y,
|
||||||
|
moved: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTouchMove = (event) => {
|
||||||
|
const touch = event.touches?.[0]
|
||||||
|
if (!touch || !dragStart) return
|
||||||
|
const deltaX = touch.clientX - dragStart.x
|
||||||
|
const deltaY = touch.clientY - dragStart.y
|
||||||
|
if (Math.abs(deltaX) > 3 || Math.abs(deltaY) > 3) {
|
||||||
|
dragStart.moved = true
|
||||||
|
isDragging.value = true
|
||||||
|
}
|
||||||
|
if (!dragStart.moved) return
|
||||||
|
playerPosition.value = clampPosition({
|
||||||
|
x: dragStart.originX + deltaX,
|
||||||
|
y: dragStart.originY + deltaY
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTouchEnd = () => {
|
||||||
|
if (dragStart?.moved) {
|
||||||
|
playerPosition.value = clampPosition(playerPosition.value)
|
||||||
|
savePosition()
|
||||||
|
suppressNextClick = true
|
||||||
|
setTimeout(() => {
|
||||||
|
suppressNextClick = false
|
||||||
|
}, 180)
|
||||||
|
}
|
||||||
|
dragStart = null
|
||||||
|
isDragging.value = false
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 使用新的推荐 API 替代已弃用的 getSystemInfoSync
|
const windowInfo = uni.getWindowInfo ? uni.getWindowInfo() : uni.getSystemInfoSync()
|
||||||
const windowInfo = uni.getWindowInfo()
|
windowMetrics = {
|
||||||
const safeAreaBottom = windowInfo.safeAreaInsets?.bottom || 0
|
width: windowInfo.windowWidth || 375,
|
||||||
bottomPosition.value = `${safeAreaBottom + 96}px`
|
height: windowInfo.windowHeight || 667,
|
||||||
|
statusBarHeight: windowInfo.statusBarHeight || 20,
|
||||||
|
safeAreaBottom: windowInfo.safeAreaInsets?.bottom || 0,
|
||||||
|
buttonSize: rpxToPx(88, windowInfo.windowWidth || 375)
|
||||||
|
}
|
||||||
|
restorePosition()
|
||||||
|
positionReady.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@@ -86,8 +190,9 @@ defineExpose({
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.music-player {
|
.music-player {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 16rpx;
|
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
width: 88rpx;
|
||||||
|
height: 88rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.music-toggle {
|
.music-toggle {
|
||||||
@@ -106,6 +211,13 @@ defineExpose({
|
|||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.music-toggle.dragging {
|
||||||
|
transform: scale(1.06);
|
||||||
|
opacity: 0.78;
|
||||||
|
border-color: rgba(216, 180, 254, 0.42);
|
||||||
|
box-shadow: 0 0 34rpx rgba(168, 85, 247, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
.music-toggle:active {
|
.music-toggle:active {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -66,9 +66,8 @@
|
|||||||
</view>
|
</view>
|
||||||
<text class="section-subtitle">你的成长之路,正在展开</text>
|
<text class="section-subtitle">你的成长之路,正在展开</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="map-btn kos-pill" @click="openMap">
|
<view class="social-import-btn" @click="openSocialImport">
|
||||||
<view class="map-icon"></view>
|
<text>导入社交数据</text>
|
||||||
<text>轨迹地图</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -263,8 +262,8 @@ const editProfile = () => {
|
|||||||
uni.navigateTo({ url: '/pages/onboarding/index?edit=1' })
|
uni.navigateTo({ url: '/pages/onboarding/index?edit=1' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const openMap = () => {
|
const openSocialImport = () => {
|
||||||
uni.navigateTo({ url: '/pages/main/PathView' })
|
uni.navigateTo({ url: '/pages/social-import/index' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const addFilter = () => {
|
const addFilter = () => {
|
||||||
@@ -567,23 +566,21 @@ const addFilter = () => {
|
|||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.map-btn {
|
.social-import-btn {
|
||||||
height: 56rpx;
|
height: 64rpx;
|
||||||
padding: 0 20rpx;
|
padding: 0 22rpx;
|
||||||
border-radius: 999rpx;
|
border-radius: 999rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10rpx;
|
justify-content: center;
|
||||||
color: #caa9ff;
|
color: #fff;
|
||||||
font-size: 22rpx;
|
font-size: 25rpx;
|
||||||
}
|
font-weight: 800;
|
||||||
|
white-space: nowrap;
|
||||||
.map-icon {
|
background:
|
||||||
width: 24rpx;
|
radial-gradient(circle at 80% 10%, rgba(255, 255, 255, 0.26), transparent 26%),
|
||||||
height: 20rpx;
|
linear-gradient(135deg, #b045ff, #612eff);
|
||||||
border: 3rpx solid currentColor;
|
box-shadow: 0 14rpx 34rpx rgba(129, 66, 255, 0.34);
|
||||||
border-radius: 4rpx;
|
|
||||||
transform: skewY(-12deg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
|
|||||||
@@ -0,0 +1,829 @@
|
|||||||
|
<template>
|
||||||
|
<view class="script-library">
|
||||||
|
<view class="page-head">
|
||||||
|
<view class="back-title" @click="backToScript">
|
||||||
|
<text class="back-arrow">‹</text>
|
||||||
|
<text class="back-text">返回</text>
|
||||||
|
</view>
|
||||||
|
<view class="head-actions">
|
||||||
|
<view class="circle-btn" @click="openSearch">
|
||||||
|
<view class="search-icon"></view>
|
||||||
|
</view>
|
||||||
|
<view class="circle-btn" @click="openMoreMenu">
|
||||||
|
<view class="more-icon">
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="type-tabs">
|
||||||
|
<text
|
||||||
|
v-for="tab in typeTabs"
|
||||||
|
:key="tab.value"
|
||||||
|
class="type-tab"
|
||||||
|
:class="{ active: activeType === tab.value }"
|
||||||
|
@click="activeType = tab.value"
|
||||||
|
>{{ tab.label }}</text>
|
||||||
|
<view class="new-script" @click="createScript">
|
||||||
|
<text class="plus">+</text>
|
||||||
|
<text>新建剧本</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="filter-bar">
|
||||||
|
<scroll-view class="status-scroll" scroll-x :show-scrollbar="false">
|
||||||
|
<view class="status-row">
|
||||||
|
<text
|
||||||
|
v-for="filter in statusFilters"
|
||||||
|
:key="filter.value"
|
||||||
|
class="status-chip"
|
||||||
|
:class="{ active: activeStatus === filter.value }"
|
||||||
|
@click="activeStatus = filter.value"
|
||||||
|
>{{ filter.label }}</text>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="sort-tools">
|
||||||
|
<text class="sort-text" @click="toggleSort">{{ sortLabel }}</text>
|
||||||
|
<view class="grid-icon" :class="{ active: viewMode === 'grid' }" @click="toggleViewMode">
|
||||||
|
<view v-for="i in 4" :key="i"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="visibleScripts.length" class="script-list" :class="{ grid: viewMode === 'grid' }">
|
||||||
|
<view
|
||||||
|
v-for="(script, index) in visibleScripts"
|
||||||
|
:key="script.id || index"
|
||||||
|
class="script-card"
|
||||||
|
@click="viewScript(script)"
|
||||||
|
>
|
||||||
|
<view class="cover" :class="'cover-' + (index % 6)">
|
||||||
|
<text>{{ getInitial(script) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-main">
|
||||||
|
<view class="card-top">
|
||||||
|
<view class="title-wrap">
|
||||||
|
<text class="script-title">{{ script.title }}</text>
|
||||||
|
<text class="length-badge">{{ getLengthLabel(script.length) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="right-state">
|
||||||
|
<text class="state-pill" :class="'state-' + getStatus(script)">{{ getStatusLabel(script) }}</text>
|
||||||
|
<text class="ellipsis" @click.stop="openScriptMenu(script)">•••</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="tag-row">
|
||||||
|
<text v-for="tag in getTags(script)" :key="tag" class="tag">{{ tag }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<text class="summary">{{ script.summary || script.content || '一段正在生成中的平行人生剧本。' }}</text>
|
||||||
|
|
||||||
|
<view class="meta-row">
|
||||||
|
<text>{{ getChapterCount(script) }}章</text>
|
||||||
|
<text>|</text>
|
||||||
|
<text>{{ getWordCount(script) }}</text>
|
||||||
|
<text>|</text>
|
||||||
|
<text>{{ getDateText(script) }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="getStatus(script) === 'progress'" class="progress-row">
|
||||||
|
<view class="progress-track">
|
||||||
|
<view class="progress-fill" :style="{ width: getProgress(script) + '%' }"></view>
|
||||||
|
</view>
|
||||||
|
<text>{{ getProgress(script) }}%</text>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="isFavorite(script)" class="favorite-row">
|
||||||
|
<text class="favorite-star">★</text>
|
||||||
|
<text>已收藏</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else class="empty-card">
|
||||||
|
<view class="empty-book">
|
||||||
|
<view></view>
|
||||||
|
<view></view>
|
||||||
|
</view>
|
||||||
|
<text class="empty-title">还没有人生剧本</text>
|
||||||
|
<text class="empty-text">去爽文生成页写下一句灵感,生成你的第一段平行人生。</text>
|
||||||
|
<view class="empty-action" @click="createScript">新建剧本</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useAppStore } from '../../stores/app.js'
|
||||||
|
|
||||||
|
const store = useAppStore()
|
||||||
|
const activeType = ref('long')
|
||||||
|
const activeStatus = ref('all')
|
||||||
|
const keyword = ref('')
|
||||||
|
const sortMode = ref('updated')
|
||||||
|
const viewMode = ref('list')
|
||||||
|
const localFavorites = ref(uni.getStorageSync('script_favorites') || {})
|
||||||
|
|
||||||
|
const typeTabs = [
|
||||||
|
{ label: '长篇', value: 'long' },
|
||||||
|
{ label: '短篇', value: 'short' },
|
||||||
|
{ label: '风格', value: 'style' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const statusFilters = [
|
||||||
|
{ label: '全部', value: 'all' },
|
||||||
|
{ label: '进行中', value: 'progress' },
|
||||||
|
{ label: '已完成', value: 'done' },
|
||||||
|
{ label: '草稿箱', value: 'draft' },
|
||||||
|
{ label: '收藏夹', value: 'favorite' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const fallbackScripts = [
|
||||||
|
{
|
||||||
|
id: 'demo-1',
|
||||||
|
title: '逆袭人生:从低谷到巅峰',
|
||||||
|
length: 'long',
|
||||||
|
status: 'progress',
|
||||||
|
tags: ['逆袭成长', '都市', '事业', '热血'],
|
||||||
|
summary: '从被分手、被否定的低谷开始,凭借天赋、努力与智慧,一步步逆袭成为行业巅峰,收获事业、财富...',
|
||||||
|
chapterCount: 28,
|
||||||
|
wordCount: 128000,
|
||||||
|
updatedAt: '今天 21:30',
|
||||||
|
progress: 28
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'demo-2',
|
||||||
|
title: '如果那年我没有放弃',
|
||||||
|
length: 'long',
|
||||||
|
status: 'done',
|
||||||
|
tags: ['成长治愈', '校园', '爱情', '温暖'],
|
||||||
|
summary: '重回十八岁,弥补遗憾,勇敢追梦,守护那些曾经错过的人和事。',
|
||||||
|
chapterCount: 36,
|
||||||
|
wordCount: 156000,
|
||||||
|
completedAt: '2025.05.10',
|
||||||
|
isFavorite: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'demo-3',
|
||||||
|
title: '重生之我在未来等你',
|
||||||
|
length: 'long',
|
||||||
|
status: 'progress',
|
||||||
|
tags: ['重生', '科幻', '爱情', '未来'],
|
||||||
|
summary: '一觉醒来,回到十年前的那一天。这一次,我不仅要改变自己的人生,还要找到你。',
|
||||||
|
chapterCount: 18,
|
||||||
|
wordCount: 83000,
|
||||||
|
updatedAt: '昨天 18:47',
|
||||||
|
progress: 46
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'demo-4',
|
||||||
|
title: '天才作曲家的璀璨之路',
|
||||||
|
length: 'long',
|
||||||
|
status: 'draft',
|
||||||
|
tags: ['音乐', '励志', '天赋', '梦想'],
|
||||||
|
summary: '从默默无闻到享誉全球,用音符征服世界,写下属于自己的传奇乐章。',
|
||||||
|
chapterCount: 9,
|
||||||
|
wordCount: 31000,
|
||||||
|
createdAt: '2025.05.08'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'demo-5',
|
||||||
|
title: '咖啡馆里的奇遇',
|
||||||
|
length: 'short',
|
||||||
|
status: 'done',
|
||||||
|
tags: ['生活', '治愈', '奇幻', '温暖'],
|
||||||
|
summary: '一杯咖啡,一次奇遇,改变了我平凡的生活,也让我遇见了最特别的你。',
|
||||||
|
chapterCount: 1,
|
||||||
|
wordCount: 23000,
|
||||||
|
completedAt: '2025.05.01',
|
||||||
|
isFavorite: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'demo-6',
|
||||||
|
title: '赛博时代的追光者',
|
||||||
|
length: 'long',
|
||||||
|
status: 'draft',
|
||||||
|
tags: ['科幻', '未来', '冒险', '热血'],
|
||||||
|
summary: '在数据与代码构建的世界里,我追寻光明,也在黑暗中寻找真正的自由。',
|
||||||
|
chapterCount: 3,
|
||||||
|
wordCount: 12000,
|
||||||
|
createdAt: '2025.05.12'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const scripts = computed(() => {
|
||||||
|
const list = store.scripts || []
|
||||||
|
return list.length ? list : fallbackScripts
|
||||||
|
})
|
||||||
|
|
||||||
|
const visibleScripts = computed(() => {
|
||||||
|
const filtered = scripts.value.filter(script => {
|
||||||
|
const status = getStatus(script)
|
||||||
|
if (keyword.value) {
|
||||||
|
const haystack = [script.title, script.summary, script.content, script.style, ...(script.tags || [])].join(' ')
|
||||||
|
if (!haystack.includes(keyword.value)) return false
|
||||||
|
}
|
||||||
|
if (activeStatus.value === 'favorite') return isFavorite(script)
|
||||||
|
if (activeStatus.value !== 'all' && status !== activeStatus.value) return false
|
||||||
|
if (activeType.value === 'short') return script.length === 'short'
|
||||||
|
if (activeType.value === 'long') return script.length !== 'short'
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return [...filtered].sort((a, b) => {
|
||||||
|
if (sortMode.value === 'words') return Number(b.wordCount || 0) - Number(a.wordCount || 0)
|
||||||
|
if (sortMode.value === 'progress') return getProgress(b) - getProgress(a)
|
||||||
|
return String(b.updateTime || b.updatedAt || b.createTime || b.date || '').localeCompare(String(a.updateTime || a.updatedAt || a.createTime || a.date || ''))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const sortLabel = computed(() => {
|
||||||
|
const map = { updated: '最近更新⌄', words: '字数最多⌄', progress: '进度最高⌄' }
|
||||||
|
return map[sortMode.value] || '最近更新⌄'
|
||||||
|
})
|
||||||
|
|
||||||
|
const getStatus = (script) => {
|
||||||
|
if (script.status) return script.status
|
||||||
|
if (script.isDraft) return 'draft'
|
||||||
|
if (script.isCompleted || script.completedAt) return 'done'
|
||||||
|
return script.progress ? 'progress' : 'done'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusLabel = (script) => {
|
||||||
|
const map = { progress: '进行中', done: '已完成', draft: '草稿' }
|
||||||
|
return map[getStatus(script)] || '已完成'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLengthLabel = (length) => {
|
||||||
|
return length === 'short' ? '短篇' : '长篇'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTags = (script) => {
|
||||||
|
if (Array.isArray(script.tags) && script.tags.length) return script.tags.slice(0, 4)
|
||||||
|
return [script.style || '逆袭成长', '都市', '事业', '热血']
|
||||||
|
}
|
||||||
|
|
||||||
|
const getChapterCount = (script) => script.chapterCount || script.chapters || Math.max(1, Math.round((script.wordCount || 30000) / 4500))
|
||||||
|
|
||||||
|
const getWordCount = (script) => {
|
||||||
|
const count = Number(script.wordCount || 0)
|
||||||
|
if (!count) return '3.1万字'
|
||||||
|
if (count >= 10000) return `${(count / 10000).toFixed(1)}万字`
|
||||||
|
return `${count}字`
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDateText = (script) => {
|
||||||
|
if (getStatus(script) === 'done') return `完成于:${script.completedAt || script.date || '2025.05.10'}`
|
||||||
|
if (getStatus(script) === 'draft') return `创建于:${script.createdAt || script.date || '2025.05.08'}`
|
||||||
|
return `最近更新:${script.updatedAt || script.date || '今天 21:30'}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const getProgress = (script) => Math.max(1, Math.min(99, Number(script.progress || 28)))
|
||||||
|
|
||||||
|
const getInitial = (script) => (script.title || '剧').slice(0, 1)
|
||||||
|
|
||||||
|
const isFavorite = (script) => {
|
||||||
|
return Boolean(script.isFavorite || script.favorite || localFavorites.value[String(script.id)])
|
||||||
|
}
|
||||||
|
|
||||||
|
const openScriptChat = (script) => {
|
||||||
|
if (!script?.id || String(script.id).startsWith('demo-')) return
|
||||||
|
uni.setStorageSync('pending_open_script_chat', {
|
||||||
|
id: script.id
|
||||||
|
})
|
||||||
|
uni.$emit('switchTab', 'script')
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.$emit('openScriptChat', { id: script.id, script })
|
||||||
|
}, 80)
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewScript = (script) => {
|
||||||
|
openScriptChat(script)
|
||||||
|
}
|
||||||
|
|
||||||
|
const openScriptDetail = (script) => {
|
||||||
|
if (!script?.id || String(script.id).startsWith('demo-')) return
|
||||||
|
uni.navigateTo({ url: `/pages/main/ScriptDetailView?id=${script.id}` })
|
||||||
|
}
|
||||||
|
|
||||||
|
const createScript = () => {
|
||||||
|
uni.$emit('switchTab', 'script')
|
||||||
|
}
|
||||||
|
|
||||||
|
const backToScript = () => {
|
||||||
|
uni.$emit('switchTab', 'script')
|
||||||
|
}
|
||||||
|
|
||||||
|
const openSearch = () => {
|
||||||
|
uni.showModal({
|
||||||
|
title: '搜索剧本',
|
||||||
|
editable: true,
|
||||||
|
placeholderText: '输入标题、标签或关键词',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) keyword.value = String(res.content || '').trim()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const openMoreMenu = () => {
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: ['清空搜索', '只看收藏', '查看全部'],
|
||||||
|
success: ({ tapIndex }) => {
|
||||||
|
if (tapIndex === 0) keyword.value = ''
|
||||||
|
if (tapIndex === 1) activeStatus.value = 'favorite'
|
||||||
|
if (tapIndex === 2) {
|
||||||
|
keyword.value = ''
|
||||||
|
activeStatus.value = 'all'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSort = () => {
|
||||||
|
const order = ['updated', 'words', 'progress']
|
||||||
|
sortMode.value = order[(order.indexOf(sortMode.value) + 1) % order.length]
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleViewMode = () => {
|
||||||
|
viewMode.value = viewMode.value === 'list' ? 'grid' : 'list'
|
||||||
|
}
|
||||||
|
|
||||||
|
const openScriptMenu = (script) => {
|
||||||
|
const favorite = isFavorite(script)
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: [favorite ? '取消收藏' : '收藏剧本', '继续生成', '查看详情'],
|
||||||
|
success: ({ tapIndex }) => {
|
||||||
|
if (tapIndex === 0) {
|
||||||
|
const next = { ...localFavorites.value }
|
||||||
|
if (favorite) delete next[String(script.id)]
|
||||||
|
else next[String(script.id)] = true
|
||||||
|
localFavorites.value = next
|
||||||
|
uni.setStorageSync('script_favorites', next)
|
||||||
|
uni.showToast({ title: favorite ? '已取消收藏' : '已收藏', icon: 'success' })
|
||||||
|
}
|
||||||
|
if (tapIndex === 1) viewScript(script)
|
||||||
|
if (tapIndex === 2) openScriptDetail(script)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.script-library {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24rpx;
|
||||||
|
padding-bottom: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-head,
|
||||||
|
.back-title,
|
||||||
|
.head-actions,
|
||||||
|
.type-tabs,
|
||||||
|
.filter-bar,
|
||||||
|
.sort-tools,
|
||||||
|
.card-top,
|
||||||
|
.title-wrap,
|
||||||
|
.right-state,
|
||||||
|
.meta-row,
|
||||||
|
.progress-row,
|
||||||
|
.favorite-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-head {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-title {
|
||||||
|
height: 60rpx;
|
||||||
|
gap: 10rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.94);
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-arrow {
|
||||||
|
font-size: 58rpx;
|
||||||
|
line-height: 1;
|
||||||
|
transform: translateY(-2rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-actions {
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-btn {
|
||||||
|
width: 58rpx;
|
||||||
|
height: 58rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1rpx solid rgba(142, 105, 255, 0.36);
|
||||||
|
background: rgba(10, 11, 38, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
width: 25rpx;
|
||||||
|
height: 25rpx;
|
||||||
|
border: 4rpx solid #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: -9rpx;
|
||||||
|
bottom: -8rpx;
|
||||||
|
width: 14rpx;
|
||||||
|
height: 4rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: #fff;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-icon {
|
||||||
|
display: flex;
|
||||||
|
gap: 5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-icon view {
|
||||||
|
width: 6rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tabs {
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1rpx solid rgba(126, 87, 255, 0.18);
|
||||||
|
padding-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tab {
|
||||||
|
position: relative;
|
||||||
|
color: rgba(224, 214, 243, 0.7);
|
||||||
|
font-size: 31rpx;
|
||||||
|
font-weight: 900;
|
||||||
|
padding: 0 20rpx 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tab.active {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tab.active::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 20rpx;
|
||||||
|
right: 20rpx;
|
||||||
|
bottom: -17rpx;
|
||||||
|
height: 5rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: #b246ff;
|
||||||
|
box-shadow: 0 0 18rpx rgba(178, 70, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-script {
|
||||||
|
margin-left: auto;
|
||||||
|
height: 64rpx;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
background: linear-gradient(135deg, #b346ff, #7330ff);
|
||||||
|
box-shadow: 0 0 26rpx rgba(168, 85, 247, 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plus {
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar {
|
||||||
|
gap: 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-scroll {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-row {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-chip {
|
||||||
|
height: 52rpx;
|
||||||
|
min-width: 88rpx;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: rgba(224, 214, 243, 0.78);
|
||||||
|
font-size: 23rpx;
|
||||||
|
border: 1rpx solid rgba(151, 111, 255, 0.42);
|
||||||
|
background: rgba(255, 255, 255, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-chip.active {
|
||||||
|
color: #fff;
|
||||||
|
border-color: rgba(206, 82, 255, 0.92);
|
||||||
|
background: rgba(130, 48, 220, 0.42);
|
||||||
|
box-shadow: 0 0 18rpx rgba(168, 67, 255, 0.46);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-tools {
|
||||||
|
gap: 14rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-text {
|
||||||
|
color: #c99fff;
|
||||||
|
font-size: 23rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-icon {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
border-radius: 18rpx;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 6rpx;
|
||||||
|
padding: 11rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1rpx solid rgba(151, 111, 255, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-icon view {
|
||||||
|
border: 2rpx solid rgba(230, 222, 250, 0.78);
|
||||||
|
border-radius: 3rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-list.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-list.grid .script-card {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-list.grid .cover {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-icon.active {
|
||||||
|
border-color: rgba(206, 82, 255, 0.9);
|
||||||
|
background: rgba(130, 48, 220, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-card {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 150rpx 1fr;
|
||||||
|
gap: 22rpx;
|
||||||
|
min-height: 196rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
border: 1rpx solid rgba(105, 79, 210, 0.34);
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 100% 0%, rgba(112, 72, 255, 0.14), transparent 38%),
|
||||||
|
rgba(9, 12, 42, 0.72);
|
||||||
|
box-shadow: inset 0 0 28rpx rgba(92, 57, 197, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover {
|
||||||
|
width: 150rpx;
|
||||||
|
height: 150rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 54rpx;
|
||||||
|
font-weight: 900;
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(135deg, #3b1a90, #d65cff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-0 { background: linear-gradient(135deg, #29135f, #9037ff 48%, #191b5e); }
|
||||||
|
.cover-1 { background: linear-gradient(135deg, #3c1c4a, #f2b3cc 48%, #16143b); }
|
||||||
|
.cover-2 { background: linear-gradient(135deg, #1a225f, #7d4cff 48%, #0a0f2c); }
|
||||||
|
.cover-3 { background: linear-gradient(135deg, #2f240b, #f7b44a 48%, #0d0a16); }
|
||||||
|
.cover-4 { background: linear-gradient(135deg, #3f2417, #d8b58a 48%, #17101d); }
|
||||||
|
.cover-5 { background: linear-gradient(135deg, #141451, #cc46ff 48%, #0c0b28); }
|
||||||
|
|
||||||
|
.card-main {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-top {
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-wrap {
|
||||||
|
min-width: 0;
|
||||||
|
gap: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.script-title {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 27rpx;
|
||||||
|
line-height: 1.25;
|
||||||
|
font-weight: 900;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.length-badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 4rpx 9rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
color: #c985ff;
|
||||||
|
font-size: 18rpx;
|
||||||
|
border: 1rpx solid rgba(182, 92, 255, 0.5);
|
||||||
|
background: rgba(128, 55, 204, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-state {
|
||||||
|
flex-shrink: 0;
|
||||||
|
gap: 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-pill {
|
||||||
|
height: 34rpx;
|
||||||
|
padding: 0 14rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 19rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-progress {
|
||||||
|
color: #ffbf4c;
|
||||||
|
background: rgba(170, 103, 20, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-done {
|
||||||
|
color: #79e6a9;
|
||||||
|
background: rgba(44, 146, 88, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-draft {
|
||||||
|
color: rgba(224, 214, 243, 0.76);
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ellipsis {
|
||||||
|
color: rgba(224, 214, 243, 0.66);
|
||||||
|
font-size: 24rpx;
|
||||||
|
letter-spacing: 3rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-top: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
height: 34rpx;
|
||||||
|
padding: 0 14rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #d49cff;
|
||||||
|
font-size: 19rpx;
|
||||||
|
background: rgba(149, 55, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
display: -webkit-box;
|
||||||
|
margin-top: 14rpx;
|
||||||
|
color: rgba(226, 215, 246, 0.72);
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 1.55;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-row {
|
||||||
|
gap: 14rpx;
|
||||||
|
margin-top: 14rpx;
|
||||||
|
color: rgba(218, 204, 243, 0.66);
|
||||||
|
font-size: 21rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-row {
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 14rpx;
|
||||||
|
margin-top: 14rpx;
|
||||||
|
color: #bd72ff;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-track {
|
||||||
|
width: 118rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: rgba(173, 160, 210, 0.18);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: inherit;
|
||||||
|
background: linear-gradient(90deg, #b246ff, #d878ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.favorite-row {
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8rpx;
|
||||||
|
margin-top: 14rpx;
|
||||||
|
color: #b768ff;
|
||||||
|
font-size: 23rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.favorite-star {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-card {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
border-radius: 26rpx;
|
||||||
|
padding: 44rpx 30rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
border: 1rpx solid rgba(105, 79, 210, 0.34);
|
||||||
|
background: rgba(9, 12, 42, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-book {
|
||||||
|
display: flex;
|
||||||
|
gap: 6rpx;
|
||||||
|
margin-bottom: 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-book view {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 46rpx;
|
||||||
|
border: 4rpx solid #b768ff;
|
||||||
|
border-radius: 8rpx 4rpx 4rpx 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-title {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
color: rgba(226, 215, 246, 0.68);
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-action {
|
||||||
|
margin-top: 22rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
padding: 0 30rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 23rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
background: linear-gradient(135deg, #b346ff, #7330ff);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
<view class="meteor meteor-one"></view>
|
<view class="meteor meteor-one"></view>
|
||||||
<view class="meteor meteor-two"></view>
|
<view class="meteor meteor-two"></view>
|
||||||
<view class="meteor meteor-three"></view>
|
<view class="meteor meteor-three"></view>
|
||||||
|
<view class="meteor meteor-four"></view>
|
||||||
|
<view class="meteor meteor-five"></view>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="viewState === 'home'" class="wish-home">
|
<view v-if="viewState === 'home'" class="wish-home">
|
||||||
<view class="home-head">
|
<view class="home-head">
|
||||||
@@ -19,11 +21,6 @@
|
|||||||
</view>
|
</view>
|
||||||
<text>历史</text>
|
<text>历史</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="head-action-row">
|
|
||||||
<view class="social-import-btn" @click="openSocialImport">
|
|
||||||
<text>导入社交数据</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="hero-copy">
|
<view class="hero-copy">
|
||||||
@@ -73,6 +70,7 @@
|
|||||||
<text class="voice-copy">{{ voiceCopy }}</text>
|
<text class="voice-copy">{{ voiceCopy }}</text>
|
||||||
|
|
||||||
<view class="wish-input-wrap" :class="{ active: homeInputFocused, twoLine: homeInputLevel === 'two', expanded: homeInputLevel === 'multi' }">
|
<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
|
<textarea
|
||||||
class="wish-input"
|
class="wish-input"
|
||||||
v-model="wishText"
|
v-model="wishText"
|
||||||
@@ -80,8 +78,6 @@
|
|||||||
:show-confirm-bar="false"
|
:show-confirm-bar="false"
|
||||||
confirm-type="send"
|
confirm-type="send"
|
||||||
maxlength="500"
|
maxlength="500"
|
||||||
placeholder="写下你的心愿,AI帮你重写人生"
|
|
||||||
placeholder-class="placeholder"
|
|
||||||
@focus="homeInputFocused = true"
|
@focus="homeInputFocused = true"
|
||||||
@blur="homeInputFocused = false"
|
@blur="homeInputFocused = false"
|
||||||
@confirm="submitWish('text')"
|
@confirm="submitWish('text')"
|
||||||
@@ -246,21 +242,21 @@
|
|||||||
>
|
>
|
||||||
<text>语音</text>
|
<text>语音</text>
|
||||||
</view>
|
</view>
|
||||||
<textarea
|
<view class="result-input-shell" :class="{ twoLine: resultInputLevel === 'two', expanded: resultInputLevel === 'multi' }">
|
||||||
class="result-chat-input"
|
<text v-if="!resultChatInput" class="custom-input-placeholder result-input-placeholder">继续提修改建议,或确认后重新生成</text>
|
||||||
:class="{ twoLine: resultInputLevel === 'two', expanded: resultInputLevel === 'multi' }"
|
<textarea
|
||||||
v-model="resultChatInput"
|
class="result-chat-input"
|
||||||
:auto-height="resultInputLevel !== 'single'"
|
v-model="resultChatInput"
|
||||||
:show-confirm-bar="false"
|
:auto-height="resultInputLevel !== 'single'"
|
||||||
:focus="resultInputFocus"
|
:show-confirm-bar="false"
|
||||||
maxlength="500"
|
:focus="resultInputFocus"
|
||||||
confirm-type="send"
|
maxlength="500"
|
||||||
placeholder="继续提修改建议,或确认后重新生成"
|
confirm-type="send"
|
||||||
placeholder-class="placeholder"
|
@focus="resultInputFocused = true"
|
||||||
@focus="resultInputFocused = true"
|
@blur="resultInputFocused = false"
|
||||||
@blur="resultInputFocused = false"
|
@confirm="sendResultChat('text')"
|
||||||
@confirm="sendResultChat('text')"
|
/>
|
||||||
/>
|
</view>
|
||||||
<view class="chat-send-btn" :class="{ disabled: !resultChatInput.trim() || resultChatting }" @click="sendResultChat('text')">发送</view>
|
<view class="chat-send-btn" :class="{ disabled: !resultChatInput.trim() || resultChatting }" @click="sendResultChat('text')">发送</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -546,14 +542,7 @@ const normalizeGeneratedScript = (data) => {
|
|||||||
|
|
||||||
const openScriptLibrary = () => {
|
const openScriptLibrary = () => {
|
||||||
analytics.track('script_history_click', {}, { eventType: 'script', pagePath })
|
analytics.track('script_history_click', {}, { eventType: 'script', pagePath })
|
||||||
uni.$emit('switchTab', 'mine')
|
uni.$emit('switchTab', 'library')
|
||||||
}
|
|
||||||
|
|
||||||
const openSocialImport = () => {
|
|
||||||
analytics.track('script_social_import_entry_click', {
|
|
||||||
source: 'home_head'
|
|
||||||
}, { eventType: 'social_import', pagePath })
|
|
||||||
uni.navigateTo({ url: '/pages/social-import/index' })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const useRecommendation = (text) => {
|
const useRecommendation = (text) => {
|
||||||
@@ -1244,22 +1233,12 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.cosmic-background {
|
.cosmic-background {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: -80rpx -80rpx;
|
inset: -120rpx -140rpx;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
overflow: hidden;
|
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 {
|
.cosmic-stars {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@@ -1293,26 +1272,27 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.planet-main {
|
.planet-main {
|
||||||
top: 118rpx;
|
top: 210rpx;
|
||||||
right: -52rpx;
|
right: -120rpx;
|
||||||
width: 188rpx;
|
width: 260rpx;
|
||||||
height: 188rpx;
|
height: 260rpx;
|
||||||
opacity: 0.38;
|
opacity: 0.18;
|
||||||
background:
|
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));
|
radial-gradient(circle at 42% 42%, rgba(209, 138, 255, 0.5), rgba(93, 38, 193, 0.22) 42%, transparent 72%);
|
||||||
box-shadow: 0 0 76rpx rgba(168, 85, 247, 0.32);
|
filter: blur(2rpx);
|
||||||
|
box-shadow: 0 0 120rpx rgba(168, 85, 247, 0.22);
|
||||||
animation: planetDrift 9s ease-in-out infinite;
|
animation: planetDrift 9s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.planet-main::after {
|
.planet-main::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -24rpx;
|
left: 14rpx;
|
||||||
top: 78rpx;
|
top: 120rpx;
|
||||||
width: 238rpx;
|
width: 228rpx;
|
||||||
height: 34rpx;
|
height: 30rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 3rpx solid rgba(255, 216, 107, 0.18);
|
border: 3rpx solid rgba(255, 216, 107, 0.08);
|
||||||
transform: rotate(-16deg);
|
transform: rotate(-16deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,34 +1309,68 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.meteor {
|
.meteor {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 132rpx;
|
width: 160rpx;
|
||||||
height: 3rpx;
|
height: 4rpx;
|
||||||
border-radius: 999rpx;
|
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;
|
opacity: 0;
|
||||||
transform: rotate(-22deg);
|
transform: rotate(22deg);
|
||||||
animation: meteorFall 5.6s linear infinite;
|
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 {
|
.meteor-one {
|
||||||
top: 142rpx;
|
top: 120rpx;
|
||||||
left: -160rpx;
|
left: -190rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.meteor-two {
|
.meteor-two {
|
||||||
top: 318rpx;
|
top: 260rpx;
|
||||||
left: 120rpx;
|
left: 46rpx;
|
||||||
width: 104rpx;
|
width: 126rpx;
|
||||||
animation-delay: 1.8s;
|
animation-delay: 1.8s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.meteor-three {
|
.meteor-three {
|
||||||
top: 520rpx;
|
top: 440rpx;
|
||||||
right: -120rpx;
|
left: 420rpx;
|
||||||
width: 88rpx;
|
width: 118rpx;
|
||||||
animation-delay: 3.4s;
|
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 {
|
@keyframes starFloat {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
@@ -1382,21 +1396,103 @@ onUnmounted(() => {
|
|||||||
@keyframes meteorFall {
|
@keyframes meteorFall {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translate3d(0, 0, 0) rotate(-22deg);
|
transform: translate3d(0, 0, 0) rotate(22deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
9% {
|
8% {
|
||||||
opacity: 0.62;
|
opacity: 0.76;
|
||||||
}
|
}
|
||||||
|
|
||||||
34% {
|
32% {
|
||||||
|
opacity: 0.18;
|
||||||
|
}
|
||||||
|
|
||||||
|
38% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translate3d(520rpx, 210rpx, 0) rotate(-22deg);
|
transform: translate3d(660rpx, 270rpx, 0) rotate(22deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
opacity: 0;
|
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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 4rpx 0 24rpx;
|
padding: 4rpx 28rpx 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wish-home {
|
.wish-home {
|
||||||
@@ -1468,30 +1564,6 @@ onUnmounted(() => {
|
|||||||
gap: 14rpx;
|
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 {
|
.history-button {
|
||||||
height: 58rpx;
|
height: 58rpx;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -1566,8 +1638,9 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.orb-wrap {
|
.orb-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 320rpx;
|
height: 300rpx;
|
||||||
margin-top: 4rpx;
|
margin-top: 44rpx;
|
||||||
|
margin-bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -1581,6 +1654,7 @@ onUnmounted(() => {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: radial-gradient(circle, rgba(116, 41, 210, 0.42), transparent 64%);
|
background: radial-gradient(circle, rgba(116, 41, 210, 0.42), transparent 64%);
|
||||||
filter: blur(6rpx);
|
filter: blur(6rpx);
|
||||||
|
animation: micHaloBreath 3.8s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mic-orb {
|
.mic-orb {
|
||||||
@@ -1596,38 +1670,108 @@ onUnmounted(() => {
|
|||||||
0 0 72rpx rgba(169, 85, 247, 0.75),
|
0 0 72rpx rgba(169, 85, 247, 0.75),
|
||||||
0 0 180rpx rgba(102, 41, 201, 0.55);
|
0 0 180rpx rgba(102, 41, 201, 0.55);
|
||||||
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
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 {
|
.mic-orb.pressing {
|
||||||
|
animation: micPressBreath 1.1s ease-in-out infinite;
|
||||||
transform: scale(1.06);
|
transform: scale(1.06);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 0 86rpx rgba(241, 160, 255, 0.82),
|
0 0 86rpx rgba(241, 160, 255, 0.82),
|
||||||
0 0 220rpx rgba(102, 41, 201, 0.68);
|
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 {
|
.mic-orb.recognizing {
|
||||||
opacity: 0.86;
|
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 {
|
.mic-symbol {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 88rpx;
|
width: 88rpx;
|
||||||
height: 118rpx;
|
height: 128rpx;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mic-head {
|
.mic-head {
|
||||||
|
position: relative;
|
||||||
width: 58rpx;
|
width: 58rpx;
|
||||||
height: 78rpx;
|
height: 78rpx;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
border-radius: 30rpx;
|
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;
|
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 {
|
.mic-stem {
|
||||||
width: 8rpx;
|
width: 8rpx;
|
||||||
height: 34rpx;
|
height: 38rpx;
|
||||||
margin: -2rpx auto 0;
|
margin: 6rpx auto 0;
|
||||||
border-radius: 999rpx;
|
border-radius: 999rpx;
|
||||||
background: rgba(255, 255, 255, 0.92);
|
background: rgba(255, 255, 255, 0.92);
|
||||||
}
|
}
|
||||||
@@ -1641,6 +1785,8 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.voice-copy {
|
.voice-copy {
|
||||||
|
margin-top: -2rpx;
|
||||||
|
margin-bottom: 46rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 34rpx;
|
font-size: 34rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -1649,8 +1795,9 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.wish-input-wrap {
|
.wish-input-wrap {
|
||||||
|
position: relative;
|
||||||
min-height: 92rpx;
|
min-height: 92rpx;
|
||||||
margin-top: auto;
|
margin-top: 0;
|
||||||
margin-bottom: 6rpx;
|
margin-bottom: 6rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -1680,26 +1827,49 @@ onUnmounted(() => {
|
|||||||
border-radius: 36rpx;
|
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 {
|
.wish-input {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 68rpx;
|
height: 72rpx;
|
||||||
min-height: 72rpx;
|
min-height: 72rpx;
|
||||||
max-height: 150rpx;
|
max-height: 150rpx;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 34rpx;
|
font-size: 34rpx;
|
||||||
line-height: 48rpx;
|
line-height: 72rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wish-input-wrap.twoLine .wish-input,
|
.wish-input-wrap.twoLine .wish-input,
|
||||||
.wish-input-wrap.expanded .wish-input {
|
.wish-input-wrap.expanded .wish-input {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
padding: 8rpx 0;
|
||||||
|
line-height: 48rpx;
|
||||||
.placeholder {
|
|
||||||
color: rgba(216, 180, 254, 0.48);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.send-button {
|
.send-button {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
min-width: 104rpx;
|
min-width: 104rpx;
|
||||||
height: 72rpx;
|
height: 72rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1744,7 +1914,7 @@ onUnmounted(() => {
|
|||||||
.recommend-grid {
|
.recommend-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
gap: 14rpx;
|
gap: 22rpx 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.recommend-card {
|
.recommend-card {
|
||||||
@@ -2385,33 +2555,63 @@ onUnmounted(() => {
|
|||||||
box-shadow: 0 0 30rpx rgba(168, 85, 247, 0.38);
|
box-shadow: 0 0 30rpx rgba(168, 85, 247, 0.38);
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-chat-input {
|
.result-input-shell {
|
||||||
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 76rpx;
|
height: 76rpx;
|
||||||
min-height: 76rpx;
|
min-height: 76rpx;
|
||||||
max-height: 146rpx;
|
max-height: 146rpx;
|
||||||
padding: 18rpx 22rpx;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 28rpx;
|
border-radius: 28rpx;
|
||||||
color: #fff;
|
|
||||||
font-size: 28rpx;
|
|
||||||
line-height: 40rpx;
|
|
||||||
background: rgba(43, 19, 83, 0.72);
|
background: rgba(43, 19, 83, 0.72);
|
||||||
border: 1rpx solid rgba(168, 85, 247, 0.36);
|
border: 1rpx solid rgba(168, 85, 247, 0.36);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-chat-input.twoLine {
|
.result-input-shell.twoLine {
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 110rpx;
|
min-height: 110rpx;
|
||||||
border-radius: 30rpx;
|
border-radius: 30rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-chat-input.expanded {
|
.result-input-shell.expanded {
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 144rpx;
|
min-height: 144rpx;
|
||||||
border-radius: 30rpx;
|
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 {
|
.chat-send-btn {
|
||||||
width: 92rpx;
|
width: 92rpx;
|
||||||
height: 76rpx;
|
height: 76rpx;
|
||||||
|
|||||||
@@ -8,10 +8,11 @@
|
|||||||
|
|
||||||
<view class="safe-top" :style="{ height: capsuleTopReservePx + 'px' }"></view>
|
<view class="safe-top" :style="{ height: capsuleTopReservePx + 'px' }"></view>
|
||||||
|
|
||||||
<scroll-view class="content" scroll-y :enhanced="true" :show-scrollbar="false">
|
<scroll-view class="content" :class="{ 'content-immersive': isImmersiveTab }" scroll-y :enhanced="true" :show-scrollbar="false">
|
||||||
<ScriptView v-if="activeTab === 'script'" />
|
<ScriptView v-if="activeTab === 'script'" />
|
||||||
<RecordView v-if="activeTab === 'record'" />
|
<RecordView v-if="activeTab === 'record'" />
|
||||||
<MineView v-if="activeTab === 'mine'" />
|
<MineView v-if="activeTab === 'mine'" />
|
||||||
|
<ScriptLibraryView v-if="activeTab === 'library'" />
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<MusicPlayer ref="musicPlayer" />
|
<MusicPlayer ref="musicPlayer" />
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<text>人生轨迹</text>
|
<text>人生轨迹</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="nav-item" :class="{ active: activeTab === 'script' }" @click="switchTab('script')">
|
<view class="nav-item" :class="{ active: activeTab === 'script' || activeTab === 'library' }" @click="switchTab('script')">
|
||||||
<view class="tab-icon book-star-icon">
|
<view class="tab-icon book-star-icon">
|
||||||
<view class="book-page left"></view>
|
<view class="book-page left"></view>
|
||||||
<view class="book-page right"></view>
|
<view class="book-page right"></view>
|
||||||
@@ -47,12 +48,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useAppStore } from '../../stores/app.js'
|
import { useAppStore } from '../../stores/app.js'
|
||||||
import RecordView from './RecordView.vue'
|
import RecordView from './RecordView.vue'
|
||||||
import ScriptView from './ScriptView.vue'
|
import ScriptView from './ScriptView.vue'
|
||||||
import MineView from './MineView.vue'
|
import MineView from './MineView.vue'
|
||||||
|
import ScriptLibraryView from './ScriptLibraryView.vue'
|
||||||
import MusicPlayer from '../../components/MusicPlayer.vue'
|
import MusicPlayer from '../../components/MusicPlayer.vue'
|
||||||
import analytics from '../../services/analytics.js'
|
import analytics from '../../services/analytics.js'
|
||||||
import { useMenuButtonSafeArea } from '../../composables/useMenuButtonSafeArea.js'
|
import { useMenuButtonSafeArea } from '../../composables/useMenuButtonSafeArea.js'
|
||||||
@@ -61,7 +63,8 @@ const store = useAppStore()
|
|||||||
const activeTab = ref('script')
|
const activeTab = ref('script')
|
||||||
const pagePath = '/pages/main/index'
|
const pagePath = '/pages/main/index'
|
||||||
const { capsuleTopReservePx } = useMenuButtonSafeArea({ extraTopPx: 10 })
|
const { capsuleTopReservePx } = useMenuButtonSafeArea({ extraTopPx: 10 })
|
||||||
const validTabs = ['script', 'record', 'mine']
|
const validTabs = ['script', 'record', 'mine', 'library']
|
||||||
|
const isImmersiveTab = computed(() => ['script', 'mine'].includes(activeTab.value))
|
||||||
|
|
||||||
const normalizeTab = (tab) => validTabs.includes(tab) ? tab : 'script'
|
const normalizeTab = (tab) => validTabs.includes(tab) ? tab : 'script'
|
||||||
|
|
||||||
@@ -174,6 +177,11 @@ onUnmounted(() => {
|
|||||||
padding: 0 28rpx 132rpx;
|
padding: 0 28rpx 132rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-immersive {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.bottom-nav {
|
.bottom-nav {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ import { useAppStore } from '../../stores/app.js'
|
|||||||
import { useMenuButtonSafeArea } from '../../composables/useMenuButtonSafeArea.js'
|
import { useMenuButtonSafeArea } from '../../composables/useMenuButtonSafeArea.js'
|
||||||
|
|
||||||
const store = useAppStore()
|
const store = useAppStore()
|
||||||
const { capsuleTopReservePx, topbarStyle } = useMenuButtonSafeArea({ extraTopPx: 10 })
|
const { capsuleTopReservePx, topbarStyle } = useMenuButtonSafeArea({ extraTopPx: 2 })
|
||||||
const isEdit = ref(false)
|
const isEdit = ref(false)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
const birthday = ref('')
|
const birthday = ref('')
|
||||||
@@ -372,23 +372,23 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
height: 92rpx;
|
height: 72rpx;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 90rpx 1fr 90rpx;
|
grid-template-columns: 76rpx 1fr 76rpx;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 32rpx;
|
padding: 0 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back {
|
.back {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 68rpx;
|
font-size: 56rpx;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 36rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
.save {
|
.save {
|
||||||
color: #b94cff;
|
color: #b94cff;
|
||||||
font-size: 28rpx;
|
font-size: 26rpx;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,35 +408,36 @@ onMounted(() => {
|
|||||||
height: 0;
|
height: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 0 28rpx 28rpx;
|
padding: 0 24rpx 28rpx;
|
||||||
|
margin-top: -6rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.glass-card {
|
.glass-card {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1rpx solid rgba(124, 75, 255, 0.34);
|
border: 1rpx solid rgba(155, 110, 255, 0.14);
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 92% 12%, rgba(104, 66, 255, 0.14), transparent 34%),
|
radial-gradient(circle at 92% 12%, rgba(104, 66, 255, 0.1), transparent 34%),
|
||||||
rgba(10, 13, 43, 0.74);
|
rgba(10, 13, 43, 0.54);
|
||||||
box-shadow: inset 0 0 34rpx rgba(123, 60, 255, 0.08), 0 14rpx 48rpx rgba(0, 0, 0, 0.22);
|
box-shadow: inset 0 0 30rpx rgba(123, 60, 255, 0.05), 0 10rpx 36rpx rgba(0, 0, 0, 0.16);
|
||||||
backdrop-filter: blur(24rpx);
|
backdrop-filter: blur(24rpx);
|
||||||
-webkit-backdrop-filter: blur(24rpx);
|
-webkit-backdrop-filter: blur(24rpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-card {
|
.hero-card {
|
||||||
min-height: 190rpx;
|
min-height: 156rpx;
|
||||||
border-radius: 24rpx;
|
border-radius: 22rpx;
|
||||||
margin-bottom: 22rpx;
|
margin-bottom: 18rpx;
|
||||||
padding: 22rpx 28rpx;
|
padding: 18rpx 24rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 28rpx;
|
gap: 22rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-wrap {
|
.avatar-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 136rpx;
|
width: 118rpx;
|
||||||
height: 136rpx;
|
height: 118rpx;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 5rpx;
|
padding: 5rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -455,8 +456,8 @@ onMounted(() => {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: -4rpx;
|
right: -4rpx;
|
||||||
bottom: -2rpx;
|
bottom: -2rpx;
|
||||||
width: 42rpx;
|
width: 38rpx;
|
||||||
height: 42rpx;
|
height: 38rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: linear-gradient(135deg, #8f4dff, #582cff);
|
background: linear-gradient(135deg, #8f4dff, #582cff);
|
||||||
box-shadow: 0 0 18rpx rgba(158, 91, 255, 0.62);
|
box-shadow: 0 0 18rpx rgba(158, 91, 255, 0.62);
|
||||||
@@ -465,7 +466,7 @@ onMounted(() => {
|
|||||||
.pen-icon {
|
.pen-icon {
|
||||||
width: 17rpx;
|
width: 17rpx;
|
||||||
height: 6rpx;
|
height: 6rpx;
|
||||||
margin: 18rpx auto;
|
margin: 16rpx auto;
|
||||||
border-radius: 999rpx;
|
border-radius: 999rpx;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
@@ -486,20 +487,20 @@ onMounted(() => {
|
|||||||
|
|
||||||
.hero-name {
|
.hero-name {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 42rpx;
|
font-size: 34rpx;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-star {
|
.hero-star {
|
||||||
font-size: 26rpx;
|
font-size: 22rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-sub {
|
.hero-sub {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 12rpx;
|
margin-top: 8rpx;
|
||||||
color: rgba(239, 232, 255, 0.84);
|
color: rgba(239, 232, 255, 0.84);
|
||||||
font-size: 25rpx;
|
font-size: 23rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-line {
|
.hero-line {
|
||||||
@@ -511,9 +512,9 @@ onMounted(() => {
|
|||||||
|
|
||||||
.hero-quote {
|
.hero-quote {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 14rpx;
|
margin-top: 12rpx;
|
||||||
color: #b94cff;
|
color: #b94cff;
|
||||||
font-size: 25rpx;
|
font-size: 23rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,9 +551,9 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
border-radius: 24rpx;
|
border-radius: 22rpx;
|
||||||
margin-bottom: 18rpx;
|
margin-bottom: 18rpx;
|
||||||
padding: 24rpx;
|
padding: 22rpx 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-head,
|
.section-head,
|
||||||
@@ -572,7 +573,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
color: rgba(239, 232, 255, 0.9);
|
color: rgba(239, 232, 255, 0.9);
|
||||||
font-size: 25rpx;
|
font-size: 24rpx;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,9 +660,9 @@ onMounted(() => {
|
|||||||
.bio-title-icon::after { top: 15rpx; }
|
.bio-title-icon::after { top: 15rpx; }
|
||||||
|
|
||||||
.profile-row {
|
.profile-row {
|
||||||
min-height: 64rpx;
|
min-height: 60rpx;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 154rpx 1fr 24rpx;
|
grid-template-columns: 142rpx 1fr 24rpx;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-top: 1rpx solid rgba(180, 139, 255, 0.16);
|
border-top: 1rpx solid rgba(180, 139, 255, 0.16);
|
||||||
}
|
}
|
||||||
@@ -672,14 +673,14 @@ onMounted(() => {
|
|||||||
|
|
||||||
.row-label {
|
.row-label {
|
||||||
color: rgba(205, 191, 238, 0.82);
|
color: rgba(205, 191, 238, 0.82);
|
||||||
font-size: 24rpx;
|
font-size: 23rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row-input,
|
.row-input,
|
||||||
.row-value {
|
.row-value {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
color: rgba(255, 255, 255, 0.9);
|
color: rgba(255, 255, 255, 0.9);
|
||||||
font-size: 24rpx;
|
font-size: 23rpx;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,7 +694,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
.chevron {
|
.chevron {
|
||||||
color: rgba(218, 204, 243, 0.7);
|
color: rgba(218, 204, 243, 0.7);
|
||||||
font-size: 44rpx;
|
font-size: 38rpx;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
@@ -729,26 +730,28 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.astro-panel {
|
.astro-panel {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 1fr 1fr;
|
flex-direction: column;
|
||||||
margin-top: 8rpx;
|
gap: 22rpx;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
padding-top: 16rpx;
|
||||||
border-top: 1rpx solid rgba(180, 139, 255, 0.16);
|
border-top: 1rpx solid rgba(180, 139, 255, 0.16);
|
||||||
}
|
}
|
||||||
|
|
||||||
.astro-col {
|
.astro-col {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 18rpx 18rpx 0 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mbti-col {
|
.mbti-col {
|
||||||
border-left: 1rpx solid rgba(180, 139, 255, 0.18);
|
border-left: 0;
|
||||||
padding-left: 18rpx;
|
padding-top: 18rpx;
|
||||||
padding-right: 0;
|
border-top: 1rpx solid rgba(180, 139, 255, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.astro-title-row {
|
.astro-title-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 34rpx 74rpx 1fr 18rpx;
|
grid-template-columns: 34rpx 76rpx 1fr 18rpx;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8rpx;
|
gap: 8rpx;
|
||||||
}
|
}
|
||||||
@@ -773,26 +776,26 @@ onMounted(() => {
|
|||||||
|
|
||||||
.astro-title {
|
.astro-title {
|
||||||
color: rgba(222, 211, 240, 0.76);
|
color: rgba(222, 211, 240, 0.76);
|
||||||
font-size: 24rpx;
|
font-size: 23rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.astro-current {
|
.astro-current {
|
||||||
color: rgba(255, 255, 255, 0.9);
|
color: rgba(255, 255, 255, 0.9);
|
||||||
font-size: 23rpx;
|
font-size: 22rpx;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-title {
|
.select-title {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 22rpx;
|
margin-top: 16rpx;
|
||||||
color: rgba(222, 211, 240, 0.72);
|
color: rgba(222, 211, 240, 0.72);
|
||||||
font-size: 21rpx;
|
font-size: 21rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zodiac-grid {
|
.zodiac-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: 14rpx 8rpx;
|
gap: 14rpx 10rpx;
|
||||||
margin-top: 14rpx;
|
margin-top: 14rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,20 +804,20 @@ onMounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8rpx;
|
gap: 7rpx;
|
||||||
color: rgba(226, 217, 246, 0.84);
|
color: rgba(226, 217, 246, 0.84);
|
||||||
font-size: 19rpx;
|
font-size: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zodiac-bubble {
|
.zodiac-bubble {
|
||||||
width: 48rpx;
|
width: 44rpx;
|
||||||
height: 48rpx;
|
height: 44rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #a855ff;
|
color: #a855ff;
|
||||||
font-size: 28rpx;
|
font-size: 26rpx;
|
||||||
background: rgba(124, 58, 237, 0.28);
|
background: rgba(124, 58, 237, 0.28);
|
||||||
border: 1rpx solid rgba(173, 84, 255, 0.36);
|
border: 1rpx solid rgba(173, 84, 255, 0.36);
|
||||||
}
|
}
|
||||||
@@ -829,12 +832,12 @@ onMounted(() => {
|
|||||||
.mbti-grid {
|
.mbti-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: 12rpx;
|
gap: 12rpx 14rpx;
|
||||||
margin-top: 14rpx;
|
margin-top: 14rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mbti-chip {
|
.mbti-chip {
|
||||||
height: 42rpx;
|
height: 40rpx;
|
||||||
font-size: 20rpx;
|
font-size: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user