完成3月试用问题修改
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,207 +1,209 @@
|
||||
# 本模块主要以项目开始时间、结束时间、轮次开始时间、结束时间计算文档中的各个时间
|
||||
from datetime import timedelta, date
|
||||
from apps.project.models import Project
|
||||
from django.shortcuts import get_object_or_404
|
||||
from ninja.errors import HttpError # 从代码抛出该异常,被ninja截取变为response
|
||||
|
||||
def format_remove_heng(dateT: date) -> str:
|
||||
"""该函数将date对象的横杠-去掉,输出str"""
|
||||
return str(dateT).replace('-', '')
|
||||
|
||||
def times_by_cover_time(cover_time: date) -> dict:
|
||||
"""该函数为每个产品文档根据封面时间,渲染签署页时间、文档变更记录时间"""
|
||||
return {
|
||||
'preparation_time_no_format': cover_time - timedelta(days=2),
|
||||
'preparation_time': format_remove_heng(cover_time - timedelta(days=2)), # 拟制时间:为编制结束时间-2天
|
||||
'inspect_time': format_remove_heng(cover_time - timedelta(days=1)), # 校对时间:为编制时间+1天
|
||||
'auditing_time': format_remove_heng(cover_time),
|
||||
'ratify_time': format_remove_heng(cover_time),
|
||||
'create_doc_time': format_remove_heng(cover_time - timedelta(days=2)),
|
||||
'doc_v1_time': format_remove_heng(cover_time)
|
||||
}
|
||||
|
||||
class DocTime:
|
||||
def __init__(self, project_id: int):
|
||||
self.project = get_object_or_404(Project, id=project_id)
|
||||
# 用户录入时间-项目
|
||||
self.p_start = self.project.beginTime # 被测件接收时间/
|
||||
self.p_end = self.project.endTime # 大纲测评时间周期结束时间/
|
||||
# 遍历轮次时间-多个
|
||||
self.round_count = self.project.pField.count()
|
||||
self.round_time = [] # 轮次按顺序排序
|
||||
for round in self.project.pField.all():
|
||||
self.round_time.append({
|
||||
'start': round.beginTime,
|
||||
'end': round.endTime,
|
||||
'location': round.location
|
||||
})
|
||||
# ~~~~由上面时间二次计算得出时间~~~~ -> TODO:可由用户设置间隔时间!!!!
|
||||
self.dg_bz_start = self.p_start + timedelta(days=1) # 大纲编制开始时间,项目开始时间+1天
|
||||
self.dg_bz_end = self.dg_bz_start + timedelta(days=6) # 大纲编制结束时间,大纲编制开始+6天
|
||||
self.test_sj_start = self.dg_bz_end + timedelta(days=1) # 测评设计与实现时间,在大纲编制结束+1天
|
||||
self.test_sj_end = self.test_sj_start + timedelta(days=5) # 测评设计与实现结束,在开始+5天
|
||||
# ~~~~储存每个文档的cover_time~~~~
|
||||
self.dg_cover_time = self.dg_bz_end
|
||||
self.sm_cover_time = self.test_sj_end
|
||||
self.jl_cover_time = self.round_time[0]['end']
|
||||
self.wtd_cover_time = self.round_time[-1]['end']
|
||||
|
||||
# 该函数生成大纲文档片段-测评时间和地点的时间和地点信息
|
||||
def dg_address_time(self):
|
||||
"""直接返回context去渲染"""
|
||||
# 需要判断round_time是否有值
|
||||
if len(self.round_time) <= 0:
|
||||
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
|
||||
return {
|
||||
'start_year': self.p_start.year,
|
||||
'start_month': self.p_start.month,
|
||||
'end_year': self.p_end.year,
|
||||
'end_month': self.p_end.month,
|
||||
'beginTime_strf': format_remove_heng(self.p_start),
|
||||
'dgCompileStart': format_remove_heng(self.dg_bz_start),
|
||||
'dgCompileEnd': format_remove_heng(self.dg_bz_end),
|
||||
'designStart': format_remove_heng(self.test_sj_start),
|
||||
'designEnd': format_remove_heng(self.test_sj_end),
|
||||
'location': self.round_time[0]['location']
|
||||
}
|
||||
|
||||
# 该函数生成报告文档片段-测评时间和地点【注意使用了dg_address_time -> 所以后续有修改注意前导】
|
||||
def bg_address_time(self):
|
||||
if len(self.round_time) <= 0:
|
||||
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
|
||||
# 先使用大纲的时间行数作为前三行
|
||||
cname = ['首轮测试', '第二轮测试', '第三轮测试', '第四轮测试', '第五轮测试', '第六轮测试', '第七轮测试',
|
||||
'第八轮测试', '第九轮测试', '第十轮测试']
|
||||
dg_address_time = self.dg_address_time()
|
||||
round_time_list = []
|
||||
index = 0
|
||||
for round_dict in self.round_time:
|
||||
one_dict = {
|
||||
'name': cname[index],
|
||||
'start': format_remove_heng(round_dict['start']),
|
||||
'end': format_remove_heng(round_dict['end']),
|
||||
'location': round_dict['location']
|
||||
}
|
||||
index += 1
|
||||
round_time_list.append(one_dict)
|
||||
return {
|
||||
'begin_year': dg_address_time['start_year'],
|
||||
'begin_month': dg_address_time['start_month'],
|
||||
'end_year': dg_address_time['end_year'],
|
||||
'end_month': dg_address_time['end_month'],
|
||||
'begin_time': dg_address_time['beginTime_strf'],
|
||||
'dg_weave_start_date': dg_address_time['dgCompileStart'],
|
||||
'dg_weave_end_date': dg_address_time['dgCompileEnd'],
|
||||
'sj_weave_start_date': dg_address_time['designStart'],
|
||||
'sj_weave_end_date': dg_address_time['designEnd'],
|
||||
'round_time_list': round_time_list,
|
||||
# 测评总结 -> 依据项目结束时间-7 ~ 项目结束时间
|
||||
'summary_start_date': format_remove_heng(self.p_end - timedelta(days=7)),
|
||||
'summary_end_date': format_remove_heng(self.p_end),
|
||||
}
|
||||
|
||||
# 生成报告中测评完成情况 -> 必须依据其他内容生成时间【注意使用了bg_address_time -> 所以后续有修改注意前导】
|
||||
def bg_completion_situation(self):
|
||||
bg_timer_dict = self.bg_address_time()
|
||||
xq_fx_time_end = self.dg_bz_start + timedelta(days=2)
|
||||
ch_time_start = xq_fx_time_end + timedelta(days=1)
|
||||
ch_time_end = self.dg_bz_end
|
||||
if len(self.round_time) < 1:
|
||||
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
|
||||
return {
|
||||
'start_time_year': bg_timer_dict['begin_year'],
|
||||
'start_time_month': bg_timer_dict['begin_month'],
|
||||
'xq_fx_time_start_year': self.dg_bz_start.year,
|
||||
'xq_fx_time_start_month': self.dg_bz_start.month,
|
||||
'xq_fx_time_start_day': self.dg_bz_start.day,
|
||||
'xq_fx_time_end_year': xq_fx_time_end.year, # 需求分析结束时间是大纲编制开始+2
|
||||
'xq_fx_time_end_month': xq_fx_time_end.month,
|
||||
'xq_fx_time_end_day': xq_fx_time_end.day,
|
||||
'ch_start_year': ch_time_start.year,
|
||||
'ch_start_month': ch_time_start.month,
|
||||
'ch_start_day': ch_time_start.day,
|
||||
'ch_end_year': ch_time_end.year,
|
||||
'ch_end_month': ch_time_end.month,
|
||||
'ch_end_day': ch_time_end.day,
|
||||
'sj_start_year': self.test_sj_start.year,
|
||||
'sj_start_month': self.test_sj_start.month,
|
||||
'sj_start_day': self.test_sj_start.day,
|
||||
'sj_end_year': self.test_sj_end.year,
|
||||
'sj_end_month': self.test_sj_end.month,
|
||||
'sj_end_day': self.test_sj_end.day,
|
||||
'end_time_year': self.p_end.year,
|
||||
'end_time_month': self.p_end.month,
|
||||
'exec_start_time_year': self.round_time[0]['start'].year,
|
||||
'exec_start_time_month': self.round_time[0]['start'].month,
|
||||
'exec_start_time_day': self.round_time[0]['start'].day,
|
||||
'exec_end_time_year': self.round_time[0]['end'].year,
|
||||
'exec_end_time_month': self.round_time[0]['end'].month,
|
||||
'exec_end_time_day': self.round_time[0]['end'].day,
|
||||
}
|
||||
|
||||
# 该函数生成最终大纲的时间
|
||||
def dg_final_time(self):
|
||||
cover_time = self.dg_bz_end
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
# 新增给大纲模版10.2章节context
|
||||
context.update(basic_line1=cover_time.strftime("%Y年%m月"), basic_line2=self.p_end.strftime("%Y年%m月"))
|
||||
# 新增给大纲模版10.3.2章节的context
|
||||
sm_context = self.sm_final_time()
|
||||
context.update(sm_end_time=sm_context['preparation_time_no_format'].strftime("%Y年%m月"))
|
||||
return context
|
||||
|
||||
# 该函数生成说明文档的时间 -> 依据项目时间而非用户第一轮填写时间!
|
||||
def sm_final_time(self):
|
||||
cover_time = self.test_sj_end # 封面时间:为大纲时间中“测评设计与实现”结束时间
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 该函数生成记录文档的时间 -> 依据第一轮测试用户填写的事件
|
||||
def jl_final_time(self):
|
||||
if len(self.round_time) < 1:
|
||||
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
|
||||
cover_time = self.round_time[0]['end'] # 封面时间为用户填写第一轮结束时间
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 问题单的时间 -> 依据最后一轮次的结束时间+1天
|
||||
def wtd_final_time(self):
|
||||
if len(self.round_time) < 1:
|
||||
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
|
||||
cover_time = self.round_time[-1]['end']
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 回归测试说明时间 -> 根据第二轮、第三轮...的开始时间
|
||||
def hsm_final_time(self, round_key: str):
|
||||
if len(self.round_time) < int(round_key) + 1:
|
||||
raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成')
|
||||
cover_time = self.round_time[int(round_key)]['start']
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 回归测试记录时间 -> 根据第二轮、第三轮...的结束时间
|
||||
def hjl_final_time(self, round_key: str) -> dict:
|
||||
if len(self.round_time) < int(round_key) + 1:
|
||||
raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成')
|
||||
cover_time = self.round_time[int(round_key)]['end']
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 生成报告非过程时间 -> 根据项目结束时间来定
|
||||
def bg_final_time(self) -> dict:
|
||||
if len(self.round_time) <= 0:
|
||||
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
|
||||
cover_time = self.p_end
|
||||
# 这里做判断,如果项目结束时间/最后一轮结束时间
|
||||
if cover_time < self.round_time[-1]['end']:
|
||||
raise HttpError(500, message='项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
# 本模块主要以项目开始时间、结束时间、轮次开始时间、结束时间计算文档中的各个时间
|
||||
from datetime import timedelta, date
|
||||
from apps.project.models import Project
|
||||
from django.shortcuts import get_object_or_404
|
||||
from ninja.errors import HttpError # 从代码抛出该异常,被ninja截取变为response
|
||||
from utils.codes import PROJECT_ENDTIME_ERROR_CODE
|
||||
|
||||
def format_remove_heng(dateT: date) -> str:
|
||||
"""该函数将date对象的横杠-去掉,输出str"""
|
||||
return str(dateT).replace('-', '')
|
||||
|
||||
def times_by_cover_time(cover_time: date) -> dict:
|
||||
"""该函数为每个产品文档根据封面时间,渲染签署页时间、文档变更记录时间"""
|
||||
return {
|
||||
'preparation_time_no_format': cover_time - timedelta(days=2),
|
||||
'preparation_time': format_remove_heng(cover_time - timedelta(days=2)), # 拟制时间:为编制结束时间-2天
|
||||
'inspect_time': format_remove_heng(cover_time - timedelta(days=1)), # 校对时间:为编制时间+1天
|
||||
'auditing_time': format_remove_heng(cover_time),
|
||||
'ratify_time': format_remove_heng(cover_time),
|
||||
'create_doc_time': format_remove_heng(cover_time - timedelta(days=2)),
|
||||
'doc_v1_time': format_remove_heng(cover_time)
|
||||
}
|
||||
|
||||
class DocTime:
|
||||
def __init__(self, project_id: int):
|
||||
self.project = get_object_or_404(Project, id=project_id)
|
||||
# 用户录入时间-项目
|
||||
self.p_start = self.project.beginTime # 被测件接收时间/
|
||||
self.p_end = self.project.endTime # 大纲测评时间周期结束时间/
|
||||
# 遍历轮次时间-多个
|
||||
self.round_count = self.project.pField.count()
|
||||
self.round_time = [] # 轮次按顺序排序
|
||||
for round in self.project.pField.all():
|
||||
self.round_time.append({
|
||||
'start': round.beginTime,
|
||||
'end': round.endTime,
|
||||
'location': round.location
|
||||
})
|
||||
# ~~~~由上面时间二次计算得出时间~~~~ -> TODO:可由用户设置间隔时间!!!!
|
||||
self.dg_bz_start = self.p_start + timedelta(days=1) # 大纲编制开始时间,项目开始时间+1天
|
||||
self.dg_bz_end = self.dg_bz_start + timedelta(days=6) # 大纲编制结束时间,大纲编制开始+6天
|
||||
self.test_sj_start = self.dg_bz_end + timedelta(days=1) # 测评设计与实现时间,在大纲编制结束+1天
|
||||
self.test_sj_end = self.test_sj_start + timedelta(days=5) # 测评设计与实现结束,在开始+5天
|
||||
# ~~~~储存每个文档的cover_time~~~~
|
||||
self.dg_cover_time = self.dg_bz_end
|
||||
self.sm_cover_time = self.test_sj_end
|
||||
self.jl_cover_time = self.round_time[0]['end']
|
||||
self.wtd_cover_time = self.round_time[-1]['end']
|
||||
|
||||
# 该函数生成大纲文档片段-测评时间和地点的时间和地点信息
|
||||
def dg_address_time(self):
|
||||
"""直接返回context去渲染"""
|
||||
# 需要判断round_time是否有值
|
||||
if len(self.round_time) <= 0:
|
||||
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
|
||||
return {
|
||||
'start_year': self.p_start.year,
|
||||
'start_month': self.p_start.month,
|
||||
'end_year': self.p_end.year,
|
||||
'end_month': self.p_end.month,
|
||||
'beginTime_strf': format_remove_heng(self.p_start),
|
||||
'dgCompileStart': format_remove_heng(self.dg_bz_start),
|
||||
'dgCompileEnd': format_remove_heng(self.dg_bz_end),
|
||||
'designStart': format_remove_heng(self.test_sj_start),
|
||||
'designEnd': format_remove_heng(self.test_sj_end),
|
||||
'location': self.round_time[0]['location']
|
||||
}
|
||||
|
||||
# 该函数生成报告文档片段-测评时间和地点【注意使用了dg_address_time -> 所以后续有修改注意前导】
|
||||
def bg_address_time(self):
|
||||
if len(self.round_time) <= 0:
|
||||
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
|
||||
# 先使用大纲的时间行数作为前三行
|
||||
cname = ['首轮测试', '第二轮测试', '第三轮测试', '第四轮测试', '第五轮测试', '第六轮测试', '第七轮测试',
|
||||
'第八轮测试', '第九轮测试', '第十轮测试']
|
||||
dg_address_time = self.dg_address_time()
|
||||
round_time_list = []
|
||||
index = 0
|
||||
for round_dict in self.round_time:
|
||||
one_dict = {
|
||||
'name': cname[index],
|
||||
'start': format_remove_heng(round_dict['start']),
|
||||
'end': format_remove_heng(round_dict['end']),
|
||||
'location': round_dict['location']
|
||||
}
|
||||
index += 1
|
||||
round_time_list.append(one_dict)
|
||||
return {
|
||||
'begin_year': dg_address_time['start_year'],
|
||||
'begin_month': dg_address_time['start_month'],
|
||||
'end_year': dg_address_time['end_year'],
|
||||
'end_month': dg_address_time['end_month'],
|
||||
'begin_time': dg_address_time['beginTime_strf'],
|
||||
'dg_weave_start_date': dg_address_time['dgCompileStart'],
|
||||
'dg_weave_end_date': dg_address_time['dgCompileEnd'],
|
||||
'sj_weave_start_date': dg_address_time['designStart'],
|
||||
'sj_weave_end_date': dg_address_time['designEnd'],
|
||||
'round_time_list': round_time_list,
|
||||
# 测评总结 -> 依据项目结束时间-7 ~ 项目结束时间
|
||||
'summary_start_date': format_remove_heng(self.p_end - timedelta(days=7)),
|
||||
'summary_end_date': format_remove_heng(self.p_end),
|
||||
}
|
||||
|
||||
# 生成报告中测评完成情况 -> 必须依据其他内容生成时间【注意使用了bg_address_time -> 所以后续有修改注意前导】
|
||||
def bg_completion_situation(self):
|
||||
bg_timer_dict = self.bg_address_time()
|
||||
xq_fx_time_end = self.dg_bz_start + timedelta(days=2)
|
||||
ch_time_start = xq_fx_time_end + timedelta(days=1)
|
||||
ch_time_end = self.dg_bz_end
|
||||
if len(self.round_time) < 1:
|
||||
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
|
||||
return {
|
||||
'start_time_year': bg_timer_dict['begin_year'],
|
||||
'start_time_month': bg_timer_dict['begin_month'],
|
||||
'xq_fx_time_start_year': self.dg_bz_start.year,
|
||||
'xq_fx_time_start_month': self.dg_bz_start.month,
|
||||
'xq_fx_time_start_day': self.dg_bz_start.day,
|
||||
'xq_fx_time_end_year': xq_fx_time_end.year, # 需求分析结束时间是大纲编制开始+2
|
||||
'xq_fx_time_end_month': xq_fx_time_end.month,
|
||||
'xq_fx_time_end_day': xq_fx_time_end.day,
|
||||
'ch_start_year': ch_time_start.year,
|
||||
'ch_start_month': ch_time_start.month,
|
||||
'ch_start_day': ch_time_start.day,
|
||||
'ch_end_year': ch_time_end.year,
|
||||
'ch_end_month': ch_time_end.month,
|
||||
'ch_end_day': ch_time_end.day,
|
||||
'sj_start_year': self.test_sj_start.year,
|
||||
'sj_start_month': self.test_sj_start.month,
|
||||
'sj_start_day': self.test_sj_start.day,
|
||||
'sj_end_year': self.test_sj_end.year,
|
||||
'sj_end_month': self.test_sj_end.month,
|
||||
'sj_end_day': self.test_sj_end.day,
|
||||
'end_time_year': self.p_end.year,
|
||||
'end_time_month': self.p_end.month,
|
||||
'exec_start_time_year': self.round_time[0]['start'].year,
|
||||
'exec_start_time_month': self.round_time[0]['start'].month,
|
||||
'exec_start_time_day': self.round_time[0]['start'].day,
|
||||
'exec_end_time_year': self.round_time[0]['end'].year,
|
||||
'exec_end_time_month': self.round_time[0]['end'].month,
|
||||
'exec_end_time_day': self.round_time[0]['end'].day,
|
||||
}
|
||||
|
||||
# 该函数生成最终大纲的时间
|
||||
def dg_final_time(self):
|
||||
cover_time = self.dg_bz_end
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
# 新增给大纲模版10.2章节context
|
||||
context.update(basic_line1=cover_time.strftime("%Y年%m月"), basic_line2=self.p_end.strftime("%Y年%m月"))
|
||||
# 新增给大纲模版10.3.2章节的context
|
||||
sm_context = self.sm_final_time()
|
||||
context.update(sm_end_time=sm_context['preparation_time_no_format'].strftime("%Y年%m月"))
|
||||
return context
|
||||
|
||||
# 该函数生成说明文档的时间 -> 依据项目时间而非用户第一轮填写时间!
|
||||
def sm_final_time(self):
|
||||
cover_time = self.test_sj_end # 封面时间:为大纲时间中“测评设计与实现”结束时间
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 该函数生成记录文档的时间 -> 依据第一轮测试用户填写的事件
|
||||
def jl_final_time(self):
|
||||
if len(self.round_time) < 1:
|
||||
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
|
||||
cover_time = self.round_time[0]['end'] # 封面时间为用户填写第一轮结束时间
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 问题单的时间 -> 依据最后一轮次的结束时间+1天
|
||||
def wtd_final_time(self):
|
||||
if len(self.round_time) < 1:
|
||||
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
|
||||
cover_time = self.round_time[-1]['end']
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 回归测试说明时间 -> 根据第二轮、第三轮...的开始时间
|
||||
def hsm_final_time(self, round_key: str):
|
||||
if len(self.round_time) < int(round_key) + 1:
|
||||
raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成')
|
||||
cover_time = self.round_time[int(round_key)]['start']
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 回归测试记录时间 -> 根据第二轮、第三轮...的结束时间
|
||||
def hjl_final_time(self, round_key: str) -> dict:
|
||||
if len(self.round_time) < int(round_key) + 1:
|
||||
raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成')
|
||||
cover_time = self.round_time[int(round_key)]['end']
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
# 生成报告非过程时间 -> 根据项目结束时间来定
|
||||
def bg_final_time(self) -> dict:
|
||||
if len(self.round_time) <= 0:
|
||||
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
|
||||
cover_time = self.p_end
|
||||
# 这里做判断,如果项目结束时间/最后一轮结束时间
|
||||
if cover_time < self.round_time[-1]['end']:
|
||||
# 注意系统对HttpError异常重新处理,所以该处status_code看api.py文件
|
||||
raise HttpError(PROJECT_ENDTIME_ERROR_CODE, message='项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
|
||||
context = times_by_cover_time(cover_time)
|
||||
context.update(cover_time=cover_time.strftime("%Y年%m月%d日"))
|
||||
return context
|
||||
|
||||
146
apps/createDocument/extensions/table_creator.py
Normal file
146
apps/createDocument/extensions/table_creator.py
Normal file
@@ -0,0 +1,146 @@
|
||||
from pathlib import Path
|
||||
from typing import Literal
|
||||
from docxtpl import DocxTemplate
|
||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
from docx.enum.table import WD_ALIGN_VERTICAL
|
||||
from docx.oxml.ns import qn
|
||||
from docx.shared import Mm
|
||||
from apps.createDocument.extensions.tools import set_table_border_by_cell_position, set_cell_margins
|
||||
from utils.path_utils import project_path
|
||||
from utils.chen_response import ChenResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from apps.project.models import Project, Round
|
||||
from django.db.models import QuerySet
|
||||
|
||||
# 创建当前轮次别名
|
||||
RoundType = Literal["0", "not0", "last"]
|
||||
chinese_round_name: list = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
|
||||
|
||||
# 通用生成静态软件项、静态硬件项、动态软件项、动态硬件信息、测评数据的context,包含fontnote和table
|
||||
def create_table_context(table_data: list[list[str]], doc: DocxTemplate, rounds_map: list[list[str]] = None,
|
||||
current_round: str = None):
|
||||
"""
|
||||
注意:该函数会增加一列序号列,并且支持单元格内回车换行(段落换行)
|
||||
传入当前轮次以及rounds_map来过滤一些其他轮次的数据,为None则不过滤
|
||||
"""
|
||||
# 过滤数据处理
|
||||
if rounds_map is not None and current_round is not None and current_round != 'last':
|
||||
filtered_data = []
|
||||
for i, row in enumerate(table_data):
|
||||
# 第一行作为表头,始终保留
|
||||
if i == 0:
|
||||
filtered_data.append(row)
|
||||
else:
|
||||
# 检查该行是否属于当前轮次
|
||||
if current_round in rounds_map[i]:
|
||||
filtered_data.append(row)
|
||||
# table_data先替换后再执行下方生成表格
|
||||
table_data = filtered_data
|
||||
|
||||
subdoc = doc.new_subdoc()
|
||||
rows = len(table_data)
|
||||
cols = len(table_data[0]) + 1
|
||||
table = subdoc.add_table(rows=rows, cols=cols)
|
||||
|
||||
# 单元格处理
|
||||
for row in range(rows):
|
||||
for col in range(cols):
|
||||
cell = table.cell(row, col) # 从上倒下,从左到右取cell
|
||||
set_cell_margins(cell, left=100, right=100, top=100, bottom=100)
|
||||
|
||||
# 获取要显示的文本内容(字符串或按行拆分后的列表)
|
||||
if col == 0:
|
||||
# 序号列
|
||||
lines = ["序号"] if row == 0 else [str(row)]
|
||||
else:
|
||||
raw_text = table_data[row][col - 1]
|
||||
# 按换行符 \n 拆分为多个段落
|
||||
lines = raw_text.split('\n') if raw_text else ['']
|
||||
|
||||
# 清空单元格原有段落(add_table 默认有一个段落)
|
||||
cell.text = ""
|
||||
# 删除默认段落,稍后统一添加
|
||||
for para in cell.paragraphs:
|
||||
p = para._element
|
||||
p.getparent().remove(p)
|
||||
|
||||
# 逐个添加段落
|
||||
for i, line in enumerate(lines):
|
||||
if i == 0:
|
||||
para = cell.add_paragraph(line)
|
||||
else:
|
||||
para = cell.add_paragraph(line)
|
||||
|
||||
# 设置段落对齐(第一列居中,其他左对齐,可根据需要调整)
|
||||
if col == 0:
|
||||
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
else:
|
||||
para.alignment = WD_ALIGN_PARAGRAPH.LEFT
|
||||
|
||||
# 对第一行(表头)设置黑体字体
|
||||
if row == 0:
|
||||
for run in para.runs:
|
||||
run.font.name = '黑体'
|
||||
run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')
|
||||
run.font.bold = False
|
||||
# 表头段落居中(覆盖前面的 left)
|
||||
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
|
||||
# 垂直居中
|
||||
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
|
||||
|
||||
# 设置序号列宽度
|
||||
for cell in table.columns[0].cells:
|
||||
cell.width = Mm(15)
|
||||
for para in cell.paragraphs:
|
||||
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
|
||||
# 表格居中
|
||||
table.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
# 设置表格外边框
|
||||
set_table_border_by_cell_position(table)
|
||||
return subdoc
|
||||
|
||||
# 统一静态软件项、静态硬件项、动态软件项、动态硬件信息、测评数据5个的word生成 - 模版模式
|
||||
def uniform_static_dynamic_response(id: int, filename: str, r_filename: str, model,
|
||||
current_round: str = "0", isHsm: bool = None) -> ChenResponse | None:
|
||||
""" 通过形参isHsm判断是否是回归测试说明 """
|
||||
project_obj = get_object_or_404(Project, id=id)
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / filename # 取相同模版
|
||||
doc = DocxTemplate(input_path)
|
||||
qs = model.objects.filter(project=project_obj)
|
||||
if qs.exists():
|
||||
obj = qs.first()
|
||||
table_data = obj.table
|
||||
# 回归测试说明生成多轮次回归测试说明的5个接口分支
|
||||
if isHsm:
|
||||
hround_list: QuerySet[Round] = project_obj.pField.exclude(key='0')
|
||||
for hround in hround_list:
|
||||
round_key = hround.key
|
||||
cname = chinese_round_name[int(round_key)] # 取中文:一、二、三...
|
||||
# key就是current_round,这里就解决文件名和那个的问题
|
||||
subdoc = create_table_context(table_data, doc, obj.rounds_map, round_key)
|
||||
context = {
|
||||
'fontnote': obj.fontnote,
|
||||
'table': subdoc,
|
||||
}
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/hsm" / "".join([f"第{cname}轮", r_filename]))
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
return ChenResponse(status=200,code=200,message="多个轮次5接口渲染完毕,文档生成完毕")
|
||||
|
||||
# 新增:传入rounds_map进行渲染
|
||||
subdoc = create_table_context(table_data, doc, obj.rounds_map, current_round)
|
||||
context = {
|
||||
'fontnote': obj.fontnote,
|
||||
'table': subdoc,
|
||||
}
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / r_filename)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
return None
|
||||
Reference in New Issue
Block a user