修复网盘bug

This commit is contained in:
chorblack
2025-07-05 20:24:17 +08:00
parent 0b54051613
commit c2946f5732
2 changed files with 891 additions and 634 deletions

View File

@@ -1,409 +1,543 @@
<template>
<div class="page" @swipe="back" @click="nextDialogue">
<image src="internal://files/{{Img}}"></image>
<image style="position: absolute;top: 300px;left: 0;" src="/common/text_bg.png" if="{{gameData.scenes[currentScene].choices == undefined && Img !== 'bg.png'}}"></image>
<text style="position: absolute;height: 50px;top: 250px;left: 8px;font-size: 28px;color: #FFFFFF;font-weight: bold" if="{{gameData.scenes[currentScene].choices == undefined && Img !== 'bg.png'}}">{{character}}</text>
<scroll scroll-y="true" bounces="true" class="scroll" id="scroll" if="{{gameData.scenes[currentScene].choices == undefined && Img !== 'bg.png'}}">
<text style="color: #FFFFFF;font-weight: bold;width: 100%;text-align: left;font-size: {{settings.textSize}}px;">{{showText}}</text>
</scroll>
<div class="page" style="background-color: #000000;" @click="nextDialogue">
</div>
<image
style="position: absolute; top: 300px; left: 0"
src="/common/text_bg.png"
if="{{gameData.scenes[currentScene].choices == undefined && Img !== 'bg.png'}}"></image>
<text
style="
position: absolute;
height: 50px;
top: 250px;
left: 8px;
font-size: 28px;
color: #ffffff;
font-weight: bold;
"
if="{{gameData.scenes[currentScene].choices == undefined && Img !== 'bg.png'}}">
{{ character }}
</text>
<scroll
scroll-y="true"
bounces="true"
class="scroll"
id="scroll"
if="{{gameData.scenes[currentScene].choices == undefined && Img !== 'bg.png'}}">
<text
style="color: #FFFFFF;font-weight: bold;width: 100%;text-align: left;font-size: {{settings.textSize}}px;">
{{ showText }}
</text>
</scroll>
<div
class="page"
style="background-color: #000000"
@click="nextDialogue"></div>
<!--选项页-->
<div class="page" style="position: absolute;" if="{{gameData.scenes[currentScene].choices !== undefined}}">
<div
class="page"
style="position: absolute"
if="{{gameData.scenes[currentScene].choices !== undefined}}">
<!--选项1-->
<text class="choice" @click="selectChoice(0)">{{gameData.scenes[currentScene].choices[0].text}}</text>
<text class="choice" @click="selectChoice(0)">
{{ gameData.scenes[currentScene].choices[0].text }}
</text>
<!--选项2-->
<text class="choice" style="top: 210px;" @click="selectChoice(1)">{{gameData.scenes[currentScene].choices[1].text}}</text>
<text class="choice" style="top: 210px" @click="selectChoice(1)">
{{ gameData.scenes[currentScene].choices[1].text }}
</text>
</div>
<!--菜单页-->
<div class="page" style="position: absolute;flex-wrap: nowrap;flex-direction: column;justify-content: center;align-items: center;background-color: #ffffff;" if="{{menu}}">
<div
class="page"
style="
position: absolute;
flex-wrap: nowrap;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #ffffff;
"
if="{{menu}}">
<text class="menu-btn" @click="toRecoveryPage(1)">保存</text>
<text class="menu-btn" @click="toRecoveryPage(2)">加载</text>
<text class="menu-btn" @click="skipScene(1)">跳过场景</text>
<text class="menu-btn" @click="skipChapter(chapter+1)">跳过章节</text>
<text class="menu-btn" @click="skipChapter(chapter + 1)">跳过章节</text>
<text class="menu-btn" @click="back('m')">返回</text>
</div>
<div class="page" style="position: absolute;background-color: #ffffff;" if="{{recovery===1}}" @swipe="back()">
<div
class="page"
style="position: absolute; background-color: #ffffff"
if="{{recovery===1}}"
@swipe="back()">
<scroll scroll-y="true" bounces="true" class="scroll1 page">
<text class="menu-btn">长按删除存档</text>
<text class="menu-btn">点击存档覆盖</text>
<text class="menu-btn" for="{{recoveryData}}" style="font-size: 30px;" @click="saveRecoveryData($idx)" @longpress="deleteRecoveryData($idx)">存档{{$idx+1}}</text>
<text
class="menu-btn"
for="{{recoveryData}}"
style="font-size: 30px"
@click="saveRecoveryData($idx)"
@longpress="deleteRecoveryData($idx)">
存档{{ $idx + 1 }}
</text>
<text class="menu-btn" @click="saveRecoveryData('new')">+</text>
</scroll>
</div>
<div class="page" style="position: absolute;background-color: #ffffff;" if="{{recovery===2}}" @swipe="back()">
<div
class="page"
style="position: absolute; background-color: #ffffff"
if="{{recovery===2}}"
@swipe="back()">
<scroll scroll-y="true" bounces="true" class="scroll1 page">
<text class="menu-btn">点击读取存档</text>
<text class="menu-btn" for="{{recoveryData}}" style="font-size: 30px;" @click="loadRecoveryData($idx)" @longpress="consoleData($idx)">存档{{$idx+1}}</text>
<text
class="menu-btn"
for="{{recoveryData}}"
style="font-size: 30px"
@click="loadRecoveryData($idx)"
@longpress="consoleData($idx)">
存档{{ $idx + 1 }}
</text>
</scroll>
</div>
<div class="page" style="position: absolute;background-color: #ffffff;flex-wrap: nowrap;flex-direction: column;align-items: center;justify-content: center;" if="{{END != ''}}" @swipe="back()">
<text style="font-size: 30px;text-align: center;color: #000000;">达成结局:{{END}}</text>
<text style="font-size: 30px;text-align: center;color: #000000;" @click="back('e')">返回主页</text>
<div
class="page"
style="
position: absolute;
background-color: #ffffff;
flex-wrap: nowrap;
flex-direction: column;
align-items: center;
justify-content: center;
"
if="{{END != ''}}"
@swipe="back()">
<text style="font-size: 30px; text-align: center; color: #000000">
达成结局:{{ END }}
</text>
<text
style="font-size: 30px; text-align: center; color: #000000"
@click="back('e')">
返回主页
</text>
</div>
</div>
</template>
<script>
import router from '@blueos.app.appmanager.router';
import storage from '@blueos.storage.storage';
import prompt from '@blueos.window.prompt';
import file from '@blueos.storage.file';
let t1;
export default {
data: {
gameData: {
scenes: [
]
import router from '@blueos.app.appmanager.router'
import storage from '@blueos.storage.storage'
import prompt from '@blueos.window.prompt'
import file from '@blueos.storage.file'
let t1, t2, t3
export default {
data: {
gameData: {
scenes: [],
},
index: 0,
canContinue: true,
currentScene: 0,
currentDialogue: 0,
Img: 'bg.png',
showText: '',
character: '',
settings: {
textSpeed: 40,
textSize: 22,
},
chapter: 0,
menu: false,
recovery: 0,
choice: [],
recoveryData: [],
load: null,
END: '',
jsonDataList: [
'b999.json',
'b101.json',
'b102.json',
'b103.json',
'b111.json',
'b112.json',
'b113.json',
'b114.json',
'b121.json',
'b122.json',
'b123.json',
'b124.json',
'b200.json',
'b201.json',
'b202.json',
'b203.json',
'b204.json',
'b205.json',
'b206.json',
'b207.json',
'b301.json',
'b302.json',
'b303.json',
'b304.json',
'b401.json',
'b402.json',
'b403.json',
'b404.json',
'b405.json',
'b406.json',
'b407.json',
'b501.json',
'b601.json',
'b701.json',
],
},
index: 0,
canContinue: true,
currentScene: 0,
currentDialogue: 0,
Img: 'bg.png',
showText: '',
character: '',
settings: {
textSpeed: 40,
textSize: 22
},
chapter: 0,
menu: false,
recovery: 0,
choice: [],
recoveryData: [],
load: null,
END: '',
jsonDataList: [
'b999.json', 'b101.json', 'b102.json', 'b103.json', 'b111.json', 'b112.json', 'b113.json', 'b114.json',
'b121.json', 'b122.json', 'b123.json', 'b124.json', 'b200.json', 'b201.json', 'b202.json', 'b203.json',
'b204.json', 'b205.json', 'b206.json', 'b207.json', 'b301.json', 'b302.json', 'b303.json', 'b304.json',
'b401.json', 'b402.json', 'b403.json', 'b404.json', 'b405.json', 'b406.json', 'b407.json', 'b501.json',
'b601.json', 'b701.json'
],
},
onInit(){
//
router.clear();
storage.get({
key: 'recoveryData',
success: (data) => {
if(data){
this.recoveryData = JSON.parse(data);
if(this.load){
if(this.load === 'TE'){
this.loadData("TE");
this.loadScene(this.currentScene);
onInit() {
//
router.clear()
storage.get({
key: 'recoveryData',
success: (data) => {
if (data) {
this.recoveryData = JSON.parse(data)
if (this.load) {
if (this.load === 'TE') {
this.loadData('TE')
this.loadScene(this.currentScene)
} else {
this.loadRecoveryData(this.load)
}
} else {
this.loadData(this.chapter)
this.loadScene(this.currentScene)
}
else{this.loadRecoveryData(this.load)}
} else {
this.loadData(this.chapter)
this.loadScene(this.currentScene)
}
else{
this.loadData(this.chapter);
this.loadScene(this.currentScene);
},
fail: () => {},
})
storage.get({
key: 'settings',
success: (data) => {
if (data) {
this.settings = JSON.parse(data)
}
}else{
this.loadData(this.chapter);
this.loadScene(this.currentScene);
}
},
fail:()=>{},
});
storage.get({
key: 'settings',
success: (data) => {
if(data){
this.settings = JSON.parse(data);
}
},
fail:()=>{},
});
},
async loadData(chapter){
let num;
if (chapter == "BE") {
num = 'b601.json';
} else if (chapter == "TE") {
num = 'b701.json';
} else {
num = this.jsonDataList[chapter];
}
console.log(num);
await file.readText({
uri: `internal://files/${num}`,
success: (data) =>{
this.gameData.scenes = JSON.parse(data.text);
//storage.getSync({ key: 'data' });
},
fail: function (_, code) {
prompt.showToast({message: code.toString()});
},
})
},
// 显示背景图
showBackground(image) {
this.Img = image;
},
// 显示对话
showDialogue(dialogue) {
this.showText = '';
this.character = dialogue.character;
this.canContinue = false;
this.index = 0;
this.zhuzi(dialogue.text);
},
zhuzi(text){
if (this.index < text.length){
this.showText += text.charAt(this.index);
this.index++;
t1 = setTimeout(() => {this.zhuzi(text);}, this.settings.textSpeed);
}
else{this.canContinue=true;}
},
onDestroy() {
// 解除内存占用
clearTimeout(t1);
},
// 加载场景
loadScene(sceneIndex) {
const scene = this.gameData.scenes[sceneIndex];
this.showBackground(scene.background);
this.currentDialogue = 0;
if(scene.choices){return}
this.showDialogue(scene.dialogues[this.currentDialogue]);
},
// 下一段对话
nextDialogue() {
if (this.canContinue) {
this.scrollToTop();//避免显示bug
this.canContinue = false;
const scene = this.gameData.scenes[this.currentScene];
if (this.currentDialogue < scene.dialogues.length - 1) {
this.currentDialogue++;
this.showDialogue(scene.dialogues[this.currentDialogue]);
} else if (this.currentScene < this.gameData.scenes.length - 1) {
if(scene.dialogues[this.currentDialogue].toScenes !== undefined){
console.log('跳转场景[选项]')
this.currentScene += scene.dialogues[this.currentDialogue].toScenes;
this.loadScene(this.currentScene);
}else{
console.log('跳转场景')
this.currentScene++;
this.loadScene(this.currentScene);
}
},
fail: () => {},
})
},
async loadData(chapter) {
let num
if (chapter == 'BE') {
num = 'b601.json'
} else if (chapter == 'TE') {
num = 'b701.json'
} else {
if(scene.dialogues[this.currentDialogue].END !== undefined){
this.END = scene.dialogues[this.currentDialogue].END;
this.getFin(this.END);
// 分支
}else if(scene.dialogues[this.currentDialogue].branch !== undefined){
console.log(this.choice)
console.log(scene.dialogues[this.currentDialogue].branch.choices)
if(JSON.stringify(this.choice)===JSON.stringify(scene.dialogues[this.currentDialogue].branch.choices)){
console.log('跳转章节[HE]')
this.chapter = scene.dialogues[this.currentDialogue].branch.toChapter;
this.loadData(this.chapter);
this.currentScene = 0;
this.currentDialogue = 0;
this.loadScene(this.currentScene);
num = this.jsonDataList[chapter]
}
console.log(num)
await file.readText({
uri: `internal://files/${num}`,
success: (data) => {
this.gameData.scenes = JSON.parse(data.text)
//storage.getSync({ key: 'data' });
},
fail: function (_, code) {
prompt.showToast({ message: code.toString() })
},
})
},
// 显示背景图
showBackground(image) {
this.Img = image
},
// 显示对话
showDialogue(dialogue) {
this.showText = ''
this.character = dialogue.character
this.canContinue = false
this.index = 0
this.zhuzi(dialogue.text)
},
zhuzi(text) {
if (this.index < text.length) {
this.showText += text.charAt(this.index)
this.index++
t1 = setTimeout(() => {
this.zhuzi(text)
}, this.settings.textSpeed)
} else {
this.canContinue = true
}
},
onDestroy() {
// 解除内存占用
clearTimeout(t1)
clearTimeout(t2)
clearTimeout(t3)
},
// 加载场景
loadScene(sceneIndex) {
const scene = this.gameData.scenes[sceneIndex]
this.showBackground(scene.background)
this.currentDialogue = 0
if (scene.choices) {
return
}
this.showDialogue(scene.dialogues[this.currentDialogue])
},
// 下一段对话
nextDialogue() {
if (this.canContinue) {
this.scrollToTop() //避免显示bug
this.canContinue = false
const scene = this.gameData.scenes[this.currentScene]
if (this.currentDialogue < scene.dialogues.length - 1) {
this.currentDialogue++
this.showDialogue(scene.dialogues[this.currentDialogue])
} else if (this.currentScene < this.gameData.scenes.length - 1) {
if (scene.dialogues[this.currentDialogue].toScenes !== undefined) {
console.log('跳转场景[选项]')
this.currentScene += scene.dialogues[this.currentDialogue].toScenes
this.loadScene(this.currentScene)
} else {
console.log('跳转场景')
this.currentScene++
this.loadScene(this.currentScene)
}
else{
console.log('跳转章节[BE]')
this.chapter = "BE";
this.loadData(this.chapter);
this.currentScene = 0;
this.currentDialogue = 0;
this.loadScene(this.currentScene);
} else {
if (scene.dialogues[this.currentDialogue].END !== undefined) {
this.END = scene.dialogues[this.currentDialogue].END
this.getFin(this.END)
// 分支
} else if (
scene.dialogues[this.currentDialogue].branch !== undefined
) {
console.log(this.choice)
console.log(scene.dialogues[this.currentDialogue].branch.choices)
if (
JSON.stringify(this.choice) ===
JSON.stringify(
scene.dialogues[this.currentDialogue].branch.choices
)
) {
console.log('跳转章节[HE]')
this.chapter =
scene.dialogues[this.currentDialogue].branch.toChapter
this.loadData(this.chapter)
this.currentScene = 0
this.currentDialogue = 0
this.loadScene(this.currentScene)
} else {
console.log('跳转章节[BE]')
this.chapter = 'BE'
this.loadData(this.chapter)
this.currentScene = 0
this.currentDialogue = 0
this.loadScene(this.currentScene)
}
} else {
this.Img = 'bg.png'
t2 = setTimeout(() => {
this.chapter++
this.loadData(this.chapter)
this.currentScene = 0
this.currentDialogue = 0
this.loadScene(this.currentScene)
}, 3000)
}
}else{
this.Img = 'bg.png';
setTimeout(() => {
this.chapter++;
this.loadData(this.chapter);
this.currentScene = 0;
this.currentDialogue = 0;
this.loadScene(this.currentScene);
}, 3000);
}
}
}
},
back(a){
if(a=='m'&&this.menu){this.menu = false}
else if(a.direction=='right'&&this.recovery!==0){this.recovery = 0}
else if(a.direction=='right'||a=='e'){router.replace({uri: "/pages/index"})}
else if(a.direction=='left'){this.menu = true}
},
// 选择选项
selectChoice(choiceIndex) {
console.log('选择选项', choiceIndex)
this.choice.push(choiceIndex);
console.log(this.choice)
const nextSceneIndex = this.gameData.scenes[this.currentScene].choices[choiceIndex].nextScene;
this.currentScene += nextSceneIndex;
this.loadScene(this.currentScene);
},
toRecoveryPage(a){
this.recovery = a;
},
saveRecoveryData(idx){
const data = {
chapter: this.chapter,
currentScene: this.currentScene,
currentDialogue: this.currentDialogue,
choice: this.choice,
}
if(idx === 'new'){
this.recoveryData.push(data);
}else{
this.recoveryData[idx] = data;
}
this.saveData()
prompt.showToast({
message:"存档成功"
})
},
deleteRecoveryData(idx){
this.recoveryData.splice(idx, 1);
this.saveData()
prompt.showToast({message: '删除成功'})
},
loadRecoveryData(idx){
const data = this.recoveryData[parseInt(idx)];
console.log('加载存档', data)
this.chapter = data.chapter;
this.currentScene = data.currentScene;
this.currentDialogue = data.currentDialogue;
this.choice = data.choice;
this.recovery = 0;
this.menu = false;
this.loadData(this.chapter);
this.loadScene(this.currentScene);
},
skipScene(a){
if(this.gameData.scenes[this.currentScene].dialogues[this.gameData.scenes[this.currentScene].dialogues.length-1].toScenes ==undefined && this.gameData.scenes[this.currentScene].choices==undefined && this.gameData.scenes[this.currentScene].dialogues[this.gameData.scenes[this.currentScene].dialogues.length-1].END==undefined && this.gameData.scenes[this.currentScene].dialogues[this.gameData.scenes[this.currentScene].dialogues.length-1].branch==undefined&&this.currentScene+a<this.gameData.scenes.length){
this.currentScene+=a;
this.loadScene(this.currentScene);
this.menu = false;
}else{
this.menu = false;
prompt.showToast({message: '无法跳过'})
}
},
skipChapter(a){
this.Img = 'bg.png';
this.menu = false;
setTimeout(() => {
this.chapter=a;
this.loadData(this.chapter);
this.currentScene = 0;
this.currentDialogue = 0;
this.loadScene(this.currentScene);
}, 3000);
},
saveData(){
storage.set({
key: 'recoveryData',
value: JSON.stringify(this.recoveryData),
success: () => {},
fail:()=>{},
})
},
getFin(a){
let fin = {};
storage.get({
key: 'fin',
success: (data) => {
if(data){
fin = JSON.parse(data);
}else{
fin = {"HE": false, "BE": false}
}
if(a=="Happy Ending"){
fin.HE = true;
}else if(a=="Bad Ending"){
fin.BE = true;
}
this.saveFin(fin);
},
fail:()=>{},
});
},
saveFin(a){
storage.set({
key: 'fin',
value: JSON.stringify(a),
success: () => {},
fail:()=>{},
})
},
consoleData(idx){
console.log('存档数据', this.recoveryData[idx])
},
scrollToTop() {
this.$element('scroll').scrollTo({
top: 0,
left: 0,
behavior: 'instant'
})
},
}
},
back(a) {
if (a == 'm' && this.menu) {
this.menu = false
} else if (a.direction == 'right' && this.recovery !== 0) {
this.recovery = 0
} else if (a.direction == 'right' || a == 'e') {
router.replace({ uri: '/pages/index' })
} else if (a.direction == 'left') {
this.menu = true
}
},
// 选择选项
selectChoice(choiceIndex) {
console.log('选择选项', choiceIndex)
this.choice.push(choiceIndex)
console.log(this.choice)
const nextSceneIndex =
this.gameData.scenes[this.currentScene].choices[choiceIndex].nextScene
this.currentScene += nextSceneIndex
this.loadScene(this.currentScene)
},
toRecoveryPage(a) {
this.recovery = a
},
saveRecoveryData(idx) {
const data = {
chapter: this.chapter,
currentScene: this.currentScene,
currentDialogue: this.currentDialogue,
choice: this.choice,
}
if (idx === 'new') {
this.recoveryData.push(data)
} else {
this.recoveryData[idx] = data
}
this.saveData()
prompt.showToast({
message: '存档成功',
})
},
deleteRecoveryData(idx) {
this.recoveryData.splice(idx, 1)
this.saveData()
prompt.showToast({ message: '删除成功' })
},
loadRecoveryData(idx) {
const data = this.recoveryData[parseInt(idx)]
console.log('加载存档', data)
this.chapter = data.chapter
this.currentScene = data.currentScene
this.currentDialogue = data.currentDialogue
this.choice = data.choice
this.recovery = 0
this.menu = false
this.loadData(this.chapter)
this.loadScene(this.currentScene)
},
skipScene(a) {
if (
this.gameData.scenes[this.currentScene].dialogues[
this.gameData.scenes[this.currentScene].dialogues.length - 1
].toScenes == undefined &&
this.gameData.scenes[this.currentScene].choices == undefined &&
this.gameData.scenes[this.currentScene].dialogues[
this.gameData.scenes[this.currentScene].dialogues.length - 1
].END == undefined &&
this.gameData.scenes[this.currentScene].dialogues[
this.gameData.scenes[this.currentScene].dialogues.length - 1
].branch == undefined &&
this.currentScene + a < this.gameData.scenes.length
) {
this.currentScene += a
this.loadScene(this.currentScene)
this.menu = false
} else {
this.menu = false
prompt.showToast({ message: '无法跳过' })
}
},
skipChapter(a) {
this.Img = 'bg.png'
this.menu = false
t3 = setTimeout(() => {
this.chapter = a
this.loadData(this.chapter)
this.currentScene = 0
this.currentDialogue = 0
this.loadScene(this.currentScene)
}, 3000)
},
saveData() {
storage.set({
key: 'recoveryData',
value: JSON.stringify(this.recoveryData),
success: () => {},
fail: () => {},
})
},
getFin(a) {
let fin = {}
storage.get({
key: 'fin',
success: (data) => {
if (data) {
fin = JSON.parse(data)
} else {
fin = { HE: false, BE: false }
}
if (a == 'Happy Ending') {
fin.HE = true
} else if (a == 'Bad Ending') {
fin.BE = true
}
this.saveFin(fin)
},
fail: () => {},
})
},
saveFin(a) {
storage.set({
key: 'fin',
value: JSON.stringify(a),
success: () => {},
fail: () => {},
})
},
consoleData(idx) {
console.log('存档数据', this.recoveryData[idx])
},
scrollToTop() {
this.$element('scroll').scrollTo({
top: 0,
left: 0,
behavior: 'instant',
})
},
}
</script>
<style>
.page {
width: 390px;
height: 450px;
}
.scroll{
position: absolute;
bottom: 0;
top: 300px;
left: 8px;
right: 8px;
width: 390px;
height: 155px;
text-overflow: ellipsis;
flex-wrap: wrap;
}
.scroll1{
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
text-overflow: ellipsis;
flex-wrap: nowrap;
flex-direction: column;
align-items: center;
}
.choice {
position: absolute;
width: 250px;
height: 61px;
left: 43px;
top: 100px;
background-color: rgba(80, 192, 231, 0.7);
color: #ffffff;
font-size: 24px;
font-weight: bold;
text-align: center;
}
.menu-btn {
width: 250px;
height: 61px;
background-color: rgba(80, 192, 231, 0.7);
color: #ffffff;
font-size: 24px;
font-weight: bold;
text-align: center;
margin-bottom: 20px;
}
</style>
.page {
width: 390px;
height: 450px;
}
.scroll {
position: absolute;
bottom: 0;
top: 300px;
left: 8px;
right: 8px;
width: 390px;
height: 155px;
text-overflow: ellipsis;
flex-wrap: wrap;
}
.scroll1 {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
text-overflow: ellipsis;
flex-wrap: nowrap;
flex-direction: column;
align-items: center;
}
.choice {
position: absolute;
width: 250px;
height: 61px;
left: 43px;
top: 100px;
background-color: rgba(80, 192, 231, 0.7);
color: #ffffff;
font-size: 24px;
font-weight: bold;
text-align: center;
}
.menu-btn {
width: 250px;
height: 61px;
background-color: rgba(80, 192, 231, 0.7);
color: #ffffff;
font-size: 24px;
font-weight: bold;
text-align: center;
margin-bottom: 20px;
}
</style>