5672 lines
136 KiB
Vue
5672 lines
136 KiB
Vue
<template>
|
||
<view>
|
||
<view>
|
||
<view v-show="getBobbiesList.reg_step == 1 || getBobbiesList.reg_step == 2 || getBobbiesList.reg_step == 3">
|
||
<uni-nav-bar fixed statusBar background-color="transparent" :border="false" title="定制专属女友"></uni-nav-bar>
|
||
<view class="back"></view>
|
||
<view class="body">
|
||
<view class="list">
|
||
<image class="list_logo" v-if="getBobbiesList.reg_step == 1"
|
||
src="https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251231/a6d2dae70029b6465ea1f1f605f77258.png"
|
||
mode="aspectFill"></image>
|
||
<image class="list_logo" v-if="getBobbiesList.reg_step == 2"
|
||
src="https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251231/69c72922c0e815086a30c370e7dbb42f.png"
|
||
mode="aspectFill"></image>
|
||
<image class="list_logo" v-if="getBobbiesList.reg_step == 3"
|
||
src="https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251231/69c72922c0e815086a30c370e7dbb42f.png"
|
||
mode="aspectFill"></image>
|
||
<view class="list_content faj" v-if="getBobbiesList.reg_step == 1" @click="tocreate">
|
||
<view class="list_title">完善个人资料</view>
|
||
<image class="list_next" src="/static/images/index_next.png" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="list_content faj" v-if="getBobbiesList.reg_step == 2" @click="tocreateLover">
|
||
<view class="list_title">完善恋人资料
|
||
</view>
|
||
<image class="list_next" src="/static/images/index_next.png" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="list_content faj" v-if="getBobbiesList.reg_step == 3" @click="togenerate">
|
||
<view class="list_title">生成专属恋人
|
||
</view>
|
||
<image class="list_next" src="/static/images/index_next.png" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="list_module faj">
|
||
<view class="list_item" :class="{ 'list_active': getBobbiesList.reg_step == 1 }"></view>
|
||
<view class="list_item" :class="{ 'list_active': getBobbiesList.reg_step == 2 }"></view>
|
||
<view class="list_item" :class="{ 'list_active': getBobbiesList.reg_step == 3 }"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view v-show="getBobbiesList.reg_step == 4">
|
||
<!-- Tab 栏 - 固定在顶部 -->
|
||
<view class="tab-container" v-if="getBobbiesList.reg_step == 4">
|
||
<scroll-view class="tab-scroll" scroll-x="true" show-scrollbar="false" :scroll-into-view="tabIntoView" scroll-with-animation="true">
|
||
<view class="tab-list">
|
||
<view
|
||
v-for="(tab, index) in tabs"
|
||
:key="index"
|
||
:id="'tab-' + index"
|
||
class="tab-item"
|
||
:class="{ 'active': currentTab === index }"
|
||
@click="switchTab(index)">
|
||
<text class="tab-name">{{ tab.name }}</text>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
|
||
<!-- Swiper 内容区域 - 自定义细线指示器 -->
|
||
<swiper
|
||
v-if="getBobbiesList.reg_step == 4"
|
||
class="swiper-container"
|
||
:current="currentTab"
|
||
@change="onSwiperChange"
|
||
:duration="300"
|
||
:indicator-dots="false">
|
||
|
||
<!-- 商城页面 (index 0) - 精美设计 -->
|
||
<swiper-item>
|
||
<view class="swiper-content shop-page">
|
||
<!-- 全屏商城背景 -->
|
||
<view class="shop-hero" @click="openShopLink">
|
||
<!-- 背景渐变 -->
|
||
<view class="shop-hero-bg"></view>
|
||
|
||
<!-- 装饰圆圈 -->
|
||
<view class="shop-decoration">
|
||
<view class="shop-circle shop-circle-1"></view>
|
||
<view class="shop-circle shop-circle-2"></view>
|
||
<view class="shop-circle shop-circle-3"></view>
|
||
<view class="shop-circle shop-circle-4"></view>
|
||
</view>
|
||
|
||
<!-- 内容区域 -->
|
||
<view class="shop-hero-content">
|
||
<!-- 顶部标签 -->
|
||
<view class="shop-hot-badge">
|
||
<text class="shop-hot-icon">💎</text>
|
||
<text class="shop-hot-text">精品商城</text>
|
||
</view>
|
||
|
||
<!-- 商城图标 -->
|
||
<view class="shop-icon-wrapper">
|
||
<image class="shop-main-icon" src="/static/images/member_logo.png" mode="aspectFit"></image>
|
||
<view class="shop-icon-glow"></view>
|
||
</view>
|
||
|
||
<!-- 标题 -->
|
||
<view class="shop-hero-title">超值优惠</view>
|
||
<view class="shop-hero-subtitle">海量道具 · 限时特惠 · 每日上新</view>
|
||
|
||
<!-- 特色标签 -->
|
||
<view class="shop-features-grid">
|
||
<view class="shop-feature-card">
|
||
<text class="shop-feature-emoji">🎁</text>
|
||
<text class="shop-feature-label">新人礼包</text>
|
||
</view>
|
||
<view class="shop-feature-card">
|
||
<text class="shop-feature-emoji">⚡</text>
|
||
<text class="shop-feature-label">限时秒杀</text>
|
||
</view>
|
||
<view class="shop-feature-card">
|
||
<text class="shop-feature-emoji">💰</text>
|
||
<text class="shop-feature-label">超值折扣</text>
|
||
</view>
|
||
<view class="shop-feature-card">
|
||
<text class="shop-feature-emoji">🔥</text>
|
||
<text class="shop-feature-label">热门推荐</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 进入按钮 -->
|
||
<view class="shop-enter-button">
|
||
<text class="shop-enter-text">立即进入商城</text>
|
||
<text class="shop-enter-arrow">→</text>
|
||
</view>
|
||
|
||
<!-- 提示文字 -->
|
||
<view class="shop-hint">
|
||
<text class="shop-hint-icon">✨</text>
|
||
<text class="shop-hint-text">点击任意位置进入商城</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
<!-- 首页内容 (index 1) -->
|
||
<swiper-item>
|
||
<view class="home-page">
|
||
<!-- 顶部操作栏 -->
|
||
<view class="home-header">
|
||
<view class="home-header-btn" @click="toreplacement">
|
||
<image class="home-header-icon" src="/static/images/replacement_switch.png" mode="aspectFit"></image>
|
||
<text class="home-header-text">装扮设置</text>
|
||
</view>
|
||
<view class="home-header-spacer"></view>
|
||
<view class="home-header-btn" @click="todynamics">
|
||
<image class="home-header-icon" src="/static/images/dynamics_logo.png" mode="aspectFit"></image>
|
||
<text class="home-header-text">朋友圈</text>
|
||
</view>
|
||
<view class="home-header-btn" @click="tointimacy">
|
||
<image class="home-header-icon" src="/static/images/index_intimate.png" mode="aspectFit"></image>
|
||
<text class="home-header-text">邀请入驻</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 选择互动对象 -->
|
||
<view class="home-title">
|
||
<text class="home-title-icon">✦</text>
|
||
<text class="home-title-text">选择一位互动对象</text>
|
||
<text class="home-title-icon">✦</text>
|
||
<text class="home-title-more" @click="toreplacement">搜索更多</text>
|
||
</view>
|
||
|
||
<!-- 主卡片区域 -->
|
||
<view class="home-card">
|
||
<view class="home-card-inner">
|
||
<!-- 女友名字 -->
|
||
<view class="home-card-name">{{ loverBasicList && loverBasicList.name ? loverBasicList.name : '简寻' }}</view>
|
||
|
||
<!-- 女友图片 -->
|
||
<image
|
||
class="home-card-image"
|
||
:src="loverBasicList && loverBasicList.image_url ? loverBasicList.image_url : 'https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251226/008a06f2c3fccdac714f25e6577ccdc4.png'"
|
||
mode="aspectFill">
|
||
</image>
|
||
|
||
<!-- 性格标签 -->
|
||
<view class="home-card-tags">
|
||
<view class="home-card-tag">多面伪神</view>
|
||
<view class="home-card-tag">甜蜜贴心</view>
|
||
</view>
|
||
|
||
<!-- 对话气泡 -->
|
||
<view class="home-card-bubble">
|
||
<text class="home-card-bubble-text">靠近点,再近点…你就能看清我眼里藏着什么了。</text>
|
||
</view>
|
||
|
||
<!-- 底部操作按钮 -->
|
||
<view class="home-card-actions">
|
||
<view class="home-card-btn home-card-btn-home" @click="tointimacy">
|
||
<image class="home-card-btn-icon" src="/static/images/index_intimate.png" mode="aspectFit"></image>
|
||
</view>
|
||
<view class="home-card-btn home-card-btn-chat" @click="tochat">
|
||
<text class="home-card-btn-text">和TA聊天</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部头像轮播 -->
|
||
<view class="home-avatars">
|
||
<view
|
||
class="home-avatar-item"
|
||
v-for="(look, index) in homeLooksList"
|
||
:key="look.id"
|
||
:class="{ 'home-avatar-active': selectedLookId === look.id }"
|
||
@click="switchLook(look)">
|
||
<image
|
||
class="home-avatar-img"
|
||
:src="look.image_url"
|
||
mode="aspectFill">
|
||
</image>
|
||
</view>
|
||
<!-- 如果形象栏为空,显示默认头像 -->
|
||
<view class="home-avatar-item" v-if="!homeLooksList || homeLooksList.length === 0">
|
||
<image
|
||
class="home-avatar-img"
|
||
:src="loverBasicList && loverBasicList.image_url ? loverBasicList.image_url : 'https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251226/008a06f2c3fccdac714f25e6577ccdc4.png'"
|
||
mode="aspectFill">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 商城入口横幅 -->
|
||
<view class="home-shop-banner" @click="openShopLink">
|
||
<!-- 背景装饰 -->
|
||
<view class="home-shop-bg">
|
||
<view class="home-shop-circle home-shop-circle-1"></view>
|
||
<view class="home-shop-circle home-shop-circle-2"></view>
|
||
<view class="home-shop-circle home-shop-circle-3"></view>
|
||
</view>
|
||
|
||
<!-- 内容区域 -->
|
||
<view class="home-shop-content">
|
||
<!-- 左侧图标和文字 -->
|
||
<view class="home-shop-left">
|
||
<view class="home-shop-icon-wrapper">
|
||
<image class="home-shop-icon" src="/static/images/member_logo.png" mode="aspectFit"></image>
|
||
<view class="home-shop-badge">HOT</view>
|
||
</view>
|
||
<view class="home-shop-text">
|
||
<view class="home-shop-title">
|
||
<text class="home-shop-title-main">精品商城</text>
|
||
<text class="home-shop-title-emoji">🛒</text>
|
||
</view>
|
||
<view class="home-shop-desc">海量道具 · 超值优惠</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 右侧按钮 -->
|
||
<view class="home-shop-button">
|
||
<text class="home-shop-button-text">立即前往</text>
|
||
<text class="home-shop-button-arrow">→</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 闪光效果 -->
|
||
<view class="home-shop-shine"></view>
|
||
</view>
|
||
|
||
<!-- 好感度信息(可选,放在底部) -->
|
||
<view class="home-intimacy" @click="tointimacy">
|
||
<view class="home-intimacy-level">Lv.{{ getBobbiesList.level ? getBobbiesList.level : 0 }}</view>
|
||
<view class="home-intimacy-bar">
|
||
<view class="home-intimacy-progress" :style="{ width: calculateProgressPercent() + '%' }"></view>
|
||
</view>
|
||
<view class="home-intimacy-text">{{ getBobbiesList.intimacy ? getBobbiesList.intimacy : 0 }}/{{ getBobbiesList.next_level_intimacy ? getBobbiesList.next_level_intimacy : 0 }}</view>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
<!-- 聊天页面 (index 1) - 嵌入完整聊天功能 -->
|
||
<swiper-item>
|
||
<view class="chat-swiper-page">
|
||
<!-- 聊天消息列表 -->
|
||
<scroll-view
|
||
class="chat-message-scroll"
|
||
scroll-y="true"
|
||
:scroll-into-view="chatIntoView"
|
||
scroll-with-animation="true">
|
||
<view class="chat-message-list">
|
||
<view
|
||
v-for="(msg, index) in chatMessages"
|
||
:key="index"
|
||
class="chat-message-item"
|
||
:class="msg.role === 'user' ? 'message-right' : 'message-left'">
|
||
<image
|
||
class="chat-avatar"
|
||
:src="msg.role === 'user' ? chatUserAvatar : chatLoverAvatar"
|
||
mode="aspectFill">
|
||
</image>
|
||
<view class="chat-message-bubble">
|
||
<text class="chat-message-text">{{ msg.content }}</text>
|
||
</view>
|
||
</view>
|
||
<view id="chat-bottom"></view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 底部输入框 -->
|
||
<view class="chat-input-bar">
|
||
<input
|
||
class="chat-message-input"
|
||
v-model="chatInputText"
|
||
placeholder="输入消息..."
|
||
confirm-type="send"
|
||
:adjust-position="true"
|
||
:hold-keyboard="false"
|
||
@confirm="sendChatMessage"
|
||
@blur="onInputBlur"
|
||
/>
|
||
<view class="chat-send-btn" @click="sendChatMessage">
|
||
<text>发送</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
<!-- 唱歌页面 (index 2) -->
|
||
<swiper-item>
|
||
<view class="sing-page">
|
||
<!-- Tab 切换 -->
|
||
<view class="sing-tabs">
|
||
<view
|
||
class="sing-tab-item"
|
||
:class="{ 'sing-tab-active': singCurrentTab === 'songs' }"
|
||
@click="switchSingTab('songs')">
|
||
<text>系统歌曲</text>
|
||
</view>
|
||
<view
|
||
class="sing-tab-item"
|
||
:class="{ 'sing-tab-active': singCurrentTab === 'library' }"
|
||
@click="switchSingTab('library')">
|
||
<text>音乐库</text>
|
||
</view>
|
||
<view
|
||
class="sing-tab-item"
|
||
:class="{ 'sing-tab-active': singCurrentTab === 'history' }"
|
||
@click="switchSingTab('history')">
|
||
<text>历史记录</text>
|
||
</view>
|
||
</view>
|
||
|
||
<scroll-view class="sing-scroll" scroll-y="true">
|
||
<!-- 系统歌曲列表 -->
|
||
<view v-if="singCurrentTab === 'songs'" class="sing-content">
|
||
<view class="section-title">选择歌曲</view>
|
||
<view class="song-list">
|
||
<view class="song-item" v-for="(item,index) in singSongsList" :key="index" @click="selectSongDirect(item)">
|
||
<view class="song-info">
|
||
<text class="song-title">{{item.title}}</text>
|
||
</view>
|
||
<image class="song-icon" src="/static/images/chat_a6.png" mode="widthFix"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 音乐库 -->
|
||
<view v-if="singCurrentTab === 'library'" class="sing-content">
|
||
<!-- 添加音乐按钮 -->
|
||
<view class="music-add-btns">
|
||
<view class="music-add-btn" @click="showAddMusicModal">
|
||
<text class="music-add-icon">➕</text>
|
||
<text class="music-add-text">添加音乐</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 音乐库列表 -->
|
||
<view class="music-library-list">
|
||
<view class="music-library-item" v-for="(item, index) in musicLibraryList" :key="item.id">
|
||
<view class="music-library-cover">
|
||
<image
|
||
class="music-cover-img"
|
||
:src="item.cover_url || '/static/images/avatar.png'"
|
||
mode="aspectFill">
|
||
</image>
|
||
<view class="music-play-overlay" @click="selectMusicFromLibrary(item)">
|
||
<text class="music-play-icon">▶</text>
|
||
</view>
|
||
</view>
|
||
<view class="music-library-info">
|
||
<view class="music-library-title">{{item.title}}</view>
|
||
<view class="music-library-artist">{{item.artist || '未知艺术家'}}</view>
|
||
<view class="music-library-meta">
|
||
<text class="music-meta-item">👤 {{item.username}}</text>
|
||
<text class="music-meta-item">▶ {{item.play_count}}</text>
|
||
<text class="music-meta-item" @click.stop="toggleMusicLike(item)">
|
||
{{item.is_liked ? '❤️' : '🤍'}} {{item.like_count}}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 加载更多 -->
|
||
<view v-if="musicLibraryHasMore" class="music-load-more" @click="loadMoreMusic">
|
||
<text>加载更多</text>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view v-if="musicLibraryList.length === 0" class="music-empty">
|
||
<text class="music-empty-icon">🎵</text>
|
||
<text class="music-empty-text">音乐库还没有歌曲</text>
|
||
<text class="music-empty-desc">快来添加第一首歌吧!</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 历史记录 -->
|
||
<view v-if="singCurrentTab === 'history'" class="sing-content">
|
||
<view class="history-list" v-if="singHistoryList.length > 0">
|
||
<view class="history-item" v-for="(item,index) in singHistoryList" :key="'history-'+index">
|
||
<view class="history-info">
|
||
<text class="history-title">{{item.song_title}}</text>
|
||
<text class="history-date">{{formatDate(item.created_at)}}</text>
|
||
</view>
|
||
<view class="history-actions">
|
||
<view class="history-btn" @click="playSingVideo(item.video_url)">播放</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view v-else class="music-empty">
|
||
<text class="music-empty-icon">📼</text>
|
||
<text class="music-empty-text">还没有历史记录</text>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
<!-- 跳舞页面 (index 3) -->
|
||
<swiper-item>
|
||
<view class="swiper-content feature-page">
|
||
<view class="feature-icon">💃</view>
|
||
<view class="feature-title">跳舞功能</view>
|
||
<view class="feature-desc">让她为你跳一支舞</view>
|
||
<scroll-view class="feature-scroll" scroll-y="true">
|
||
<view class="history-section" v-if="danceHistoryList.length > 0">
|
||
<view class="history-section-header">
|
||
<view class="section-title">历史视频</view>
|
||
<view class="section-more" @click="openHistoryModal('dance', 'all')">查看全部</view>
|
||
</view>
|
||
<view class="history-list">
|
||
<view class="history-item" v-for="(item,index) in danceHistoryList.slice(0, 2)" :key="'dance-history-'+index">
|
||
<view class="history-info">
|
||
<text class="history-title">{{item.prompt || '跳舞视频'}}</text>
|
||
<text class="history-date">{{formatDate(item.created_at)}}</text>
|
||
</view>
|
||
<view class="history-actions">
|
||
<view class="history-btn" @click="playDanceVideo(item.video_url)">播放</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="dance-form">
|
||
<textarea
|
||
class="dance-input"
|
||
v-model="dancePrompt"
|
||
placeholder="描述你想看的舞蹈动作"
|
||
maxlength="200" />
|
||
<view class="dance-btn" @click="requestDance">生成舞蹈视频</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
<!-- 换服装页面 (index 4) -->
|
||
<swiper-item>
|
||
<scroll-view class="swiper-scroll" scroll-y="true">
|
||
<view class="outfit-container">
|
||
<view class="outfit-header">
|
||
<view class="outfit-title">换装</view>
|
||
<view class="outfit-count" v-if="outfitListInfo && outfitListInfo.clothes_num != null">剩余次数:{{ outfitListInfo.clothes_num }}次</view>
|
||
</view>
|
||
<view class="outfit-loading" v-if="!outfitListInfo">加载中...</view>
|
||
<view class="outfit-content" v-else>
|
||
<view class="outfit-section" v-if="outfitListInfo.top && outfitListInfo.top.length">
|
||
<view class="section-title">上衣</view>
|
||
<view class="outfit-grid-wrapper">
|
||
<view class="outfit-item-wrapper" v-for="(item, idx) in outfitListInfo.top" :key="'top-'+idx" :class="isSelectedTop(item.id) ? 'outfit-grid-item-selected' : ''" @click="selectTop(item)">
|
||
<view class="outfit-grid-inner">
|
||
<image class="outfit-grid-img" :src="item.image_url ? item.image_url : '/static/images/replacement_pictureA.png'" mode="aspectFill"></image>
|
||
<view class="outfit-check-mark" v-if="isSelectedTop(item.id)">✓</view>
|
||
<view class="outfit-grid-badge" v-if="item.is_current">使用中</view>
|
||
<view class="outfit-grid-lock" v-if="item.is_lock && !item.is_free">🔒</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="outfit-section" v-if="outfitListInfo.bottom && outfitListInfo.bottom.length">
|
||
<view class="section-title">下装</view>
|
||
<view class="outfit-grid-wrapper">
|
||
<view class="outfit-item-wrapper" v-for="(item, idx) in outfitListInfo.bottom" :key="'bottom-'+idx" :class="isSelectedBottom(item.id) ? 'outfit-grid-item-selected' : ''" @click="selectBottom(item)">
|
||
<view class="outfit-grid-inner">
|
||
<image class="outfit-grid-img" :src="item.image_url ? item.image_url : '/static/images/replacement_pictureA.png'" mode="aspectFill"></image>
|
||
<view class="outfit-check-mark" v-if="isSelectedBottom(item.id)">✓</view>
|
||
<view class="outfit-grid-badge" v-if="item.is_current">使用中</view>
|
||
<view class="outfit-grid-lock" v-if="item.is_lock && !item.is_free">🔒</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="outfit-section" v-if="outfitListInfo.dress && outfitListInfo.dress.length">
|
||
<view class="section-title">连体服</view>
|
||
<view class="outfit-grid-wrapper">
|
||
<view class="outfit-item-wrapper" v-for="(item, idx) in outfitListInfo.dress" :key="'dress-'+idx" :class="isSelectedDress(item.id) ? 'outfit-grid-item-selected' : ''" @click="selectDress(item)">
|
||
<view class="outfit-grid-inner">
|
||
<image class="outfit-grid-img" :src="item.image_url ? item.image_url : '/static/images/replacement_pictureA.png'" mode="aspectFill"></image>
|
||
<view class="outfit-check-mark" v-if="isSelectedDress(item.id)">✓</view>
|
||
<view class="outfit-grid-badge" v-if="item.is_current">使用中</view>
|
||
<view class="outfit-grid-lock" v-if="item.is_lock && !item.is_free">🔒</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="outfit-generate-btn" @click="toggleSaveToLook">{{ outfitSaveToLook ? '已勾选:保存到形象栏' : '勾选:保存到形象栏' }}</view>
|
||
<view class="outfit-generate-btn" @click="confirmOutfitChange">换装</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</swiper-item>
|
||
|
||
<!-- 刷礼物页面 (index 5) -->
|
||
<swiper-item>
|
||
<view class="swiper-content gift-page">
|
||
<view class="gift-header">
|
||
<view class="gift-header-title">🎁 礼物匣</view>
|
||
<view class="gift-header-desc">送她一份心意</view>
|
||
<view class="gift-intimacy-bar">
|
||
<view class="gift-intimacy-label">当前好感度</view>
|
||
<view class="gift-intimacy-info">
|
||
<text class="gift-intimacy-level">Lv.{{ getBobbiesList.level ? getBobbiesList.level : 0 }}</text>
|
||
<view class="gift-intimacy-progress">
|
||
<view class="gift-intimacy-progress-bar" :style="{ width: calculateProgressPercent() + '%' }"></view>
|
||
</view>
|
||
<text class="gift-intimacy-value">{{ getBobbiesList.intimacy ? getBobbiesList.intimacy : 0 }}/{{ getBobbiesList.next_level_intimacy ? getBobbiesList.next_level_intimacy : 0 }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<scroll-view class="gift-scroll" scroll-y="true">
|
||
<view class="gift-list">
|
||
<view class="gift-item" v-for="(item, index) in giftOptions" :key="index" @click="giftGiftClick(index)">
|
||
<view class="gift-item-inner">
|
||
<image class="gift-item-img" :src="giftGlobal + item.image" mode="aspectFit"></image>
|
||
<view class="gift-item-name">{{ item.name }}</view>
|
||
<view class="gift-item-price">{{ item.price }}金币</view>
|
||
<view class="gift-item-intimacy">+{{ item.intimacy_value }}好感</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 礼物详情弹窗 -->
|
||
<view class="gift-modal" v-if="giftStats" @click.self="giftCloseClick()">
|
||
<view class="gift-modal-content">
|
||
<view class="gift-modal-header">
|
||
<text class="gift-modal-title">礼物详情</text>
|
||
<image class="gift-modal-close" src="/static/images/close.png" @click="giftCloseClick()"></image>
|
||
</view>
|
||
|
||
<view class="gift-modal-body">
|
||
<image class="gift-modal-img" :src="giftGlobal + (giftInfoOptions && giftInfoOptions.image ? giftInfoOptions.image : '')" mode="aspectFit"></image>
|
||
|
||
<view class="gift-modal-info">
|
||
<view class="gift-modal-name">{{ giftInfoOptions && giftInfoOptions.name ? giftInfoOptions.name : '' }}</view>
|
||
<view class="gift-modal-intimacy">+{{ giftInfoOptions && giftInfoOptions.intimacy_value ? giftInfoOptions.intimacy_value : '0' }} 好感度</view>
|
||
<view class="gift-modal-price">{{ giftInfoOptions && giftInfoOptions.price ? giftInfoOptions.price : '0' }} 金币</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="gift-modal-quantity">
|
||
<text class="gift-modal-quantity-label">数量</text>
|
||
<view class="gift-modal-quantity-control">
|
||
<image class="gift-quantity-btn" src="/static/images/minus.png" @click="giftDecreaseNumber"></image>
|
||
<input class="gift-quantity-input" v-model="giftForm.nums" type="number" />
|
||
<image class="gift-quantity-btn" src="/static/images/add.png" @click="giftIncreaseNumber"></image>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="gift-modal-balance">余额:{{ giftUserInfo && giftUserInfo.money != null ? giftUserInfo.money : 0 }} 金币</view>
|
||
|
||
<view class="gift-modal-btn" @click="giftGiveClick()">
|
||
<text v-if="(Number(giftInfoOptions && giftInfoOptions.price ? giftInfoOptions.price : 0) * Number(giftForm.nums || 0)) > Number(giftUserInfo && giftUserInfo.money != null ? giftUserInfo.money : 0)">充值并赠送</text>
|
||
<text v-else>赠送Ta</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
<!-- 商城页面 (index 6) -->
|
||
<swiper-item>
|
||
<view class="swiper-content" @click="openShopLink">
|
||
<view class="feature-page shop-link-page">
|
||
<view class="feature-icon">🛒</view>
|
||
<view class="feature-title">商城</view>
|
||
<view class="feature-desc">购买更多功能和道具</view>
|
||
<view class="shop-link-banner">
|
||
<image class="shop-banner-img" src="/static/images/member_logo.png" mode="aspectFit"></image>
|
||
<view class="shop-link-text">点击进入商城</view>
|
||
</view>
|
||
<view class="feature-btn shop-external-btn">立即前往 →</view>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
<!-- 短剧页面 (index 7) -->
|
||
<swiper-item>
|
||
<view class="swiper-content drama-page">
|
||
<!-- 全屏海报背景 -->
|
||
<view class="drama-hero" @click="openDramaLink">
|
||
<!-- 背景图片 -->
|
||
<image
|
||
class="drama-hero-bg"
|
||
src="https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251231/a6d2dae70029b6465ea1f1f605f77258.png"
|
||
mode="aspectFill">
|
||
</image>
|
||
|
||
<!-- 渐变遮罩 -->
|
||
<view class="drama-hero-overlay"></view>
|
||
|
||
<!-- 内容区域 -->
|
||
<view class="drama-hero-content">
|
||
<!-- 热门标签 -->
|
||
<view class="drama-hot-badge">
|
||
<text class="drama-hot-icon">🔥</text>
|
||
<text class="drama-hot-text">热门推荐</text>
|
||
</view>
|
||
|
||
<!-- 标题 -->
|
||
<view class="drama-hero-title">精彩短剧</view>
|
||
<view class="drama-hero-subtitle">海量热门短剧等你来看</view>
|
||
|
||
<!-- 标签组 -->
|
||
<view class="drama-tags">
|
||
<view class="drama-tag">💕 甜宠</view>
|
||
<view class="drama-tag">👑 霸总</view>
|
||
<view class="drama-tag">🎭 逆袭</view>
|
||
<view class="drama-tag">⚡ 爽文</view>
|
||
</view>
|
||
|
||
<!-- 播放按钮 -->
|
||
<view class="drama-play-button">
|
||
<view class="drama-play-icon">▶</view>
|
||
<text class="drama-play-text">立即观看</text>
|
||
</view>
|
||
|
||
<!-- 提示文字 -->
|
||
<view class="drama-hint">
|
||
<text class="drama-hint-icon">✨</text>
|
||
<text class="drama-hint-text">点击任意位置进入短剧世界</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部特色推荐(可选) -->
|
||
<view class="drama-features">
|
||
<view class="drama-feature-item">
|
||
<text class="drama-feature-icon">📺</text>
|
||
<text class="drama-feature-text">海量剧集</text>
|
||
</view>
|
||
<view class="drama-feature-item">
|
||
<text class="drama-feature-icon">🆓</text>
|
||
<text class="drama-feature-text">免费观看</text>
|
||
</view>
|
||
<view class="drama-feature-item">
|
||
<text class="drama-feature-icon">⚡</text>
|
||
<text class="drama-feature-text">每日更新</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
|
||
</swiper>
|
||
|
||
<!-- 自定义细线指示器 - 聊天页面时隐藏 -->
|
||
<view class="swiper-indicator" v-if="getBobbiesList.reg_step == 4" :class="{ 'indicator-hidden': currentTab === 2 }">
|
||
<view
|
||
v-for="(tab, index) in tabs"
|
||
:key="index"
|
||
class="indicator-line"
|
||
:class="{ 'active': currentTab === index }">
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 青少年模式弹框 -->
|
||
<under-age :reg-step="getBobbiesList.reg_step" @underAgeStatusChanged="handleUnderAgeStatusChange"></under-age>
|
||
|
||
<!-- 底部 Tab 栏 - 聊天页面时隐藏 -->
|
||
<view class="bottom-tab-bar" :class="{ 'tab-bar-hidden': currentTab === 2 }">
|
||
<tab-bar></tab-bar>
|
||
</view>
|
||
|
||
<!-- 青少年模式遮罩层 -->
|
||
<view v-if="underAgeEnabled" class="underage-overlay">
|
||
<view class="underage-text">已开启青少年模式</view>
|
||
</view>
|
||
|
||
<view v-if="historyModalVisible" class="modal-mask" @click="closeHistoryModal">
|
||
<view class="modal-card" @click.stop>
|
||
<view class="modal-header">
|
||
<view class="modal-title">{{ historyModalType === 'dance' ? (historyModalMode === 'all' ? '跳舞全部历史' : '跳舞历史视频') : (historyModalMode === 'all' ? '唱歌全部历史' : '唱歌历史视频') }}</view>
|
||
<view class="modal-close" @click="closeHistoryModal">关闭</view>
|
||
</view>
|
||
<scroll-view class="modal-list" scroll-y="true">
|
||
<view class="modal-item" v-for="(item,index) in historyModalList" :key="'modal-'+index">
|
||
<view class="modal-item-info">
|
||
<text class="modal-item-title">{{ historyModalType === 'dance' ? (item.prompt || '跳舞视频') : (item.song_title || '唱歌视频') }}</text>
|
||
<text class="modal-item-date">{{ formatDate(item.created_at) }}</text>
|
||
<text v-if="historyModalMode === 'all'" class="modal-item-status">{{ formatHistoryStatus(item) }}</text>
|
||
</view>
|
||
<view class="modal-item-actions">
|
||
<view v-if="item.video_url" class="modal-play" @click="openVideoPlayer(item.video_url)">播放</view>
|
||
<view v-if="historyModalMode === 'all' && item.status === 'failed'" class="modal-retry" @click="retryHistoryItem(item)">重新下载</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="videoPlayerVisible" class="modal-mask" @click="closeVideoPlayer">
|
||
<view class="modal-card" @click.stop>
|
||
<view class="modal-header">
|
||
<view class="modal-title">视频播放</view>
|
||
<view class="modal-close" @click="closeVideoPlayer">关闭</view>
|
||
</view>
|
||
<video class="modal-video" :src="videoPlayerUrl" controls></video>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="singGenerating && currentTab === 2" class="global-block-mask" @touchmove.stop.prevent>
|
||
<view class="global-block-card">
|
||
<view class="global-block-title">正在生成视频中</view>
|
||
<view class="global-block-sub">预计等待15分钟</view>
|
||
<view class="global-block-actions">
|
||
<view class="global-block-btn" @click.stop="cancelSingGeneration">取消生成</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="danceGenerating && currentTab === 3" class="global-block-mask" @touchmove.stop.prevent>
|
||
<view class="global-block-card">
|
||
<view class="global-block-title">正在生成视频中</view>
|
||
<view class="global-block-sub">预计等待15分钟</view>
|
||
<view class="global-block-actions">
|
||
<view class="global-block-btn" @click.stop="cancelDanceGeneration">取消生成</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 添加音乐弹窗 -->
|
||
<view v-if="showMusicModal" class="modal-mask" @click="closeMusicModal">
|
||
<view class="modal-card music-modal-card" @click.stop>
|
||
<view class="modal-header">
|
||
<view class="modal-title">添加音乐</view>
|
||
<view class="modal-close" @click="closeMusicModal">关闭</view>
|
||
</view>
|
||
<view class="music-modal-body">
|
||
<view class="music-form-item">
|
||
<view class="music-form-label">歌曲标题 *</view>
|
||
<input class="music-form-input" v-model="musicForm.title" placeholder="请输入歌曲标题" />
|
||
</view>
|
||
<view class="music-form-item">
|
||
<view class="music-form-label">艺术家</view>
|
||
<input class="music-form-input" v-model="musicForm.artist" placeholder="请输入艺术家名称" />
|
||
</view>
|
||
<view class="music-form-item">
|
||
<view class="music-form-label">音乐链接 *</view>
|
||
<textarea
|
||
class="music-form-textarea"
|
||
v-model="musicForm.music_url"
|
||
placeholder="请粘贴音乐文件链接(支持 mp3、m4a 等格式)"
|
||
maxlength="500" />
|
||
</view>
|
||
<view class="music-form-item">
|
||
<view class="music-form-label">封面图链接</view>
|
||
<input class="music-form-input" v-model="musicForm.cover_url" placeholder="请输入封面图链接(可选)" />
|
||
</view>
|
||
<view class="music-form-item">
|
||
<view class="music-form-label">时长(秒)</view>
|
||
<input class="music-form-input" v-model.number="musicForm.duration" type="number" placeholder="请输入歌曲时长" />
|
||
</view>
|
||
<view class="music-modal-btn" @click="submitMusic">
|
||
<text>提交</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
GetUserBasic,
|
||
LoverInit,
|
||
LoverBasic,
|
||
OutfitList,
|
||
OutfitPurchase,
|
||
OutfitChange,
|
||
GiftsLists,
|
||
GiftsGive,
|
||
GiftsGiveApi,
|
||
CreateGiftsOrderApi,
|
||
JinbiPayApi,
|
||
SingSongs,
|
||
SingGenerate,
|
||
SingGenerateTask,
|
||
SingCurrent,
|
||
DanceGenerate,
|
||
DanceGenerateTask,
|
||
DanceCurrent,
|
||
SessionInit,
|
||
SessionSend
|
||
} from '@/utils/api.js'
|
||
import { baseURL, baseURLPy } from '@/utils/request.js'
|
||
import notHave from '@/components/not-have.vue';
|
||
import topSafety from '@/components/top-safety.vue';
|
||
import tabBar from '@/components/tab-bar.vue';
|
||
import UnderAge from '@/components/under-age.vue'; // 导入under-age组件
|
||
import uniNavBar from '@/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue'; // 导入uni-nav-bar组件
|
||
import {
|
||
useConversationStore
|
||
} from '@/stores/conversation';
|
||
|
||
export default {
|
||
components: {
|
||
notHave,
|
||
topSafety,
|
||
tabBar,
|
||
UnderAge,
|
||
uniNavBar,
|
||
},
|
||
data() {
|
||
return {
|
||
// Tab 相关
|
||
currentTab: 1, // 默认显示首页(商城是 0,首页是 1)
|
||
tabIntoView: 'tab-1',
|
||
tabs: [
|
||
{ name: '商城' },
|
||
{ name: '首页' },
|
||
{ name: '聊天' },
|
||
{ name: '唱歌' },
|
||
{ name: '跳舞' },
|
||
{ name: '换服装' },
|
||
{ name: '刷礼物' },
|
||
{ name: '短剧' }
|
||
],
|
||
// 首页形象栏相关
|
||
homeLooksList: [],
|
||
selectedLookId: null,
|
||
currentLookImageUrl: '',
|
||
// 聊天相关
|
||
chatMessages: [],
|
||
chatInputText: '',
|
||
chatScrollTop: 0,
|
||
chatIntoView: '',
|
||
chatSessionId: null,
|
||
chatUserAvatar: '',
|
||
chatLoverAvatar: '',
|
||
chatSending: false,
|
||
dancePrompt: '',
|
||
singSongsList: [],
|
||
singHistoryList: [],
|
||
danceHistoryList: [],
|
||
songId: 0,
|
||
singGenerating: false, // 唱歌视频生成中状态
|
||
singGeneratingTaskId: 0,
|
||
danceGenerating: false, // 跳舞视频生成中状态
|
||
danceGeneratingTaskId: 0,
|
||
singPollTimer: null,
|
||
dancePollTimer: null,
|
||
// 音乐库相关
|
||
singCurrentTab: 'songs', // songs, library, history
|
||
musicLibraryList: [],
|
||
musicLibraryPage: 1,
|
||
musicLibraryPageSize: 20,
|
||
musicLibraryTotal: 0,
|
||
musicLibraryHasMore: true,
|
||
showMusicModal: false,
|
||
musicForm: {
|
||
title: '',
|
||
artist: '',
|
||
music_url: '',
|
||
cover_url: '',
|
||
duration: null
|
||
},
|
||
outfitListInfo: null,
|
||
outfitBuyForm: {
|
||
item_id: ''
|
||
},
|
||
outfitMode: null,
|
||
outfitFormTopBottom: {
|
||
top_item_id: '',
|
||
bottom_item_id: '',
|
||
save_to_look: false
|
||
},
|
||
outfitFormDress: {
|
||
dress_item_id: '',
|
||
save_to_look: false
|
||
},
|
||
outfitSaveToLook: false,
|
||
giftGlobal: baseURL,
|
||
giftStats: false,
|
||
successStats: false,
|
||
giftForm: {
|
||
gifts_id: '',
|
||
nums: 1,
|
||
to_user_id: ''
|
||
},
|
||
giftOptions: [],
|
||
giftInfoOptions: null,
|
||
giftUserInfo: {},
|
||
statusBarHeight: uni.getWindowInfo().statusBarHeight,
|
||
currentStep: 0,
|
||
chartData: {},
|
||
opts: {
|
||
color: ["#9F47FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
|
||
"#ea7ccc"
|
||
],
|
||
padding: undefined,
|
||
title: {
|
||
name: "",
|
||
fontSize: 17,
|
||
color: "#F661B5"
|
||
},
|
||
subtitle: {
|
||
name: "",
|
||
fontSize: 12,
|
||
color: "#FFFFFF"
|
||
},
|
||
extra: {
|
||
arcbar: {
|
||
type: "default",
|
||
width: 5,
|
||
backgroundColor: "rgba(255,255,255,0.2)",
|
||
startAngle: 0.75,
|
||
endAngle: 0.25,
|
||
gap: 2,
|
||
linearType: "custom",
|
||
customColor: ["#F661B5"]
|
||
}
|
||
}
|
||
},
|
||
getBobbiesList: '',
|
||
loverBasicList: '',
|
||
underAgeEnabled: false, // 添加青少年模式状态变量
|
||
historyModalVisible: false,
|
||
historyModalType: 'sing',
|
||
historyModalMode: 'preview',
|
||
historyModalList: [],
|
||
videoPlayerVisible: false,
|
||
videoPlayerUrl: '',
|
||
}
|
||
},
|
||
onLoad(options) {
|
||
//#ifdef MP-WEIXIN
|
||
this.checkPermission()
|
||
//#endif
|
||
console.log('uni.env.',uni.env)
|
||
|
||
// 如果有 tab 参数,切换到对应的 tab
|
||
if (options && options.tab) {
|
||
const tabIndex = parseInt(options.tab);
|
||
if (!isNaN(tabIndex) && tabIndex >= 0 && tabIndex < this.tabs.length) {
|
||
this.currentTab = tabIndex;
|
||
}
|
||
}
|
||
},
|
||
onReady() {
|
||
this.getServerData();
|
||
},
|
||
onShow() {
|
||
// 每次页面显示时检查本地存储的青少年模式状态
|
||
this.checkUnderAgeStatus();
|
||
|
||
if (uni.getStorageSync('token')) {
|
||
this.getUserBasic()
|
||
this.loverBasic()
|
||
this.loadHomeLooks() // 加载首页形象栏
|
||
}
|
||
|
||
// 获取歌曲列表
|
||
this.getSingSongs();
|
||
this.getDanceHistory();
|
||
if (this.currentTab === 2) {
|
||
this.restoreSingGeneration();
|
||
}
|
||
if (this.currentTab === 3) {
|
||
this.restoreDanceGeneration();
|
||
}
|
||
if (this.currentTab === 4) {
|
||
this.ensureOutfitLoaded();
|
||
}
|
||
if (this.currentTab === 5) {
|
||
this.ensureGiftLoaded();
|
||
}
|
||
},
|
||
methods: {
|
||
// Tab 切换方法
|
||
switchTab(index) {
|
||
console.log('点击 Tab,切换到索引:', index, '对应 Tab:', this.tabs[index].name);
|
||
|
||
|
||
// 如果切换到聊天 tab(现在是 index 2),初始化聊天会话
|
||
if (index === 2 && !this.chatSessionId) {
|
||
this.initChatSession();
|
||
}
|
||
|
||
this.currentTab = index;
|
||
this.updateTabIntoView(index);
|
||
if (index === 3) {
|
||
this.restoreSingGeneration();
|
||
}
|
||
if (index === 4) {
|
||
this.restoreDanceGeneration();
|
||
}
|
||
if (index === 5) {
|
||
this.ensureOutfitLoaded();
|
||
}
|
||
if (index === 6) {
|
||
this.ensureGiftLoaded();
|
||
}
|
||
},
|
||
onSwiperChange(e) {
|
||
console.log('Swiper 滑动,当前索引:', e.detail.current, '对应 Tab:', this.tabs[e.detail.current].name);
|
||
this.currentTab = e.detail.current;
|
||
this.updateTabIntoView(e.detail.current);
|
||
|
||
// 如果滑动到聊天 tab(现在是 index 2),初始化聊天会话
|
||
if (e.detail.current === 2 && !this.chatSessionId) {
|
||
this.initChatSession();
|
||
}
|
||
if (e.detail.current === 3) {
|
||
this.restoreSingGeneration();
|
||
}
|
||
if (e.detail.current === 4) {
|
||
this.restoreDanceGeneration();
|
||
}
|
||
if (e.detail.current === 5) {
|
||
this.ensureOutfitLoaded();
|
||
}
|
||
if (e.detail.current === 6) {
|
||
this.ensureGiftLoaded();
|
||
}
|
||
},
|
||
updateTabIntoView(index) {
|
||
this.$nextTick(() => {
|
||
this.tabIntoView = 'tab-' + index;
|
||
});
|
||
},
|
||
// 选择歌曲
|
||
selectSongDirect(song) {
|
||
// 防止重复点击
|
||
if (this.singGenerating) {
|
||
uni.showToast({
|
||
title: '视频生成中,请稍候...',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
return;
|
||
}
|
||
|
||
this.songId = song.id;
|
||
this.singGenerating = true;
|
||
this.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
uni.setStorageSync('singGenerating', true);
|
||
|
||
SingGenerate({ song_id: song.id }).then(res => {
|
||
if (res.code == 1) {
|
||
this.singGeneratingTaskId = res.data.generation_task_id;
|
||
uni.setStorageSync('singGeneratingTaskId', this.singGeneratingTaskId);
|
||
this.getSingGenerateTask(res.data.generation_task_id);
|
||
} else {
|
||
this.singGenerating = false;
|
||
this.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
uni.showToast({ title: res.msg, icon: 'none' });
|
||
}
|
||
}).catch(err => {
|
||
this.singGenerating = false;
|
||
this.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
uni.showToast({
|
||
title: '请求失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
});
|
||
},
|
||
restoreSingGeneration() {
|
||
if (this.currentTab !== 2) {
|
||
return;
|
||
}
|
||
if (!uni.getStorageSync('token')) {
|
||
return;
|
||
}
|
||
if (this.singGenerating) {
|
||
return;
|
||
}
|
||
const storedTaskId = parseInt(uni.getStorageSync('singGeneratingTaskId') || 0);
|
||
const storedFlag = !!uni.getStorageSync('singGenerating');
|
||
if (storedFlag && storedTaskId > 0) {
|
||
this.singGenerating = true;
|
||
this.singGeneratingTaskId = storedTaskId;
|
||
this.getSingGenerateTask(storedTaskId);
|
||
return;
|
||
}
|
||
SingCurrent({}).then(res => {
|
||
if (res && res.code == 1 && res.data && res.data.generation_task_id) {
|
||
this.singGenerating = true;
|
||
this.singGeneratingTaskId = res.data.generation_task_id;
|
||
uni.setStorageSync('singGenerating', true);
|
||
uni.setStorageSync('singGeneratingTaskId', this.singGeneratingTaskId);
|
||
this.getSingGenerateTask(this.singGeneratingTaskId);
|
||
}
|
||
}).catch(() => {});
|
||
},
|
||
restoreDanceGeneration() {
|
||
if (this.currentTab !== 3) {
|
||
return;
|
||
}
|
||
if (!uni.getStorageSync('token')) {
|
||
return;
|
||
}
|
||
if (this.danceGenerating) {
|
||
return;
|
||
}
|
||
const storedTaskId = parseInt(uni.getStorageSync('danceGeneratingTaskId') || 0);
|
||
const storedFlag = !!uni.getStorageSync('danceGenerating');
|
||
if (storedFlag && storedTaskId > 0) {
|
||
this.danceGenerating = true;
|
||
this.danceGeneratingTaskId = storedTaskId;
|
||
this.getDanceGenerateTask(storedTaskId);
|
||
return;
|
||
}
|
||
DanceCurrent({}).then(res => {
|
||
if (res && res.code == 1 && res.data && res.data.generation_task_id) {
|
||
this.danceGenerating = true;
|
||
this.danceGeneratingTaskId = res.data.generation_task_id;
|
||
uni.setStorageSync('danceGenerating', true);
|
||
uni.setStorageSync('danceGeneratingTaskId', this.danceGeneratingTaskId);
|
||
this.getDanceGenerateTask(this.danceGeneratingTaskId);
|
||
}
|
||
}).catch(() => {});
|
||
},
|
||
ensureOutfitLoaded() {
|
||
if (!uni.getStorageSync('token')) {
|
||
return;
|
||
}
|
||
if (this.outfitListInfo) {
|
||
return;
|
||
}
|
||
this.fetchOutfitList();
|
||
},
|
||
fetchOutfitList() {
|
||
OutfitList({}).then(res => {
|
||
if (res && res.code == 1) {
|
||
this.outfitListInfo = res.data || null;
|
||
this.normalizeOutfitList();
|
||
this.selectCurrentOutfitInTab();
|
||
} else {
|
||
this.outfitListInfo = null;
|
||
uni.showToast({ title: (res && res.msg) ? res.msg : '加载失败', icon: 'none' });
|
||
}
|
||
}).catch(() => {
|
||
this.outfitListInfo = null;
|
||
uni.showToast({ title: '加载失败', icon: 'none' });
|
||
});
|
||
},
|
||
normalizeOutfitList() {
|
||
if (!this.outfitListInfo) return;
|
||
const owned = Array.isArray(this.outfitListInfo.owned_outfit_ids) ? this.outfitListInfo.owned_outfit_ids : [];
|
||
const current = this.outfitListInfo.current_outfit || {};
|
||
const mark = (arr, type) => {
|
||
if (!Array.isArray(arr)) return;
|
||
for (let i = 0; i < arr.length; i++) {
|
||
const it = arr[i];
|
||
if (type === 'top') it.is_current = (current.top_id == it.id);
|
||
if (type === 'bottom') it.is_current = (current.bottom_id == it.id);
|
||
if (type === 'dress') it.is_current = (current.dress_id == it.id);
|
||
it.is_lock = !owned.includes(it.id);
|
||
}
|
||
};
|
||
mark(this.outfitListInfo.top, 'top');
|
||
mark(this.outfitListInfo.bottom, 'bottom');
|
||
mark(this.outfitListInfo.dress, 'dress');
|
||
},
|
||
selectCurrentOutfitInTab() {
|
||
if (!this.outfitListInfo) return;
|
||
const cur = this.outfitListInfo.current_outfit || {};
|
||
if (cur.dress_id) {
|
||
this.outfitMode = 1;
|
||
this.outfitFormDress.dress_item_id = cur.dress_id;
|
||
this.outfitFormTopBottom.top_item_id = '';
|
||
this.outfitFormTopBottom.bottom_item_id = '';
|
||
return;
|
||
}
|
||
if (cur.top_id || cur.bottom_id) {
|
||
this.outfitMode = 2;
|
||
this.outfitFormTopBottom.top_item_id = cur.top_id || '';
|
||
this.outfitFormTopBottom.bottom_item_id = cur.bottom_id || '';
|
||
this.outfitFormDress.dress_item_id = '';
|
||
}
|
||
},
|
||
isSelectedTop(id) {
|
||
return this.outfitFormTopBottom.top_item_id === id;
|
||
},
|
||
isSelectedBottom(id) {
|
||
return this.outfitFormTopBottom.bottom_item_id === id;
|
||
},
|
||
isSelectedDress(id) {
|
||
return this.outfitFormDress.dress_item_id === id;
|
||
},
|
||
openOutfitDetail(item) {
|
||
if (!item || !item.id) return;
|
||
this.outfitBuyForm.item_id = item.id;
|
||
const price = item.price_gold ? String(item.price_gold) : '0';
|
||
uni.showModal({
|
||
title: '购买服装',
|
||
content: `${item.name ? item.name : '该服装'}\n价格:${price}金币`,
|
||
confirmText: '购买',
|
||
cancelText: '取消',
|
||
success: (r) => {
|
||
if (r.confirm) {
|
||
this.buyOutfit();
|
||
}
|
||
}
|
||
});
|
||
},
|
||
buyOutfit() {
|
||
if (!this.outfitBuyForm.item_id) return;
|
||
OutfitPurchase(this.outfitBuyForm).then(res => {
|
||
if (res && res.code == 1) {
|
||
uni.showToast({ title: '购买成功', icon: 'none' });
|
||
this.fetchOutfitList();
|
||
} else {
|
||
uni.showToast({ title: (res && res.msg) ? res.msg : '购买失败', icon: 'none' });
|
||
}
|
||
}).catch(() => {
|
||
uni.showToast({ title: '购买失败', icon: 'none' });
|
||
});
|
||
},
|
||
selectTop(item) {
|
||
if (!item) return;
|
||
if (item.is_lock && !item.is_free) {
|
||
this.openOutfitDetail(item);
|
||
return;
|
||
}
|
||
if (this.outfitMode === 1 && this.outfitFormDress.dress_item_id) {
|
||
uni.showToast({ title: '连体服模式下不能选择上衣', icon: 'none' });
|
||
return;
|
||
}
|
||
this.outfitMode = 2;
|
||
this.outfitFormTopBottom.top_item_id = (this.outfitFormTopBottom.top_item_id === item.id) ? '' : item.id;
|
||
},
|
||
selectBottom(item) {
|
||
if (!item) return;
|
||
if (item.is_lock && !item.is_free) {
|
||
this.openOutfitDetail(item);
|
||
return;
|
||
}
|
||
if (this.outfitMode === 1 && this.outfitFormDress.dress_item_id) {
|
||
uni.showToast({ title: '连体服模式下不能选择下装', icon: 'none' });
|
||
return;
|
||
}
|
||
this.outfitMode = 2;
|
||
this.outfitFormTopBottom.bottom_item_id = (this.outfitFormTopBottom.bottom_item_id === item.id) ? '' : item.id;
|
||
},
|
||
selectDress(item) {
|
||
if (!item) return;
|
||
if (item.is_lock && !item.is_free) {
|
||
this.openOutfitDetail(item);
|
||
return;
|
||
}
|
||
if (this.outfitMode === 2 && (this.outfitFormTopBottom.top_item_id || this.outfitFormTopBottom.bottom_item_id)) {
|
||
uni.showToast({ title: '上衣下装模式下不能选择连体服', icon: 'none' });
|
||
return;
|
||
}
|
||
this.outfitMode = 1;
|
||
if (this.outfitFormDress.dress_item_id === item.id) {
|
||
this.outfitFormDress.dress_item_id = '';
|
||
} else {
|
||
this.outfitFormTopBottom.top_item_id = '';
|
||
this.outfitFormTopBottom.bottom_item_id = '';
|
||
this.outfitFormDress.dress_item_id = item.id;
|
||
}
|
||
},
|
||
toggleSaveToLook() {
|
||
this.outfitSaveToLook = !this.outfitSaveToLook;
|
||
this.outfitFormDress.save_to_look = this.outfitSaveToLook;
|
||
this.outfitFormTopBottom.save_to_look = this.outfitSaveToLook;
|
||
},
|
||
confirmOutfitChange() {
|
||
if (!this.outfitListInfo || !this.outfitListInfo.clothes_num) {
|
||
uni.showToast({ title: '当前暂无次数', icon: 'none' });
|
||
return;
|
||
}
|
||
const hasDress = this.outfitMode === 1 && this.outfitFormDress.dress_item_id;
|
||
const hasTopBottom = this.outfitMode === 2 && (this.outfitFormTopBottom.top_item_id || this.outfitFormTopBottom.bottom_item_id);
|
||
if (!hasDress && !hasTopBottom) {
|
||
uni.showToast({ title: '请先选择要换装的服装', icon: 'none' });
|
||
return;
|
||
}
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确认是否换装',
|
||
success: (r) => {
|
||
if (r.confirm) {
|
||
this.doOutfitChange();
|
||
}
|
||
}
|
||
});
|
||
},
|
||
doOutfitChange() {
|
||
const payload = (this.outfitMode === 1 && this.outfitFormDress.dress_item_id) ? this.outfitFormDress : this.outfitFormTopBottom;
|
||
OutfitChange(payload).then(res => {
|
||
if (res && res.code == 1) {
|
||
uni.showToast({ title: '换装成功', icon: 'success' });
|
||
this.fetchOutfitList();
|
||
} else {
|
||
uni.showToast({ title: (res && res.msg) ? res.msg : '换装失败', icon: 'none' });
|
||
}
|
||
}).catch(() => {
|
||
uni.showToast({ title: '换装失败', icon: 'none' });
|
||
});
|
||
},
|
||
ensureGiftLoaded() {
|
||
if (!uni.getStorageSync('token')) {
|
||
return;
|
||
}
|
||
if (this.giftOptions && this.giftOptions.length > 0 && this.giftUserInfo) {
|
||
return;
|
||
}
|
||
this.giftGiftsLists();
|
||
this.giftGetUserBasic();
|
||
},
|
||
giftGetUserBasic() {
|
||
GetUserBasic({}).then(res => {
|
||
if (res && res.code == 1) {
|
||
this.giftUserInfo = res.data || {};
|
||
}
|
||
}).catch(() => {});
|
||
},
|
||
giftGiftsLists() {
|
||
GiftsLists({}).then(res => {
|
||
if (res && res.code == 1) {
|
||
this.giftOptions = (res.data && res.data.data) ? res.data.data : [];
|
||
} else {
|
||
this.giftOptions = [];
|
||
uni.showToast({ title: (res && res.msg) ? res.msg : '加载失败', icon: 'none', position: 'top' });
|
||
}
|
||
}).catch(() => {
|
||
this.giftOptions = [];
|
||
uni.showToast({ title: '加载失败', icon: 'none', position: 'top' });
|
||
});
|
||
},
|
||
giftGiftClick(index) {
|
||
this.giftInfoOptions = (this.giftOptions && this.giftOptions[index]) ? this.giftOptions[index] : null;
|
||
this.giftStats = !this.giftStats;
|
||
},
|
||
giftGiveClick() {
|
||
if (!this.giftInfoOptions) {
|
||
uni.showToast({ title: '请选择礼物', icon: 'none', position: 'top' });
|
||
return;
|
||
}
|
||
this.giftForm.gifts_id = this.giftInfoOptions.id;
|
||
const total = Number(this.giftInfoOptions.price || 0) * Number(this.giftForm.nums || 0);
|
||
const money = Number(this.giftUserInfo && this.giftUserInfo.money != null ? this.giftUserInfo.money : 0);
|
||
if (total > money) {
|
||
this.giftGiftsTopUp();
|
||
} else {
|
||
this.giftGiftsGive();
|
||
}
|
||
},
|
||
giftGiftsGive() {
|
||
let fn = GiftsGiveApi;
|
||
if (this.giftForm.to_user_id && String(this.giftForm.to_user_id).trim()) {
|
||
fn = GiftsGive;
|
||
}
|
||
fn(this.giftForm).then(res => {
|
||
if (res && res.code == 1) {
|
||
uni.showToast({ title: '赠送成功', icon: 'none', position: 'top' });
|
||
setTimeout(() => {
|
||
this.giftGetUserBasic();
|
||
this.getUserBasic(); // 刷新好感度数据
|
||
this.giftStats = false;
|
||
}, 1000);
|
||
} else {
|
||
uni.showToast({ title: (res && res.msg) ? res.msg : '赠送失败', icon: 'none', position: 'top' });
|
||
}
|
||
}).catch(() => {
|
||
uni.showToast({ title: '赠送失败', icon: 'none', position: 'top' });
|
||
});
|
||
},
|
||
giftGiftsTopUp() {
|
||
if (!this.giftInfoOptions) return;
|
||
CreateGiftsOrderApi({
|
||
gifts_id: this.giftInfoOptions.id,
|
||
nums: this.giftForm.nums,
|
||
pay_type: 'miniWechat'
|
||
}).then(res => {
|
||
if (res && res.code == 1 && res.data && res.data.out_trade_no) {
|
||
this.giftGoPay(res.data.out_trade_no);
|
||
}
|
||
}).catch(() => {});
|
||
},
|
||
giftGoPay(orderId) {
|
||
JinbiPayApi({ out_trade_no: orderId }).then(res => {
|
||
if (res && res.code == 1) {
|
||
setTimeout(() => {
|
||
this.giftGiftsGive();
|
||
}, 1000);
|
||
} else {
|
||
uni.showToast({ title: (res && res.msg) ? res.msg : '支付失败', icon: 'none', position: 'top' });
|
||
}
|
||
}).catch(() => {
|
||
uni.showToast({ title: '支付失败', icon: 'none', position: 'top' });
|
||
});
|
||
},
|
||
giftCloseClick() {
|
||
this.giftStats = false;
|
||
this.giftForm.nums = 1;
|
||
this.giftInfoOptions = null;
|
||
},
|
||
giftIncreaseNumber() {
|
||
this.giftForm.nums = parseInt(this.giftForm.nums) || 0;
|
||
this.giftForm.nums++;
|
||
},
|
||
giftDecreaseNumber() {
|
||
this.giftForm.nums = parseInt(this.giftForm.nums) || 0;
|
||
if (this.giftForm.nums > 1) {
|
||
this.giftForm.nums--;
|
||
}
|
||
},
|
||
// 请求跳舞
|
||
requestDance() {
|
||
if (!this.dancePrompt || !this.dancePrompt.trim()) {
|
||
this.dancePrompt = '跳一段可爱的舞蹈';
|
||
}
|
||
if (this.danceGenerating) {
|
||
uni.showToast({ title: '视频生成中,请稍候...', icon: 'none', duration: 2000 });
|
||
return;
|
||
}
|
||
this.danceGenerating = true;
|
||
this.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
uni.setStorageSync('danceGenerating', true);
|
||
DanceGenerate({ prompt: this.dancePrompt.trim() }).then(res => {
|
||
if (res.code == 1) {
|
||
this.danceGeneratingTaskId = res.data.generation_task_id;
|
||
uni.setStorageSync('danceGeneratingTaskId', this.danceGeneratingTaskId);
|
||
this.getDanceGenerateTask(this.danceGeneratingTaskId);
|
||
} else {
|
||
this.danceGenerating = false;
|
||
this.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
uni.showToast({ title: res.msg, icon: 'none' });
|
||
}
|
||
}).catch(() => {
|
||
this.danceGenerating = false;
|
||
this.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
uni.showToast({ title: '请求失败,请重试', icon: 'none' });
|
||
});
|
||
},
|
||
// 打开商城外部链接
|
||
openShopLink() {
|
||
// 在 H5 环境中打开外部链接
|
||
// #ifdef H5
|
||
window.open('http://apidoc.weipinshang.net/web/#/1?page_id=450', '_blank');
|
||
// #endif
|
||
|
||
// 在 APP 环境中使用 plus.runtime.openURL
|
||
// #ifdef APP-PLUS
|
||
plus.runtime.openURL('http://apidoc.weipinshang.net/web/#/1?page_id=450');
|
||
// #endif
|
||
|
||
// 在小程序环境中复制链接
|
||
// #ifdef MP
|
||
uni.setClipboardData({
|
||
data: 'http://apidoc.weipinshang.net/web/#/1?page_id=450',
|
||
success: function () {
|
||
uni.showToast({
|
||
title: '链接已复制,请在浏览器中打开',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
}
|
||
});
|
||
// #endif
|
||
},
|
||
// 打开短剧外部链接
|
||
openDramaLink() {
|
||
// 在 H5 环境中打开外部链接
|
||
// #ifdef H5
|
||
window.open('https://djcps.meinvclk.top', '_blank');
|
||
// #endif
|
||
|
||
// 在 APP 环境中使用 plus.runtime.openURL
|
||
// #ifdef APP-PLUS
|
||
plus.runtime.openURL('https://djcps.meinvclk.top');
|
||
// #endif
|
||
|
||
// 在小程序环境中复制链接
|
||
// #ifdef MP
|
||
uni.setClipboardData({
|
||
data: 'https://djcps.meinvclk.top',
|
||
success: function () {
|
||
uni.showToast({
|
||
title: '链接已复制,请在浏览器中打开',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
}
|
||
});
|
||
// #endif
|
||
},
|
||
getDanceHistory() {
|
||
uni.request({
|
||
url: baseURLPy + '/dance/history',
|
||
method: 'GET',
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
},
|
||
success: (res) => {
|
||
console.log('跳舞历史:', res.data);
|
||
if (res.data.code === 1 && res.data.data) {
|
||
this.danceHistoryList = res.data.data;
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('获取跳舞历史失败:', err);
|
||
}
|
||
});
|
||
},
|
||
playDanceVideo(videoUrl) {
|
||
this.openVideoPlayer(videoUrl);
|
||
},
|
||
openHistoryModal(type, mode = 'preview') {
|
||
this.historyModalType = type;
|
||
this.historyModalMode = mode;
|
||
if (mode === 'all') {
|
||
this.fetchAllHistory(type);
|
||
return;
|
||
}
|
||
this.historyModalList = type === 'dance' ? (this.danceHistoryList || []) : (this.singHistoryList || []);
|
||
this.historyModalVisible = true;
|
||
},
|
||
fetchAllHistory(type) {
|
||
const endpoint = type === 'dance' ? '/dance/history/all' : '/sing/history/all';
|
||
uni.request({
|
||
url: baseURLPy + endpoint,
|
||
method: 'GET',
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
},
|
||
success: (res) => {
|
||
if (res.data && res.data.code === 1 && res.data.data) {
|
||
this.historyModalList = res.data.data;
|
||
} else {
|
||
this.historyModalList = [];
|
||
}
|
||
this.historyModalVisible = true;
|
||
},
|
||
fail: () => {
|
||
this.historyModalList = [];
|
||
this.historyModalVisible = true;
|
||
}
|
||
});
|
||
},
|
||
isDownloadFailed(item) {
|
||
const msg = (item && item.error_msg ? String(item.error_msg) : '') || '';
|
||
return msg.indexOf('下载失败') !== -1;
|
||
},
|
||
formatHistoryStatus(item) {
|
||
if (!item) return '';
|
||
const status = item.status || '';
|
||
if (status === 'succeeded') return '成功';
|
||
if (status === 'pending' || status === 'running') return '生成中';
|
||
if (status === 'failed') {
|
||
if (this.isDownloadFailed(item)) return '文件下载失败';
|
||
return '生成失败';
|
||
}
|
||
return '';
|
||
},
|
||
retryHistoryItem(item) {
|
||
if (!item || !item.id) return;
|
||
const id = item.id;
|
||
const endpoint = this.historyModalType === 'dance' ? ('/dance/retry/' + id) : ('/sing/retry/' + id);
|
||
uni.showLoading({ title: '处理中...', mask: true });
|
||
uni.request({
|
||
url: baseURLPy + endpoint,
|
||
method: 'POST',
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
},
|
||
success: () => {
|
||
uni.hideLoading();
|
||
uni.showToast({ title: '已触发重新下载', icon: 'none', duration: 1500 });
|
||
this.fetchAllHistory(this.historyModalType);
|
||
},
|
||
fail: () => {
|
||
uni.hideLoading();
|
||
uni.showToast({ title: '重试失败', icon: 'none', duration: 1500 });
|
||
}
|
||
});
|
||
},
|
||
closeHistoryModal() {
|
||
this.historyModalVisible = false;
|
||
},
|
||
openVideoPlayer(url) {
|
||
if (!url) return;
|
||
this.videoPlayerUrl = url;
|
||
this.videoPlayerVisible = true;
|
||
},
|
||
closeVideoPlayer() {
|
||
this.videoPlayerVisible = false;
|
||
this.videoPlayerUrl = '';
|
||
},
|
||
// 获取歌曲列表
|
||
// 获取歌曲列表
|
||
getSingSongs() {
|
||
SingSongs().then(res => {
|
||
if (res.code == 1) {
|
||
this.singSongsList = res.data.songs || [];
|
||
}
|
||
});
|
||
// 同时获取历史记录
|
||
this.getSingHistory();
|
||
},
|
||
// 获取唱歌历史记录
|
||
getSingHistory() {
|
||
uni.request({
|
||
url: baseURLPy + '/sing/history',
|
||
method: 'GET',
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
},
|
||
success: (res) => {
|
||
console.log('唱歌历史:', res.data);
|
||
if (res.data.code === 1 && res.data.data) {
|
||
this.singHistoryList = res.data.data;
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('获取唱歌历史失败:', err);
|
||
}
|
||
});
|
||
},
|
||
// 播放唱歌视频
|
||
playSingVideo(videoUrl) {
|
||
this.openVideoPlayer(videoUrl);
|
||
},
|
||
// 格式化日期
|
||
formatDate(dateStr) {
|
||
if (!dateStr) return '';
|
||
const date = new Date(dateStr);
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
const hour = String(date.getHours()).padStart(2, '0');
|
||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||
return `${month}-${day} ${hour}:${minute}`;
|
||
},
|
||
// 加载换装数据
|
||
// 轮询监听唱歌任务结果
|
||
getSingGenerateTask(task_id) {
|
||
const that = this;
|
||
let attempts = 0;
|
||
const maxAttempts = 225; // 15分钟左右 (225*4s)
|
||
|
||
const doPoll = () => {
|
||
if (!that.singGenerating || that.singGeneratingTaskId !== task_id) {
|
||
return;
|
||
}
|
||
attempts++;
|
||
if (attempts > maxAttempts) {
|
||
that.singGenerating = false;
|
||
that.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
if (that.singPollTimer) {
|
||
clearTimeout(that.singPollTimer);
|
||
that.singPollTimer = null;
|
||
}
|
||
uni.showToast({
|
||
title: '处理超时,请稍后查看',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
return;
|
||
}
|
||
|
||
SingGenerateTask(task_id).then(res => {
|
||
if (res.code == 1) {
|
||
const data = res.data;
|
||
if (data.status == 'succeeded') {
|
||
that.singGenerating = false;
|
||
that.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
uni.showToast({
|
||
title: '生成成功!',
|
||
icon: 'success',
|
||
duration: 2000
|
||
});
|
||
// 可以在这里刷新聊天消息或显示视频
|
||
} else if (data.status == 'failed') {
|
||
that.singGenerating = false;
|
||
that.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
uni.showToast({
|
||
title: data.error_msg || '生成失败',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
} else {
|
||
// 继续轮询
|
||
that.singGenerating = true;
|
||
that.singGeneratingTaskId = task_id;
|
||
uni.setStorageSync('singGenerating', true);
|
||
uni.setStorageSync('singGeneratingTaskId', task_id);
|
||
that.singPollTimer = setTimeout(doPoll, 4000);
|
||
}
|
||
} else {
|
||
that.singGenerating = false;
|
||
that.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
if (that.singPollTimer) {
|
||
clearTimeout(that.singPollTimer);
|
||
that.singPollTimer = null;
|
||
}
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
}
|
||
}).catch(err => {
|
||
that.singGenerating = false;
|
||
that.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
uni.showToast({
|
||
title: '查询失败,请重试',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
});
|
||
};
|
||
|
||
doPoll();
|
||
},
|
||
getDanceGenerateTask(task_id) {
|
||
const that = this;
|
||
let attempts = 0;
|
||
const maxAttempts = 225; // 15分钟左右 (225*4s)
|
||
const doPoll = () => {
|
||
if (!that.danceGenerating || that.danceGeneratingTaskId !== task_id) {
|
||
return;
|
||
}
|
||
attempts++;
|
||
if (attempts > maxAttempts) {
|
||
that.danceGenerating = false;
|
||
that.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
if (that.dancePollTimer) {
|
||
clearTimeout(that.dancePollTimer);
|
||
that.dancePollTimer = null;
|
||
}
|
||
uni.showToast({ title: '处理超时,请稍后查看', icon: 'none', duration: 2000 });
|
||
return;
|
||
}
|
||
DanceGenerateTask(task_id).then(res => {
|
||
if (res.code == 1) {
|
||
const data = res.data;
|
||
if (data.status == 'succeeded') {
|
||
that.danceGenerating = false;
|
||
that.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
uni.showToast({ title: '生成成功!', icon: 'success', duration: 2000 });
|
||
that.getDanceHistory();
|
||
} else if (data.status == 'failed') {
|
||
that.danceGenerating = false;
|
||
that.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
uni.showToast({ title: data.error_msg || '生成失败', icon: 'none', duration: 2000 });
|
||
} else {
|
||
that.danceGenerating = true;
|
||
that.danceGeneratingTaskId = task_id;
|
||
uni.setStorageSync('danceGenerating', true);
|
||
uni.setStorageSync('danceGeneratingTaskId', task_id);
|
||
that.dancePollTimer = setTimeout(doPoll, 4000);
|
||
}
|
||
} else {
|
||
that.danceGenerating = false;
|
||
that.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
if (that.dancePollTimer) {
|
||
clearTimeout(that.dancePollTimer);
|
||
that.dancePollTimer = null;
|
||
}
|
||
uni.showToast({ title: res.msg, icon: 'none', duration: 2000 });
|
||
}
|
||
}).catch(() => {
|
||
that.danceGenerating = false;
|
||
that.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
if (that.dancePollTimer) {
|
||
clearTimeout(that.dancePollTimer);
|
||
that.dancePollTimer = null;
|
||
}
|
||
uni.showToast({ title: '查询失败,请重试', icon: 'none', duration: 2000 });
|
||
});
|
||
};
|
||
doPoll();
|
||
},
|
||
cancelSingGeneration() {
|
||
this.singGenerating = false;
|
||
this.singGeneratingTaskId = 0;
|
||
uni.setStorageSync('singGenerating', false);
|
||
uni.setStorageSync('singGeneratingTaskId', 0);
|
||
if (this.singPollTimer) {
|
||
clearTimeout(this.singPollTimer);
|
||
this.singPollTimer = null;
|
||
}
|
||
uni.showToast({ title: '已取消生成', icon: 'none', duration: 1500 });
|
||
},
|
||
cancelDanceGeneration() {
|
||
this.danceGenerating = false;
|
||
this.danceGeneratingTaskId = 0;
|
||
uni.setStorageSync('danceGenerating', false);
|
||
uni.setStorageSync('danceGeneratingTaskId', 0);
|
||
if (this.dancePollTimer) {
|
||
clearTimeout(this.dancePollTimer);
|
||
this.dancePollTimer = null;
|
||
}
|
||
uni.showToast({ title: '已取消生成', icon: 'none', duration: 1500 });
|
||
},
|
||
// 处理青少年模式状态改变事件
|
||
handleUnderAgeStatusChange(status) {
|
||
this.underAgeEnabled = status;
|
||
},
|
||
// 检查本地存储的青少年模式状态
|
||
checkUnderAgeStatus() {
|
||
const storedStatus = uni.getStorageSync('underAgeEnabled');
|
||
console.log('storedStatus:', storedStatus)
|
||
this.underAgeEnabled = !!storedStatus; // 确保是布尔值
|
||
},
|
||
async checkPermission() {
|
||
try {
|
||
const settingRes = await new Promise((resolve, reject) => {
|
||
uni.getSetting({
|
||
success: (res) => resolve(res),
|
||
fail: (err) => reject(err)
|
||
});
|
||
});
|
||
console.log(settingRes.authSetting, '当前授权状态');
|
||
// 检查摄像头权限
|
||
if (!settingRes.authSetting['scope.camera']) {
|
||
try {
|
||
await new Promise((resolve, reject) => {
|
||
uni.authorize({
|
||
scope: 'scope.camera',
|
||
success: () => resolve(),
|
||
fail: (err) => {
|
||
console.warn('摄像头授权失败', err);
|
||
// 用户拒绝授权,可以引导用户手动开启
|
||
this.showPermissionGuide('摄像头');
|
||
reject(err);
|
||
}
|
||
});
|
||
});
|
||
} catch (err) {
|
||
console.warn('摄像头授权失败', err);
|
||
}
|
||
}
|
||
// 检查麦克风权限 - 注意:微信小程序是 scope.recordMicrophone 而不是 scope.record
|
||
if (!settingRes.authSetting['scope.record']) {
|
||
try {
|
||
await new Promise((resolve, reject) => {
|
||
uni.authorize({
|
||
scope: 'scope.record', // 修正权限名称
|
||
success: () => resolve(),
|
||
fail: (err) => {
|
||
console.warn('麦克风授权失败', err);
|
||
this.showPermissionGuide('麦克风');
|
||
reject(err);
|
||
}
|
||
});
|
||
});
|
||
} catch (err) {
|
||
console.warn('麦克风授权失败', err);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('获取授权设置失败', error);
|
||
}
|
||
},
|
||
// 显示权限引导提示
|
||
showPermissionGuide(permissionType) {
|
||
uni.showModal({
|
||
title: '需要授权',
|
||
content: `需要${permissionType}权限才能正常使用相关功能,请在设置中开启`,
|
||
showCancel: true,
|
||
cancelText: '取消',
|
||
confirmText: '去设置',
|
||
success: (modalRes) => {
|
||
if (modalRes.confirm) {
|
||
// 跳转到小程序设置页面
|
||
uni.openSetting({
|
||
success: (settingRes) => {
|
||
console.log('用户设置结果', settingRes);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
});
|
||
},
|
||
getUserBasic() {
|
||
GetUserBasic({}).then(res => {
|
||
if (res.code == 1) {
|
||
let data = res.data
|
||
const conversationStore = useConversationStore();
|
||
let listener = {
|
||
nickname: data.username,
|
||
headImage: data.avatar,
|
||
openid: data.wxapp_openid,
|
||
}
|
||
conversationStore.setUserInfo(listener); //存储用户信息
|
||
this.getBobbiesList = data
|
||
console.log('data', data)
|
||
this.getServerData();
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
position: 'top'
|
||
})
|
||
}
|
||
}).catch(() => {})
|
||
},
|
||
loverInit() {
|
||
LoverInit().then(res => {
|
||
if (res.code == 1) {
|
||
this.getUserBasic()
|
||
}
|
||
})
|
||
},
|
||
loverBasic() {
|
||
LoverBasic().then(res => {
|
||
if (res.code == 1) {
|
||
this.loverBasicList = res.data
|
||
uni.setStorageSync('loverBasicList', res.data)
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
position: 'top'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
getServerData() {
|
||
//模拟从服务器获取数据时的延时
|
||
setTimeout(() => {
|
||
//模拟服务器返回数据,如果数据格式和标准格式不同,需自行按下面的格式拼接
|
||
let todayPercent = this.getBobbiesList.bond_today_percent / 100 ? this.getBobbiesList.bond_today_percent /
|
||
100 : 0
|
||
console.log('todayPercent', todayPercent)
|
||
let res = {
|
||
series: [{
|
||
name: "正确率",
|
||
color: "#9F47FF",
|
||
data: todayPercent
|
||
}]
|
||
};
|
||
this.chartData = JSON.parse(JSON.stringify(res));
|
||
}, 500);
|
||
},
|
||
calculateProgressWidth() {
|
||
if (this.getBobbiesList.intimacy == null || this.getBobbiesList.next_level_intimacy == null) {
|
||
return 0;
|
||
}
|
||
// 根据比例计算实际宽度,确保不超过最大宽度160rpx
|
||
const actualWidth = (this.getBobbiesList.intimacy / this.getBobbiesList.next_level_intimacy) * 160;
|
||
const result = Math.min(actualWidth, 160);
|
||
|
||
// 打印计算过程和结果
|
||
console.log('最终结果:', result);
|
||
return result;
|
||
},
|
||
calculateProgressPercent() {
|
||
if (this.getBobbiesList.intimacy == null || this.getBobbiesList.next_level_intimacy == null) {
|
||
return 0;
|
||
}
|
||
const percent = (this.getBobbiesList.intimacy / this.getBobbiesList.next_level_intimacy) * 100;
|
||
return Math.min(percent, 100);
|
||
},
|
||
togenerate() {
|
||
this.loverBasic()
|
||
this.loverInit()
|
||
this.$nextTick(() => {
|
||
this.getServerData();
|
||
});
|
||
},
|
||
// 定制专属女友
|
||
tocreate() {
|
||
uni.navigateTo({
|
||
url: '/pages/create/index'
|
||
});
|
||
},
|
||
tocreateLover() {
|
||
uni.navigateTo({
|
||
url: '/pages/create/lover'
|
||
});
|
||
},
|
||
toties() {
|
||
uni.navigateTo({
|
||
url: '/pages/index/ties'
|
||
});
|
||
},
|
||
tointimacy() {
|
||
uni.navigateTo({
|
||
url: '/pages/index/intimacy'
|
||
});
|
||
},
|
||
toreplacement1(){
|
||
uni.navigateTo({
|
||
url: '/pages/chat/test1'
|
||
});
|
||
},
|
||
toreplacement() {
|
||
// if (this.getBobbiesList.level >= 4) {
|
||
// uni.navigateTo({
|
||
// url: '/pages/index/replacement'
|
||
// });
|
||
// } else {
|
||
// uni.showToast({
|
||
// title: '达到Lv.4才可以解锁换装',
|
||
// icon: 'none',
|
||
// position: 'top'
|
||
// });
|
||
// }
|
||
uni.navigateTo({
|
||
url: '/pages/index/replacement'
|
||
});
|
||
// uni.navigateTo({
|
||
// url: '/pages/chat/test0'
|
||
// });
|
||
},
|
||
tochat() {
|
||
uni.navigateTo({
|
||
url: '/pages/chat/index'
|
||
});
|
||
},
|
||
tophone() {
|
||
// if (this.getBobbiesList.level >= 2) {
|
||
// uni.navigateTo({
|
||
// url: '/pages/chat/phone'
|
||
// });
|
||
// } else {
|
||
// uni.showToast({
|
||
// title: '达到Lv.2才可以解锁电话',
|
||
// icon: 'none',
|
||
// position: 'top'
|
||
// });
|
||
// }
|
||
uni.navigateTo({
|
||
url: '/pages/chat/phone'
|
||
});
|
||
},
|
||
togift() {
|
||
uni.navigateTo({
|
||
url: '/pages/index/gift'
|
||
});
|
||
},
|
||
todynamics() {
|
||
uni.navigateTo({
|
||
url: '/pages/index/dynamics'
|
||
});
|
||
},
|
||
|
||
// ========== 聊天相关方法 ==========
|
||
// 初始化聊天会话
|
||
initChatSession() {
|
||
// 获取用户头像
|
||
const userInfo = uni.getStorageSync('userinfo');
|
||
this.chatUserAvatar = userInfo?.avatar || '/static/images/avatar.png';
|
||
|
||
// 获取恋人头像 - 优先使用当前选中的形象,否则使用基本信息中的头像
|
||
if (this.currentLookImageUrl) {
|
||
this.chatLoverAvatar = this.currentLookImageUrl;
|
||
} else if (this.loverBasicList?.image_url) {
|
||
this.chatLoverAvatar = this.loverBasicList.image_url;
|
||
} else {
|
||
this.chatLoverAvatar = '/static/images/avatar.png';
|
||
}
|
||
|
||
uni.showLoading({ title: '加载中...' });
|
||
|
||
SessionInit().then(res => {
|
||
uni.hideLoading();
|
||
if (res.code === 1) {
|
||
this.chatSessionId = res.data.session_id;
|
||
// 加载历史消息(只显示最近10条)
|
||
const allMessages = res.data.messages || [];
|
||
this.chatMessages = allMessages.slice(-10).map(msg => ({
|
||
role: msg.role === 'lover' ? 'ai' : 'user',
|
||
content: msg.content
|
||
}));
|
||
|
||
// 滚动到底部
|
||
this.$nextTick(() => {
|
||
this.scrollChatToBottom();
|
||
});
|
||
} else {
|
||
uni.showToast({ title: res.msg || '加载失败', icon: 'none' });
|
||
}
|
||
}).catch(err => {
|
||
uni.hideLoading();
|
||
console.error('初始化会话失败:', err);
|
||
uni.showToast({ title: '网络错误', icon: 'none' });
|
||
});
|
||
},
|
||
|
||
// 发送聊天消息
|
||
sendChatMessage() {
|
||
if (!this.chatInputText.trim()) {
|
||
return;
|
||
}
|
||
|
||
if (this.chatSending) {
|
||
return;
|
||
}
|
||
|
||
if (!this.chatSessionId) {
|
||
uni.showToast({ title: '会话未初始化', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
const userMessage = this.chatInputText.trim();
|
||
this.chatInputText = '';
|
||
|
||
// 让输入框失去焦点,收起键盘
|
||
uni.hideKeyboard();
|
||
|
||
// 添加用户消息到列表
|
||
this.chatMessages.push({
|
||
role: 'user',
|
||
content: userMessage
|
||
});
|
||
|
||
// 滚动到底部
|
||
this.$nextTick(() => {
|
||
this.scrollChatToBottom();
|
||
});
|
||
|
||
// 添加"思考中"提示
|
||
const thinkingIndex = this.chatMessages.length;
|
||
this.chatMessages.push({
|
||
role: 'ai',
|
||
content: '思考中...'
|
||
});
|
||
|
||
this.chatSending = true;
|
||
|
||
// 发送到后端
|
||
SessionSend({
|
||
session_id: this.chatSessionId,
|
||
message: userMessage
|
||
}).then(res => {
|
||
this.chatSending = false;
|
||
|
||
if (res.code === 1) {
|
||
// 移除"思考中"
|
||
this.chatMessages.splice(thinkingIndex, 1);
|
||
|
||
// 添加 AI 回复
|
||
this.chatMessages.push({
|
||
role: 'ai',
|
||
content: res.data.reply || '...'
|
||
});
|
||
|
||
// 滚动到底部
|
||
this.$nextTick(() => {
|
||
this.scrollChatToBottom();
|
||
});
|
||
} else {
|
||
// 移除"思考中"
|
||
this.chatMessages.splice(thinkingIndex, 1);
|
||
uni.showToast({ title: res.msg || '发送失败', icon: 'none' });
|
||
}
|
||
}).catch(err => {
|
||
this.chatSending = false;
|
||
// 移除"思考中"
|
||
this.chatMessages.splice(thinkingIndex, 1);
|
||
console.error('发送消息失败:', err);
|
||
uni.showToast({ title: '发送失败', icon: 'none' });
|
||
});
|
||
},
|
||
|
||
// 输入框失去焦点时的处理
|
||
onInputBlur() {
|
||
// 确保输入框恢复正常状态
|
||
this.$nextTick(() => {
|
||
// 强制重新渲染,确保样式正确
|
||
});
|
||
},
|
||
|
||
// 滚动聊天到底部
|
||
scrollChatToBottom() {
|
||
this.chatIntoView = '';
|
||
this.$nextTick(() => {
|
||
this.chatIntoView = 'chat-bottom';
|
||
});
|
||
},
|
||
|
||
// ========== 首页形象栏相关方法 ==========
|
||
// 加载首页形象栏
|
||
loadHomeLooks() {
|
||
OutfitList({}).then(res => {
|
||
if (res && res.code == 1 && res.data) {
|
||
this.homeLooksList = res.data.looks || [];
|
||
// 如果有形象栏数据,默认选中第一个
|
||
if (this.homeLooksList.length > 0) {
|
||
this.selectedLookId = this.homeLooksList[0].id;
|
||
this.currentLookImageUrl = this.homeLooksList[0].image_url;
|
||
// 同时更新聊天头像
|
||
this.chatLoverAvatar = this.homeLooksList[0].image_url;
|
||
}
|
||
}
|
||
}).catch(err => {
|
||
console.error('加载形象栏失败:', err);
|
||
});
|
||
},
|
||
|
||
// 切换形象
|
||
switchLook(look) {
|
||
if (!look || !look.id) return;
|
||
|
||
// 调用后端 API 切换形象
|
||
uni.request({
|
||
url: baseURLPy + '/outfit/looks/use/' + look.id,
|
||
method: 'POST',
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
},
|
||
success: (res) => {
|
||
if (res.data && res.data.code === 1) {
|
||
this.selectedLookId = look.id;
|
||
this.currentLookImageUrl = look.image_url;
|
||
|
||
// 更新聊天页面的头像
|
||
this.chatLoverAvatar = look.image_url;
|
||
|
||
// 更新女友基本信息(刷新图片)
|
||
this.loverBasic();
|
||
|
||
uni.showToast({
|
||
title: '形象切换成功',
|
||
icon: 'success',
|
||
duration: 1500
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: res.data.msg || '切换失败',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('切换形象失败:', err);
|
||
uni.showToast({
|
||
title: '切换失败,请重试',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
// ========== 音乐库相关方法 ==========
|
||
// 切换唱歌Tab
|
||
switchSingTab(tab) {
|
||
this.singCurrentTab = tab;
|
||
if (tab === 'library' && this.musicLibraryList.length === 0) {
|
||
this.loadMusicLibrary();
|
||
}
|
||
},
|
||
|
||
// 加载音乐库
|
||
loadMusicLibrary(page = 1) {
|
||
uni.request({
|
||
url: baseURLPy + '/music/library',
|
||
method: 'GET',
|
||
data: {
|
||
page: page,
|
||
page_size: this.musicLibraryPageSize
|
||
},
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
},
|
||
success: (res) => {
|
||
if (res.data && res.data.code === 1) {
|
||
const data = res.data.data;
|
||
if (page === 1) {
|
||
this.musicLibraryList = data.list || [];
|
||
} else {
|
||
this.musicLibraryList = this.musicLibraryList.concat(data.list || []);
|
||
}
|
||
this.musicLibraryTotal = data.total || 0;
|
||
this.musicLibraryPage = page;
|
||
this.musicLibraryHasMore = this.musicLibraryList.length < this.musicLibraryTotal;
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('加载音乐库失败:', err);
|
||
uni.showToast({ title: '加载失败', icon: 'none' });
|
||
}
|
||
});
|
||
},
|
||
|
||
// 加载更多音乐
|
||
loadMoreMusic() {
|
||
if (!this.musicLibraryHasMore) return;
|
||
this.loadMusicLibrary(this.musicLibraryPage + 1);
|
||
},
|
||
|
||
// 显示添加音乐弹窗
|
||
showAddMusicModal() {
|
||
this.showMusicModal = true;
|
||
this.musicForm = {
|
||
title: '',
|
||
artist: '',
|
||
music_url: '',
|
||
cover_url: '',
|
||
duration: null
|
||
};
|
||
},
|
||
|
||
// 关闭添加音乐弹窗
|
||
closeMusicModal() {
|
||
this.showMusicModal = false;
|
||
},
|
||
|
||
// 提交音乐
|
||
submitMusic() {
|
||
if (!this.musicForm.title || !this.musicForm.music_url) {
|
||
uni.showToast({ title: '请填写歌曲标题和音乐链接', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
uni.showLoading({ title: '提交中...' });
|
||
|
||
uni.request({
|
||
url: baseURLPy + '/music/add-link',
|
||
method: 'POST',
|
||
data: this.musicForm,
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token"),
|
||
'Content-Type': 'application/json'
|
||
},
|
||
success: (res) => {
|
||
uni.hideLoading();
|
||
if (res.data && res.data.code === 1) {
|
||
uni.showToast({ title: '添加成功', icon: 'success' });
|
||
this.closeMusicModal();
|
||
this.loadMusicLibrary(1); // 刷新列表
|
||
} else {
|
||
uni.showToast({ title: res.data.msg || '添加失败', icon: 'none' });
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading();
|
||
console.error('添加音乐失败:', err);
|
||
uni.showToast({ title: '添加失败', icon: 'none' });
|
||
}
|
||
});
|
||
},
|
||
|
||
// 从音乐库选择歌曲
|
||
selectMusicFromLibrary(music) {
|
||
// 记录播放次数
|
||
uni.request({
|
||
url: baseURLPy + '/music/' + music.id + '/play',
|
||
method: 'POST',
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
}
|
||
});
|
||
|
||
// 使用音乐库的歌曲生成视频
|
||
if (this.singGenerating) {
|
||
uni.showToast({ title: '视频生成中,请稍候...', icon: 'none', duration: 2000 });
|
||
return;
|
||
}
|
||
|
||
// 这里需要调用唱歌API,传入音乐库的音乐URL
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: `确定让她唱《${music.title}》吗?`,
|
||
success: (modalRes) => {
|
||
if (modalRes.confirm) {
|
||
// TODO: 调用唱歌API,使用 music.music_url
|
||
uni.showToast({ title: '功能开发中...', icon: 'none' });
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
// 切换音乐点赞
|
||
toggleMusicLike(music) {
|
||
uni.request({
|
||
url: baseURLPy + '/music/' + music.id + '/like',
|
||
method: 'POST',
|
||
header: {
|
||
'Authorization': 'Bearer ' + uni.getStorageSync("token")
|
||
},
|
||
success: (res) => {
|
||
if (res.data && res.data.code === 1) {
|
||
music.is_liked = res.data.data.is_liked;
|
||
music.like_count = res.data.data.like_count;
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('点赞失败:', err);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style>
|
||
page {
|
||
background: #FFFFFF;
|
||
}
|
||
</style>
|
||
<style>
|
||
/* ========== 礼物页面样式 ========== */
|
||
.gift-page {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
background: linear-gradient(180deg, #FFE5F5 0%, #F5F5FF 100%);
|
||
}
|
||
|
||
.gift-header {
|
||
padding: 40rpx 30rpx 20rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.gift-header-title {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #9F47FF;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.gift-header-desc {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.gift-intimacy-bar {
|
||
background: rgba(255, 255, 255, 0.8);
|
||
border-radius: 20rpx;
|
||
padding: 20rpx;
|
||
box-shadow: 0 4rpx 12rpx rgba(159, 71, 255, 0.1);
|
||
}
|
||
|
||
.gift-intimacy-label {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.gift-intimacy-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15rpx;
|
||
}
|
||
|
||
.gift-intimacy-level {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #9F47FF;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.gift-intimacy-progress {
|
||
flex: 1;
|
||
height: 20rpx;
|
||
background: #E5E5E5;
|
||
border-radius: 10rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.gift-intimacy-progress-bar {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #FF6B9D 0%, #9F47FF 100%);
|
||
border-radius: 10rpx;
|
||
transition: width 0.3s ease;
|
||
}
|
||
|
||
.gift-intimacy-value {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.gift-scroll {
|
||
flex: 1;
|
||
padding: 0 20rpx;
|
||
}
|
||
|
||
.gift-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
padding-bottom: 40rpx;
|
||
}
|
||
|
||
.gift-item {
|
||
width: 32%;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.gift-item-inner {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 20rpx;
|
||
box-shadow: 0 4rpx 12rpx rgba(159, 71, 255, 0.15);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.gift-item-inner:active {
|
||
transform: scale(0.95);
|
||
box-shadow: 0 2rpx 8rpx rgba(159, 71, 255, 0.2);
|
||
}
|
||
|
||
.gift-item-img {
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.gift-item-name {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
text-align: center;
|
||
margin-bottom: 8rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
width: 100%;
|
||
}
|
||
|
||
.gift-item-price {
|
||
font-size: 24rpx;
|
||
color: #FF6B9D;
|
||
font-weight: bold;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
|
||
.gift-item-intimacy {
|
||
font-size: 22rpx;
|
||
color: #9F47FF;
|
||
background: rgba(159, 71, 255, 0.1);
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
/* 礼物详情弹窗 */
|
||
.gift-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: flex-end;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.gift-modal-content {
|
||
width: 100%;
|
||
background: linear-gradient(180deg, #FFE5F5 0%, #FFFFFF 100%);
|
||
border-radius: 40rpx 40rpx 0 0;
|
||
padding: 40rpx 30rpx;
|
||
padding-bottom: 60rpx;
|
||
}
|
||
|
||
.gift-modal-header {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
position: relative;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.gift-modal-title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.gift-modal-close {
|
||
position: absolute;
|
||
right: 0;
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.gift-modal-body {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
padding: 20rpx;
|
||
background: rgba(255, 255, 255, 0.6);
|
||
border-radius: 20rpx;
|
||
}
|
||
|
||
.gift-modal-img {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
margin-right: 30rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.gift-modal-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.gift-modal-name {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #9F47FF;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.gift-modal-intimacy {
|
||
font-size: 26rpx;
|
||
color: #FF6B9D;
|
||
margin-bottom: 10rpx;
|
||
background: rgba(255, 107, 157, 0.1);
|
||
padding: 6rpx 12rpx;
|
||
border-radius: 8rpx;
|
||
display: inline-block;
|
||
}
|
||
|
||
.gift-modal-price {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #FF0000;
|
||
}
|
||
|
||
.gift-modal-quantity {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
padding: 20rpx;
|
||
background: rgba(255, 255, 255, 0.6);
|
||
border-radius: 16rpx;
|
||
}
|
||
|
||
.gift-modal-quantity-label {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.gift-modal-quantity-control {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.gift-quantity-btn {
|
||
width: 50rpx;
|
||
height: 50rpx;
|
||
}
|
||
|
||
.gift-quantity-input {
|
||
width: 80rpx;
|
||
height: 50rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
background: #fff;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.gift-modal-balance {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
text-align: center;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.gift-modal-btn {
|
||
padding: 28rpx 0;
|
||
background: linear-gradient(135deg, #FF6B9D 0%, #C239B3 100%);
|
||
color: #fff;
|
||
text-align: center;
|
||
border-radius: 16rpx;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
box-shadow: 0 8rpx 20rpx rgba(255, 107, 157, 0.3);
|
||
}
|
||
|
||
.gift-modal-btn:active {
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
/* ========== 旧的礼物样式(已废弃,保留以防需要) ========== */
|
||
.gift-tab .body {
|
||
position: relative;
|
||
}
|
||
|
||
.gift-tab .back {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 1624rpx;
|
||
display: block;
|
||
}
|
||
|
||
.gift-tab .list {
|
||
position: relative;
|
||
}
|
||
|
||
.gift-tab .list_logo {
|
||
margin: -140rpx 0 0 0;
|
||
width: 100%;
|
||
height: 556rpx;
|
||
display: block;
|
||
}
|
||
|
||
.gift-tab .list_content {
|
||
position: relative;
|
||
}
|
||
|
||
.gift-tab .list_backA {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.gift-tab .list_module {
|
||
position: relative;
|
||
padding: 46rpx 34rpx;
|
||
}
|
||
|
||
.gift-tab .list_detail {
|
||
position: relative;
|
||
}
|
||
|
||
.gift-tab .list_title {
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
color: #CC9DFF;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.gift-tab .list_body {
|
||
position: relative;
|
||
margin: 54rpx 0 0 0;
|
||
}
|
||
|
||
.gift-tab .gift-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.gift-tab .list_item {
|
||
position: relative;
|
||
width: 30%;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.gift-tab .list_scrollDetail {
|
||
position: relative;
|
||
}
|
||
|
||
.gift-tab .list_image {
|
||
position: relative;
|
||
width: 176rpx;
|
||
height: 176rpx;
|
||
}
|
||
|
||
.gift-tab .list_border {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.gift-tab .list_picture {
|
||
position: relative;
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
display: block;
|
||
}
|
||
|
||
.gift-tab .list_name {
|
||
margin: 8rpx 0 0 0;
|
||
font-weight: 500;
|
||
font-size: 30rpx;
|
||
color: #F661B5;
|
||
line-height: 50rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.gift-tab .list_btn {
|
||
margin: 150rpx 0 0 0;
|
||
padding: 24rpx 0;
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
background: linear-gradient(135deg, #F0BDDD 0%, #A89CF7 100%);
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.gift-tab .alert {
|
||
position: fixed;
|
||
width: 100%;
|
||
height: 100%;
|
||
left: 0;
|
||
bottom: 0;
|
||
box-sizing: border-box;
|
||
background: rgba(0, 0, 0, 0.2);
|
||
z-index: 2;
|
||
}
|
||
|
||
.gift-tab .alert_content {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background: linear-gradient(180deg, #EDD6F5 0%, #FFFFFF 100%);
|
||
border-radius: 40rpx 40rpx 0rpx 0rpx;
|
||
padding: 46rpx 40rpx 68rpx 40rpx;
|
||
}
|
||
|
||
.gift-tab .alert_title {
|
||
position: relative;
|
||
font-weight: 500;
|
||
font-size: 36rpx;
|
||
color: #333333;
|
||
line-height: 50rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.gift-tab .alert_title image {
|
||
position: absolute;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
width: 30rpx;
|
||
height: 30rpx;
|
||
margin: auto 0;
|
||
}
|
||
|
||
.gift-tab .alert_module {
|
||
position: relative;
|
||
margin: 68rpx 0 58rpx 0;
|
||
}
|
||
|
||
.gift-tab .alert_image {
|
||
width: 256rpx;
|
||
height: 256rpx;
|
||
display: block;
|
||
}
|
||
|
||
.gift-tab .alert_alert {
|
||
position: relative;
|
||
margin: 0 0 0 62rpx;
|
||
}
|
||
|
||
.gift-tab .alert_item {
|
||
position: relative;
|
||
margin: 0 0 0 44rpx;
|
||
}
|
||
|
||
.gift-tab .alert_item image {
|
||
width: 36rpx;
|
||
height: 48rpx;
|
||
}
|
||
|
||
.gift-tab .alert_name {
|
||
margin: 0 14rpx;
|
||
font-weight: 500;
|
||
font-size: 32rpx;
|
||
color: #9779FA;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.gift-tab .alert_explain {
|
||
margin: 18rpx 0 0 0;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
color: #9779FA;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.gift-tab .alert_add {
|
||
margin: 0 0 0 80rpx;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
color: #9779FA;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.gift-tab .alert_money {
|
||
margin: 28rpx 0 0 0;
|
||
font-weight: 700;
|
||
font-size: 44rpx;
|
||
color: #FF0000;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.gift-tab .alert_money text {
|
||
font-size: 28rpx;
|
||
line-height: 65rpx;
|
||
}
|
||
|
||
.gift-tab .alert_number {
|
||
position: relative;
|
||
}
|
||
|
||
.gift-tab .alert_number_title {
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
color: #222222;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.gift-tab .alert_number_content {
|
||
margin: 0 0 0 100rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.gift-tab .alert_number_content image {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
}
|
||
|
||
.gift-tab .alert_number_content input {
|
||
padding: 0 8rpx;
|
||
width: 78rpx;
|
||
font-weight: 500;
|
||
font-size: 28rpx;
|
||
color: #000000;
|
||
line-height: 40rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.gift-tab .alert_number_value {
|
||
color: #333333;
|
||
}
|
||
|
||
.gift-tab .alert_balance {
|
||
margin: 78rpx 0 26rpx 0;
|
||
font-weight: 500;
|
||
font-size: 30rpx;
|
||
color: #909090;
|
||
line-height: 50rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.gift-tab .alert_btn {
|
||
position: relative;
|
||
padding: 26rpx 112rpx;
|
||
font-weight: 500;
|
||
font-size: 30rpx;
|
||
line-height: 50rpx;
|
||
border-radius: 12rpx;
|
||
color: #FFFFFF;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%), #D8D8D8;
|
||
}
|
||
.body {
|
||
position: relative;
|
||
}
|
||
|
||
.back {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 656rpx;
|
||
background: linear-gradient(180deg, #C7A7FF 0%, #F7F7F7 100%);
|
||
}
|
||
|
||
.body {
|
||
position: relative;
|
||
margin: 44rpx 0 0 0;
|
||
padding: 0 40rpx 200rpx 40rpx;
|
||
}
|
||
|
||
.list {
|
||
position: relative;
|
||
width: 100%;
|
||
}
|
||
|
||
.list_logo {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 1164rpx;
|
||
display: block;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.list_content {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 98rpx;
|
||
margin: 0 60rpx;
|
||
padding: 22rpx 0;
|
||
font-weight: 600;
|
||
font-size: 34rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.list_title {
|
||
font-weight: 600;
|
||
font-size: 34rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.list_next {
|
||
margin: 0 0 0 8rpx;
|
||
width: 34rpx;
|
||
height: 8rpx;
|
||
}
|
||
|
||
.list_module {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 36rpx;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.list_item {
|
||
margin: 0 22rpx 0 0;
|
||
width: 60rpx;
|
||
height: 4rpx;
|
||
background: #FFFFFF;
|
||
border-radius: 5rpx;
|
||
}
|
||
|
||
.list_item:nth-child(3) {
|
||
margin: 0 0 0 0;
|
||
}
|
||
|
||
.list_active {
|
||
width: 90rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%), #FFFFFF;
|
||
}
|
||
|
||
.global-block-mask {
|
||
position: fixed;
|
||
top: calc(80rpx + var(--status-bar-height));
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.45);
|
||
z-index: 900;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.global-block-card {
|
||
width: 520rpx;
|
||
padding: 36rpx 28rpx;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
border-radius: 16rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.global-block-title {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
color: #111111;
|
||
line-height: 48rpx;
|
||
}
|
||
|
||
.global-block-sub {
|
||
margin-top: 14rpx;
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
line-height: 38rpx;
|
||
}
|
||
|
||
.global-block-actions {
|
||
margin-top: 22rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.global-block-btn {
|
||
padding: 14rpx 28rpx;
|
||
border-radius: 999rpx;
|
||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||
font-size: 26rpx;
|
||
color: #333333;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
}
|
||
|
||
.backA {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 656rpx;
|
||
background: linear-gradient(180deg, #FFE3E9 0%, #F7F7F7 100%);
|
||
}
|
||
|
||
.bodyA {
|
||
position: relative;
|
||
padding: 0 40rpx 200rpx 40rpx;
|
||
z-index: 2;
|
||
}
|
||
|
||
.listA {
|
||
position: relative;
|
||
height: 1082rpx;
|
||
}
|
||
|
||
.listA_back {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
border-radius: 20rpx;
|
||
}
|
||
|
||
.listA_content {
|
||
position: relative;
|
||
padding: 52rpx 32rpx;
|
||
}
|
||
|
||
.listA_title {
|
||
font-weight: 700;
|
||
font-size: 50rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.listA_module {
|
||
position: relative;
|
||
margin: 34rpx 0 0 0;
|
||
}
|
||
|
||
|
||
.listA_dight {
|
||
position: relative;
|
||
width: 45rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.listA_dight image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
|
||
.listA_grade {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
margin: auto;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.listA_item {
|
||
position: relative;
|
||
margin: 0 0 0 10rpx;
|
||
}
|
||
|
||
.listA_level {
|
||
font-weight: 500;
|
||
font-size: 30rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.listA_level text {
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.listA_line {
|
||
position: relative;
|
||
width: 160rpx;
|
||
height: 12rpx;
|
||
background: rgba(255, 255, 255, 0.5);
|
||
border-radius: 88rpx;
|
||
}
|
||
|
||
.listA_line text {
|
||
position: absolute;
|
||
left: 5rpx;
|
||
top: 0;
|
||
bottom: 0;
|
||
margin: auto 0;
|
||
width: 40rpx;
|
||
height: 8rpx;
|
||
background: linear-gradient(310deg, #D14499 0%, #9F47FF 100%);
|
||
border-radius: 88rpx;
|
||
}
|
||
|
||
.listA_progress {
|
||
position: relative;
|
||
margin: 40rpx 0 0 0;
|
||
}
|
||
|
||
.listA_charts {
|
||
position: relative;
|
||
width: 176rpx;
|
||
height: 93px;
|
||
}
|
||
|
||
.listA_number {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
margin: auto;
|
||
font-weight: 700;
|
||
font-size: 36rpx;
|
||
color: #F661B5;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.listA_number text {
|
||
font-size: 28rpx;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.listA_text {
|
||
margin: -20rpx 0 0 0;
|
||
width: 176rpx;
|
||
font-size: 28rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.listA_dynamics {
|
||
margin: 20rpx 0 0 0;
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
display: block;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
.listA_detail {
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
.listA_white {
|
||
/* position: absolute;
|
||
bottom: -6rpx;
|
||
left: -6rpx;
|
||
width: 300rpx; */
|
||
|
||
position: relative;
|
||
/* bottom: -8rpx; */
|
||
bottom: -12rpx;
|
||
/* left: -8rpx; */
|
||
left: -10rpx;
|
||
width: 300rpx;
|
||
}
|
||
|
||
.listA_chat {
|
||
/* position: relative; */
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
margin: 0 0 5rpx 5rpx;
|
||
width: 230rpx;
|
||
}
|
||
|
||
.listA_backA {
|
||
position: relative;
|
||
width: 100%;
|
||
display: block;
|
||
border-radius: 0 20rpx 20rpx 0;
|
||
}
|
||
|
||
.listA_exchange {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
margin: auto;
|
||
font-weight: 500;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.listA_chatA {
|
||
margin: 0 16rpx 0 0;
|
||
width: 41rpx;
|
||
height: 41rpx;
|
||
}
|
||
|
||
.listA_opt {
|
||
position: absolute;
|
||
right: 25rpx;
|
||
bottom: 13rpx;
|
||
}
|
||
|
||
.listA_phone {
|
||
margin: 0 25rpx 0 0;
|
||
width: 88rpx;
|
||
height: 88rpx;
|
||
}
|
||
|
||
.listA_gift {
|
||
position: relative;
|
||
padding: 12rpx 14rpx;
|
||
font-weight: 500;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
background: rgba(255, 255, 255, 0.3);
|
||
border-radius: 22rpx;
|
||
}
|
||
|
||
.listA_gift image {
|
||
width: 66rpx;
|
||
height: 66rpx;
|
||
}
|
||
|
||
.bannerA {
|
||
position: relative;
|
||
margin: 30rpx 0 0 0;
|
||
width: 100%;
|
||
}
|
||
|
||
.bannerA image {
|
||
width: 100%;
|
||
height: 184rpx;
|
||
display: block;
|
||
border-radius: 0 20rpx 20rpx 0;
|
||
}
|
||
|
||
.bannerA_text {
|
||
position: absolute;
|
||
left: 102rpx;
|
||
top: 0;
|
||
bottom: 0;
|
||
margin: auto;
|
||
font-weight: 700;
|
||
font-size: 40rpx;
|
||
color: #FEFEFE;
|
||
line-height: 50rpx;
|
||
}
|
||
|
||
.promptA {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
margin: auto;
|
||
}
|
||
|
||
.promptA text {
|
||
padding: 22rpx 42rpx;
|
||
font-weight: 500;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
line-height: 50rpx;
|
||
background: #9779FA;
|
||
border-radius: 20rpx;
|
||
}
|
||
|
||
/* 青少年模式遮罩层样式 */
|
||
.underage-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(0, 0, 0, 0.7);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 9;
|
||
}
|
||
|
||
.underage-text {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: white;
|
||
text-align: center;
|
||
padding: 40rpx;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
border-radius: 20rpx;
|
||
}
|
||
|
||
/* Tab 栏样式 - 固定在顶部 */
|
||
.tab-container {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 1000;
|
||
background: rgba(255, 255, 255, 0.95);
|
||
padding: 10rpx 0;
|
||
padding-top: calc(10rpx + var(--status-bar-height));
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.tab-scroll {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.tab-list {
|
||
display: inline-flex;
|
||
padding: 0 20rpx;
|
||
}
|
||
|
||
.tab-item {
|
||
display: inline-block;
|
||
padding: 15rpx 30rpx;
|
||
margin: 0 10rpx;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
border-radius: 30rpx;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.tab-item.active {
|
||
color: #fff;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.tab-name {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* Swiper 容器样式 */
|
||
.swiper-container {
|
||
flex: 1;
|
||
width: 100%;
|
||
height: calc(100vh - 120rpx);
|
||
margin-top: calc(80rpx + var(--status-bar-height));
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
.swiper-scroll {
|
||
height: 100%;
|
||
width: 100%;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
.swiper-content {
|
||
height: 100%;
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* 功能页面样式 */
|
||
.feature-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 40rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.feature-icon {
|
||
font-size: 120rpx;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.feature-title {
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.feature-desc {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
margin-bottom: 40rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.feature-btn {
|
||
padding: 20rpx 60rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
color: #fff;
|
||
border-radius: 50rpx;
|
||
font-size: 30rpx;
|
||
}
|
||
|
||
.feature-scroll {
|
||
width: 100%;
|
||
max-height: 60vh;
|
||
margin-top: 20rpx;
|
||
box-sizing: border-box;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
/* 历史视频样式 */
|
||
.history-section {
|
||
width: 100%;
|
||
padding: 20rpx;
|
||
margin-bottom: 30rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.history-section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 20rpx;
|
||
padding-left: 10rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 0;
|
||
padding-left: 0;
|
||
}
|
||
|
||
.section-more {
|
||
font-size: 26rpx;
|
||
color: #0053FA;
|
||
padding: 8rpx 16rpx;
|
||
border-radius: 20rpx;
|
||
background: rgba(0, 83, 250, 0.08);
|
||
}
|
||
|
||
.history-list {
|
||
width: 100%;
|
||
}
|
||
|
||
.history-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 25rpx;
|
||
margin-bottom: 15rpx;
|
||
background: linear-gradient(135deg, rgba(159, 71, 255, 0.1) 0%, rgba(0, 83, 250, 0.1) 100%);
|
||
border-radius: 15rpx;
|
||
border: 1px solid rgba(159, 71, 255, 0.2);
|
||
}
|
||
|
||
.history-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.history-title {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.history-date {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.history-actions {
|
||
display: flex;
|
||
gap: 15rpx;
|
||
}
|
||
|
||
.history-btn {
|
||
padding: 12rpx 30rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
color: #fff;
|
||
border-radius: 25rpx;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
/* 歌曲列表样式 */
|
||
.song-list {
|
||
width: 100%;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.song-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 25rpx;
|
||
margin-bottom: 20rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 15rpx;
|
||
}
|
||
|
||
.song-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.song-title {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.song-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
/* 跳舞表单样式 */
|
||
.dance-form {
|
||
width: 100%;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.dance-input {
|
||
width: 100%;
|
||
min-height: 200rpx;
|
||
padding: 20rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 15rpx;
|
||
font-size: 28rpx;
|
||
margin-bottom: 30rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.dance-btn {
|
||
width: 100%;
|
||
padding: 25rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
color: #fff;
|
||
text-align: center;
|
||
border-radius: 50rpx;
|
||
font-size: 30rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 商城列表样式 */
|
||
.shop-list {
|
||
width: 100%;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.shop-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 15rpx;
|
||
}
|
||
|
||
.shop-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.shop-title {
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.shop-desc {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.shop-price {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.price-value {
|
||
font-size: 36rpx;
|
||
color: #ff4444;
|
||
font-weight: bold;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.shop-buy-btn {
|
||
padding: 10rpx 30rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
color: #fff;
|
||
border-radius: 30rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
/* 商城外部链接页面样式 */
|
||
.shop-link-page {
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.shop-link-page:active {
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
.shop-link-banner {
|
||
width: 80%;
|
||
max-width: 500rpx;
|
||
margin: 40rpx auto;
|
||
padding: 40rpx;
|
||
background: linear-gradient(135deg, #FFE5F0 0%, #E5F0FF 100%);
|
||
border-radius: 20rpx;
|
||
border: 2rpx solid #9F47FF;
|
||
box-shadow: 0 8rpx 20rpx rgba(159, 71, 255, 0.2);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.shop-banner-img {
|
||
width: 200rpx;
|
||
height: 200rpx;
|
||
}
|
||
|
||
.shop-link-text {
|
||
font-size: 32rpx;
|
||
color: #9F47FF;
|
||
font-weight: bold;
|
||
text-align: center;
|
||
}
|
||
|
||
.shop-external-btn {
|
||
background: linear-gradient(135deg, #FF6B9D 0%, #C239B3 100%);
|
||
font-weight: bold;
|
||
box-shadow: 0 4rpx 12rpx rgba(255, 107, 157, 0.3);
|
||
}
|
||
|
||
/* ========== 新商城页面全屏设计样式 ========== */
|
||
.shop-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.shop-hero {
|
||
flex: 1;
|
||
position: relative;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.shop-hero-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(135deg,
|
||
#FFE5F5 0%,
|
||
#F5E5FF 25%,
|
||
#E5F0FF 50%,
|
||
#FFE5F0 75%,
|
||
#F5F0FF 100%);
|
||
animation: gradientShift 10s ease infinite;
|
||
}
|
||
|
||
@keyframes gradientShift {
|
||
0%, 100% {
|
||
background-position: 0% 50%;
|
||
}
|
||
50% {
|
||
background-position: 100% 50%;
|
||
}
|
||
}
|
||
|
||
/* 装饰圆圈 */
|
||
.shop-decoration {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
z-index: 1;
|
||
}
|
||
|
||
.shop-circle {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle, rgba(159, 71, 255, 0.15) 0%, transparent 70%);
|
||
animation: float 6s ease-in-out infinite;
|
||
}
|
||
|
||
.shop-circle-1 {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
top: 10%;
|
||
left: -10%;
|
||
animation-delay: 0s;
|
||
}
|
||
|
||
.shop-circle-2 {
|
||
width: 200rpx;
|
||
height: 200rpx;
|
||
top: 60%;
|
||
right: -5%;
|
||
animation-delay: 2s;
|
||
}
|
||
|
||
.shop-circle-3 {
|
||
width: 250rpx;
|
||
height: 250rpx;
|
||
bottom: 15%;
|
||
left: 10%;
|
||
animation-delay: 4s;
|
||
}
|
||
|
||
.shop-circle-4 {
|
||
width: 180rpx;
|
||
height: 180rpx;
|
||
top: 30%;
|
||
right: 15%;
|
||
animation-delay: 1s;
|
||
}
|
||
|
||
.shop-hero-content {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 60rpx 40rpx;
|
||
z-index: 2;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 顶部标签 */
|
||
.shop-hot-badge {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
padding: 12rpx 28rpx;
|
||
background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
|
||
border-radius: 30rpx;
|
||
margin-bottom: 40rpx;
|
||
box-shadow: 0 8rpx 20rpx rgba(255, 215, 0, 0.4);
|
||
animation: pulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
.shop-hot-icon {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.shop-hot-text {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
/* 商城图标 */
|
||
.shop-icon-wrapper {
|
||
position: relative;
|
||
width: 200rpx;
|
||
height: 200rpx;
|
||
margin-bottom: 40rpx;
|
||
}
|
||
|
||
.shop-main-icon {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
z-index: 2;
|
||
animation: bounce 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes bounce {
|
||
0%, 100% {
|
||
transform: translateY(0);
|
||
}
|
||
50% {
|
||
transform: translateY(-20rpx);
|
||
}
|
||
}
|
||
|
||
.shop-icon-glow {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 240rpx;
|
||
height: 240rpx;
|
||
background: radial-gradient(circle, rgba(159, 71, 255, 0.3) 0%, transparent 70%);
|
||
border-radius: 50%;
|
||
animation: glow 2s ease-in-out infinite;
|
||
z-index: 1;
|
||
}
|
||
|
||
@keyframes glow {
|
||
0%, 100% {
|
||
opacity: 0.5;
|
||
transform: translate(-50%, -50%) scale(1);
|
||
}
|
||
50% {
|
||
opacity: 1;
|
||
transform: translate(-50%, -50%) scale(1.2);
|
||
}
|
||
}
|
||
|
||
/* 标题 */
|
||
.shop-hero-title {
|
||
font-size: 64rpx;
|
||
font-weight: bold;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #FF6B9D 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
text-align: center;
|
||
margin-bottom: 20rpx;
|
||
letter-spacing: 4rpx;
|
||
}
|
||
|
||
.shop-hero-subtitle {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
text-align: center;
|
||
margin-bottom: 50rpx;
|
||
}
|
||
|
||
/* 特色网格 */
|
||
.shop-features-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 20rpx;
|
||
width: 100%;
|
||
max-width: 500rpx;
|
||
margin-bottom: 50rpx;
|
||
}
|
||
|
||
.shop-feature-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
padding: 30rpx 20rpx;
|
||
background: rgba(255, 255, 255, 0.8);
|
||
backdrop-filter: blur(10rpx);
|
||
border-radius: 20rpx;
|
||
border: 2rpx solid rgba(159, 71, 255, 0.2);
|
||
box-shadow: 0 4rpx 12rpx rgba(159, 71, 255, 0.1);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.shop-feature-card:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.shop-feature-emoji {
|
||
font-size: 48rpx;
|
||
}
|
||
|
||
.shop-feature-label {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 进入按钮 */
|
||
.shop-enter-button {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15rpx;
|
||
padding: 28rpx 60rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #FF6B9D 100%);
|
||
border-radius: 60rpx;
|
||
box-shadow: 0 12rpx 30rpx rgba(159, 71, 255, 0.4);
|
||
margin-bottom: 30rpx;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.shop-enter-button:active {
|
||
transform: scale(0.95);
|
||
box-shadow: 0 8rpx 20rpx rgba(159, 71, 255, 0.3);
|
||
}
|
||
|
||
.shop-enter-text {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
letter-spacing: 2rpx;
|
||
}
|
||
|
||
.shop-enter-arrow {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
/* 提示文字 */
|
||
.shop-hint {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
padding: 12rpx 24rpx;
|
||
background: rgba(159, 71, 255, 0.1);
|
||
backdrop-filter: blur(10rpx);
|
||
border-radius: 30rpx;
|
||
animation: float 3s ease-in-out infinite;
|
||
}
|
||
|
||
.shop-hint-icon {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.shop-hint-text {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
/* 短剧列表样式 */
|
||
.drama-list {
|
||
width: 100%;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.drama-item {
|
||
display: flex;
|
||
margin-bottom: 30rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 15rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.drama-cover {
|
||
width: 200rpx;
|
||
height: 150rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.drama-info {
|
||
flex: 1;
|
||
padding: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.drama-title {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.drama-desc {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.drama-play-btn {
|
||
align-self: flex-start;
|
||
padding: 8rpx 25rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
color: #fff;
|
||
border-radius: 20rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
/* 短剧外部链接特殊样式 */
|
||
.drama-link-item {
|
||
position: relative;
|
||
background: linear-gradient(135deg, #FFE5F0 0%, #E5F0FF 100%);
|
||
border: 2rpx solid #9F47FF;
|
||
box-shadow: 0 4rpx 12rpx rgba(159, 71, 255, 0.2);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.drama-link-item:active {
|
||
transform: scale(0.98);
|
||
box-shadow: 0 2rpx 8rpx rgba(159, 71, 255, 0.3);
|
||
}
|
||
|
||
.drama-banner {
|
||
width: 200rpx;
|
||
height: 150rpx;
|
||
border-right: 2rpx solid rgba(159, 71, 255, 0.2);
|
||
}
|
||
|
||
.drama-link-badge {
|
||
position: absolute;
|
||
top: 10rpx;
|
||
left: 10rpx;
|
||
padding: 4rpx 12rpx;
|
||
background: linear-gradient(135deg, #FF6B9D 0%, #C239B3 100%);
|
||
color: #fff;
|
||
font-size: 20rpx;
|
||
border-radius: 8rpx;
|
||
font-weight: bold;
|
||
z-index: 1;
|
||
}
|
||
|
||
.drama-external-btn {
|
||
background: linear-gradient(135deg, #FF6B9D 0%, #C239B3 100%);
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* ========== 新短剧页面全屏海报样式 ========== */
|
||
.drama-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #000;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.drama-hero {
|
||
flex: 1;
|
||
position: relative;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.drama-hero-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.drama-hero-overlay {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(180deg,
|
||
rgba(0, 0, 0, 0.3) 0%,
|
||
rgba(0, 0, 0, 0.5) 50%,
|
||
rgba(0, 0, 0, 0.8) 100%);
|
||
z-index: 1;
|
||
}
|
||
|
||
.drama-hero-content {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 60rpx 40rpx;
|
||
z-index: 2;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 热门标签 */
|
||
.drama-hot-badge {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
padding: 12rpx 24rpx;
|
||
background: linear-gradient(135deg, #FF6B9D 0%, #FF4757 100%);
|
||
border-radius: 30rpx;
|
||
margin-bottom: 40rpx;
|
||
box-shadow: 0 8rpx 20rpx rgba(255, 107, 157, 0.4);
|
||
animation: pulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% {
|
||
transform: scale(1);
|
||
}
|
||
50% {
|
||
transform: scale(1.05);
|
||
}
|
||
}
|
||
|
||
.drama-hot-icon {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.drama-hot-text {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
/* 标题 */
|
||
.drama-hero-title {
|
||
font-size: 72rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
text-align: center;
|
||
margin-bottom: 20rpx;
|
||
text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.5);
|
||
letter-spacing: 4rpx;
|
||
}
|
||
|
||
.drama-hero-subtitle {
|
||
font-size: 32rpx;
|
||
color: rgba(255, 255, 255, 0.9);
|
||
text-align: center;
|
||
margin-bottom: 50rpx;
|
||
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
/* 标签组 */
|
||
.drama-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
gap: 15rpx;
|
||
margin-bottom: 60rpx;
|
||
padding: 0 20rpx;
|
||
}
|
||
|
||
.drama-tag {
|
||
padding: 12rpx 24rpx;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
backdrop-filter: blur(10rpx);
|
||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||
border-radius: 30rpx;
|
||
font-size: 26rpx;
|
||
color: #FFFFFF;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 播放按钮 */
|
||
.drama-play-button {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15rpx;
|
||
padding: 28rpx 60rpx;
|
||
background: linear-gradient(135deg, #FF6B9D 0%, #C239B3 100%);
|
||
border-radius: 60rpx;
|
||
box-shadow: 0 12rpx 30rpx rgba(255, 107, 157, 0.5);
|
||
margin-bottom: 40rpx;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.drama-play-button:active {
|
||
transform: scale(0.95);
|
||
box-shadow: 0 8rpx 20rpx rgba(255, 107, 157, 0.4);
|
||
}
|
||
|
||
.drama-play-icon {
|
||
font-size: 36rpx;
|
||
color: #FFFFFF;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.drama-play-text {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
letter-spacing: 2rpx;
|
||
}
|
||
|
||
/* 提示文字 */
|
||
.drama-hint {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
padding: 12rpx 24rpx;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
backdrop-filter: blur(10rpx);
|
||
border-radius: 30rpx;
|
||
animation: float 3s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes float {
|
||
0%, 100% {
|
||
transform: translateY(0);
|
||
}
|
||
50% {
|
||
transform: translateY(-10rpx);
|
||
}
|
||
}
|
||
|
||
.drama-hint-icon {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.drama-hint-text {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
}
|
||
|
||
/* 底部特色推荐 */
|
||
.drama-features {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
padding: 30rpx 20rpx;
|
||
background: rgba(0, 0, 0, 0.8);
|
||
backdrop-filter: blur(20rpx);
|
||
border-top: 1rpx solid rgba(255, 255, 255, 0.1);
|
||
z-index: 3;
|
||
}
|
||
|
||
.drama-feature-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
}
|
||
|
||
.drama-feature-icon {
|
||
font-size: 48rpx;
|
||
}
|
||
|
||
.drama-feature-text {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
}
|
||
|
||
/* 自定义细线指示器样式 */
|
||
.swiper-indicator {
|
||
position: fixed;
|
||
bottom: 20rpx;
|
||
left: 0;
|
||
right: 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
z-index: 100;
|
||
padding: 0 20rpx;
|
||
transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
|
||
transform: translateY(0);
|
||
opacity: 1;
|
||
}
|
||
|
||
.swiper-indicator.indicator-hidden {
|
||
transform: translateY(100%);
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.indicator-line {
|
||
flex: 1;
|
||
height: 3rpx;
|
||
background: rgba(0, 0, 0, 0.1);
|
||
border-radius: 2rpx;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.indicator-line.active {
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
height: 4rpx;
|
||
}
|
||
|
||
/* 聊天预览容器样式 */
|
||
.chat-preview-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 40rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.chat-preview-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 40rpx;
|
||
padding-bottom: 20rpx;
|
||
border-bottom: 2rpx solid #f0f0f0;
|
||
}
|
||
|
||
.chat-preview-title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.chat-preview-btn {
|
||
padding: 15rpx 30rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
color: #fff;
|
||
border-radius: 30rpx;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.chat-preview-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 60rpx 40rpx;
|
||
}
|
||
|
||
.chat-preview-tip {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
margin-bottom: 60rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.chat-preview-image {
|
||
width: 300rpx;
|
||
height: 300rpx;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
margin-bottom: 30rpx;
|
||
box-shadow: 0 8rpx 20rpx rgba(159, 71, 255, 0.2);
|
||
}
|
||
|
||
.chat-preview-image image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.chat-preview-name {
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.chat-preview-desc {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
|
||
/* 换装页面样式 - 和谐配色 */
|
||
.outfit-container {
|
||
width: 100%;
|
||
min-height: 100%;
|
||
padding: 30rpx;
|
||
background: linear-gradient(180deg, #f8f9fa 0%, #ffffff 100%);
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.outfit-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 20rpx 0;
|
||
margin-bottom: 30rpx;
|
||
border-bottom: 1rpx solid #e8e8e8;
|
||
}
|
||
|
||
.outfit-title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.outfit-count {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
padding: 8rpx 20rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 20rpx;
|
||
}
|
||
|
||
.outfit-loading {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 100rpx 0;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.outfit-content {
|
||
width: 100%;
|
||
padding-bottom: 40rpx;
|
||
}
|
||
|
||
.outfit-section {
|
||
margin-bottom: 50rpx;
|
||
background: #fff;
|
||
border-radius: 20rpx;
|
||
padding: 30rpx 20rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: 500;
|
||
color: #555;
|
||
margin-bottom: 25rpx;
|
||
padding-left: 10rpx;
|
||
border-left: 4rpx solid #8a7cff;
|
||
}
|
||
|
||
.section-title-top {
|
||
font-size: 70rpx !important;
|
||
font-weight: bold !important;
|
||
color: #000 !important;
|
||
text-align: center !important;
|
||
margin: 0 0 40rpx 0 !important;
|
||
padding: 20rpx 0 !important;
|
||
background: #f0f0f0 !important;
|
||
border-radius: 12rpx !important;
|
||
display: block !important;
|
||
width: 100% !important;
|
||
}
|
||
|
||
/* 网格容器 - 使用固定宽度 */
|
||
.outfit-grid-wrapper {
|
||
width: 100%;
|
||
overflow: hidden;
|
||
text-align: left;
|
||
}
|
||
|
||
.outfit-item-wrapper {
|
||
float: left;
|
||
width: 220rpx;
|
||
margin-right: 15rpx;
|
||
margin-bottom: 20rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.outfit-grid-inner {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 280rpx;
|
||
border-radius: 12rpx;
|
||
overflow: hidden;
|
||
background: #fff;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
|
||
transition: all 0.3s ease;
|
||
border: 5rpx solid #ddd;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.outfit-grid-item-selected .outfit-grid-inner {
|
||
border: 5rpx solid #ff0000 !important;
|
||
box-shadow: 0 4rpx 20rpx rgba(255, 0, 0, 0.4) !important;
|
||
}
|
||
|
||
.outfit-grid-img {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.outfit-check-mark {
|
||
position: absolute !important;
|
||
top: 8rpx !important;
|
||
left: 8rpx !important;
|
||
width: 40rpx !important;
|
||
height: 40rpx !important;
|
||
background: #8a7cff;
|
||
color: #fff;
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 10 !important;
|
||
pointer-events: none;
|
||
line-height: 1;
|
||
}
|
||
|
||
.outfit-grid-badge {
|
||
position: absolute;
|
||
top: 8rpx;
|
||
right: 8rpx;
|
||
padding: 8rpx 16rpx;
|
||
background: rgba(255, 0, 0, 0.9);
|
||
color: #fff;
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
border-radius: 12rpx;
|
||
z-index: 2;
|
||
}
|
||
|
||
.outfit-grid-lock {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
font-size: 60rpx;
|
||
opacity: 0.8;
|
||
z-index: 3;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.outfit-generate-btn {
|
||
margin: 20rpx 0;
|
||
padding: 28rpx 0;
|
||
background: linear-gradient(135deg, #8a7cff 0%, #6b5ce7 100%);
|
||
color: #fff;
|
||
text-align: center;
|
||
border-radius: 16rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
box-shadow: 0 8rpx 20rpx rgba(138, 124, 255, 0.3);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.outfit-generate-btn:active {
|
||
transform: scale(0.98);
|
||
box-shadow: 0 4rpx 12rpx rgba(138, 124, 255, 0.3);
|
||
}
|
||
|
||
/* ========== 聊天 Swiper 页面样式 ========== */
|
||
.chat-swiper-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 0;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.chat-message-scroll {
|
||
flex: 1;
|
||
height: 0;
|
||
min-height: 0;
|
||
padding: 20rpx;
|
||
padding-left: 30rpx;
|
||
padding-right: 30rpx;
|
||
box-sizing: border-box;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.chat-message-list {
|
||
width: 100%;
|
||
}
|
||
|
||
.chat-message-item {
|
||
display: flex;
|
||
margin-bottom: 30rpx;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.message-left {
|
||
flex-direction: row;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.message-right {
|
||
flex-direction: row-reverse;
|
||
justify-content: flex-start;
|
||
padding-left: 0;
|
||
}
|
||
|
||
.chat-avatar {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.chat-message-bubble {
|
||
max-width: 420rpx; /* 减小气泡宽度,给头像留更多空间 */
|
||
padding: 20rpx 25rpx;
|
||
border-radius: 20rpx;
|
||
margin: 0 20rpx;
|
||
}
|
||
|
||
.message-left .chat-message-bubble {
|
||
background: #fff;
|
||
border-top-left-radius: 5rpx;
|
||
}
|
||
|
||
.message-right .chat-message-bubble {
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
}
|
||
|
||
.chat-message-text {
|
||
font-size: 28rpx;
|
||
line-height: 1.6;
|
||
word-wrap: break-word;
|
||
}
|
||
|
||
.message-left .chat-message-text {
|
||
color: #333;
|
||
}
|
||
|
||
.message-right .chat-message-text {
|
||
color: #fff;
|
||
}
|
||
|
||
.chat-input-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 10rpx 20rpx;
|
||
padding-bottom: calc(10rpx + env(safe-area-inset-bottom));
|
||
background: #fff;
|
||
border-top: 1rpx solid #e5e5e5;
|
||
box-sizing: border-box;
|
||
flex-shrink: 0; /* 防止被压缩 */
|
||
}
|
||
|
||
.chat-message-input {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
padding: 0 25rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 40rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.chat-send-btn {
|
||
margin-left: 20rpx;
|
||
padding: 20rpx 40rpx;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #0053FA 100%);
|
||
color: #fff;
|
||
border-radius: 40rpx;
|
||
font-size: 28rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ========== 底部 Tab 栏隐藏动画 ========== */
|
||
.bottom-tab-bar {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 999;
|
||
transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
|
||
transform: translateY(0);
|
||
opacity: 1;
|
||
}
|
||
|
||
.bottom-tab-bar.tab-bar-hidden {
|
||
transform: translateY(100%); /* 向下移动,完全隐藏 */
|
||
opacity: 0; /* 透明度为0 */
|
||
pointer-events: none; /* 禁用点击事件 */
|
||
}
|
||
.modal-mask {
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0,0,0,0.6);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 9999;
|
||
}
|
||
.modal-card {
|
||
width: 92%;
|
||
max-height: 80%;
|
||
background: #ffffff;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
box-sizing: border-box;
|
||
}
|
||
.modal-header {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24rpx;
|
||
border-bottom: 1px solid rgba(0,0,0,0.06);
|
||
}
|
||
.modal-title {
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
max-width: 70%;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #333333;
|
||
}
|
||
.modal-close {
|
||
position: absolute;
|
||
right: 24rpx;
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
padding: 6rpx 12rpx;
|
||
}
|
||
.modal-list {
|
||
max-height: 60vh;
|
||
padding: 12rpx 24rpx 24rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
.modal-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 12rpx;
|
||
padding: 16rpx 0;
|
||
border-bottom: 1px solid rgba(0,0,0,0.06);
|
||
}
|
||
.modal-item-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex: 1;
|
||
min-width: 0;
|
||
padding-right: 12rpx;
|
||
}
|
||
.modal-item-title {
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.modal-retry {
|
||
min-width: 112rpx;
|
||
max-width: 140rpx;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
font-size: 24rpx;
|
||
color: #ffffff;
|
||
background: #1DB954;
|
||
padding: 10rpx 16rpx;
|
||
border-radius: 12rpx;
|
||
text-align: center;
|
||
box-sizing: border-box;
|
||
margin-left: 12rpx;
|
||
}
|
||
.modal-item-date {
|
||
font-size: 22rpx;
|
||
color: #999999;
|
||
margin-top: 6rpx;
|
||
}
|
||
.modal-item-status {
|
||
font-size: 22rpx;
|
||
color: #666666;
|
||
margin-top: 6rpx;
|
||
line-height: 1.4;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.modal-item-actions {
|
||
flex: 0 0 auto;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
margin-left: auto;
|
||
padding-left: 12rpx;
|
||
}
|
||
.modal-play {
|
||
min-width: 112rpx;
|
||
max-width: 140rpx;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
font-size: 24rpx;
|
||
color: #ffffff;
|
||
background: #F661B5;
|
||
padding: 10rpx 16rpx;
|
||
border-radius: 12rpx;
|
||
text-align: center;
|
||
box-sizing: border-box;
|
||
}
|
||
.modal-video {
|
||
width: 100%;
|
||
height: 420rpx;
|
||
background: #000000;
|
||
}
|
||
|
||
/* ========== 首页卡片式设计样式 ========== */
|
||
.home-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: linear-gradient(180deg, #F8F3FF 0%, #FFF5F9 50%, #F0F8FF 100%);
|
||
padding: 20rpx 30rpx;
|
||
box-sizing: border-box;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
/* 顶部操作栏 */
|
||
.home-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 20rpx 0;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.home-header-btn {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
padding: 10rpx 15rpx;
|
||
background: rgba(255, 255, 255, 0.8);
|
||
border-radius: 16rpx;
|
||
transition: all 0.3s ease;
|
||
box-shadow: 0 2rpx 8rpx rgba(159, 71, 255, 0.1);
|
||
}
|
||
|
||
.home-header-btn:active {
|
||
transform: scale(0.95);
|
||
background: rgba(255, 255, 255, 1);
|
||
}
|
||
|
||
.home-header-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.home-header-text {
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.home-header-spacer {
|
||
flex: 1;
|
||
}
|
||
|
||
/* 选择互动对象标题 */
|
||
.home-title {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 15rpx 0;
|
||
margin-bottom: 25rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.home-title-icon {
|
||
font-size: 24rpx;
|
||
color: #9F47FF;
|
||
margin: 0 10rpx;
|
||
}
|
||
|
||
.home-title-text {
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
|
||
.home-title-more {
|
||
position: absolute;
|
||
right: 0;
|
||
font-size: 24rpx;
|
||
color: #9F47FF;
|
||
padding: 6rpx 16rpx;
|
||
background: rgba(159, 71, 255, 0.1);
|
||
border-radius: 20rpx;
|
||
}
|
||
|
||
/* 主卡片区域 */
|
||
.home-card {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 30rpx;
|
||
padding: 0 10rpx;
|
||
}
|
||
|
||
.home-card-inner {
|
||
width: 100%;
|
||
max-width: 600rpx;
|
||
background: linear-gradient(180deg, #FFFFFF 0%, #FFF5F9 100%);
|
||
border-radius: 30rpx;
|
||
padding: 30rpx;
|
||
box-shadow: 0 12rpx 40rpx rgba(159, 71, 255, 0.15);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.home-card-inner::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: -50%;
|
||
left: -50%;
|
||
width: 200%;
|
||
height: 200%;
|
||
background: radial-gradient(circle, rgba(159, 71, 255, 0.05) 0%, transparent 70%);
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 女友名字 */
|
||
.home-card-name {
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
color: #9F47FF;
|
||
margin-bottom: 20rpx;
|
||
text-align: center;
|
||
z-index: 1;
|
||
}
|
||
|
||
/* 女友图片 */
|
||
.home-card-image {
|
||
width: 400rpx;
|
||
height: 500rpx;
|
||
border-radius: 20rpx;
|
||
margin-bottom: 25rpx;
|
||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
|
||
z-index: 1;
|
||
}
|
||
|
||
/* 性格标签 */
|
||
.home-card-tags {
|
||
display: flex;
|
||
gap: 15rpx;
|
||
margin-bottom: 25rpx;
|
||
z-index: 1;
|
||
}
|
||
|
||
.home-card-tag {
|
||
padding: 8rpx 20rpx;
|
||
background: linear-gradient(135deg, rgba(159, 71, 255, 0.15) 0%, rgba(255, 107, 157, 0.15) 100%);
|
||
color: #9F47FF;
|
||
font-size: 24rpx;
|
||
border-radius: 20rpx;
|
||
border: 1rpx solid rgba(159, 71, 255, 0.3);
|
||
}
|
||
|
||
/* 对话气泡 */
|
||
.home-card-bubble {
|
||
width: 100%;
|
||
padding: 20rpx 25rpx;
|
||
background: rgba(159, 71, 255, 0.08);
|
||
border-radius: 20rpx;
|
||
border-left: 4rpx solid #9F47FF;
|
||
margin-bottom: 30rpx;
|
||
z-index: 1;
|
||
}
|
||
|
||
.home-card-bubble-text {
|
||
font-size: 26rpx;
|
||
color: #555;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
/* 底部操作按钮 */
|
||
.home-card-actions {
|
||
width: 100%;
|
||
display: flex;
|
||
gap: 20rpx;
|
||
z-index: 1;
|
||
}
|
||
|
||
.home-card-btn {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 20rpx;
|
||
border-radius: 50rpx;
|
||
transition: all 0.3s ease;
|
||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.home-card-btn:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.home-card-btn-home {
|
||
flex: 0 0 auto;
|
||
width: 100rpx;
|
||
background: linear-gradient(135deg, #FFE5F0 0%, #E5F0FF 100%);
|
||
border: 2rpx solid rgba(159, 71, 255, 0.2);
|
||
}
|
||
|
||
.home-card-btn-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
|
||
.home-card-btn-chat {
|
||
background: linear-gradient(135deg, #9F47FF 0%, #FF6B9D 100%);
|
||
box-shadow: 0 8rpx 20rpx rgba(159, 71, 255, 0.3);
|
||
}
|
||
|
||
.home-card-btn-text {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
/* 底部头像轮播 */
|
||
.home-avatars {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 20rpx;
|
||
padding: 20rpx 0;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.home-avatar-item {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
border: 3rpx solid #FFFFFF;
|
||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||
transition: all 0.3s ease;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.home-avatar-item:active {
|
||
transform: scale(1.15);
|
||
}
|
||
|
||
/* 选中状态 - 紫色边框 */
|
||
.home-avatar-item.home-avatar-active {
|
||
border-color: #9F47FF;
|
||
border-width: 4rpx;
|
||
box-shadow: 0 4rpx 16rpx rgba(159, 71, 255, 0.4);
|
||
transform: scale(1.05);
|
||
}
|
||
|
||
.home-avatar-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
/* 好感度信息 */
|
||
.home-intimacy {
|
||
width: 100%;
|
||
padding: 20rpx 30rpx;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
border-radius: 20rpx;
|
||
box-shadow: 0 4rpx 12rpx rgba(159, 71, 255, 0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15rpx;
|
||
}
|
||
|
||
.home-intimacy-level {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #9F47FF;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.home-intimacy-bar {
|
||
flex: 1;
|
||
height: 16rpx;
|
||
background: #E5E5E5;
|
||
border-radius: 8rpx;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
.home-intimacy-progress {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #FF6B9D 0%, #9F47FF 100%);
|
||
border-radius: 8rpx;
|
||
transition: width 0.5s ease;
|
||
}
|
||
|
||
.home-intimacy-text {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ========== 首页商城横幅样式 ========== */
|
||
.home-shop-banner {
|
||
position: relative;
|
||
width: 100%;
|
||
padding: 0;
|
||
margin-bottom: 20rpx;
|
||
border-radius: 20rpx;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
box-shadow: 0 8rpx 24rpx rgba(159, 71, 255, 0.2);
|
||
}
|
||
|
||
.home-shop-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(135deg, #FFE5F5 0%, #F5E5FF 50%, #E5F0FF 100%);
|
||
z-index: 1;
|
||
}
|
||
|
||
.home-shop-circle {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%);
|
||
}
|
||
|
||
.home-shop-circle-1 {
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
top: -30rpx;
|
||
left: -20rpx;
|
||
}
|
||
|
||
.home-shop-circle-2 {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
bottom: -20rpx;
|
||
right: 50rpx;
|
||
}
|
||
|
||
.home-shop-circle-3 {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
top: 20rpx;
|
||
right: -10rpx;
|
||
}
|
||
|
||
.home-shop-content {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 25rpx 30rpx;
|
||
z-index: 2;
|
||
}
|
||
|
||
.home-shop-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20rpx;
|
||
flex: 1;
|
||
}
|
||
|
||
.home-shop-icon-wrapper {
|
||
position: relative;
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.home-shop-icon {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 50%;
|
||
box-shadow: 0 4rpx 12rpx rgba(159, 71, 255, 0.3);
|
||
}
|
||
|
||
.home-shop-badge {
|
||
position: absolute;
|
||
top: -8rpx;
|
||
right: -8rpx;
|
||
padding: 4rpx 10rpx;
|
||
background: linear-gradient(135deg, #FF6B9D 0%, #FF4757 100%);
|
||
color: #FFFFFF;
|
||
font-size: 18rpx;
|
||
font-weight: bold;
|
||
border-radius: 10rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(255, 107, 157, 0.4);
|
||
animation: pulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
.home-shop-text {
|
||
flex: 1;
|
||
}
|
||
|
||
.home-shop-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
margin-bottom: 6rpx;
|
||
}
|
||
|
||
.home-shop-title-main {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #FF6B9D 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
.home-shop-title-emoji {
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.home-shop-desc {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.home-shop-button {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
padding: 15rpx 28rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #FF6B9D 100%);
|
||
border-radius: 40rpx;
|
||
box-shadow: 0 4rpx 12rpx rgba(159, 71, 255, 0.3);
|
||
flex-shrink: 0;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.home-shop-banner:active .home-shop-button {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.home-shop-button-text {
|
||
font-size: 26rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
.home-shop-button-arrow {
|
||
font-size: 26rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
}
|
||
|
||
/* 闪光效果 */
|
||
.home-shop-shine {
|
||
position: absolute;
|
||
top: 0;
|
||
left: -100%;
|
||
width: 50%;
|
||
height: 100%;
|
||
background: linear-gradient(90deg,
|
||
transparent 0%,
|
||
rgba(255, 255, 255, 0.3) 50%,
|
||
transparent 100%);
|
||
transform: skewX(-20deg);
|
||
animation: shine 3s ease-in-out infinite;
|
||
z-index: 3;
|
||
pointer-events: none;
|
||
}
|
||
|
||
@keyframes shine {
|
||
0% {
|
||
left: -100%;
|
||
}
|
||
20%, 100% {
|
||
left: 150%;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<style>
|
||
/* ========== 唱歌页面音乐库样式 ========== */
|
||
.sing-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.sing-tabs {
|
||
display: flex;
|
||
background: #fff;
|
||
padding: 10rpx 20rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.sing-tab-item {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 20rpx 0;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
position: relative;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.sing-tab-active {
|
||
color: #9F47FF;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.sing-tab-active::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 60rpx;
|
||
height: 4rpx;
|
||
background: linear-gradient(90deg, #9F47FF 0%, #FF6B9D 100%);
|
||
border-radius: 2rpx;
|
||
}
|
||
|
||
.sing-scroll {
|
||
flex: 1;
|
||
height: 0;
|
||
}
|
||
|
||
.sing-content {
|
||
padding: 20rpx;
|
||
}
|
||
|
||
/* 添加音乐按钮 */
|
||
.music-add-btns {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.music-add-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10rpx;
|
||
padding: 20rpx 40rpx;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #FF6B9D 100%);
|
||
color: #fff;
|
||
border-radius: 50rpx;
|
||
box-shadow: 0 8rpx 20rpx rgba(159, 71, 255, 0.3);
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.music-add-btn:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
.music-add-icon {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.music-add-text {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 音乐库列表 */
|
||
.music-library-list {
|
||
width: 100%;
|
||
}
|
||
|
||
.music-library-item {
|
||
display: flex;
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 20rpx;
|
||
margin-bottom: 20rpx;
|
||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
.music-library-cover {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
border-radius: 12rpx;
|
||
overflow: hidden;
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.music-cover-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.music-play-overlay {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.3);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.music-play-overlay:active {
|
||
background: rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
.music-play-icon {
|
||
font-size: 60rpx;
|
||
color: #fff;
|
||
}
|
||
|
||
.music-library-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.music-library-title {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 8rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.music-library-artist {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.music-library-meta {
|
||
display: flex;
|
||
gap: 20rpx;
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.music-meta-item {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 加载更多 */
|
||
.music-load-more {
|
||
text-align: center;
|
||
padding: 30rpx;
|
||
color: #9F47FF;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
/* 空状态 */
|
||
.music-empty {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 100rpx 40rpx;
|
||
}
|
||
|
||
.music-empty-icon {
|
||
font-size: 120rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.music-empty-text {
|
||
font-size: 32rpx;
|
||
color: #666;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.music-empty-desc {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
/* 添加音乐弹窗 */
|
||
.music-modal-card {
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.music-modal-body {
|
||
padding: 30rpx;
|
||
}
|
||
|
||
.music-form-item {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.music-form-label {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 15rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.music-form-input {
|
||
width: 100%;
|
||
padding: 20rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 12rpx;
|
||
font-size: 28rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.music-form-textarea {
|
||
width: 100%;
|
||
min-height: 150rpx;
|
||
padding: 20rpx;
|
||
background: #f5f5f5;
|
||
border-radius: 12rpx;
|
||
font-size: 28rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.music-modal-btn {
|
||
padding: 28rpx 0;
|
||
background: linear-gradient(135deg, #9F47FF 0%, #FF6B9D 100%);
|
||
color: #fff;
|
||
text-align: center;
|
||
border-radius: 16rpx;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
box-shadow: 0 8rpx 20rpx rgba(159, 71, 255, 0.3);
|
||
margin-top: 20rpx;
|
||
}
|
||
|
||
.music-modal-btn:active {
|
||
transform: scale(0.98);
|
||
}
|
||
</style>
|