1. 项目设置支持邮件通知和钉钉通知开关

2. 设置支持邮件通知收件人配置
3. models.py优化db.Boolean类型字段server_default默认值写法,优化db.Integer类型字段default默认值写法
This commit is contained in:
azhengzz 2021-02-21 18:25:13 +08:00
parent b8badfc2cf
commit 0d6a554d12
7 changed files with 413 additions and 52 deletions

View File

@ -13,7 +13,8 @@ from app.extensions import (db, migrate, login_manager, mail, csrf, bootstrap, h
socketio, dispatcher_scheduler)
from app import models
from app.template_global import (render_to_json, sort_by_order_in_module, sort_by_order_in_logic_controller,
can_show, is_forbidden, get_latest_reports, get_case_from_id, get_tool_from_id)
can_show, is_forbidden, get_latest_reports, get_case_from_id, get_tool_from_id,
calc_percent)
from app.cores.ws import register_all_user_socket
@ -169,6 +170,7 @@ def register_template_global(app: Flask):
app.add_template_global(is_forbidden, 'is_forbidden')
app.add_template_global(get_case_from_id, 'get_case_from_id')
app.add_template_global(get_tool_from_id, 'get_tool_from_id')
app.add_template_global(calc_percent, 'calc_percent')
def register_before_first_request_funcs(app: Flask):

View File

@ -0,0 +1,25 @@
# coding=utf-8
# 邮件通知
from typing import List, Mapping, Any
from flask import current_app, render_template
from app.email import send_email
def send_email_report(addresses: List, report_data: Mapping[str, Any]):
"""
邮件发送本次调度结果
:param addresses: 收件人地址
:param report_data: 案例执行结果
:return: None
"""
send_email(
subject="[ApiAutomationTest] 构建结果通知",
sender=current_app.config['ADMINS'][0],
recipients=addresses,
# text_body=render_template("email/email_authentication.txt"),
html_body=render_template("email/summary_report.html",
report_data=report_data,
module_results=report_data.get('module_results'))
)

View File

@ -93,8 +93,8 @@ class EmailSetting(db.Model):
receiver_address: 收件地址, 多个收件人以逗号分隔
"""
id = db.Column(db.Integer, primary_key=True)
whether_send_email = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
whether_gen_report = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
whether_send_email = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
whether_gen_report = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
email_title = db.Column(db.String(128), nullable=False, default='', server_default='')
email_text = db.Column(db.Text, nullable=False, default='', server_default='')
receiver_address = db.Column(db.Text, nullable=False, default='', server_default='')
@ -211,16 +211,23 @@ class ProjectAdvancedConfiguration(db.Model):
"""
产品高级设置
字段说明
stop_on_error 发生错误时终止执行
ding_talk_notify 执行完毕后是否发送钉钉通知
email_notify 执行完毕后是否发送邮件
"""
id = db.Column(db.Integer, primary_key=True)
stop_on_error = db.Column(db.Boolean, nullable=False, default=True, server_default='True')
stop_on_error = db.Column(db.Boolean, nullable=False, default=True, server_default='1')
ding_talk_notify = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
email_notify = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
# relationship
project_id = db.Column(db.Integer, db.ForeignKey('project.id'))
project = db.relationship('Project', back_populates='project_advanced_configuration')
def update(self, stop_on_error):
def update(self, stop_on_error, ding_talk_notify, email_notify):
self.stop_on_error = stop_on_error
self.ding_talk_notify = ding_talk_notify
self.email_notify = email_notify
db.session.commit()
@ -1550,7 +1557,7 @@ class HTTPCase(db.Model):
content_type = db.Column(db.String(128), nullable=False, default='', server_default='')
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
# relationship
@ -1806,9 +1813,9 @@ class HTTPCaseParameter(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), nullable=False, default='', server_default='')
value = db.Column(db.Text, nullable=False, default='', server_default='')
url_encode = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
url_encode = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
content_type = db.Column(db.String(128), nullable=False, default='', server_default='')
include_equals = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
include_equals = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
# relationship
http_case_id = db.Column(db.Integer, db.ForeignKey('http_case.id'))
@ -1843,9 +1850,9 @@ class HTTPCaseExpectation(db.Model):
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
value = db.Column(db.Text, nullable=False, default='', server_default='')
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
# relationship
http_case_id = db.Column(db.Integer, db.ForeignKey('http_case.id'))
@ -1929,7 +1936,7 @@ class SSHCase(db.Model):
method = db.Column(db.String(128), nullable=False, default='', server_default='')
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
# relationship
@ -2130,9 +2137,9 @@ class SSHCaseExpectation(db.Model):
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
value = db.Column(db.Text, nullable=False, default='', server_default='')
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
# relationship
ssh_case_id = db.Column(db.Integer, db.ForeignKey('ssh_case.id'))
@ -2189,7 +2196,7 @@ class SQLCase(db.Model):
charset = db.Column(db.String(64), nullable=False, default='', server_default='')
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
# relationship
@ -2401,9 +2408,9 @@ class SQLCaseExpectation(db.Model):
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
value = db.Column(db.Text, nullable=False, default='', server_default='')
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
# relationship
sql_case_id = db.Column(db.Integer, db.ForeignKey('sql_case.id'))
@ -2442,11 +2449,11 @@ class DebugCase(db.Model):
case: 案例组件 Case:DebugCase is 1:1
"""
id = db.Column(db.Integer, primary_key=True)
project_variable = db.Column(db.Boolean, nullable=False, default=False, server_default='True')
project_variable = db.Column(db.Boolean, nullable=False, default=False, server_default='1')
expectation_logic = db.Column(db.String(64), nullable=False, default=EXPECTATION_LOGIC.AND, server_default=EXPECTATION_LOGIC.AND)
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
postprocessor_failure = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
# relationship
@ -2595,9 +2602,9 @@ class DebugCaseExpectation(db.Model):
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
value = db.Column(db.Text, nullable=False, default='', server_default='')
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
last_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
last_failure_msg = db.Column(db.Text, nullable=False, default='初次执行前默认失败', server_default='初次执行前默认失败')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
# relationship
debug_case_id = db.Column(db.Integer, db.ForeignKey('debug_case.id'))
@ -2642,13 +2649,13 @@ class Dispatcher(db.Model):
# field
id = db.Column(db.Integer, primary_key=True)
element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
status = db.Column(db.String(64), nullable=False, default='', server_default='')
progress = db.Column(db.Float(), nullable=False, default=text('0.0'), server_default=text('0.0')) # TODO 控制精度?
progress = db.Column(db.Float(), nullable=False, default=0.0, server_default=text('0.0')) # TODO 控制精度?
start_time = db.Column(db.DateTime, nullable=False, default=datetime.now, server_default=text('CURRENT_TIMESTAMP'))
end_time = db.Column(db.DateTime, nullable=False, default=datetime.now, server_default=text('CURRENT_TIMESTAMP'))
log = db.Column(db.Text, nullable=False, default='', server_default='')
user_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
user_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
# relationship
details = db.relationship('DispatcherDetail', back_populates='dispatcher', cascade='all, delete-orphan')
@ -2692,10 +2699,10 @@ class DispatcherDetail(db.Model):
# field
id = db.Column(db.Integer, primary_key=True)
element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
element_name = db.Column(db.String(512), nullable=False, default='', server_default='') # case.name大小为512
parent_dispatcher_detail_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
parent_element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
parent_dispatcher_detail_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
parent_element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
parent_element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
start_time = db.Column(db.DateTime, nullable=False, default=datetime.now, server_default=text('CURRENT_TIMESTAMP'))
@ -2816,6 +2823,8 @@ class ReportCaseData(db.Model):
字段说明
case_type: 案例类型
case_id: 案例编号
module_id: 案例所属模块id
module_name: 案例所属模块名称
request_header: 请求头
request_body: 请求体
response_header: 应答头
@ -2835,20 +2844,22 @@ class ReportCaseData(db.Model):
"""
# field
id = db.Column(db.Integer, primary_key=True)
case_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
case_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
case_type = db.Column(db.String(64), nullable=False, default='', server_default='')
module_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
module_name = db.Column(db.String(64), nullable=False, default='', server_default='')
request_header = db.Column(db.Text, nullable=False, default='', server_default='')
request_body = db.Column(db.Text, nullable=False, default='', server_default='')
response_header = db.Column(db.Text, nullable=False, default='', server_default='')
response_body = db.Column(db.Text, nullable=False, default='', server_default='')
preprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_script = db.Column(db.TEXT, nullable=False, default='', server_default='')
postprocessor_result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
postprocessor_result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
postprocessor_failure_message = db.Column(db.Text, nullable=False, default='', server_default='')
log = db.Column(db.Text, nullable=False, default='', server_default='')
expectation_logic = db.Column(db.String(64), nullable=False, default=EXPECTATION_LOGIC.AND,
server_default=EXPECTATION_LOGIC.AND)
elapsed_time = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
elapsed_time = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
result = db.Column(db.String(64), nullable=False, default='', server_default='')
# relationship
@ -2860,11 +2871,13 @@ class ReportCaseData(db.Model):
dispatcher_detail = db.relationship('DispatcherDetail')
@classmethod
def add(cls, report_id, dispatcher_detail_id, case_type, case_id, request_header, request_body, response_header,
response_body, elapsed_time, preprocessor_script, postprocessor_script, postprocessor_result,
postprocessor_failure_message, log, expectation_logic, result):
def add(cls, report_id, dispatcher_detail_id, case_type, case_id, module_id, module_name, request_header,
request_body, response_header, response_body, elapsed_time, preprocessor_script, postprocessor_script,
postprocessor_result, postprocessor_failure_message, log, expectation_logic, result):
report_case_data = cls(case_type=case_type,
case_id=case_id,
module_id=module_id,
module_name=module_name,
request_header=request_header,
request_body=request_body,
response_header=response_header,
@ -2904,8 +2917,8 @@ class ReportCaseExpectationData(db.Model):
test_field = db.Column(db.String(64), nullable=False, default='', server_default='')
value = db.Column(db.Text, nullable=False, default='', server_default='')
matching_rule = db.Column(db.String(64), nullable=False, default='', server_default='')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
result = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
negater = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
result = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
failure_msg = db.Column(db.Text, nullable=False, default='', server_default='')
# relationship
@ -2941,7 +2954,7 @@ class ReportToolData(db.Model):
# field
id = db.Column(db.Integer, primary_key=True)
tool_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
tool_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
tool_type = db.Column(db.String(64), nullable=False, default='', server_default='')
# relationship
@ -3066,9 +3079,9 @@ class Scheduler(db.Model):
# field
id = db.Column(db.Integer, primary_key=True)
element_type = db.Column(db.String(64), nullable=False, default='', server_default='')
element_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
element_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
cron = db.Column(db.Text, nullable=False, default='', server_default='')
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
@classmethod
def get_scheduler(cls, element_type, element_id):
@ -3099,10 +3112,10 @@ class DingTalkRobotSetting(db.Model):
"""
# field
id = db.Column(db.Integer, primary_key=True)
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
access_token = db.Column(db.String(512), nullable=False, default='', server_default='')
secret = db.Column(db.String(512), nullable=False, default='', server_default='')
at_all = db.Column(db.Boolean, nullable=False, default=False, server_default='False')
at_all = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
at_mobiles = db.Column(db.Text, nullable=False, default='', server_default='')
@classmethod
@ -3155,8 +3168,85 @@ class DingTalkRobotSettingAssociationProject(db.Model):
"""钉钉机器人配置与项目关系表"""
# field
id = db.Column(db.Integer, primary_key=True)
setting_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
project_id = db.Column(db.Integer, nullable=False, default=text('0'), server_default=text('0'))
setting_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
project_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
@classmethod
def add(cls, setting_id, projects):
for project_id in projects:
db.session.add(cls(setting_id=setting_id, project_id=project_id))
db.session.commit()
@classmethod
def delete(cls, setting_id):
rows = cls.query.filter_by(setting_id=setting_id).all()
for row in rows:
db.session.delete(row)
db.session.commit()
class EmailReceiverSetting(db.Model):
"""
邮件收件人配置
字段说明
enable 是否启用当前收件人地址
name 收件人名称
address 邮件地址
"""
# field
id = db.Column(db.Integer, primary_key=True)
enable = db.Column(db.Boolean, nullable=False, default=False, server_default='0')
name = db.Column(db.String(128), nullable=False, default='', server_default='')
address = db.Column(db.String(512), nullable=False, default='', server_default='')
@classmethod
def get_project_email_receiver_setting(cls, project_id):
"""获取该项目需要通知的所有收件人"""
email_receiver_settings = []
rows = EmailReceiverSettingAssociationProject.query.filter_by(project_id=project_id).all()
if rows:
for row in rows:
email_receiver_setting = cls.query.filter_by(id=row.setting_id).first()
if email_receiver_setting:
email_receiver_settings.append(email_receiver_setting)
return email_receiver_settings
@classmethod
def add(cls, enable, name, address, projects=None):
email_receiver_setting = cls(enable=enable,
name=name,
address=address)
db.session.add(email_receiver_setting)
db.session.commit()
EmailReceiverSettingAssociationProject.add(setting_id=email_receiver_setting.id, projects=projects)
return email_receiver_setting
@classmethod
def modify(cls, id, enable, name, address, projects=None):
email_receiver_setting = cls.query.filter_by(id=id).first()
if email_receiver_setting:
email_receiver_setting.enable = enable
email_receiver_setting.name = name
email_receiver_setting.address = address
db.session.commit()
EmailReceiverSettingAssociationProject.delete(setting_id=id)
EmailReceiverSettingAssociationProject.add(setting_id=id, projects=projects)
@classmethod
def delete(cls, id):
email_receiver_setting = cls.query.filter_by(id=id).first()
if email_receiver_setting:
db.session.delete(email_receiver_setting)
db.session.commit()
EmailReceiverSettingAssociationProject.delete(setting_id=email_receiver_setting.id)
class EmailReceiverSettingAssociationProject(db.Model):
"""邮件收件人配置与项目关系表"""
# field
id = db.Column(db.Integer, primary_key=True)
setting_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
project_id = db.Column(db.Integer, nullable=False, default=0, server_default=text('0'))
@classmethod
def add(cls, setting_id, projects):

View File

@ -107,5 +107,18 @@ def get_tool_from_id(tool_id):
return Tool.query.filter_by(id=tool_id).first()
def calc_percent(a, b):
try:
a = float(a)
b = float(b)
except Exception as e:
return None
else:
if b > 0:
return round(a / b * 100, 2)
else:
return None
if __name__ == '__main__':
print(render_to_json)

View File

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>TestCenter-PBOX-NewAutoTest-第348次构建日志</title></head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tbody>
<tr>
<td>
<span style="color: #FF0000;">(本邮件是程序自动下发的,请勿回复!)</span></td>
</tr>
<tr>
<td>
<h2 style="color: #0000FF">调度 - {{ report_data.get('dispatcher_end_type') }}</h2></td>
</tr>
<tr>
<td>
<br />
<b><span style="color: #0B610B">调度信息</span></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>名称:&nbsp;{{ report_data.get('report_name') }}</li>
<li>级别:&nbsp;{{ report_data.get('trigger_element_type') }}</li>
<li>调度编号:&nbsp;第{{ report_data.get('dispatcher_id') }}次构建</li>
<li>报告编号:&nbsp;第{{ report_data.get('report_id') }}号报告</li>
<li>触发类型:&nbsp;{{ report_data.get('dispatcher_trigger_type') }}</li>
<li>详细报告:&nbsp;
<a href="{{ request.url_root }}report/detail/{{ report_data.get('report_id') }}">{{ request.url_root }}report/detail/{{ report_data.get('report_id') }}</a></li>
<li>开始时间:&nbsp;{{ report_data.get('start_time') }}</li>
<li>结束时间:&nbsp;{{ report_data.get('end_time') }}</li>
<li>耗时:&nbsp;{{ report_data.get('elapsed_time') }}</li>
</ul>
</td>
</tr>
<tr>
<td>
<br />
<b><span style="color: #0B610B">模块执行结果统计</span></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<div style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<style type="text/css">* { margin: 0; padding: 0 } html, body { width: 100%; height: 100%; font-size: 12px;} table { border-collapse: collapse; table-layout: fixed ;bgcolor:#F0E68C} td { vertical-align: baseline; font-size: 12px }</style>
<table align="center" class="details" border="1" cellpadding="5" cellspacing="2" width="95%" bgcolor="#FAFAD2">
<tbody>
<tr valign="top" bgcolor="#87CEFA" name="line">
<th>模块编号</th>
<th>模块名称</th>
<th>案例个数</th>
<th>成功</th>
<th>失败</th>
<th>错误</th>
<th>跳过</th>
<th>成功率</th>
</tr>
{% for module_result in module_results %}
<tr valign="top">
<td align="center">{{ module_result.get('module_id') }}</td>
<td align="center">{{ module_result.get('module_name') }}</td>
<td align="center" style="background-color: rgba(0,132,255,0.7)">{{ module_result.get('case_count') }}</td>
<td align="center" style="background-color: rgba(40,167,69,0.7)">{{ module_result.get('success_count') }}</td>
<td align="center" style="background-color: rgba(220,53,69,0.7)">{{ module_result.get('failure_count') }}</td>
<td align="center" style="background-color: rgba(205,0,204,0.7)">{{ module_result.get('error_count') }}</td>
<td align="center" style="background-color: rgba(108,117,125,0.7)">{{ module_result.get('skip_count') }}</td>
<td align="center">{{ calc_percent(module_result.get('success_count', 0), module_result.get('case_count', 0)) }}%</td>
</tr>
{% endfor %}
<tr valign="top" bgcolor="#87CEFA">
<td align="center" colspan="2">
<b>总计</b>
</td>
<td align="center">
<b>{{ report_data.get('case_count', 0) }}</b>
</td>
<td align="center">
<b>{{ report_data.get('success_count', 0) }}</b>
</td>
<td align="center">
<b>{{ report_data.get('failure_count', 0) }}</b>
</td>
<td align="center">
<b>{{ report_data.get('error_count', 0) }}</b>
</td>
<td align="center">
<b>{{ report_data.get('skip_count', 0) }}</b>
</td>
<td align="center">
<b>{{ calc_percent(report_data.get('success_count', 0), report_data.get('case_count', 0)) }}%</b>
</td>
</tr>
</tbody>
</table>
</div>
<br/></td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -90,7 +90,7 @@ class="bg-gradient-grey"
<div class="modal-body">
<input type="text" class="form-control" id="input-config-project-id" placeholder="" disabled style="display: none"/>
<div class="form-group">
<label>发生错误终止运行</label>
<label>发生错误终止运行</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="stop-on-error" id="radio-stop-on-error-yes" autocomplete="off">
@ -100,8 +100,30 @@ class="bg-gradient-grey"
</label>
</div>
</div>
<div class="form-group">
<label>钉钉通知</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="ding-talk-notify" id="radio-ding-talk-notify-yes" autocomplete="off">
</label>
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="ding-talk-notify" id="radio-ding-talk-notify-no" autocomplete="off">
</label>
</div>
</div>
<div class="form-group">
<label>邮件通知</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="email-notify" id="radio-email-notify-yes" autocomplete="off">
</label>
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="email-notify" id="radio-email-notify-no" autocomplete="off">
</label>
</div>
</div>
<div class="input-group input-group-sm mt-2">
<label>定时任务:</label>
<label>定时任务</label>
<div class="input-group-prepend">
<label class="input-group-text" for="checkbox-use-scheduler">是否启用</label>
</div>

View File

@ -9,16 +9,17 @@
{% endblock styles %}
{% block body_attribs %}
data-spy="scroll" data-target="#navbar-example3" style="position: relative"
data-spy="scroll" data-target="#navbar-basic-setting" style="position: relative"
{% endblock %}
{% block app_content %}
<div class="row">
<div class="col-lg-2">
<nav id="navbar-example3" class="navbar navbar-light bg-light" style="position: fixed">
<nav id="navbar-basic-setting" class="navbar navbar-light bg-light" style="position: fixed">
<!--<a class="navbar-brand" href="#">Navbar</a>-->
<nav class="nav nav-pills flex-column">
{# <a class="nav-link" href="#email">邮件设置</a>#}
<a class="nav-link" href="#email-receiver-setting">邮件通知</a>
<a class="nav-link" href="#ding-talk-robot-setting">钉钉通知</a>
<nav class="nav nav-pills flex-column">
<a class="nav-link svg-bi-arrow-up-circle-fill" href="#">
@ -32,7 +33,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
</nav>
</div>
<div class="col-lg-10">
<div data-spy="scroll" data-target="#navbar-example3" data-offset="0">
<div data-spy="scroll" data-target="#navbar-basic-setting" data-offset="0">
{# <h2 id="email">邮件设置</h2>#}
{# <form method="post" action="{{ url_for('setting.basic_setting') }}">#}
{# {{ form.csrf_token() }}#}
@ -43,6 +44,13 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
{# {{ render_field(form.receiver_address) }}#}
{# {{ render_field(form.submit, class="btn btn-primary") }}#}
{# </form>#}
<h2 class="mt-2" id="email-receiver-setting">邮件通知</h2>
<div class="btn-toolbar" role="toolbar" id="table-email-receiver-setting-toolbar">
<div class="btn-group mr-2" role="group">
<button type="button" class="btn btn-primary" id="btn-add-email-receiver">新增</button>
</div>
</div>
<table id="table-email-receiver-setting"></table>
<h2 class="mt-2" id="ding-talk-robot-setting">钉钉通知</h2>
<div class="btn-toolbar" role="toolbar" id="table-ding-talk-robot-setting-toolbar">
<div class="btn-group mr-2" role="group">
@ -65,7 +73,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
</div>
<div class="modal-body">
<div class="form-group">
<label>是否启用</label>
<label>是否启用</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-add-ding-talk-robot-enable" id="input-add-ding-talk-robot-enable-yes" autocomplete="off">
@ -74,7 +82,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
<input type="radio" name="input-add-ding-talk-robot-enable" id="input-add-ding-talk-robot-enable-no" autocomplete="off" checked>
</label>
</div>
<label>@全体成员</label>
<label>@全体成员</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-add-ding-talk-robot-at-all" id="input-add-ding-talk-robot-at-all-yes" autocomplete="off">
@ -97,7 +105,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
<input type="text" class="form-control" id="input-add-ding-talk-robot-at-mobiles" placeholder="请输入需要@成员的手机号,多个成员以,分割">
</div>
<div class="form-group">
<label for="select-add-ding-talk-robot-projects">关联项目: </label>
<label for="select-add-ding-talk-robot-projects">关联项目</label>
<select id="select-add-ding-talk-robot-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
{% for project in projects %}
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
@ -125,7 +133,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
<div class="modal-body">
<input type="text" class="form-control" id="input-modify-ding-talk-robot-id" placeholder="" disabled style="display: none"/>
<div class="form-group">
<label>是否启用</label>
<label>是否启用</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-modify-ding-talk-robot-enable" id="input-modify-ding-talk-robot-enable-yes" autocomplete="off">
@ -134,7 +142,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
<input type="radio" name="input-modify-ding-talk-robot-enable" id="input-modify-ding-talk-robot-enable-no" autocomplete="off" checked>
</label>
</div>
<label>@全体成员</label>
<label>@全体成员</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-modify-ding-talk-robot-at-all" id="input-modify-ding-talk-robot-at-all-yes" autocomplete="off">
@ -157,7 +165,7 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
<input type="text" class="form-control" id="input-modify-ding-talk-robot-at-mobiles" placeholder="请输入需要@成员的手机号,多个成员以,分割">
</div>
<div class="form-group">
<label for="select-modify-ding-talk-robot-projects">关联项目: </label>
<label for="select-modify-ding-talk-robot-projects">关联项目</label>
<select id="select-modify-ding-talk-robot-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
{% for project in projects %}
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
@ -172,6 +180,100 @@ data-spy="scroll" data-target="#navbar-example3" style="position: relative"
</div>
</div>
</div>
<div class="modal fade" id="modal-add-email-receiver-setting" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">新增邮件收件人</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>是否启用</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-add-email-receiver-enable" id="input-add-email-receiver-enable-yes" autocomplete="off">
</label>
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-add-email-receiver-enable" id="input-add-email-receiver-enable-no" autocomplete="off" checked>
</label>
</div>
</div>
<div class="form-group">
<label for="input-add-email-receiver-name">名称</label>
<input type="text" class="form-control" id="input-add-email-receiver-name" placeholder="请输入收件人名称">
</div>
<div class="form-group">
<label for="input-add-email-receiver-address">邮箱地址</label>
<input type="text" class="form-control" id="input-add-email-receiver-address" placeholder="请输入邮箱地址">
</div>
<div class="form-group">
<label for="select-add-email-receiver-projects">关联项目</label>
<select id="select-add-email-receiver-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
{% for project in projects %}
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
<button id="btn-save-add-email-receiver-setting" type="button" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-modify-email-receiver-setting" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">修改邮件收件人</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<input type="text" class="form-control" id="input-modify-email-receiver-id" placeholder="" disabled style="display: none"/>
<div class="form-group">
<label>是否启用</label>
<div class="btn-group btn-group-sm" data-toggle="buttons">
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-modify-email-receiver-enable" id="input-modify-email-receiver-enable-yes" autocomplete="off">
</label>
<label class="btn btn-outline-secondary btn-sm">
<input type="radio" name="input-modify-email-receiver-enable" id="input-modify-email-receiver-enable-no" autocomplete="off" checked>
</label>
</div>
</div>
<div class="form-group">
<label for="input-modify-email-receiver-name">名称</label>
<input type="text" class="form-control" id="input-modify-email-receiver-name" placeholder="请输入收件人名称">
</div>
<div class="form-group">
<label for="input-modify-email-receiver-address">邮箱地址</label>
<input type="text" class="form-control" id="input-modify-email-receiver-address" placeholder="请输入邮箱地址">
</div>
<div class="form-group">
<label for="select-modify-email-receiver-projects">关联项目</label>
<select id="select-modify-email-receiver-projects" class="selectpicker" multiple data-width="100%" data-actions-box="true">
{% for project in projects %}
<option value="{{ project.id }}" data-subtext="(project_id: {{ project.id }})">{{ project.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
<button id="btn-save-modify-email-receiver-setting" type="button" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
{% endblock app_content %}
{% block scripts %}