style:修改主页样式和个人页样式
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
## 一、页面结构
|
## 一、页面结构
|
||||||
|
|
||||||
|
### 完整页面布局(4个分类区块纵向堆叠)
|
||||||
|
|
||||||
```
|
```
|
||||||
┌──────────────────────────────────────┐
|
┌──────────────────────────────────────┐
|
||||||
│ 热门推荐 │
|
│ BannerCarousel │
|
||||||
├──────────────────────────────────────┤
|
├──────────────────────────────────────┤
|
||||||
|
│ 热门推荐 │
|
||||||
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
│ │ │ │ │ │ │ │ │ ← 行1 │
|
│ │ │ │ │ │ │ │ │ ← 行1 │
|
||||||
│ └────┘ └────┘ └────┘ └────┘ │
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
@ -13,6 +16,52 @@
|
|||||||
│ │ │ │ │ │ │ │ │ ← 行2 │
|
│ │ │ │ │ │ │ │ │ ← 行2 │
|
||||||
│ └────┘ └────┘ └────┘ └────┘ │
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
│ 🔄 刷新 查看更多 ›│
|
│ 🔄 刷新 查看更多 ›│
|
||||||
|
├──────────────────────────────────────┤
|
||||||
|
│ 热门星卡 │
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ ← 行1 │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ ← 行2 │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
|
│ 🔄 刷新 查看更多 ›│
|
||||||
|
├──────────────────────────────────────┤
|
||||||
|
│ 热门吧唧 │
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ ← 行1 │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ ← 行2 │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
|
│ 🔄 刷新 查看更多 ›│
|
||||||
|
├──────────────────────────────────────┤
|
||||||
|
│ 热门海报 │
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ ← 行1 │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ ← 行2 │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
|
│ 🔄 刷新 查看更多 ›│
|
||||||
|
├──────────────────────────────────────┤
|
||||||
|
│ CreationGrid(原有组件,不变) │
|
||||||
|
│ [热门作品] [最新作品] [星卡] [吧唧]... │
|
||||||
|
└──────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 单个 HotCategoryBlock 内部结构
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────┐
|
||||||
|
│ 热门推荐 │ ← block-title
|
||||||
|
├──────────────────────────────────────┤
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │ ← block-grid (4×2)
|
||||||
|
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
|
||||||
|
│ │ │ │ │ │ │ │ │ │
|
||||||
|
│ └────┘ └────┘ └────┘ └────┘ │
|
||||||
|
│ 🔄 刷新 查看更多 ›│ ← block-actions
|
||||||
└──────────────────────────────────────┘
|
└──────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -11,10 +11,6 @@ const app = new Vue({
|
|||||||
app.$mount()
|
app.$mount()
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef VUE3 && H5
|
|
||||||
import './pages/castlove/create-laser-upload.css'
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef VUE3
|
// #ifdef VUE3
|
||||||
import { createSSRApp } from 'vue'
|
import { createSSRApp } from 'vue'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
|
|||||||
@ -5,83 +5,85 @@
|
|||||||
<text class="back-icon" :style="{ color: backIconColor }">←</text>
|
<text class="back-icon" :style="{ color: backIconColor }">←</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 右侧图标区域 -->
|
<!-- 左侧水晶余额 -->
|
||||||
<view class="right-icons">
|
<view class="crystal-balance-new" @click="handleAvatarClick">
|
||||||
<!-- 任务图标 -->
|
<!-- 1. 左侧钻石图标:层级最高,盖住右侧背景 -->
|
||||||
<view v-if="showTaskIcon" class="daily-task-group" @click="handleTaskClick">
|
<view class="crystal-icon-box">
|
||||||
<!-- 1. 上层:任务图标(悬浮在上面) -->
|
<image class="crystal-icon" src="/static/icon/crystal.png" mode="aspectFit"></image>
|
||||||
<view class="task-icon-box">
|
|
||||||
<image class="task-icon-img" src="/static/icon/task.png" mode="aspectFit"></image>
|
|
||||||
<image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 2. 下层:文字背景块 -->
|
|
||||||
<view class="task-text-box">
|
|
||||||
<text class="task-text-label">每日任务</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 新手引导 -->
|
<!-- 2. 右侧容器:用于包裹背景和文字 -->
|
||||||
<!-- <view v-if="showGuideIcon" class="daily-task-group" @click="handleGuideClick">
|
<view class="crystal-info-container">
|
||||||
1. 上层:新手引导(悬浮在上面)
|
<image class="crystal-bg-img" src="/static/square/shuijingzhanshikuang.png" mode="aspectFill">
|
||||||
<view class="task-icon-box">
|
</image>
|
||||||
<image class="task-icon-img" src="/static/icon/onboarding-bg.png" mode="aspectFit"></image>
|
|
||||||
<image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
|
<!-- 上层:文字内容 -->
|
||||||
|
<view class="crystal-text-layer">
|
||||||
|
<text class="balance-number">{{ exhibitionRevenue }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
2. 下层:文字背景块
|
<!-- 收益文字 -->
|
||||||
<view class="task-text-box">
|
<!-- <view class="crystal-bg-layer">
|
||||||
<text class="task-text-label">新手引导</text>
|
<text class="balance-income">收益 {{ hourlyEarnings }}/时</text>
|
||||||
</view>
|
</view> -->
|
||||||
</view> -->
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 星援活动列表 -->
|
<!-- 右侧图标区域 -->
|
||||||
<view v-if="showStarActivityIcon" class="star-activity-list">
|
<view class="right-icons">
|
||||||
<view v-for="activity in starActivities" :key="activity.id" class="daily-task-group"
|
<view class="left-items">
|
||||||
@click="handleActivityClick(activity)">
|
<!-- 任务图标 -->
|
||||||
<!-- 上层:活动图标 -->
|
<view v-if="showTaskIcon" class="daily-task-group" @click="handleTaskClick">
|
||||||
|
<!-- 1. 上层:任务图标(悬浮在上面) -->
|
||||||
<view class="task-icon-box">
|
<view class="task-icon-box">
|
||||||
<image class="task-icon-img" :src="activity.icon || '/static/icon/bus-icon.png'"
|
<image class="task-icon-img" src="/static/icon/task.png" mode="aspectFit"></image>
|
||||||
mode="aspectFit"></image>
|
|
||||||
<image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
|
<image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 下层:文字背景块 -->
|
<!-- 2. 下层:文字背景块 -->
|
||||||
<view class="task-text-box">
|
<view class="task-text-box">
|
||||||
<text class="task-text-label">{{ activity.theme || '星援活动' }}</text>
|
<text class="task-text-label">每日任务</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 新手引导 -->
|
||||||
|
<!-- <view v-if="showGuideIcon" class="daily-task-group" @click="handleGuideClick">
|
||||||
|
1. 上层:新手引导(悬浮在上面)
|
||||||
|
<view class="task-icon-box">
|
||||||
|
<image class="task-icon-img" src="/static/icon/onboarding-bg.png" mode="aspectFit"></image>
|
||||||
|
<image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
2. 下层:文字背景块
|
||||||
|
<view class="task-text-box">
|
||||||
|
<text class="task-text-label">新手引导</text>
|
||||||
|
</view>
|
||||||
|
</view> -->
|
||||||
|
|
||||||
|
<!-- 星援活动列表 -->
|
||||||
|
<view v-if="showStarActivityIcon" class="star-activity-list">
|
||||||
|
<view v-for="activity in starActivities" :key="activity.id" class="daily-task-group"
|
||||||
|
@click="handleActivityClick(activity)">
|
||||||
|
<!-- 上层:活动图标 -->
|
||||||
|
<view class="task-icon-box">
|
||||||
|
<image class="task-icon-img" :src="activity.icon || '/static/icon/bus-icon.png'"
|
||||||
|
mode="aspectFit"></image>
|
||||||
|
<image class="task-red-dot" src="/static/square/tishi.png" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 下层:文字背景块 -->
|
||||||
|
<view class="task-text-box">
|
||||||
|
<text class="task-text-label">{{
|
||||||
|
activity.theme || "星援活动"
|
||||||
|
}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 顶粉水晶余额 -->
|
|
||||||
<view class="crystal-balance-new" @click="handleAvatarClick">
|
|
||||||
<!-- 1. 左侧钻石图标:层级最高,盖住右侧背景 -->
|
|
||||||
<view class="crystal-icon-box">
|
|
||||||
<image class="crystal-icon" src="/static/icon/crystal.png" mode="aspectFit"></image>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 2. 右侧容器:用于包裹背景和文字 -->
|
|
||||||
<view class="crystal-info-container">
|
|
||||||
<image class="crystal-bg-img" src="/static/square/shuijingzhanshikuang.png" mode="aspectFill">
|
|
||||||
</image>
|
|
||||||
|
|
||||||
<!-- 上层:文字内容 -->
|
|
||||||
<view class="crystal-text-layer">
|
|
||||||
<text class="balance-number">{{ exhibitionRevenue }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 收益文字 -->
|
|
||||||
<view class="crystal-bg-layer">
|
|
||||||
<text class="balance-income">收益 {{ hourlyEarnings }}/时</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 用户头像 -->
|
<!-- 用户头像 -->
|
||||||
<view class="icon-item avatar-icon" @click="handleAvatarClick">
|
<view class="icon-item avatar-icon" @click="handleAvatarClick">
|
||||||
<Avatar :key="avatarKey" :userId="userUid" :avatarUrl="userAvatarUrl" :size="96" :borderWidth="2" />
|
<Avatar :key="avatarKey" :userId="userUid" :avatarUrl="userAvatarUrl" :size="68" :borderWidth="2" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -94,15 +96,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, onMounted, onUnmounted } from 'vue';
|
import { computed, ref, onMounted, onUnmounted } from "vue";
|
||||||
import { onShow } from '@dcloudio/uni-app';
|
import { onShow } from "@dcloudio/uni-app";
|
||||||
import { useStore } from 'vuex';
|
import { useStore } from "vuex";
|
||||||
import Avatar from './Avatar.vue';
|
import Avatar from "./Avatar.vue";
|
||||||
import DailyTasks from '@/pages/tasks/daily-tasks.vue';
|
import DailyTasks from "@/pages/tasks/daily-tasks.vue";
|
||||||
import GuideModal from '@/pages/tasks/GuideModal.vue';
|
import GuideModal from "@/pages/tasks/GuideModal.vue";
|
||||||
import { useBanner } from '@/pages/square/composables/useBanner.js';
|
import { useBanner } from "@/pages/square/composables/useBanner.js";
|
||||||
import { reportEvent } from '@/utils/task-api.js';
|
import { reportEvent } from "@/utils/task-api.js";
|
||||||
import { getEarningsSummaryApi } from '@/utils/api.js';
|
import { getEarningsSummaryApi } from "@/utils/api.js";
|
||||||
|
|
||||||
// 获取星援活动数据(复用 square 的 useBanner)
|
// 获取星援活动数据(复用 square 的 useBanner)
|
||||||
const { bannerActivities, loadBannerActivities } = useBanner();
|
const { bannerActivities, loadBannerActivities } = useBanner();
|
||||||
@ -111,28 +113,28 @@ const { bannerActivities, loadBannerActivities } = useBanner();
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
showBack: {
|
showBack: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
backUrl: {
|
backUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: "",
|
||||||
},
|
},
|
||||||
backIconColor: {
|
backIconColor: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '#000000'
|
default: "#000000",
|
||||||
},
|
},
|
||||||
showTaskIcon: {
|
showTaskIcon: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
showGuideIcon: {
|
showGuideIcon: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
showStarActivityIcon: {
|
showStarActivityIcon: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@ -150,24 +152,24 @@ const showGuideModal = ref(false);
|
|||||||
// 从本地存储读取用户信息
|
// 从本地存储读取用户信息
|
||||||
const loadUserInfo = () => {
|
const loadUserInfo = () => {
|
||||||
try {
|
try {
|
||||||
const userStr = uni.getStorageSync('user');
|
const userStr = uni.getStorageSync("user");
|
||||||
if (userStr) {
|
if (userStr) {
|
||||||
userInfo.value = JSON.parse(userStr);
|
userInfo.value = JSON.parse(userStr);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('解析用户信息失败:', e);
|
console.error("解析用户信息失败:", e);
|
||||||
userInfo.value = null;
|
userInfo.value = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取用户UID
|
// 获取用户UID
|
||||||
const userUid = computed(() => {
|
const userUid = computed(() => {
|
||||||
return userInfo.value?.uid || '';
|
return userInfo.value?.uid || "";
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取用户头像URL
|
// 获取用户头像URL
|
||||||
const userAvatarUrl = computed(() => {
|
const userAvatarUrl = computed(() => {
|
||||||
return userInfo.value?.avatar_url || '';
|
return userInfo.value?.avatar_url || "";
|
||||||
});
|
});
|
||||||
|
|
||||||
// // 获取水晶余额
|
// // 获取水晶余额
|
||||||
@ -190,7 +192,7 @@ const loadEarningsSummary = async () => {
|
|||||||
hourlyEarnings.value = data.total_hourly_earnings || 0;
|
hourlyEarnings.value = data.total_hourly_earnings || 0;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('获取收益汇总失败:', e);
|
console.error("获取收益汇总失败:", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -213,7 +215,10 @@ const handleUserInfoUpdate = () => {
|
|||||||
// 监听余额更新事件
|
// 监听余额更新事件
|
||||||
const handleBalanceUpdate = (data) => {
|
const handleBalanceUpdate = (data) => {
|
||||||
if (userInfo.value) {
|
if (userInfo.value) {
|
||||||
userInfo.value = { ...userInfo.value, crystal_balance: data.crystal_balance };
|
userInfo.value = {
|
||||||
|
...userInfo.value,
|
||||||
|
crystal_balance: data.crystal_balance,
|
||||||
|
};
|
||||||
exhibitionRevenue.value = data.crystal_balance || 0;
|
exhibitionRevenue.value = data.crystal_balance || 0;
|
||||||
} else {
|
} else {
|
||||||
loadUserInfo();
|
loadUserInfo();
|
||||||
@ -223,43 +228,51 @@ const handleBalanceUpdate = (data) => {
|
|||||||
// 检查并上报每日首次登录事件
|
// 检查并上报每日首次登录事件
|
||||||
function checkAndReportDailyLogin() {
|
function checkAndReportDailyLogin() {
|
||||||
// 5点之前属于昨日周期,不触发登录事件
|
// 5点之前属于昨日周期,不触发登录事件
|
||||||
const now = new Date()
|
const now = new Date();
|
||||||
const currentHour = now.getHours()
|
const currentHour = now.getHours();
|
||||||
if (currentHour < 5) return // 5点之前不触发
|
if (currentHour < 5) return; // 5点之前不触发
|
||||||
|
|
||||||
const today = now.toISOString().split('T')[0]
|
const today = now.toISOString().split("T")[0];
|
||||||
const starId = uni.getStorageSync('star_id')
|
const starId = uni.getStorageSync("star_id");
|
||||||
if (!starId) return
|
if (!starId) return;
|
||||||
|
|
||||||
// 获取用户ID
|
// 获取用户ID
|
||||||
const userStr = uni.getStorageSync('user')
|
const userStr = uni.getStorageSync("user");
|
||||||
let userId = null
|
let userId = null;
|
||||||
if (userStr) {
|
if (userStr) {
|
||||||
try {
|
try {
|
||||||
const user = JSON.parse(userStr)
|
const user = JSON.parse(userStr);
|
||||||
userId = user?.uid || null
|
userId = user?.uid || null;
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
}
|
}
|
||||||
if (!userId) return
|
if (!userId) return;
|
||||||
|
|
||||||
// 每个用户每个明星身份有独立的每日登录状态
|
// 每个用户每个明星身份有独立的每日登录状态
|
||||||
const dailyLoginKey = `daily_login_completed_${today}_${userId}_${starId}`
|
const dailyLoginKey = `daily_login_completed_${today}_${userId}_${starId}`;
|
||||||
if (!uni.getStorageSync(dailyLoginKey)) {
|
if (!uni.getStorageSync(dailyLoginKey)) {
|
||||||
reportEvent('daily_login', starId).then(() => {
|
reportEvent("daily_login", starId)
|
||||||
// 报告成功后标记今日已完成,并清除昨日的记录
|
.then(() => {
|
||||||
uni.setStorageSync(dailyLoginKey, true)
|
// 报告成功后标记今日已完成,并清除昨日的记录
|
||||||
const yesterday = new Date(now.getTime() - 86400000).toISOString().split('T')[0]
|
uni.setStorageSync(dailyLoginKey, true);
|
||||||
uni.removeStorageSync(`daily_login_completed_${yesterday}_${userId}_${starId}`)
|
const yesterday = new Date(now.getTime() - 86400000)
|
||||||
}).catch(err => {
|
.toISOString()
|
||||||
console.error('上报登录事件失败:', err)
|
.split("T")[0];
|
||||||
})
|
uni.removeStorageSync(
|
||||||
|
`daily_login_completed_${yesterday}_${userId}_${starId}`,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("上报登录事件失败:", err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 星援活动列表 - 从 bannerActivities 中获取非 expired 的活动
|
// 星援活动列表 - 从 bannerActivities 中获取非 expired 的活动
|
||||||
const starActivities = computed(() => {
|
const starActivities = computed(() => {
|
||||||
// return bannerActivities.value
|
// return bannerActivities.value
|
||||||
return bannerActivities.value.filter(activity => activity.status !== 'expired');
|
return bannerActivities.value.filter(
|
||||||
|
(activity) => activity.status !== "expired",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 组件挂载时加载用户信息和星援活动数据
|
// 组件挂载时加载用户信息和星援活动数据
|
||||||
@ -267,9 +280,9 @@ onMounted(async () => {
|
|||||||
await loadUserInfo();
|
await loadUserInfo();
|
||||||
await loadBannerActivities();
|
await loadBannerActivities();
|
||||||
// await loadEarningsSummary();
|
// await loadEarningsSummary();
|
||||||
uni.$on('avatarUpdated', handleAvatarUpdate);
|
uni.$on("avatarUpdated", handleAvatarUpdate);
|
||||||
uni.$on('userInfoUpdated', handleUserInfoUpdate);
|
uni.$on("userInfoUpdated", handleUserInfoUpdate);
|
||||||
uni.$on('balanceUpdated', handleBalanceUpdate);
|
uni.$on("balanceUpdated", handleBalanceUpdate);
|
||||||
|
|
||||||
// 上报每日首次登录事件(每日5点重置后首次挂载时)
|
// 上报每日首次登录事件(每日5点重置后首次挂载时)
|
||||||
checkAndReportDailyLogin();
|
checkAndReportDailyLogin();
|
||||||
@ -282,16 +295,16 @@ onShow(() => {
|
|||||||
|
|
||||||
// 组件卸载时移除事件监听
|
// 组件卸载时移除事件监听
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
uni.$off('avatarUpdated', handleAvatarUpdate);
|
uni.$off("avatarUpdated", handleAvatarUpdate);
|
||||||
uni.$off('userInfoUpdated', handleUserInfoUpdate);
|
uni.$off("userInfoUpdated", handleUserInfoUpdate);
|
||||||
uni.$off('balanceUpdated', handleBalanceUpdate);
|
uni.$off("balanceUpdated", handleBalanceUpdate);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理返回按钮点击
|
// 处理返回按钮点击
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
if (props.backUrl) {
|
if (props.backUrl) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: props.backUrl
|
url: props.backUrl,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 获取页面栈
|
// 获取页面栈
|
||||||
@ -302,7 +315,7 @@ const handleBack = () => {
|
|||||||
} else {
|
} else {
|
||||||
// 没有上一页,跳转到square页面
|
// 没有上一页,跳转到square页面
|
||||||
uni.reLaunch({
|
uni.reLaunch({
|
||||||
url: '/pages/square/square'
|
url: "/pages/square/square",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +329,7 @@ const handleTaskClick = () => {
|
|||||||
const handleActivityClick = (activity) => {
|
const handleActivityClick = (activity) => {
|
||||||
if (activity) {
|
if (activity) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/support-activity/index?id=${activity.id}`
|
url: `/pages/support-activity/index?id=${activity.id}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -329,22 +342,22 @@ const handleGuideClick = () => {
|
|||||||
// 引导更新回调
|
// 引导更新回调
|
||||||
const handleGuideUpdated = () => {
|
const handleGuideUpdated = () => {
|
||||||
// 可以在这里刷新相关数据
|
// 可以在这里刷新相关数据
|
||||||
console.log('[Header] Guide updated');
|
console.log("[Header] Guide updated");
|
||||||
};
|
};
|
||||||
|
|
||||||
// 执行引导
|
// 执行引导
|
||||||
const handleStartGuide = (params) => {
|
const handleStartGuide = (params) => {
|
||||||
const key = typeof params === 'string' ? params : (params?.key || '');
|
const key = typeof params === "string" ? params : params?.key || "";
|
||||||
const fromStep = typeof params === 'object' ? (params.fromStep ?? 0) : 0;
|
const fromStep = typeof params === "object" ? (params.fromStep ?? 0) : 0;
|
||||||
const targetPage = typeof params === 'object' ? (params.targetPage || '') : '';
|
const targetPage = typeof params === "object" ? params.targetPage || "" : "";
|
||||||
|
|
||||||
console.log('[Header] handleStartGuide:', { key, fromStep, targetPage });
|
console.log("[Header] handleStartGuide:", { key, fromStep, targetPage });
|
||||||
|
|
||||||
showGuideListModal.value = false;
|
showGuideListModal.value = false;
|
||||||
|
|
||||||
// 根据引导类型跳转到对应页面
|
// 根据引导类型跳转到对应页面
|
||||||
if (key === 'square_home') {
|
if (key === "square_home") {
|
||||||
const navigateUrl = targetPage || '/pages/square/square';
|
const navigateUrl = targetPage || "/pages/square/square";
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: navigateUrl,
|
url: navigateUrl,
|
||||||
success: () => {
|
success: () => {
|
||||||
@ -355,7 +368,7 @@ const handleStartGuide = (params) => {
|
|||||||
store.dispatch("guide/resumeGuide", key);
|
store.dispatch("guide/resumeGuide", key);
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (fromStep === 0) {
|
if (fromStep === 0) {
|
||||||
@ -383,20 +396,20 @@ const handleAvatarClick = () => {
|
|||||||
if (pages.length > 0) {
|
if (pages.length > 0) {
|
||||||
const currentPage = pages[pages.length - 1];
|
const currentPage = pages[pages.length - 1];
|
||||||
// 检查当前页面是否是个人信息页面
|
// 检查当前页面是否是个人信息页面
|
||||||
if (currentPage.route === 'pages/profile/myWorks') {
|
if (currentPage.route === "pages/profile/myWorks") {
|
||||||
// 已经在个人信息页面,不执行跳转
|
// 已经在个人信息页面,不执行跳转
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/profile/myWorks'
|
url: "/pages/profile/myWorks",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 将方法暴露给模板
|
// 将方法暴露给模板
|
||||||
defineExpose({
|
defineExpose({
|
||||||
showTaskModal,
|
showTaskModal,
|
||||||
closeTaskModal
|
closeTaskModal,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -438,32 +451,43 @@ defineExpose({
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.left-items {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.star-activity-list {
|
.star-activity-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8rpx;
|
gap: 8rpx;
|
||||||
|
width: 68rpx;
|
||||||
|
/* 控制整体宽度,根据图标大小调整 */
|
||||||
|
height: 156rpx;
|
||||||
|
/* 预估高度,包含图标和文字块 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.daily-task-group {
|
.daily-task-group {
|
||||||
position: relative;
|
position: relative;
|
||||||
/* 必须是相对定位,作为子元素的定位基准 */
|
/* 必须是相对定位,作为子元素的定位基准 */
|
||||||
width: 100rpx;
|
width: 68rpx;
|
||||||
/* 控制整体宽度,根据图标大小调整 */
|
/* 控制整体宽度,根据图标大小调整 */
|
||||||
height: 120rpx;
|
height: 156rpx;
|
||||||
/* 预估高度,包含图标和文字块 */
|
/* 预估高度,包含图标和文字块 */
|
||||||
|
margin-right: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- 上层图标样式 --- */
|
/* --- 上层图标样式 --- */
|
||||||
.task-icon-box {
|
.task-icon-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8rpx;
|
top: 40rpx;
|
||||||
/* 固定在顶部 */
|
/* 固定在顶部 */
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
/* 水平居中 */
|
/* 水平居中 */
|
||||||
width: 88rpx;
|
width: 34rpx;
|
||||||
/* 图标宽度 */
|
/* 图标宽度 */
|
||||||
height: 88rpx;
|
height: 40rpx;
|
||||||
/* 图标高度 */
|
/* 图标高度 */
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
/* 确保图标在文字块上面 */
|
/* 确保图标在文字块上面 */
|
||||||
@ -490,12 +514,13 @@ defineExpose({
|
|||||||
/* 关键:调整这个值,让文字块往上顶,与图标产生重叠 */
|
/* 关键:调整这个值,让文字块往上顶,与图标产生重叠 */
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 88rpx;
|
width: 60rpx;
|
||||||
height: 80rpx;
|
height: 60rpx;
|
||||||
background-image: url('/static/square/gerenzhongxincangpinkuang.png');
|
background-image: url("/static/square/gerenzhongxincangpinkuang.png");
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
|
box-shadow: 0px 4px 4px 0px #ee262654;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -504,11 +529,13 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.task-text-label {
|
.task-text-label {
|
||||||
font-size: 16rpx;
|
font-weight: 500;
|
||||||
color: #fff;
|
font-size: 12rpx;
|
||||||
text-shadow: 1rpx 1rpx 2rpx rgba(0, 0, 0, 0.9);
|
line-height: 100%;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
color: #fff9e7;
|
||||||
|
text-shadow: 1rpx 1rpx 2rpx rgba(0, 0, 0, 0.84);
|
||||||
margin-top: 32rpx;
|
margin-top: 32rpx;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 水晶余额组件 */
|
/* 水晶余额组件 */
|
||||||
@ -526,13 +553,14 @@ defineExpose({
|
|||||||
/* --- 左侧钻石图标 --- */
|
/* --- 左侧钻石图标 --- */
|
||||||
.crystal-icon-box {
|
.crystal-icon-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 8rpx;
|
||||||
bottom: 10rpx;
|
bottom: 24rpx;
|
||||||
/* 与右侧底部平齐 */
|
/* 与右侧底部平齐 */
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
/* 最高层级:盖住右侧背景 */
|
width: 68rpx;
|
||||||
width: 100rpx;
|
height: 60rpx;
|
||||||
height: 100rpx;
|
transform: rotate(-15deg);
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.crystal-icon {
|
.crystal-icon {
|
||||||
@ -543,12 +571,14 @@ defineExpose({
|
|||||||
/* --- 右侧容器 --- */
|
/* --- 右侧容器 --- */
|
||||||
.crystal-info-container {
|
.crystal-info-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 56rpx;
|
height: 34rpx;
|
||||||
width: 80rpx;
|
width: 120rpx;
|
||||||
border-radius: 16rpx;
|
opacity: 1;
|
||||||
bottom: 4rpx;
|
border-radius: 20rpx;
|
||||||
padding-right: 28rpx;
|
border-width: 1px;
|
||||||
padding-left: 56rpx;
|
border: 1px solid #F3A68A40;
|
||||||
|
box-shadow: 2px 2px 4.1px 0px #F936365C;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.crystal-bg-img {
|
.crystal-bg-img {
|
||||||
@ -567,14 +597,18 @@ defineExpose({
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 8rpx;
|
border-radius: 120rpx;
|
||||||
|
opacity: 0.75;
|
||||||
|
background: linear-gradient(270deg, rgba(168, 17, 255, 0.83) 0%, rgba(30, 180, 217, 0.470865) 81.01%, rgba(101, 10, 153, 0) 178.07%);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.balance-number {
|
.balance-number {
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #FFB800;
|
color: #ffb800;
|
||||||
font-family: 'yt', sans-serif;
|
font-family: "yt", sans-serif;
|
||||||
text-shadow:
|
text-shadow:
|
||||||
0 0 10rpx rgba(255, 184, 0, 0.8),
|
0 0 10rpx rgba(255, 184, 0, 0.8),
|
||||||
0 2rpx 4rpx rgba(0, 0, 0, 0.5);
|
0 2rpx 4rpx rgba(0, 0, 0, 0.5);
|
||||||
@ -586,14 +620,14 @@ defineExpose({
|
|||||||
|
|
||||||
.balance-income {
|
.balance-income {
|
||||||
font-size: 18rpx;
|
font-size: 18rpx;
|
||||||
color: #FFFFFF;
|
color: #ffffff;
|
||||||
margin-bottom: 2rpx;
|
margin-bottom: 2rpx;
|
||||||
margin-left: 28rpx;
|
margin-left: 28rpx;
|
||||||
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.9);
|
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- 下层:渐变背景 --- */
|
/* --- 下层:渐变背景 --- */
|
||||||
.crystal-bg-layer {
|
/* .crystal-bg-layer {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -605,9 +639,9 @@ defineExpose({
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
background: linear-gradient(to bottom right,
|
background: linear-gradient(to bottom right,
|
||||||
#F0E4B1 0%,
|
#f0e4b1 0%,
|
||||||
#F08399 50%,
|
#f08399 50%,
|
||||||
#B94E7399 100%);
|
#b94e7399 100%);
|
||||||
|
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
|
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
|
||||||
@ -615,15 +649,13 @@ defineExpose({
|
|||||||
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4),
|
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4),
|
||||||
inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
||||||
border-radius: 10rpx;
|
border-radius: 10rpx;
|
||||||
}
|
} */
|
||||||
|
|
||||||
.icon-item {
|
.icon-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-left: 32rpx;
|
|
||||||
margin-top: 16rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-icon {
|
.task-icon {
|
||||||
|
|||||||
@ -2,18 +2,22 @@
|
|||||||
<view class="profile-container">
|
<view class="profile-container">
|
||||||
<!-- 背景图片 - 固定在容器上 -->
|
<!-- 背景图片 - 固定在容器上 -->
|
||||||
<image class="background-image" src="/static/square/squearbj.png" mode="aspectFill"></image>
|
<image class="background-image" src="/static/square/squearbj.png" mode="aspectFill"></image>
|
||||||
<scroll-view class="profile-scroll" scroll-y :show-scrollbar="false" :enable-back-to-top="true">
|
<!-- 可替换背景装饰层 -->
|
||||||
|
<view class="replaceable-bg-layer">
|
||||||
|
<image class="replaceable-bg-overlay-image" :src="replaceableBgOverlay" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<!-- Header组件 -->
|
||||||
|
<view class="nav-back" @tap="goBack">
|
||||||
|
<text class="nav-back-icon">←</text>
|
||||||
|
</view>
|
||||||
|
<view class="profile-scroll">
|
||||||
|
<!-- 右上角模块 -->
|
||||||
|
<view class="top-right-module">
|
||||||
|
<text class="level-label">LV:</text>
|
||||||
|
<text class="level-value">{{ fanLevel }}</text>
|
||||||
|
</view>
|
||||||
<!-- 上半部分:用户信息卡片 -->
|
<!-- 上半部分:用户信息卡片 -->
|
||||||
<view class="top-section">
|
<view class="top-section">
|
||||||
|
|
||||||
<!-- 蒙层 -->
|
|
||||||
<view class="background-overlay"></view>
|
|
||||||
|
|
||||||
<!-- Header组件 -->
|
|
||||||
<view class="nav-back" @tap="goBack">
|
|
||||||
<text class="nav-back-icon">←</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 用户信息卡片 -->
|
<!-- 用户信息卡片 -->
|
||||||
<view class="user-info-card">
|
<view class="user-info-card">
|
||||||
<!-- 上半部分:头像和用户信息左右布局 -->
|
<!-- 上半部分:头像和用户信息左右布局 -->
|
||||||
@ -43,7 +47,7 @@
|
|||||||
<text class="info-label">链上地址</text>
|
<text class="info-label">链上地址</text>
|
||||||
<view class="address-row">
|
<view class="address-row">
|
||||||
<text class="info-value address-value" @longpress="copyAddress">{{ displayAddress
|
<text class="info-value address-value" @longpress="copyAddress">{{ displayAddress
|
||||||
}}</text>
|
}}</text>
|
||||||
<view class="toggle-btn" @tap="showBlockNumber = !showBlockNumber">
|
<view class="toggle-btn" @tap="showBlockNumber = !showBlockNumber">
|
||||||
<image class="toggle-icon"
|
<image class="toggle-icon"
|
||||||
:src="showBlockNumber ? '/static/icon/show.png' : '/static/icon/hide.png'"
|
:src="showBlockNumber ? '/static/icon/show.png' : '/static/icon/hide.png'"
|
||||||
@ -270,7 +274,7 @@
|
|||||||
<view class="logout-section">
|
<view class="logout-section">
|
||||||
<button class="logout-button" @tap="handleLogout">退出登录</button>
|
<button class="logout-button" @tap="handleLogout">退出登录</button>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</view>
|
||||||
|
|
||||||
<!-- 新手引导弹窗 -->
|
<!-- 新手引导弹窗 -->
|
||||||
<GuideModal :visible="showGuideModal" @close="showGuideModal = false" @updated="handleGuideUpdated" />
|
<GuideModal :visible="showGuideModal" @close="showGuideModal = false" @updated="handleGuideUpdated" />
|
||||||
@ -356,6 +360,15 @@ const mobile = ref('');
|
|||||||
const showBlockNumber = ref(false);
|
const showBlockNumber = ref(false);
|
||||||
const showMobile = ref(false);
|
const showMobile = ref(false);
|
||||||
|
|
||||||
|
// 可替换背景叠加层图片(类似微信更换主页背景)
|
||||||
|
const replaceableBgOverlay = ref('/static/sucai/image-06.png');
|
||||||
|
|
||||||
|
|
||||||
|
// 更新背景叠加层方法
|
||||||
|
const updateBgOverlay = (newOverlayImage) => {
|
||||||
|
replaceableBgOverlay.value = newOverlayImage;
|
||||||
|
};
|
||||||
|
|
||||||
// 显示手机号(根据showMobile状态显示脱敏或未脱敏)
|
// 显示手机号(根据showMobile状态显示脱敏或未脱敏)
|
||||||
const displayMobile = computed(() => {
|
const displayMobile = computed(() => {
|
||||||
console.log('displayMobile computed, mobile:', mobile.value, 'showMobile:', showMobile.value);
|
console.log('displayMobile computed, mobile:', mobile.value, 'showMobile:', showMobile.value);
|
||||||
@ -1263,10 +1276,18 @@ onShow(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.profile-scroll {
|
.profile-scroll {
|
||||||
width: 100%;
|
width: 616rpx;
|
||||||
height: 100%;
|
height: 955.2rpx;
|
||||||
position: relative;
|
position: fixed;
|
||||||
z-index: 1;
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 2;
|
||||||
|
border-radius: 86rpx;
|
||||||
|
background: linear-gradient(133.78deg, rgba(154, 146, 255, 0.19) 9.69%, rgba(255, 202, 229, 0.19) 43.91%, rgba(255, 250, 253, 0.1881) 76.13%, rgba(63, 63, 76, 0.19) 91.61%);
|
||||||
|
backdrop-filter: blur(35.70000076293945px);
|
||||||
|
box-shadow: 2px 4px 1.8px 0px #D629291F;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 隐藏滚动条 */
|
/* 隐藏滚动条 */
|
||||||
@ -1276,6 +1297,35 @@ onShow(() => {
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 右上角模块 */
|
||||||
|
.top-right-module {
|
||||||
|
position: fixed;
|
||||||
|
width: 313.6rpx;
|
||||||
|
height: 73.6rpx;
|
||||||
|
top: -16rpx;
|
||||||
|
right: 0;
|
||||||
|
border-top-right-radius: 35.5rpx;
|
||||||
|
border-top-left-radius: 7rpx;
|
||||||
|
border-bottom-left-radius: 35.5rpx;
|
||||||
|
border-bottom-right-radius: 6rpx;
|
||||||
|
background: linear-gradient(135deg, #9E90FF 0%, #FFCAD3 100%);
|
||||||
|
z-index: 4;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-label {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-value {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* 上半部分:用户信息区域 */
|
/* 上半部分:用户信息区域 */
|
||||||
.top-section {
|
.top-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -1298,12 +1348,26 @@ onShow(() => {
|
|||||||
/* filter: blur(20rpx); */
|
/* filter: blur(20rpx); */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.replaceable-bg-layer {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 80vh;
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replaceable-bg-overlay-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
.background-overlay {
|
.background-overlay {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-back {
|
.nav-back {
|
||||||
position: relative;
|
position: fixed;
|
||||||
top: 96rpx;
|
top: 96rpx;
|
||||||
left: 32rpx;
|
left: 32rpx;
|
||||||
width: 80rpx;
|
width: 80rpx;
|
||||||
@ -1313,6 +1377,7 @@ onShow(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
/* background: rgba(255,255,255,0.5);
|
/* background: rgba(255,255,255,0.5);
|
||||||
border-radius: 50%; */
|
border-radius: 50%; */
|
||||||
|
z-index: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-back-icon {
|
.nav-back-icon {
|
||||||
|
|||||||
@ -1,23 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="creation-grid">
|
<view class="creation-grid">
|
||||||
<view v-for="(item, index) in creationList" :key="item.id" class="creation-card" @click="handleCardClick(item)">
|
<view class="recommend-tag">
|
||||||
<image class="creation-image" :src="item.cover_image" mode="aspectFill"></image>
|
<text class="recommend-text">猜你喜欢</text>
|
||||||
<!-- 光波动画层 - 外层 -->
|
</view>
|
||||||
<view class="wf-like-wave wf-like-wave-outer" :class="{ 'wf-like-wave-active': likingMap[item.id] }" />
|
|
||||||
<!-- 光波动画层 - 内层 -->
|
<view class="creation-list">
|
||||||
<view class="wf-like-wave wf-like-wave-inner" :class="{ 'wf-like-wave-active': likingMap[item.id] }" />
|
<view class="col-left">
|
||||||
<view class="creation-info">
|
<view
|
||||||
<view class="creation-id">
|
v-for="item in col1"
|
||||||
<text class="id-text">#{{ item.certificate_id }}</text>
|
:key="item.id"
|
||||||
</view>
|
class="creation-card"
|
||||||
<view class="creation-meta">
|
@click="handleCardClick(item)"
|
||||||
<view class="creator-info">
|
>
|
||||||
<image class="creator-avatar" :src="item.creator_avatar" mode="aspectFill"></image>
|
<image
|
||||||
<text class="creator-name">{{ item.creator_name }}</text>
|
class="creation-image"
|
||||||
|
:src="item.cover_image"
|
||||||
|
mode="widthFix"
|
||||||
|
></image>
|
||||||
|
<view class="like-badge">
|
||||||
|
<view class="like-icon-wrapper">
|
||||||
|
<image
|
||||||
|
class="like-icon"
|
||||||
|
:src="item.is_liked ? '/static/icon/heart-icon.png' : '/static/icon/heart-icon-false.png'"
|
||||||
|
mode="aspectFit"
|
||||||
|
></image>
|
||||||
|
<text class="like-count">{{ formatCount(item.like_count) }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="like-info">
|
<view
|
||||||
<image class="like-icon" src="/static/icon/heart-icon.png" mode="aspectFit"></image>
|
class="wf-like-wave wf-like-wave-outer"
|
||||||
<text class="like-count">{{ formatCount(item.like_count) }}</text>
|
:class="{ 'wf-like-wave-active': likingMap[item.id] }"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
class="wf-like-wave wf-like-wave-inner"
|
||||||
|
:class="{ 'wf-like-wave-active': likingMap[item.id] }"
|
||||||
|
/>
|
||||||
|
<view class="creation-info">
|
||||||
|
<view class="creation-meta">
|
||||||
|
<view class="creator-info">
|
||||||
|
<text class="creator-name">{{ item.creator_name }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="col-right">
|
||||||
|
<view
|
||||||
|
v-for="item in col2"
|
||||||
|
:key="item.id"
|
||||||
|
class="creation-card"
|
||||||
|
@click="handleCardClick(item)"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
class="creation-image"
|
||||||
|
:src="item.cover_image"
|
||||||
|
mode="widthFix"
|
||||||
|
></image>
|
||||||
|
<view class="like-badge">
|
||||||
|
<view class="like-icon-wrapper">
|
||||||
|
<image
|
||||||
|
class="like-icon"
|
||||||
|
:src="item.is_liked ? '/static/icon/heart-icon.png' : '/static/icon/heart-icon-false.png'"
|
||||||
|
mode="aspectFit"
|
||||||
|
></image>
|
||||||
|
<text class="like-count">{{ formatCount(item.like_count) }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="wf-like-wave wf-like-wave-outer"
|
||||||
|
:class="{ 'wf-like-wave-active': likingMap[item.id] }"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
class="wf-like-wave wf-like-wave-inner"
|
||||||
|
:class="{ 'wf-like-wave-active': likingMap[item.id] }"
|
||||||
|
/>
|
||||||
|
<view class="creation-info">
|
||||||
|
<view class="creation-meta">
|
||||||
|
<view class="creator-info">
|
||||||
|
<text class="creator-name">
|
||||||
|
{{ item.creator_name }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -33,154 +98,248 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, onMounted, onUnmounted } from 'vue'
|
import { ref, watch, onMounted, onUnmounted } from "vue";
|
||||||
import { getInspirationFlowApi } from '@/utils/api.js'
|
import { getInspirationFlowApi } from "@/utils/api.js";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
screenWidth: { type: Number, default: 375 },
|
screenWidth: { type: Number, default: 375 },
|
||||||
screenHeight: { type: Number, default: 812 },
|
screenHeight: { type: Number, default: 812 },
|
||||||
bannerBottom: { type: Number, default: 200 },
|
bannerBottom: { type: Number, default: 200 },
|
||||||
useMockData: { type: Boolean, default: false },
|
useMockData: { type: Boolean, default: false },
|
||||||
category: { type: String, default: '' },
|
category: { type: String, default: "" },
|
||||||
isActive: { type: Boolean, default: true },
|
isActive: { type: Boolean, default: true },
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['cardClick', 'scroll'])
|
const emit = defineEmits(["cardClick", "scroll"]);
|
||||||
|
|
||||||
const creationList = ref([])
|
const creationList = ref([]);
|
||||||
const cursor = ref('')
|
const col1 = ref([]);
|
||||||
const isLoading = ref(false)
|
const col2 = ref([]);
|
||||||
const noMore = ref(false)
|
const cursor = ref("");
|
||||||
const likingMap = ref({})
|
const isLoading = ref(false);
|
||||||
let isComponentMounted = false
|
const noMore = ref(false);
|
||||||
|
const likingMap = ref({});
|
||||||
|
let isComponentMounted = false;
|
||||||
|
|
||||||
const formatCount = (count) => {
|
const formatCount = (count) => {
|
||||||
if (!count) return '0'
|
if (!count) return "0";
|
||||||
if (count >= 10000) return (count / 10000).toFixed(1) + 'w'
|
if (count >= 10000) return (count / 10000).toFixed(1) + "w";
|
||||||
if (count >= 1000) return (count / 1000).toFixed(1) + 'k'
|
if (count >= 1000) return (count / 1000).toFixed(1) + "k";
|
||||||
return count.toString()
|
return count.toString();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCardClick = (item) => {
|
const handleCardClick = (item) => {
|
||||||
emit('cardClick', item)
|
emit("cardClick", item);
|
||||||
}
|
};
|
||||||
|
|
||||||
const loadUsers = async () => {
|
const loadUsers = async () => {
|
||||||
if (!isComponentMounted) return Promise.resolve()
|
if (!isComponentMounted) return Promise.resolve();
|
||||||
|
|
||||||
cursor.value = ''
|
cursor.value = "";
|
||||||
isLoading.value = true
|
isLoading.value = true;
|
||||||
noMore.value = false
|
noMore.value = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await getInspirationFlowApi({ limit: 20, type: props.category, cursor: '' })
|
const res = await getInspirationFlowApi({
|
||||||
if (!isComponentMounted) return
|
limit: 20,
|
||||||
|
type: props.category,
|
||||||
|
cursor: "",
|
||||||
|
});
|
||||||
|
if (!isComponentMounted) return;
|
||||||
|
|
||||||
if (res.code === 200 && res.data?.items && res.data.items.length > 0) {
|
if (res.code === 200 && res.data?.items && res.data.items.length > 0) {
|
||||||
const items = res.data.items
|
const items = res.data.items;
|
||||||
cursor.value = res.data.cursor || ''
|
cursor.value = res.data.cursor || "";
|
||||||
|
|
||||||
creationList.value = items.map((item) => {
|
creationList.value = items.map((item) => {
|
||||||
return {
|
return {
|
||||||
id: item.asset_id,
|
id: item.asset_id,
|
||||||
certificate_id: item.asset_id,
|
certificate_id: item.asset_id,
|
||||||
cover_image: item.cover_url || '',
|
cover_image: item.cover_url || "",
|
||||||
creator_avatar: item.owner_avatar || '',
|
creator_avatar: item.owner_avatar || "",
|
||||||
creator_name: item.owner_nickname || item.name || '',
|
creator_name: item.owner_nickname || item.name || "",
|
||||||
like_count: item.likes || item.like_count || 0,
|
like_count: item.likes || item.like_count || 0,
|
||||||
}
|
is_liked: item.is_liked || false,
|
||||||
})
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 分成两列:奇数放col1,偶数放col2
|
||||||
|
col1.value = creationList.value.filter((_, i) => i % 2 === 0);
|
||||||
|
col2.value = creationList.value.filter((_, i) => i % 2 === 1);
|
||||||
} else {
|
} else {
|
||||||
noMore.value = true
|
noMore.value = true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[CreationGrid] 加载数据失败', e?.message ?? e)
|
console.error("[CreationGrid] 加载数据失败", e?.message ?? e);
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const loadMore = async () => {
|
const loadMore = async () => {
|
||||||
if (!isComponentMounted || isLoading.value || noMore.value) return
|
if (!isComponentMounted || isLoading.value || noMore.value) return;
|
||||||
|
|
||||||
isLoading.value = true
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
const res = await getInspirationFlowApi({ limit: 20, type: props.category, cursor: cursor.value })
|
const res = await getInspirationFlowApi({
|
||||||
if (!isComponentMounted) return
|
limit: 20,
|
||||||
|
type: props.category,
|
||||||
|
cursor: cursor.value,
|
||||||
|
});
|
||||||
|
if (!isComponentMounted) return;
|
||||||
|
|
||||||
if (res.code === 200 && res.data?.items && res.data.items.length > 0) {
|
if (res.code === 200 && res.data?.items && res.data.items.length > 0) {
|
||||||
const items = res.data.items
|
const items = res.data.items;
|
||||||
cursor.value = res.data.cursor || ''
|
cursor.value = res.data.cursor || "";
|
||||||
|
|
||||||
const newItems = items.map((item) => {
|
const newItems = items.map((item) => {
|
||||||
return {
|
return {
|
||||||
id: item.asset_id,
|
id: item.asset_id,
|
||||||
certificate_id: item.asset_id,
|
certificate_id: item.asset_id,
|
||||||
cover_image: item.cover_url || '',
|
cover_image: item.cover_url || "",
|
||||||
creator_avatar: item.owner_avatar || '',
|
creator_avatar: item.owner_avatar || "",
|
||||||
creator_name: item.owner_nickname || item.name || '',
|
creator_name: item.owner_nickname || item.name || "",
|
||||||
like_count: item.likes || item.like_count || 0,
|
like_count: item.likes || item.like_count || 0,
|
||||||
}
|
is_liked: item.is_liked || false,
|
||||||
})
|
};
|
||||||
|
});
|
||||||
|
|
||||||
creationList.value = [...creationList.value, ...newItems]
|
creationList.value = [...creationList.value, ...newItems];
|
||||||
|
|
||||||
|
// 重新分成两列
|
||||||
|
col1.value = creationList.value.filter((_, i) => i % 2 === 0);
|
||||||
|
col2.value = creationList.value.filter((_, i) => i % 2 === 1);
|
||||||
} else {
|
} else {
|
||||||
noMore.value = true
|
noMore.value = true;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[CreationGrid] 加载更多失败', e?.message ?? e)
|
console.error("[CreationGrid] 加载更多失败", e?.message ?? e);
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
watch(() => props.category, () => {
|
watch(
|
||||||
loadUsers()
|
() => props.category,
|
||||||
})
|
() => {
|
||||||
|
loadUsers();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
watch(() => props.isActive, (active) => {
|
watch(
|
||||||
if (active && creationList.value.length === 0) {
|
() => props.isActive,
|
||||||
loadUsers()
|
(active) => {
|
||||||
}
|
if (active && creationList.value.length === 0) {
|
||||||
})
|
loadUsers();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
isComponentMounted = true
|
isComponentMounted = true;
|
||||||
// 监听点赞事件,实时更新点赞数
|
// 监听点赞事件,实时更新点赞数
|
||||||
uni.$on('assetLiked', ({ asset_id, data }) => {
|
uni.$on("assetLiked", ({ asset_id, data }) => {
|
||||||
// 触发动画
|
// 触发动画
|
||||||
likingMap.value = { ...likingMap.value, [asset_id]: true }
|
likingMap.value = { ...likingMap.value, [asset_id]: true };
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
likingMap.value = { ...likingMap.value, [asset_id]: false }
|
likingMap.value = { ...likingMap.value, [asset_id]: false };
|
||||||
}, 600)
|
}, 600);
|
||||||
const idx = creationList.value.findIndex(c => c.id === asset_id)
|
const idx = creationList.value.findIndex((c) => c.id === asset_id);
|
||||||
if (idx !== -1 && data && typeof data.new_like_count === 'number') {
|
if (idx !== -1) {
|
||||||
creationList.value[idx].like_count = data.new_like_count
|
if (data && typeof data.new_like_count === "number") {
|
||||||
creationList.value = [...creationList.value]
|
creationList.value[idx].like_count = data.new_like_count;
|
||||||
|
}
|
||||||
|
if (data && typeof data.is_liked === "boolean") {
|
||||||
|
creationList.value[idx].is_liked = data.is_liked;
|
||||||
|
}
|
||||||
|
creationList.value = [...creationList.value];
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
loadUsers()
|
loadUsers();
|
||||||
})
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
isComponentMounted = false
|
isComponentMounted = false;
|
||||||
uni.$off('assetLiked')
|
uni.$off("assetLiked");
|
||||||
})
|
});
|
||||||
|
|
||||||
defineExpose({ loadMore })
|
defineExpose({ loadMore });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.creation-grid {
|
.creation-grid {
|
||||||
|
padding: 0 24rpx;
|
||||||
|
padding-top: 52rpx;
|
||||||
|
padding-bottom: 88rpx;
|
||||||
|
border-top-left-radius: 72rpx;
|
||||||
|
border-top-right-radius: 24rpx;
|
||||||
|
border-bottom-right-radius: 24rpx;
|
||||||
|
border-bottom-left-radius: 24rpx;
|
||||||
|
opacity: 0.78;
|
||||||
|
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(148, 204, 153, 0.32) 0%,
|
||||||
|
rgba(185, 176, 220, 0.32) 29.33%,
|
||||||
|
rgba(207, 160, 227, 0.32) 56.25%,
|
||||||
|
rgba(129, 227, 240, 0.32) 77.88%,
|
||||||
|
rgba(220, 196, 155, 0.32) 100%
|
||||||
|
);
|
||||||
|
backdrop-filter: blur(11px);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommend-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: -24rpx;
|
||||||
|
left: 4rpx;
|
||||||
|
width: 250rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
border-top-left-radius: 44rpx;
|
||||||
|
border-top-right-radius: 8rpx;
|
||||||
|
border-bottom-right-radius: 44rpx;
|
||||||
|
border-bottom-left-radius: 4rpx;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(96, 210, 236, 0.73) 0%,
|
||||||
|
rgba(107, 60, 216, 0.4964) 51.44%,
|
||||||
|
rgba(226, 137, 236, 0.73) 100%
|
||||||
|
);
|
||||||
|
box-shadow: 2px 2px 4px 0px #d9262640;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
padding: 24rpx;
|
z-index: 10;
|
||||||
padding-bottom: 120rpx;
|
}
|
||||||
|
|
||||||
|
.recommend-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0px 2px 8px #000000ba;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 100%;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.creation-list {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-left,
|
||||||
|
.col-right {
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-right {
|
||||||
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.creation-card {
|
.creation-card {
|
||||||
width: 48%;
|
width: 100%;
|
||||||
margin-bottom: 24rpx;
|
margin-bottom: 24rpx;
|
||||||
background: rgba(255, 255, 255, 0.15);
|
background: rgba(255, 255, 255, 0.15);
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
@ -192,27 +351,77 @@ defineExpose({ loadMore })
|
|||||||
|
|
||||||
.creation-image {
|
.creation-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 400rpx;
|
display: block;
|
||||||
|
box-shadow: 3px 3px 4.5px 2px #00000026;
|
||||||
|
backdrop-filter: blur(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.like-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 122rpx;
|
||||||
|
height: 140rpx;
|
||||||
|
opacity: 1;
|
||||||
|
border-top-left-radius: 7px;
|
||||||
|
border-bottom-right-radius: 21.5px;
|
||||||
|
background: linear-gradient(
|
||||||
|
177.83deg,
|
||||||
|
rgba(83, 244, 211, 0.2) 2.52%,
|
||||||
|
rgba(15, 9, 0, 0) 69.07%
|
||||||
|
);
|
||||||
|
backdrop-filter: blur(0px);
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.like-icon-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.like-badge .like-icon {
|
||||||
|
width: 38rpx;
|
||||||
|
height: 38rpx;
|
||||||
|
margin-right: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.like-badge .like-count {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 100%;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
color: #fffabd;
|
||||||
|
text-shadow:
|
||||||
|
-1px 1px 4px #ce0909d6,
|
||||||
|
0px 0px 10px #fffabd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 光波动画 */
|
|
||||||
.wf-like-wave {
|
.wf-like-wave {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 400rpx;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wf-like-wave-outer {
|
.wf-like-wave-outer {
|
||||||
background: radial-gradient(circle, rgba(255, 107, 107, 0.8) 0%, transparent 70%);
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
rgba(255, 107, 107, 0.8) 0%,
|
||||||
|
transparent 70%
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wf-like-wave-inner {
|
.wf-like-wave-inner {
|
||||||
background: radial-gradient(circle, rgba(255, 184, 0, 0.6) 0%, transparent 70%);
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
rgba(255, 184, 0, 0.6) 0%,
|
||||||
|
transparent 70%
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wf-like-wave-active {
|
.wf-like-wave-active {
|
||||||
@ -224,6 +433,7 @@ defineExpose({ loadMore })
|
|||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(1.5);
|
transform: scale(1.5);
|
||||||
@ -231,24 +441,29 @@ defineExpose({ loadMore })
|
|||||||
}
|
}
|
||||||
|
|
||||||
.creation-info {
|
.creation-info {
|
||||||
padding: 16rpx;
|
position: absolute;
|
||||||
}
|
width: 100%;
|
||||||
|
height: 148rpx;
|
||||||
|
bottom: 0;
|
||||||
|
border-top-left-radius: 7px;
|
||||||
|
border-top-right-radius: 7px;
|
||||||
|
opacity: 1;
|
||||||
|
background: linear-gradient(
|
||||||
|
177.83deg,
|
||||||
|
rgba(235, 228, 219, 0) 20.38%,
|
||||||
|
rgba(138, 135, 131, 0.228804) 45.67%,
|
||||||
|
rgba(255, 231, 231, 0.446775) 62.04%,
|
||||||
|
rgba(255, 255, 255, 0.710766) 83.52%,
|
||||||
|
#ffffff 98.2%
|
||||||
|
);
|
||||||
|
|
||||||
.creation-id {
|
backdrop-filter: blur(0px);
|
||||||
margin-bottom: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.id-text {
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #FFB800;
|
|
||||||
font-weight: 600;
|
|
||||||
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.creation-meta {
|
.creation-meta {
|
||||||
display: flex;
|
position: absolute;
|
||||||
justify-content: space-between;
|
bottom: 8rpx;
|
||||||
align-items: center;
|
left: 40rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.creator-info {
|
.creator-info {
|
||||||
@ -256,16 +471,18 @@ defineExpose({ loadMore })
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.creator-avatar {
|
|
||||||
width: 40rpx;
|
|
||||||
height: 40rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
margin-right: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.creator-name {
|
.creator-name {
|
||||||
font-size: 22rpx;
|
font-weight: 400;
|
||||||
color: #fff;
|
font-size: 24rpx;
|
||||||
|
line-height: 100%;
|
||||||
|
letter-spacing: 0%;
|
||||||
|
color: #554545;
|
||||||
|
word-break: break-all;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.like-info {
|
.like-info {
|
||||||
@ -273,17 +490,6 @@ defineExpose({ loadMore })
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.like-icon {
|
|
||||||
width: 24rpx;
|
|
||||||
height: 24rpx;
|
|
||||||
margin-right: 4rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.like-count {
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-more,
|
.loading-more,
|
||||||
.no-more {
|
.no-more {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@ -56,7 +56,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 区域二:分类标签区 -->
|
<!-- 区域二:分类标签区 -->
|
||||||
<view id="category-section" class="category-section" :class="{ fixed: isFixed }">
|
<!-- <view id="category-section" class="category-section" :class="{ fixed: isFixed }">
|
||||||
<scroll-view class="category-scroll" scroll-x :show-scrollbar="false">
|
<scroll-view class="category-scroll" scroll-x :show-scrollbar="false">
|
||||||
<view
|
<view
|
||||||
v-for="(category, index) in categories"
|
v-for="(category, index) in categories"
|
||||||
@ -68,7 +68,7 @@
|
|||||||
<text class="category-text">{{ category.label }}</text>
|
<text class="category-text">{{ category.label }}</text>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view> -->
|
||||||
|
|
||||||
<!-- 热门分类区块 -->
|
<!-- 热门分类区块 -->
|
||||||
<view
|
<view
|
||||||
@ -111,14 +111,14 @@ import BannerCarousel from './components/BannerCarousel.vue'
|
|||||||
import HotCategoryBlock from './components/HotCategoryBlock.vue'
|
import HotCategoryBlock from './components/HotCategoryBlock.vue'
|
||||||
import CreationGrid from './components/CreationGrid.vue'
|
import CreationGrid from './components/CreationGrid.vue'
|
||||||
import { getHotInspirationFlowBatchApi } from '@/utils/api.js'
|
import { getHotInspirationFlowBatchApi } from '@/utils/api.js'
|
||||||
import { clearSubStepProgress, shouldShowGuideStartModal } from '@/utils/guideConfig.js'
|
// import { clearSubStepProgress, shouldShowGuideStartModal } from '@/utils/guideConfig.js'
|
||||||
import { useBanner } from './composables/useBanner.js'
|
import { useBanner } from './composables/useBanner.js'
|
||||||
import { doubleTapLike } from '@/utils/likeHelper.js'
|
import { doubleTapLike } from '@/utils/likeHelper.js'
|
||||||
import { USE_MOCK_DATA } from './config/mockData.js'
|
// import { USE_MOCK_DATA } from './config/mockData.js'
|
||||||
|
|
||||||
// ========== Store & User Info ==========
|
// ========== Store & User Info ==========
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const currentUserNickname = computed(() => store.state.user?.userInfo?.nickname || '')
|
// const currentUserNickname = computed(() => store.state.user?.userInfo?.nickname || '')
|
||||||
const currentStarId = ref(uni.getStorageSync('star_id') || null)
|
const currentStarId = ref(uni.getStorageSync('star_id') || null)
|
||||||
|
|
||||||
// ========== UI State ==========
|
// ========== UI State ==========
|
||||||
@ -289,30 +289,30 @@ onHide(() => {
|
|||||||
isActive.value = false
|
isActive.value = false
|
||||||
})
|
})
|
||||||
|
|
||||||
onLoad((options) => {
|
// onLoad((options) => {
|
||||||
if (options && 'guide_debug' in options) {
|
// if (options && 'guide_debug' in options) {
|
||||||
const debugValue = options.guide_debug
|
// const debugValue = options.guide_debug
|
||||||
const isDebug = debugValue === '1' || debugValue === 'true'
|
// const isDebug = debugValue === '1' || debugValue === 'true'
|
||||||
if (isDebug) {
|
// if (isDebug) {
|
||||||
uni.setStorageSync('guide_debug_mode', true)
|
// uni.setStorageSync('guide_debug_mode', true)
|
||||||
uni.setStorageSync('is_new_user', true)
|
// uni.setStorageSync('is_new_user', true)
|
||||||
console.log('[Guide] 调试模式已开启')
|
// console.log('[Guide] 调试模式已开启')
|
||||||
} else {
|
// } else {
|
||||||
uni.setStorageSync('guide_debug_mode', false)
|
// uni.setStorageSync('guide_debug_mode', false)
|
||||||
uni.removeStorageSync('is_new_user')
|
// uni.removeStorageSync('is_new_user')
|
||||||
console.log('[Guide] 调试模式已关闭')
|
// console.log('[Guide] 调试模式已关闭')
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (options && options.guide_key) {
|
// if (options && options.guide_key) {
|
||||||
console.log('[Guide] 收到引导跳转参数, guide_key:', options.guide_key, 'guide_step:', options.guide_step)
|
// console.log('[Guide] 收到引导跳转参数, guide_key:', options.guide_key, 'guide_step:', options.guide_step)
|
||||||
store.dispatch('guide/resumeGuide', options.guide_key).then(res => {
|
// store.dispatch('guide/resumeGuide', options.guide_key).then(res => {
|
||||||
console.log('[Guide] resumeGuide 结果:', res)
|
// console.log('[Guide] resumeGuide 结果:', res)
|
||||||
}).catch(err => {
|
// }).catch(err => {
|
||||||
console.error('[Guide] resumeGuide 失败:', err)
|
// console.error('[Guide] resumeGuide 失败:', err)
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
|
||||||
// 监听引导打开组件事件
|
// 监听引导打开组件事件
|
||||||
uni.$on('guide:openComponent', (componentName) => {
|
uni.$on('guide:openComponent', (componentName) => {
|
||||||
@ -350,7 +350,7 @@ onUnmounted(() => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - 64rpx);
|
height: 100vh;
|
||||||
/* margin-top: 160rpx; */
|
/* margin-top: 160rpx; */
|
||||||
padding: 240rpx 24rpx 0;
|
padding: 240rpx 24rpx 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 47 KiB |
BIN
图标1 (1).png
|
Before Width: | Height: | Size: 13 KiB |