fix: pk comment
This commit is contained in:
12
api/pk.js
12
api/pk.js
@@ -71,5 +71,17 @@ export const likeComment = async (data) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取用户 pk 列表
|
||||
* @param { page: number }
|
||||
*/
|
||||
export const fetchUserPkList = async (data) => {
|
||||
return request({
|
||||
url: "/api/rating/personal/pk/list",
|
||||
method: "GET",
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -148,11 +148,6 @@ import { onUnmounted } from "vue";
|
||||
import CommentItem from "@/components/CommentItem/CommentItem.vue";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const defaultTabs = [
|
||||
{ label: "最热", value: "hot" },
|
||||
{ label: "最新", value: "new" },
|
||||
];
|
||||
|
||||
const props = defineProps({
|
||||
requestKey: {
|
||||
type: String,
|
||||
@@ -176,7 +171,10 @@ const props = defineProps({
|
||||
},
|
||||
tabs: {
|
||||
type: Array,
|
||||
default: () => defaultTabs,
|
||||
default: () => [
|
||||
{ label: "最热", value: "hot" },
|
||||
{ label: "最新", value: "new" },
|
||||
],
|
||||
},
|
||||
allowCompose: {
|
||||
type: Boolean,
|
||||
@@ -320,7 +318,7 @@ const emit = defineEmits(["need-login", "published"]);
|
||||
const userStore = useUserStore();
|
||||
|
||||
const comments = ref([]);
|
||||
const currentTab = ref(defaultTabs[0].value);
|
||||
const currentTab = ref("hot");
|
||||
const currentPage = ref(1);
|
||||
const hasMore = ref(true);
|
||||
const loading = ref(false);
|
||||
|
||||
@@ -112,6 +112,15 @@
|
||||
"enablePullDownRefresh": true,
|
||||
"onReachBottomDistance": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/pk",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我参与的PK",
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": true,
|
||||
"onReachBottomDistance": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
@@ -65,7 +65,12 @@
|
||||
<view class="menu-card">
|
||||
<view class="menu-item" @tap="navTo('/pages/mine/topics')">
|
||||
<view class="icon-left"><text class="icon-bookmark"></text></view>
|
||||
<text class="menu-text">我的参与</text>
|
||||
<text class="menu-text">我参与的话题</text>
|
||||
<text class="menu-value" v-if="isLoggedIn">{{ userStats.participant }}</text>
|
||||
</view>
|
||||
<view class="menu-item" @tap="navTo('/pages/mine/pk')">
|
||||
<view class="icon-left"><text class="icon-bookmark"></text></view>
|
||||
<text class="menu-text">我参与的PK</text>
|
||||
<text class="menu-value" v-if="isLoggedIn">{{ userStats.participant }}</text>
|
||||
</view>
|
||||
<view class="menu-item" @tap="navTo('comments')">
|
||||
@@ -226,6 +231,11 @@ const navTo = (page) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (page === "/pages/mine/pk") {
|
||||
uni.navigateTo({ url: page });
|
||||
return;
|
||||
}
|
||||
|
||||
uni.showToast({ title: "功能开发中", icon: "none" });
|
||||
};
|
||||
</script>
|
||||
|
||||
786
pages/mine/pk.vue
Normal file
786
pages/mine/pk.vue
Normal file
@@ -0,0 +1,786 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<view class="nav-bar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="nav-content">
|
||||
<view class="nav-left" @tap="goBack">
|
||||
<text class="back-icon"></text>
|
||||
<text class="nav-title">我参与的PK</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view :style="{ height: statusBarHeight + 44 + 'px' }"></view>
|
||||
|
||||
<view class="content-wrap">
|
||||
<!-- <view class="hero-card">
|
||||
<view class="hero-main">
|
||||
<text class="hero-badge">PK Record</text>
|
||||
<text class="hero-title">我的站队记录</text>
|
||||
<text class="hero-desc">回看你参与过的每一场 PK,对比风向,看看你是大众派还是眼光独到。</text>
|
||||
</view>
|
||||
<view class="hero-stats">
|
||||
<view class="hero-stat">
|
||||
<text class="hero-stat-num">{{ isLoggedIn ? totalCount : "-" }}</text>
|
||||
<text class="hero-stat-label">参与场次</text>
|
||||
</view>
|
||||
<view class="hero-stat-divider"></view>
|
||||
<view class="hero-stat">
|
||||
<text class="hero-stat-num">{{ supportWinCount }}</text>
|
||||
<text class="hero-stat-label">站队领先</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<view v-if="!isLoggedIn" class="state-card">
|
||||
<text class="state-title">登录后查看你的 PK 足迹</text>
|
||||
<text class="state-desc">你参与过的 PK 对局、站队结果和支持率都会记录在这里。</text>
|
||||
<button class="state-btn" @tap="openLoginPopup('请先登录')">立即登录</button>
|
||||
</view>
|
||||
|
||||
<view v-else-if="loading && !pkList.length" class="state-card">
|
||||
<text class="state-title">正在加载 PK 记录...</text>
|
||||
<text class="state-desc">马上为你整理最近参与过的对决</text>
|
||||
</view>
|
||||
|
||||
<view v-else-if="loadError && !pkList.length" class="state-card">
|
||||
<text class="state-title">加载失败</text>
|
||||
<text class="state-desc">{{ loadError }}</text>
|
||||
<button class="state-btn" @tap="refreshList">重新加载</button>
|
||||
</view>
|
||||
|
||||
<view v-else-if="!pkList.length" class="state-card empty-card">
|
||||
<view class="empty-orbit orbit-1"></view>
|
||||
<view class="empty-orbit orbit-2"></view>
|
||||
<view class="empty-core">
|
||||
<text class="empty-emoji">⚔️</text>
|
||||
</view>
|
||||
<text class="state-title">你还没有参与任何 PK</text>
|
||||
<text class="state-desc">去 PK 站挑一场神仙打架,留下你的第一条站队记录吧。</text>
|
||||
<button class="state-btn" @tap="goToPkStation">去 PK 站看看</button>
|
||||
</view>
|
||||
|
||||
<view v-else class="pk-list">
|
||||
<view
|
||||
v-for="item in pkList"
|
||||
:key="item.id"
|
||||
class="pk-card"
|
||||
@tap="goToPkDetail(item)"
|
||||
>
|
||||
<view class="pk-card-top">
|
||||
<view class="pk-topic-wrap">
|
||||
<text class="pk-topic-label">话题</text>
|
||||
<text class="pk-topic-title">{{ item.topicTitle }}</text>
|
||||
</view>
|
||||
<view class="pk-time-chip">
|
||||
<text class="pk-time-text">{{ item.votedAtText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="battle-stage">
|
||||
<view class="fighter-card left" :class="{ selected: item.selfChooseSide === 'left' }">
|
||||
<view class="fighter-badge" v-if="item.selfChooseSide === 'left'">我站这边</view>
|
||||
<image class="fighter-avatar" :src="item.left.avatar" mode="aspectFill" />
|
||||
<text class="fighter-name">{{ item.left.name }}</text>
|
||||
<text class="fighter-votes">{{ item.leftVoteCount }} 票</text>
|
||||
</view>
|
||||
|
||||
<view class="battle-middle">
|
||||
<view class="vs-badge">VS</view>
|
||||
<text class="battle-middle-text">{{ item.voteCount }} 人参与</text>
|
||||
</view>
|
||||
|
||||
<view class="fighter-card right" :class="{ selected: item.selfChooseSide === 'right' }">
|
||||
<view class="fighter-badge fighter-badge--right" v-if="item.selfChooseSide === 'right'">我站这边</view>
|
||||
<image class="fighter-avatar" :src="item.right.avatar" mode="aspectFill" />
|
||||
<text class="fighter-name">{{ item.right.name }}</text>
|
||||
<text class="fighter-votes">{{ item.rightVoteCount }} 票</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="support-bar">
|
||||
<view class="support-fill left-fill" :style="{ width: `${item.leftPercent}%` }"></view>
|
||||
<view class="support-fill right-fill" :style="{ width: `${item.rightPercent}%` }"></view>
|
||||
</view>
|
||||
|
||||
<view class="support-row">
|
||||
<text class="support-text left-text">{{ item.leftPercent }}% 支持 {{ item.left.name }}</text>
|
||||
<text class="support-text right-text">{{ item.rightPercent }}% 支持 {{ item.right.name }}</text>
|
||||
</view>
|
||||
|
||||
<view class="pk-card-footer">
|
||||
<view class="choice-pill" :class="item.selfChooseSide === 'right' ? 'choice-pill--right' : ''">
|
||||
<text class="choice-pill-label">我的选择</text>
|
||||
<text class="choice-pill-value">{{ item.selfChooseName }}</text>
|
||||
</view>
|
||||
<text class="footer-link">继续查看</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="pkList.length" class="load-more">
|
||||
<text>{{ loading ? '加载中...' : (hasMore ? '上拉加载更多' : '没有更多了') }}</text>
|
||||
</view>
|
||||
|
||||
<LoginPopup ref="loginPopupRef" @logind="handleLoginSuccess" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { onLoad, onPullDownRefresh, onReachBottom, onShow } from "@dcloudio/uni-app";
|
||||
import { getStatusBarHeight } from "@/utils/system";
|
||||
import { fetchUserPkList } from "@/api/pk";
|
||||
import { FILE_BASE_URL } from "@/utils/constants";
|
||||
import { formatDate } from "@/utils/date";
|
||||
import LoginPopup from "@/components/LoginPopup/LoginPopup.vue";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const loginPopupRef = ref(null);
|
||||
const statusBarHeight = ref(getStatusBarHeight() || 44);
|
||||
const pkList = ref([]);
|
||||
const loading = ref(false);
|
||||
const hasMore = ref(true);
|
||||
const page = ref(1);
|
||||
const totalCount = ref(0);
|
||||
const loadError = ref("");
|
||||
|
||||
const isLoggedIn = computed(() => !!userStore.token || !!userStore.userInfo?.nickName);
|
||||
const supportWinCount = computed(() => {
|
||||
return pkList.value.filter((item) => {
|
||||
if (item.selfChooseSide === "left") return item.leftPercent >= item.rightPercent;
|
||||
if (item.selfChooseSide === "right") return item.rightPercent >= item.leftPercent;
|
||||
return false;
|
||||
}).length;
|
||||
});
|
||||
|
||||
const buildAvatarUrl = (avatar) => {
|
||||
if (!avatar) return "https://api.dicebear.com/7.x/avataaars/svg?seed=fallback";
|
||||
const normalizedAvatar = String(avatar).trim();
|
||||
return normalizedAvatar.startsWith("http") ? normalizedAvatar : `${FILE_BASE_URL}${normalizedAvatar}`;
|
||||
};
|
||||
|
||||
const clampPercent = (value) => {
|
||||
const number = Number(value);
|
||||
if (!Number.isFinite(number)) return 0;
|
||||
return Math.max(0, Math.min(100, Math.round(number)));
|
||||
};
|
||||
|
||||
const normalizePercentPair = (item) => {
|
||||
let leftPercent = clampPercent(item.leftPercent);
|
||||
let rightPercent = clampPercent(item.rightPercent);
|
||||
|
||||
if (!leftPercent && !rightPercent) {
|
||||
const leftVotes = Number(item.leftVoteCount || 0);
|
||||
const rightVotes = Number(item.rightVoteCount || 0);
|
||||
const totalVotes = leftVotes + rightVotes;
|
||||
if (totalVotes > 0) {
|
||||
leftPercent = Math.round((leftVotes / totalVotes) * 100);
|
||||
rightPercent = 100 - leftPercent;
|
||||
} else {
|
||||
leftPercent = 50;
|
||||
rightPercent = 50;
|
||||
}
|
||||
} else if (!leftPercent) {
|
||||
leftPercent = 100 - rightPercent;
|
||||
} else if (!rightPercent) {
|
||||
rightPercent = 100 - leftPercent;
|
||||
}
|
||||
|
||||
const total = leftPercent + rightPercent;
|
||||
if (total && total !== 100) {
|
||||
leftPercent = Math.round((leftPercent / total) * 100);
|
||||
rightPercent = 100 - leftPercent;
|
||||
}
|
||||
|
||||
return { leftPercent, rightPercent };
|
||||
};
|
||||
|
||||
const normalizePkItem = (item = {}) => {
|
||||
const { leftPercent, rightPercent } = normalizePercentPair(item);
|
||||
const selfChooseSide =
|
||||
item.selfChooseSide ||
|
||||
(item.selfChooseItemId && item.selfChooseItemId === item.leftItemId
|
||||
? "left"
|
||||
: item.selfChooseItemId && item.selfChooseItemId === item.rightItemId
|
||||
? "right"
|
||||
: "");
|
||||
const selfChooseName =
|
||||
selfChooseSide === "right"
|
||||
? (item.rightItemName || "右侧对象")
|
||||
: selfChooseSide === "left"
|
||||
? (item.leftItemName || "左侧对象")
|
||||
: "未记录";
|
||||
|
||||
return {
|
||||
id: item.id || "",
|
||||
topicId: item.topicId || "",
|
||||
topicTitle: item.topicTitle || "未知话题",
|
||||
voteCount: Number(item.voteCount || 0),
|
||||
leftVoteCount: Number(item.leftVoteCount || 0),
|
||||
rightVoteCount: Number(item.rightVoteCount || 0),
|
||||
selfChooseItemId: item.selfChooseItemId || "",
|
||||
selfChooseSide,
|
||||
selfChooseName,
|
||||
leftPercent,
|
||||
rightPercent,
|
||||
votedAt: item.votedAt || "",
|
||||
votedAtText: formatDate(item.votedAt, "YYYY-MM-DD HH:mm") || "刚刚参与",
|
||||
left: {
|
||||
id: item.leftItemId || "",
|
||||
name: item.leftItemName || "左侧对象",
|
||||
avatar: buildAvatarUrl(item.leftItemAvatar),
|
||||
},
|
||||
right: {
|
||||
id: item.rightItemId || "",
|
||||
name: item.rightItemName || "右侧对象",
|
||||
avatar: buildAvatarUrl(item.rightItemAvatar),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
const openLoginPopup = (message = "请先登录") => {
|
||||
loginPopupRef.value?.open();
|
||||
if (message) {
|
||||
uni.showToast({ title: message, icon: "none" });
|
||||
}
|
||||
};
|
||||
|
||||
const goToPkStation = () => {
|
||||
uni.switchTab({
|
||||
url: "/pages/pk/index",
|
||||
});
|
||||
};
|
||||
|
||||
const goToPkDetail = (item) => {
|
||||
if (!item?.topicId) return;
|
||||
const focusItemId = item.selfChooseItemId || item.left.id;
|
||||
uni.navigateTo({
|
||||
url: `/pages/rating/pk?topicId=${item.topicId}&itemId=${focusItemId}`,
|
||||
});
|
||||
};
|
||||
|
||||
const loadList = async (targetPage = 1) => {
|
||||
if (!isLoggedIn.value || loading.value) return;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
loadError.value = "";
|
||||
const res = await fetchUserPkList({ page: targetPage });
|
||||
const data = res?.data || res || {};
|
||||
const rawList = data.list || res?.list || [];
|
||||
const list = Array.isArray(rawList) ? rawList : [];
|
||||
const formattedList = list.map(normalizePkItem);
|
||||
const nextTotalCount = Number(data.totalCount || res?.totalCount || 0);
|
||||
|
||||
totalCount.value = nextTotalCount;
|
||||
pkList.value = targetPage === 1 ? formattedList : [...pkList.value, ...formattedList];
|
||||
|
||||
if (nextTotalCount > 0) {
|
||||
hasMore.value = pkList.value.length < nextTotalCount;
|
||||
} else {
|
||||
hasMore.value = list.length > 0;
|
||||
}
|
||||
} catch (error) {
|
||||
loadError.value = "网络开了点小差,稍后重试";
|
||||
if (targetPage > 1) {
|
||||
page.value -= 1;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const refreshList = async () => {
|
||||
page.value = 1;
|
||||
hasMore.value = true;
|
||||
await loadList(1);
|
||||
};
|
||||
|
||||
const handleLoginSuccess = async () => {
|
||||
await refreshList();
|
||||
};
|
||||
|
||||
onLoad(() => {});
|
||||
|
||||
onShow(() => {
|
||||
if (!isLoggedIn.value) {
|
||||
pkList.value = [];
|
||||
totalCount.value = 0;
|
||||
hasMore.value = false;
|
||||
return;
|
||||
}
|
||||
refreshList();
|
||||
});
|
||||
|
||||
onPullDownRefresh(async () => {
|
||||
if (isLoggedIn.value) {
|
||||
await refreshList();
|
||||
}
|
||||
uni.stopPullDownRefresh();
|
||||
});
|
||||
|
||||
onReachBottom(() => {
|
||||
if (!isLoggedIn.value || !hasMore.value || loading.value) return;
|
||||
page.value += 1;
|
||||
loadList(page.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(circle at top, rgba(111, 90, 255, 0.12), transparent 30%),
|
||||
linear-gradient(180deg, #f7f8ff 0%, #f6f7fb 42%, #ffffff 100%);
|
||||
padding-bottom: 56rpx;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
background: rgba(247, 248, 255, 0.88);
|
||||
backdrop-filter: blur(24rpx);
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
|
||||
.nav-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23202433' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='19' y1='12' x2='5' y2='12'%3E%3C/line%3E%3Cpolyline points='12 19 5 12 12 5'%3E%3C/polyline%3E%3C/svg%3E");
|
||||
background-size: cover;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 800;
|
||||
color: #202433;
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
padding: 24rpx 32rpx 0;
|
||||
}
|
||||
|
||||
.hero-card,
|
||||
.pk-card,
|
||||
.state-card {
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
border: 2rpx solid rgba(229, 232, 246, 0.92);
|
||||
border-radius: 32rpx;
|
||||
box-shadow: 0 18rpx 42rpx rgba(87, 92, 145, 0.08);
|
||||
}
|
||||
|
||||
.hero-card {
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.hero-main {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 44rpx;
|
||||
padding: 0 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(92, 67, 245, 0.1);
|
||||
color: #5c43f5;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
display: block;
|
||||
font-size: 42rpx;
|
||||
font-weight: 800;
|
||||
color: #1f2432;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.hero-desc {
|
||||
font-size: 25rpx;
|
||||
color: #7b8191;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.hero-stats {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 20rpx 8rpx;
|
||||
border-radius: 24rpx;
|
||||
background: linear-gradient(135deg, rgba(92, 67, 245, 0.08), rgba(92, 67, 245, 0.02));
|
||||
}
|
||||
|
||||
.hero-stat {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-stat-num {
|
||||
display: block;
|
||||
font-size: 38rpx;
|
||||
font-weight: 800;
|
||||
color: #202433;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.hero-stat-label {
|
||||
font-size: 22rpx;
|
||||
color: #8a90a0;
|
||||
}
|
||||
|
||||
.hero-stat-divider {
|
||||
width: 2rpx;
|
||||
height: 52rpx;
|
||||
background: rgba(206, 211, 229, 0.8);
|
||||
}
|
||||
|
||||
.state-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 64rpx 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.state-title {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
color: #232734;
|
||||
font-weight: 800;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.state-desc {
|
||||
display: block;
|
||||
font-size: 25rpx;
|
||||
color: #8a90a0;
|
||||
line-height: 1.7;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.state-btn {
|
||||
width: 240rpx;
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #111827;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.state-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.empty-card {
|
||||
padding-top: 92rpx;
|
||||
}
|
||||
|
||||
.empty-orbit {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
border: 2rpx dashed rgba(99, 102, 241, 0.16);
|
||||
}
|
||||
|
||||
.orbit-1 {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
top: 26rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.orbit-2 {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
top: 56rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.empty-core {
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
margin: 0 auto 130rpx;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #eef2ff 100%);
|
||||
box-shadow: 0 16rpx 34rpx rgba(99, 102, 241, 0.14);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.empty-emoji {
|
||||
font-size: 52rpx;
|
||||
}
|
||||
|
||||
.pk-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.pk-card {
|
||||
padding: 28rpx;
|
||||
}
|
||||
|
||||
.pk-card-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.pk-topic-wrap {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.pk-topic-label {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #8a90a0;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.pk-topic-title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
line-height: 1.45;
|
||||
color: #202433;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.pk-time-chip {
|
||||
flex-shrink: 0;
|
||||
padding: 10rpx 16rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(17, 24, 39, 0.06);
|
||||
}
|
||||
|
||||
.pk-time-text {
|
||||
font-size: 22rpx;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.battle-stage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 22rpx;
|
||||
}
|
||||
|
||||
.fighter-card {
|
||||
position: relative;
|
||||
width: 224rpx;
|
||||
min-height: 276rpx;
|
||||
border-radius: 28rpx;
|
||||
padding: 30rpx 18rpx 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(180deg, #fafbff 0%, #ffffff 100%);
|
||||
border: 2rpx solid transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.fighter-card.left {
|
||||
border-color: rgba(92, 67, 245, 0.18);
|
||||
}
|
||||
|
||||
.fighter-card.right {
|
||||
border-color: rgba(255, 153, 102, 0.2);
|
||||
}
|
||||
|
||||
.fighter-card.selected {
|
||||
transform: translateY(-4rpx);
|
||||
box-shadow: 0 14rpx 28rpx rgba(92, 67, 245, 0.12);
|
||||
}
|
||||
|
||||
.fighter-badge {
|
||||
position: absolute;
|
||||
top: 16rpx;
|
||||
left: 16rpx;
|
||||
padding: 8rpx 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(92, 67, 245, 0.12);
|
||||
color: #5c43f5;
|
||||
font-size: 20rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.fighter-badge--right {
|
||||
background: rgba(255, 141, 95, 0.14);
|
||||
color: #ff7a45;
|
||||
}
|
||||
|
||||
.fighter-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
border: 6rpx solid #fff;
|
||||
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.fighter-name {
|
||||
font-size: 30rpx;
|
||||
color: #1f2432;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.fighter-votes {
|
||||
font-size: 22rpx;
|
||||
color: #858b9b;
|
||||
}
|
||||
|
||||
.battle-middle {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.vs-badge {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #6a5bff, #4d44f1);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 900;
|
||||
box-shadow: 0 16rpx 30rpx rgba(92, 67, 245, 0.24);
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.battle-middle-text {
|
||||
font-size: 22rpx;
|
||||
color: #8a90a0;
|
||||
}
|
||||
|
||||
.support-bar {
|
||||
height: 18rpx;
|
||||
border-radius: 999rpx;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
background: #eceff8;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.support-fill {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.left-fill {
|
||||
background: linear-gradient(90deg, #6557ff, #4d44f1);
|
||||
}
|
||||
|
||||
.right-fill {
|
||||
background: linear-gradient(90deg, #ffb15f, #ff8d5f);
|
||||
}
|
||||
|
||||
.support-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 22rpx;
|
||||
}
|
||||
|
||||
.support-text {
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.left-text {
|
||||
color: #5c43f5;
|
||||
}
|
||||
|
||||
.right-text {
|
||||
color: #ff8d5f;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.pk-card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.choice-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding: 12rpx 18rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(92, 67, 245, 0.1);
|
||||
}
|
||||
|
||||
.choice-pill--right {
|
||||
background: rgba(255, 141, 95, 0.12);
|
||||
}
|
||||
|
||||
.choice-pill-label {
|
||||
font-size: 22rpx;
|
||||
color: #8a90a0;
|
||||
}
|
||||
|
||||
.choice-pill-value {
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
color: #4d44f1;
|
||||
}
|
||||
|
||||
.choice-pill--right .choice-pill-value {
|
||||
color: #ff7a45;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
text-align: center;
|
||||
padding: 24rpx 0 40rpx;
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user