作者 杨再宏

新增邮件与短信发送;代码优化

<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="Flask">
<option name="enabled" value="true" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/app/templates" />
</list>
</option>
</component>
</module>
\ No newline at end of file
... ...
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="24">
<item index="0" class="java.lang.String" itemvalue="alembic" />
<item index="1" class="java.lang.String" itemvalue="python-dateutil" />
<item index="2" class="java.lang.String" itemvalue="SQLAlchemy" />
<item index="3" class="java.lang.String" itemvalue="setuptools" />
<item index="4" class="java.lang.String" itemvalue="MarkupSafe" />
<item index="5" class="java.lang.String" itemvalue="python-editor" />
<item index="6" class="java.lang.String" itemvalue="Jinja2" />
<item index="7" class="java.lang.String" itemvalue="pip" />
<item index="8" class="java.lang.String" itemvalue="itsdangerous" />
<item index="9" class="java.lang.String" itemvalue="Flask" />
<item index="10" class="java.lang.String" itemvalue="email-validator" />
<item index="11" class="java.lang.String" itemvalue="dnspython" />
<item index="12" class="java.lang.String" itemvalue="six" />
<item index="13" class="java.lang.String" itemvalue="Flask-Script" />
<item index="14" class="java.lang.String" itemvalue="Werkzeug" />
<item index="15" class="java.lang.String" itemvalue="wheel" />
<item index="16" class="java.lang.String" itemvalue="Flask-WTF" />
<item index="17" class="java.lang.String" itemvalue="click" />
<item index="18" class="java.lang.String" itemvalue="Flask-SQLAlchemy" />
<item index="19" class="java.lang.String" itemvalue="WTForms" />
<item index="20" class="java.lang.String" itemvalue="Flask-Migrate" />
<item index="21" class="java.lang.String" itemvalue="PyMySQL" />
<item index="22" class="java.lang.String" itemvalue="Mako" />
<item index="23" class="java.lang.String" itemvalue="idna" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="W292" />
<option value="E501" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N801" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyShadowingBuiltinsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredNames">
<list>
<option value="list" />
<option value="sum" />
</list>
</option>
</inspection_tool>
</profile>
</component>
\ No newline at end of file
... ...
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12 (IOTMS)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (IOTMS)" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="6667d1e0-67b9-4911-9383-6ccd47455133" name="更改" comment="提交项目">
<change beforePath="$PROJECT_DIR$/app/admin/views.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/admin/views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/api/response.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/api/response.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/1001_index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/1001_index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/3001_index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/3001_index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/4001_index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/4001_index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/5001_index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/5001_index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/6001_index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/6001_index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/7001_index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/7001_index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/8001_index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/8001_index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/templates/admin/menu.html" beforeDir="false" afterPath="$PROJECT_DIR$/app/templates/admin/menu.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/manage.py" beforeDir="false" afterPath="$PROJECT_DIR$/manage.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test.py" beforeDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Flask Main" />
<option value="HTML File" />
<option value="Python Script" />
</list>
</option>
</component>
<component name="FlaskConsoleOptions" custom-start-script="import sys&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;from flask.cli import ScriptInfo&#10;locals().update(ScriptInfo(create_app=None).load_app().make_shell_context())&#10;print(&quot;Python %s on %s\nApp: %s [%s]\nInstance: %s&quot; % (sys.version, sys.platform, app.import_name, app.env, app.instance_path))">
<envs>
<env key="FLASK_APP" value="app" />
</envs>
<option name="myCustomStartScript" value="import sys&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;from flask.cli import ScriptInfo&#10;locals().update(ScriptInfo(create_app=None).load_app().make_shell_context())&#10;print(&quot;Python %s on %s\nApp: %s [%s]\nInstance: %s&quot; % (sys.version, sys.platform, app.import_name, app.env, app.instance_path))" />
<option name="myEnvs">
<map>
<entry key="FLASK_APP" value="app" />
</map>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 4
}</component>
<component name="ProjectId" id="2euAaW8tC7vFanl3HDgjL0fAoQP" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;DefaultHtmlFileTemplate&quot;: &quot;HTML File&quot;,
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;last_opened_file_path&quot;: &quot;E:/python12.0Project/flask/IOTMS/app/templates/admin&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="E:\python12.0Project\flask\IOTMS\app\templates\admin" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="E:\python12.0Project\flask\IOTMS\app" />
</key>
</component>
<component name="RunManager">
<configuration name="IOTMS" type="PythonConfigurationType" factoryName="Python">
<module name="IOTMS" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/__init__.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="IOTMS" type="Python.FlaskServer">
<module name="IOTMS" />
<option name="target" value="$PROJECT_DIR$/app/__init__.py" />
<option name="targetType" value="PATH" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="launchJavascriptDebuger" value="false" />
<method v="2" />
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="默认任务">
<changelist id="6667d1e0-67b9-4911-9383-6ccd47455133" name="更改" comment="" />
<created>1712744153440</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1712744153440</updated>
<workItem from="1712744178234" duration="539000" />
<workItem from="1712797526665" duration="19598000" />
<workItem from="1712883238837" duration="10276000" />
<workItem from="1712911806583" duration="1622000" />
<workItem from="1713147036316" duration="20687000" />
<workItem from="1713230674276" duration="11238000" />
<workItem from="1713256268965" duration="5659000" />
<workItem from="1713316224129" duration="26153000" />
<workItem from="1713402221547" duration="16235000" />
<workItem from="1713489035662" duration="10873000" />
<workItem from="1713754186717" duration="13996000" />
<workItem from="1713921132189" duration="1437000" />
<workItem from="1713925651307" duration="10390000" />
<workItem from="1714007621362" duration="13881000" />
<workItem from="1714095253280" duration="1258000" />
<workItem from="1714266356827" duration="1983000" />
<workItem from="1714352589052" duration="6416000" />
<workItem from="1714381984518" duration="2081000" />
<workItem from="1714439832284" duration="11106000" />
<workItem from="1715062841268" duration="15311000" />
<workItem from="1715130405561" duration="23708000" />
<workItem from="1715216726319" duration="20414000" />
<workItem from="1715302475700" duration="24941000" />
<workItem from="1715389298807" duration="12116000" />
<workItem from="1715562838288" duration="17298000" />
<workItem from="1715649238545" duration="25313000" />
<workItem from="1715735641302" duration="12530000" />
<workItem from="1715822154508" duration="16862000" />
<workItem from="1715907880472" duration="10486000" />
<workItem from="1715928408269" duration="11056000" />
<workItem from="1716167939911" duration="21674000" />
<workItem from="1716270839068" duration="5119000" />
<workItem from="1716346370983" duration="2490000" />
<workItem from="1716771942520" duration="15082000" />
<workItem from="1716861607617" duration="5149000" />
<workItem from="1716881478181" duration="638000" />
<workItem from="1716883475984" duration="306000" />
<workItem from="1716883858098" duration="1211000" />
<workItem from="1716885478533" duration="6120000" />
<workItem from="1716945001118" duration="10963000" />
<workItem from="1717038536867" duration="2734000" />
<workItem from="1717050517193" duration="2002000" />
<workItem from="1717054719755" duration="2594000" />
<workItem from="1717057571743" duration="5979000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="提交项目" />
<option name="LAST_COMMIT_MESSAGE" value="提交项目" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/admin/views.py</url>
<line>1292</line>
<option name="timeStamp" value="4" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/admin/views.py</url>
<line>1380</line>
<option name="timeStamp" value="8" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/admin/views.py</url>
<line>1240</line>
<option name="timeStamp" value="9" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/admin/views.py</url>
<line>450</line>
<option name="timeStamp" value="10" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/admin/views.py</url>
<line>1646</line>
<option name="timeStamp" value="12" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/admin/views.py</url>
<line>981</line>
<option name="timeStamp" value="31" />
</line-breakpoint>
<line-breakpoint enabled="true" type="javascript">
<url>file://$PROJECT_DIR$/app/templates/admin/alarm_list.html</url>
<line>262</line>
<option name="timeStamp" value="32" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/IOTMS$views.coverage" NAME="views 覆盖结果" MODIFIED="1717061804597" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/app/admin" />
<SUITE FILE_PATH="coverage/IOTMS$Flask__manage_py_.coverage" NAME="Flask (manage.py) 覆盖结果" MODIFIED="1717062026498" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
<SUITE FILE_PATH="coverage/IOTMS$IOTMS.coverage" NAME="IOTMS 覆盖结果" MODIFIED="1717061297780" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
</component>
</project>
\ No newline at end of file
... ...
... ... @@ -2,6 +2,8 @@
import os
import uuid
from datetime import datetime
import app.api.response
from app import db
from . import admin
from flask import render_template, redirect, url_for, flash, session, request, g, abort, make_response, current_app
... ... @@ -15,7 +17,6 @@ from functools import wraps
from app.config import DeviceType as DT
from app.api.stack_func import get_stack
current_user = ""
... ... @@ -73,7 +74,8 @@ def change_filename(filename):
@admin.route("/")
@admin_login
def index():
days = datetime.strptime(f'{datetime.now().year}-{datetime.now().month}-{datetime.now().day} 00:00', "%Y-%m-%d %H:%M")
days = datetime.strptime(f'{datetime.now().year}-{datetime.now().month}-{datetime.now().day} 00:00',
"%Y-%m-%d %H:%M")
device_data = Device.query.group_by(
Device.devicetype_id
... ... @@ -81,10 +83,7 @@ def index():
Device.devicetype_id.asc()
).all()
for d in device_data:
if d.devicetype.type == 7001:
for dd in d.devicetype.device:
print(dd.title)
print(d.devicetype.type)
video = Alarm.query.join(
Device
... ... @@ -269,6 +268,60 @@ def user_list():
return render_template("admin/user_list.html", page_data=page_data, year=datetime.now().year)
@admin.route("/email/notification/", methods=["GET"])
@admin_login
def email_notification():
"""
邮件通知
"""
page = request.args.get('page', 1, type=int) # 获取page参数值
keyword = request.args.get('keyword', '', type=str)
if keyword:
# 根据姓名或者邮箱查询
filters = or_(User.email == keyword)
page_data = User.query.filter(
User.email is not None
).filter(filters).order_by(
User.addtime.desc()
).paginate(page=page, per_page=10)
else:
page_data = User.query.filter(
User.email is not None
).order_by(
User.addtime.desc()
).paginate(page=page, per_page=10)
return render_template("admin/email_notification.html", page_data=page_data, year=datetime.now().year)
@admin.route("/phone/notification/", methods=["GET"])
@admin_login
def phone_notification():
"""
邮件通知
"""
page = request.args.get('page', 1, type=int) # 获取page参数值
keyword = request.args.get('keyword', '', type=str)
if keyword:
# 根据姓名或者邮箱查询
filters = or_(User.phone == keyword)
page_data = User.query.filter(
User.phone is not None
).filter(filters).order_by(
User.addtime.desc()
).paginate(page=page, per_page=10)
else:
page_data = User.query.filter(
User.phone is not None
).order_by(
User.addtime.desc()
).paginate(page=page, per_page=10)
return render_template("admin/phone_notification.html", page_data=page_data, year=datetime.now().year)
@admin.route('/power/add/', methods=["GET", "POST"])
@admin_login
def power_add():
... ... @@ -977,7 +1030,8 @@ def alarm_list():
).order_by(
Alarm.addtime.desc()
).paginate(page=page, per_page=10)
return render_template("admin/alarm_list.html", key=last_key, st=last_st, et=last_et, page_data=page_data, year=datetime.now().year)
return render_template("admin/alarm_list.html", key=last_key, st=last_st, et=last_et, page_data=page_data,
year=datetime.now().year)
@admin.route("/alarm/edit/", methods=["GET"])
... ... @@ -1045,7 +1099,8 @@ def alarm_statistics():
if is_valid_time_format(dt2.replace("T", " ")):
et = dt2
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
return render_template("admin/alarm_statistics.html", s_url=request.host_url, st=st, et=et, year=datetime.now().year)
return render_template("admin/alarm_statistics.html", s_url=request.host_url, st=st, et=et,
year=datetime.now().year)
@admin.route("/notification/list/", methods=["GET"])
... ... @@ -1060,6 +1115,40 @@ def notification_list():
return render_template("admin/notification_list.html", page_data="", year=datetime.now().year)
@admin.route("/emailnotification_edit", methods=["GET"])
def emailnotification_edit():
try:
id = request.args.get("id", 0)
user = User.query.get_or_404(int(id)) # 根据ID查找设备是否存在
# 属性赋值
user.emailnotification = request.args.get('email', 0)
db.session.commit() # 提交数据
return app.api.response.Response(code=200, msg='ok', success=True).json
except:
return app.api.response.Response(code=400, msg='err', success=False).json
@admin.route("/phonenotification_edit", methods=["GET"])
def phonenotification_edit():
try:
id = request.args.get("id", 0)
user = User.query.get_or_404(int(id)) # 根据ID查找设备是否存在
# 属性赋值
user.phonenotification = request.args.get('phone', 0)
db.session.commit() # 提交数据
return app.api.response.Response(code=200, msg='ok', success=True).json
except:
return app.api.response.Response(code=400, msg='err', success=False).json
@admin.route("/adminloginlog/list/", methods=["GET"])
@admin_login
def adminloginlog_list(page=None):
... ... @@ -1570,13 +1659,12 @@ def get_line_chart():
idx = 9
@admin.route("/lineDynamicData")
def update_line_data():
# global idx
# idx = idx + 1
# return jsonify({"name": idx, "value": randrange(50, 80)})
c = line_base()
return c.dump_options_with_quotes()
@admin.route("/getDynamicData")
def update_dynamic_data():
list = app.api.stack_func.get_stack()
# print(type(list))
# print(list)
return list
@admin.route("/barChart")
... ... @@ -1586,25 +1674,36 @@ def get_bar_chart():
def get_alarm_statistics(start_time, end_time):
pd = Alarm.query.join(
Device
).join(
DeviceType
).filter(
Alarm.device_id == Device.id
).filter(
Device.devicetype_id == DeviceType.type
).filter(
datetime.strptime(start_time, "%Y-%m-%d %H:%M") < Alarm.addtime
).filter(
Alarm.addtime < datetime.strptime(end_time, "%Y-%m-%d %H:%M")
).order_by(
Device.devicetype_id.asc()
).group_by(
DeviceType.type
).all()
return pd
# pd = Alarm.query.join(
# Device
# ).join(
# DeviceType
# ).filter(
# Alarm.device_id == Device.id
# ).filter(
# Device.devicetype_id == DeviceType.type
# ).filter(
# datetime.strptime(start_time, "%Y-%m-%d %H:%M") < Alarm.addtime
# ).filter(
# Alarm.addtime < datetime.strptime(end_time, "%Y-%m-%d %H:%M")
# ).order_by(
# Device.devicetype_id.asc()
# ).group_by(
# DeviceType.type
# ).all()
from sqlalchemy import text
sql = text(
f"SELECT count(a.id) as c, dt.`name` as n FROM alarm as a, device as d, devicetype as dt WHERE a.addtime>'{start_time}' \
and a.addtime<'{end_time}' AND a.device_id=d.id and d.devicetype_id=dt.type \
GROUP BY dt.type ORDER BY c desc")
res = db.session.execute(sql).fetchall()
for r in res:
print(r)
return res
def alarm_bar_base(alarm, st, et) -> Bar:
... ... @@ -1613,8 +1712,8 @@ def alarm_bar_base(alarm, st, et) -> Bar:
alarm_name = []
alarm_count = []
for a in alarm:
alarm_name.append(a.device.devicetype.name)
alarm_count.append(len(a.device.alarm))
alarm_name.append(a[1])
alarm_count.append(a[0])
# for dt in devicetype:
# if dt.name in alarm_name:
... ... @@ -1646,7 +1745,7 @@ def alarm_bar_base(alarm, st, et) -> Bar:
.set_series_opts(label_opts=opts.LabelOpts(position="right"))
.set_global_opts(
title_opts=opts.TitleOpts(title="设备报警柱形图", subtitle="报警次数",),
title_opts=opts.TitleOpts(title="设备报警柱形图", subtitle="报警次数", ),
legend_opts=opts.LegendOpts(
orient="center", # 水平排布
),
... ... @@ -1672,8 +1771,8 @@ def alarm_pie_base(alarm) -> Pie:
alarm_name = []
alarm_count = []
for a in alarm:
alarm_name.append(a.device.devicetype.name)
alarm_count.append(len(a.device.alarm))
alarm_name.append(a[1])
alarm_count.append(a[0])
c = (
Pie()
.add(
... ... @@ -1683,7 +1782,7 @@ def alarm_pie_base(alarm) -> Pie:
)
.set_global_opts(
title_opts=opts.TitleOpts(title="设备报警饼状图", subtitle="报警次数"),
#legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
# legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
)
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
)
... ... @@ -1708,7 +1807,7 @@ def gauge_chart():
Gauge(init_opts=opts.InitOpts(width="150px", height="150px"))
.add(
"电流图",
[("漏电流(mA)", 155.5),],
[("漏电流(mA)", 155.5), ],
max_=1000,
split_number=5,
axisline_opts=opts.AxisLineOpts(
... ... @@ -1799,5 +1898,3 @@ def get_liquid_chart():
)
return c.dump_options_with_quotes()
... ...
... ... @@ -41,9 +41,9 @@ class GasConcentration:
unit: str
lowAlarmValue: float
highAlarmValue: float
range: float
type: int
name: str
gasRange: float
gasType: int
gasName: str
lastUpdateTime: str
@property
... ...
import zmail
import urllib.request
from urllib import parse
def send_sms(mobile, sms_info):
try:
"""
#python3
#接口类型:互亿无线触发短信接口,支持发送验证码短信、订单通知短信等。
#账户注册:请通过该地址开通账户https://user.ihuyi.com/new/register.html
#注意事项:
#(1)调试期间,请用默认的模板进行测试,默认模板详见接口文档;
#(2)请使用 用户名 及 APIkey来调用接口,APIkey在会员中心可以获取;
#(3)该代码仅供接入互亿无线短信接口参考使用,客户可根据实际需要自行编写;
"""
# 接口地址
url = 'http://106.ihuyi.com/webservice/sms.php?method=Submit'
# 定义请求的数据
values = {
'account': 'C61245995',
'password': 'b018ad136d2005b1b687dd16b119e78f',
'mobile': mobile,
'content': sms_info,
'format': 'json',
}
# 将数据进行编码
data = urllib.parse.urlencode(values).encode(encoding='UTF8')
# 发起请求
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
res = response.read()
return res
except Exception as e:
print(e)
def send_email(recv_email, title, content):
try:
# 设置邮件信息
mail_content = {
'subject': title, # 邮件标题
'content_text': content # 邮件内容
}
# 发件人的用户名和密码
server = zmail.server('yangzaihong@163.com', 'OTGKSKPJIMBXYLUK') # 发件人
# 发送邮件
server.send_mail(recv_email, mail_content) # 收件人
print('邮件已发送完毕')
except Exception as e:
print(e)
... ...
... ... @@ -27,6 +27,8 @@ class User(db.Model):
__tablename__ = "user"
#__table_args__ = {"useexisting": True}
id = db.Column(db.Integer, primary_key=True) # 编号
emailnotification = db.Column(db.Integer) # 邮件通知
phonenotification = db.Column(db.Integer) # 短信通知
username = db.Column(db.String(100)) # 用户名
pwd = db.Column(db.String(1024)) # 密码
email = db.Column(db.String(100)) # 邮箱
... ...
... ... @@ -69,7 +69,7 @@
</div>
<div class="product-info">
<a href="javascript:void(0)" class="product-title">{{dd.title}}
<span class="label label-success pull-right">在线</span>
<span class="label label-success pull-right" id="span-{{ d.devicetype.type }}-{{ dd.address }}">在线</span>
</a>
<span class="product-description">
检测区域:{{ dd.detectingpoint.no }}#{{ dd.detectingpoint.name }}
... ...
... ... @@ -69,7 +69,7 @@
</div>
<div class="product-info">
<a href="javascript:void(0)" class="product-title">{{dd.title}}
<span class="label label-success pull-right">在线</span>
<span class="label label-success pull-right" id="span-{{ d.devicetype.type }}-{{ dd.address }}">在线</span>
</a>
<span class="product-description">
检测区域:{{ dd.detectingpoint.no }}#{{ dd.detectingpoint.name }}
... ...
... ... @@ -56,7 +56,7 @@
</div>
<div class="product-info">
<a href="javascript:void(0)" class="product-title">{{dd.title}}
<span class="label label-success pull-right">在线</span>
<span class="label label-success pull-right" id="span-{{ d.devicetype.type }}-{{ dd.address }}">在线</span>
</a>
<span class="product-description">
检测区域:{{ dd.detectingpoint.no }}#{{ dd.detectingpoint.name }}
... ...
... ... @@ -57,7 +57,7 @@
</div>
<div class="product-info">
<a href="javascript:void(0)" class="product-title">{{dd.title}}
<span class="label label-success pull-right">在线</span>
<span class="label label-success pull-right" id="span-{{ d.devicetype.type }}-{{ dd.address }}">在线</span>
</a>
<span class="product-description">
检测区域:{{ dd.detectingpoint.no }}#{{ dd.detectingpoint.name }}
... ...
... ... @@ -57,7 +57,7 @@
</div>
<div class="product-info">
<a href="javascript:void(0)" class="product-title">{{dd.title}}
<span class="label label-success pull-right">在线</span>
<span class="label label-success pull-right" id="span-{{ d.devicetype.type }}-{{ dd.address }}">在线</span>
</a>
<span class="product-description">
检测区域:{{ dd.detectingpoint.no }}#{{ dd.detectingpoint.name }}
... ...
... ... @@ -112,7 +112,7 @@
</div>
<div class="product-info">
<a href="javascript:void(0)" class="product-title">{{dd.title}}
<span class="label label-success pull-right">在线</span>
<span class="label label-success pull-right" id="span-{{ d.devicetype.type }}-{{ dd.address }}">在线</span>
</a>
<span class="product-description">
检测区域:{{ dd.detectingpoint.no }}#{{ dd.detectingpoint.name }}
... ...
... ... @@ -57,7 +57,7 @@
</div>
<div class="product-info">
<a href="javascript:void(0)" class="product-title">{{dd.title}}
<span class="label label-success pull-right">在线</span>
<span class="label label-success pull-right" id="span-{{ d.devicetype.type }}-{{ dd.address }}">在线</span>
</a>
<span class="product-description">
检测区域:{{ dd.detectingpoint.no }}#{{ dd.detectingpoint.name }}
... ...
{% extends 'admin/admin.html' %}
{% import "common/admin_page.html" as pg %}
{% block content %}
<!--内容-->
<section class="content-header">
<h1>安监物联管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 报警管理</a></li>
<li class="active">邮件通知</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">通知列表</h3>
<div class="box-tools">
<form action="" method="GET">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="keyword" class="form-control pull-right"
placeholder="请输入邮箱">
<div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="box-body table-responsive no-padding">
{% for msg in get_flashed_messages(category_filter=["ok"]) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功</h4>
{{ msg }}
</div>
{% endfor %}
<table class="table table-hover" id="table">
<tbody>
<tr>
<th>编号</th>
<th>昵称</th>
<th>邮箱</th>
<th>头像</th>
<th>选择</th>
<th>操作</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.username }}</td>
<td>{{ v.email }}</td>
<td>
<img style="width: 50px;height: 50px;"
src="{{ url_for('static', filename='uploads/users/huazai.jpg') }}"
class="img-responsive center-block" alt="">
</td>
<td>
{% if v.emailnotification == 1 %}
<input type="checkbox" id="check{{ v.id }}" checked="checked">
{% else %}
<input type="checkbox" id="check{{ v.id }}">
{% endif %}
</td>
<td>
<button onclick="submit_btn(this)" id="{{ v.id }}" class="btn btn-info btn-xs">保存</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.user_list') }}
</div>
</div>
</div>
</div>
</section>
<!--内容-->
{% endblock %}
{% block js %}
<script>
$(document).ready(function(){
$("#g-5").addClass("active");
$("#g-5-2").addClass("active");
});
function submit_btn(obj) {
var id = $(obj).attr("id");
try {
var check = document.getElementById("check"+id).checked;
var c = 1;
if (check)
{
c = 1;
}
else
{
c = 0;
}
var s_url = "{{ s_url }}";
$.ajax({
type: "GET",
url: s_url + "/emailnotification_edit",
data: {id:id, email:c},
dataType: "json",
success: function (result) {
alert("保存成功");
},
error: function (e) {
alert("error");
}
});
}
catch (e) {
alert(e);
}
}
</script>
{% endblock %}
\ No newline at end of file
... ...
... ... @@ -30,27 +30,38 @@
{% block js %}
<script>
$(document).ready(function(){
$(document).ready(function() {
$("#g-1").addClass("active");
$("#g-1-1").addClass("active");
});
$(document).ready(function(){
var charta = echarts.init(document.getElementById('pie_a'), 'white', {renderer: 'canvas'});
var chartv = echarts.init(document.getElementById('pie_v'), 'white', {renderer: 'canvas'});
//var chartl = echarts.init(document.getElementById('liquid'), 'white', {renderer: 'canvas'});
$(document).ready(function() {
var s_url = "{{ s_url }}";
var pie_a = document.getElementById('pie_a');
var pie_v = document.getElementById('pie_v');
if (pie_a) {
var charta = echarts.init(pie_a, 'white', {renderer: 'canvas'});
$(
function () {
fetchDataA(charta);
}
);
}
if (pie_v) {
var chartv = echarts.init(pie_v, 'white', {renderer: 'canvas'});
$(
function () {
fetchDataV(chartv);
//fetchDataL(chartl);
//setInterval(getDynamicData, 2000);
}
);
}
function fetchDataA() {
$.ajax({
... ... @@ -87,25 +98,40 @@
});
}
setInterval(getDynamicData, 10000);
function getDynamicData() {
$.ajax({
type: "GET",
url: s_url + "/lineDynamicData",
url: s_url + "/getDynamicData",
dataType: "json",
success: function (result) {
chart.setOption(result);
//old_data.push([result.name, result.value]);
//if (old_data.length > 20)
//alert(old_data);
//old_data.shift();
//alert(old_data);
//chart.setOption({
// series: [{data: old_data}]
//});
dataAnalysis(result);
}
});
}
function dataAnalysis(res) {
if (res == null) return;
try {
if (res.length> 0) {
for (var i = 0; i < res.length; i++) {
var r = res[i];
}
}
}
catch (e) {
alert(e);
}
}
});
</script>
<script src="{{url_for('static',filename='base/js/jquery.easing.1.3.js')}}"></script>
... ...
... ... @@ -109,12 +109,12 @@
<ul class="treeview-menu">
<li id="g-5-1">
<a href="#">
<a href="{{ url_for('admin.phone_notification') }}">
<i class="fa fa-circle-o"></i> 短信通知
</a>
</li>
<li id="g-5-2">
<a href="#">
<a href="{{ url_for('admin.email_notification') }}">
<i class="fa fa-circle-o"></i> 邮件通知
</a>
</li>
... ...
{% extends 'admin/admin.html' %}
{% import "common/admin_page.html" as pg %}
{% block content %}
<!--内容-->
<section class="content-header">
<h1>安监物联管理系统</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> 报警管理</a></li>
<li class="active">短信通知</li>
</ol>
</section>
<section class="content" id="showcontent">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">通知列表</h3>
<div class="box-tools">
<form action="" method="GET">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="keyword" class="form-control pull-right"
placeholder="请输入手机号">
<div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="box-body table-responsive no-padding">
{% for msg in get_flashed_messages(category_filter=["ok"]) %}
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×
</button>
<h4><i class="icon fa fa-check"></i> 操作成功</h4>
{{ msg }}
</div>
{% endfor %}
<table class="table table-hover" id="table">
<tbody>
<tr>
<th>编号</th>
<th>昵称</th>
<th>手机</th>
<th>头像</th>
<th>选择</th>
<th>操作</th>
</tr>
{% for v in page_data.items %}
<tr>
<td>{{ v.id }}</td>
<td>{{ v.username }}</td>
<td>{{ v.phone }}</td>
<td>
<img style="width: 50px;height: 50px;"
src="{{ url_for('static', filename='uploads/users/huazai.jpg') }}"
class="img-responsive center-block" alt="">
</td>
<td>
{% if v.phonenotification == 1 %}
<input type="checkbox" id="check{{ v.id }}" checked="checked">
{% else %}
<input type="checkbox" id="check{{ v.id }}">
{% endif %}
</td>
<td>
<button onclick="submit_btn(this)" id="{{ v.id }}" class="btn btn-info btn-xs">保存</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="box-footer clearfix">
{{ pg.page(page_data,'admin.user_list') }}
</div>
</div>
</div>
</div>
</section>
<!--内容-->
{% endblock %}
{% block js %}
<script>
$(document).ready(function(){
$("#g-5").addClass("active");
$("#g-5-1").addClass("active");
});
function submit_btn(obj) {
var id = $(obj).attr("id");
try {
var check = document.getElementById("check"+id).checked;
var c = 1;
if (check)
{
c = 1;
}
else
{
c = 0;
}
var s_url = "{{ s_url }}";
$.ajax({
type: "GET",
url: s_url + "/phonenotification_edit",
data: {id:id, phone:c},
dataType: "json",
success: function (result) {
alert("保存成功");
},
error: function (e) {
alert("error");
}
});
}
catch (e) {
alert(e);
}
}
</script>
{% endblock %}
\ No newline at end of file
... ...
... ... @@ -6,28 +6,6 @@ import zmail
app = create_app("default")
def send_email(title, content):
try:
# 设置邮件信息
mail_content = {
'subject': title, # 邮件标题
'content_text': content # 邮件内容
}
# 发件人的用户名和密码
server = zmail.server('yangzaihong@163.com', 'OTGKSKPJIMBXYLUK') # 发件人
# 发送邮件
server.send_mail('905462018@qq.com', mail_content) # 收件人
print('邮件已发送完毕')
except Exception as e:
print(e)
def get_generate_password_hash(pwd):
from werkzeug.security import generate_password_hash
return generate_password_hash(password=pwd)
if __name__ == '__main__':
# print(get_generate_password_hash("123456"))
# send_email('测试', '测试')
app.run(host='0.0.0.0', port=5000, debug=True)
... ...
import pyecharts
print(pyecharts.__version__) # 输出 '2.0.5'
#print(pyecharts.__python_version__) # 输出 pyecharts依赖的Python版本
\ No newline at end of file