第十五届蓝桥杯(Web 应用开发)模拟赛 2 期-大学组(详细分析解答)

目录

 1.相不相等

1.1 题目要求

1.2 题目分析

1.3 源代码

2.三行情书

2.1 题目要求

2.2 题目分析

2.3 源代码

3.电影院在线订票

3.1 题目要求

3.2 题目分析

3.3 源代码

 4.老虎坤(不然违规发不出来)

4.1 题目要求

4.2 题目分析

4.3 源代码

5.星际通讯

5.1 题目要求

5.2 题目分析

5.3 源代码

6.蓝桥杯排位

6.1 题目要求

6.2 题目分析

7.拼出一个未来

8.超能英雄联盟

9.实时展示权限日志

10.账户验证


刚做完第一期的模拟题目,第二期又开始发布了,花了点时间做完了,分享下自己的解题思路。

 1.相不相等

1.1 题目要求

请你编写一个名为 expectFn 的函数,用于帮助开发人员测试他们的代码。它可以通过参数 val 接受任何值,并返回一个对象,该对象包含下面两个函数:

  • toBe(val):接受另一个值并在两个值相等( === )时返回 true 。如果它们不相等,则返回 "Not Equal" 。
  • notToBe(val):接受另一个值并在两个值不相等( !== )时返回 true 。如果它们相等,则返回 "Equal" 。

1.2 题目分析

题目要求写的很清楚了,按照其要求做判断条件即可

1.3 源代码

var expectFn = function (val) {
  // TODO
  return {
    toBe: function (value) {
      if (val === value) {
        return true
      } else {
        return 'Not Equal'
      }
    },
    notToBe: function (value) {
      if (val !== value) {
        return true
      } else {
        return 'Equal'
      }
    }
  }
}

2.三行情书

2.1 题目要求

请完善 style.css 的 TODO 部分,具体要求如下:

  1. 让第一行标题即 .content span 标签中的文字单行显示,多余溢出显示省略号。
  2. 请使用 -webkit-box 语法使得下面的文字即 .content p 标签里的内容显示三行,多余溢出显示省略号。

2.2 题目分析

这里主要是如果写过案例的话,应该就知道怎么写,需要注意的是span元素是单行元素,要想达到效果,需要将其变为块级元素。

2.3 源代码

span {
    font-size: 20px;
    color: #837362;
    /* TODO:补充下面的代码 */
    /* 单行显示,多余溢出省略号 */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
    /* 使得溢出部分显示省略号 */
}

p {
    color: #837362;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    /* 显示的行数 */
    overflow: hidden;
}

3.电影院在线订票

3.1 题目要求

  1. 实现异步数据读取和渲染功能,使用 axios 请求 ./data.json(必须使用该路径请求,否则可能会请求不到数据)的数据。
    • 将电影名字 name 渲染到 id 为 movie-name 的节点中。
    • 将电影售价 price 渲染到 id 为 movie-price 的节点中。
    • 将座位信息 seats 渲染到 id 为 seat-area 的节点中,二维数组中每一个子数组代表一行,0 代表没有被他人占位,1 代表已经被订购。
  2. 实现座位选择和总价计算的功能:
    • 被别人订过的座位不能再被选择。
    • 座位被选中后,状态更新,为相应的座位添加选中样式(即 selected),并更新已选择的座位数和总价。
    • 自己所选择的座位可以被取消,并更新已选择的座位数和总价。

3.2 题目分析

  • 第一点是使用axios发送请求获取到数据,这个不会的可以参考一下axios官网的案例学习一下
  • 第二个是根据拿到的数据渲染html的结构,这个的就是创建对应的html结构,最后添加到对应的节点。
  • 第三个是实现作为选择的功能,实现思路就是给所有的座位都绑定一个点击事件,通过事件对象身上是否被选中来替换类名,然后就是渲染数量。

3.3 源代码

/* TODO: 
      1. 完成数据请求,生成电影名,价格以及座位情况
      2. 绑定点击事件,实现订票功能
 */

let data = {}
axios
  .get('../data.json')
  .then((res) => {
    console.log(res)
    data = res.data
    movieNameNode.innerHTML = data.name
    moviePriceNode.innerHTML = data.price
    //创建节点渲染数据
    data.seats.forEach((item) => {
      let row = document.createElement('div')
      row.className = 'row'
      item.forEach((item) => {
        let seat = document.createElement('div')
        seat.className = 'seat'
        row.appendChild(seat)
        if (item) {
          seat.classList.add('occupied')
        }
      })
      seatAreaNode.appendChild(row)
    })
  })
  .catch((err) => {
    console.log(err)
  })

// 获取座位区域节点
const seatAreaNode = document.getElementById('seat-area')
// 获取电影名节点
const movieNameNode = document.getElementById('movie-name')
// 获取电影票价节点
const moviePriceNode = document.getElementById('movie-price')
// 获取已订电影票数量节点
const count = document.getElementById('count')
// 获取已订电影票总价节点
const total = document.getElementById('total')

// 获取所有座位节点
const seatNodes = document.querySelectorAll('.seat')
// 初始化已选择座位数和总价
let selectedSeatsCount = 0
let totalPrice = 0

// 监听座位点击事件
seatAreaNode.addEventListener('click', (event) => {
  const clickedSeat = event.target

  // 检查是否点击的是座位
  if (clickedSeat.classList.contains('seat') && !clickedSeat.classList.contains('occupied')) {
    // 切换座位的选中状态
    clickedSeat.classList.toggle('selected')

    // 更新已选择座位数和总价
    if (clickedSeat.classList.contains('selected')) {
      selectedSeatsCount++
      totalPrice += data.price
    } else {
      selectedSeatsCount--
      totalPrice -= data.price
    }

    // 更新显示
    updateDisplay()
  }
})

// 更新显示函数
function updateDisplay() {
  count.textContent = selectedSeatsCount
  total.textContent = totalPrice 
}

 4.老虎坤(不然违规发不出来)

4.1 题目要求

找到 js/index.js 中的 GetResult 函数,完成此函数,实现以下目标:

点击开始后,可以通过 GetResult的三个参数 r1r2r3 计算出滚动后每一列图片的停留位置。当最后停留的图片都相同时,意味着玩家中了大奖!文字框(class = textPanel)显示“恭喜你,中奖了”,否则显示:“很遗憾,未中奖”。

参数介绍:r1r2r3 表示的是三列元素下的 li 的最后停留位置,分别对应第一列(id=sevenFirst)、第二列(id=sevenSecond)、第三列(id=sevenThird)。以第一列为例,最终显示的元素是 sevenFirst 下的第 r 个 li 元素。请使用显示的 li 元素的 data-point 属性判断三张图片是否相同。当 data-point 属性对应的值相同时,说明这三张图片相同。

4.2 题目分析

这一题很明确的考察点就是获取元素身上的属性,需要用到getAttribute()方法,通过获取到的属性对比是否一样,如果三个相同则中奖。

4.3 源代码

if (sevenFirst.children[r1 - 1].getAttribute('data-point') == sevenSecond.children[r2 - 1].getAttribute('data-point') 
&& sevenFirst.children[r1 - 1].getAttribute('data-point') == sevenThird.children[r3 - 1].getAttribute('data-point')) {
      textPanel.innerHTML = '恭喜你,中奖了'
    } else {
      textPanel.innerHTML = '很遗憾,未中奖'
    }

5.星际通讯

5.1 题目要求

完善 index.js 中的 translate 函数,完善其中的 TODO 部分:

translate 函数接收一个字符串参数 alienMessage,其中包含一系列外星人的密文。函数根据特定的翻译规则将密文翻译成人类语言,并返回翻译后的结果字符串。外星人密文翻译规则存放在 codonTable 变量中。

5.2 题目分析

这个题目就是js的切割 遍历 

5.3 源代码

// 密语规则
const codonTable = {
  IIX: '人类',
  VII: '哈喽',
  III: '你好',
  IXI: '赞',
  XVI: '嗨',
  CUV: '打击',
  XII: '夜晚',
  IVI: '我',
  XIC: '想',
  XIV: '交个朋友',
  VIX: '月亮',
  XCI: '代码',
  XIX: '祈福',
  XVI: '和',
  XXI: 'stop'
}

/**
 * @param {string} alienMessage 外星人的密文
 * @return {string}  翻译结果
 */
const translate = (alienMessage) => {
  // TODO:待补充代码
  // 检查密文是否为空
  if (!alienMessage) {
    return ''
  }

  // 切分密文
  const codons = []
  for (let i = 0; i < alienMessage.length; i += 3) {
    codons.push(alienMessage.slice(i, i + 3))
  }
  // 初始化翻译结果
  let translation = ''

  // 遍历密文
  for (const codon of codons) {
    // 检查是否为停止符号
    if (codon === 'XXI') {
      break
    }

    // 查找翻译表
    const translationResult = codonTable[codon]

    // 如果找到翻译结果,则添加到最终结果中
    if (translationResult) {
      translation += translationResult
    } else {
      // 未找到对应翻译结果,返回无效密语
      return '无效密语'
    }
  }
  return translation
}
// 请注意:以下代码用于检测,请勿删除。
try {
  module.exports = translate
} catch (e) {}

6.蓝桥杯排位

6.1 题目要求

  1. 根据请求的数据正确完成左侧热力地图。
  2. 右侧战力榜中柱形图中,根据 power 字段的值对所有学校进行排序,取出排在前 10 名的学校,从左到右降序排列。
  3. 完成数据请求(数据来源 ./mock/map.json),map.json 中存放的数据为省市对应的学校数据

6.2 题目分析

根据要求获取数据,然后替换options中的配置即可

const { createApp, ref, onMounted } = Vue
const app = createApp({
  setup() {
    const chartsData = ref([])
    onMounted(() => {
      // TODO:待补充代码 请求数据,并正确渲染柱形图和地图
      axios
        .get('../mock/map.json')
        .then((res) => {
          chartsData.value = res.data
          showChartBar()
          showChinaMap()
        })
        .catch((err) => {
          console.log(err)
        })
    })
    // 展示柱状图
    const showChartBar = () => {
      const myChart = echarts.init(document.getElementById('chart'))

      let data = chartsData.value.map((item, index) => {
        return item.school_power
      })
      console.log(data)
      let result = data.flat(1).sort((a, z) => {
        return z.power - a.power
      })
      let arr = result.slice(0, 10)
      let school = arr.map((item) => {
        return item.name
      })
      let power = arr.map((item) => {
        return item.power
      })
      console.log(school)
      console.log(power)
      // 指定配置和数据
      const option = {
        xAxis: {
          type: 'category',
          axisLabel: { interval: 0, rotate: 40 },
          // TODO:待修改  柱状图 x 轴数据 -> 前 10 学校名称
          data: school
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        yAxis: {
          type: 'value',
          boundaryGap: [0, 0.01]
        },
        series: [
          {
            // TODO:待修改   柱状图 y 轴数据->学校战力值
            data: power,
            type: 'bar',
            showBackground: true,
            backgroundStyle: {
              color: 'rgba(180, 180, 180, 0.2)'
            },
            itemStyle: {
              color: '#8c7ae6'
            }
          }
        ]
      }

      // 把配置给实例对象
      myChart.setOption(option)
      // 根据浏览器大小切换图表尺寸
      window.addEventListener('resize', function () {
        myChart.resize()
      })
    }

    // 展示地图
    const showChinaMap = () => {
      const chinaMap = echarts.init(document.getElementById('chinaMap'))

      // 进行相关配置
      const mapOption = {
        tooltip: [
          {
            backgroundColor: '#fff',
            subtext: 'aaa',
            borderColor: '#ccc',
            padding: 15,
            formatter: (params) => {
              return params.name + '热度值:' + params.value + '<br>' + params.data.school_count + '所学校已加入备赛'
            },
            textStyle: {
              fontSize: 18,
              fontWeight: 'bold',
              color: '#464646'
            },
            subtextStyle: {
              fontSize: 12,
              color: '#6E7079'
            }
          }
        ],
        geo: {
          // 这个是重点配置区
          map: 'china', // 表示中国地图
          label: {
            normal: {
              show: false // 是否显示对应地名
            }
          },
          itemStyle: {
            normal: {
              borderColor: 'rgb(38,63,168)',
              borderWidth: '0.4',
              areaColor: '#fff'
            },
            emphasis: {
              //鼠标移入的效果
              areaColor: 'rgb(255,158,0)',
              shadowOffsetX: 0,
              shadowOffsetY: 0,
              shadowBlur: 20,
              borderWidth: 0,
              shadowColor: 'rgba(0, 0, 0, 0.5)'
            }
          }
        },
        visualMap: {
          show: true,
          left: 'center',
          top: 'bottom',
          type: 'piecewise',
          align: 'bottom',
          orient: 'horizontal',
          pieces: [
            {
              gte: 80000,
              color: 'rgb(140,122,230)'
            },
            {
              min: 50000,
              max: 79999,
              color: 'rgba(140,122,230,.8)'
            },
            {
              min: 30000,
              max: 49999,
              color: 'rgba(140,122,230,.6)'
            },
            {
              min: 10000,
              max: 29999,
              color: 'rgba(140,122,230,.4)'
            },
            {
              min: 1,
              max: 9999,
              color: 'rgba(140,122,230,.2)'
            }
          ],
          textStyle: {
            color: '#000',
            fontSize: '11px'
          }
        },
        series: [
          {
            type: 'map',
            geoIndex: 0,
            // TODO:待修改 地图对应数据
            data: chartsData.value.map((item) => {
              return {
                name: item.name,
                school_count: item.school_count,
                value: item.value
              }
            })
          }
        ]
      }

      // 把配置给实例对象
      chinaMap.setOption(mapOption)
    }

    return {
      chartsData,
      showChartBar,
      showChinaMap
    }
  }
})

app.mount('#app')

7.拼出一个未来

题目要求和分析就不写了 ,代码中给了注释

// 声明一个数组,包含了所有的拼图块数据
var puzzlePieces = [
  { src: './images/img1.png', id: 1 },
  { src: './images/img2.png', id: 2 },
  { src: './images/img3.png', id: 3 },
  { src: './images/img4.png', id: 4 },
  { src: './images/img5.png', id: 5 },
  { src: './images/img6.png', id: 6 },
  { src: './images/img7.png', id: 7 },
  { src: './images/img8.png', id: 8 },
  { src: './images/img9.png', id: 9 }
]

// 定义一个打乱数组的函数
function shuffleArray(array) {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[array[i], array[j]] = [array[j], array[i]]
  }
  return array
}

// 使用定义的函数打乱拼图块数组
puzzlePieces = shuffleArray(puzzlePieces)

// 获取拼图容器元素
var container = document.getElementById('puzzle-container')

// 遍历拼图块数据数组
puzzlePieces.forEach(function (pieceData) {
  // 创建一个新的拼图块元素
  var piece = document.createElement('div')
  piece.classList.add('puzzle-piece')
  piece.setAttribute('draggable', 'true')

  // 创建一个新的图片元素
  var image = document.createElement('img')
  image.src = pieceData.src
  image.dataset.id = pieceData.id

  // 将图片元素添加到拼图块元素中
  piece.appendChild(image)

  // 将拼图块元素添加到父容器元素中
  container.appendChild(piece)
})

// 获取所有的拼图块元素,并转换为数组
const puzzleArray = Array.from(document.querySelectorAll('.puzzle-piece'))

// 获取成功消息元素
const successMessage = document.getElementById('success-message')

// 为每个拼图块元素添加拖拽事件监听器
puzzleArray.forEach((piece) => {
  piece.addEventListener('dragstart', dragStart)
  piece.addEventListener('dragover', dragOver)
  piece.addEventListener('drop', drop)
})

// 声明一个变量用来保存正在拖动的拼图块
let draggedPiece = null

// 定义开始拖动事件的处理函数
function dragStart(event) {
  draggedPiece = this
  event.dataTransfer.setData('text/plain', null)
}

// 定义在拖动过程中的处理函数,阻止默认行为
function dragOver(event) {
  event.preventDefault()
}

// 定义拖放事件的处理函数
function drop(event) {
  // 检查是否拖动的拼图块不是当前目标拼图块
  // draggedPiece 被拖动的拼图块元素。this 目标位置的拼图块元素。
  let num = 0
  if (draggedPiece !== this) {
    // TODO:待补充代码
    // 交换图片的 src 属性和 data-id 属性
    let tempSrc = draggedPiece.querySelector('img').src
    let tempDataId = draggedPiece.querySelector('img').dataset.id

    draggedPiece.querySelector('img').src = this.querySelector('img').src
    draggedPiece.querySelector('img').dataset.id = this.querySelector('img').dataset.id

    this.querySelector('img').src = tempSrc
    this.querySelector('img').dataset.id = tempDataId

    // 检查是否拼图成功
    puzzleArray.forEach((item, index) => {
      if (parseInt(item.children[0].getAttribute('data-id')) === index + 1) {
        num++
      }
    })
    if (num === 9) {
      successMessage.classList.remove('hide')
      successMessage.classList.add('show')
    } else {
      successMessage.classList.remove('show')
      successMessage.classList.add('hide')
    }
    // 重置正在拖动的拼图块
    draggedPiece = null
  }
}

8.超能英雄联盟

HeroList:

// TODO:补全代码,实现目标效果
const HeroList = {
  template: `
  <div class="hero-list">
    <h2>可选英雄</h2>
    <ul>
      <li class="hero-item" v-for="(item,index) in store.heroes" :key="item.id">
        <span>{{item.name}}</span>
        <span>{{item.ability}}</span>
        <span>{{item.strength}}</span>
        <button @click=store.add(item.id) :disabled="item.btn">{{ item.btn ?  '已添加' : '添加至队伍' }}</button>
      </li>
    </ul>
  </div>
  `,
  setup() {
    //第一步获取数据
    const store = useHeroStore()
    axios
      .get('./js/heroes.json')
      .then((res) => {
        store.heroes = res.data
      })
      .catch((err) => {
        console.log(err)
      })
    return {
      store
    }
  }
}
// TODOEnd

TeamList:

// TODO:补全代码,实现目标效果
const TeamList = {
  template: `
  <div class="team-list">
      <h2>我的队伍</h2>
      <ul>
        <li class="team-item" v-for="(item,index) in store.team" :key="item.id">
          <span>{{item.name}}</span>
          <span>{{item.strength}}</span>
          <button @click=store.removeHero(item.id)>移除</button>
        </li>
      </ul>
      <button class="sort-button" @click=store.sort>按实力排序</button>
      <p class="total-strength">当前队伍战斗力:{{store.totalStrength}} </p>
  </div>
  `,
  setup() {
    const store = useHeroStore()
    return {
      store
    }
  }
}
// TODOEnd

store.js:

const { defineStore } = Pinia
const { ref } = Vue

const useHeroStore = defineStore('hero', {
  state: () => ({
    heroes: [], //英雄列表
    team: [] // 队伍列表
  }),
  // TODO:补全代码,实现目标效果
  getters: {
    //计算出战力总和strength
    totalStrength() {
      return this.team.reduce((total, hero) => {
        return total + hero.strength
      }, 0)
    }
  },
  actions: {
    add(id) {
      this.heroes[id - 1].btn = true
      this.team.push(this.heroes[id - 1])
    },
    removeHero(id) {
      this.heroes[id - 1].btn = false
      //移出team中的元素
      this.team = this.team.filter((hero) => hero.id !== id)
    },
    sort() {
      //按照实力排序strength
      this.team.sort((a, b) => {
        return b.strength - a.strength
      })
    }
  }
  // TODOEnd
})

9.实时展示权限日志

这个题目我不知道为啥,明明在线测试基本上满足题目要求了,但是就是不能完全通过

node.js:

/**
 * 请完成下面的 TODO 部分,其他代码请勿改动
 */
const fs = require('fs')
const http = require('http')
const path = require('path')
const dataUrl = path.resolve(__dirname, '../data.json')
const loggerUrl = path.resolve(__dirname, '../logger.json')
// 获取唯一的id
function getLoggerId() {
  return Buffer.from(Date.now().toString()).toString('base64') + Math.random().toString(36).substring(2)
}

/**
 * 该方法统一了服务器返回的消息格式,并返回给客户端
 * @param {*} res 响应 response
 * @param {*} code 状态码,默认为 0 代表没有错误,如果有错误固定为 404
 * @param {*} msg 错误消息,固定为空字符串即可 ''
 * @param {*} data 响应体,为 js 对象,若 data 为 utf-8 编码时需要使用 eval(data) 处理
 */
function send(res, code, msg, data) {
  const responseObj = {
    code,
    msg,
    data
  }
  const da = JSON.stringify(responseObj)
  res.setHeader('Content-Type', 'application/json;charset=utf-8')
  res.write(da)
  res.end()
}

function handleStatic(res, pathName, part) {
  const content = fs.readFileSync(path.resolve(__dirname, pathName))
  let contentType = 'text/html'
  switch (part) {
    case 'css':
      contentType = 'text/css'
      break
    case 'js':
      contentType = 'text/js'
      break
  }
  res.writeHead(200, 'Content-Type', contentType)
  res.write(content)
  res.end()
}

const server = http.createServer((req, res) => {
  res.setHeader('Access-Control-Allow-Origin', '*')
  if (req.url === '/') {
    handleStatic(res, '../index.html', '')
  } else if (req.url === '/css/index.css') {
    handleStatic(res, `..${req.url}`, 'css')
  } else if (req.url === '/js/index.js') {
    handleStatic(res, `..${req.url}`, 'js')
  } else if (req.url === '/js/axios.min.js') {
    handleStatic(res, `..${req.url}`, 'js')
  } else if (req.url === '/js/vue3.global.min.js') {
    handleStatic(res, `..${req.url}`, 'js')
  }

  if (req.method === 'GET' && req.url === '/users') {
    // TODO 处理获取文件内容的操作
    //读取data.json中的数据
    let fileContent = fs.readFileSync(dataUrl, 'utf-8')
    let data = JSON.parse(fileContent)
    if (fileContent) {
      //将读取到的数据转化为json格式
      //将json格式的数据响应给客户端
      send(res, 0, '', data)
    }
  } else if (req.method === 'PUT' && req.url === '/editUser') {
    let fileContent = fs.readFileSync(dataUrl, 'utf-8')
    let data = JSON.parse(fileContent)
    let body = ''
    req.on('readable', () => {
      let chunk = ''
      if (null !== (chunk = req.read())) {
        body += chunk
      }
    })
    req.on('end', () => {
      if (body) {
        // TODO 处理更改文件数据并将最新的文件数据响应给客户端
        //处理put请求
        let bodyData = JSON.parse(body)
        //修改data.json中的数据
        data.forEach((item) => {
          if (item.id == bodyData.id) {
            item.power = bodyData.power
          }
        })
        //存储文件数据到data.json中
        fs.writeFileSync(dataUrl, JSON.stringify(data))
        send(res, 0, '', data)
      }
    })
  } else if (req.method === 'POST' && req.url === '/logger') {
    let body = ''
    req.on('readable', () => {
      let chunk = ''
      if (null !== (chunk = req.read())) {
        body += chunk
      }
    })
    req.on('end', () => {
      let fileContentLog = fs.readFileSync(loggerUrl, 'utf-8')
      //判断是否有日志
      let dataLog = []
      if (fileContentLog) {
        dataLog = JSON.parse(fileContentLog)
      }
      let fileContentUser = fs.readFileSync(dataUrl, 'utf-8')
      let dataUser = JSON.parse(fileContentUser)
      if (body) {
        // TODO 处理新增日志
        let bodyData = JSON.parse(body)

        let dataJson = {
          id: getLoggerId(),
          msg: bodyData.data,
          // 时间格式为:2023/6/6 上午8:10:35
          time: `${getTime()}`
        }
        //存储日志
        dataLog.unshift(dataJson)
        // 并在该对象转化成 JSON 格式的末尾添加换行符(如不添加换行符会导致检测不通过)
        fs.writeFileSync(loggerUrl, JSON.stringify(dataLog, null, 2) + '\n')
        send(res, 0, '', dataJson)
      }
    })
  }
})

function getTime() {
  // 获取当前时间
  const currentDate = new Date()
  // 获取年、月、日、时、分、秒
  const year = currentDate.getFullYear()
  const month = currentDate.getMonth() + 1 // 月份是从 0 开始的,所以要加 1
  const day = currentDate.getDate()
  const hours = currentDate.getHours()
  //获取是上午还是下午
  const amPm = hours >= 12 ? '下午' : '上午'
  const minutes = currentDate.getMinutes()
  const seconds = currentDate.getSeconds()
  // 格式化时间
  const formattedTime = `${year}/${month}/${day} ${amPm}${hours}:${minutes}:${seconds}`
  return formattedTime
}

server.listen(8080, () => {
  console.log('Server running on port 8080')
})

index.js:

/**
 * 请完成下面的 TODO 部分,其他代码请勿改动
 */

// 对响应进行统一处理,如果不调用该函数,可能导致判题出错
// 参数为服务器的响应对象
function parseRes(res) {
  return (res.json && res.json()) || res.data
}

const App = {
  setup() {
    const { onMounted } = Vue
    const data = Vue.reactive({
      userList: [], //用户数组
      loggerList: [] //日志数组
    })
    const getPowerText = (power) => {
      return power ? '可以登录' : '禁止登录'
    }
    const handleChange = async (e) => {
      if (e.target.tagName !== 'INPUT') {
        return
      }
      // TODO 处理发送请求修改当前用户的权限并更新一条日志记录
      //处理put请求
      let res = await axios.put(`/editUser`, {
        id: e.target.dataset.id,
        power: e.target.checked
      })
      if (res.status == 200) {
        data.userList = parseRes(res.data)
      } else {
        console.log('修改失败')
      }
      //调用post请求,添加一条修改日志
      //用id找出用户名
      let userName = data.userList.find((item) => item.id == e.target.dataset.id).name
      let postRes = await axios.post('/logger', {
        data: `超级管理员将用户${userName}设置为${getPowerText(e.target.checked)}权限`
      })
      if (postRes.status == 200) {
        //将数据放在数组首
        let a = parseRes(postRes.data)
        data.loggerList.unshift(a)
      } else {
        console.log('添加日志失败')
      }
    }

    // TODO 在页面挂载之前请求用户数据并修改对应的响应数据
    //利用axios获取数据
    const getUserData = async () => {
      let res = await axios.get('/users')
      if (res.status == 200) {
        data.userList = res.data.data
      } else {
        getUserData()
      }
    }
    onMounted(() => {
      getUserData()
    })
    return {
      data,
      handleChange,
      getPowerText,
      getUserData
    }
  }
}
const app = Vue.createApp(App)
app.mount(document.querySelector('#app'))

10.账户验证

<!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/element-plus@2.3.7/index.css">
  <script src="./js/vue3.global.js"></script>
  <script src="./css/element-plus@2.3.7/index.full.js"></script>
  <script type="importmap">
    {
      "imports": {
        "vue-demi": "./js/index.mjs",
        "vue": "./js/vue.esm-browser.prod.js",
        "pinia": "./js/pinia.esm-browser.js"
      }
    }
  </script>
  <script src="./js/pinia.esm-browser.js" type="module"></script>
</head>

<body>
  <!-- app根组件开始 -->
  <div id="app">
    <div class="header">
      <img class="back-btn" src="images/arrow.png" />
      <span id="main_title">使用手机号登录</span>
      <span class="blank"></span>
    </div>
    <component :is="showName"></component>
  </div>
  <!-- app根组件结束 -->

  <!-- phone组件开始 -->
  <template id="phone">
    <div>
      <ul class="phone">
        <span>输入手机号码</span>
        <li>
          <input v-model="phoneVal" type="text" autofocus id="numberInput" />
        </li>
        <li>
          <input v-model="isSure" type="checkbox" name="" id="checkbox" />
          <span>已阅读并同意
            <a href="javascript:;">服务协议</a>
            和
            <a href="javascript:;">隐私保护指引</a>
          </span>
        </li>
        <button id="btn" @click="nextStep">下一步</button>
      </ul>
    </div>
  </template>
  <!-- phone组件结束 -->

  <!-- check组件开始 -->
  <template id="check">
    <ul class="number">
      <span>输入短信验证码</span>
      <li class="hassend">已向
        <i>{{ handlePhoneVal }}</i>
        发送验证码
      </li>
      <li class="code-container">
        <input v-for="(item, index) in verificationCodeInput" :key="index" v-model="item" @input="handleInput(index)"
          @keydown="handleKeyDown(index)" class="code" type="number" min="0" max="9" ref="codeInput{{index}}"
          required />
      </li>
      <a href="javascript:;" id="resend" @click="resendCode">重新发送</a>
    </ul>
  </template>
  <!-- check组件结束 -->

  <!-- success组件开始 -->
  <template id="success">
    <div class="success">
      <ul>
        <div>验证成功!</div>
        <div>5s后将自动跳转</div>
      </ul>
    </div>
  </template>
  <!-- success组件结束 -->
</body>

<script type="module">
  import { createPinia } from 'pinia';
  import { createApp, ref, reactive, provide, inject, onBeforeMount } from 'vue';
  const { ElNotification } = ElementPlus;

  const app = createApp({
    setup() {
      const data = reactive({
        showName: 'phone',
      });

      const code = ref([]);
      const phoneVal = ref('');
      const createCode = function () {
        let res = '';
        function* _create() {
          let count = 0;
          while (++count <= 6) {
            yield Math.floor(Math.random() * 10);
          }
        }
        for (const iterator of _create()) {
          res += iterator;
        }
        return res;
      };

      const handlePhone = (num) => {
        let res = '';
        for (let idx in num) {
          if (idx > 2 && idx < num.length - 2) {
            res += '*';
          } else {
            res += num[idx];
          }
        }
        return res;
      };

      provide('code', code);
      provide('phoneVal', phoneVal);
      provide('createCode', createCode);
      provide('data', data);
      provide('handlePhone', handlePhone);

      return {
        ...data,
      };
    },
  });

  app.use(ElementPlus);
  app.use(createPinia());

  app.component('phone', {
    template: '#phone',
    setup() {
      const isSure = ref('');
      const phoneVal = inject('phoneVal');
      const code = inject('code');
      const createCode = inject('createCode');
      const data = inject('data');

      function verifyPhone(num) {
        if (num.length !== 11) return false;
        return num[0] === '1' && num[1] === '8';
      }

      return {
        isSure,
        phoneVal,
        nextStep() {
          if (!isSure.value)
            return ElNotification({
              title: '发送失败',
              message: '请先阅读并同意下方协议',
              type: 'error',
            });
          if (!verifyPhone(phoneVal.value))
            return ElNotification({
              title: '发送失败',
              message: '无效的手机号码',
              type: 'error',
            });
          code.value = createCode();
          ElNotification({
            title: '发送成功',
            message: '您在验证码为' + code.value,
            type: 'success',
          });
          data.showName = 'check';
        },
      };
    },
  });

  app.component('check', {
    template: '#check',
    setup() {
      const phoneVal = inject('phoneVal');
      const handlePhoneVal = inject('handlePhone')(phoneVal.value);
      const data = inject('data');
      const code = inject('code');
      const createCode = inject('createCode');
      const verificationCodeInput = Array(6).fill('');

      onBeforeMount(() => {
        setTimeout(() => {
          const oCodeIptList = [...document.getElementsByClassName('code')];

          oCodeIptList[0].focus();

          oCodeIptList.map((item) => {
            item.oninput = function () {
              if (item.value) {
                item?.nextElementSibling && item?.nextElementSibling.focus();
              } else {
                item?.previousElementSibling && item?.previousElementSibling.focus();
              }
              trackVal();
            };
          });

          function trackVal() {
            const val = verificationCodeInput.join('');
            if (val.length === 6) {
              if (val === code.value) {
                ElNotification({
                  title: '验证成功',
                  message: '欢迎回来',
                  type: 'success',
                });
                data.showName = 'success';
              } else {
                ElNotification({
                  title: '验证失败',
                  message: '您输入的验证码有误',
                  type: 'error',
                });
                verificationCodeInput.fill('');
                oCodeIptList[0].focus();
              }
            }
          }
        });
      });

      return {
        handlePhoneVal,
        verificationCodeInput,
        handleInput(index) {
          if (index < 5 && verificationCodeInput[index].length === 1) {
            this.$refs[`codeInput${index + 1}`]?.focus();
          } else if (index > 0 && verificationCodeInput[index].length === 0) {
            this.$refs[`codeInput${index - 1}`]?.focus();
          }
          trackVal();
        },
        handleKeyDown(index) {
          if (event.key === 'Backspace' && index > 0) {
            this.$refs[`codeInput${index - 1}`]?.focus();
          }
        },
        trackVal() {
          const val = verificationCodeInput.join('');
          if (val.length === 6) {
            if (val === code.value) {
              ElNotification({
                title: '验证成功',
                message: '欢迎回来',
                type: 'success',
              });
              data.showName = 'success';
            } else {
              ElNotification({
                title: '验证失败',
                message: '您输入的验证码有误',
                type: 'error',
              });
              verificationCodeInput.fill('');
              this.$refs['codeInput0']?.focus();
            }
          }
        },
        resendCode() {
          code.value = createCode();
          ElNotification({
            title: '发送成功',
            message: '您的验证码为' + code.value,
            type: 'success',
          });
        },
      };
    },
  });

  app.component('success', {
    template: '#success',
  });

  app.mount('#app');
</script>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/202121.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mac 聚焦搜索不显示

我是连搜索框都不显示&#xff0c;不是搜索结果显示异常 点右上角的搜索按钮都毫无反应 我检查过快捷键之类的设置&#xff0c;都正常&#xff0c;最后是通过删除文件解决的 cd ~/Library/Preferences/ rm com.apple.Spotlight.plist 重启 mac 参考 Spotlight Search Not W…

“rhdf5filters.so’ not found when install ‘glmGamPoi‘ package

在R中安装glmGamPoi包的时候&#xff0c;出现了如下报错&#xff1a; install.packages(glmGamPoi) 尝试方案一&#xff1a; sudo apt install pkg-config libhdf5-dev安装lighdf5-dev&#xff0c;并将安装路径链接至usr/lib/文件。 locate rhdf5filters.so sudo ln -s /hom…

java-var类型推断的使用时机

写在前面&#xff1a; 在jdk9的时候引入了var关键字&#xff0c;但是这是一把双刃剑&#xff0c;使用的好的话可以简化代码提高可读性&#xff0c;如果使用的不好的话会导致反效果。 文章目录 使用原则推荐使用时机new关键字创建对象类型不重要for循环 不适合与泛型大量结合字…

【Java学习笔记】75 - 算法优化入门 - 马踏棋盘问题

一、意义 1.算法是程序的灵魂&#xff0c;为什么有些程序可以在海量数据计算时&#xff0c;依然保持高速计算? 2.拿老韩实际工作经历来说&#xff0c;在Unix下开发服务器程序&#xff0c;功能是要支持上千万人同时在线&#xff0c;在上线前&#xff0c; 做内测&#xff0c;一…

vuepress-----9、PWA

# 9、PWA 使用babel 的插件形式 [vuepress/pwa,{serviceWorker: true,updatePopup: {message: "New content is available.",buttonText: "Refresh"}}]提供 Manifest 和 icons (opens new window) 拷贝到public目录下 发布后出现 service workers [外链图片…

Spring第三课,Lombok工具包下载,对应图书管理系统列表和登录界面的后端代码,分层思想

目录 一、Lombok工具包下载 二、前后端互联的图书管理系统 规范 三、分层思想 三层架构&#xff1a; 1.表现层 2.业务逻辑层 3.数据层 一、Lombok工具包下载 这个工具包是为了做什么呢&#xff1f; 他是为了不去反复的设置setting and getting 而去产生的工具包 ⚠️工具…

二叉树(判断是否为对称二叉树)

题目&#xff08;力扣&#xff09;&#xff1a; 观察题目&#xff0c;只需判断该二叉树是否对称。 判断二叉树是否对称&#xff0c;就可以换位去判断该二叉树的左子树和右子树是否对称。 这时就可以写一个辅助函数来方便判断。 该函数是判断两颗树是否镜像对称&#xff0c;这…

【华为数通HCIP | 网络工程师】821刷题日记-IS-IS(2)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

Docker—更新应用程序

在本部分中&#xff0c;你将更新应用程序和映像。您还将了解如何停止和移除容器。 一、更新源代码 在以下步骤中&#xff0c;当您没有任何待办事项列表项时&#xff0c;您将把“空文本”更改为“您还没有待办事项&#xff01;在上面添加一个&#xff01;” 1、在src/static/…

电子学会C/C++编程等级考试2022年12月(三级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:鸡兔同笼 一个笼子里面关了鸡和兔子(鸡有2只脚,兔子有4只脚,没有例外)。已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至多有多少只动物。 时间限制:1000 内存限制:65536输入 一行,一个正整数a (a < 327…

分发测试应用平台怎么用之应用详情功能

我的应用 应用功能引导 ●您会看到以下页面&#xff0c;下图为功能的解释方便您的运行 我的应用-详情-应用详情 ●我们点击应用详情数字③&#xff0c;点击应用详情&#xff0c;下图是对详情页的功能介绍。 详情-应用设置 ●详情-应用设置-下图为应用设置的上半部分 ●下图为应…

保障海外业务发展,Coremail提供高效安全的海外通邮服务

11月22日&#xff0c;Coremail举办《全球通邮&#xff1a;如何保障安全、快捷的海外中继服务》直播分享会&#xff0c;直播会上Coremail安全团队和直播嘉宾复旦大学校园信息化办公室徐艺扬老师就海外中继服务进行了深度分享。 ​ 海外通邮困难重重 境外垃圾邮件数量居高不下…

力扣日记11.28-【二叉树篇】二叉树的最小深度

力扣日记&#xff1a;【二叉树篇】二叉树的最小深度 日期&#xff1a;2023.11.28 参考&#xff1a;代码随想录、力扣 111. 二叉树的最小深度 题目描述 难度&#xff1a;简单 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点…

快速入门opencv(python版)

Open Source Computer Vision Library。OpenCV是一个&#xff08;开源&#xff09;发行的跨平台计算机视觉库&#xff0c;可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C 类构成&#xff0c;同时提供了Python、Ruby、MATLAB等语言的…

后端项目连接数据库-添加MyBatis依赖并检测是否成功

一.在pom.xml添加Mybatis相关依赖 在Spring Boot项目中&#xff0c;编译时会自动加载项目依赖&#xff0c;然后使用依赖包。 需要在根目录下pom.xml文件中添加Mybatis依赖项 <!-- Mybatis整合Spring Boot的依赖项 --> <dependency><groupId>org.mybatis.s…

数据结构---树

树概念及结构 1.树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的 有一个特殊的结点&#xff0c…

血的教训---入侵redis并免密登录redis所在服务器

血的教训—入侵redis并免密登录redis所在服务器 今天就跟着我一起来入侵redis并免密登录redis所在服务器吧&#xff0c;废话不多说&#xff0c;我们直接开始吧。 这是一个体系的学习步骤&#xff0c;当然如果基础扎实的话可以继续往下面看 以下都是关联的文章&#xff0c;可以学…

4.6-容器的端口映射

首先&#xff0c;我们来拉取Nginx的image镜像。 docker pull nginx 接下来我们创建一个Nginx的容器。 docker run --name nginx -d nginx 但是&#xff0c;这样启动nginx容器的话我们没法访问。这个时候怎么办呢&#xff1f;就需要将Nginx这个服务暴露给外面的世界。 这时可以使…

【CodeTop】TOP 100 刷题 21-30

文章目录 21. 螺旋矩阵题目描述代码与解题思路 22. 反转链表 II题目描述代码与解题思路 23. 相交链表题目描述代码与解题思路 24. 合并 K 个升序链表题目描述代码与解题思路 25. 字符串相加题目描述代码与解题思路 26. 最长递增子序列题目描述代码与解题思路 27. 重排链表题目描…

删除list中除最后一个之外所有的数据

1.你可以新建一个list List<Integer> listnew ArrayList<>();int i0;while (i<100){list.add(i);}List<Integer> subList list.subList(list.size()-1, list.size());System.out.println("原list大小--"list.size());System.out.println("…