Commit 47aa4834 by Hantao

feat(first): 添加第一关游戏页面及组件

- 新增第一关完整游戏页面,包含垃圾清理、油膜分离、酸碱中和三个交互阶段
- 实现垃圾清理的拖拽垃圾桶清除功能,支持左右移动清除不同垃圾
- 实现油膜分离的进度条拖拽交互,达到特定进度显示净化值
- 实现酸碱中和的试剂选择交互,选择正确试剂进入下一阶段
- 添加阶段切换逻辑和完成弹窗,集成进度条显示
- 更新页面路由配置,添加第一关页面入口
- 替换静态图片资源为CDN链接,优化加载性能
- 更新切图文档,补充徽章和第一关切图地址
parent 076aeaaf
...@@ -35,6 +35,12 @@ ...@@ -35,6 +35,12 @@
} }
}, },
{ {
"path": "pages/first/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/second/index", "path": "pages/second/index",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
......
...@@ -3,22 +3,22 @@ import { ref, computed } from 'vue'; ...@@ -3,22 +3,22 @@ import { ref, computed } from 'vue';
import navBar from '@/components/navBar.vue'; import navBar from '@/components/navBar.vue';
const ASSETS = Object.freeze({ const ASSETS = Object.freeze({
blank: '/static/badge/blank.webp', blank: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/d7873615505b400abd996b7498aaa4b6wcS02B18DXFm131a1e3b221f4a5853c94500ebbe1dbf.webp',
badge1: '/static/badge/badge1.webp', badge1: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/672e8e6fbd5444c884675dde50c446a5Y2af2XVB0T-Jb7e73ab2397ffdb37f2b5c132dc584da.webp',
badge2: '/static/badge/badge2.webp', badge2: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/cd584ad7bc204aaa92e22b7d6294d752J4r8jf1sLeDBe39016508c55312b7a0d6d0ab378c691.webp',
badge3: '/static/badge/badge3.webp', badge3: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/252505de8901440b89c01ceae8ba92735cwiy47_s9O92237a043d60f2620a390cd3980a7f3c6.webp',
badge4: '/static/badge/badge4.webp', badge4: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/10c6937c832d498f8e9d7e0a975263329nC4ASG9gQBka44a97e514fdb44b775b49e72d9aefbc.webp',
badge5: '/static/badge/badge5.webp', badge5: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/b926e4cd469b4400bc19ba9ed6798e88XwyB9JqUSWXGcf436811eae73ba6229615399dab16aa.webp',
badge1Gray: '/static/badge/badge1-grey.webp', badge1Gray: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/a155a0a5c619418b90e656792e2a0d1114pNJPNn64ss4e6fe0a34a2c181ecffb4ba77bace4f2.webp',
badge2Gray: '/static/badge/badge2-grey.webp', badge2Gray: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/d495a86e446046faabfdea09d84a44d1fGL8pw_2cHR4a4d071d2ed6d75cd0227298ef969a4d9.webp',
badge3Gray: '/static/badge/badge3-grey.webp', badge3Gray: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/22ff15d76d144306909f94c4029670abiCgKOBoreJ-1bcbb00df1ba5682386e031ccedc3c6cb.webp',
badge4Gray: '/static/badge/badge4-grey.webp', badge4Gray: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/018385573cde45eb927283dbb8e6468acj8h_7C-hy9v38ef8079391af2ddb8785bfb0ee8f041.webp',
badge5Gray: '/static/badge/badge5-grey.webp', badge5Gray: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/498cf3a935334fa09f0b0d45ee300795QSZy9n9Y6yBR8b4fabffd32f8517af6ba129810be346.webp',
display1: '/static/badge/display1.webp', display1: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/d8b5013e03ed435e87df67f23a336c5004LqofmY2_AB12cc8ce7b029bc417ca372f0adf99357.webp',
display2: '/static/badge/display2.webp', display2: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/429f24ee65ea41a08375e52561163383fHpZ7I1MpNm6dd4ee291f5836d1f4c2d2dfc18ac3af7.webp',
display3: '/static/badge/display3.webp', display3: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/e7415cd5630e4d0e8c7526fc3b5432daZVjP7LzdCneu558949671d27a4a9165a4b04038e17dc.webp',
display4: '/static/badge/display4.webp', display4: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/cdb8a5aa5d884b15b3b3df5ab467603aRlgBB7VFxdiZe002226923227b90a51c8e269b34a785.webp',
display5: '/static/badge/display5.webp', display5: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/68240835222e4fdf95dce8759ea7effd89x90XC2gyYK04083bca99804e8496bbe94a90d090ab.webp',
}) })
const badges = computed(() => [ const badges = computed(() => [
......
<script setup>
const ASSETS = Object.freeze({
water: '/static/first/water.png',
});
</script>
<template>
<view class="container">
<view class="content">
<view class="top">
<image :src="ASSETS.water" style="width: 48rpx; height: 48rpx;" />
<view class="title">小知识点:</view>
</view>
<view class="text">“我国80%的城市水源面临污染挑战,安吉尔RO膜能够过滤99%的污染物,守护千万家饮水与用水的安全。”</view>
</view>
</view>
</template>
<style scoped lang="scss">
.container {
width: 100%;
height: 100%;
position: relative;
.content {
position: absolute;
top: 500rpx;
left: 50%;
transform: translate(-50%, -50%);
width: 456rpx;
height: 260rpx;
border-radius: 24rpx;
border: 3rpx solid #FFF;
background: #F0F9FC;
box-shadow: 0 8rpx 8rpx 0 #0b768266, 0 0 39.6rpx 0 #C8EEFF inset;
.top {
display: flex;
align-items: center;
padding: 20rpx 20rpx 12rpx;
.title {
font-size: 34rpx;
color: #2d4b5d;
font-weight: 600;
margin-left: 12rpx;
}
}
.text {
padding: 0 20rpx;
color: #2d4b5d;
font-size: 28rpx;
font-weight: 400;
}
}
}
</style>
<script setup>
import { ref, watch } from 'vue';
const props = defineProps({
isTransitioning: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['all-cleared', 'show-purification', 'move-left', 'move-right', 'hide-purification']);
const ASSETS = Object.freeze({
rubbishOne: '/static/first/rubbish-one.png',
rubbishTwo: '/static/first/rubbish-two.png',
arrowLeft: '/static/first/arrowLeft.png',
arrowRight: '/static/first/arrowRight.png',
trashCan: '/static/first/trashCan.png',
});
// 垃圾桶移动相关状态
const trashCanOffsetX = ref(0);
const trashCanStartX = ref(0);
const isDragging = ref(false);
const isTrashCanEnlarged = ref(false);
// 垃圾清除状态
const isOneRemoved = ref(false);
const isTwoRemoved = ref(false);
// 移动阈值
const LEFT_THRESHOLD = -200;
const RIGHT_THRESHOLD = 200;
const MAX_OFFSET = 200;
// 触摸开始
const onTrashCanTouchStart = (e) => {
if (props.isTransitioning) return;
isDragging.value = true;
trashCanStartX.value = e.touches[0].clientX;
isTrashCanEnlarged.value = true;
emit('hide-purification');
};
// 触摸移动
const onTrashCanTouchMove = (e) => {
if (!isDragging.value || props.isTransitioning) return;
const touchX = e.touches[0].clientX;
const deltaX = touchX - trashCanStartX.value;
const screenWidth = uni.getSystemInfoSync().windowWidth;
const deltaRpx = (deltaX / screenWidth) * 750;
// 限制移动范围
if (deltaRpx < -MAX_OFFSET) {
trashCanOffsetX.value = -MAX_OFFSET;
} else if (deltaRpx > MAX_OFFSET) {
trashCanOffsetX.value = MAX_OFFSET;
} else {
trashCanOffsetX.value = deltaRpx;
}
// 检查是否到达阈值并清除垃圾
checkAndClearTrash();
};
// 触摸结束
const onTrashCanTouchEnd = () => {
isDragging.value = false;
isTrashCanEnlarged.value = false;
setTimeout(() => {
trashCanOffsetX.value = 0;
}, 300);
};
// 检查并清除垃圾
const checkAndClearTrash = () => {
// 向左移动清除one
if (trashCanOffsetX.value <= LEFT_THRESHOLD && !isOneRemoved.value) {
isOneRemoved.value = true;
emit('move-left');
emit('show-purification');
}
// 向右移动清除two
if (trashCanOffsetX.value >= RIGHT_THRESHOLD && !isTwoRemoved.value) {
isTwoRemoved.value = true;
emit('move-right');
emit('show-purification');
}
};
// 监听清除状态变化
watch([isOneRemoved, isTwoRemoved], ([oneRemoved, twoRemoved]) => {
if (oneRemoved && twoRemoved) {
emit('all-cleared');
}
});
</script>
<template>
<view class="garbage-cleanup">
<view class="content">
<view class="cleartitle">清理垃圾</view>
<view class="clearContent">
<view class="clearItem">
<!-- one垃圾图片 -->
<image
class="item one"
:class="{ removed: isOneRemoved }"
:src="ASSETS.rubbishOne"
mode="aspectFill"
></image>
<image class="item itemArrow" :src="ASSETS.arrowLeft" mode="aspectFill"></image>
<!-- 垃圾桶 -->
<image
class="item trashCan"
:class="{ enlarged: isTrashCanEnlarged }"
:style="{ transform: isTrashCanEnlarged ? `translateX(${trashCanOffsetX}rpx) scale(1.2)` : `translateX(${trashCanOffsetX}rpx)` }"
@touchstart="onTrashCanTouchStart"
@touchmove="onTrashCanTouchMove"
@touchend="onTrashCanTouchEnd"
:src="ASSETS.trashCan"
mode="aspectFill"
></image>
<image class="item itemArrow" :src="ASSETS.arrowRight" mode="aspectFill"></image>
<!-- two垃圾图片 -->
<image
class="item two"
:class="{ removed: isTwoRemoved }"
:src="ASSETS.rubbishTwo"
mode="aspectFill"
></image>
</view>
</view>
</view>
</view>
</template>
<style scoped lang="scss">
.garbage-cleanup {
.content {
width: 100%;
margin-top: 148rpx;
.cleartitle {
margin: 0 auto;
width: 240rpx;
padding: 5rpx 0 15rpx;
text-align: center;
font-size: 40rpx;
color: #FFFFFF;
font-weight: 600;
background: #376069;
border: 2rpx solid #ffffff;
border-radius: 34rpx;
}
.clearContent {
background: #ffffff8f;
border: 4rpx dashed #376069;
border-radius: 32rpx;
width: 558rpx;
height: 166rpx;
margin: 30rpx auto;
position: relative;
.clearItem {
display: flex;
align-items: center;
justify-content: space-between;
padding: 34rpx 32rpx;
position: relative;
.item {
transition: all 0.3s ease;
position: relative;
z-index: 2;
}
.one {
width: 108rpx;
height: 106rpx;
opacity: 1;
transition: opacity 0.5s ease;
&.removed {
opacity: 0;
transform: scale(0.8);
}
}
.two {
width: 98rpx;
height: 106rpx;
opacity: 1;
transition: opacity 0.5s ease;
&.removed {
opacity: 0;
transform: scale(0.8);
}
}
.trashCan {
width: 100rpx;
height: 110rpx;
z-index: 10;
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
&.enlarged {
/* transform removed */
}
}
.itemArrow {
width: 70rpx;
height: 50rpx;
}
}
}
}
}
</style>
<script setup>
import { ref, watch, defineEmits } from 'vue';
// 定义组件事件
const emit = defineEmits(['stage-complete']);
const ASSETS = Object.freeze({
hand: '/static/first/hand.png',
purificationValue: '/static/first/purificationValue.png',
});
// 进度相关状态
const progressPercentage = ref(0); // 进度百分比 0-100
const hintPosition = ref(0); // hint位置百分比
// 触摸相关状态
const isDragging = ref(false);
const touchStartX = ref(0);
const hintStartPosition = ref(0);
// 净化值显示状态
const showPurificationValue = ref(false);
const hasShownAt50 = ref(false); // 是否已经在50%显示过一次
const isCompleted = ref(false); // 是否已经完成
// 触摸开始
const onHintTouchStart = (e) => {
if (isCompleted.value) return; // 如果已完成,不再响应触摸
isDragging.value = true;
touchStartX.value = e.touches[0].clientX;
hintStartPosition.value = hintPosition.value;
};
// 触摸移动
const onHintTouchMove = (e) => {
if (!isDragging.value || isCompleted.value) return;
const touchX = e.touches[0].clientX;
const screenWidth = uni.getSystemInfoSync().windowWidth;
// 计算移动距离(百分比)
const deltaX = touchX - touchStartX.value;
const deltaPercentage = (deltaX / screenWidth) * 100;
// 计算新的位置
let newPosition = hintStartPosition.value + deltaPercentage;
// 限制在0-100%范围内
if (newPosition < 0) {
newPosition = 0;
} else if (newPosition > 100) {
newPosition = 100;
}
// 更新位置
hintPosition.value = newPosition;
// 更新进度(进度跟随hint位置)
progressPercentage.value = newPosition;
// 检查进度并触发净化值显示
checkProgressForPurification();
};
// 触摸结束
const onHintTouchEnd = () => {
isDragging.value = false;
// 如果未完成,可以添加自动回弹效果
if (progressPercentage.value < 100 && !isCompleted.value) {
// 可选:自动回弹到当前位置的附近
// setTimeout(() => {
// hintPosition.value = progressPercentage.value
// }, 100)
}
};
// 检查进度并触发净化值显示
const checkProgressForPurification = () => {
const progress = progressPercentage.value;
// 达到50%时显示净化值
if (progress >= 50 && progress < 51 && !hasShownAt50.value) {
showPurificationValueEffect();
hasShownAt50.value = true;
}
// 达到100%时再次显示净化值并触发完成事件
if (progress >= 100 && progress < 101 && !isCompleted.value) {
isCompleted.value = true;
showPurificationValueEffect();
// 触发完成事件
emit('stage-complete');
// 完成时的额外处理
setTimeout(() => {
uni.showToast({
title: '油膜分离完成!',
icon: 'success',
duration: 2000,
});
}, 1000);
}
};
// 显示净化值效果
const showPurificationValueEffect = () => {
showPurificationValue.value = true;
// 3秒后隐藏净化值
setTimeout(() => {
showPurificationValue.value = false;
}, 3000);
};
// 监听进度变化(可选)
watch(progressPercentage, (newValue) => {
// 如果进度减少到50%以下,重置标志
if (newValue < 50) {
hasShownAt50.value = false;
}
});
</script>
<template>
<view class="oil-film-separation">
<!-- 主内容区域 -->
<view class="content">
<view class="gameTitle">油膜分离区</view>
<view class="gameContent">
<!-- 进度条背景 -->
<view class="progressBar">
<!-- 填充的进度 -->
<view
class="progressFill"
:style="{ width: `${progressPercentage}%` }"
>
<!-- 斜杠图案层 -->
<view class="diagonalPattern"></view>
<!-- 渐变颜色层 -->
<view class="gradientLayer"></view>
</view>
<!-- 进度条边框 -->
<view class="progressBorder"></view>
</view>
<!-- 拖动提示区域(hint) -->
<view
class="hint"
:style="{ left: `${hintPosition}%` }"
@touchstart="onHintTouchStart"
@touchmove="onHintTouchMove"
@touchend="onHintTouchEnd"
>
<!-- 拖动手柄 -->
<view class="hintHandle"></view>
</view>
</view>
</view>
<!-- 净化值显示区域 -->
<view class="purificationValue" :class="{ show: showPurificationValue }">
<image
class="purificationValueImg"
:src="ASSETS.purificationValue"
mode="aspectFill"
></image>
</view>
</view>
</template>
<style scoped lang="scss">
.oil-film-separation {
width: 100%;
.content {
width: 100%;
margin-top: 150rpx;
.gameTitle {
margin: 0 auto;
width: 240rpx;
padding: 5rpx 0 15rpx;
text-align: center;
font-size: 40rpx;
color: #FFFFFF;
font-weight: 600;
background: #376069;
border: 2rpx solid #ffffff;
border-radius: 34rpx;
}
.gameContent {
position: relative;
width: 566rpx;
height: 200rpx;
margin: 62rpx auto 0;
// 进度条容器
.progressBar {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 100%;
height: 52rpx;
// 进度条边框(背景)
.progressBorder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #376069;
border: 4rpx solid #FFF;
border-radius: 80rpx;
z-index: 1;
}
// 进度条填充
.progressFill {
position: absolute;
top: 8rpx;
left: 4rpx;
height: 44rpx;
border-radius: 76rpx;
transition: width 0.1s ease;
z-index: 2;
overflow: hidden; // 确保子元素不会超出边界
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2);
// 斜杠图案层
.diagonalPattern {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: repeating-linear-gradient(
135deg,
// 135度斜角
rgba(255, 255, 255, 0.15) 0,
// 斜杠颜色和透明度
rgba(255, 255, 255, 0.15) 12rpx,
// 斜杠宽度
transparent 6rpx,
// 斜杠结束
transparent 30rpx // 斜杠间隔
);
z-index: 1;
animation: patternMove 3s linear infinite; // 添加动画效果
}
// 渐变颜色层
.gradientLayer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, #9C83E5 0%, #45AAE8 36.54%, #5AC3D0 61.06%, #EBDB66 87.98%);
z-index: 0;
}
}
}
// hint拖动区域
.hint {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 34rpx;
height: 88rpx;
z-index: 10;
touch-action: none; // 防止页面滚动
// hint手柄
.hintHandle {
position: relative;
width: 100%;
height: 100%;
background: #D5E9FC;
border: 4rpx solid #376069;
border-radius: 28rpx;
box-shadow: 4rpx 4rpx 8rpx 0 #FFF inset;
cursor: pointer;
z-index: 11;
&:active {
background: #b8d5f8;
transform: scale(0.95);
}
}
// 添加拖动指示
&::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
width: 4rpx;
height: 20rpx;
background: #376069;
border-radius: 2rpx;
z-index: 1;
}
}
}
}
// 净化值显示区域
.purificationValue {
position: absolute;
top: 66%;
left: 35%;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
z-index: 100;
pointer-events: none;
&.show {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
.purificationValueImg {
width: 368rpx;
height: 362rpx;
filter: drop-shadow(0 10rpx 20rpx rgba(0, 0, 0, 0.3));
animation: float 3s ease-in-out infinite;
}
}
}
// 漂浮动画
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-20rpx);
}
}
// 斜杠图案移动动画
@keyframes patternMove {
0% {
background-position: 0 0;
}
100% {
background-position: 24rpx 24rpx; // 移动距离等于斜杠间隔的两倍
}
}
// 添加拖动时的动画效果
.hint:active {
.hintHandle {
animation: pulse 0.5s ease-in-out infinite alternate;
}
}
@keyframes pulse {
from {
box-shadow: 4rpx 4rpx 8rpx 0 #FFF inset, 0 0 0 rgba(157, 131, 229, 0.4);
}
to {
box-shadow: 4rpx 4rpx 8rpx 0 #FFF inset, 0 0 20rpx rgba(157, 131, 229, 0.8);
}
}
</style>
<script setup>
import { ref, computed } from 'vue';
// 定义emit事件
const emit = defineEmits(['complete']);
const ASSETS = Object.freeze({
reagents: '/static/first/reagents.png',
reagentsOne: '/static/first/reagentsOne.png',
reagentsTwo: '/static/first/reagentsTwo.png',
reagentsThree: '/static/first/reagentsThree.png',
});
// 区域位置数组
const areaPositions = ['22px', '110px', '202px'];
// 当前显示的图片
const currentImage = ref(ASSETS.reagents);
// 当前悬停的区域 (0表示没有悬停,1,2,3分别对应三个区域)
const hoverArea = ref(0);
// 是否已选择区域
const isSelected = ref(false);
// 图片映射关系
const imageMap = {
1: ASSETS.reagentsOne,
2: ASSETS.reagentsTwo,
3: ASSETS.reagentsThree,
};
// 计算图片样式
const imageStyle = computed(() => {
if (currentImage.value === ASSETS.reagents) {
return {
width: '422rpx',
height: '134rpx',
};
} else {
return {
width: '444rpx',
height: '148rpx',
};
}
});
// 是否选中了正确的试剂
const isCorrectSelected = computed(() => {
return currentImage.value === ASSETS.reagentsOne;
});
// 选择区域
const selectArea = (areaIndex) => {
// 如果已经选中了正确的试剂,则不再响应点击
if (isCorrectSelected.value) return;
if (isSelected.value) return;
isSelected.value = true;
currentImage.value = imageMap[areaIndex];
// 选择后清空悬停状态
hoverArea.value = 0;
// 如果选择了第一个区域(正确的试剂),则触发完成事件
if (areaIndex === 1) {
emit('stage-complete', { selectedIndex: areaIndex, isCorrect: true });
} else {
// 选择错误的试剂,显示提示
uni.showToast({
title: '这不是正确的试剂,请重新选择',
icon: 'none',
duration: 2000,
});
// 2秒后重置选择
setTimeout(() => {
resetSelection();
}, 2000);
}
};
// 重置选择
const resetSelection = () => {
isSelected.value = false;
currentImage.value = ASSETS.reagents;
hoverArea.value = 0;
};
// 暴露重置方法给父组件
defineExpose({
resetSelection,
});
</script>
<template>
<view class="container">
<view class="content">
<view class="gameContent">
<view class="hint">
<!-- 显示当前选中的图片 -->
<image :src="currentImage" :style="imageStyle" mode="scaleToFill" />
<!-- 三个可点击区域 -->
<view
class="click-area"
v-for="i in 3"
:key="i"
:class="{ active: hoverArea === i && !isSelected }"
:style="{ left: areaPositions[i - 1], pointerEvents: isCorrectSelected ? 'none' : 'auto' }"
@click="selectArea(i)"
></view>
</view>
</view>
<view class="textTips">
<view class="text">
当前<br />
经检测该河流呈酸性<br />
请选择合适的试剂进行中和
</view>
</view>
</view>
</view>
</template>
<style scoped lang="scss">
.container {
width: 100%;
min-height: 100vh;
position: relative;
touch-action: none;
.content {
.gameContent {
background: #ffffff8f;
border: 4rpx dashed #376069;
border-radius: 32rpx;
width: 558rpx;
height: 196rpx;
margin: 30rpx auto;
position: relative;
.hint {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
.click-area {
position: absolute;
width: 130rpx;
height: 144rpx;
border-radius: 12rpx;
background: transparent;
z-index: 10;
&.active {
background: rgba(48, 195, 57, 0.3);
border: 2rpx solid #30C339;
box-shadow: 0 0 20rpx rgba(48, 195, 57, 0.5);
transition: all 0.2s ease;
}
}
}
}
.textTips {
border-radius: 24rpx;
border: 2rpx solid #FFF;
background: #F0F9FC;
box-shadow: 0 0 39.6rpx 0 #C8EEFF inset;
width: 520rpx;
height: 196rpx;
position: fixed;
bottom: 320rpx;
left: 15%;
pointer-events: none;
.text {
color: #2D4B5D;
text-align: center;
font-size: 36rpx;
font-weight: 600;
margin-top: 20rpx;
}
}
}
}
</style>
...@@ -32,7 +32,7 @@ const IMAGES = { ...@@ -32,7 +32,7 @@ const IMAGES = {
tabActiveTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b91478ab6f2d4c2186a948ae9b614f45Group%20348447426.webp', tabActiveTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b91478ab6f2d4c2186a948ae9b614f45Group%20348447426.webp',
tabActivePh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b9c5667e95ea48a1b4c10f2d9ee84db6Group%20348447426.webp', tabActivePh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b9c5667e95ea48a1b4c10f2d9ee84db6Group%20348447426.webp',
tabInactiveTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/a4bd654c5fd4401bb4d09ce1a8e08aa3Group%20348447427.webp', tabInactiveTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/a4bd654c5fd4401bb4d09ce1a8e08aa3Group%20348447427.webp',
tabInactivePh: '/static/1.webp', tabInactivePh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/023189e7e11545e6bd49c1f37d9a1478iHA7EcKejNiNbde90471ce05a5bbbc559a25533ed83d.webp',
// 介绍内部图片 // 介绍内部图片
instructionTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/1a62746fad3743d19f01e8b612ed8d42Group%20348447435.webp', instructionTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/1a62746fad3743d19f01e8b612ed8d42Group%20348447435.webp',
instructionPh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/32ac38db03994072aca53ae518b996eeGroup%20348447450.webp', instructionPh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/32ac38db03994072aca53ae518b996eeGroup%20348447450.webp',
......
## 安吉尔小游戏 ## 安吉尔小游戏
...@@ -4,6 +4,39 @@ ...@@ -4,6 +4,39 @@
- https://codesign.qq.com/s/642835417449801 - https://codesign.qq.com/s/642835417449801
- 密码:UDKM - 密码:UDKM
#### 徽章切图地址
-徽章1
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/672e8e6fbd5444c884675dde50c446a5Y2af2XVB0T-Jb7e73ab2397ffdb37f2b5c132dc584da.webp
-徽章1灰色
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/a155a0a5c619418b90e656792e2a0d1114pNJPNn64ss4e6fe0a34a2c181ecffb4ba77bace4f2.webp
-徽章2
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/cd584ad7bc204aaa92e22b7d6294d752J4r8jf1sLeDBe39016508c55312b7a0d6d0ab378c691.webp
-徽章2灰色
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/d495a86e446046faabfdea09d84a44d1fGL8pw_2cHR4a4d071d2ed6d75cd0227298ef969a4d9.webp
-徽章3
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/252505de8901440b89c01ceae8ba92735cwiy47_s9O92237a043d60f2620a390cd3980a7f3c6.webp
-徽章3灰色
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/22ff15d76d144306909f94c4029670abiCgKOBoreJ-1bcbb00df1ba5682386e031ccedc3c6cb.webp
-徽章4
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/10c6937c832d498f8e9d7e0a975263329nC4ASG9gQBka44a97e514fdb44b775b49e72d9aefbc.webp
-徽章4灰色
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/018385573cde45eb927283dbb8e6468acj8h_7C-hy9v38ef8079391af2ddb8785bfb0ee8f041.webp
-徽章5
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/b926e4cd469b4400bc19ba9ed6798e88XwyB9JqUSWXGcf436811eae73ba6229615399dab16aa.webp
-徽章5灰色
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/498cf3a935334fa09f0b0d45ee300795QSZy9n9Y6yBR8b4fabffd32f8517af6ba129810be346.webp
-空白展示
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/d7873615505b400abd996b7498aaa4b6wcS02B18DXFm131a1e3b221f4a5853c94500ebbe1dbf.webp
-展示1
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/d8b5013e03ed435e87df67f23a336c5004LqofmY2_AB12cc8ce7b029bc417ca372f0adf99357.webp
-展示2
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/429f24ee65ea41a08375e52561163383fHpZ7I1MpNm6dd4ee291f5836d1f4c2d2dfc18ac3af7.webp
-展示3
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/e7415cd5630e4d0e8c7526fc3b5432daZVjP7LzdCneu558949671d27a4a9165a4b04038e17dc.webp
-展示4
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/cdb8a5aa5d884b15b3b3df5ab467603aRlgBB7VFxdiZe002226923227b90a51c8e269b34a785.webp
-展示5
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/68240835222e4fdf95dce8759ea7effd89x90XC2gyYK04083bca99804e8496bbe94a90d090ab.webp
#### 第一关切图地址 #### 第一关切图地址
- 暂无 - 暂无
#### 第二关切图地址 #### 第二关切图地址
...@@ -44,6 +77,7 @@ ...@@ -44,6 +77,7 @@
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b9c5667e95ea48a1b4c10f2d9ee84db6Group%20348447426.webp - https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b9c5667e95ea48a1b4c10f2d9ee84db6Group%20348447426.webp
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/51e1fc432e2b406d9d00f1028213221bGroup%20348447439.webp - https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/51e1fc432e2b406d9d00f1028213221bGroup%20348447439.webp
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/f8df9974d93a478f8c6b760fd32e15aaGroup%20348447439.webp - https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/f8df9974d93a478f8c6b760fd32e15aaGroup%20348447439.webp
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-02-26/023189e7e11545e6bd49c1f37d9a1478iHA7EcKejNiNbde90471ce05a5bbbc559a25533ed83d.webp
- 灯泡 - 灯泡
- https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d2a7b1b81bff44c2b9099a8d48d9d6f1Frame%282%29.webp - https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d2a7b1b81bff44c2b9099a8d48d9d6f1Frame%282%29.webp
- 标签 - 标签
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment