|
|
@ -0,0 +1,561 @@
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
|
|
import {onMounted, ref, watch} from 'vue'
|
|
|
|
|
|
|
|
import {ElMessage, ElNotification} from 'element-plus'
|
|
|
|
|
|
|
|
import {listStudent, rollCall, updatePoints} from "@/api/student.js";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 响应式状态
|
|
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
|
|
const cards = ref([])
|
|
|
|
|
|
|
|
const canSelect = ref(true)
|
|
|
|
|
|
|
|
const isResetting = ref(false)
|
|
|
|
|
|
|
|
const dialogVisible = ref(false)
|
|
|
|
|
|
|
|
const cardResult = ref({})
|
|
|
|
|
|
|
|
const studentTable = ref([])
|
|
|
|
|
|
|
|
const avatarUrl = ref('https://api.aspark.cc')
|
|
|
|
|
|
|
|
const avatarKey = ref(0)
|
|
|
|
|
|
|
|
const pointChange = ref(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 洗牌
|
|
|
|
|
|
|
|
const shuffle = (array, count) => {
|
|
|
|
|
|
|
|
// 创建一个数组副本用于打乱,不改变原数组
|
|
|
|
|
|
|
|
const shuffled = [...array];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fisher-Yates 洗牌算法
|
|
|
|
|
|
|
|
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
|
|
|
|
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
|
|
|
|
|
|
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; // 交换位置
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果打乱后的数组长度大于等于 count,返回前 count 个元素
|
|
|
|
|
|
|
|
if (shuffled.length >= count) {
|
|
|
|
|
|
|
|
return shuffled.slice(0, count);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果数组长度不足,随机补充元素
|
|
|
|
|
|
|
|
const result = [...shuffled];
|
|
|
|
|
|
|
|
while (result.length < count) {
|
|
|
|
|
|
|
|
const randomIndex = Math.floor(Math.random() * array.length);
|
|
|
|
|
|
|
|
result.push(array[randomIndex]); // 随机从原数组中选取元素进行补充
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const initCards = async () => {
|
|
|
|
|
|
|
|
const response = await rollCall()
|
|
|
|
|
|
|
|
pointChange.value = 0
|
|
|
|
|
|
|
|
cardResult.value = response.data
|
|
|
|
|
|
|
|
const totalCards = 27
|
|
|
|
|
|
|
|
const shuffledResult = shuffle(studentTable.value, totalCards)
|
|
|
|
|
|
|
|
// console.log(shuffledResult)
|
|
|
|
|
|
|
|
cards.value = shuffledResult.map(({name}) => ({name, isFlipped: false}))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
avatarKey.value = Date.now()
|
|
|
|
|
|
|
|
const img = new Image()
|
|
|
|
|
|
|
|
img.src = `${avatarUrl.value}/random/${avatarKey.value}`
|
|
|
|
|
|
|
|
img.onerror = () => {
|
|
|
|
|
|
|
|
console.error('Failed to load avatar')
|
|
|
|
|
|
|
|
avatarUrl.value = 'path/to/default/avatar.png'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectCard = (index) => {
|
|
|
|
|
|
|
|
if (!canSelect.value || cards.value[index].isFlipped) return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cards.value[index] = {
|
|
|
|
|
|
|
|
name: cardResult.value.name,
|
|
|
|
|
|
|
|
isFlipped: true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
canSelect.value = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ElMessage.success(`恭喜你 ${cards.value[index].name}!`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
|
|
cards.value.forEach((card, i) => {
|
|
|
|
|
|
|
|
if (i !== index) {
|
|
|
|
|
|
|
|
card.isFlipped = true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleRestart = () => {
|
|
|
|
|
|
|
|
dialogVisible.value = false
|
|
|
|
|
|
|
|
if (isResetting.value) return
|
|
|
|
|
|
|
|
isResetting.value = true
|
|
|
|
|
|
|
|
canSelect.value = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cards.value.forEach(card => {
|
|
|
|
|
|
|
|
card.isFlipped = false
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(async () => {
|
|
|
|
|
|
|
|
await initCards()
|
|
|
|
|
|
|
|
canSelect.value = true
|
|
|
|
|
|
|
|
isResetting.value = false
|
|
|
|
|
|
|
|
}, 600)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
|
|
const response = await listStudent()
|
|
|
|
|
|
|
|
studentTable.value = response.data
|
|
|
|
|
|
|
|
await initCards()
|
|
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
|
|
ElNotification({
|
|
|
|
|
|
|
|
title: '提示',
|
|
|
|
|
|
|
|
message: '从下方 27 张卡片中任意抽取一张吧!',
|
|
|
|
|
|
|
|
type: 'info',
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const formatTooltip = (value) => {
|
|
|
|
|
|
|
|
return value > 0 ? `+${value}` : value.toString();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const updateSliderColor = () => {
|
|
|
|
|
|
|
|
const slider = document.querySelector('.el-slider__runway');
|
|
|
|
|
|
|
|
const sliderButton = document.querySelector('.el-slider__button');
|
|
|
|
|
|
|
|
if (!slider || !sliderButton) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设置按钮边框颜色
|
|
|
|
|
|
|
|
if (pointChange.value < 0) {
|
|
|
|
|
|
|
|
sliderButton.style.borderColor = '#f56c6c';
|
|
|
|
|
|
|
|
} else if (pointChange.value > 0) {
|
|
|
|
|
|
|
|
sliderButton.style.borderColor = '#67c23a';
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
sliderButton.style.borderColor = '#409EFF'; // 默认颜色,当值为0时
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 移除旧的颜色条
|
|
|
|
|
|
|
|
const oldBars = slider.querySelectorAll('.custom-slider-bar');
|
|
|
|
|
|
|
|
oldBars.forEach(bar => bar.remove());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建负值(红色)和正值(绿色)的颜色条
|
|
|
|
|
|
|
|
const negativeBar = document.createElement('div');
|
|
|
|
|
|
|
|
const positiveBar = document.createElement('div');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
negativeBar.className = 'custom-slider-bar negative';
|
|
|
|
|
|
|
|
positiveBar.className = 'custom-slider-bar positive';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
slider.appendChild(negativeBar);
|
|
|
|
|
|
|
|
slider.appendChild(positiveBar);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const zeroPosition = 50; // 0点在50%的位置
|
|
|
|
|
|
|
|
const currentPosition = pointChange.value * 8 * 2 + 50;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pointChange.value < 0) {
|
|
|
|
|
|
|
|
// 负值:显示红色,从0点到当前位置
|
|
|
|
|
|
|
|
negativeBar.style.left = `${currentPosition}%`;
|
|
|
|
|
|
|
|
negativeBar.style.width = `${zeroPosition - currentPosition}%`;
|
|
|
|
|
|
|
|
positiveBar.style.width = '0';
|
|
|
|
|
|
|
|
} else if (pointChange.value > 0) {
|
|
|
|
|
|
|
|
// 正值:显示绿色,从0点到当前位置
|
|
|
|
|
|
|
|
positiveBar.style.left = `${zeroPosition}%`;
|
|
|
|
|
|
|
|
positiveBar.style.width = `${currentPosition - zeroPosition}%`;
|
|
|
|
|
|
|
|
negativeBar.style.width = '0';
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// 0值:都不显示
|
|
|
|
|
|
|
|
negativeBar.style.width = '0';
|
|
|
|
|
|
|
|
positiveBar.style.width = '0';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const decrementPoints = () => {
|
|
|
|
|
|
|
|
if (pointChange.value > -5) {
|
|
|
|
|
|
|
|
pointChange.value -= 0.5;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const incrementPoints = () => {
|
|
|
|
|
|
|
|
if (pointChange.value < 5) {
|
|
|
|
|
|
|
|
pointChange.value += 0.5;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch(pointChange, updateSliderColor);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
|
|
updateSliderColor();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handlePointsChange = async () => {
|
|
|
|
|
|
|
|
if (pointChange.value === 0) {
|
|
|
|
|
|
|
|
dialogVisible.value = false
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const response = await updatePoints(cardResult.value.id, pointChange.value)
|
|
|
|
|
|
|
|
if (response.code === 0) {
|
|
|
|
|
|
|
|
ElMessage.error('失败,原因:' + response.msg)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dialogVisible.value = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
|
|
<el-card v-loading="loading">
|
|
|
|
|
|
|
|
<div class="lottery-container">
|
|
|
|
|
|
|
|
<div class="cards-grid">
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
|
|
|
v-for="(card, index) in cards"
|
|
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
|
|
class="card"
|
|
|
|
|
|
|
|
:class="{ 'flipped': card.isFlipped }"
|
|
|
|
|
|
|
|
@click="selectCard(index)"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<div class="card-inner">
|
|
|
|
|
|
|
|
<div class="card-front"></div>
|
|
|
|
|
|
|
|
<div class="card-back">
|
|
|
|
|
|
|
|
<div class="card-content">
|
|
|
|
|
|
|
|
<!-- <div class="text-column">-->
|
|
|
|
|
|
|
|
<!-- <span class="vertical-text student-no">{{ card.no }}</span>-->
|
|
|
|
|
|
|
|
<!-- </div>-->
|
|
|
|
|
|
|
|
<div class="text-column">
|
|
|
|
|
|
|
|
<span class="vertical-text student-name">{{ card.name }}</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
<el-dialog
|
|
|
|
|
|
|
|
v-model="dialogVisible"
|
|
|
|
|
|
|
|
width="400px"
|
|
|
|
|
|
|
|
:align-center="true"
|
|
|
|
|
|
|
|
class="profile-dialog"
|
|
|
|
|
|
|
|
@close="handleRestart"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<div class="profile-content">
|
|
|
|
|
|
|
|
<el-avatar
|
|
|
|
|
|
|
|
:size="100"
|
|
|
|
|
|
|
|
:src="avatarUrl + '/random/' + avatarKey"
|
|
|
|
|
|
|
|
class="profile-avatar"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
<h2 class="profile-name">{{ cardResult.no }} {{ cardResult.name }}</h2>
|
|
|
|
|
|
|
|
<h3 class="profile-points">当前积分:{{ cardResult.points }}</h3>
|
|
|
|
|
|
|
|
<div class="slider-demo-block">
|
|
|
|
|
|
|
|
<div class="slider-controls">
|
|
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
|
|
@click="decrementPoints"
|
|
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
|
|
class="slider-button decrease"
|
|
|
|
|
|
|
|
>-</el-button>
|
|
|
|
|
|
|
|
<div class="slider-wrapper">
|
|
|
|
|
|
|
|
<el-slider
|
|
|
|
|
|
|
|
v-model="pointChange"
|
|
|
|
|
|
|
|
:min="-3"
|
|
|
|
|
|
|
|
:max="3"
|
|
|
|
|
|
|
|
:step="0.5"
|
|
|
|
|
|
|
|
show-stops
|
|
|
|
|
|
|
|
:format-tooltip="formatTooltip"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
|
|
@click="incrementPoints"
|
|
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
|
|
class="slider-button increase"
|
|
|
|
|
|
|
|
>+</el-button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="point-change-label">
|
|
|
|
|
|
|
|
<span>积分变动:</span>
|
|
|
|
|
|
|
|
<span :class="{'positive': pointChange > 0, 'negative': pointChange < 0}">
|
|
|
|
|
|
|
|
{{ pointChange > 0 ? '+' : ''}}{{ pointChange }}
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="button-container">
|
|
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
|
|
type="danger"
|
|
|
|
|
|
|
|
@click="handleRestart"
|
|
|
|
|
|
|
|
class="round-button"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<i class="iconfont yaya-xmark" style="font-size: 24px;"/>
|
|
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
|
|
type="success"
|
|
|
|
|
|
|
|
@click="handlePointsChange"
|
|
|
|
|
|
|
|
class="round-button"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<i class="iconfont yaya-duigou" style="font-size: 24px;" />
|
|
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<p class="profile-bio">Coding the World.</p>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
|
|
|
body .el-dialog {
|
|
|
|
|
|
|
|
--el-dialog-border-radius: 20px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
|
|
.lottery-container {
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.cards-grid {
|
|
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
|
|
grid-template-columns: repeat(9, 1fr);
|
|
|
|
|
|
|
|
grid-template-rows: repeat(3, 1fr);
|
|
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
max-width: 1400px;
|
|
|
|
|
|
|
|
aspect-ratio: 2.7/1;
|
|
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card {
|
|
|
|
|
|
|
|
perspective: 1000px;
|
|
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
aspect-ratio: 0.7/1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card-inner {
|
|
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
transition: transform 0.6s;
|
|
|
|
|
|
|
|
transform-style: preserve-3d;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card.flipped .card-inner {
|
|
|
|
|
|
|
|
transform: rotateY(180deg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card-front,
|
|
|
|
|
|
|
|
.card-back {
|
|
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
backface-visibility: hidden;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
border-radius: 5px;
|
|
|
|
|
|
|
|
background-size: cover;
|
|
|
|
|
|
|
|
background-position: center;
|
|
|
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card-front {
|
|
|
|
|
|
|
|
background-image: url('../assets/card.webp');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card-back {
|
|
|
|
|
|
|
|
background-image: url('../assets/card2.webp');
|
|
|
|
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
|
|
|
|
color: black;
|
|
|
|
|
|
|
|
transform: rotateY(180deg);
|
|
|
|
|
|
|
|
font-family: '隶书', '隶书-online', '微软雅黑', sans-serif;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card-content {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
gap: 2px;
|
|
|
|
|
|
|
|
width: 90%;
|
|
|
|
|
|
|
|
height: 90%;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.text-column {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.vertical-text {
|
|
|
|
|
|
|
|
writing-mode: vertical-rl;
|
|
|
|
|
|
|
|
text-orientation: upright;
|
|
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
|
|
max-height: 100%;
|
|
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.text-column .student-name {
|
|
|
|
|
|
|
|
font-size: clamp(1px, 3vw, 24px);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.text-column .student-name {
|
|
|
|
|
|
|
|
font-size: clamp(1px, 2.5vw, 14px);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.card-content {
|
|
|
|
|
|
|
|
gap: 1px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.profile-dialog :deep(.el-dialog) {
|
|
|
|
|
|
|
|
background-color: #f5f7f5;
|
|
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.profile-content {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.profile-avatar {
|
|
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.profile-name {
|
|
|
|
|
|
|
|
color: #2c3e50;
|
|
|
|
|
|
|
|
font-size: 1.8em;
|
|
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.profile-points {
|
|
|
|
|
|
|
|
color: #67c23a;
|
|
|
|
|
|
|
|
font-size: 1.4em;
|
|
|
|
|
|
|
|
margin-bottom: 25px;
|
|
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.profile-bio {
|
|
|
|
|
|
|
|
color: #5c6b77;
|
|
|
|
|
|
|
|
font-size: 1.1em;
|
|
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
|
|
font-family: 'Nautilus-pompilius', sans-serif;
|
|
|
|
|
|
|
|
font-style: italic;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.slider-demo-block {
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
margin-bottom: 40px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.slider-controls {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.slider-wrapper {
|
|
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
margin: 0 15px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.slider-button {
|
|
|
|
|
|
|
|
width: 32px;
|
|
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.slider-button.decrease {
|
|
|
|
|
|
|
|
background-color: #f56c6c;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.slider-button.increase {
|
|
|
|
|
|
|
|
background-color: #67c23a;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.slider-button:hover {
|
|
|
|
|
|
|
|
transform: scale(1.05);
|
|
|
|
|
|
|
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.point-change-label {
|
|
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.point-change-label .positive {
|
|
|
|
|
|
|
|
color: #67c23a;
|
|
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.point-change-label .negative {
|
|
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-slider__runway) {
|
|
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
|
|
background-color: #e4e7ed;
|
|
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.custom-slider-bar) {
|
|
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
|
|
height: 6px;
|
|
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.custom-slider-bar.negative) {
|
|
|
|
|
|
|
|
background-color: #f56c6c;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.custom-slider-bar.positive) {
|
|
|
|
|
|
|
|
background-color: #67c23a;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-slider__bar) {
|
|
|
|
|
|
|
|
display: none; /* 隐藏原始的滑块条 */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-slider__button) {
|
|
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
|
|
border: 2px solid; /* 移除固定的边框颜色 */
|
|
|
|
|
|
|
|
background-color: white;
|
|
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
z-index: 3;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-slider__button:hover) {
|
|
|
|
|
|
|
|
transform: scale(1.1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-slider__stop) {
|
|
|
|
|
|
|
|
background-color: transparent;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.button-container {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
gap: 20px; /* 可根据需要调整间距 */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.round-button {
|
|
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
|
|
width: 50px; /* 根据需要调整大小 */
|
|
|
|
|
|
|
|
height: 50px; /* 根据需要调整大小 */
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</style>
|