Remove supervisor.log and update uWSGI configuration paths to reflect new directory structure; enhance filtering options in work order views and improve CSS styles for better UI responsiveness.

This commit is contained in:
2025-12-10 12:00:50 +08:00
parent c7dc4d6c02
commit 0f41063688
39 changed files with 2643 additions and 3698 deletions
+7 -7
View File
@@ -2,7 +2,7 @@
SECRET_KEY=kU/W5y3uFbWuK1x+RTTOPgLp38yM6Z7d
# 数据库连接
DATABASE_URI=mysql+pymysql://4an:GtbJp6Ai5azntnTB@10.10.10.253/4an
DATABASE_URI=mysql+pymysql://4an:GtbJp6Ai5azntnTB@10.10.10.14/4an
# 量子密信消息Webhook
LZMX_WEBHOOK_URL=http://imtwo.zdxlz.com/im-external/v1/webhook/send?key=ef1dc605827f425e96491ce5725b5274
@@ -11,7 +11,7 @@ LZMX_WEBHOOK_URL=http://imtwo.zdxlz.com/im-external/v1/webhook/send?key=ef1dc605
UPLOAD_FOLDER=static/uploads
# 1key110数据库配置
KEY110_DB_HOST=10.10.10.253
KEY110_DB_HOST=10.10.10.14
KEY110_DB_USER=1key110
KEY110_DB_PASSWORD=KzdKtf7KfkXe7iCN
KEY110_DB_DATABASE=1key110
@@ -20,11 +20,11 @@ KEY110_DB_DATABASE=1key110
UWSGI_HTTP=0.0.0.0:18019
UWSGI_PROCESSES=4
UWSGI_THREADS=2
UWSGI_LOG_FILE=/opt/1panel/docker/compose/4an/uwsgi.log
UWSGI_VIRTUALENV=/mnt/nfs/.venv
UWSGI_CHDIR=/opt/1panel/docker/compose/4an/app
UWSGI_PID_FILE=/opt/1panel/docker/compose/4an/uwsgi.pid
UWSGI_SOCKET=/opt/1panel/docker/compose/4an/uwsgi.sock
UWSGI_LOG_FILE=/home/v6ole/pyproject/4an/uwsgi.log
UWSGI_VIRTUALENV=/home/v6ole/pyproject/venv/
UWSGI_CHDIR=/home/v6ole/pyproject/4an/app
UWSGI_PID_FILE=/home/v6ole/pyproject/4an/uwsgi.pid
UWSGI_SOCKET=/home/v6ole/pyproject/4an/uwsgi.sock
# uWSGI性能优化配置
UWSGI_MASTER=true
Binary file not shown.
Binary file not shown.
Executable → Regular
+83 -583
View File
@@ -1,594 +1,94 @@
2025-04-23 09:18:08 INFO: 应用启动
2025-04-23 09:18:19 INFO: 用户 韦矍森(19977899008) 登录成功
2025-04-23 09:18:34 INFO: 用户 韦矍森 访问统计页面
2025-04-23 09:18:35 INFO: 用户 韦矍森 访问历史记录页面
2025-04-23 09:18:36 INFO: 用户 韦矍森 访问统计页面
2025-04-23 09:18:38 INFO: 用户 韦矍森 访问历史记录页面
2025-04-23 09:18:42 INFO: 用户 韦矍森 访问历史记录页面
2025-04-23 09:18:44 INFO: 用户 韦矍森 访问统计页面
2025-04-23 09:18:45 INFO: 用户 韦矍森 访问历史记录页面
2025-04-23 09:18:46 INFO: 用户 韦矍森 访问统计页面
2025-04-23 10:56:36 INFO: 用户 韦矍森 访问历史记录页面
2025-04-23 10:56:49 INFO: 用户 韦矍森 访问统计页面
2025-04-23 11:05:57 INFO: 用户 韦矍森 开始同步离线设备
2025-04-23 11:05:57 INFO: 同步完成:创建了 77 个工单,恢复了 0 个设备
2025-04-23 11:05:59 INFO: 用户请求验证码
2025-04-23 11:05:59 INFO: 验证码获取成功
2025-04-23 11:06:04 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-04-23 11:06:04 INFO: 尝试登录中兴平台
2025-04-23 11:06:04 INFO: 登录成功,开始获取在线信息
2025-04-23 11:06:04 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-04-23 11:06:04 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 589 个
2025-04-23 11:06:05 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-04-23 11:06:05 INFO: 查询到 1294 个需要同步的设备
2025-04-23 11:06:06 INFO: 发现 472 个离线设备需要创建工单
2025-04-23 11:06:07 INFO: 成功创建 472 个工单
2025-04-23 11:06:42 INFO: 应用启动
2025-04-23 11:06:47 INFO: 用户 韦矍森(19977899008) 登录成功
2025-04-23 11:06:58 INFO: 用户 韦矍森 开始同步离线设备
2025-04-23 11:06:58 INFO: 同步完成:创建了 77 个工单,恢复了 0 个设备
2025-04-23 11:07:01 INFO: 用户请求验证码
2025-04-23 11:07:01 INFO: 验证码获取成功
2025-04-23 11:07:05 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-04-23 11:07:05 INFO: 尝试登录中兴平台
2025-04-23 11:07:06 INFO: 登录成功,开始获取在线信息
2025-04-23 11:07:06 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-04-23 11:07:06 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 589 个
2025-04-23 11:07:09 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-04-23 11:07:09 INFO: 查询到 1107 个需要同步的设备
2025-04-23 11:07:10 INFO: 发现 308 个离线设备需要创建工单
2025-04-23 11:07:10 INFO: 成功创建 308 个工单
2025-04-23 11:07:18 INFO: 用户 韦矍森 访问统计页面
2025-04-24 10:28:55 INFO: 用户 韦矍森(19977899008) 登录成功
2025-04-24 10:31:33 INFO: 用户 韦矍森 访问统计页面
2025-04-24 10:32:55 INFO: 用户 韦矍森(19977899008) 登录成功
2025-04-24 10:33:16 INFO: 用户 韦矍森 访问统计页面
2025-04-24 10:33:17 INFO: 用户 韦矍森 访问历史记录页面
2025-04-24 10:35:18 INFO: 用户 韦矍森 开始同步离线设备
2025-04-24 10:35:18 INFO: 同步完成:创建了 3 个工单,恢复了 3 个设备
2025-04-24 16:01:53 INFO: 用户 韦宗兴(15307786493) 登录成功
2025-04-24 17:25:05 INFO: 用户 韦宗兴 访问统计页面
2025-04-24 17:25:09 INFO: 用户 韦宗兴 访问统计页面
2025-04-24 17:25:46 INFO: 用户 韦宗兴 访问统计页面
2025-04-24 17:29:40 INFO: 用户 韦宗兴 访问统计页面
2025-04-24 17:32:35 INFO: 用户 韦宗兴 开始创建手工故障单
2025-04-24 17:32:39 INFO: 用户 韦宗兴 开始创建手工故障单
2025-04-24 17:32:51 INFO: 用户 韦宗兴 创建手工故障单成功:M202504240001
2025-04-24 17:32:51 INFO: 用户 韦宗兴 访问历史记录页面
2025-04-24 17:32:54 INFO: 用户 韦宗兴 访问历史记录页面
2025-04-24 17:36:32 INFO: 用户 韦宗兴 开始创建手工故障
2025-04-24 17:36:36 INFO: 用户 韦宗兴 创建手工故障单成功:M202504240002
2025-04-24 17:36:36 INFO: 用户 韦宗兴 访问历史记录页面
2025-04-24 17:36:51 INFO: 用户 韦宗兴 查看工单 M202504240001 的详情
2025-04-24 17:36:54 INFO: 用户 韦宗兴 查看工单 M202504240001 的详情
2025-04-25 10:00:56 INFO: 应用启动
2025-04-28 09:36:26 INFO: 应用启动
2025-04-29 15:10:25 INFO: 用户 韦矍森(19977899008) 登录成功
2025-04-29 15:11:42 INFO: 用户 韦矍森 访问历史记录页面
2025-04-29 15:12:16 INFO: 用户 韦矍森 访问历史记录页面
2025-04-29 15:12:17 INFO: 用户 韦矍森 访问统计页面
2025-04-29 15:13:14 INFO: 用户 覃建(18174938515) 登录成功
2025-04-29 15:14:07 INFO: 用户 韦矍森(19977899008) 登出
2025-04-29 15:14:12 INFO: 用户 韦矍森(19977899008) 登录成功
2025-04-29 15:14:19 INFO: 用户 覃建 访问统计页面
2025-04-29 15:14:42 INFO: 用户 韦矍森 访问历史记录页面
2025-04-29 15:20:42 INFO: 用户 覃建 开始创建手工故障单
2025-04-29 15:20:45 INFO: 用户 覃建 创建手工故障单成功:M202504290001
2025-04-29 15:20:45 INFO: 用户 覃建 访问历史记录页面
2025-05-03 01:30:02 INFO: 应用启动
2025-05-07 08:50:16 INFO: 应用启动
2025-05-08 08:49:44 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-08 08:54:37 INFO: 应用启动
2025-05-08 09:13:33 INFO: 应用启动
2025-05-08 09:13:47 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-08 09:13:49 INFO: 用户 韦矍森 访问历史记录页面
2025-05-08 09:19:29 INFO: 用户 韦矍森 访问历史记录页面
2025-05-08 09:19:31 INFO: 用户 韦矍森 访问统计页面
2025-05-08 09:20:48 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-08 09:30:46 INFO: 应用启动
2025-05-08 09:30:54 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-12 14:59:10 INFO: 用户 覃建(18174938515) 登录成功
2025-05-12 15:06:39 INFO: 用户 覃建 访问统计页面
2025-05-12 15:06:57 INFO: 用户 覃建 访问历史记录页面
2025-05-12 15:07:04 INFO: 用户 覃建 访问统计页面
2025-05-12 15:08:43 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-12 15:14:27 INFO: 用户 韦矍森 开始同步离线设备
2025-05-12 15:14:27 INFO: 同步完成:创建了 4 个工单,恢复了 1 个设备
2025-05-12 15:14:30 INFO: 用户请求验证码
2025-05-12 15:14:30 INFO: 验证码获取成功
2025-05-12 15:14:34 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-05-12 15:14:34 INFO: 尝试登录中兴平台
2025-05-12 15:14:34 INFO: 登录成功,开始获取在线信息
2025-05-12 15:14:34 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-05-12 15:14:35 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 585 个
2025-05-12 15:14:47 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-05-12 15:14:47 INFO: 查询到 1107 个需要同步的设备
2025-05-12 15:14:48 INFO: 发现 21 个离线设备需要创建工单
2025-05-12 15:14:48 INFO: 成功创建 21 个工单
2025-05-12 15:15:49 INFO: 用户 覃建 访问统计页面
2025-05-12 18:04:43 INFO: 应用启动
2025-05-12 18:06:38 WARNING: 登录失败:用户不存在 (手机号: 199778990008)
2025-05-12 18:06:41 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-12 18:06:43 INFO: 用户 韦矍森 访问历史记录页面
2025-05-12 18:06:57 INFO: 用户 韦矍森 访问历史记录页面
2025-05-12 18:06:58 INFO: 用户 韦矍森 访问统计页面
2025-05-12 18:07:25 INFO: 用户 韦矍森 访问历史记录页面
2025-05-13 08:11:30 INFO: 用户 覃建(18174938515) 登录成功
2025-05-13 08:11:36 INFO: 用户 覃建 访问历史记录页面
2025-05-13 11:13:52 INFO: 用户 韦宗兴(15307786493) 登录成功
2025-05-13 11:32:42 INFO: 用户 韦矍森 访问统计页面
2025-05-13 11:57:15 INFO: 应用启动
2025-05-13 11:57:24 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-13 13:05:12 INFO: 用户 韦宗兴(15307786493) 登录成功
2025-05-14 17:45:07 INFO: 用户 韦矍森 访问统计页面
2025-05-14 17:45:35 INFO: 用户 韦矍森 检查设备工单状态,设备数量:4
2025-05-14 17:45:35 INFO: 发现 0 个设备存在故障工单
2025-05-14 17:45:54 INFO: 用户 韦矍森 检查设备工单状态,设备数量:3
2025-05-14 17:45:54 INFO: 发现 0 个设备存在故障工单
2025-05-14 17:46:34 INFO: 用户 易靖欢(18174939957) 登录成功
2025-05-14 17:49:50 INFO: 用户 易靖欢(18174939957) 登出
2025-05-14 17:50:06 INFO: 用户 黄建(19977818669) 登录成功
2025-05-14 17:51:52 INFO: 用户 黄建 访问历史记录页面
2025-05-14 17:51:54 INFO: 用户 黄建 访问统计页面
2025-05-14 17:51:58 INFO: 用户 黄建(19977818669) 登出
2025-05-14 17:52:02 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-14 17:52:04 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:52:05 INFO: 用户 韦矍森 访问统计页面
2025-05-14 17:53:39 INFO: 用户 韦矍森 导出月度统计报表
2025-05-14 17:54:13 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:54:18 INFO: 用户 韦矍森 访问统计页面
2025-05-14 17:54:59 INFO: 用户 韦矍森 访问统计页面
2025-05-14 17:57:08 INFO: 用户 韦矍森 访问统计页面
2025-05-14 17:57:46 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:57:50 INFO: 用户 韦矍森 查看工单 202505140007 的详情
2025-05-14 17:57:53 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:57:54 INFO: 用户 韦矍森 查看工单 202505140005 的详情
2025-05-14 17:57:54 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:57:55 INFO: 用户 韦矍森 查看工单 202505140001 的详情
2025-05-14 17:57:57 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:57:58 INFO: 用户 韦矍森 查看工单 202505120022 的详情
2025-05-14 17:58:13 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:58:18 INFO: 用户 韦矍森 查看工单 M202504240002 的详情
2025-05-14 17:58:24 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:58:26 INFO: 用户 韦矍森 查看工单 M202504220001 的详情
2025-05-14 17:58:28 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:58:29 INFO: 用户 韦矍森 查看工单 M202504220001 的详情
2025-05-14 17:58:32 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:58:33 INFO: 用户 韦矍森 查看工单 202504230324 的详情
2025-05-14 17:58:49 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:58:53 INFO: 用户 韦矍森 访问统计页面
2025-05-14 17:59:08 INFO: 用户 韦矍森 访问历史记录页面
2025-05-14 17:59:09 INFO: 用户 韦矍森 访问统计页面
2025-05-14 17:59:19 INFO: 用户 韦矍森 访问统计页面
2025-05-14 18:04:25 INFO: 用户 韦矍森 检查设备工单状态,设备数量:1
2025-05-14 18:04:25 INFO: 发现 0 个设备存在故障工单
2025-05-14 18:10:19 INFO: 应用启动
2025-05-14 18:10:30 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-15 14:44:38 INFO: 用户 韦矍森 访问统计页面
2025-05-19 21:47:13 INFO: 用户 韦矍森 访问统计页面
2025-05-19 21:47:33 INFO: 用户 韦矍森 访问历史记录页面
2025-05-19 21:47:39 INFO: 用户 韦矍森 访问统计页面
2025-05-19 21:49:07 INFO: 用户 韦矍森 导出月度统计报表
2025-05-19 23:58:35 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-19 23:58:40 INFO: 用户 韦矍森 访问历史记录页面
2025-05-19 23:58:42 INFO: 用户 韦矍森 访问统计页面
2025-05-19 23:58:51 INFO: 用户 韦矍森 导出月度统计报表
2025-05-20 00:07:56 INFO: 应用启动
2025-05-20 00:08:02 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-20 00:08:04 INFO: 用户 韦矍森 访问历史记录页面
2025-05-20 00:08:06 INFO: 用户 韦矍森 访问统计页面
2025-05-20 00:08:06 ERROR: Exception on /statistics [GET]
2025-11-27 16:03:48 INFO: 应用启动
2025-11-27 16:03:48 INFO: 错误处理器初始化完成
2025-11-27 16:03:57 INFO: 用户 韦矍森(19977899008) 登录成功
2025-11-27 16:03:57 INFO: 用户 韦矍森 访问仪表盘页面
2025-11-27 16:05:16 INFO: 应用启动
2025-11-27 16:05:16 INFO: 错误处理器初始化完成
2025-11-27 16:05:23 INFO: 用户 韦矍森 访问仪表盘页面
2025-11-27 16:05:29 INFO: 用户 韦矍森 访问历史记录页面
2025-11-27 16:05:30 INFO: 用户 韦矍森 访问历史记录页面
2025-12-03 14:31:04 INFO: 用户 韦矍森(19977899008) 登录成功
2025-12-03 14:31:04 INFO: 用户 韦矍森 访问仪表盘页面
2025-12-03 14:31:23 INFO: 用户 韦矍森 访问统计页面
2025-12-03 14:31:23 INFO: 用户 韦矍森 访问统计页面
2025-12-03 14:31:27 INFO: 用户 韦矍森 访问仪表盘页面
2025-12-03 14:31:27 INFO: 用户 韦矍森 访问统计页面
2025-12-03 14:31:27 INFO: 用户 韦矍森 访问统计页面
2025-12-03 14:31:31 INFO: 用户 韦矍森 访问统计页面
2025-12-03 14:31:31 INFO: 用户 韦矍森 访问统计页面
2025-12-03 14:32:03 INFO: 用户 韦矍森(19977899008) 登出
2025-12-03 14:32:29 INFO: 用户 唐昊(18977846300) 登录成功
2025-12-03 14:32:29 INFO: 用户 唐昊 访问仪表盘页面
2025-12-03 14:32:30 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:32:30 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:32:35 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:32:35 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:32:45 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:32:45 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:33:04 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:33:04 INFO: 用户 唐昊 访问统计页面
2025-12-03 14:33:12 INFO: 用户 韦炳育(18176156082) 登录成功
2025-12-03 14:33:12 INFO: 用户 韦炳育 访问仪表盘页面
2025-12-03 14:34:03 INFO: 用户 韦炳育 访问仪表盘页面
2025-12-03 14:38:02 INFO: 用户 韦炳育 开始创建手工故障单
2025-12-03 14:38:02 INFO: 用户 韦炳育 创建手工故障单成功:M202512030001
2025-12-03 14:38:02 INFO: 用户 韦炳育 访问历史记录页面
2025-12-03 14:38:05 INFO: 用户 韦炳育 访问历史记录页面
2025-12-03 14:38:29 INFO: 用户 韦炳育 访问仪表盘页面
2025-12-03 14:38:45 INFO: 用户 韦炳育 访问历史记录页面
2025-12-03 14:38:47 INFO: 用户 韦炳育 查看工单 M202512030001 的详情
2025-12-03 14:39:26 INFO: 用户 韦炳育 访问仪表盘页面
2025-12-05 08:08:48 INFO: 应用启动
2025-12-05 08:08:48 INFO: 错误处理器初始化完成
2025-12-05 12:10:36 INFO: 用户 韦炳育(18176156082) 登录成功
2025-12-05 12:10:36 INFO: 用户 韦炳育 访问仪表盘页面
2025-12-05 12:11:59 INFO: 用户 韦炳育 访问仪表盘页面
2025-12-05 14:57:55 INFO: 应用启动
2025-12-05 14:57:55 INFO: 错误处理器初始化完成
2025-12-09 12:23:07 INFO: 用户 韦矍森(19977899008) 登录成功
2025-12-09 12:23:07 INFO: 用户 韦矍森 访问仪表盘页面
2025-12-09 12:23:15 INFO: 用户请求验证码
2025-12-09 12:23:15 INFO: 验证码获取成功
2025-12-09 12:23:21 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-12-09 12:23:21 INFO: 尝试登录中兴平台
2025-12-09 12:23:21 INFO: 登录成功,开始获取在线信息
2025-12-09 12:23:22 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-12-09 12:23:22 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 720 个
2025-12-09 12:23:23 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-12-09 12:23:24 INFO: 查询到 1107 个需要同步的设备
2025-12-09 12:23:24 INFO: 发现 35 个离线设备需要创建工
2025-12-09 12:23:24 INFO: 成功创建 35 个工单
2025-12-10 10:38:00 ERROR: 未处理异常: 405 Method Not Allowed: The method is not allowed for the requested URL.
Traceback (most recent call last):
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/utils.py", line 290, in decorated_view
return current_app.ensure_sync(func)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/1panel/docker/compose/4an/app/views/statistics.py", line 179, in statistics
return render_template('statistics.html',
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/templating.py", line 150, in render_template
return _render(app, template, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/templating.py", line 131, in _render
rv = template.render(context)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/jinja2/environment.py", line 1304, in render
self.environment.handle_exception()
File "/mnt/nfs/.venv/lib/python3.12/site-packages/jinja2/environment.py", line 939, in handle_exception
raise rewrite_traceback_stack(source=source)
File "/opt/1panel/docker/compose/4an/app/templates/statistics.html", line 1, in top-level template code
{% extends "base.html" %}
File "/opt/1panel/docker/compose/4an/app/templates/base.html", line 108, in top-level template code
{% block content %}{% endblock %}
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/1panel/docker/compose/4an/app/templates/statistics.html", line 74, in block 'content'
<a href="{{ url_for('export_monthly_stats') }}" class="export_button">📥︎ 导出本月明细</a>
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 1121, in url_for
return self.handle_url_build_error(error, endpoint, values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 1110, in url_for
rv = url_adapter.build( # type: ignore[union-attr]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 924, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.exceptions.BuildError: Could not build url for endpoint 'export_monthly_stats'. Did you forget to specify values ['month', 'year']?
2025-05-20 00:11:14 INFO: 应用启动
2025-05-20 00:11:17 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-20 00:11:19 INFO: 用户 韦矍森 访问统计页面
2025-05-20 00:11:24 INFO: 用户 韦矍森 导出 2025年1月 统计报表
2025-05-20 00:11:24 INFO: 用户 韦矍森 访问统计页面
2025-05-20 00:11:31 INFO: 用户 韦矍森 导出 2025年4月 统计报表
2025-05-20 00:13:12 INFO: 用户 韦矍森 访问统计页面
2025-05-20 00:13:13 INFO: 用户 韦矍森 访问历史记录页面
2025-05-20 15:21:10 INFO: 用户 韦矍森 开始同步离线设备
2025-05-20 15:21:11 INFO: 同步完成:创建了 71 个工单,恢复了 0 个设备
2025-05-20 15:25:19 INFO: 用户 唐运莹(18176136697) 登录成功
2025-05-20 17:17:14 INFO: 用户 韦矍森 访问历史记录页面
2025-05-22 08:40:07 INFO: 用户 韦矍森 访问历史记录页面
2025-05-22 08:40:12 INFO: 用户 韦矍森 访问统计页面
2025-05-27 08:48:59 INFO: 用户 韦矍森(19977899008) 登录成功
2025-05-27 08:53:47 INFO: 用户 韦矍森 开始同步离线设备
2025-05-27 08:53:47 INFO: 同步完成:创建了 6 个工单,恢复了 3 个设备
2025-05-27 08:53:59 INFO: 用户 韦矍森 访问统计页面
2025-05-27 08:54:00 INFO: 用户 韦矍森 访问历史记录页面
2025-05-27 14:49:09 INFO: 用户 韦矍森 访问历史记录页面
2025-05-28 09:48:26 INFO: 用户 韦矍森 访问历史记录页面
2025-05-29 08:39:59 INFO: 用户 韦矍森 访问历史记录页面
2025-06-03 01:30:03 INFO: 应用启动
2025-06-15 15:48:55 INFO: 应用启动
2025-06-17 09:43:15 INFO: 用户 韦矍森(19977899008) 登录成功
2025-06-17 09:43:30 INFO: 用户 韦矍森 访问历史记录页面
2025-06-17 09:43:31 INFO: 用户 韦矍森 访问统计页面
2025-06-17 09:43:52 INFO: 用户 韦矍森 开始同步离线设备
2025-06-17 09:43:53 INFO: 同步完成:创建了 11 个工单,恢复了 4 个设备
2025-06-17 09:43:55 INFO: 用户请求验证码
2025-06-17 09:43:55 INFO: 验证码获取成功
2025-06-17 09:44:02 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-06-17 09:44:02 INFO: 尝试登录中兴平台
2025-06-17 09:44:02 INFO: 登录成功,开始获取在线信息
2025-06-17 09:44:03 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-06-17 09:44:03 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 605 个
2025-06-17 09:44:07 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-06-17 09:44:07 INFO: 查询到 1107 个需要同步的设备
2025-06-17 09:44:07 INFO: 发现 25 个离线设备需要创建工单
2025-06-17 09:44:08 INFO: 成功创建 25 个工单
2025-06-17 17:52:13 INFO: 应用启动
2025-06-17 17:54:03 INFO: 应用启动
2025-06-17 17:54:13 INFO: 应用启动
2025-06-17 17:55:25 INFO: 应用启动
2025-06-17 17:55:35 INFO: 应用启动
2025-06-17 17:55:52 INFO: 应用启动
2025-06-17 17:56:38 INFO: 应用启动
2025-06-17 17:58:50 INFO: 应用启动
2025-06-17 18:00:20 ERROR: Exception on /statistics [GET]
Traceback (most recent call last):
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/utils.py", line 285, in decorated_view
return current_app.login_manager.unauthorized()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/login_manager.py", line 187, in unauthorized
flash(self.login_message, category=self.login_message_category)
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/helpers.py", line 335, in flash
session["_flashes"] = flashes
~~~~~~~^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/sessions.py", line 104, in _fail
raise RuntimeError(
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
2025-06-17 18:01:38 INFO: 应用启动
2025-06-17 18:02:09 ERROR: Exception on /statistics [GET]
Traceback (most recent call last):
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/utils.py", line 285, in decorated_view
return current_app.login_manager.unauthorized()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/login_manager.py", line 187, in unauthorized
flash(self.login_message, category=self.login_message_category)
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/helpers.py", line 335, in flash
session["_flashes"] = flashes
~~~~~~~^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/sessions.py", line 104, in _fail
raise RuntimeError(
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
2025-06-17 18:02:12 ERROR: Exception on /statistics [GET]
Traceback (most recent call last):
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/utils.py", line 285, in decorated_view
return current_app.login_manager.unauthorized()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/login_manager.py", line 187, in unauthorized
flash(self.login_message, category=self.login_message_category)
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/helpers.py", line 335, in flash
session["_flashes"] = flashes
~~~~~~~^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/sessions.py", line 104, in _fail
raise RuntimeError(
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
2025-06-17 18:03:23 INFO: 应用启动
2025-06-17 18:05:02 ERROR: Exception on /statistics [GET]
Traceback (most recent call last):
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/utils.py", line 285, in decorated_view
return current_app.login_manager.unauthorized()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask_login/login_manager.py", line 187, in unauthorized
flash(self.login_message, category=self.login_message_category)
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/helpers.py", line 335, in flash
session["_flashes"] = flashes
~~~~~~~^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/sessions.py", line 104, in _fail
raise RuntimeError(
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
2025-06-17 18:05:57 INFO: 应用启动
2025-06-17 18:06:01 INFO: 应用启动
2025-06-17 18:07:16 INFO: 应用启动
2025-06-17 18:08:32 INFO: 应用启动
2025-06-17 18:08:46 INFO: 用户 韦矍森(19977899008) 登录成功
2025-06-18 06:51:33 INFO: 应用启动
2025-06-18 06:52:12 INFO: 应用启动
2025-06-19 21:16:20 INFO: 应用启动
2025-06-21 06:04:07 INFO: 应用启动
2025-06-21 06:04:47 INFO: 应用启动
2025-06-23 12:12:28 INFO: 应用启动
2025-07-16 06:19:45 INFO: 应用启动
2025-07-25 17:02:48 INFO: 用户 韦矍森(19977899008) 登录成功
2025-07-25 17:02:52 INFO: 用户 韦矍森 开始同步离线设备
2025-07-25 17:02:52 INFO: 同步完成:创建了 33 个工单,恢复了 7 个设备
2025-07-25 17:02:55 INFO: 用户请求验证码
2025-07-25 17:02:55 INFO: 验证码获取成功
2025-07-25 17:03:00 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-07-25 17:03:00 INFO: 尝试登录中兴平台
2025-07-25 17:03:00 INFO: 登录成功,开始获取在线信息
2025-07-25 17:03:00 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-07-25 17:03:01 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 674 个
2025-07-25 17:03:04 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-07-25 17:03:04 INFO: 查询到 1107 个需要同步的设备
2025-07-25 17:03:05 INFO: 发现 82 个离线设备需要创建工单
2025-07-25 17:03:05 INFO: 成功创建 82 个工单
2025-07-25 17:03:36 INFO: 用户 韦矍森 开始同步离线设备
2025-07-25 17:03:36 INFO: 同步完成:创建了 107 个工单,恢复了 0 个设备
2025-07-25 17:04:04 INFO: 用户请求验证码
2025-07-25 17:04:05 INFO: 验证码获取成功
2025-07-25 17:04:10 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-07-25 17:04:10 INFO: 尝试登录中兴平台
2025-07-25 17:04:10 WARNING: 登录中兴平台失败:验证码错误
2025-07-25 17:04:13 INFO: 用户请求验证码
2025-07-25 17:04:13 INFO: 验证码获取成功
2025-07-25 17:04:17 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-07-25 17:04:17 INFO: 尝试登录中兴平台
2025-07-25 17:04:17 WARNING: 登录中兴平台失败:验证码错误
2025-07-25 17:04:18 INFO: 用户请求验证码
2025-07-25 17:04:18 INFO: 验证码获取成功
2025-07-25 17:04:22 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-07-25 17:04:22 INFO: 尝试登录中兴平台
2025-07-25 17:04:23 INFO: 登录成功,开始获取在线信息
2025-07-25 17:04:23 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-07-25 17:04:23 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 674 个
2025-07-25 17:04:24 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-07-25 17:04:25 INFO: 查询到 1107 个需要同步的设备
2025-07-25 17:04:25 INFO: 发现 382 个离线设备需要创建工单
2025-07-25 17:04:26 INFO: 成功创建 382 个工单
2025-07-25 17:05:07 INFO: 用户 韦矍森 开始同步离线设备
2025-07-25 17:05:07 INFO: 同步完成:创建了 107 个工单,恢复了 0 个设备
2025-07-25 17:05:15 INFO: 用户 韦矍森 访问历史记录页面
2025-07-25 17:05:19 INFO: 用户 韦矍森 访问统计页面
2025-07-25 17:08:06 INFO: 用户 韦矍森 访问统计页面
2025-07-25 17:08:09 INFO: 用户 韦矍森 访问历史记录页面
2025-07-25 17:13:13 INFO: 用户 韦矍森(19977899008) 登录成功
2025-07-25 17:13:14 INFO: 用户 韦矍森 访问历史记录页面
2025-07-25 18:13:01 INFO: 应用启动
2025-07-25 18:13:01 INFO: 错误处理器初始化完成
2025-07-25 18:13:03 INFO: 用户 韦矍森 访问仪表盘页面
2025-07-25 18:13:12 INFO: 用户 韦矍森 访问历史记录页面
2025-07-25 18:13:13 INFO: 用户 韦矍森 访问统计页面
2025-07-25 18:13:14 INFO: 用户 韦矍森 访问仪表盘页面
2025-07-28 08:27:08 INFO: 用户 韦矍森 访问仪表盘页面
2025-07-28 08:29:41 INFO: 用户 韦矍森 开始同步离线设备
2025-07-28 08:29:41 INFO: 同步完成:创建了 3 个工单,恢复了 0 个设备
2025-07-28 08:29:43 INFO: 用户请求验证码
2025-07-28 08:29:43 INFO: 验证码获取成功
2025-07-28 08:29:52 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-07-28 08:29:52 INFO: 尝试登录中兴平台
2025-07-28 08:29:52 WARNING: 登录中兴平台失败:验证码错误
2025-07-28 08:29:53 INFO: 用户请求验证码
2025-07-28 08:29:53 INFO: 验证码获取成功
2025-07-28 08:29:58 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-07-28 08:29:58 INFO: 尝试登录中兴平台
2025-07-28 08:29:59 INFO: 登录成功,开始获取在线信息
2025-07-28 08:30:00 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-07-28 08:30:00 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 678 个
2025-07-28 08:30:01 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-07-28 08:30:01 INFO: 查询到 1107 个需要同步的设备
2025-07-28 08:30:02 INFO: 发现 9 个离线设备需要创建工单
2025-07-28 08:30:02 INFO: 成功创建 9 个工单
2025-07-28 08:30:04 INFO: 用户 韦矍森 访问仪表盘页面
2025-07-28 08:30:38 INFO: 用户 韦矍森 访问仪表盘页面
2025-07-28 08:51:47 INFO: 用户 韦矍森 访问统计页面
2025-07-28 08:51:49 INFO: 用户 韦矍森 访问历史记录页面
2025-07-28 08:52:02 INFO: 用户 韦矍森 访问仪表盘页面
2025-07-28 08:52:54 INFO: 用户 韦矍森 访问历史记录页面
2025-07-28 08:52:55 INFO: 用户 韦矍森 访问统计页面
2025-07-28 08:52:58 INFO: 用户 韦矍森 访问仪表盘页面
2025-07-28 23:35:22 INFO: 应用启动
2025-07-28 23:35:22 INFO: 错误处理器初始化完成
2025-07-28 23:49:56 INFO: 应用启动
2025-07-28 23:49:56 INFO: 错误处理器初始化完成
2025-07-30 07:37:35 ERROR: 未处理异常: 405 Method Not Allowed: The method is not allowed for the requested URL.
Traceback (most recent call last):
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 891, in dispatch_request
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 891, in dispatch_request
self.raise_routing_exception(req)
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/app.py", line 500, in raise_routing_exception
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 500, in raise_routing_exception
raise request.routing_exception # type: ignore[misc]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/flask/ctx.py", line 362, in match_request
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/ctx.py", line 362, in match_request
result = self.url_adapter.match(return_rule=True) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/mnt/nfs/.venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 624, in match
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 624, in match
raise MethodNotAllowed(valid_methods=list(e.have_match_for)) from None
werkzeug.exceptions.MethodNotAllowed: 405 Method Not Allowed: The method is not allowed for the requested URL.
2025-12-10 10:38:00 ERROR: 未处理异常: 405 Method Not Allowed: The method is not allowed for the requested URL.
Traceback (most recent call last):
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 891, in dispatch_request
self.raise_routing_exception(req)
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/app.py", line 500, in raise_routing_exception
raise request.routing_exception # type: ignore[misc]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/flask/ctx.py", line 362, in match_request
result = self.url_adapter.match(return_rule=True) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/v6ole/pyproject/venv/lib/python3.12/site-packages/werkzeug/routing/map.py", line 624, in match
raise MethodNotAllowed(valid_methods=list(e.have_match_for)) from None
werkzeug.exceptions.MethodNotAllowed: 405 Method Not Allowed: The method is not allowed for the requested URL.
2025-08-05 06:56:05 INFO: 应用启动
2025-08-05 06:56:05 INFO: 错误处理器初始化完成
2025-08-05 11:37:35 WARNING: 登录失败:用户不存在 (手机号: 199778999008)
2025-08-05 11:37:39 INFO: 用户 韦矍森(19977899008) 登录成功
2025-08-05 11:37:39 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-05 11:37:53 INFO: 用户 韦矍森 开始同步离线设备
2025-08-05 11:37:53 INFO: 同步完成:创建了 105 个工单,恢复了 0 个设备
2025-08-05 11:37:56 INFO: 用户请求验证码
2025-08-05 11:37:56 INFO: 验证码获取成功
2025-08-05 11:37:59 INFO: 用户 韦矍森 开始同步摄像头第一步
2025-08-05 11:37:59 INFO: 尝试登录中兴平台
2025-08-05 11:37:59 INFO: 登录成功,开始获取在线信息
2025-08-05 11:38:00 INFO: 获取到 1436 个设备信息,开始更新数据库
2025-08-05 11:38:00 INFO: 数据库更新完成,更新了 1436 条记录,其中离线设备 665 个
2025-08-05 11:38:01 INFO: 用户 韦矍森 开始同步摄像头第二步
2025-08-05 11:38:01 INFO: 查询到 1107 个需要同步的设备
2025-08-05 11:38:02 INFO: 发现 378 个离线设备需要创建工单
2025-08-05 11:38:02 INFO: 成功创建 378 个工单
2025-08-05 11:38:05 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-05 11:38:42 INFO: 用户 韦矍森 访问历史记录页面
2025-08-05 11:38:44 INFO: 用户 韦矍森 访问统计页面
2025-08-06 08:31:05 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-06 12:46:40 INFO: 应用启动
2025-08-06 12:46:40 INFO: 错误处理器初始化完成
2025-08-07 16:39:57 INFO: 用户 韦矍森(19977899008) 登录成功
2025-08-07 16:39:57 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 09:54:17 INFO: 用户 韦矍森(19977899008) 登录成功
2025-08-08 09:54:18 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 09:54:30 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 09:54:43 INFO: 用户 韦矍森 访问历史记录页面
2025-08-08 10:12:48 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:13:00 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:13:04 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:13:13 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:17 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:13:17 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:20 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:28 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:28 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:30 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:30 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:31 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:13:31 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:24 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:24 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:26 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:26 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:28 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:28 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:29 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:29 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:17:39 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:17:41 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:17:57 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:18:06 INFO: 用户 韦矍森 访问历史记录页面
2025-08-08 10:18:20 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:21:25 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:26:58 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:27:02 INFO: 用户 韦矍森 访问历史记录页面
2025-08-08 10:27:08 INFO: 用户 韦矍森 访问仪表盘页面
2025-08-08 10:29:37 INFO: 应用启动
2025-08-08 10:29:37 INFO: 错误处理器初始化完成
2025-08-08 10:30:45 INFO: 应用启动
2025-08-08 10:30:45 INFO: 错误处理器初始化完成
2025-08-08 10:33:52 INFO: 应用启动
2025-08-08 10:33:52 INFO: 错误处理器初始化完成
2025-08-08 10:36:13 ERROR: 数据库操作错误: (pymysql.err.OperationalError) (1066, "Not unique table/alias: 'device'")
[SQL: SELECT work_order.order_id AS work_order_order_id, work_order.device_id AS work_order_device_id, work_order.dispatch_time AS work_order_dispatch_time, work_order.status AS work_order_status, work_order.branch AS work_order_branch
FROM work_order INNER JOIN device ON device.device_id = work_order.device_id INNER JOIN device ON device.device_id = work_order.device_id
WHERE work_order.status = %(status_1)s AND device.device_type = %(device_type_1)s AND device.project_type = %(project_type_1)s
LIMIT %(param_1)s, %(param_2)s]
[parameters: {'status_1': '待处理', 'device_type_1': '摄像头', 'project_type_1': '校园安防"5+N"项目', 'param_1': 0, 'param_2': 50}]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
2025-08-08 10:36:13 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:36:17 ERROR: 数据库操作错误: (pymysql.err.OperationalError) (1066, "Not unique table/alias: 'device'")
[SQL: SELECT work_order.order_id AS work_order_order_id, work_order.device_id AS work_order_device_id, work_order.dispatch_time AS work_order_dispatch_time, work_order.status AS work_order_status, work_order.branch AS work_order_branch
FROM work_order INNER JOIN device ON device.device_id = work_order.device_id INNER JOIN device ON device.device_id = work_order.device_id
WHERE work_order.status = %(status_1)s AND device.device_type = %(device_type_1)s AND device.project_type = %(project_type_1)s
LIMIT %(param_1)s, %(param_2)s]
[parameters: {'status_1': '待处理', 'device_type_1': '摄像头', 'project_type_1': '校园安防"6+N"项目', 'param_1': 0, 'param_2': 50}]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
2025-08-08 10:36:17 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:36:21 ERROR: 数据库操作错误: (pymysql.err.OperationalError) (1066, "Not unique table/alias: 'device'")
[SQL: SELECT work_order.order_id AS work_order_order_id, work_order.device_id AS work_order_device_id, work_order.dispatch_time AS work_order_dispatch_time, work_order.status AS work_order_status, work_order.branch AS work_order_branch
FROM work_order INNER JOIN device ON device.device_id = work_order.device_id INNER JOIN device ON device.device_id = work_order.device_id
WHERE work_order.status = %(status_1)s AND device.device_type = %(device_type_1)s AND device.project_type = %(project_type_1)s
LIMIT %(param_1)s, %(param_2)s]
[parameters: {'status_1': '待处理', 'device_type_1': '摄像头', 'project_type_1': '校园安防"4+N"项目', 'param_1': 0, 'param_2': 50}]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
2025-08-08 10:36:21 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:36:27 ERROR: 数据库操作错误: (pymysql.err.OperationalError) (1066, "Not unique table/alias: 'device'")
[SQL: SELECT work_order.order_id AS work_order_order_id, work_order.device_id AS work_order_device_id, work_order.dispatch_time AS work_order_dispatch_time, work_order.status AS work_order_status, work_order.branch AS work_order_branch
FROM work_order INNER JOIN device ON device.device_id = work_order.device_id INNER JOIN device ON device.device_id = work_order.device_id
WHERE work_order.status = %(status_1)s AND device.device_type = %(device_type_1)s AND device.project_type = %(project_type_1)s
LIMIT %(param_1)s, %(param_2)s]
[parameters: {'status_1': '待处理', 'device_type_1': '摄像头', 'project_type_1': '校园安防"4+N"项目', 'param_1': 0, 'param_2': 50}]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
2025-08-08 10:36:27 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:36:33 ERROR: 数据库操作错误: (pymysql.err.OperationalError) (1066, "Not unique table/alias: 'device'")
[SQL: SELECT work_order.order_id AS work_order_order_id, work_order.device_id AS work_order_device_id, work_order.dispatch_time AS work_order_dispatch_time, work_order.status AS work_order_status, work_order.branch AS work_order_branch
FROM work_order INNER JOIN device ON device.device_id = work_order.device_id INNER JOIN device ON device.device_id = work_order.device_id
WHERE work_order.status = %(status_1)s AND device.device_type = %(device_type_1)s AND device.project_type = %(project_type_1)s
LIMIT %(param_1)s, %(param_2)s]
[parameters: {'status_1': '待处理', 'device_type_1': '一键报警', 'project_type_1': '校园安防"4+N"项目', 'param_1': 0, 'param_2': 50}]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
2025-08-08 10:36:33 INFO: 用户 韦矍森 访问统计页面
2025-08-08 10:36:35 INFO: 用户 韦矍森 访问统计页面
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

+314 -87
View File
@@ -2,31 +2,274 @@
.receive_filter {
margin: 20px 0;
padding: 20px;
background: #fff;
border-radius: 10px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07);
border: 1px solid #e2e8f0;
}
.filter_header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 2px solid #e2e8f0;
}
.filter_title {
margin: 0;
font-size: 1.2em;
color: #1e293b;
font-weight: 600;
display: flex;
align-items: center;
}
.filter_title::before {
content: "🔍";
margin-right: 8px;
font-size: 1.1em;
}
.filter_actions {
display: flex;
gap: 10px;
}
.filter_form {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
align-items: end;
}
.filter_group {
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
flex-direction: column;
gap: 8px;
}
.filter_label {
font-size: 0.9em;
font-weight: 500;
color: #374151;
margin-bottom: 4px;
}
.filter_select {
padding: 8px 12px;
border: 1px solid #e2e8f0;
border-radius: 6px;
padding: 12px 16px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-size: 14px;
background: white;
min-width: 150px;
color: #374151;
outline: none;
transition: border-color 0.3s;
transition: all 0.3s ease;
cursor: pointer;
}
.filter_select:hover {
border-color: #cbd5e1;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.filter_select:focus {
border-color: #4f46e5;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}
.receive_btn_clear {
background: linear-gradient(135deg, #f59e0b, #d97706);
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
font-size: 0.9em;
text-decoration: none;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 6px;
}
.receive_btn_clear::before {
content: "✕";
font-size: 0.8em;
}
.receive_btn_clear:hover {
background: linear-gradient(135deg, #d97706, #b45309);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
text-decoration: none;
color: white;
}
.receive_btn_primary {
background: linear-gradient(135deg, #4f46e5, #3b82f6);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
justify-content: center;
}
.receive_btn_primary::before {
content: "✓";
font-size: 0.9em;
}
.receive_btn_primary:hover {
background: linear-gradient(135deg, #3b82f6, #2563eb);
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(79, 70, 229, 0.3);
}
.receive_btn_warning {
background: linear-gradient(135deg, #ef4444, #dc2626);
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
font-size: 0.9em;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 6px;
}
.receive_btn_warning::before {
content: "⚠";
font-size: 0.9em;
}
.receive_btn_warning:hover {
background: linear-gradient(135deg, #dc2626, #b91c1c);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(239, 68, 68, 0.3);
}
/* 统计卡片网格布局 */
.stats_section {
margin: 20px 0;
}
.stats_section_title {
font-size: 1.1em;
color: #374151;
margin-bottom: 15px;
font-weight: 600;
}
.stats_grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
margin-bottom: 20px;
}
.stats_card {
background: linear-gradient(135deg, #f8fafc, #e2e8f0);
padding: 12px 16px;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
transition: all 0.3s ease;
border: 2px solid transparent;
text-decoration: none;
color: inherit;
cursor: pointer;
}
.stats_card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
text-decoration: none;
color: inherit;
}
.stats_card.active {
border-color: currentColor;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.stats_card_label {
font-size: 0.9em;
color: #6b7280;
margin-bottom: 4px;
}
.stats_card_value {
font-size: 1.4em;
font-weight: bold;
color: #1f2937;
}
/* 设备类型颜色 */
.stats_card.device-type-摄像头 {
background: linear-gradient(135deg, #dbeafe, #bfdbfe);
border-color: #3b82f6;
}
.stats_card.device-type-摄像头 .stats_card_value {
color: #1d4ed8;
}
.stats_card.device-type-一键报警 {
background: linear-gradient(135deg, #fed7aa, #fdba74);
border-color: #f59e0b;
}
.stats_card.device-type-一键报警 .stats_card_value {
color: #d97706;
}
.stats_card.device-type-紫色 {
background: linear-gradient(135deg, #e9d5ff, #c4b5fd);
border-color: #8b5cf6;
}
.stats_card.device-type-紫色 .stats_card_value {
color: #7c3aed;
}
.stats_card.device-type-绿色 {
background: linear-gradient(135deg, #dcfce7, #bbf7d0);
border-color: #22c55e;
}
.stats_card.device-type-绿色 .stats_card_value {
color: #16a34a;
}
.stats_card.device-type-灰色 {
background: linear-gradient(135deg, #f3f4f6, #e5e7eb);
border-color: #6b7280;
}
.stats_card.device-type-灰色 .stats_card_value {
color: #4b5563;
}
/* 项目类型颜色 */
.stats_card[class*="project-type-"] {
background: linear-gradient(135deg, #fef3c7, #fde68a);
border-color: #f59e0b;
}
.stats_card[class*="project-type-"] .stats_card_value {
color: #d97706;
}
/* 统计卡片样式 */
@@ -59,77 +302,6 @@
margin-left: auto;
}
.stats_branches {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.stats_branches_row {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin: 15px 0;
}
.branch_stat {
background: #f8fafc;
padding: 8px 15px;
border-radius: 6px;
border: 2px solid #e2e8f0;
transition: all 0.2s;
text-decoration: none;
color: inherit;
display: flex;
align-items: center;
gap: 8px;
}
.branch_stat:hover {
background: #f1f5f9;
transform: translateY(-1px);
}
.branch_stat.active {
background: #7eb6ff3b;
color: white;
border-color: #2563eb;
}
.branch_name {
font-size: 0.9em;
}
.branch_count {
font-weight: bold;
color: currentColor;
}
.branch_stat:hover {
transform: translateY(-2px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.branch_name {
color: #64748b;
font-size: 0.9em;
}
.branch_count {
display: block;
color: #1e293b;
font-size: 1.2em;
font-weight: bold;
margin-top: 5px;
}
.receive_actions {
display: flex;
gap: 12px;
margin-top: 15px;
}
.receive_btn {
padding: 8px 16px;
border: none;
@@ -363,11 +535,6 @@
/* 移动端适配 */
@media (max-width: 768px) {
.receive_actions {
flex-direction: column;
width: 100%;
}
.receive_btn {
width: 100%;
padding: 12px 16px;
@@ -377,6 +544,7 @@
margin: 10vh auto;
padding: 20px;
}
.receive_card {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 20px;
@@ -397,4 +565,63 @@
.receive_card_item {
padding: 6px 0;
}
/* 筛选区域在移动端的适配 */
.filter_header {
flex-direction: column;
gap: 12px;
align-items: flex-start;
}
.filter_title {
font-size: 1.1em;
}
.filter_form {
grid-template-columns: 1fr;
gap: 16px;
}
.filter_group {
gap: 6px;
}
.filter_select {
padding: 10px 14px;
font-size: 16px; /* 防止移动端自动缩放 */
}
.receive_btn_primary {
padding: 14px 20px;
font-size: 16px;
width: 100%;
margin-top: 8px;
}
.receive_btn_clear {
padding: 10px 16px;
font-size: 0.9em;
align-self: stretch;
}
.stats_grid {
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 8px;
}
.stats_card {
padding: 10px 12px;
}
.stats_card_label {
font-size: 0.8em;
}
.stats_card_value {
font-size: 1.2em;
}
.stats_section_title {
font-size: 1em;
margin-bottom: 12px;
}
}

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

+1 -1
View File
@@ -54,7 +54,7 @@
<div class="dev-info">
<p><strong>联系:</strong>韦矍森</p>
<p><strong>电话:</strong>19977899008</p>
<p><strong>部门:</strong>大化政企业务交付运营中心</p>
<p><strong>部门:</strong>大化云中台</p>
</div>
</div>
+125 -125
View File
@@ -1,125 +1,125 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大化重点项目工单管理平台</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
<nav class="navbar navbar-expand-lg nav_container">
<div class="container-fluid">
<a class="nav_brand">
{% if request.endpoint == 'dispatch' %}
故障派单
{% elif request.endpoint == 'receive' %}
在途工单
{% elif request.endpoint == 'statistics' %}
工单统计
{% elif request.endpoint == 'history' %}
历史工单
{% elif request.endpoint == 'manual' %}
申报故障
{% elif request.endpoint == 'dashboard' %}
设备仪表盘
{% else %}
重点项目工单管理平台
{% endif %}
</a>
<button class="navbar-toggler nav_toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon nav_toggler_icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0 nav_menu">
{% if current_user.is_authenticated %}
{% if current_user.role == '统计员' %}
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'dashboard' }}" href="{{ url_for('dashboard') }}">仪表盘</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'dispatch' }}" href="{{ url_for('dispatch') }}">派单</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'receive' }}" href="{{ url_for('receive') }}">在途</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'manual' }}" href="{{ url_for('manual') }}">申报</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'statistics' }}" href="{{ url_for('statistics') }}">统计</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'history' }}" href="{{ url_for('history') }}">历史</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'about' }}" href="{{ url_for('about') }}">关于</a>
</li>
{% elif current_user.role == '装维员' %}
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'dashboard' }}" href="{{ url_for('dashboard') }}">仪表盘</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'receive' }}" href="{{ url_for('receive') }}">在途</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'manual' }}" href="{{ url_for('manual') }}">申报</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'statistics' }}" href="{{ url_for('statistics') }}">统计</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'history' }}" href="{{ url_for('history') }}">历史</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'about' }}" href="{{ url_for('about') }}">关于</a>
</li>
{% endif %}
{% endif %}
</ul>
<ul class="navbar-nav nav_menu">
{% if current_user.is_authenticated %}
<li class="nav-item">
<a class="nav_link" href="{{ url_for('logout') }}">退出</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% if not request.endpoint == 'login' %}
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="modal" id="flashModal" tabindex="-1" style="display: block; background: rgba(0,0,0,0.5);">
<div class="modal-dialog modal-dialog-centered" style="z-index: 1060;">
<div class="modal-content">
<div class="modal-body">
{% for message in messages %}
<p class="mb-0">{{ message }}</p>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="closeFlashModal()">确定</button>
</div>
</div>
</div>
</div>
{% endif %}
{% endwith %}
{% endif %}
{% block content %}{% endblock %}
</div>
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
<script>
function closeFlashModal() {
document.getElementById('flashModal').style.display = 'none';
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大化重点项目工单管理平台</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
<nav class="navbar navbar-expand-lg nav_container">
<div class="container-fluid">
<a class="nav_brand">
{% if request.endpoint == 'dispatch' %}
故障派单
{% elif request.endpoint == 'receive' %}
在途工单
{% elif request.endpoint == 'statistics' %}
工单统计
{% elif request.endpoint == 'history' %}
历史工单
{% elif request.endpoint == 'manual' %}
工单申报
{% elif request.endpoint == 'dashboard' %}
设备仪表盘
{% else %}
重点项目工单管理平台
{% endif %}
</a>
<button class="navbar-toggler nav_toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon nav_toggler_icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0 nav_menu">
{% if current_user.is_authenticated %}
{% if current_user.role == '统计员' %}
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'dashboard' }}" href="{{ url_for('dashboard') }}">仪表盘</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'dispatch' }}" href="{{ url_for('dispatch') }}">派单</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'receive' }}" href="{{ url_for('receive') }}">在途</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'manual' }}" href="{{ url_for('manual') }}">申报</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'statistics' }}" href="{{ url_for('statistics') }}">统计</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'history' }}" href="{{ url_for('history') }}">历史</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'about' }}" href="{{ url_for('about') }}">关于</a>
</li>
{% elif current_user.role == '装维员' %}
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'dashboard' }}" href="{{ url_for('dashboard') }}">仪表盘</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'receive' }}" href="{{ url_for('receive') }}">在途</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'manual' }}" href="{{ url_for('manual') }}">申报</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'statistics' }}" href="{{ url_for('statistics') }}">统计</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'history' }}" href="{{ url_for('history') }}">历史</a>
</li>
<li class="nav-item">
<a class="nav_link {{ 'active' if request.endpoint == 'about' }}" href="{{ url_for('about') }}">关于</a>
</li>
{% endif %}
{% endif %}
</ul>
<ul class="navbar-nav nav_menu">
{% if current_user.is_authenticated %}
<li class="nav-item">
<a class="nav_link" href="{{ url_for('logout') }}">退出</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% if not request.endpoint == 'login' %}
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="modal" id="flashModal" tabindex="-1" style="display: block; background: rgba(0,0,0,0.5);">
<div class="modal-dialog modal-dialog-centered" style="z-index: 1060;">
<div class="modal-content">
<div class="modal-body">
{% for message in messages %}
<p class="mb-0">{{ message }}</p>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="closeFlashModal()">确定</button>
</div>
</div>
</div>
</div>
{% endif %}
{% endwith %}
{% endif %}
{% block content %}{% endblock %}
</div>
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
<script>
function closeFlashModal() {
document.getElementById('flashModal').style.display = 'none';
}
</script>
</body>
</html>
+5 -4
View File
@@ -6,6 +6,7 @@
<p>注意事项</p>
<ul>
<li>本页面用于填写用户来电申报或者巡检途中发现的故障、移机,申报前请确保在途工单中没有重复故障</li>
<li>新装设备、移机等请在申报类型选择“新装”或“移机”</li>
<li>现场照片最多可上传5张,支持jpg、jpeg、png</li>
<li>距离支局公里数请填写支局办公室到故障地点实际距离</li>
<li><span class="required">*</span> 的字段为必填项</li>
@@ -44,9 +45,9 @@
</div>
<div class="form-group">
<label for="fault_type">故障类型<span class="required">*</span></label>
<label for="fault_type">申报类型<span class="required">*</span></label>
<select id="fault_type" name="fault_type" required>
<option value="">请选择故障类型</option>
<option value="">请选择申报类型</option>
<option value="光猫故障">光猫故障</option>
<option value="设备故障">设备故障</option>
<option value="电源故障">电源故障</option>
@@ -55,8 +56,8 @@
<option value="皮线故障">皮线故障</option>
<option value="数据问题">数据问题</option>
<option value="用户欠费">用户欠费</option>
<option value="移机">移机</option>
<option value="新增"></option>
<option value="移机">移机申报</option>
<option value="新增">装申报</option>
<option value="其他">其他</option>
</select>
</div>
+74 -30
View File
@@ -8,46 +8,90 @@
<span class="stats_label">在途工单总数</span>
<span class="stats_value">{{ total_orders }}</span>
</div>
{% if current_user.branch == '交付中心' %}
<div class="stats_branches_row">
{% for branch, count in branch_stats.items() %}
<a href="{{ url_for('receive', branch=branch) }}" class="branch_stat {% if branch == selected_branch %}active{% endif %}">
<span class="branch_name">{{ branch }}</span>
<span class="branch_count">{{ count }}</span>
</a>
{% endfor %}
<!-- 设备类型统计 -->
{% if device_type_stats %}
<div class="stats_section">
<h4 class="stats_section_title">设备类型分布</h4>
<div class="stats_grid">
{% for device_type, count in device_type_stats.items() %}
<a href="{{ url_for('receive', device_type=device_type, branch=selected_branch, per_page=request.args.get('per_page', '50')) }}" class="stats_card device-type-{{ device_type | replace(' ', '-') }} {% if device_type == request.args.get('device_type') %}active{% endif %}">
<span class="stats_card_label">{{ device_type }}</span>
<span class="stats_card_value">{{ count }}</span>
</a>
{% endfor %}
</div>
</div>
<div class="receive_actions">
<button onclick="recallAllOrders()" class="receive_btn receive_btn_warning">一键追回所有工单</button>
{% if selected_branch %}
<a href="{{ url_for('receive') }}" class="receive_btn receive_btn_secondary">清除筛选</a>
{% endif %}
{% endif %}
<!-- 项目类型统计 -->
{% if project_type_stats %}
<div class="stats_section">
<h4 class="stats_section_title">项目类型分布</h4>
<div class="stats_grid">
{% for project_type, count in project_type_stats.items() %}
<a href="{{ url_for('receive', project_type=project_type, branch=selected_branch, per_page=request.args.get('per_page', '50')) }}" class="stats_card project-type-{{ project_type | replace(' ', '-') }} {% if project_type == request.args.get('project_type') %}active{% endif %}">
<span class="stats_card_label">{{ project_type }}</span>
<span class="stats_card_value">{{ count }}</span>
</a>
{% endfor %}
</div>
</div>
{% endif %}
</div>
<!-- 筛选区域 -->
<div class="receive_filter">
<div class="filter_header">
<h4 class="filter_title">工单筛选</h4>
<div class="filter_actions">
{% if current_user.branch == '交付中心' %}
<button onclick="recallAllOrders()" class="receive_btn receive_btn_warning">一键追回所有工单</button>
{% endif %}
{% if request.args.get('device_type') or request.args.get('project_type') or selected_branch %}
<a href="{{ url_for('receive', per_page=request.args.get('per_page', '50')) }}" class="receive_btn receive_btn_clear">清除所有筛选</a>
{% endif %}
</div>
</div>
<form method="GET" action="{{ url_for('receive') }}" class="filter_form">
<select name="device_type" class="filter_select">
<option value="">所有设备类型</option>
{% for device_type in device_types %}
<option value="{{ device_type }}" {% if device_type == request.args.get('device_type') %}selected{% endif %}>{{ device_type }}</option>
{% endfor %}
</select>
<select name="project_type" class="filter_select">
<option value="">所有项目类型</option>
{% for project_type in project_types %}
<option value="{{ project_type }}" {% if project_type == request.args.get('project_type') %}selected{% endif %}>{{ project_type }}</option>
{% endfor %}
</select>
<input type="hidden" name="branch" value="{{ selected_branch }}">
{% if current_user.branch == '交付中心' %}
<div class="filter_group">
<label class="filter_label">所属支局</label>
<select name="branch" class="filter_select">
<option value="">所有支局</option>
{% for branch in branches %}
<option value="{{ branch }}" {% if branch == selected_branch %}selected{% endif %}>{{ branch }}</option>
{% endfor %}
</select>
</div>
{% endif %}
<div class="filter_group">
<label class="filter_label">设备类型</label>
<select name="device_type" class="filter_select">
<option value="">所有设备类型</option>
{% for device_type in device_types %}
<option value="{{ device_type }}" {% if device_type == request.args.get('device_type') %}selected{% endif %}>{{ device_type }}</option>
{% endfor %}
</select>
</div>
<div class="filter_group">
<label class="filter_label">项目类型</label>
<select name="project_type" class="filter_select">
<option value="">所有项目类型</option>
{% for project_type in project_types %}
<option value="{{ project_type }}" {% if project_type == request.args.get('project_type') %}selected{% endif %}>{{ project_type }}</option>
{% endfor %}
</select>
</div>
<input type="hidden" name="page" value="1">
<input type="hidden" name="per_page" value="{{ request.args.get('per_page', '50') }}">
<button type="submit" class="receive_btn receive_btn_primary">筛选</button>
{% if request.args.get('device_type') or request.args.get('project_type') %}
<a href="{{ url_for('receive', branch=selected_branch, per_page=request.args.get('per_page', '50')) }}" class="receive_btn receive_btn_secondary">清除筛选</a>
{% endif %}
<div class="filter_group">
<button type="submit" class="receive_btn receive_btn_primary">应用筛选</button>
</div>
</form>
</div>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5 -5
View File
@@ -39,24 +39,24 @@ buffer-size = 32768
# 指定日志文件的路径
# uWSGI 的运行日志将写入此文件
logto = /opt/1panel/docker/compose/4an/uwsgi.log
logto = /home/v6ole/pyproject/4an/uwsgi.log
# 指定虚拟环境的路径
# uWSGI 将使用此虚拟环境中的 Python 解释器和依赖库
virtualenv = /mnt/nfs/.venv
virtualenv = /home/v6ole/pyproject/venv
# 设置应用的根目录
# uWSGI 将切换到此目录运行,确保应用的相对路径正确
chdir = /opt/1panel/docker/compose/4an/app
chdir = /home/v6ole/pyproject/4an/app
# 设置 PID 文件的路径
# PID 文件用于管理 uWSGI 进程(如停止、重启)
pidfile = /opt/1panel/docker/compose/4an/uwsgi.pid
pidfile = /home/v6ole/pyproject/4an/uwsgi.pid
# 设置 Unix Socket 文件的路径
# 用于与 Nginx 或其他代理服务器通信
# 如果使用 HTTP 模式,可以注释掉此行
socket = /opt/1panel/docker/compose/4an/uwsgi.sock
socket = /home/v6ole/pyproject/4an/uwsgi.sock
# 设置 Socket 文件的权限
# 660 表示只有所有者和所属组有读写权限
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+65 -19
View File
@@ -132,14 +132,26 @@ def init_work_order_routes(app):
device_type = request.args.get('device_type', '')
project_type = request.args.get('project_type', '')
# 基础查询
query = WorkOrder.query.filter_by(status='待处理')
# 基础查询,直接join Device表
query = WorkOrder.query.join(Device).filter(WorkOrder.status == '待处理')
# 根据用户权限筛选工单
if current_user.branch != '交付中心':
query = query.join(Device).filter(Device.branch == current_user.branch)
query = query.filter(Device.branch == current_user.branch)
# 获取总数统计
# 应用分支筛选(仅交付中心可用)
if branch and current_user.branch == '交付中心':
query = query.filter(Device.branch == branch)
# 应用设备类型筛选
if device_type:
query = query.filter(Device.device_type == device_type)
# 应用项目类型筛选
if project_type:
query = query.filter(Device.project_type == project_type)
# 获取总数统计(使用相同的筛选条件)
total_orders = query.count()
# 获取各支局统计
@@ -154,21 +166,17 @@ def init_work_order_routes(app):
branch_stats = dict(branch_counts)
# 应用分支筛选(仅交付中心可用)
if branch and current_user.branch == '交付中心':
query = query.join(Device).filter(Device.branch == branch)
# 应用设备类型筛选
if device_type:
query = query.join(Device).filter(Device.device_type == device_type)
# 应用项目类型筛选
if project_type:
query = query.join(Device).filter(Device.project_type == project_type)
# 获取筛选选项
device_types_query = db.session.query(Device.device_type).distinct().join(WorkOrder).filter(WorkOrder.status == '待处理')
project_types_query = db.session.query(Device.project_type).distinct().join(WorkOrder).filter(WorkOrder.status == '待处理')
# 获取筛选选项 - 修正查询方向
device_types_query = db.session.query(Device.device_type).distinct().filter(
Device.device_id.in_(
db.session.query(WorkOrder.device_id).filter(WorkOrder.status == '待处理')
)
)
project_types_query = db.session.query(Device.project_type).distinct().filter(
Device.device_id.in_(
db.session.query(WorkOrder.device_id).filter(WorkOrder.status == '待处理')
)
)
# 根据用户权限进一步筛选选项
if current_user.branch != '交付中心':
@@ -181,6 +189,42 @@ def init_work_order_routes(app):
device_types = [dt[0] for dt in device_types_query.all() if dt[0]]
project_types = [pt[0] for pt in project_types_query.all() if pt[0]]
# 获取设备类型统计
device_type_stats = {}
if device_types:
device_type_counts = db.session.query(
Device.device_type,
db.func.count(WorkOrder.order_id)
).join(WorkOrder, WorkOrder.device_id == Device.device_id
).filter(WorkOrder.status == '待处理')
# 应用同样的权限筛选
if current_user.branch != '交付中心':
device_type_counts = device_type_counts.filter(Device.branch == current_user.branch)
elif branch:
device_type_counts = device_type_counts.filter(Device.branch == branch)
device_type_counts = device_type_counts.group_by(Device.device_type).all()
device_type_stats = dict(device_type_counts)
# 获取项目类型统计
project_type_stats = {}
if project_types:
project_type_counts = db.session.query(
Device.project_type,
db.func.count(WorkOrder.order_id)
).join(WorkOrder, WorkOrder.device_id == Device.device_id
).filter(WorkOrder.status == '待处理')
# 应用同样的权限筛选
if current_user.branch != '交付中心':
project_type_counts = project_type_counts.filter(Device.branch == current_user.branch)
elif branch:
project_type_counts = project_type_counts.filter(Device.branch == branch)
project_type_counts = project_type_counts.group_by(Device.project_type).all()
project_type_stats = dict(project_type_counts)
# 获取分页数据
work_orders = query.paginate(page=page, per_page=per_page)
@@ -195,6 +239,8 @@ def init_work_order_routes(app):
work_orders=work_orders,
total_orders=total_orders,
branch_stats=branch_stats,
device_type_stats=device_type_stats,
project_type_stats=project_type_stats,
show_filter=current_user.branch == '交付中心', # 只有交付中心可以看到筛选
branches=get_branches() if current_user.branch == '交付中心' else [], # 只有交付中心可以看到支局列表
selected_branch=branch,