前言
省赛真题解析见:
2022年第十三届蓝桥杯Web大学组省赛真题解析(完整版)
2022年第十三届蓝桥杯Web大学组省赛真题解析(精华版)
更多蓝桥杯题解请查阅专栏:蓝桥杯
之前写省赛解析时篇幅过长,写的花里胡哨的,导致文章阅读体验不好,这次就不整那些了,直接贴代码,解析都写在代码注释里了,相信各位老大稍微思考一下就能够理解了,同样的,相应的真题代码
也会分享给大家:
「蓝桥杯」https://www.aliyundrive.com/s/7fsobhSy8dZ 提取码: 34pi
如果在阅读文章时大佬有好的见解,或者发现了问题,还请多多留言,互相探讨
文章目录
1、分一分(5分)
/**
* @param {Object} oldArr
* @param {Object} num
* */
const splitArray = (oldArr, num) => {
// TODO:请补充代码实现功能
let newArr = [];
// 升序排序后解构赋值深拷贝给oldArr2
let oldArr2 = [...oldArr.sort((a, b) => a - b)];
const len = oldArr2.length;
for (let i = 0, j = 0; i < len; i += num, j++) {
// splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
newArr[j] = oldArr2.splice(0, num);
}
return newArr;
};
module.exports = splitArray; // 检测需要,请勿删除
2、新鲜的蔬菜(5 分)
/* TODO:待补充代码 */
#box1 {
display: flex;
justify-content: center;
align-items: center;
}
#box2,
#box3 {
display: flex;
flex-direction: column;
justify-content: space-between;
}
#box2 span:nth-child(2),
#box3 span:nth-child(3) {
align-self: flex-end;
}
#box3 span:nth-child(2) {
align-self: center;
}
3、水果消消乐(10分)
// TODO:请补充代码
function startGame() {
$('#start').hide()
$('.img-box img').show(500)
$('.img-box img').hide(500)
let lastImg = null; // 上一个点击的img
let showIndex = 0; // 当前显示的图片数量
let result = 0; //分数
$('.img-box').click(function(e){
const imgBox = e.target
const img = imgBox.children[0]
// 图片不存在或者两次图片一样了不做处理
if(!img||img == lastImg) return;
$(img).show(); // 先显示图片
showIndex++; // 图片显示数量+1
if(showIndex == 2) {
// 如果已经选择了两张图片,则开始比较
if(img.alt == lastImg.alt) {
// 两次点击的是同样的图片
// 因为在异步的定时器里会用到lastImg,并且下面同步代码中会重置lastImg
// 所以为了使定时器里能获取到当前的lastImg而不是重置后的lastImg,需要缓存一下当前的lastImg
// 这里选择将lastImg作为参数传递给setTimeout的第三个参数
// setTimeout的前两个之外的参数都会在定时器结束后作为参数传递给回调函数,所以在回调函数里可以通过last来接收setTimeout的lastImg
setTimeout((last) => {
// 设置图片容器透明度为0
$(imgBox).css('opacity',0)
$(last.parentElement).css('opacity',0)
// 更新分数
result += 2
$('#score').text(result)
}, 500,lastImg);
}else {
// 两次点击的不是同样的图片
setTimeout((last) => {
$(last).hide()
$(img).hide()
// 更新分数
result -= 2
$('#score').text(result)
}, 500,lastImg);
}
// 比较过后重置lastImg与showIndex
lastImg = null;
showIndex = 0
} else {
// 如果选择的图片少于两张,则说明是第一次点击(每一轮需要点击两次,这里说的第一次指的是这一轮里的第一次)
lastImg = img // 直接缓存这次的图片供下次点击时比对即可
}
})
}
4、用什么来做计算A (10分)
// TODO:请补充代码
const btn = document.getElementsByClassName("calc-button");
const formula = document.getElementById("formula");
const result = document.getElementById("result");
// 计算机表达式展示
let showText = "";
// 计算结果
let num = "";
[...btn].forEach((item) => {
item.onclick = function () {
switch (this.id) {
// 点击 =
case "equal":
// eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
num = eval(showText.replace("x", "*").replace("÷", "/"));
result.value = num;
return;
// 点击 √
case "sqrt":
num = eval(showText.replace("x", "*").replace("÷", "/"));
num = Math.sqrt(num);
result.value = num;
return;
// 点击 AC
case "reset":
showText = "";
num = "";
formula.value = showText;
result.value = num;
return;
default:
showText += this.innerHTML;
formula.value = showText;
return;
}
};
});
5、开学礼物大放送(15 分)
考察的只是简答的页面实现,每个人的实现方式不同,代码差异也很大,这里就不放代码了
6、权限管理(15 分)
$(function () {
// 使用 ajax 获取 userList.json 数据并渲染到页面
getData();
// 为按钮添加事件
$("#add").click(function () {
// TODO:补充代码,实现功能
// 获取选中的option
let option = $("#leftSelect option:selected");
// jQ方法:each() 遍历jQ获取的节点
option.each((index, item) => {
// 删除左侧对应的option
$(`#leftSelect option[value=${item.value}]`).remove();
// 向右侧添加option
$("#rightSelect")[0].add(new Option(item.value, item.value));
});
changeAccess("管理员", option);
});
$("#addAll").click(function () {
// TODO:补充代码,实现功能
let option = $("#leftSelect option");
option.each((index, item) => {
$(`#leftSelect option[value=${item.value}]`).remove();
$("#rightSelect")[0].add(new Option(item.value, item.value));
});
changeAccess("管理员", option);
});
$("#remove").click(function () {
// TODO:补充代码,实现功能
let option = $("#rightSelect option:selected");
option.each((index, item) => {
$(`#rightSelect option[value=${item.value}]`).remove();
$("#leftSelect")[0].add(new Option(item.value, item.value));
});
changeAccess("普通用户", option);
});
$("#removeAll").click(function () {
// TODO:补充代码,实现功能
let option = $("#rightSelect option");
option.each((index, item) => {
$(`#rightSelect option[value=${item.value}]`).remove();
$("#leftSelect")[0].add(new Option(item.value, item.value));
});
changeAccess("普通用户", option);
});
});
/**
* 修改权限
* @param {Object} right 要修改的权限
* @param {Object} changeList 要修改权限的用户列表
*/
function changeAccess(right, changeList) {
// TODO:补充代码,实现功能
changeList.each((index, item) => {
// 将option.value与tr.name对应,找到对应的td并修改其内容
// jQ方法::last 获取最后个元素
$(`#userList tr[name=${item.value}] td:last`).html(right);
});
}
// 异步获取数据
function getData() {
// TODO:补充代码,实现功能
$.ajax("./js/userList.json").then((res) => {
res.forEach((item) => {
// jQ方法:html() 设置html内容
$("#userList tbody").html(
$("#userList tbody").html() +
` <tr name=${item.name}>
<td>${item.name}</td>
<td>${item.right ? "管理员" : "普通用户"}</td>
</tr>`
);
});
});
}
7、一起会议吧(20分)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>一起会议吧</title>
<link rel="stylesheet" type="text/css" href="./css/index.css" />
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
</head>
<body>
<div id="app">
<!-- TODO:请在下面实现需求 -->
<!-- 登录/注销窗口 -->
<div class="login">
<div class="left-tools">
<a class="close-btn"></a>
<a class="shrink-btn"></a>
</div>
<h3>{{isLogin?'注销':'登录'}}</h3>
<p v-if="!isLogin">
选择用户:<select id="selectUser" @change="changeOption($event)">
<option :value="item.id" v-for="item in list" :key="item.id">{{item.name}}</option>
</select>
</p>
<p v-else>当前用户为:{{loginUser.name}}</p>
<a class="login-btn" @click="btn">{{isLogin?'注销':'登录'}}</a>
</div>
<!-- 右侧显示用户列表窗口按钮 -->
<button id="show" class="right-btn" v-if="!showUser&&isLogin" @click="showUser=true">
<span class="iconfont icon-left-arrow"></span>
</button>
<!-- 用户列表窗口 -->
<div class="user-dialog" v-if="isLogin&&showUser">
<!-- 用户列表窗口上侧工具栏 -->
<ul class="tools">
<li class="tools-left">
<button :class="{'active':isButton<0}" @click="isButton=-1">
<span class="iconfont icon-close"></span>
</button>
<button :class="{'active':isButton=='0'}" @click="isButton=0">
<span class="iconfont icon-dialog"></span>
</button>
<button :class="{'active':isButton>0}" @click="isButton=1">
<span class="iconfont icon-list"></span>
</button>
</li>
<li class="tools-right">
<button class="show-list" @click="showUser=false">
<span class="iconfont icon-retract"></span>
</button>
</li>
</ul>
<!-- 用户列表 -->
<ul class="say-list">
<li>
<span class="iconfont icon-microphone"></span>
</li>
<li class="line"></li>
<li>正在讲话:{{list.find(item=>item.isHost).name}};</li>
</ul>
<ul class="user-list">
<li v-show="isButton>=0">
<img class="header" :src="loginUser.imgPath" />
<div class="user-name">
<span class="iconfont icon-user header-icon" v-if="loginUser.isHost"></span>
<span class="iconfont icon-microphone"></span> {{loginUser.name}}
</div>
</li>
<li v-for="item in list" :key="item.id" v-if="item.id!==loginUser.id" v-show="isButton>0">
<img class="header" :src="item.imgPath" />
<div class="user-name">
<span class="iconfont icon-user header-icon" v-if="item.isHost"></span>
<span class="iconfont icon-microphone"></span> {{item.name}}
</div>
</li>
</ul>
</div>
</div>
<script type="text/javascript" src="./js/vue.js"></script>
<script type="text/javascript" src="./js/axios.min.js"></script>
<script type="text/javascript">
// TODO:请在下面实现需求
new Vue({
el: "#app",
data: {
// 用户列表
list: [],
// 选择用户id
value: '1',
// 是否登录
isLogin: false,
// 是否显示用户参会窗口
showUser: true,
// 登录的用户信息
loginUser: {},
// 用户列表显示效果切换的状态
isButton: 0
},
created() {
axios.get('./js/userList.json').then(res => {
this.list = res.data
})
},
methods: {
btn() {
this.isLogin = !this.isLogin
if (this.isLogin) {
this.loginUser = this.list.find(item => item.id == this.value)
} else {
this.loginUser = {}
this.value = '1'
this.isButton = 0
this.showUser = true
}
},
// 选择下拉框用户时
changeOption(e) {
this.value = e.target.value
}
}
});
</script>
</body>
</html>
8、天气趋势A (20分)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>天气趋势</title>
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
/>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script src="./js/axios.js"></script>
<script src="js/vue.min.js" type="text/javascript" charset="utf-8"></script>
<script
src="js/echarts.min.js"
type="text/javascript"
charset="utf-8"
></script>
</head>
<body>
<div id="app">
<div class="top-bar">2022年 Y 城全年温度统计图</div>
<!-- 主体 -->
<div class="container">
<!-- 月份 -->
<div class="month">
<ul>
<!-- TODO:待补充代码 在下面的 li 标签中完成 12个月份 (即 monthList) 的渲染 -->
<!-- monthList是一个对象,v-for遍历对象时item是对象属性值,key是对象属性名 -->
<li :class="{active:showMonthEN == key}" :key="key" v-for="(item,key) in monthList" @click="changeMonth(key)">{{item}}</li>
</ul>
</div>
<div class="chart">
<!-- TODO:待补充代码 -->
<!-- currentMonth 未来七天和本月 tab 切换,只有当前月才显示 -->
<!-- nowMounth是数字,showMonthEN是英文名 -->
<div id="currentMonth" v-show="nowMounth+'月' == monthList[showMonthEN]">
<div class="title">
<h3>{{typeTitle}}</h3>
<div class="type">
<span id="seven" @click="showSeven" :class="{active:typeTitle == '未来七天天气'}">未来7天</span>
<!-- 这里的内容显示时,说明showMonthEN就是本月,所以点击“本月时”直接调用changeMonth(showMonthEN)即可 -->
<span id="current" @click="changeMonth(showMonthEN)" :class="{active:typeTitle == '本月天气'}">本月</span>
</div>
</div>
</div>
<div id="chart"></div>
</div>
</div>
</div>
</body>
</html>
<script>
// TODO:待补充代码
var vm = new Vue({
el: "#app",
data: {
totalData:[], // 全部数据
showMonthEN:'January', // 当前显示的月份英文名
nowMounth:null, // 当前本地月份
chart: null, // 图表
chartOptions: null, // 图表配置项
typeTitle: "本月天气",
monthList: {
January: "1月",
February: "2月",
March: "3月",
April: "4月",
May: "5月",
June: "6月",
July: "7月",
August: "8月",
September: "9月",
October: "10月",
November: "11月",
December: "12月",
},
},
async created(){
// 获取数据
const res = await axios.get('./js/weather.json')
this.totalData = res.data
// 默认更改为一月
this.changeMonth('January')
// 保存当前本地月份
this.nowMounth = new Date().getMonth() + 1
},
mounted: function () {
// 初始化 echarts
this.$nextTick(() => {
this.initChart();
});
},
methods: {
// 显示未来七天的数据
showSeven(){
this.typeTitle = '未来七天天气'
const nowDate = new Date().getDate() // 当前是几号
// Object.values获取的是对象属性值的集合
const nowMouthData = Object.values(this.totalData[this.nowMounth-1])[0] // 当前月的数据
const sevenData = [] // 未来七天的数据
const sevenDate = [] // 未来七天的日期
// 先遍历当前月份数据,填充sevenData
for (let i = nowDate - 1; i < nowMouthData.length; i++) {
sevenData.push(nowMouthData[i])
sevenDate.push(`${this.nowMounth}/${i+1}`)
// 如果数据里已经有了七天的就不用再循环了
if(sevenData.length == 7) break;
}
// 经过上面当前月份数据的填充,如果sevenData中数据少于七条,则继续填充下一个月的数据
if(sevenData.length < 7) {
const nextMouthData = Object.values(this.totalData[this.nowMounth])[0] // 下月的数据
for (let i = 0; i < nextMouthData.length; i++) {
sevenData.push(nextMouthData[i])
sevenDate.push(`${this.nowMounth + 1}/${i+1}`)
// 如果数据里已经有了七天的就不用再循环了
if(sevenData.length == 7) break;
}
}
// 重新设置图标
this.setChart(sevenDate,sevenData)
},
// 更改月份,接收的是需要更改到的月份的英文名
changeMonth(monthEN) {
this.typeTitle = '本月天气'
this.showMonthEN = monthEN
/**
* totalData格式[{January:[25,14,...]},{February:[25,14,...]},...]
* 数组里面嵌套每一个月的对象,对象里有该月对应得英文名属性,该属性值是这个月的数据
* 下面先在totalData中查找具有monthEN属性的对象,也就是monthEN对应月的对象
* 然后从该对象中获取monthEN属性的值,也就是获取monthEN对应月的数据
*/
const data = this.totalData.find(m => m[monthEN])[monthEN] // 数据
// 获得这个月的日期,数组下标 +1 即可
const date = data.map((_,i) => i+1) // 日期
this.setChart(date,data)
},
// 设置图标,xdata,ydata分别代表x轴和y轴的数据
setChart(xdata,ydata){
this.chartOptions.xAxis[0].data = xdata
this.chartOptions.series[0].data = ydata
this.chart.setOption(this.chartOptions);
},
// 下面时题中自带的代码,不用看了
initChart() {
// 初始化图表
this.chart = echarts.init(document.getElementById("chart"));
// 配置项
this.chartOptions = {
grid: {
top: 35,
bottom: 5,
left: 10,
right: 10,
containLabel: true,
},
tooltip: {
trigger: "axis",
axisPointer: {
lineStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "rgba(255,255,255,0)",
},
{
offset: 0.5,
color: "rgba(255,255,255,1)",
},
{
offset: 1,
color: "rgba(255,255,255,0)",
},
],
global: false,
},
},
},
},
xAxis: [
{
type: "category",
boundaryGap: false,
axisLabel: {
formatter: "{value}",
fontSize: 12,
margin: 20,
textStyle: {
color: "#bfbfbf",
},
},
axisLine: {
lineStyle: {
color: "#e9e9e9",
},
},
splitLine: {
show: true,
lineStyle: {
color: "#f7f7f7",
},
},
axisTick: {
show: false,
},
// x 轴显示的数据,日期
data: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
],
},
],
yAxis: [
{
boundaryGap: false,
type: "value",
axisLabel: {
textStyle: {
color: "#bfbfbf",
},
formatter: `{value}\u2103`,
},
nameTextStyle: {
color: "#fff",
fontSize: 12,
lineHeight: 40,
},
splitLine: {
lineStyle: {
color: "#f7f7f7",
},
},
axisLine: {
show: true,
lineStyle: {
color: "#e9e9e9",
},
},
axisTick: {
show: false,
},
},
],
series: [
{
name: "天气",
type: "line",
smooth: false,
showSymbol: false,
symbolSize: 0,
zlevel: 3,
itemStyle: {
color: "#ff6600",
borderColor: "#a3c8d8",
},
lineStyle: {
normal: {
width: 3,
color: "#ff6600",
},
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: "#ff6600",
},
{
offset: 0.8,
color: "#ff9900",
},
],
false
),
},
},
// Y 轴显示的数据,即温度数据
data: [
23, 19, 30, 31, 18, 20, 16, 15, 23, 27, 29, 30, 32, 23, 25, 20,
22, 24, 34, 24, 21, 26, 23, 24, 25, 23, 25, 28, 32, 20,
],
},
],
};
// 调用此方法设置 echarts 数据
this.chart.setOption(this.chartOptions);
},
},
});
</script>
9、JSON生成器(25 分)
2023/5/26 补
这题当初自己没写出来于是就没写题解,现在补一下,感觉时间过的好快,突然发现我之前是真的菜😑
// 定义正则
let reg = /^\{\{(.+)\}\}$/; // 匹配{{..}}
let repeatReg = /^\{\{repeat\(\d+(,\d+)?\)\}\}$/; // 匹配{{repeat(n)}}和{{repeat(n,m)}}
let boolReg = /^\{\{bool\(\)\}\}$/; // 匹配{{bool()}}
let integerReg = /^\{\{integer\(\d+,\d+\)\}\}$/; // 匹配{{integer(n,m)}}
let objReg = [boolReg, integerReg]; // 对象里会用到的所有正则
// 判断value是否符合objReg中的规则
function isConformObjReg(value) {
return objReg.find((r) => r.test(value));
}
// 随机生成布尔值的函数
function bool() {
return Math.random() < 0.5 ? true : false;
}
// 生成n到m之间的随机整数(包含n和m)
function integer(n, m) {
return Math.floor(Math.random() * (m - n + 1) + n);
}
// 获得需要重复的次数,次数在n到m之间,没传递m时次数为n
function repeat(n, m) {
if (!m) return n;
return integer(n, m);
}
/*
* @param {*} 左侧输入框输入的值转化成的 js 数据
* @return {*} 根据传入的数据生成对应的 js 格式数据
*/
let generateData = (data) => {
// TODO:待补充代码
if (typeof data !== "object") {
// 如果data是基础数据类型,不做处理
return data;
}
// 到这里说明data一定是object类型的
let result; // 存放结果
if (Array.isArray(data)) {
// 如果data是数组
result = [];
if (repeatReg.test(data[0])) {
// 数组第一项是{{repeat(...)}}
// 获得需要重复的次数
const nums = eval(reg.exec(data[0])[1]);
for (let i = 0; i < nums; i++) {
// 以数组第二项为基准生成数据,递归调用generateData
result[i] = generateData(data[1]);
}
} else {
// 数组第一项不是{{repeat(...)}},则直接遍历数据对数组每一项进行generateData处理
for (let i = 0; i < data.length; i++) {
result[i] = generateData(data[i]);
}
}
} else {
// 如果data不是数组那就是对象
result = {};
for (const key in data) {
const value = data[key];
if (isConformObjReg(value)) {
// 属性值是{{bool()}}或{{integer(...)}}
// 获得{{和}}之间的匹配的结果,如:"bool()"或"integer(...)""
const fnStr = reg.exec(value)[1];
// 用eval将fnStr字符串当作js代码来运行,如果fnStr为"bool()"则 eval(fnStr)代表运行bool函数
result[key] = eval(fnStr);
} else if (typeof value === "object") {
// 属性值不符合对象允许的正则规则并且属性值是object类型,则递归调用generateData
result[key] = generateData(value);
} else {
// 属性值不符合对象允许的正则规则并且属性值不是object类型,则属性值是基础数据类型,不做处理
result[key] = value;
}
}
}
return result;
};
module.exports = { generateData };
10、商城管理系统(25 分)
// menuList 仅为示例数据,非实际使用数据,实际使用数据层级不确定(可能是四级五级六级等),数据结构与 menuList 一致
// 1. `parentId` 如果为 `-1`,则表示此条数据为顶级数据。
// 2. `parentId` 为该条数据的父级数据的 `id`。
let menuList = [
{ parentId: -1, name: "添加管理员", id: 10, auth: "admin" },
{ parentId: 10, name: "管理员权限分配", id: 11, auth: "admin-auth" },
{ parentId: -1, name: "商品管理", id: 1, auth: "product" },
{ parentId: 1, name: "商品列表", id: 4, auth: "productList" },
{ parentId: 4, name: "商品分类", id: 5, auth: "category" },
{ parentId: 5, name: "添加分类", id: 8, auth: "addClassification" },
{ parentId: 4, name: "商品上架", id: 6, auth: "product" },
{ parentId: -1, name: "评论管理", id: 2, auth: "comments" },
{ parentId: -1, name: "个人中心", id: 3, auth: "profile" },
];
/**
* @param {*} menuList 传入的数据
* @return {*} menus 转化后的树形结构数据,auths 转化后的权限列表数组
*/
const getMenuListAndAuth = (menuList) => {
// TODO:待补充代码
// 使用map映射获取auth列表
const auths = menuList.map(item => item.auth)
/**
* 定义一个递归函数,根据父级id查找这个父级id的子项
* @param {Number} parentId 父级id
* @param {Array} list 数据列表
* @returns 父级id为parentId的所有数据的集合
*/
function getListByParentId(parentId,list) {
let result = [] // 结果数组
// 遍历数据列表
list.forEach(item => {
if(item.parentId == parentId) {
// 当前项的父级id满足条件就将它加入到结果数组中
result.push(item)
// 然后递归调用查询当前项的子项并赋值给自身的children属性
item.children = getListByParentId(item.id,list)
}
});
return result
}
const menus = getListByParentId(-1,menuList)
return { menus, auths }; // menus 转化后的树形结构数据,auths 转化后的权限列表数组
};
// 请勿删除和修改以下代码
try {
module.exports = { getMenuListAndAuth };
} catch (e) {}
总结心得
如果说之前省赛是一场大水,这次国赛就是实实在在的旱田了,不含一点水分(当时考的时候是这样感觉的),还记得当时刚开考看到第一题先要排序,我立马就想到了数组原型上有自带的排序方法,但讽刺的是我忘记了它是哪个,log
打印了Array.prototype
,然后看着哪个像我就试哪一个,但最终一看时间已经过去半小时了,我急了,不得已采用冒泡排序这种笨但很简单的方法
就这样我在想api
上浪费了太多时间,究其原因还是我的基础不够牢固
因为省赛太过水了,考前一直感觉可能国赛也就那样吧,考试的时候我也是不慌不忙,慢慢的做,遇到有好法子能实现但是一时半刻想不起api
的我也不跳过,就一直在那想,可时间就这样拖着拖着就没了,当我真正意识到时间不够了,不能再拖的时候,已经晚了。
哎,现在回过头重新做了一遍题,发现我写最后一题的时间还没有考试时在第一题上浪费的时间一半多,考试时因为最后时间不够,最后一题压根就没看,真是讽刺啊。
感谢这次蓝桥杯的经历,让我真正认识到了自己的不足和努力的方向。
谨以此篇记录我这一段失败的经历