这个作业属于哪个课程 | https://bbs.csdn.net/forums/ssynkqtd-05 |
---|---|
这个作业要求在哪里 | https://bbs.csdn.net/topics/617377308 |
这个作业的目标 | 继续完善作业1的计算器,增加功能并且实现前后端分离 |
其他参考文献 |
前言
本次作业的任务目标是在上一个作业的完成的计算器的基础上,增加功能并且实现前后端的分类。本次作业前端依然使用html,css,js,在上一次作业的基础上进行改进,后端选择了django框架进行开发。
一、git仓库链接和代码规范链接
二、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 25 |
· Estimate | · 估计这个任务需要多少时间 | 20 | 15 |
Development | 开发 | 800 | 850 |
· Analysis | · 需求分析 (包括学习新技术) | 70 | 90 |
· Design Spec | · 生成设计文档 | 50 | 40 |
· Design Review | · 设计复审 | 15 | 15 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 50 |
· Design | · 具体设计 | 40 | 50 |
· Coding | · 具体编码 | 500 | 600 |
· Code Review | · 代码复审 | 30 | 33 |
· Test | · 测试(自我测试,修改代码,提交修改 | 250 | 270 |
Reporting | 报告 | 120 | 122 |
· Test Report | · 测试报告 | 20 | 30 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 50 | 65 |
合计 | 2035 | 2257 |
三、成品展示
1.四则运算、取余、括号以及清零回退计算前后端展示
基础
2.错误提示和读取历史记录
报错和历史
3.页面原型设计
4.存款贷款计算
存款
四、设计实现过程
1.前端设计
(1)原有计算器已有基础运算,清零退回,部分科学计算器等功能,在此基础上增加了错误提示和读取历史记录的功能。其中历史记录采用跳转。
(2在原有计算器的界面还补充了利率计算器,可实现的功能有计算存款、贷款利息。
2.后端设计
后端使用python语言,首次学习并采用了Django框架,数据库使用db.sqlite3。
五、代码说明
1.前端
javascript
(1)定义一个lgbut_compute()函数,从前端读取输入需计算的表达式,以字符串形式存储到后端数据库,后端判断是否输入错误,若无误将计算结果保存并返回给前端,若有误返回相应错误
function lgbut_compute() {
var value = document.calculator.display.value;
console.log(value);
fetch('http://127.0.0.1:80/compute/', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: value,
}),
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error)
} else {
document.calculator.display.value = data.frontend_data;
console.log(document.calculator.display.value);
}
})
.catch(error => {
console.error('Error:', error);
});
}
(2)增加ANS按钮,当用户点击该按钮,从后端取出查看历史记录读取最后十个字符串式子和对应的计算结果并返回给前端,前端跳转到new2.html展示数据
document.getElementById('former').addEventListener('click', function () {
try {
var value = document.calculator.display.value;
console.log(value);
fetch('http://127.0.0.1:80/ppp/', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: value,
}),
})
.then(response => response.json())
.then(data => {
document.calculator.display.value = data.frontend_data1;
console.log(document.calculator.display.value);
})
.catch(error => {
console.error('Error:', error);
});
}
catch (error) {
document.calculator.display.value = 'error';
}
});
<a href="new2.html">点此查看更多历史记录</a>
new2.html页面
<style>
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
h1 {
text-align: center;
margin-top: 50px;
}
#history_list {
width: 50%;
margin: 0 auto;
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
</style>
<h1>历史数据</h1>
<ul id="history_list"></ul>
<script>
fetch('http://127.0.0.1:80/history/', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: 1
}),
})
.then(response => response.json())
.then(data => {
if (!Array.isArray(data)) {
var data = [data];
var display = [];
length = Object.keys(data[0]).length;
for (var i = 1; i <= length; i++) {
var input = data[0][i]['c_input'];
var output = data[0][i]['c_output'];
var dis = input + '=' + output;
display.push('记录' + i + ':' + dis)
}
document.getElementById("history_list").innerHTML = display.join('<br>');
}
})
.catch(error => {
console.error('Error fetching data:', error);
});
</script>
(3)增加“存款计算”按钮和存款时间选择器,用户输入存款金额和存款时间,再点击“存款计算”按钮,后端接收存款金额,根据输入的存款时间(字符串类型),在后端数据库找到对应的存款利率,进行计算并将结果返回给前端。
document.getElementById('cunkuan').addEventListener('click', function () {
var value1 = document.calculator.display.value;
var year = document.getElementById('years').value;
console.log(year)
console.log(value1);
fetch('http://127.0.0.1:80/lilv_c/', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: value1,
year: year,
}),
})
.then(response => response.json())
.then(data => {
document.calculator.display.value = data.frontend_data;
console.log(document.calculator.display.value);
})
.catch(error => {
console.error('Error:', error);
});
});
(4)类似存款计算,增加“贷款计算”按钮和存款时间选择器,用户输入贷款金额和贷款时间,再点击“贷款计算”按钮,后端接收贷款金额,根据输入的贷款时间(字符串类型),在后端数据库找到对应的贷款利率,进行计算并将结果返回给前端。
document.getElementById('daikuan').addEventListener('click', function () {
var value = document.calculator.display.value;
var years = document.getElementById('years2').value;
console.log(years)
console.log(value);
fetch('http://127.0.0.1:80/daikuan_c/', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: value,
year: years,
}),
})
.then(response => response.json())
.then(data => {
document.calculator.display.value = data.frontend_data;
console.log(document.calculator.display.value);
})
.catch(error => {
console.error('Error:', error);
});
});
html
新增功能按钮和界面设计
<select id="years" name="fruits"
style="background-color: rgb(206, 221, 240); border-radius:20px;width:100px ;height:25px" font-size:
15px;>
<option value="活期">活期</option>
<option value="三个月">三个月</option>
<option value="半年">半年</option>
<option value="一年">一年</option>
<option value="两年">两年</option>
<option value="三年">三年</option>
<option value="五年">五年</option>
</select>
</input>
<input type="button" value="存款计算" id="cunkuan" onclick=""
style="background-color: rgb(220, 129, 104); font-size: 10px;width: 100px;" font-size: 10px;>
<br><br>
<select id="years2" name="fruits2"
style="background-color: rgb(206, 221, 240); border-radius:10px; width:100px ;height:25px" font-size:
15px;>
<option value="六个月">六个月</option>
<option value="一年">一年</option>
<option value="一至三年">一至三年</option>
<option value="三至五年">三至五年</option>
<option value="五年">五年</option>
</select>
</input>
<input type="button" value="贷款计算" id="daikuan" onclick=""
style="background-color: rgb(231, 195, 111); font-size: 10px;width: 100px;">
</select>
<br><br>
<a href="new2.html">点此查看更多历史记录</a>
<input type="button" value=ANS id="former" class="function" style="background-color: rgb(163, 223, 139); ">
css没有什么大改动,就不再展示了
2.后端
(1)构建表
class Jisuan(models.Model):
c_input = models.CharField(max_length=100)
c_output = models.IntegerField(default=0)
class Meta:
app_label = 'app'
db_table = 'app_jisuan'
class Lilv(models.Model):
field1 = models.CharField(max_length=100)
field2 = models.FloatField()
field3 = models.FloatField(default=0)
class Meta:
app_label = 'app'
db_table = 'app_lilv'
class Daikuan(models.Model):
field1 = models.CharField(max_length=100)
field2 = models.FloatField(0)
class Meta:
app_label = 'app'
db_table = 'app_daikuan'
(2)编写视图函数
def compute(request):
if request.method == 'POST':
data = json.loads(request.body)
if data: # 确保请求体不为空
data1 = data.get('code')
if judge_zero(data1) == False:
return JsonResponse({'error': '0不能作为除数'})
elif judge_parentheses(data1) == False:
return JsonResponse({'error': '括号不匹配'})
else:
comresult = eval(data1)
response_data = {'frontend_data': comresult}
# 前端数据传入后端数据库
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
# 插入数据
cursor.execute("INSERT INTO app_jisuan (c_input,c_output) VALUES (?,?)", (data1, comresult))
# 提交更改并关闭连接
conn.commit()
conn.close()
return JsonResponse(response_data)
else:
return JsonResponse({'error': '请求体为空'})
else:
return JsonResponse({'error': '请求方法不是POST1'})
def judge_zero(data):
parts = data.split('/')
if len(parts) < 2:
return True #正确
return False # 错误
def judge_parentheses(s):
# 匹配开括号 '(' 和闭括号 ')'
pattern = r'\(|\)'
matches = re.findall(pattern, s)
if len(matches) % 2 != 0:
return False
def lilv_c(request):
if request.method == 'POST':
data = json.loads(request.body)
data1=data['code']
t1=float(eval(data1))
print(type(t1))
float_nums = t1
# float_nums = float(data1)
data2=data['year']
if data1: # 确保请求体不为空
data0 = data.get('code')
data2 = data.get('year')
try:
instance = Lilv.objects.get(field1=data2)
# return instance.field2
f2 = instance.field2
f3=instance.field3
r_lilv=float_nums*f2*f3
except Lilv.DoesNotExist:
return None
response_data = {'frontend_data': r_lilv}
return JsonResponse(response_data)
else:
return JsonResponse({'error': '请求体为空'})
else:
return JsonResponse({'error': '请求方法不是POST1'})
def daikuan_c(request):
if request.method == 'POST':
data = json.loads(request.body)
data1=data['code']
t1=float(eval(data1))
float_nums = t1
# float_nums = float(data1)
data2=data['year']
if data1: # 确保请求体不为空
data0 = data.get('code')
data2 = data.get('year')
try:
instance = Daikuan.objects.get(field1=data2)
# return instance.field2
f2 = instance.field2
r_lilv=float_nums*f2
except Daikuan.DoesNotExist:
return None
response_data = {'frontend_data': r_lilv}
return JsonResponse(response_data)
else:
return JsonResponse({'error': '请求体为空'})
else:
return JsonResponse({'error': '请求方法不是POST1'})
def history(request):
if request.method == 'POST':
latest_data = Jisuan.objects.order_by('-id')[:10]
data_list = []
for item in latest_data:
data_list.append({'c_input':item.c_input,'c_output': item.c_output})
keys = ['1', '2', '3' , '4' ,'5','6','7','8','9','10']
wrapped_dict = {key: value for key, value in zip(keys, data_list)}
return JsonResponse(wrapped_dict, safe=False)
else:
return JsonResponse({'error': '请求方法不是POST3'})
def ppp(request):
if request.method == 'POST':
connection = sqlite3.connect('db.sqlite3')
cursor = connection.cursor()
# 查询最新一行数据
# timestamp = time.time()
query = "SELECT c_output FROM app_jisuan ORDER BY id DESC LIMIT 1"
print(query,3456678900)
cursor.execute(query)
# 获取查询结果
ans = cursor.fetchone()
print(ans,'23445')
# 将数据ans送至前端
response_data = {'frontend_data1': ans}
# 关闭游标和连接
cursor.close()
connection.close()
return JsonResponse(response_data)
else:
return JsonResponse({'error': '请求方法不是POST2'})
(3)构建URL
from django.contrib import admin
from django.urls import path
from app import views
from app.views import *
urlpatterns = [
path("admin/", admin.site.urls),
path('compute/', compute, name='compute'),
path('lilv_c/', lilv_c, name='lilv_c'),
path('daikuan_c/', daikuan_c, name='daikuan_c'),
path('history/', history, name='history'),
path('ppp/', ppp, name='ppp'),
# 其他 URL 配置
]
六、心路历程和收获
在此次作业中,我开始了解Django框架的使用,并且首次尝试使用它来进行后端开发,在数日的努力下我完成一个虽然简陋但是比较完整的计算器,完整地熟悉了开发的整个流程,对于程序的调试能力也有了提升。不论是代码的编写还是在gitcode的仓库的创建,和第一次作业时相比(第一次作业在单元测试花太多时间,导致最后在gitcode提交太匆忙格式完全乱套了呜呜),都有了较大的进步。
不得不承认的是还有太多太多太多不足,在编写代码规范时我意识到自己的代码虽然可以达到最终目的,但有很多不规范之处,比如没有将前端三件套分开编写,而是都写在了html里,style的插入也非常随意;后端也是为了达到目的而没有顾及较多编写规范。这是第一次代码不合规导致的,在此基础上的延伸也就不尽人意,因为这次任务我中心放在了后端的开发学习上,所以对前端的开发也就没有时间做过多改进。作为第一次后端开发,我花了较多时间进行学习然后通过向有经验的同学学习,较快地上了手,但我的开发知识还非常匮乏,很多地方都没有完全理解只是借鉴一些网上的零零散散的经验。在之后的时间里我还会继续学习,尽可能更自主地编写更加规范的代码。