Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
angel-angel-mini-game
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
杜洋
angel-angel-mini-game
Commits
434bda5c
Commit
434bda5c
authored
Jan 24, 2026
by
Hantao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
基本完成第三关
parent
5973401e
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
718 additions
and
31 deletions
+718
-31
BottomActionBar.vue
src/pages/third/components/BottomActionBar.vue
+67
-8
TabsInstructionsPanel.vue
src/pages/third/components/TabsInstructionsPanel.vue
+571
-16
beaker.vue
src/pages/third/components/beaker.vue
+20
-4
index.vue
src/pages/third/index.vue
+60
-3
1.webp
src/static/1.webp
+0
-0
No files found.
src/pages/third/components/BottomActionBar.vue
View file @
434bda5c
...
...
@@ -5,32 +5,91 @@
<image
class=
"bar-bg"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/a681444d883d4fe29851d702703302b0Rectangle%203597.webp"
mode=
"scaleToFill"
></image>
<text
class=
"test-status"
>
当前测试:
<text
class=
"highlight"
>
{{
statusText
}}
</text></text>
<view
class=
"start-btn-wrapper"
@
click=
"handleStartTest"
>
<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
>
import
{
computed
}
from
'vue'
;
import
{
computed
,
ref
,
watch
}
from
'vue'
;
const
props
=
defineProps
({
isTesting
:
{
type
:
Boolean
,
default
:
false
},
isSecondTest
:
{
type
:
Boolean
,
default
:
false
},
isResultShown
:
{
type
:
Boolean
,
default
:
false
},
isProgressFinished
:
{
type
:
Boolean
,
default
:
false
}
});
const
emit
=
defineEmits
([
'startTest'
,
'restartTest'
,
'showFinalCard'
,
'showCompletionPopup'
]);
const
isDisabled
=
ref
(
false
);
const
statusText
=
computed
(()
=>
{
if
(
props
.
isSecondTest
)
return
'2/2'
;
return
props
.
isTesting
?
'1/2'
:
'0/2'
;
});
const
btnImage
=
computed
(()
=>
{
if
(
props
.
isSecondTest
)
{
if
(
props
.
isResultShown
)
{
return
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/f8df9974d93a478f8c6b760fd32e15aaGroup%20348447439.webp'
;
}
if
(
props
.
isTesting
)
{
return
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/5d0f462d13ec4cbcb6eee7080c637897Group%20348447439.webp'
;
}
return
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/51e1fc432e2b406d9d00f1028213221bGroup%20348447439.webp'
;
}
if
(
props
.
isTesting
&&
props
.
isProgressFinished
&&
!
props
.
isResultShown
)
{
return
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/5d0f462d13ec4cbcb6eee7080c637897Group%20348447439.webp'
;
}
return
props
.
isTesting
?
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/5d0f462d13ec4cbcb6eee7080c637897Group%20348447439.webp'
:
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/51e1fc432e2b406d9d00f1028213221bGroup%20348447439.webp'
;
});
const
emit
=
defineEmits
([
'startTest'
]);
watch
(()
=>
props
.
isTesting
,
(
newVal
)
=>
{
if
(
newVal
)
{
isDisabled
.
value
=
true
;
}
});
const
statusText
=
computed
(()
=>
props
.
isTesting
?
'1/2'
:
'0/2'
);
watch
(()
=>
props
.
isProgressFinished
,
(
newVal
)
=>
{
if
(
newVal
)
{
isDisabled
.
value
=
false
;
}
});
const
btnImage
=
computed
(()
=>
props
.
isTesting
?
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/5d0f462d13ec4cbcb6eee7080c637897Group%20348447439.webp'
:
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/51e1fc432e2b406d9d00f1028213221bGroup%20348447439.webp'
);
watch
(()
=>
props
.
isResultShown
,
(
newVal
)
=>
{
if
(
newVal
)
{
isDisabled
.
value
=
false
;
}
});
const
handleStartTest
=
()
=>
{
emit
(
'startTest'
);
if
(
isDisabled
.
value
)
return
;
if
(
!
props
.
isTesting
)
{
emit
(
'startTest'
);
}
else
if
(
props
.
isTesting
&&
props
.
isProgressFinished
&&
!
props
.
isResultShown
)
{
emit
(
'showFinalCard'
);
}
else
if
(
props
.
isResultShown
&&
props
.
isSecondTest
)
{
emit
(
'showCompletionPopup'
);
}
else
if
(
props
.
isResultShown
&&
!
props
.
isSecondTest
)
{
emit
(
'restartTest'
);
}
};
</
script
>
...
...
src/pages/third/components/TabsInstructionsPanel.vue
View file @
434bda5c
<
template
>
<view
class=
"tabs-instructions-container"
>
<view
class=
"tabs-row"
>
<template
v-if=
"!isSecondTest"
>
<view
class=
"tab-container"
>
<image
class=
"tab-btn-active
"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b91478ab6f2d4c2186a948ae9b614f45Group%20348447426.webp"
mode=
"aspect
Fill"
></image>
<image
class=
"tab-btn-active
tds-active-tab"
:src=
"activeTabImage"
mode=
"scaleTo
Fill"
></image>
</view>
<view
class=
"tab-container"
>
<image
class=
"tab-btn"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/a4bd654c5fd4401bb4d09ce1a8e08aa3Group%20348447427.webp
"
></image>
<image
class=
"tab-btn"
:src=
"inactiveTabImage"
mode=
"scaleToFill
"
></image>
</view>
</view>
</
template
>
<
template
v-else
>
<view
class=
"tab-container"
>
<image
class=
"tab-btn ph-inactive-tab"
:src=
"inactiveTabImage"
mode=
"scaleToFill"
></image>
</view>
<view
class=
"tab-container"
>
<image
class=
"tab-btn-active ph-active-tab"
:src=
"activeTabImage"
mode=
"scaleToFill"
></image>
</view>
</
template
>
</view>
<view
class=
"instructions-card"
v-if=
"!isTesting"
>
<image
class=
"card-bg"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/87e28ba2f4764f33a36b0d1cfd47d74aRectangle%203589.webp"
mode=
"scaleToFill"
></image>
<view
class=
"card-content"
>
<view
class=
"card-title"
>
操作说明
</view>
<view
class=
"card-body"
>
<text
class=
"instruction-text"
>
点击"开始检测"按钮测试TDS值
</text>
<image
class=
"ppm-icon"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/1a62746fad3743d19f01e8b612ed8d42Group%20348447435.webp"
mode=
"heightFix"
></image>
<text
class=
"instruction-text"
>
{{ instructionText }}
</text>
<image
class=
"ppm-icon"
:class=
"{ 'ph-icon': isSecondTest }"
:src=
"instructionIcon"
:mode=
"iconMode"
v-if=
"instructionIcon"
@
error=
"handleImageError"
></image>
<image
class=
"ph-label-img"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/536133e8a44f4482b2848016385d79cbPH.webp"
mode=
"aspectFit"
v-if=
"isSecondTest"
></image>
</view>
</view>
</view>
<view
class=
"progress-panel"
v-else
>
<view
class=
"progress-bar-container"
>
<view
class=
"progress-bar-container"
v-if=
"!showFinalCard"
>
<image
class=
"progress-bar-bg result-img"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/45cebdfeb99a44049d18ab3b04024ac2Group%20348447442.webp"
mode=
"scaleToFill"
...
...
@@ -31,10 +51,88 @@
mode=
"scaleToFill"
v-if=
"!showResults"
></image>
</view>
<view
class=
"result-boxes"
>
<view
class=
"result-card"
v-if=
"showFinalCard"
>
<image
class=
"card-bg"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/87e28ba2f4764f33a36b0d1cfd47d74aRectangle%203589.webp"
mode=
"scaleToFill"
></image>
<view
class=
"card-content"
>
<view
class=
"card-title"
>
检测结果
</view>
<view
class=
"card-body result-body"
v-if=
"!isSecondTest"
>
<view
class=
"comparison-section"
>
<text
class=
"section-title"
>
TDS值对比
</text>
<view
class=
"comparison-row"
>
<view
class=
"value-badge before"
>
<text>
前: 450ppm
</text>
</view>
<text
class=
"arrow"
>
→
</text>
<view
class=
"value-badge after"
>
<text>
后: 15ppm
</text>
</view>
</view>
<view
class=
"rate-row"
>
<text
class=
"rate-label"
>
净化率:
</text>
<text
class=
"rate-value"
>
96.7%
</text>
<view
class=
"rate-bar"
>
<view
class=
"rate-fill"
:style=
"{ width: '93.7%' }"
></view>
</view>
</view>
</view>
<view
class=
"chart-section"
>
<view
class=
"chart-container"
>
<view
class=
"bar-group red"
>
<text
class=
"bar-label"
>
450ppm
</text>
<view
class=
"bar"
></view>
</view>
<view
class=
"bar-group green"
>
<text
class=
"bar-label"
>
15ppm
</text>
<view
class=
"bar"
></view>
</view>
</view>
<image
class=
"badge-icon"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/44463cae0882429ebd84049240ff5330Group%20348447451.webp"
mode=
"aspectFit"
></image>
</view>
</view>
<view
class=
"card-body ph-result-body"
v-else
>
<view
class=
"ph-comparison-row"
>
<view
class=
"ph-value-group"
>
<text
class=
"label"
>
前:
</text>
<text
class=
"value highlight-green"
>
8.5
</text>
<view
class=
"ph-tag alkaline"
>
<text>
偏碱性
</text>
</view>
</view>
<image
class=
"ph-warning-icon"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/0c6358f526fd4a72a098e5e46c9a8759Frame%2017.webp"
mode=
"aspectFit"
></image>
<text
class=
"ph-arrow"
>
→
</text>
<view
class=
"ph-value-group"
>
<text
class=
"label"
>
后:
</text>
<text
class=
"value highlight-lime"
>
7.0
</text>
<view
class=
"ph-tag neutral"
>
<text>
中性
</text>
</view>
</view>
<image
class=
"ph-success-icon"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/dd15bc1646cb4fcb86670b2b1ae04809Group%20348447459.webp"
mode=
"aspectFit"
></image>
</view>
<view
class=
"ph-chart-container"
>
<image
class=
"ph-chart-img"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/3df0383e2218465c83af9aeeae10e1baGroup%20348447462.webp"
mode=
"widthFix"
></image>
</view>
<view
class=
"ph-footer-row"
>
<text
class=
"ph-footer-label"
>
酸碱度:
<text
class=
"highlight"
>
已优化
</text></text>
<view
class=
"ph-badge"
>
适合饮用
</view>
</view>
</view>
</view>
</view>
<view
class=
"result-boxes"
v-if=
"!showFinalCard"
>
<view
class=
"result-box"
>
<text
class=
"box-title"
>
污染水
</text>
<text
class=
"box-value"
:style=
"
{ color: showResults ? '#FF3300' : '#25334D' }">
TDS值:
{{
showResults
?
'450'
:
'???'
}}
</text>
<text
class=
"box-value"
:style=
"{ color: showResults ? '#FF3300' : '#25334D' }"
>
{{ resultLabel }}:{{ pollutedValue
}}
</text>
<image
class=
"status-icon"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/0c6358f526fd4a72a098e5e46c9a8759Frame%2017.webp"
alt=
"警告"
...
...
@@ -42,7 +140,7 @@
</view>
<view
class=
"result-box"
>
<text
class=
"box-title"
>
净化水
</text>
<text
class=
"box-value"
:style=
"
{ color: showResults ? '#00CC99' : '#25334D' }">
TDS值:
{{
showResults
?
'15'
:
'???'
}}
</text>
<text
class=
"box-value"
:style=
"{ color: showResults ? '#00CC99' : '#25334D' }"
>
{{ resultLabel }}:{{ purifiedValue
}}
</text>
<image
class=
"status-icon"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/e7e6a286a568480fada2cafab781cc3cFrame.webp"
alt=
"通过"
...
...
@@ -70,25 +168,102 @@ const props = defineProps({
isTesting
:
{
type
:
Boolean
,
default
:
false
},
isSecondTest
:
{
type
:
Boolean
,
default
:
false
},
triggerShowFinalCard
:
{
type
:
Boolean
,
default
:
false
}
});
const
emit
=
defineEmits
([
'resultShown'
,
'progressFinished'
]);
const
showResults
=
ref
(
false
);
const
showFinalCard
=
ref
(
false
);
const
activeTabImage
=
computed
(()
=>
{
return
props
.
isSecondTest
?
'/static/1.webp'
:
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/b91478ab6f2d4c2186a948ae9b614f45Group%20348447426.webp'
;
});
const
inactiveTabImage
=
computed
(()
=>
{
return
props
.
isSecondTest
?
'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/a4bd654c5fd4401bb4d09ce1a8e08aa3Group%20348447427.webp'
;
});
const
instructionText
=
computed
(()
=>
{
return
props
.
isSecondTest
?
"点击‘开始检测’测试水的酸碱度"
:
'点击"开始检测"按钮测试TDS值'
;
});
const
instructionIcon
=
computed
(()
=>
{
return
props
.
isSecondTest
?
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/32ac38db03994072aca53ae518b996eeGroup%20348447450.webp'
:
'https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/1a62746fad3743d19f01e8b612ed8d42Group%20348447435.webp'
;
});
const
iconMode
=
computed
(()
=>
{
return
props
.
isSecondTest
?
'aspectFit'
:
'heightFix'
;
});
const
handleImageError
=
(
e
)
=>
{
console
.
error
(
'Image load failed:'
,
e
.
detail
.
errMsg
);
};
const
tipsText
=
computed
(()
=>
{
return
props
.
isTesting
?
'安吉尔RO反渗透技术可将TDS降至15以下'
:
'TDS代表总溶解固体,数值越低水质越纯净'
;
if
(
props
.
isSecondTest
)
{
if
(
props
.
isTesting
)
{
return
'pH试纸通过颜色变化判断酸碱性'
;
}
return
'理想饮用水pH值应在6.5-8.5之间'
;
}
if
(
!
props
.
isTesting
)
{
return
'TDS代表总溶解固体,数值越低水质越纯净'
;
}
return
showFinalCard
.
value
?
'优质饮用水TDS值应低于50ppm'
:
'安吉尔RO反渗透技术可将TDS降至15以下'
;
});
const
resultLabel
=
computed
(()
=>
{
return
props
.
isSecondTest
?
'PH值'
:
'TDS值'
;
});
const
pollutedValue
=
computed
(()
=>
{
if
(
!
showResults
.
value
)
return
'???'
;
return
props
.
isSecondTest
?
'8.5'
:
'450'
;
});
const
purifiedValue
=
computed
(()
=>
{
if
(
!
showResults
.
value
)
return
'???'
;
return
props
.
isSecondTest
?
'7.0'
:
'15'
;
});
watch
(()
=>
props
.
isTesting
,
(
newVal
)
=>
{
if
(
newVal
)
{
showResults
.
value
=
false
;
showFinalCard
.
value
=
false
;
setTimeout
(()
=>
{
showResults
.
value
=
true
;
emit
(
'progressFinished'
);
},
1000
);
}
else
{
showResults
.
value
=
false
;
showFinalCard
.
value
=
false
;
}
});
watch
(()
=>
props
.
triggerShowFinalCard
,
(
newVal
)
=>
{
if
(
newVal
)
{
showFinalCard
.
value
=
true
;
emit
(
'resultShown'
);
}
});
</
script
>
...
...
@@ -117,12 +292,29 @@ watch(() => props.isTesting, (newVal) => {
.tab-btn-active
{
width
:
280
rpx
;
height
:
80
rpx
;
height
:
84
rpx
;
&.tds-active-tab
{
width
:
280
rpx
;
height
:
124
rpx
;
}
&
.ph-active-tab
{
width
:
274
rpx
;
height
:
128
rpx
;
margin-top
:
10
rpx
;
}
}
.tab-btn
{
width
:
240
rpx
;
height
:
80
rpx
;
height
:
84
rpx
;
&.ph-inactive-tab
{
width
:
242
rpx
;
height
:
94
rpx
;
margin-left
:
20
rpx
;
}
}
}
...
...
@@ -130,7 +322,7 @@ watch(() => props.isTesting, (newVal) => {
position
:
relative
;
width
:
120%
;
max-width
:
710
rpx
;
height
:
2
12
rpx
;
height
:
2
24
rpx
;
margin
:
1vh
0
;
border-radius
:
24
rpx
;
border
:
4
rpx
solid
#457AAB
;
...
...
@@ -175,12 +367,32 @@ watch(() => props.isTesting, (newVal) => {
.instruction-text
{
font-size
:
30
rpx
;
color
:
#25334D
;
font-weight
:
600
;
}
.ppm-icon
{
height
:
84
rpx
;
margin-left
:
10
rpx
;
}
.ph-icon
{
width
:
112
rpx
;
height
:
160
rpx
;
margin-top
:
0
;
position
:
absolute
;
right
:
12
rpx
;
top
:
50%
;
transform
:
translateY
(
-50%
);
}
.ph-label-img
{
position
:
absolute
;
right
:
96
rpx
;
top
:
28%
;
transform
:
translateY
(
-50%
);
width
:
50
rpx
;
height
:
28
rpx
;
}
}
}
}
...
...
@@ -188,7 +400,7 @@ watch(() => props.isTesting, (newVal) => {
.progress-panel
{
width
:
120%
;
max-width
:
710
rpx
;
margin
:
1vh
0
;
margin
:
1vh
0
0
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
...
...
@@ -218,6 +430,348 @@ watch(() => props.isTesting, (newVal) => {
}
}
.result-card
{
position
:
relative
;
width
:
100%
;
height
:
226
rpx
;
margin-bottom
:
24
rpx
;
border-radius
:
24
rpx
;
border
:
4
rpx
solid
#457AAB
;
background
:
#BEDCF3
;
box-sizing
:
border-box
;
.card-bg
{
position
:
absolute
;
top
:
50%
;
left
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
width
:
98%
;
height
:
94%
;
z-index
:
0
;
display
:
block
;
}
.card-content
{
position
:
relative
;
z-index
:
1
;
width
:
100%
;
height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
.card-title
{
text-align
:
center
;
font-size
:
34
rpx
;
font-weight
:
600
;
color
:
#25334D
;
}
.card-body
{
flex
:
1
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
padding
:
0
20
rpx
;
.instruction-text
{
font-size
:
30
rpx
;
color
:
#25334D
;
}
&
.result-body
{
justify-content
:
flex-start
;
align-items
:
flex-start
;
padding
:
10
rpx
40
rpx
;
.comparison-section
{
display
:
flex
;
flex-direction
:
column
;
gap
:
12
rpx
;
.section-title
{
font-size
:
30
rpx
;
color
:
#25334D
;
font-weight
:
600
;
}
.comparison-row
{
display
:
flex
;
align-items
:
center
;
gap
:
16
rpx
;
.value-badge
{
padding
:
6
rpx
14
rpx
;
border-radius
:
16
rpx
;
font-size
:
24
rpx
;
color
:
#FFFFFF
;
font-weight
:
600
;
&.before
{
background
:
#D93A12
;
border
:
3
rpx
solid
#9D341A
;
}
&
.after
{
background
:
#0FA983
;
border
:
3
rpx
solid
#1F8F73
;
}
}
.arrow
{
color
:
#457AAB
;
font-weight
:
bold
;
font-size
:
28
rpx
;
}
}
.rate-row
{
display
:
flex
;
align-items
:
center
;
margin-top
:
4
rpx
;
.rate-label
{
font-size
:
30
rpx
;
color
:
#25334D
;
font-weight
:
600
;
}
.rate-value
{
font-size
:
32
rpx
;
color
:
#00CC99
;
font-weight
:
bold
;
margin-left
:
10
rpx
;
}
.rate-bar
{
width
:
192
rpx
;
height
:
28
rpx
;
background
:
#8FB2CE
;
border-radius
:
22
rpx
;
border
:
1px
solid
rgba
(
69
,
122
,
171
,
0.8
);
box-shadow
:
0
3
rpx
4
rpx
0
rgba
(
90
,
108
,
122
,
0.4
)
inset
;
margin-left
:
20
rpx
;
overflow
:
hidden
;
position
:
relative
;
.rate-fill
{
height
:
100%
;
background
:
#00CC99
;
border-radius
:
22
rpx
;
box-shadow
:
0
0
4
rpx
0
rgba
(
255
,
255
,
255
,
0.7
)
inset
;
}
}
}
}
.chart-section
{
width
:
186
rpx
;
height
:
138
rpx
;
background
:
#BEDCF3
;
border
:
2
rpx
solid
rgba
(
69
,
122
,
171
,
0.5
);
border-radius
:
12
rpx
;
position
:
absolute
;
right
:
20
rpx
;
top
:
60%
;
transform
:
translateY
(
-50%
);
box-sizing
:
border-box
;
z-index
:
10
;
.chart-container
{
width
:
100%
;
height
:
100%
;
position
:
relative
;
display
:
flex
;
align-items
:
flex-end
;
padding
:
0
20
rpx
10
rpx
;
box-sizing
:
border-box
;
gap
:
30
rpx
;
.bar-group
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
gap
:
4
rpx
;
position
:
absolute
;
bottom
:
3
rpx
;
.bar-label
{
font-size
:
20
rpx
;
font-weight
:
600
;
white-space
:
nowrap
;
}
.bar
{
width
:
32
rpx
;
border-radius
:
4
rpx
4
rpx
0
0
;
}
&
.red
{
left
:
15
rpx
;
.bar-label
{
color
:
#D93A12
;
}
.bar
{
height
:
80
rpx
;
background
:
linear-gradient
(
180deg
,
#EE6E4E
0%
,
#D93A12
100%
);
border
:
1
rpx
solid
#9D341A
;
}
}
&
.green
{
right
:
20
rpx
;
.bar-label
{
color
:
#0FA983
;
margin-bottom
:
4
rpx
;
}
.bar
{
height
:
16
rpx
;
background
:
linear-gradient
(
180deg
,
#36E6BB
0%
,
#0FA983
100%
);
border
:
1
rpx
solid
#1F8F73
;
}
}
}
}
.badge-icon
{
position
:
absolute
;
top
:
10
rpx
;
right
:
10
rpx
;
width
:
68
rpx
;
height
:
68
rpx
;
z-index
:
2
;
}
}
}
&
.ph-result-body
{
flex-direction
:
column
;
justify-content
:
space-between
;
padding
:
10
rpx
30
rpx
!important
;
.ph-comparison-row
{
display
:
flex
;
align-items
:
center
;
width
:
100%
;
justify-content
:
center
;
gap
:
16
rpx
;
margin-top
:
18
rpx
;
.ph-value-group
{
display
:
flex
;
align-items
:
center
;
gap
:
8
rpx
;
.label
{
color
:
#25334D
;
font-size
:
30
rpx
;
font-weight
:
600
;
}
.value
{
font-size
:
30
rpx
;
font-weight
:
600
;
&.highlight-green
{
color
:
#4C9F6A
;
}
&
.highlight-lime
{
color
:
#B2C849
;
}
}
.ph-tag
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
text
{
color
:
#fff
;
font-size
:
16
rpx
;
font-weight
:
500
;
line-height
:
1
;
}
&
.alkaline
{
width
:
72
rpx
;
height
:
30
rpx
;
border-radius
:
26
rpx
;
border
:
2
rpx
solid
#0E692E
;
background
:
#4C9F6A
;
}
&
.neutral
{
width
:
56
rpx
;
height
:
30
rpx
;
border-radius
:
26
rpx
;
border
:
2
rpx
solid
#748A08
;
background
:
#B2C849
;
}
}
}
.ph-warning-icon
,
.ph-success-icon
{
width
:
36
rpx
;
height
:
36
rpx
;
}
.ph-success-icon
{
width
:
32
rpx
;
height
:
32
rpx
;
}
.ph-arrow
{
color
:
#457AAB
;
font-weight
:
bold
;
font-size
:
32
rpx
;
margin
:
0
10
rpx
;
}
}
.ph-chart-container
{
width
:
100%
;
margin
:
10
rpx
0
;
display
:
flex
;
justify-content
:
center
;
.ph-chart-img
{
width
:
95%
;
}
}
.ph-footer-row
{
width
:
100%
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
padding
:
0
10
rpx
;
.ph-footer-label
{
font-size
:
30
rpx
;
color
:
#25334D
;
font-weight
:
600
;
.highlight
{
color
:
#B2C849
;
}
}
.ph-badge
{
background
:
#B2C849
;
color
:
#fff
;
font-size
:
24
rpx
;
padding
:
6
rpx
16
rpx
;
border-radius
:
36
rpx
;
font-weight
:
600
;
border
:
2
rpx
solid
#748A08
;
}
}
}
}
}
}
.result-boxes
{
width
:
100%
;
display
:
flex
;
...
...
@@ -318,6 +872,7 @@ watch(() => props.isTesting, (newVal) => {
z-index
:
5
;
display
:
flex
;
align-items
:
center
;
font-weight
:
600
;
}
}
</
style
>
src/pages/third/components/beaker.vue
View file @
434bda5c
<
template
>
<view
class=
"main-content"
>
<view
class=
"beaker-section"
>
<view
class=
"beaker-item polluted-beaker"
>
<view
class=
"beaker-item polluted-beaker"
:class=
"
{ 'no-transform': isSecondTest }"
>
<view
class=
"beaker-img-wrapper"
>
<image
class=
"beaker-img"
:class=
"
{ 'img-hidden': isTesting }"
...
...
@@ -41,17 +41,33 @@
</
template
>
<
script
setup
>
import
{
computed
}
from
'vue'
;
const
props
=
defineProps
({
isTesting
:
{
type
:
Boolean
,
default
:
false
},
isSecondTest
:
{
type
:
Boolean
,
default
:
false
}
});
const
pollutedImageDefault
=
'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'
;
const
pollutedImageTesting
=
'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'
;
const
purifiedImageDefault
=
'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'
;
const
purifiedImageTesting
=
'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
?
'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'
:
'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'
;
});
const
purifiedImageTesting
=
computed
(()
=>
{
return
props
.
isSecondTest
?
'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'
:
'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'
;
});
</
script
>
<
style
scoped
lang=
"scss"
>
...
...
@@ -106,7 +122,7 @@ const purifiedImageTesting = 'https://userone-oss-cdn.angelgroup.com.cn/static/2
}
}
&
.polluted-beaker
.beaker-img-overlay
{
&
.polluted-beaker
:not
(
.no-transform
)
.beaker-img-overlay
{
transform
:
scale
(
1.03
)
translateY
(
25
rpx
);
transform-origin
:
center
bottom
;
}
...
...
src/pages/third/index.vue
View file @
434bda5c
...
...
@@ -6,14 +6,18 @@
<image
class=
"title"
src=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/e9ddd6b498fe452b9254e86c04596df3Group%20348447251.webp"
mode=
"heightFix"
></image>
</view>
<Beaker
:isTesting=
"isTesting"
/>
<Beaker
:isTesting=
"isTesting"
:isSecondTest=
"isSecondTest"
/>
<view
class=
"bottom-panel"
>
<TabsInstructionsPanel
:isTesting=
"isTesting"
/>
<TabsInstructionsPanel
:isTesting=
"isTesting"
:isSecondTest=
"isSecondTest"
:triggerShowFinalCard=
"triggerShowFinalCard"
@
resultShown=
"handleResultShown"
@
progressFinished=
"handleProgressFinished"
/>
<BottomActionBar
:isTesting=
"isTesting"
@
startTest=
"startTest
"
/>
<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=
"https://userone-oss-cdn.angelgroup.com.cn/static/2026-01-23/d204d71cf2a54b18a6404e6132618cd6%E5%AE%8C%E6%88%90%E5%BC%B9%E7%AA%97.webp"
mode=
"scaleToFill"
@
click
.
stop=
"closeCompletion"
></image>
</view>
</view>
</
template
>
...
...
@@ -26,6 +30,11 @@ import BottomActionBar from './components/BottomActionBar.vue';
const
statusBarHeight
=
ref
(
20
);
const
isTesting
=
ref
(
false
);
const
isSecondTest
=
ref
(
false
);
const
isResultShown
=
ref
(
false
);
const
isProgressFinished
=
ref
(
false
);
const
triggerShowFinalCard
=
ref
(
false
);
const
showCompletion
=
ref
(
false
);
onLoad
(()
=>
{
const
systemInfo
=
uni
.
getSystemInfoSync
();
...
...
@@ -45,6 +54,37 @@ const goBack = () => {
const
startTest
=
()
=>
{
console
.
log
(
'Start detection'
);
isTesting
.
value
=
true
;
isProgressFinished
.
value
=
false
;
triggerShowFinalCard
.
value
=
false
;
};
const
handleResultShown
=
()
=>
{
isResultShown
.
value
=
true
;
};
const
handleProgressFinished
=
()
=>
{
isProgressFinished
.
value
=
true
;
};
const
handleShowFinalCard
=
()
=>
{
triggerShowFinalCard
.
value
=
true
;
};
const
restartTest
=
()
=>
{
console
.
log
(
'Restart detection'
);
isTesting
.
value
=
false
;
isResultShown
.
value
=
false
;
isProgressFinished
.
value
=
false
;
triggerShowFinalCard
.
value
=
false
;
isSecondTest
.
value
=
true
;
};
const
handleShowCompletion
=
()
=>
{
showCompletion
.
value
=
true
;
};
const
closeCompletion
=
()
=>
{
showCompletion
.
value
=
false
;
};
</
script
>
...
...
@@ -111,6 +151,23 @@ const startTest = () => {
}
}
.completion-overlay
{
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
z-index
:
9999
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
.completion-img
{
width
:
100%
;
height
:
100%
;
}
}
.bottom-panel
{
width
:
100%
;
height
:
48vh
;
...
...
src/static/1.webp
0 → 100644
View file @
434bda5c
File added
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment