Commit b521a783 by Hantao

完成第二关的part2

parent 70741af1
...@@ -3,7 +3,31 @@ ...@@ -3,7 +3,31 @@
{ {
"path": "pages/index/index", "path": "pages/index/index",
"style": { "style": {
"navigationBarTitleText": "uni-app" "navigationStyle": "custom"
}
},
{
"path": "pages/start/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/second/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/second/part1",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/second/part2",
"style": {
"navigationStyle": "custom"
} }
}, },
{ {
......
import { ref, onMounted, onUnmounted } from 'vue';
export function useProgress() {
const progress = ref(0);
const isPaused = ref(false);
// 速度控制参数
const speed = ref(50); // 速度滑块值 (0-100)
const targetFPS = ref(60); // 目标帧率 (FPS)
let lastTime = 0;
let animationTimer = null;
const updateProgress = () => {
if (isPaused.value || progress.value >= 100) {
return;
}
const now = Date.now();
const interval = 1000 / targetFPS.value;
const elapsed = now - lastTime;
if (elapsed > interval) {
// 基础速度:speed 值为 50 时,每秒约增加 10%
const increment = (speed.value / 100) * (elapsed / 1000) * 20;
progress.value = Math.min(progress.value + increment, 100);
lastTime = now - (elapsed % interval);
}
animationTimer = setTimeout(updateProgress, interval);
};
const start = () => {
progress.value = 0;
isPaused.value = false;
lastTime = Date.now();
if (animationTimer) clearTimeout(animationTimer);
updateProgress();
};
// 暂停/继续控制
const togglePause = () => {
isPaused.value = !isPaused.value;
if (!isPaused.value) {
lastTime = Date.now();
updateProgress();
}
};
// 设置速度
const setSpeed = (value) => {
speed.value = Math.max(0, Math.min(100, value));
};
// 设置FPS
const setFPS = (value) => {
targetFPS.value = Math.max(1, Math.min(120, value));
};
onUnmounted(() => {
if (animationTimer) clearTimeout(animationTimer);
});
return {
progress,
isPaused,
speed,
targetFPS,
start,
togglePause,
setSpeed,
setFPS
};
}
<script setup>
import { onMounted, watch } from 'vue';
import { useProgress } from './hook/speed';
// 图片路径
const ASSETS = {
bg: '/static/shouping/bg.webp',
logo: '/static/shouping/logo.webp',
title: '/static/shouping/title.webp',
water: '/static/shouping/water.webp',
};
const { progress, start } = useProgress();
watch(progress, (newVal) => {
if (newVal >= 100) {
setTimeout(handleNavigation, 1000);
}
});
const handleNavigation = () => {
uni.reLaunch({
url: '/pages/start/index',
fail: (err) => {
console.error('Navigation failed:', err);
uni.showToast({
title: '页面跳转失败,请重试',
icon: 'none',
duration: 2000
});
}
});
};
onMounted(() => {
start();
});
</script>
<template> <template>
<view class="content"> <view class="landing-container">
<image class="logo" src="/static/logo.png"></image> <!-- 背景图片 -->
<view class="text-area"> <image class="bg-image" :src="ASSETS.bg" mode="scaleToFill" />
<text class="title">{{title}}</text>
</view> <!-- 内容区域 -->
</view> <view class="content-wrapper">
<!-- Logo -->
<view class="logo-box">
<image class="logo-img" :src="ASSETS.logo" mode="widthFix" />
</view>
<!-- 标题 -->
<view class="title-box">
<image class="title-img" :src="ASSETS.title" mode="widthFix" />
</view>
<!-- 进度条区域 -->
<view class="progress-section">
<view class="progress-track">
<view class="progress-bar" :style="{ width: `${progress}%` }">
<view class="water-drop-wrapper">
<image class="water-drop" :src="ASSETS.water" mode="widthFix" />
</view>
</view>
</view>
<view class="loading-info">
<text class="loading-text">加载资源中 {{ Math.floor(progress) }}%</text>
</view>
</view>
</view>
</view>
</template> </template>
<script> <style scoped lang="scss">
export default { .landing-container {
data() { position: relative;
return { width: 100vw;
title: 'Hello' height: 100vh;
} overflow: hidden;
}, display: flex;
onLoad() { flex-direction: column;
}
}, .bg-image {
methods: { position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
} .content-wrapper {
} position: relative;
</script> z-index: 1;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 15vh;
}
.logo-box {
margin-bottom: 40rpx;
.logo-img {
width: 280rpx;
height: auto;
}
}
.title-box {
margin-bottom: 100rpx;
display: flex;
justify-content: center;
.title-img {
width: 600rpx;
height: auto;
}
}
.progress-section {
width: 600rpx;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 3vh;
margin-bottom: 25vh;
.progress-track {
width: 100%;
height: 40rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 20rpx;
position: relative;
border: 2rpx solid #000;
box-sizing: border-box;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #2facff 0%, #6cd9ff 100%);
border-radius: 18rpx;
position: relative;
transition: width 0.1s linear;
.water-drop-wrapper {
position: absolute;
right: -18rpx;
top: 50%;
transform: translateY(-50%);
width: 60rpx;
height: 60rpx;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
}
.water-drop {
width: 48rpx;
height: 48rpx;
filter: drop-shadow(0 2rpx 4rpx rgba(0,0,0,0.2));
}
}
<style> .loading-text {
.content { margin-top: 20rpx;
display: flex; font-size: 28rpx;
flex-direction: column; color: #333;
align-items: center; font-weight: 600;
justify-content: center; letter-spacing: 2rpx;
} text-shadow: 0 2rpx 0 rgba(255,255,255,0.5);
}
.logo { }
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style> </style>
<script setup>
const ASSETS = {
bg: '/static/second/bg.webp',
info: '/static/second/info.webp',
title: '/static/second/title.webp',
jdt: '/static/second/jdt.webp',
next: '/static/second/next.webp',
};
const handleNext = () => {
uni.navigateTo({
url: '/pages/second/part1'
});
};
</script>
<template>
<view class="container">
<!-- 主体内容 -->
<view class="main-content">
<!-- 背景 -->
<image class="bg-img" :src="ASSETS.bg" mode="aspectFill" />
<!-- 标题 -->
<view class="title-area">
<image class="title-img" :src="ASSETS.title" mode="widthFix" />
</view>
<!-- 右侧信息区域 -->
<view class="info-area">
<image class="info-img" :src="ASSETS.info" mode="scaleToFill" />
</view>
<!-- 底部区域 -->
<view class="bottom-area">
<image class="progress-bar" :src="ASSETS.jdt" mode="scaleToFill" />
<view class="next-btn-wrapper" @click="handleNext">
<image class="next-btn" :src="ASSETS.next" mode="scaleToFill" />
</view>
</view>
</view>
</view>
</template>
<style scoped lang="scss">
.container {
width: 100vw;
height: 100vh;
position: relative;
overflow: hidden;
}
.main-content {
width: 100%;
height: 100%;
position: relative;
}
.bg-img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.title-area {
position: absolute;
top: 7vh;
left: 0;
width: 100%;
display: flex;
justify-content: center;
z-index: 10;
.title-img {
width: 240rpx;
height: auto;
}
}
.info-area {
position: absolute;
top: 48%;
right: 22rpx;
transform: translateY(-45%);
z-index: 10;
display: flex;
justify-content: flex-end;
.info-img {
width: 440rpx;
height: 780rpx;
}
}
.bottom-area {
position: absolute;
bottom: 0;
width: 100%;
height: 180rpx;
padding: 40rpx;
padding-bottom: calc(40rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
z-index: 20;
background: linear-gradient(180deg, #73D8FF 0%, #3498F4 100%);
border-radius: 40rpx 40rpx 0 0;
border-top: 4rpx solid #CCECFD;
.progress-bar {
position: absolute;
left: 40rpx;
top: 50%;
transform: translateY(-50%);
width: 428rpx;
height: 56rpx;
}
.next-btn-wrapper {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
width: 230rpx;
height: 72px;
transition: transform 0.2s ease;
align-self: auto;
margin: 0;
.next-btn {
width: 100%;
height: 100%;
}
}
}
@media screen and (min-width: 768px) {
.title-area {
top: 10vh;
.title-img {
width: 20vw;
}
}
.info-area {
right: 10vw;
.info-img {
width: 440rpx;
height: 740rpx;
}
}
.bottom-area {
bottom: 10vh;
.progress-bar {
width: 30vw;
}
.next-btn-wrapper {
right: 10vw;
.next-btn {
width: 15vw;
}
}
}
}
</style>
<script setup>
const ASSETS = {
title: '/static/second/part1/title.webp',
center: '/static/second/part1/center.webp',
zzjd: '/static/second/zzjd1.webp',
panzi: '/static/second/panzi.webp',
resetIcon: '/static/second/reset.webp',
blockIcon: '/static/second/block.webp',
arrow: '/static/second/jt.webp',
};
</script>
<template>
<view class="part1-container">
<!-- 顶部标题 -->
<view class="header-section">
<image class="title-img" :src="ASSETS.title" mode="widthFix" />
</view>
<!-- 主体区域 -->
<view class="main-area">
<!-- 中间拼图区域 -->
<view class="center-wrapper">
<image class="center-img" :src="ASSETS.center" mode="widthFix" />
</view>
<!-- 右侧进度条 -->
<view class="progress-wrapper">
<text class="progress-title">组装进度</text>
<image class="progress-img" :src="ASSETS.zzjd" mode="scaleToFill" />
</view>
</view>
<!-- 下方托盘区域 -->
<view class="tray-area">
<image class="tray-img" :src="ASSETS.panzi" mode="scaleToFill" />
</view>
<!-- 底部按钮 -->
<view class="btn-group">
<view class="action-btn reset-btn" @click="handleReset">
<image class="btn-icon" :src="ASSETS.resetIcon" mode="widthFix" />
<text>重置</text>
</view>
<view class="action-btn complete-btn" @click="handleComplete">
<image class="btn-icon block-icon" :src="ASSETS.blockIcon" mode="widthFix" />
<view class="btn-text-col">
<text class="main-text">完成</text>
<text class="sub-text">完成0/6吸附</text>
</view>
</view>
</view>
<image class="arrow-icon" :src="ASSETS.arrow" mode="scaleToFill" />
</view>
</template>
<style scoped lang="scss">
.part1-container {
width: 100vw;
height: 100vh;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
background-color: #77CFF8;
box-sizing: border-box;
}
.header-section {
margin-top: 200rpx;
z-index: 10;
flex-shrink: 0;
.title-img {
width: 344rpx;
height: auto;
}
}
.main-area {
width: 100%;
position: relative;
display: flex;
justify-content: center;
align-items: flex-start;
margin-top: 60rpx;
flex-shrink: 0;
}
.center-wrapper {
position: relative;
margin-left: -130rpx;
.center-img {
width: 580rpx;
height: auto;
}
}
.progress-wrapper {
position: absolute;
right: 20rpx;
top: -28rpx;
display: flex;
flex-direction: column;
align-items: center;
.progress-title {
font-size: 32rpx;
color: #000;
margin-bottom: 24rpx;
font-weight: 600;
}
.progress-img {
width: 94rpx;
height: 548rpx;
}
}
.tray-area {
width: 88%;
display: flex;
justify-content: center;
margin-top: 44rpx;
margin-bottom: 20rpx;
position: relative;
z-index: 10;
flex-shrink: 0;
.tray-img {
width: 100%;
height: 466rpx;
}
}
.btn-group {
display: flex;
justify-content: center;
gap: 80rpx;
margin-top: 20rpx;
margin-bottom: 60rpx;
z-index: 20;
flex-shrink: 0;
.action-btn {
display: flex;
justify-content: center;
align-items: center;
border-radius: 42rpx;
height: 84rpx;
box-sizing: border-box;
}
.reset-btn {
width: 230rpx;
background: #BAC4CA;
box-shadow: 0 6rpx 2rpx 0 #529bbda6, 0 4rpx 4rpx 0 #ffffff8c inset;
border: 2rpx solid #000000;
color: #5E5C5C;
font-size: 34rpx;
font-weight: bold;
.btn-icon {
width: 44rpx;
height: 44rpx;
margin-right: 10rpx;
}
}
.complete-btn {
width: 250rpx;
background: #5EB6F0;
border: 2rpx solid #000000;
box-shadow: 0 6rpx 2rpx 0 #529bbda6, 0 4rpx 2rpx 0 #76DDEE inset;
color: #134571;
.block-icon {
width: 44rpx;
height: auto;
margin-right: 16rpx;
}
.btn-text-col {
display: flex;
flex-direction: column;
align-items: flex-start;
.main-text {
font-size: 32rpx;
font-weight: bold;
line-height: 1;
margin-bottom: 4rpx;
margin-left: 20rpx;
}
.sub-text {
font-size: 20rpx;
line-height: 1;
}
}
}
}
.arrow-icon {
position: absolute;
top: 48%;
left: 62%;
width: 116rpx;
height: 144rpx;
z-index: 100;
}
</style>
<script setup>
import { ref } from 'vue';
// 图片路径
const ASSETS = {
bg: '/static/start/bg.webp',
title: '/static/start/title.webp',
startBtn: '/static/start/start.webp',
restartBtn: '/static/start/restart.webp',
progress: '/static/start/yxjd.webp',
top: '/static/start/top.webp',
bottom: '/static/start/bottom.webp',
sidebarIcon: '/static/start/cbl.webp',
sidebarMenu: '/static/start/all.webp',
};
// 侧边栏状态
const isSidebarExpanded = ref(false);
const handleStart = () => {
};
const handleRestart = () => {
};
const toggleSidebar = () => {
isSidebarExpanded.value = !isSidebarExpanded.value;
};
const closeSidebar = () => {
if (isSidebarExpanded.value) {
isSidebarExpanded.value = false;
}
};
</script>
<template>
<view class="start-container" @click="closeSidebar">
<!-- 背景 -->
<image class="bg-image" :src="ASSETS.bg" mode="scaleToFill" />
<!-- 顶部用户信息 -->
<view class="top-section">
<image class="top-info" :src="ASSETS.top" mode="widthFix" />
</view>
<!-- 主要内容 -->
<view class="content-wrapper">
<!-- 标题 -->
<view class="title-box">
<image class="title-img" :src="ASSETS.title" mode="widthFix" />
</view>
<!-- 游戏进度展示 -->
<view class="progress-box">
<image class="progress-img" :src="ASSETS.progress" mode="widthFix" />
</view>
<!-- 按钮区域 -->
<view class="btn-group">
<view class="btn-item" @click="handleStart">
<image class="btn-img start-btn" :src="ASSETS.startBtn" mode="widthFix" />
</view>
<view class="btn-item" @click="handleRestart">
<image class="btn-img restart-btn" :src="ASSETS.restartBtn" mode="widthFix" />
</view>
</view>
</view>
<!-- 侧边栏 -->
<view class="sidebar-container" :class="{ expanded: isSidebarExpanded }">
<view class="sidebar-wrapper" @click.stop="toggleSidebar">
<image
v-if="!isSidebarExpanded"
class="sidebar-icon"
:src="ASSETS.sidebarIcon"
mode="heightFix"
/>
<image
v-else
class="sidebar-menu"
:src="ASSETS.sidebarMenu"
mode="heightFix"
/>
</view>
</view>
<image class="bottom-decoration" :src="ASSETS.bottom" mode="widthFix" />
</view>
</template>
<style scoped lang="scss">
.start-container {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.top-section {
position: relative;
z-index: 1;
width: 95%;
padding-top: 162rpx;
padding-left: 20rpx;
padding-right: 20rpx;
box-sizing: border-box;
display: flex;
justify-content: center;
.top-info {
width: 100%;
height: auto;
}
}
.bottom-decoration {
position: absolute;
bottom: 90rpx;
left: 40rpx;
width: 90%;
z-index: 1;
}
.content-wrapper {
position: relative;
z-index: 2;
width: 100%;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 40rpx;
}
.title-box {
.title-img {
width: 500rpx;
height: auto;
animation: bounceIn 1s ease-out;
}
}
.progress-box {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
margin-top: -40rpx;
position: relative;
z-index: 5;
.progress-img {
width: 100%;
height: auto;
}
}
.btn-group {
display: flex;
flex-direction: column;
align-items: center;
gap: 30rpx;
margin-top: -60rpx;
position: relative;
z-index: 10;
}
.btn-item {
transition: transform 0.1s;
&:active {
transform: scale(0.95);
}
.btn-img {
height: auto;
}
.start-btn {
width: 380rpx;
}
.restart-btn {
width: 300rpx;
}
}
.sidebar-container {
position: absolute;
right: 0;
top: 408rpx;
z-index: 20;
display: flex;
justify-content: flex-end;
&.expanded {
top: 408rpx;
}
.sidebar-wrapper {
display: flex;
justify-content: flex-end;
}
.sidebar-icon {
width: auto;
height: 700rpx;
}
.sidebar-menu {
width: auto;
height: 700rpx;
animation: slideInRight 0.3s ease-out;
}
}
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes bounceIn {
0% {
transform: scale(0.5);
opacity: 0;
}
60% {
transform: scale(1.05);
opacity: 1;
}
100% {
transform: scale(1);
}
}
</style>
\ No newline at end of file
<template>
<view class="bottom-bar">
<image :src="IMAGES.testing"
style="width:0;height:0;opacity:0;position:absolute;pointer-events:none;"></image>
<image class="bar-bg" :src="IMAGES.background" mode="scaleToFill"></image>
<text class="test-status">当前测试: <text class="highlight">{{ statusText }}</text></text>
<view class="start-btn-wrapper" @click="handleStartTest" :class="{ 'disabled': isDisabled }">
<image class="start-btn-img" :src="btnImage" mode="scaleToFill"></image>
</view>
</view>
</template>
<script setup> <script setup>
import { computed } from 'vue'; import { computed } from 'vue';
...@@ -87,6 +74,19 @@ const handleStartTest = () => { ...@@ -87,6 +74,19 @@ const handleStartTest = () => {
}; };
</script> </script>
<template>
<view class="bottom-bar">
<image :src="IMAGES.testing"
style="width:0;height:0;opacity:0;position:absolute;pointer-events:none;"></image>
<image class="bar-bg" :src="IMAGES.background" mode="scaleToFill"></image>
<text class="test-status">当前测试: <text class="highlight">{{ statusText }}</text></text>
<view class="start-btn-wrapper" @click="handleStartTest" :class="{ 'disabled': isDisabled }">
<image class="start-btn-img" :src="btnImage" mode="scaleToFill"></image>
</view>
</view>
</template>
<style scoped lang="scss"> <style scoped lang="scss">
.bottom-bar { .bottom-bar {
position: absolute; position: absolute;
......
<script setup>
import { computed } from 'vue';
const props = defineProps({
isTesting: {
type: Boolean,
default: false,
},
isSecondTest: {
type: Boolean,
default: false,
},
});
//烧杯图片
const IMAGES = {
pollutedDefault: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d2729bd9ca6249728c29c66a6e7f1baf%E7%83%A7%E6%9D%AF_%E6%B1%A1%E6%9F%93%E6%B0%B4%E7%89%88%202.webp',
purifiedDefault: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/048d81b1821442c3b80d312e4ef7c1e4%E7%83%A7%E6%9D%AF_%E6%B0%B4%E9%9D%A2%E5%B9%B3%E6%95%B4%E7%89%88%201.webp',
vsIcon: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/8678ceab4c7b41ac80cc1982054c45f4VS.webp',
pollutedPh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/a277ce4fb175493c9cedd60f6aa788d1%E7%83%A7%E6%9D%AF_%E6%9C%AA%E4%BD%BF%E7%94%A8%E9%85%B8%E7%A2%B1%E8%AF%95%E7%BA%B8%201.webp',
pollutedTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d775e2166f2d426f857e69dc3d115d47%E7%83%A7%E6%9D%AF_%E6%97%A0%E6%B0%B4%E6%BB%B4%E5%9B%9B%E8%82%A2_%E5%9B%BE2%201.webp',
purifiedPh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/7b1c0214a1344946908e8de7ddaaea5e%E7%83%A7%E6%9D%AF_%E6%9C%AA%E4%BD%BF%E7%94%A8%E9%85%B8%E7%A2%B1%E8%AF%95%E7%BA%B8_%E5%87%80%E5%8C%96%E6%B0%B4%201.webp',
purifiedTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/c18364684a82445382105028ec6d8f44%E7%83%A7%E6%9D%AF_%E6%97%A0%E6%B0%B4%E6%BB%B4%E5%9B%9B%E8%82%A2_%E5%9B%BE1%201.webp',
};
const pollutedImageTesting = computed(() => {
return props.isSecondTest ? IMAGES.pollutedPh : IMAGES.pollutedTds;
});
const purifiedImageTesting = computed(() => {
return props.isSecondTest ? IMAGES.purifiedPh : IMAGES.purifiedTds;
});
</script>
<template> <template>
<view class="main-content"> <view class="main-content">
<view class="beaker-section"> <view class="beaker-section">
...@@ -42,40 +76,6 @@ ...@@ -42,40 +76,6 @@
</view> </view>
</template> </template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
isTesting: {
type: Boolean,
default: false,
},
isSecondTest: {
type: Boolean,
default: false,
},
});
//烧杯图片
const IMAGES = {
pollutedDefault: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d2729bd9ca6249728c29c66a6e7f1baf%E7%83%A7%E6%9D%AF_%E6%B1%A1%E6%9F%93%E6%B0%B4%E7%89%88%202.webp',
purifiedDefault: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/048d81b1821442c3b80d312e4ef7c1e4%E7%83%A7%E6%9D%AF_%E6%B0%B4%E9%9D%A2%E5%B9%B3%E6%95%B4%E7%89%88%201.webp',
vsIcon: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/8678ceab4c7b41ac80cc1982054c45f4VS.webp',
pollutedPh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/a277ce4fb175493c9cedd60f6aa788d1%E7%83%A7%E6%9D%AF_%E6%9C%AA%E4%BD%BF%E7%94%A8%E9%85%B8%E7%A2%B1%E8%AF%95%E7%BA%B8%201.webp',
pollutedTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d775e2166f2d426f857e69dc3d115d47%E7%83%A7%E6%9D%AF_%E6%97%A0%E6%B0%B4%E6%BB%B4%E5%9B%9B%E8%82%A2_%E5%9B%BE2%201.webp',
purifiedPh: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/7b1c0214a1344946908e8de7ddaaea5e%E7%83%A7%E6%9D%AF_%E6%9C%AA%E4%BD%BF%E7%94%A8%E9%85%B8%E7%A2%B1%E8%AF%95%E7%BA%B8_%E5%87%80%E5%8C%96%E6%B0%B4%201.webp',
purifiedTds: 'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/c18364684a82445382105028ec6d8f44%E7%83%A7%E6%9D%AF_%E6%97%A0%E6%B0%B4%E6%BB%B4%E5%9B%9B%E8%82%A2_%E5%9B%BE1%201.webp',
};
const pollutedImageTesting = computed(() => {
return props.isSecondTest ? IMAGES.pollutedPh : IMAGES.pollutedTds;
});
const purifiedImageTesting = computed(() => {
return props.isSecondTest ? IMAGES.purifiedPh : IMAGES.purifiedTds;
});
</script>
<style scoped lang="scss"> <style scoped lang="scss">
.main-content { .main-content {
flex: 1; flex: 1;
......
<template>
<view class="container">
<image class="bg" :src="assets.bg" mode="aspectFill" />
<view class="header" :style="{ paddingTop: statusBarHeight + 'px' }">
<image class="title" :src="assets.title" mode="heightFix" />
</view>
<Beaker :isTesting="isTesting" :isSecondTest="isSecondTest" />
<view class="bottom-panel">
<TabsInstructionsPanel
:isTesting="isTesting"
:isSecondTest="isSecondTest"
:triggerShowFinalCard="triggerShowFinalCard"
@resultShown="handleResultShown"
@progressFinished="handleProgressFinished"
/>
<BottomActionBar
:isTesting="isTesting"
:isSecondTest="isSecondTest"
:isResultShown="isResultShown"
:isProgressFinished="isProgressFinished"
@startTest="startTest"
@restartTest="restartTest"
@showFinalCard="handleShowFinalCard"
@showCompletionPopup="handleShowCompletion"
/>
</view>
<view class="completion-overlay" v-if="showCompletion" @click="closeCompletion">
<image
class="completion-img"
:src="assets.completionPopup"
mode="scaleToFill"
@click.stop="closeCompletion"
/>
</view>
</view>
</template>
<script setup> <script setup>
import { ref } from 'vue'; import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
...@@ -103,6 +61,48 @@ const closeCompletion = () => { ...@@ -103,6 +61,48 @@ const closeCompletion = () => {
}; };
</script> </script>
<template>
<view class="container">
<image class="bg" :src="assets.bg" mode="aspectFill" />
<view class="header" :style="{ paddingTop: statusBarHeight + 'px' }">
<image class="title" :src="assets.title" mode="heightFix" />
</view>
<Beaker :isTesting="isTesting" :isSecondTest="isSecondTest" />
<view class="bottom-panel">
<TabsInstructionsPanel
:isTesting="isTesting"
:isSecondTest="isSecondTest"
:triggerShowFinalCard="triggerShowFinalCard"
@resultShown="handleResultShown"
@progressFinished="handleProgressFinished"
/>
<BottomActionBar
:isTesting="isTesting"
:isSecondTest="isSecondTest"
:isResultShown="isResultShown"
:isProgressFinished="isProgressFinished"
@startTest="startTest"
@restartTest="restartTest"
@showFinalCard="handleShowFinalCard"
@showCompletionPopup="handleShowCompletion"
/>
</view>
<view class="completion-overlay" v-if="showCompletion" @click="closeCompletion">
<image
class="completion-img"
:src="assets.completionPopup"
mode="scaleToFill"
@click.stop="closeCompletion"
/>
</view>
</view>
</template>
<style lang="scss" scoped> <style lang="scss" scoped>
.container { .container {
width: 100vw; width: 100vw;
......
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