文章目录
1. 基本信息
1.1学生个人信息
姓名 | 学号 |
---|---|
高浩城 | 3121005210 |
江迅舟 | 3121005215 |
1.2作业基本信息
这个作业属于哪个课程 | 课程链接 |
---|---|
这个作业要求在哪里 | 作业要求地址 |
这个作业的目标 | 实现一个自动生成小学四则运算题目的命令行程序 |
1.3 gitcode 地址
2. PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 88 |
· Estimate | · 估计这个任务需要多少时间 | 500 | 506 |
Development | 开发 | 550 | 652 |
· Analysis | · 需求分析 (包括学习新技术) | 30 | 35 |
· Design Spec | · 生成设计文档 | 30 | 20 |
· Design Review | · 设计复审 (和同事审核设计文档) | 20 | 15 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 100 | 120 |
· Design | · 具体设计 | 30 | 52 |
· Coding | · 具体编码 | 300 | 380 |
· Code Review | · 代码复审 | 20 | 20 |
· Test | · 测试 (自我测试,修改代码,提交修改 | 20 | 10 |
Reporting | 报告 | 40 | 40 |
· Test Report | · 测试报告 | 10 | 10 |
· Size Measurement | · 计算工作量 | 20 | 15 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 15 |
合计 | 650 | 780 |
3. 效能分析
使用工具:Lighthouse
4. 设计实现过程
核心算法函数 | 功能 |
---|---|
randomInt | 生成随机数 |
randomFraction | 生成真分数 |
randomOperator | 生成运算符 |
generateExpression | 生成算式 |
isValid | 检查算式是否符合要求 |
generateExercises | 生成题目 |
calculateAnswers | 计算答案 |
5. 代码说明
项目基于 Vite+Vue3+TS 实现:
<script setup lang="ts">
import type { FormInstance, FormItemRule, FormRules, UploadProps, UploadUserFile } from 'element-plus'
import { saveAs } from 'file-saver';
import { ref } from 'vue'
import type { CalFormData } from '@/types/form'
const ruleFormRef = ref<FormInstance>()
const formData = ref<CalFormData>({
quesNum: '',
minNum: '',
maxNum: '',
})
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl)
return
formEl.resetFields()
}
// 生成随机数
const randomInt = (low: number, high: number) => {
return Math.floor(Math.random() * (high - low + 1) + low)
}
// 生成真分数
const randomFraction = (low: number, high: number) => {
const numerator = randomInt(low, high)
const denominator = randomInt(numerator + 1, high)
return `${numerator}/${denominator}`
}
// 生成运算符
const randomOperator = () => {
const operators = ['+', '-', '*', '/']
return operators[randomInt(0, 3)]
}
// 生成算式
const generateExpression = (min: number, max: number) => {
const num = randomInt(min, max)
let expression = num.toString()
const operatorCount = randomInt(1, 3)
for (let i = 0; i < operatorCount; i++) {
const operator = randomOperator()
if (operator === '/') {
const fraction = randomFraction(min, max)
expression += operator + fraction
}
else {
const num = randomInt(min, max)
expression += operator + num
}
}
return expression
}
const calculate = (expression: string) => {
const result = eval(expression)
return Number.isInteger(result) ? result : result.toFixed(2)
}
// 检查算式是否符合要求
const isValid = (expression: any) => {
const reg = /\d+\/\d+/
if (reg.test(expression)) {
// 如果存在真分数,计算其值并检查是否小于1
const fraction = expression.match(reg)[0]
const result = eval(fraction)
if (result >= 1)
return false
}
// 检查是否产生负数
const nums = expression.match(/\d+/g)
const ops = expression.match(/[+\-*/]/g)
let lastNum = nums[0]
for (let i = 1; i < nums.length; i++) {
const op = ops[i - 1]
const num = nums[i]
if (op === '-' && num > lastNum)
return false
lastNum = num
}
return true
}
// 生成题目
const generateExercises = (n: number, min: number, max: number) => {
const exercises = new Set()
while (exercises.size < n) {
const expression = generateExpression(min, max)
if (isValid(expression))
exercises.add(expression)
}
return Array.from(exercises)
}
// 计算答案
const calculateAnswers = (exercises: any[]) => {
const answers = []
for (const expression of exercises) {
const answer = calculate(expression)
answers.push(answer)
}
return answers
}
let questionArr: any = ref([])
let ansArr: any = ref([])
// 数字校验
const validateNum: FormItemRule['validator'] = (rule, value, callback) => {
// 去除空格
const num = value.replace(/\s/g, '')
const regs = /^\d{0,5}$/
if (!regs.test(num))
callback(new Error('数字输入不合法'))
else
callback()
}
// 表单校验
const rules: FormRules = {
quesNum: [
{
required: true,
message: '请输入要生成的数量',
trigger: 'blur',
},
{
validator: validateNum,
message: '请输入正确的数字',
trigger: 'blur',
},
],
minNum: [
{
required: true,
message: '请输入要生成的最小数字',
trigger: 'blur',
},
{
validator: validateNum,
message: '请输入正确的数字',
trigger: 'blur',
},
],
maxNum: [
{
required: true,
message: '请输入要生成的最大数字',
trigger: 'blur',
},
{
validator: validateNum,
message: '请输入正确的数字',
trigger: 'blur',
},
],
}
// 提交表单
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl)
return
formEl.validate((valid) => {
if (valid) {
questionArr.value = generateExercises(formData.value.quesNum, formData.value.minNum, formData.value.maxNum) as any
ansArr.value = calculateAnswers(questionArr.value) as any
}
else
ElMessage.error('请输入正确的数字')
})
}
// 下载题目
const downloadQues = () => {
let str = questionArr.value
let strData = new Blob([str], { type: 'text/plain;charset=utf-8' });
saveAs(strData, "Exercises.txt");
}
// 下载答案
const downloadAns = () => {
let str = ansArr.value
let strData = new Blob([str], { type: 'text/plain;charset=utf-8' });
saveAs(strData, "Answers.txt");
}
// 上传文件
const fileList = ref<UploadUserFile[]>([])
const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
ElMessage.warning(
`The limit is 3, you selected ${files.length} files this time, add up to ${
files.length + uploadFiles.length
} totally`
)
}
const beforeRemove: UploadProps['beforeRemove'] = (uploadFile, uploadFiles) => {
return ElMessageBox.confirm(
`确认删除 ${uploadFile.name} ?`
).then(
() => true,
() => false
)
}
</script>
<template>
<div class="ques-generator">
<el-container>
// 界面结构
......
</el-container>
</div>
</template>
<style lang="scss" scoped>
// 界面样式
......
</style>
6. 测试运行
界面整体
输入参数运行
可生成10000道题目
题目下载及上传功能均实现
7. 项目小结
项目的优点
这个项目基于 Vite+Vue3+TS 实现,使用了 Element-plus 组件库,技术栈较新,使用 TS 也能够大幅提升代码的健壮性。同时,这个项目中进行了较多的前端工程化搭建,例如引入了 eslint+lint-stage+commitlint 对代码的编写和提交进行规范,具体为:使用 Eslint 作为 linter 和 formatter,使用@antfu/eslint-config
提供 Eslint 对 ts、vue、json 等类型文件的解析和代码检查,其中使用 commitlint 的配置 config-conventional
作为提交格式规范,它沿用了 Conventional Commits
中提到的基础规范,并拓展了 commit message 的 type,对这个 type 的解释可以看 Angular 仓库的描述。以上,能够让整个项目更加的规范化和工程化。
项目的不足
项目开发的时间分配不好,导致工期比较紧,代码的性能不高。同时,有一些流程没有完全完善,例如,虽然项目有直接的性能测试,但没有时间写测试代码进行更系统的自动化测试等。
7.1 结对感受
这次的结对编程是一个全新的体验,在项目初期,我们进行了认真的讨论和调研,才最终决定要用的技术。在结对编程中,团队的成员的水平是有高有低的,这其中就会有讨论学习的过程,有思考的碰撞。结对编程中,需要成员之间的互相交流磨合,有分歧要及时提出解决,尽量做到力往一处使。当遇到自己解决不了的问题时,可以虚心向他人学习,提高自己的能力,减小水平差距带来的不便。