Compare commits

...

349 Commits
fan ... master

Author SHA1 Message Date
4a0d65683d revert a74efe77f0
revert 修改jl-graphic依赖引用的仓库地址
2024-09-04 18:02:52 +08:00
soul-walker
a74efe77f0 修改jl-graphic依赖引用的仓库地址 2024-09-04 17:59:29 +08:00
fan
e1c4cd8a1a 删除lamp 2024-01-25 14:45:54 +08:00
fan
3aa3038504 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2024-01-25 10:15:39 +08:00
fan
ea84c6ecdd 信号机实现逻辑调整 2024-01-25 10:15:32 +08:00
joylink_zhaoerwei
12f0bdf6d2 区段吸附点修改 2024-01-10 16:30:37 +08:00
joylink_zhaoerwei
e699ac3ef3 测试微调 2023-12-28 15:10:41 +08:00
joylink_zhaoerwei
c8580b9d42 微调 2023-12-27 17:37:35 +08:00
Yuan
17fdddb17e 道岔及区段关系逻辑修正 2023-12-27 16:57:37 +08:00
joylink_zhaoerwei
91d290abf1 测试调整 2023-12-27 13:21:10 +08:00
joylink_zhaoerwei
a0b9e27e71 测试调整 2023-12-27 09:47:24 +08:00
joylink_zhaoerwei
e97a677c3b 测试修改 2023-12-27 09:27:34 +08:00
joylink_zhaoerwei
b604fbd59c 故障测试修改 2023-12-27 08:54:26 +08:00
joylink_zhaoerwei
0cec0db90a 一级联锁集中站多选 2023-12-22 16:10:04 +08:00
joylink_zhaoerwei
3b6da014ed 线网页面调整 2023-12-22 15:55:21 +08:00
joylink_zhaoerwei
418ee1a269 线路页面调整 2023-12-22 15:52:47 +08:00
dong
b374bcddb1 鼠标在弹窗标题字体上也可拖拽窗口 2023-12-22 15:25:26 +08:00
fan
0a96d88efc 画布调整 2023-12-22 15:09:59 +08:00
fan
8cd499c355 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-12-22 14:51:01 +08:00
fan
77afce4d1d 画布高度调整 2023-12-22 14:50:52 +08:00
joylink_zhaoerwei
10271fc959 微调 2023-12-22 14:44:37 +08:00
dong
db277254f9 限制拖拽弹窗Y轴范围 2023-12-22 14:44:56 +08:00
dong
5af0362c0e 修复socket断连提示 2023-12-22 10:36:43 +08:00
joylink_zhaoerwei
cc9e593916 站台-是否 2023-12-21 17:23:53 +08:00
fan
f2a59743cb Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-12-21 17:16:32 +08:00
fan
c95ddf4372 信号机关联设备调整 2023-12-21 17:16:26 +08:00
joylink_zhaoerwei
4ac1338b85 公里标配置 2023-12-21 16:39:54 +08:00
joylink_zhaoerwei
d41843a10a 区段边界处信号机关联集中站不特殊处理 2023-12-21 16:08:10 +08:00
joylink_zhaoerwei
693e1de289 一键关联集中站 2023-12-21 15:50:06 +08:00
joylink_zhaoerwei
c06a9d7e85 测试去掉集中站 2023-12-21 14:23:21 +08:00
joylink_zhaoerwei
d94ae6b975 车站增加是否车辆段 2023-12-21 14:08:11 +08:00
joylink_zhaoerwei
938559a0a9 集中站相关 2023-12-21 13:42:22 +08:00
fan
2349f81149 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-12-21 10:29:39 +08:00
fan
ff655373ed 信号机添加关联设备 2023-12-21 10:29:33 +08:00
joylink_zhaoerwei
5d83a368e0 微调 2023-12-20 17:41:56 +08:00
joylink_zhaoerwei
8d926b37cd socket调整 2023-12-20 17:36:32 +08:00
dong
64569f9b3c 修改socket刷新报错 2023-12-20 17:24:32 +08:00
joylink_zhaoerwei
9edc6971ca 与卡斯柯连接状态信息 2023-12-20 16:23:17 +08:00
dong
232536ae34 代码调整 2023-12-20 15:51:08 +08:00
dong
c72b11fd81 通信链接断开位置调整;线路初始化删除列车 2023-12-20 13:57:39 +08:00
dong
c0219744ff 取消pixi 2023-12-19 14:09:50 +08:00
joylink_zhaoerwei
322c81fb45 StompMessagingClient修改 2023-12-19 13:13:50 +08:00
fan
4c807dc273 revert 2023-12-19 10:38:11 +08:00
fan
ff93c4d825 Revert "Revert "id调整&框架调整""
This reverts commit c8f62ff5
2023-12-19 10:35:12 +08:00
fan
30a36121ad Merge branch 'handle_id'
# Conflicts:
#	src/drawApp/lineNetApp.ts
#	src/drawApp/rangeConfigApp.ts
#	yarn.lock
2023-12-19 10:13:02 +08:00
fan
ca296a2a97 问题代码调整 2023-12-18 09:56:05 +08:00
fan
c8f62ff5a0 Revert "id调整&框架调整"
This reverts commit 13d9e8615a.
2023-12-15 16:39:03 +08:00
fan
13d9e8615a id调整&框架调整 2023-12-15 15:38:00 +08:00
fan
ef47f4df5e Revert "id调整&框架引入调整"
This reverts commit 5c8ef2ad03.
2023-12-15 15:03:57 +08:00
fan
5c8ef2ad03 id调整&框架引入调整 2023-12-15 14:47:16 +08:00
fan
91f1ad4f46 注释批处理数据代码 2023-12-15 10:05:04 +08:00
fan
4394a9814f proto同步 2023-12-15 10:03:58 +08:00
fan
d032bdf036 同步proto 2023-12-15 09:56:13 +08:00
fan
266f1ce829 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-12-15 09:55:47 +08:00
fan
c343e80428 id调整 2023-12-15 09:54:51 +08:00
joylink_zhaoerwei
bd84045111 站台关联物理区段 2023-12-14 17:44:32 +08:00
dong
4f1e58aac6 登录失败取消loading效果 2023-11-30 16:24:30 +08:00
dong
1f6e55a0dc 登录页添加loading效果 2023-11-27 13:26:44 +08:00
joylink_zhaoerwei
4bf4aa13d7 同步框架 2023-11-09 10:18:39 +08:00
joylink_zhaoerwei
623f538399 报警列表布局下移 2023-11-06 15:06:07 +08:00
joylink_zhaoerwei
8b7aa520d1 左右键变换bug修复 2023-11-06 09:05:01 +08:00
dong
c971f5fdb6 报警统计调整 2023-11-03 17:42:44 +08:00
joylink_zhaoerwei
47375663a2 微调 2023-11-03 17:25:25 +08:00
joylink_zhaoerwei
674ffc598f 加全部 2023-11-03 16:57:05 +08:00
joylink_zhaoerwei
6141e48bc7 告警列表查询添加"处理状态"的查询 2023-11-03 16:02:21 +08:00
joylink_zhaoerwei
37915f60f4 2.告警列表需要添加刷新--防抖,1秒最多一刷
5.告警提示框 下面的摁钮 添加“人工接警”的摁钮
2023-11-03 15:07:57 +08:00
dong
f345c17a1d 代码调整 2023-11-03 13:45:40 +08:00
dong
ea54841d8a 线路订阅调整 2023-11-03 13:21:17 +08:00
dong
ea363b44cd 报警统计添加处理状态 2023-11-03 11:15:18 +08:00
fan
6f4d1f8c05 订阅调整 2023-11-03 10:54:04 +08:00
joylink_zhaoerwei
b90522ec42 全部改为一键确认 2023-11-02 12:02:43 +08:00
dong
6cbbbc2df8 列表表号调整 2023-11-02 12:01:02 +08:00
joylink_zhaoerwei
30e5445997 一键误报改为一键确认 2023-11-02 11:56:50 +08:00
dong
5dc1d2ce35 框架代码同步 2023-11-02 09:26:47 +08:00
joylink_zhaoerwei
7aec94a34c 弹5个bug修复 2023-11-01 15:56:35 +08:00
dong
463620a75b 列车订阅状态调整 2023-11-01 15:55:25 +08:00
joylink_zhaoerwei
036fddf8fe 待弹框的数据为非响应式的 2023-11-01 15:07:40 +08:00
joylink_zhaoerwei
49bfd7e346 左键托画布 2023-11-01 14:26:46 +08:00
joylink_zhaoerwei
9edfdfa935 一键误报没选择给提示 2023-11-01 13:39:08 +08:00
joylink_zhaoerwei
9a5bc59184 微调 2023-11-01 13:08:08 +08:00
joylink_zhaoerwei
7ec224e954 微调 2023-11-01 11:12:45 +08:00
joylink_zhaoerwei
3a387e8cb3 误报后不显示决策信息;点误报后取消勾选 2023-11-01 10:59:36 +08:00
dong
3bdb6304a1 列车车组号显示调整 2023-11-01 10:27:31 +08:00
joylink_zhaoerwei
50af8c6c52 微调 2023-11-01 09:07:11 +08:00
joylink_zhaoerwei
3a2324b274 弹框只能弹5个,未弹的入队列,关掉一个弹一个 2023-10-31 18:05:07 +08:00
joylink_zhaoerwei
1ae91da1cd 循环播放音乐逻辑调整,一键误报前关闭所有弹框 2023-10-31 16:24:35 +08:00
joylink_zhaoerwei
1f6955e4a2 勾选只能勾未处理 2023-10-31 13:33:48 +08:00
joylink_zhaoerwei
9d56dfd106 微调 2023-10-31 11:23:44 +08:00
joylink_zhaoerwei
bb10c84c91 微调 2023-10-31 11:14:00 +08:00
joylink_zhaoerwei
2d68f9631b 播放音乐替换 2023-10-31 11:09:38 +08:00
joylink_zhaoerwei
763a4f059c 需求--一键误报 2023-10-31 11:03:20 +08:00
joylink_zhaoerwei
a534e941ee 报警调整 2023-10-27 14:43:20 +08:00
fan
37fa4b17e4 运行线调整 2023-10-25 13:14:17 +08:00
fan
f769d1148f Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-10-25 09:24:24 +08:00
fan
73791597f1 运行线灰线段 2023-10-25 09:24:19 +08:00
joylink_zhaoerwei
22def6e5ff 车站对应的小圆圈变灰 2023-10-25 09:07:31 +08:00
joylink_zhaoerwei
cb39384b42 线网车站加颜色选择 2023-10-24 18:06:52 +08:00
tiger_zhou
ef8cabe774 添加正式打包环境 2023-10-20 16:53:34 +08:00
dong
d2f0668323 修改quasar启动报错 2023-10-20 10:58:31 +08:00
dong
c5f033a598 移除列车调整 2023-10-18 15:04:08 +08:00
joylink_zhaoerwei
f126cef711 去弹框顶部的radius 2023-10-18 15:01:45 +08:00
joylink_zhaoerwei
5f1999adfb 代码优化--定时器 2023-10-18 11:17:45 +08:00
tiger_zhou
c221bd6d56 告警参数变更 2023-10-17 11:10:30 +08:00
tiger_zhou
26b0ba9b3a 告警参数变更 2023-10-17 11:09:53 +08:00
tiger_zhou
157398ac9b 告警参数变更 2023-10-17 10:56:46 +08:00
tiger_zhou
763136c4e6 告警参数变更 2023-10-17 10:55:28 +08:00
tiger_zhou
a2513a7e55 告警参数变更 2023-10-17 10:50:47 +08:00
tiger_zhou
f6d3ccc7e4 告警参数变更 2023-10-17 10:49:38 +08:00
tiger_zhou
96298d4d60 告警参数变更 2023-10-17 10:44:16 +08:00
tiger_zhou
306d624508 告警参数变更 2023-10-17 10:38:22 +08:00
tiger_zhou
a2bf56da76 告警参数变更 2023-10-17 10:31:35 +08:00
tiger_zhou
c8685a9213 告警参数变更 2023-10-17 10:30:55 +08:00
tiger_zhou
4c384ec372 告警参数变更 2023-10-16 17:53:44 +08:00
tiger_zhou
3305ec024e 告警参数变更 2023-10-16 17:49:43 +08:00
tiger_zhou
dc8425559f 告警参数变更 2023-10-16 17:48:00 +08:00
tiger_zhou
113e1edb28 告警参数变更 2023-10-16 17:39:00 +08:00
tiger_zhou
da13d24e7f 告警参数变更 2023-10-16 17:37:37 +08:00
tiger_zhou
e427cc3748 告警参数变更 2023-10-16 17:35:51 +08:00
tiger_zhou
64c3678d08 支持分环境打包 2023-10-16 14:01:38 +08:00
joylink_zhaoerwei
e74fce268e 侧边栏顺序调整 2023-10-10 16:21:23 +08:00
joylink_zhaoerwei
37a81de2ce 播放音乐调整 2023-10-10 16:14:07 +08:00
joylink_zhaoerwei
8149d6d6f1 循环报警修改 2023-10-10 14:02:46 +08:00
joylink_zhaoerwei
60f97b5ea3 需求调整--报警边框、每3分钟播放音乐、确认后更新报警列表 2023-10-10 11:08:42 +08:00
joylink_zhaoerwei
f0d7f13ae9 报警弹框---换行 2023-10-09 10:31:48 +08:00
joylink_zhaoerwei
94adee376c 故意演示框选调整 2023-10-09 09:35:05 +08:00
joylink_zhaoerwei
c253ee4461 微调 2023-10-08 16:38:20 +08:00
joylink_zhaoerwei
89dcf0e28d 范围配置更改 2023-10-08 15:50:26 +08:00
joylink_zhaoerwei
a79f6c71eb 需求调整--演示、单选、线路Id、站台门 2023-10-08 13:11:46 +08:00
joylink_zhaoerwei
58b04e3024 删除无用代码+框选bug 2023-09-27 14:56:48 +08:00
joylink_zhaoerwei
ce8b36179d 1范围划分 故障类型 删除 二级联锁
2 范围划分 故障类型 隐藏 联锁区红光带,联锁区橙光带
3 范围划分 故障类型 “一级联锁” 只能选择一个故障类型,且只能选择一个设备(集中站)
4 决策信息筛选 添加SWITCH_LOST_INTERLOCK_AREA(联锁区失表)
5 告警提示对SWITCH_LOST_INTERLOCK_AREA(联锁区失表)类型的支持
6 决策信息筛选 隐藏 “一级联锁”选项
2023-09-27 14:34:30 +08:00
joylink_zhaoerwei
6070c127fe 加tip提示 2023-09-26 17:48:01 +08:00
joylink_zhaoerwei
199c06560e 范围配置加省略号 2023-09-26 17:44:52 +08:00
joylink_zhaoerwei
4dd2d5a046 范围配置增加故障类型 2023-09-25 14:41:21 +08:00
tiger_zhou
95b6f380b9 更改logo文件名称,在现场无法显示问题 2023-09-22 16:55:53 +08:00
joylink_zhaoerwei
6b7411bccd 灯改光 2023-09-22 15:49:30 +08:00
joylink_zhaoerwei
4104017e31 微调 2023-09-22 15:43:35 +08:00
dong
f04d74e660 代码调整 2023-09-22 15:34:29 +08:00
joylink_zhaoerwei
09e3333a0d 微调 2023-09-22 11:18:42 +08:00
fan
73b00b10aa Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-09-22 11:06:02 +08:00
fan
b965bd7c77 框架同步 2023-09-22 11:05:57 +08:00
joylink_zhaoerwei
db705bf0e3 故障设置框选 2023-09-22 10:49:34 +08:00
dong
03b8ebd4f1 代码调整 2023-09-22 10:03:02 +08:00
dong
ff8a4f1c07 修改设置故障测试框选问题 2023-09-22 09:44:00 +08:00
joylink_zhaoerwei
3a8e48b06f 故障演练可以选道岔物理区段 2023-09-22 09:06:19 +08:00
joylink_zhaoerwei
b988cf146a 微调 2023-09-21 18:03:27 +08:00
joylink_zhaoerwei
96407b6d1c 设置演练故障 2023-09-21 16:57:48 +08:00
joylink_zhaoerwei
4eb6f82f33 道岔公里标 2023-09-21 15:49:17 +08:00
joylink_zhaoerwei
7dcd8cac17 框选bugfix 2023-09-21 15:32:29 +08:00
joylink_zhaoerwei
01f2e9cccf 打包配置以及列车故障只选一个设备 2023-09-21 15:10:01 +08:00
joylink_zhaoerwei
060b909a9f 增加故障测试 2023-09-21 14:09:40 +08:00
joylink_zhaoerwei
5c081c99a8 绘图表单优化--备用 2023-09-20 16:34:03 +08:00
joylink_zhaoerwei
43dffe1c4b 微调 2023-09-20 10:38:24 +08:00
joylink_zhaoerwei
8146ee4f79 决策信息编辑 2023-09-20 09:58:53 +08:00
joylink_zhaoerwei
9392e28258 微调 2023-09-19 16:54:22 +08:00
joylink_zhaoerwei
3ade4996d3 决策信息时间修改 2023-09-19 16:51:00 +08:00
joylink_zhaoerwei
421fa1e545 范围列表修改 2023-09-19 16:23:10 +08:00
joylink_zhaoerwei
e54ba3ba51 查找决策信息微调 2023-09-19 16:14:35 +08:00
joylink_zhaoerwei
7a7d8e18f0 微调 2023-09-19 15:46:06 +08:00
joylink_zhaoerwei
4b891b97f4 增加时间配置 2023-09-19 15:38:26 +08:00
joylink_zhaoerwei
3dcc701050 增加故障类型 2023-09-19 10:39:48 +08:00
joylink_zhaoerwei
307d2f778a 增加设置故障类型 2023-09-19 10:31:20 +08:00
joylink_zhaoerwei
1ac416e7a4 同步框架 2023-09-18 17:40:41 +08:00
joylink_zhaoerwei
fc619890fe 绘制图形属性组件去除watch 2023-09-18 15:51:37 +08:00
fan
490fdab81d Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-09-18 11:21:25 +08:00
fan
dad0a34339 同步框架代码 2023-09-18 11:21:20 +08:00
dong
303876413a 代码调整 2023-09-18 09:46:07 +08:00
Yuan
b5716e181b link 2023-09-15 16:42:19 +08:00
joylink_zhaoerwei
450780677e 范围配置修改 2023-09-15 16:35:59 +08:00
joylink_zhaoerwei
c7d0bbe9bc 报警跳转都报 2023-09-14 17:31:34 +08:00
joylink_zhaoerwei
50558f46c7 微调 2023-09-14 16:40:19 +08:00
joylink_zhaoerwei
2b6ca6e010 微调 2023-09-14 16:36:40 +08:00
joylink_zhaoerwei
be75846529 跳转逻辑修改 2023-09-14 16:32:21 +08:00
dong
31682d9f28 添加路由拦截 2023-09-14 14:26:08 +08:00
dong
1f32be8ce1 登录和注册界面调整 2023-09-14 13:54:48 +08:00
joylink_zhaoerwei
0686831059 微调 2023-09-14 13:38:25 +08:00
joylink_zhaoerwei
a1c73423f2 报警列表增加查询 2023-09-14 10:56:08 +08:00
joylink_zhaoerwei
238edf7869 音乐替换-范围管理和决策信息管理优化添加查询条件 2023-09-14 10:32:22 +08:00
dong
65b70debed 添加报警统计 2023-09-13 16:28:41 +08:00
joylink_zhaoerwei
7d18f8dca7 报警界面和ATS界面分离+跳转逻辑修改 2023-09-12 13:12:49 +08:00
dong
b615906e8c 路由调整 2023-09-12 10:22:26 +08:00
dong
d965af29d9 路由调整 2023-09-12 10:11:10 +08:00
dong
7229abfc62 logo调整 2023-09-11 18:01:08 +08:00
dong
b54e3a77fc logo图片调整 2023-09-11 17:49:25 +08:00
dong
c153582c3a 代码调整 2023-09-11 17:19:41 +08:00
dong
6a80bd0473 更换logo图片 2023-09-11 16:54:34 +08:00
Yuan
30f645bf0a Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-09-05 16:30:47 +08:00
Yuan
67c8eb8dfb bugfix 2023-09-05 16:30:41 +08:00
joylink_zhaoerwei
f2e16f8312 隐藏状态属性--抽屉 2023-09-05 16:15:00 +08:00
dong
dba7d34f1a 添加socket订阅 2023-09-05 10:57:30 +08:00
Yuan
c0ebe15789 rangeConfigApp 2023-09-04 10:32:39 +08:00
Yuan
c38fa9d8b3 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-09-01 18:01:04 +08:00
Yuan
8f27d88af4 lineApp 2023-09-01 18:01:01 +08:00
fan
caed6c021d Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-09-01 17:16:06 +08:00
fan
fb8e0df87d 同步框架代码 2023-09-01 17:15:37 +08:00
Yuan
1ec8e86ee8 框架同步 2023-09-01 17:15:33 +08:00
Yuan
7f292426c8 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-09-01 17:14:13 +08:00
Yuan
bad9c90983 lineNetApp 2023-09-01 17:14:08 +08:00
fan
f8e6f60e6f Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-09-01 16:34:54 +08:00
fan
cc077e3f21 框架代码同步 2023-09-01 16:34:46 +08:00
Yuan
f63ec5b12c Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-09-01 14:31:45 +08:00
Yuan
eb07afb452 lineApp 2023-09-01 14:30:45 +08:00
joylink_zhaoerwei
dee86e132f 隐藏滚动条 2023-09-01 13:55:18 +08:00
joylink_zhaoerwei
32cfc5f329 图形绘制的引入修改 2023-09-01 10:02:58 +08:00
joylink_zhaoerwei
a2c0bceb2d 绘制调整 2023-09-01 09:49:16 +08:00
joylink_zhaoerwei
73379f4bd3 同步框架代码 2023-08-31 17:46:38 +08:00
Yuan
d96778aa7a graphics框架更新 2023-08-31 15:58:31 +08:00
Yuan
f980c4f557 graphics框架更新 2023-08-31 15:58:15 +08:00
dong
97fa9307b7 代码调整 2023-08-30 17:52:59 +08:00
dong
c0d55ccee6 报警故障阈值配置新增项 2023-08-30 17:43:59 +08:00
joylink_zhaoerwei
be5408aedc 故障音乐map调整 2023-08-29 15:36:13 +08:00
joylink_zhaoerwei
ed3eb1ea9a 增加故障提示音 2023-08-29 13:04:16 +08:00
joylink_zhaoerwei
0f83f9e004 微调 2023-08-28 16:58:15 +08:00
joylink_zhaoerwei
ae23f7de71 微调 2023-08-28 15:37:14 +08:00
joylink_zhaoerwei
e35637524d 模拟故障增加故障设备 2023-08-28 15:22:03 +08:00
joylink_zhaoerwei
041052113a 决策信息故障选择后指定范围配置 2023-08-28 10:32:43 +08:00
Yuan
e402fc8f6a 删除无用的import 2023-08-28 10:11:02 +08:00
joylink_zhaoerwei
debdde142e 增加全线蓝显 2023-08-28 09:48:11 +08:00
Yuan
0ab592a01d 范围配置app销毁 2023-08-25 18:18:17 +08:00
Yuan
6f2c573411 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-25 17:28:50 +08:00
Yuan
b5795f19e0 范围管理拆分App 2023-08-25 17:27:25 +08:00
dong
7d6e9c6161 代码调整 2023-08-25 14:50:11 +08:00
joylink_zhaoerwei
1535755414 临时用 2023-08-25 13:11:46 +08:00
joylink_zhaoerwei
da829d4d54 新建提交后表单不校验 2023-08-25 09:31:55 +08:00
joylink_zhaoerwei
e388069ff1 微调 2023-08-25 08:59:18 +08:00
joylink_zhaoerwei
3fbc2f20f0 bug修复 2023-08-24 18:24:49 +08:00
tiger_zhou
6df6aa6b3a 告警参数变更 2023-08-24 17:49:40 +08:00
joylink_zhaoerwei
030bea1293 protobuf同步 2023-08-24 16:53:06 +08:00
joylink_zhaoerwei
4e72128bbd 增加字段 2023-08-24 16:14:21 +08:00
joylink_zhaoerwei
13e7d78f1b 增加故障类型 2023-08-24 15:37:37 +08:00
dong
1b0582979f 代码调整 2023-08-24 14:00:52 +08:00
dong
31c520359c 列车找不到所在设备时删除列车 2023-08-24 13:59:10 +08:00
dong
cc45d794e9 代码调整 2023-08-24 13:29:24 +08:00
dong
4915d0c9ce 代码调整 2023-08-24 13:14:49 +08:00
dong
264d1a696c 报警故障阈值配置调整 2023-08-24 13:11:59 +08:00
joylink_zhaoerwei
057554d224 决策信息隐藏时间 2023-08-24 10:06:01 +08:00
joylink_zhaoerwei
007e340ae2 微调 2023-08-23 18:04:27 +08:00
joylink_zhaoerwei
283e576442 微调 2023-08-23 17:16:40 +08:00
joylink_zhaoerwei
91c6290513 列表高度自适应 2023-08-23 17:07:18 +08:00
joylink_zhaoerwei
9901c2334f 类型修改,去any 2023-08-23 16:54:15 +08:00
joylink_zhaoerwei
e46997271a 增加删除选择的图形 2023-08-23 16:25:49 +08:00
joylink_zhaoerwei
3036016928 范围配置和决策信息修改 2023-08-23 15:56:50 +08:00
Yuan
c3d4c7cc12 范围列表调整 2023-08-23 15:45:43 +08:00
Yuan
1ce48a45d0 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-23 14:52:30 +08:00
Yuan
49d5f6c0ac 删除提示 2023-08-23 14:52:27 +08:00
joylink_zhaoerwei
fa213a9225 范围配置字段修改 2023-08-23 14:45:03 +08:00
joylink_zhaoerwei
3ab1ee41a1 编辑按钮bug修复 2023-08-23 13:26:53 +08:00
joylink_zhaoerwei
104656affb 框选方式修改 2023-08-23 11:23:45 +08:00
Yuan
b2b8eb6c4f 范围删除 2023-08-23 10:47:05 +08:00
joylink_zhaoerwei
ad7a6db096 微调 2023-08-23 09:56:47 +08:00
Yuan
f81690be14 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-23 09:50:38 +08:00
Yuan
4293d4e8e0 列表数据去除data 2023-08-23 09:50:35 +08:00
joylink_zhaoerwei
06f453a686 范围配置编辑 2023-08-23 09:44:23 +08:00
Yuan
c881d48145 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-23 09:18:17 +08:00
Yuan
5d5527f692 范围列表 2023-08-23 09:17:50 +08:00
dong
2af63042f5 添加报警故障阈值配置 2023-08-22 16:47:12 +08:00
joylink_zhaoerwei
e388576562 编辑范围配置 2023-08-22 15:45:35 +08:00
Yuan
6768738344 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-22 15:22:54 +08:00
Yuan
513debd156 范围列表也 2023-08-22 15:22:26 +08:00
joylink_zhaoerwei
70c6cf571a 微调 2023-08-22 15:21:00 +08:00
joylink_zhaoerwei
efd57e13bd 微调 2023-08-22 14:28:59 +08:00
Yuan
b678b64db8 范围配置入口调整 2023-08-22 13:51:55 +08:00
joylink_zhaoerwei
456a8f9aa8 微调 2023-08-22 13:49:45 +08:00
Yuan
5bb9b1dea2 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-22 13:41:50 +08:00
Yuan
94a4fb6726 范围配置入口 2023-08-22 13:41:46 +08:00
joylink_zhaoerwei
4b53e3c714 区域配置 2023-08-22 13:21:22 +08:00
Yuan
c31551eaf7 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-22 10:27:41 +08:00
Yuan
6925e761dc 范围配置列表 2023-08-22 10:27:35 +08:00
joylink_zhaoerwei
9ceb537427 微调 2023-08-21 17:58:46 +08:00
joylink_zhaoerwei
268c28c6ac 设备范围配置 2023-08-21 17:25:27 +08:00
Yuan
3ea2ce9dae 消息同步 2023-08-21 10:13:58 +08:00
joylink_zhaoerwei
a0fbbf9f69 关闭多个打开的弹框 2023-08-18 13:38:30 +08:00
Yuan
519db50c87 代码同步 2023-08-18 13:14:14 +08:00
Yuan
a0eb49b73b Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-18 13:12:53 +08:00
Yuan
96749d8811 道岔和区段关系显示调整 2023-08-18 13:12:50 +08:00
joylink_zhaoerwei
9ea0fdd522 微调 2023-08-18 10:35:54 +08:00
dong
11bc0ba046 代码调整 2023-08-18 10:24:30 +08:00
dong
68a96b32c2 代码调整 2023-08-18 10:06:43 +08:00
joylink_zhaoerwei
bba26fcdf1 测试音乐路径 2023-08-18 09:59:57 +08:00
joylink_zhaoerwei
4db27e9e3c 音乐路径修改 2023-08-18 09:54:27 +08:00
joylink_zhaoerwei
ebbdff239d 微调 2023-08-18 09:01:40 +08:00
joylink_zhaoerwei
0c8163e7b5 光带修改 2023-08-17 18:19:05 +08:00
dong
b35b8892f6 代码调整 2023-08-17 18:04:54 +08:00
joylink_zhaoerwei
6e76faf9f7 微调 2023-08-17 17:06:43 +08:00
joylink_zhaoerwei
795d6a2199 字段调整--红光带变光带 2023-08-17 16:41:40 +08:00
joylink_zhaoerwei
01b8113a73 动态播放音乐及弹框 2023-08-17 15:27:48 +08:00
joylink_zhaoerwei
52155b6939 增加模拟故障种类 2023-08-17 11:20:10 +08:00
joylink_zhaoerwei
7d68bcb16a 报警信息确认处理 2023-08-17 11:06:34 +08:00
dong
b0b9dc11b8 添加未处理报警角标 2023-08-17 11:02:40 +08:00
Yuan
72fdc9997c Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-17 10:10:40 +08:00
dong
54999a9339 路由调整 2023-08-17 10:09:39 +08:00
Yuan
a3f49f67ff Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-17 09:40:07 +08:00
Yuan
9877c7db05 类型 2023-08-17 09:40:04 +08:00
joylink_zhaoerwei
d3e12f5846 微调 2023-08-16 18:00:38 +08:00
joylink_zhaoerwei
b38872c13b 调到具体故障设备 2023-08-16 17:44:16 +08:00
joylink_zhaoerwei
8aefbb12e5 代码备用--报警弹框和列表 2023-08-16 16:18:15 +08:00
Yuan
9f74f659ad 区段增加转换轨字段 2023-08-16 16:12:20 +08:00
Yuan
38e85d3dfd Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-16 15:52:47 +08:00
Yuan
87d3fee04e 删除注释 2023-08-16 15:52:43 +08:00
fan
bbee8cc5e1 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-08-16 14:02:32 +08:00
fan
15c3ae9a16 蓝显调整 2023-08-16 14:02:23 +08:00
joylink_zhaoerwei
5082d847bf 微调 2023-08-14 13:22:22 +08:00
joylink_zhaoerwei
cde1cc2334 车站状态数据 2023-08-14 10:55:42 +08:00
fan
ca7d76b979 同步框架代码 2023-08-11 14:41:33 +08:00
fan
32a2c702b5 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-08-10 11:12:06 +08:00
fan
b2521653c8 列车显示调整 2023-08-10 11:11:58 +08:00
Yuan
8b2a40ef92 道岔失表不显示红框 2023-08-10 10:17:23 +08:00
fan
4f115f4f58 信号机碰撞检测调整 2023-08-08 14:47:01 +08:00
fan
4d82d8d4f2 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-08-07 10:32:52 +08:00
fan
fbf4eb56d3 信号机多次创建问题调整 2023-08-07 10:32:46 +08:00
joylink_zhaoerwei
e22b1f4d1f 车次窗去掉碰撞检测 2023-08-07 10:15:35 +08:00
joylink_zhaoerwei
2dd92f7b0c 车次窗、矩形的碰撞检测修改 2023-08-07 09:46:33 +08:00
fan
d684043743 列车计算车次窗调整 2023-08-04 15:55:15 +08:00
Yuan
5fb9bb0e3c 道岔物理区段构建与子道岔的关系 2023-08-04 15:49:34 +08:00
joylink_zhaoerwei
fa4b5e2b7d 车次窗关联道岔物理区段 2023-08-04 15:18:14 +08:00
fan
6983c0feda 同步框架代码 2023-08-04 13:47:22 +08:00
fan
0a2ecc0bb3 线网销毁 2023-08-03 17:58:07 +08:00
fan
49e810e4ed baseUrl调整 2023-08-03 14:22:04 +08:00
fan
9a303f7c2c Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-08-03 14:21:25 +08:00
fan
fc770634ee ncc问题调整 2023-08-03 14:21:18 +08:00
Yuan
f114be9a98 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-03 10:11:30 +08:00
Yuan
f0ee9b3080 道岔物理区段禁用右键端点编辑菜单 2023-08-03 10:11:26 +08:00
fan
a737745fd2 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-08-03 10:06:58 +08:00
fan
b6b1630a91 西安ncc状态同步调整 2023-08-03 10:06:52 +08:00
Yuan
4656f3147d 物理区段目的地码显示 2023-08-03 09:26:45 +08:00
fan
d14f0a0e8b Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-08-02 16:13:57 +08:00
fan
5a6848b005 框架代码同步 2023-08-02 16:13:51 +08:00
joylink_zhaoerwei
8d78f32e72 微调 2023-08-02 14:26:48 +08:00
Yuan
988eafd521 道岔限速显示修改 2023-08-02 09:25:48 +08:00
Yuan
9d9806beac 道岔限速显示调整 2023-08-01 17:30:14 +08:00
Yuan
8e7120b5dd Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-08-01 16:35:57 +08:00
Yuan
059c905951 道岔区段限速 2023-08-01 16:35:53 +08:00
fan
c4ed2bde5d Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-08-01 16:27:04 +08:00
fan
bfd937da72 运行线调整 2023-08-01 16:26:57 +08:00
joylink_zhaoerwei
870169a870 线网画布微调 2023-08-01 14:03:23 +08:00
joylink_zhaoerwei
6a5bed588f 线路图监控画布调整 2023-08-01 13:19:56 +08:00
joylink_zhaoerwei
5085de4d6d 类型报错修改 2023-08-01 10:15:57 +08:00
joylink_zhaoerwei
b130ee33d7 微调 2023-08-01 09:33:05 +08:00
Yuan
e7c755348b 框架同步 2023-07-31 17:04:18 +08:00
d04209e756 Merge branch 'master' of https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-client 2023-07-31 16:52:53 +08:00
61c3c10bd2 bugfix-打包报错: line-net-store.js TypeError: Cannot read properties of undefined (reading 'prototype')
报错原因:protobufjs包使用vite打包导致代码顺序问题(使用在声明之前),通过配置添加alias,直接使用已经build好的protobufjs代码
2023-07-31 16:52:44 +08:00
Yuan
d9af13bb46 Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-07-31 16:46:00 +08:00
Yuan
b6ec60b242 道岔切除 2023-07-31 16:45:55 +08:00
joylink_zhaoerwei
dbde11026c 站台车站状态调整方式更改 2023-07-31 16:37:45 +08:00
Yuan
9490392177 区段限速 2023-07-31 16:33:06 +08:00
Yuan
53f6d882ab 区段和道岔故障锁闭显示白光带 2023-07-31 14:35:23 +08:00
Yuan
3447055aa5 橙光带对应actInvalid 2023-07-31 14:03:02 +08:00
Yuan
14bd3b7b65 道岔颜色根据正反位显示 && 道岔和区段增加overlap状态显示 2023-07-31 13:49:38 +08:00
Yuan
a3c264312d Merge branch 'master' of git.code.tencent.com:xian-ncc-da/xian-ncc-da-client 2023-07-31 11:30:15 +08:00
Yuan
86cc8754fb 白屏暂时修复 2023-07-31 11:30:05 +08:00
210 changed files with 13223 additions and 13303 deletions

4
.env.dev Normal file
View File

@ -0,0 +1,4 @@
API=192.168.3.233:9081
HTTP=http://
NS=
WS=ws://

4
.env.dev-show Normal file
View File

@ -0,0 +1,4 @@
API=test.joylink.club
HTTP=https://
NS=/ncc
WS=wss://

4
.env.local Normal file
View File

@ -0,0 +1,4 @@
API=localhost:9081
HTTP=http://
NS=
WS=ws://

4
.env.prod Normal file
View File

@ -0,0 +1,4 @@
API=10.255.6.60:9081
HTTP=http://
NS=
WS=ws://

4
.gitmodules vendored
View File

@ -1,7 +1,3 @@
[submodule "xian-ncc-da-message"]
path = xian-ncc-da-message
url = https://git.code.tencent.com/xian-ncc-da/xian-ncc-da-message.git
[submodule "graphic-pixi"]
path = graphic-pixi
url = https://git.code.tencent.com/jl-framework/graphic-pixi.git
branch = xian-ncc-da

19
EnvParse.js Normal file
View File

@ -0,0 +1,19 @@
const DotEnv = require('dotenv');
module.exports = function () {
let script = process.env.npm_lifecycle_script;
let name = 'dev';
if (script) {
// quasar启动没有这个
script = script.substring(script.indexOf('NODE_ENV=') + 'NODE_ENV='.length);
name = script.substring(0, script.indexOf('&'));
} else {
if (process.env.NODE_ENV == 'production') {
name = 'prod';
}
}
console.log(name);
name = '.env.' + name;
let parsedEnv = DotEnv.config({ path: name }).parsed;
return parsedEnv;
};

@ -1 +1 @@
Subproject commit 91eb4a1d0835a8bc007febaf9054291c27d065ff
Subproject commit b5ca64750380db0ff8e4e4a56a471363db684e12

View File

@ -3,19 +3,43 @@
<head>
<title><%= productName %></title>
<meta charset="utf-8">
<meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">
<meta charset="utf-8" />
<meta name="description" content="<%= productDescription %>" />
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<meta
name="viewport"
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"
/>
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png">
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
<link rel="icon" type="image/ico" href="favicon.ico">
<link
rel="icon"
type="image/png"
sizes="128x128"
href="logo/xian_favicon.png"
/>
<link
rel="icon"
type="image/png"
sizes="96x96"
href="logo/xian_favicon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="logo/xian_favicon.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="logo/xian_favicon.png"
/>
<!-- <link rel="icon" type="image/ico" href="favicon.ico" /> -->
<link rel="icon" type="image/png" href="logo/xian_favicon.png" />
</head>
<body>
<body style="overflow: hidden">
<!-- quasar:entry-point -->
</body>
</html>

View File

@ -9,24 +9,25 @@
"lint": "eslint --ext .js,.ts,.vue ./",
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
"test": "echo \"No test specified\" && exit 0",
"dev": "quasar dev",
"build": "quasar build",
"dev": "set NODE_ENV=dev&&quasar dev",
"local": "set NODE_ENV=local&&quasar dev",
"build": "set NODE_ENV=dev&&quasar build",
"prod": "set NODE_ENV=prod&&quasar build",
"dev-show": "set NODE_ENV=dev-show&&quasar build",
"protoc": "node scripts/proto.cjs",
"sync": "node scripts/sync.cjs"
},
"dependencies": {
"@pixi/filter-outline": "^5.2.0",
"@pixi/graphics-extras": "^7.2.4",
"@quasar/extras": "^1.0.0",
"@stomp/stompjs": "^7.0.0",
"centrifuge": "^4.0.1",
"axios": "^1.2.1",
"centrifuge": "^4.0.1",
"dotenv": "^16.3.1",
"google-protobuf": "^3.21.2",
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.3",
"js-base64": "^3.7.5",
"pinia": "^2.0.11",
"pixi-viewport": "^5.0.1",
"pixi.js": "^7.2.4",
"quasar": "^2.6.0",
"save-dev": "0.0.1-security",
"vue": "^3.0.0",
"vue-router": "^4.0.0"
},

Binary file not shown.

Binary file not shown.

BIN
public/alarmMusic/blue.mp3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/alarmMusic/red.mp3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/logo/NCC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
public/logo/NCC_bai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
public/logo/logoBg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
public/logo/xian.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -53,10 +53,23 @@ module.exports = configure(function (/* ctx */) {
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
build: {
target: {
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
browser: ['es2020'],
node: 'node16',
},
env: require('./EnvParse.js')(),
chainWebpack(chain) {
chain
.plugin('eslint-webpack-plugin')
.use(ESLintPlugin, [{ extensions: ['js', 'vue'] }]);
chain.plugin('define').use(require('webpack/lib/DefinePlugin'), [
{
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
},
]);
},
vueRouterMode: 'history', // available values: 'hash', 'history'
vueRouterBase: BasePath,
// vueDevtools,
@ -71,10 +84,16 @@ module.exports = configure(function (/* ctx */) {
// ignorePublicFolder: true,
// minify: false,
// polyfillModulePreload: true,
// distDir
distDir: 'dist/xianncc',
// distDir: `dist/${BasePath}`,
// extendViteConf (viteConf) {},
alias: { 'protobufjs/light': 'protobufjs/dist/light/protobuf.min.js' },
// extendViteConf(viteConf) {
// viteConf.resolve.alias = Object.assign({}, viteConf.resolve.alias, {
// 'protobufjs/light': 'protobufjs/dist/light/protobuf.min.js',
// });
// },
// viteVuePluginOptions: {},
// vitePlugins: [

View File

@ -1,70 +0,0 @@
/**
* 同步图形框架文件到 src/jl-graphic/
*/
const {
readdirSync,
existsSync,
copyFileSync,
mkdirSync,
rmSync,
} = require('fs');
const { resolve } = require('path');
const jlGraphicSrcPath = resolve(__dirname, '../graphic-pixi/src/jlgraphic');
const jlGraphicLibPath = resolve(__dirname, '../src/jl-graphic');
/**
* 检查并初始化当前项目引入的jl-graphic库
*/
function checkAndInitJlGraphicLib() {
const exist = existsSync(jlGraphicLibPath);
if (exist) {
console.log('jl-graphic文件夹已存在,清空');
readdirSync(jlGraphicLibPath, {
withFileTypes: true,
}).forEach((file) => {
if (file.isDirectory()) {
rmSync(resolve(jlGraphicLibPath, file.name), { recursive: true });
} else {
rmSync(resolve(jlGraphicLibPath, file.name));
}
});
} else {
console.log('jl-graphic文件夹不存在,创建');
// 文件夹不存在,创建
mkdirSync(jlGraphicLibPath);
}
}
function copyJlGraphicFiles() {
readdirSync(jlGraphicSrcPath, {
withFileTypes: true,
}).forEach((file) => {
recursiveCopyFiles(file);
});
}
function recursiveCopyFiles(file, path = []) {
if (file.isFile()) {
const fileSrcPath = resolve(jlGraphicSrcPath, ...path, file.name);
const fileDestPath = resolve(jlGraphicLibPath, ...path, file.name);
console.log(`copy file ${fileSrcPath} -> ${fileDestPath}`);
copyFileSync(fileSrcPath, fileDestPath);
} else if (file.isDirectory()) {
const srcDir = resolve(jlGraphicSrcPath, ...path, file.name);
const dirPath = resolve(jlGraphicLibPath, ...path, file.name);
mkdirSync(dirPath);
readdirSync(srcDir, {
withFileTypes: true,
}).forEach((subFile) => {
recursiveCopyFiles(subFile, [...path, file.name]);
});
}
}
function main() {
checkAndInitJlGraphicLib();
copyJlGraphicFiles();
}
main();

View File

@ -0,0 +1,27 @@
import { api } from 'src/boot/axios';
const BaseUrl = '/api/config/device';
export interface ParamsItem {
id?: number;
lineId: number;
configData: string;
}
/**
* /
* @param params
* @returns
*/
export function saveThreshold(data: ParamsItem) {
return api.post(`${BaseUrl}/save`, data);
}
/**
*
* @param lineId 线id
*/
export async function getBaseDataByLineId(lineId: number): Promise<ParamsItem> {
const response = await api.get(`${BaseUrl}/initData/${lineId}`);
return response.data;
}

View File

@ -0,0 +1,56 @@
import { api } from 'src/boot/axios';
import { PageDto, PageQueryDto } from './ApiCommon';
const BaseUrl = '/api/alert/tip/time';
export interface TimeConfigItem {
id?: number;
timeName: string;
startHour: string;
endHour: string;
timeType: string;
publicPeak?: string;
}
export enum TipTimeConfig {
= 'HOLIDAYS_MORN_PEAK',
= 'HOLIDAYS_EVENING_PEAK',
= 'MORN_PEAK',
= 'EVENING_PEARK',
= 'NORMAL_UNPEARK',
}
export enum ShowTipTimeConfig {
HOLIDAYS_MORN_PEAK = '假期早高峰',
HOLIDAYS_EVENING_PEAK = '假期晚高峰',
MORN_PEAK = '早高峰',
EVENING_PEARK = '晚高峰',
NORMAL_UNPEARK = '低峰',
}
/**
* /
* @param data
* @returns
*/
export function creatOrEditTimeConfig(data: TimeConfigItem) {
return api.post(`${BaseUrl}`, data);
}
class PageQueryParams extends PageQueryDto {
timeName?: string;
timeType?: string;
}
/**
*
* @param params
* @returns
*/
export async function alarmTipTimeConfigPageQuery(
params: PageQueryParams
): Promise<PageDto<TimeConfigItem>> {
const response = await api.post(`${BaseUrl}/page`, {
params: params,
});
return response.data;
}

View File

@ -1,24 +1,68 @@
import { api } from 'src/boot/axios';
import { PageDto, PageQueryDto } from './ApiCommon';
import { AlarmInfo } from './DecisionInfo';
const alertUriBase = '/api/alert/mock';
export function mockAlertSet(data: { lineId: number; alertType: string }) {
//故障测试
export function mockLocalDemoTestSet(
alertType: string,
data: {
lineId: number;
deviceInfos: {
deviceName: string;
deviceType: string;
status: string;
groupId?: string;
}[];
}
) {
return api.post(`${alertUriBase}/localDemoTest/${alertType}`, data);
}
//故障演示
export function mockAlertSet(data: {
lineId: number;
alertType: string;
deviceCodes: string[];
}) {
return api.post(`${alertUriBase}/set`, data);
}
/**
*
* @param id 线id
* @param alertType
*/
export async function getDeviceByAlarmType(
id: number,
alertType: string
): Promise<DeviceConfigItem[]> {
const response = await api.post(`${alertUriBase}/find/${id}/${alertType}`);
return response.data;
}
export interface DeviceConfigItem {
name: string;
code: string;
}
export class PagingQueryParams extends PageQueryDto {
alertType?: string;
lineId?: number;
beginDateTime?: string;
endDateTime?: string;
alertStatus?: number;
}
interface Item {
export interface Item {
id: number;
alertType: string;
timeType: string;
locationType: string;
drivingInfo: string;
submissionInfo: string;
alarmStatus: number;
}
/**
@ -29,8 +73,70 @@ interface Item {
export async function alarmInfoListQuery(
params: PagingQueryParams
): Promise<PageDto<Item>> {
const response = await api.get('/api/alertRecord/page/detail', {
params: params,
});
const response = await api.post('/api/alertRecord/page/detail', params);
return response.data;
}
/**
*
* @param id id
* @param tipType
* @param alertLocationId id
*/
export function recordConfirmAlarmInfoByTipType(
id: number,
tipType: string,
alertLocationId?: number
): Promise<AlarmInfo<Item>> {
return api.get(`/api/alertRecord/confirm/${id}/${tipType}`, {
params: { alertLocationId: alertLocationId },
});
}
/**
* --
* @param recordId id
*/
export function recordFailAlarmInfoById(recordId: number) {
return api.post(`/api/alertRecord/fail/${recordId}`);
}
/**
* --
* @param recordId id
*/
export function recordManualAlarmInfoById(recordId: number[]) {
return api.post('/api/alertRecord/warn', recordId);
}
export interface IReportParams {
alertTypes?: string[];
beginDateTime?: string;
endDateTime?: string;
alertStatus?: number;
}
interface IReportRes {
alertType: string;
counter: number;
}
/**
*
* @param lineId 线id
*/
export async function recordAlarmReport(
lineId: number,
data: IReportParams
): Promise<IReportRes[]> {
const response = await api.post(`/api/alertRecord/report/${lineId}`, data);
return response.data;
}
/**
*
* @param linId 线id
*/
export function resetApi(linId: number): Promise<string> {
return api.get(`${alertUriBase}/reset/${linId}`);
}

View File

@ -25,7 +25,7 @@ export class OrderItemDto {
}
}
export interface PageDto<T = unknown> {
export interface PageDto<T> {
records: T[];
/**
*

65
src/api/ConfigApi.ts Normal file
View File

@ -0,0 +1,65 @@
import { api } from 'src/boot/axios';
import { PageDto, PageQueryDto } from './ApiCommon';
export interface IAreaConfigListItem {
id: number;
lineId: number;
areaName: string;
deviceType: string;
}
export async function getDeviceAreaList({
lineId,
deviceType,
current,
size,
areaName,
}: {
lineId?: string;
deviceType?: string;
areaName?: string;
} & PageQueryDto) {
const resp = await api.get<PageDto<IAreaConfigListItem>>(
`/api/config/device/area/page/${lineId}`,
{ params: { current, size, deviceType, areaName } }
);
if (resp.status === 200) {
return resp.data;
} else {
throw Error(resp.statusText);
}
}
export async function deleteDeviceArea(id: number) {
const resp = await api.delete(`/api/config/device/area/${id}`);
if (resp.status === 200) {
return resp;
} else {
throw Error(resp.statusText);
}
}
export interface IAreaConfigItem {
id?: number;
lineId: number;
areaName: string;
deviceType: string;
alertTypes: string[];
data: number[];
}
export function deviceRangeSet(data: IAreaConfigItem) {
return api.post('/api/config/device/area/save', data);
}
/**
* id获取配置信息
* @param id id
*/
export function queryDeviceRangeById(
id: number
): Promise<IAreaConfig<IAreaConfigItem>> {
return api.get(`/api/config/device/area/${id}`);
}
interface IAreaConfig<T = unknown> {
data: T;
}

View File

@ -1,29 +1,36 @@
import { api } from 'src/boot/axios';
import { PageDto, PageQueryDto } from './ApiCommon';
import { TimeConfigItem } from './AlarmTipTimeConfig';
const DraftUriBase = '/api/alertTip';
const AlertTipUriBase = '/api/alertTip';
export interface createParams {
interface AlarmInfoCreateParams {
id: number;
alertType: string;
timeType: string;
locationType: string;
tipTimeIds: string[];
areaConfigId: number;
drivingInfo: string;
submissionInfo: string;
}
interface Item {
export interface AlarmInfoListItem {
id: number;
alertType: string;
timeType: string;
locationType: string;
timeConfigList: TimeConfigItem[];
areaConfigId: number;
drivingInfo: string;
submissionInfo: string;
areaConfigName?: string;
}
export interface AlarmInfo<T = unknown> {
data: T;
}
export class PagingQueryParams extends PageQueryDto {
alertType?: string;
timeType?: string;
locationType?: string;
areaConfigName?: string;
}
/**
@ -33,8 +40,8 @@ export class PagingQueryParams extends PageQueryDto {
*/
export async function alarmInfoPageQuery(
params: PagingQueryParams
): Promise<PageDto<Item>> {
const response = await api.get(`${DraftUriBase}/page`, {
): Promise<PageDto<AlarmInfoListItem>> {
const response = await api.get(`${AlertTipUriBase}/page`, {
params: params,
});
return response.data;
@ -44,17 +51,29 @@ export async function alarmInfoPageQuery(
* id获取决策信息
* @param id 稿id
*/
export function queryAlarmInfoById(id: number): Promise<AlarmInfo<Item>> {
return api.get(`${DraftUriBase}/id/${id}`);
export function queryAlarmInfoById(
id: number
): Promise<AlarmInfo<AlarmInfoListItem>> {
return api.get(`${AlertTipUriBase}/id/${id}`);
}
/**
*
*
* @param type 稿type
*/
export function queryAlarmInfoByType(
type: string
): Promise<AlarmInfo<AlarmInfoListItem>> {
return api.get(`${AlertTipUriBase}/type/${type}`);
}
/**
*
* @param params
* @returns
*/
export function createAlarmInfo(draftData: createParams) {
return api.post(`${DraftUriBase}`, draftData);
export function createAlarmInfo(draftData: AlarmInfoCreateParams) {
return api.post(`${AlertTipUriBase}`, draftData);
}
/**
@ -62,18 +81,26 @@ export function createAlarmInfo(draftData: createParams) {
* @param id 稿id
*/
export function deleteAlarmInfo(id: number) {
return api.delete(`${DraftUriBase}/id/${id}`);
return api.delete(`${AlertTipUriBase}/id/${id}`);
}
/**
*
* @param data
* @returns
*
* @param id 线id
* @param tipType
*/
export function updataAlarmInfo(id: number, data: Item) {
return api.put(`${DraftUriBase}/id`, data);
export async function getDeviceAreaByAlarmType(
id: number,
alertType: string
): Promise<AreaConfigItem[]> {
const response = await api.post(
`${AlertTipUriBase}/find/type/${id}/${alertType}`,
{}
);
return response.data;
}
export interface AlarmInfo<T = unknown> {
data: T;
export interface AreaConfigItem {
id: number;
areaName: string;
}

View File

@ -2,39 +2,39 @@ import { api } from 'src/boot/axios';
const platformUriBase = '/mock/platform/status';
const stationUriBase = '/mock/rtu/status';
const serverUriBase = '/mock/server/send';
export function mockPlatformApi(
lineId: number,
data: {
emergstop: boolean;
trainberth: boolean;
close: boolean;
upHold: boolean;
downHold: boolean;
upOccHold: boolean;
downOccHold: boolean;
psdOpen: boolean;
psdCut: boolean;
upSkipstop: boolean;
downSkipstop: boolean;
upTrainSkipstop: boolean;
downTrainSkipstop: boolean;
id: string;
nextSectionRunTime: 0;
nextSectionRunLevel: 0;
stopTime: 0;
}
) {
export interface mockPlatformParams {
emergstop: boolean;
trainberth: boolean;
close: boolean;
upHold: boolean;
downHold: boolean;
upOccHold: boolean;
downOccHold: boolean;
psdOpen: boolean;
psdCut: boolean;
upSkipstop: boolean;
downSkipstop: boolean;
upTrainSkipstop: boolean;
downTrainSkipstop: boolean;
id: string;
nextSectionRunTime: number;
nextSectionRunLevel: number;
stopTime: number;
}
export function mockPlatformApi(lineId: number, data: mockPlatformParams) {
return api.post(`${platformUriBase}/${lineId}`, data);
}
export function mockStationApi(
lineId: number,
data: {
ipRtuStusDown: true;
ipRtuStusInLocalCtrl: true;
ipRtuStusInCentralCtrl: true;
ipRtuStusInEmergencyCtrl: true;
ipRtuStusDown: boolean;
ipRtuStusInLocalCtrl: boolean;
ipRtuStusInCentralCtrl: boolean;
ipRtuStusInEmergencyCtrl: boolean;
id: string;
}
) {
@ -72,3 +72,14 @@ export function mockSignalApi(
) {
return api.post(`/mock/signal/status/${lineId}`, data);
}
export function mockServerApi(data: {
deviceType: string;
messageId: string;
lineId: number;
rtuId: number;
deviceName: string;
deviceStatus: number;
}) {
return api.post(serverUriBase, data);
}

View File

@ -44,6 +44,21 @@ export enum DevType {
DEVICE_TYPE_GAMA = 'DEVICE_TYPE_GAMA',
}
export const deviceTypeMap = {
DEVICE_TYPE_UNKNOW: '未知设备',
DEVICE_TYPE_RTU: '集中站',
DEVICE_TYPE_STATION: '车站',
DEVICE_TYPE_SIGNAL: '信号机',
DEVICE_TYPE_SWITCH: '道岔',
DEVICE_TYPE_TRACK: '轨道',
DEVICE_TYPE_ENTRY: '方向设备',
DEVICE_TYPE_PLATFORM: '站台',
DEVICE_TYPE_SCADA: '供电区段',
DEVICE_TYPE_WATERPROOF_DOOR: '防淹门',
DEVICE_TYPE_WORK_AREA: '工作区',
DEVICE_TYPE_GAMA: '区域自动驾驶',
};
export function trainMockApi(
lineId: number,
data: {

View File

@ -1,7 +1,4 @@
import { api } from 'src/boot/axios';
import { ITurnoutState } from 'src/graphics/turnout/Turnout';
const base = '/mock/train';
interface State {
id: string;
@ -37,9 +34,6 @@ interface State {
export async function setSwitchStatus(lineId: string, state: State) {
try {
delete state._state;
delete state._graphicType;
state.speedLimit = 0;
return await api.post(`/mock/switch/status/${lineId}`, state);
} catch (err) {
console.error(err);
@ -47,8 +41,6 @@ export async function setSwitchStatus(lineId: string, state: State) {
}
export async function setTrackStatus(lineId: string, state: State) {
try {
delete state._state;
delete state._graphicType;
return await api.post(`/mock/track/status/${lineId}`, state);
} catch (err) {
console.error(err);

View File

@ -0,0 +1,80 @@
<template>
<draggable-dialog
ref="dialogRef"
@show="onDialogShow"
seamless
title="与卡斯柯连接状态信息"
:width="300"
:height="0"
>
<template v-slot:footer>
<q-table
ref="tableRef"
row-key="id"
v-model:pagination="pagination"
:rows="rows"
:columns="columns"
@request="onRequest"
:rows-per-page-options="[10, 20, 50, 100]"
>
</q-table>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import DraggableDialog from './common/DraggableDialog.vue';
import { QTable } from 'quasar';
import { useLineNetStore } from 'src/stores/line-net-store';
import { state } from 'src/protos/system_warn_message';
const lineNetStore = useLineNetStore();
const dialogRef = ref<InstanceType<typeof DraggableDialog>>();
const tableRef = ref<QTable>();
const columns: QTable['columns'] = [
{ name: 'lineId', label: '线路ID', field: 'lineId', align: 'center' },
{
name: 'areaName',
label: '实时连接',
field: (row) => (row.occRealConned ? '是' : '否'),
align: 'center',
},
{
name: 'deviceType',
label: '非实时连接',
field: (row) => (row.occUnrealConned ? '是' : '否'),
align: 'center',
},
];
const rows = ref<state.WarnMessage[]>([]);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
watch(
() => lineNetStore.connectInfo,
() => {
onDialogShow();
}
);
const onRequest: QTable['onRequest'] = async (props) => {
const { page, rowsPerPage } = props.pagination;
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
const datas = lineNetStore.connectInfo?.msgs;
if (datas) {
rows.value = datas.slice((page - 1) * rowsPerPage, page * rowsPerPage - 1);
pagination.value.rowsNumber = datas.length;
}
};
const onDialogShow = () => {
tableRef.value?.requestServerInteraction();
};
</script>

View File

@ -0,0 +1,30 @@
import { type GraphicDataBase } from 'src/drawApp/graphics/GraphicDataBase';
import { IDrawApp, JlGraphic } from 'jl-graphic';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, onUnmounted, reactive } from 'vue';
const drawStore = useDrawStore();
export function useFormData<T extends GraphicDataBase>(
source: T,
app: IDrawApp
) {
const data = reactive<T>(source);
onMounted(() => {
app.bindFormData(data);
});
onUnmounted(() => {
app.unbindFormData(data);
});
function onUpdate() {
const graphic = drawStore.selectedGraphic as JlGraphic;
if (graphic) {
app.updateGraphicAndRecord(graphic, data);
}
}
return { data, onUpdate };
}

View File

@ -43,16 +43,14 @@ import { reactive } from 'vue';
const list = reactive([
{
path: '',
label: '系统管理',
icon: 'dataset',
children: [
{
path: '/sysManage/user',
label: '用户管理',
icon: 'manage_accounts',
},
],
path: '/monitor',
label: '监控',
icon: 'computer',
},
{
path: '/alarmList',
label: '报警列表',
icon: 'access_alarm',
},
{
path: '',
@ -67,24 +65,41 @@ const list = reactive([
{
path: '/dataManage/publish',
label: '发布管理',
icon: 'app_registration',
icon: 'playlist_add_check',
},
{
path: '/dataManage/lineInfo',
label: '线路信息管理',
icon: 'app_registration',
icon: 'format_list_numbered',
},
{
path: '/dataManage/decisionInfo',
label: '决策信息管理',
icon: 'app_registration',
icon: 'format_align_center',
},
{
path: '/dataManage/thresholdValue',
label: '报警故障阈值配置',
icon: 'format_indent_increase',
},
{
path: '/dataManage/alarmTipTimeConfig',
label: '报警提示时间配置',
icon: 'access_time',
},
],
},
{
path: '/monitor',
label: '监控',
icon: 'computer',
path: '',
label: '系统管理',
icon: 'dataset',
children: [
{
path: '/sysManage/user',
label: '用户管理',
icon: 'manage_accounts',
},
],
},
]);
</script>

View File

@ -1,5 +1,6 @@
<template>
<draggable-dialog
v-model="showDialog"
seamless
title="报警"
:titleColor="`${bgColor}`"
@ -8,6 +9,7 @@
:width="dialogWidth"
fontColor=""
:height="0"
bgBorder="solid 2px black"
>
<template v-slot:footer>
<div>
@ -17,18 +19,52 @@
<q-separator />
<div class="alarm-message-detail">
<div class="left">
<div class="text">时间:{{ alarmInfo.time }}</div>
<div class="text">级别:{{ alarmInfo.level }}</div>
<div class="text">线路:{{ alarmInfo.lineId }}号线</div>
<div class="text">时间{{ alarmInfo.time }}</div>
<div class="text">级别{{ alarmInfo.level }}</div>
<div class="text">线路{{ alarmInfo.lineId }}号线</div>
</div>
<div class="right">
<div class="text">设备:{{ alarmInfo.alertObject }}</div>
<div class="text">类型:{{ alarmInfo.alertType }}</div>
<div class="text">设备{{ alarmInfo.alertObject }}</div>
<div class="text" v-if="!showFaultType">
类型{{ alarmInfo.alertType }}
</div>
<div class="text" v-else>类型{{ faultType }}</div>
</div>
</div>
</q-card>
</div>
<div class="decision-message">
<div class="confirm-message" v-if="showConfirmMmessage">
<q-card class="box-card">
<div class="head">选择故障类型</div>
<q-separator />
<q-form class="detail" ref="myForm" @submit="confirmAlarm">
<q-select
style="width: 200px"
dense
outlined
v-model="faultType"
:options="faultTypeOptions"
label="故障类型"
:rules="[(val) => val.length > 0 || '请选择故障类型!']"
/>
<q-card-actions align="left">
<div class="q-gutter-md">
<q-btn color="primary" label="确认" type="submit" />
<q-btn color="red" label="误报" @click="falseAlarm" />
<q-btn
color="primary"
label="人工接警"
@click="manualAlarm"
/>
</div>
</q-card-actions>
</q-form>
</q-card>
</div>
<div
class="decision-message"
v-if="!showConfirmMmessage && showDecisionmessage"
>
<q-card class="box-card">
<div class="head">行车方面</div>
<q-separator />
@ -51,39 +87,30 @@
<script setup lang="ts">
import DraggableDialog from '../common/DraggableDialog.vue';
import { useLineNetStore } from 'src/stores/line-net-store';
import { onMounted, ref, watch } from 'vue';
import { useLineNetStore, AlarmInfo } from 'src/stores/line-net-store';
import { onMounted, ref } from 'vue';
import { QForm, useQuasar } from 'quasar';
import { saveAlertTypeData, showAlertTypeData } from './alarmInfoEnum';
import {
recordConfirmAlarmInfoByTipType,
recordFailAlarmInfoById,
recordManualAlarmInfoById,
} from 'src/api/AlertMock';
import { queryAlarmInfoById } from 'src/api/DecisionInfo';
import { useQuasar } from 'quasar';
const props = defineProps<{
alarmMeaasge?: AlarmInfo;
waitAlarmMeaasge?: AlarmInfo;
onHandle: (id: string) => void;
}>();
let bgColor = ref('');
const dialogWidth = window.screen.width * 0.5;
const lineNetStore = useLineNetStore();
watch(
() => lineNetStore.alarmInfo,
(val) => {
if (val.length) {
search();
updata();
}
},
{ deep: true }
);
const mapAlarmMessage = new Map([
['I', 'I类信息'],
['II', 'II类信息'],
['III', 'III类信息'],
['IV', 'IV类信息'],
['0', '未知'],
['1', '蓝显'],
['2', '列车延误2分钟'],
['3', '列车延误10分钟'],
['4', '整侧站台门无关闭锁紧信号'],
['5', '整侧站台门无法打开'],
['6', '整侧站台门无法关闭'],
]);
const showConfirmMmessage = ref(true);
const faultType = ref('');
let faultTypeOptions = [];
const showFaultType = ref(false);
const mapColor = new Map([
['I', 'rgb(250,61,46)'],
@ -100,36 +127,106 @@ const alarmInfo = ref({
alertObject: '',
alertType: '',
locator_device_id: '',
alert_location_id: '',
});
const drivingInfo = ref('');
const submissionInfo = ref('');
let messageUse: AlarmInfo;
const showDialog = ref(true);
const showDecisionmessage = ref(true);
onMounted(() => {
search();
if (props.alarmMeaasge == undefined && props.waitAlarmMeaasge == undefined) {
messageUse = lineNetStore.alarmInfo[0] as AlarmInfo;
} else if (props.waitAlarmMeaasge) {
messageUse = props.waitAlarmMeaasge as AlarmInfo;
} else {
messageUse = props.alarmMeaasge as AlarmInfo;
if (messageUse.alarmStatus == 1) {
showConfirmMmessage.value = false;
searchById();
} else if (messageUse.alarmStatus == 0) {
showConfirmMmessage.value = false;
showDecisionmessage.value = false;
}
}
updata();
switch (alarmInfo.value.alertType) {
case '道岔失表':
faultTypeOptions = ['道岔均失表', '道岔定位失表', '道岔反位失表'];
break;
default:
faultTypeOptions = [alarmInfo.value.alertType];
faultType.value = alarmInfo.value.alertType;
break;
}
});
function updata() {
bgColor.value = mapColor.get(lineNetStore.alarmInfo[0].level) as string;
alarmInfo.value.time = lineNetStore.alarmInfo[0].alert_time
.substring(0, 19)
.replace('T', ' ');
alarmInfo.value.level = mapAlarmMessage.get(
lineNetStore.alarmInfo[0].level
) as string;
alarmInfo.value.alertType = mapAlarmMessage.get(
lineNetStore.alarmInfo[0].alert_type + ''
) as string;
alarmInfo.value.alertObject = lineNetStore.alarmInfo[0].alert_object.replace(
/\[|]/g,
''
);
alarmInfo.value.lineId = lineNetStore.alarmInfo[0].line_id;
const myForm = ref<QForm | null>(null);
function confirmAlarm() {
myForm.value?.validate().then(async (res) => {
if (res) {
showConfirmMmessage.value = false;
showFaultType.value = true;
searchByTipType().then(() => {
lineNetStore.alarmInfoListTable?.requestServerInteraction();
props.onHandle(messageUse.id);
});
}
});
}
async function search() {
function falseAlarm() {
showDialog.value = false;
recordFailAlarmInfoById(+messageUse.id).then(() => {
lineNetStore.alarmInfoListTable?.requestServerInteraction();
props.onHandle(messageUse.id);
});
}
function manualAlarm() {
showDialog.value = false;
recordManualAlarmInfoById([+messageUse.id]).then(() => {
lineNetStore.alarmInfoListTable?.requestServerInteraction();
props.onHandle(messageUse.id);
});
}
function updata() {
bgColor.value = mapColor.get(messageUse.level) as string;
alarmInfo.value.time = messageUse.alert_time
.substring(0, 19)
.replace('T', ' ');
alarmInfo.value.level = (showAlertTypeData as never)[messageUse.level + ''];
alarmInfo.value.alertType = (showAlertTypeData as never)[
messageUse.alert_type + ''
];
alarmInfo.value.alertObject = messageUse.alert_object.replace(/\[|]/g, '');
alarmInfo.value.lineId = messageUse.line_id;
}
async function searchByTipType() {
try {
const id = lineNetStore.alarmInfo[0].alert_tip_id;
const type = (saveAlertTypeData as never)[faultType.value];
const response = await recordConfirmAlarmInfoByTipType(
+messageUse.id,
type,
messageUse.alert_location_id
);
drivingInfo.value = JSON.parse(response.data.drivingInfo);
submissionInfo.value = JSON.parse(response.data.submissionInfo);
lineNetStore.treatedAlarm(messageUse);
} catch (err) {
$q.notify({
type: 'negative',
message: '没有此类故障的辅助决策信息',
});
}
}
async function searchById() {
try {
const id = messageUse.alert_tip_id;
const response = await queryAlarmInfoById(id);
drivingInfo.value = JSON.parse(response.data.drivingInfo);
submissionInfo.value = JSON.parse(response.data.submissionInfo);
@ -154,11 +251,14 @@ async function search() {
}
.alarm-message-detail {
display: flex;
flex-flow: row wrap;
.left,
.right {
width: 50%;
padding: 0 5px;
.text {
width: 450px;
word-wrap: break-word;
margin-bottom: 10px;
font-size: 20px;
}
@ -166,12 +266,26 @@ async function search() {
}
}
}
.confirm-message {
margin-top: 10px;
.box-card {
height: 180px;
padding: 0 5px;
.head {
padding: 5px 5px;
font-size: 20px;
font-weight: 600;
}
.detail {
margin-top: 10px;
}
}
}
.decision-message {
display: flex;
justify-content: space-between;
margin: 10px 0;
margin-top: 10px;
.box-card {
max-height: 300px;
overflow: auto;
.head {
padding: 5px 5px;

View File

@ -0,0 +1,138 @@
export enum showAlertTypeData {
'未知故障',
'蓝显',
'列车延误2分钟',
'列车延误10分钟',
'整侧站台门无关闭锁紧信号',
'整侧站台门无法打开',
'整侧站台门无法关闭',
'道岔失表',
'道岔均失表',
'道岔定位失表',
'道岔反位失表',
'红光带',
'橙光带',
'计轴红光带',
'计轴大面积红光带',
'计轴橙光带',
'计轴大面积橙光带',
'道岔大面积失表',
'列车信号故障',
'全线蓝显',
'联锁区红光带',
'联锁区橙光带',
'联锁区失表',
'一级联锁',
I = 'I类信息',
II = 'II类信息',
III = 'III类信息',
IV = 'IV类信息',
TRAIN_DELAY_2 = '列车延误2分钟',
TRAIN_DELAY_10 = '列车延误10分钟',
BLUE_DISPLAY = '蓝显',
PLATFORM_DOOR_WITHOUT_LOCKED_SIGNAL = '整侧站台门无关闭锁紧信号',
PLATFORM_DOOR_CANNOT_OPEN = '整侧站台门无法打开',
PLATFORM_DOOR_CANNOT_CLOSE = '整侧站台门无法关闭',
QX = '全线',
YHZ_LSQ = '鱼化寨联锁区',
HJM_LSQ = '胡家庙联锁区',
BCT_LSQ = '北池头联锁区',
BSQ_LSQ = '保税区联锁区',
SWITCH_LOST = '道岔失表',
SWITCH_All_LOST = '道岔均失表',
SWITCH_DW_LOST = '道岔定位失表',
SWITCH_FW_LOST = '道岔反位失表',
AXLE_LED_RED = '计轴红光带',
AXLE_LED_RED_MOST = '计轴大面积红光带',
AXLE_LED_ORANGE = '计轴橙光带',
AXLE_LED_ORANGE_MOST = '计轴大面积橙光带',
SWITCH_LOST_MOST = '道岔大面积失表',
TRAIN_EB_ATP = '列车信号故障',
ALL_LINE_BLUE_DISPLAY = '全线蓝显',
AXLE_LED_RED_INTERLOCK_AREA = '联锁区红光带',
AXLE_LED_ORANGE_INTERLOCK_AREA = '联锁区橙光带',
SWITCH_LOST_INTERLOCK_AREA = '联锁区失表',
INTERLOCK_LEVEL_ONE = '一级联锁',
}
export enum saveAlertTypeData {
2 = 'TRAIN_DELAY_2',
10 = 'TRAIN_DELAY_10',
= 'BLUE_DISPLAY',
= 'PLATFORM_DOOR_WITHOUT_LOCKED_SIGNAL',
= 'PLATFORM_DOOR_CANNOT_OPEN',
= 'PLATFORM_DOOR_CANNOT_CLOSE',
线 = 'QX',
= 'YHZ_LSQ',
= 'HJM_LSQ',
= 'BCT_LSQ',
= 'BSQ_LSQ',
= 'SWITCH_LOST',
= 'SWITCH_All_LOST',
= 'SWITCH_DW_LOST',
= 'SWITCH_FW_LOST',
= 'AXLE_LED_RED',
= 'AXLE_LED_RED_MOST',
= 'AXLE_LED_ORANGE',
= 'AXLE_LED_ORANGE_MOST',
= 'SWITCH_LOST_MOST',
= 'TRAIN_EB_ATP',
线 = 'ALL_LINE_BLUE_DISPLAY',
= 'AXLE_LED_RED_INTERLOCK_AREA',
= 'AXLE_LED_ORANGE_INTERLOCK_AREA',
= 'SWITCH_LOST_INTERLOCK_AREA',
= 'INTERLOCK_LEVEL_ONE',
}
export const GuardConfigTypeData = {
switchLostTimes: { label: '道岔失表', unit: '秒', deviceType: '道岔' },
switchLostMostNums: {
label: '道岔大面积失表',
unit: '个',
deviceType: '道岔',
},
redLedMostNums: { label: '大面积红光带', unit: '个', deviceType: '计轴区段' },
orangeLedMostNums: {
label: '大面积橙光带',
unit: '个',
deviceType: '计轴区段',
},
canNotOpenTimes: {
label: '站台门无法打开',
unit: '秒',
deviceType: '屏蔽门',
},
canNotCloseTimes: {
label: '站台门无法关闭',
unit: '秒',
deviceType: '屏蔽门',
},
trainAtpCutTimes: {
label: '列车制动后导致atp切除的超时时间',
unit: '秒',
deviceType: '信号',
},
};
type findType = string | number;
export function isArraysEqual(arr1: findType[], arr2: findType[]) {
if (arr1.length !== arr2.length) {
return false;
}
return arr1.sort().join(',') === arr2.sort().join(',');
}
export enum ShowAlertStateData {
'未处理' = -1,
'误报',
'确认',
'人工接警',
}
export const alertStatusOptions = [
{ label: '全部', value: 999 },
{ label: '未处理', value: -1 },
{ label: '误报', value: 0 },
{ label: '确认', value: 1 },
{ label: '人工接警', value: 2 },
];

View File

@ -1,173 +0,0 @@
<template>
<draggable-dialog
seamless
title="报警列表"
:width="dialogWidth"
:height="dialogHeight"
>
<q-table
ref="tableRef"
title="报警信息"
:style="{ height: dialogHeight + 'px' }"
:rows="rows"
:columns="columnDefs"
row-key="id"
v-model:pagination="pagination"
:rows-per-page-options="[10, 20, 50, 100]"
:loading="loading"
:filter="filter"
binary-state-sort
@request="onRequest"
>
<template v-slot:top-left>
<q-input
dense
debounce="1000"
v-model.number="filter.lineId"
label="线路ID"
type="number"
/>
<q-btn flat round color="primary" icon="search" />
</template>
<template v-slot:top-right>
<q-input
dense
debounce="1000"
v-model="filter.alertType"
label="故障类型"
></q-input>
<q-btn flat round color="primary" icon="search" />
</template>
</q-table>
</draggable-dialog>
</template>
<script setup lang="ts">
import DraggableDialog from '../common/DraggableDialog.vue';
import { ref, reactive, onMounted } from 'vue';
import { useQuasar, type QTableColumn } from 'quasar';
import { alarmInfoListQuery } from 'src/api/AlertMock';
const $q = useQuasar();
const dialogWidth = window.screen.width * 0.5;
const dialogHeight = window.screen.height * 0.5;
onMounted(() => {
setTimeout(() => {
tableRef.value.requestServerInteraction();
});
});
const columnDefs: QTableColumn[] = [
{
name: 'id',
label: '编号',
field: 'id',
required: true,
align: 'center',
},
{
name: 'alertTime',
label: '时间',
field: 'alertTime',
align: 'center',
},
{
name: 'lineId',
label: '线路',
field: 'lineId',
align: 'center',
},
{
name: 'alertObject',
label: '设备',
field: 'alertObject',
align: 'center',
},
{
name: 'level',
label: '级别',
field: (row) => {
if (row.level) {
return (showAlertTypeData as never)[row.level + ''];
}
},
align: 'center',
},
{
name: 'alertType',
label: '故障类型',
field: (row) => {
if (row.alertType) {
return (showAlertTypeData as never)[row.alertType];
}
},
align: 'center',
},
];
const tableRef = ref();
const rows = reactive([]);
const filter = reactive({
alertType: '',
lineId: '',
});
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
async function onRequest(props: any) {
const { page, rowsPerPage, sortBy, descending } = props.pagination;
const filter = props.filter;
loading.value = true;
try {
let response = await alarmInfoListQuery({
current: page,
size: rowsPerPage,
alertType: (saveAlertTypeData as never)[filter.alertType],
lineId: filter.lineId,
});
const pageData = response;
pagination.value.rowsNumber = pageData.total;
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
pagination.value.sortBy = sortBy;
pagination.value.descending = descending;
rows.splice(0, rows.length, ...(pageData.records as []));
} catch (err) {
$q.notify({
type: 'negative',
message: '无法获取报警信息列表',
});
} finally {
loading.value = false;
}
}
enum showAlertTypeData {
ALERT_TYPE_UNKNOWN = '未知故障',
BLUE_DISPLAY = '蓝显',
TRAIN_DELAY_2 = '列车延误2分钟',
TRAIN_DELAY_10 = '列车延误10分钟',
PLATFORM_DOOR_WITHOUT_LOCKED_SIGNAL = '站台门无关闭且锁紧信号',
PLATFORM_DOOR_CANNOT_OPEN = '整侧站台门无法打开',
PLATFORM_DOOR_CANNOT_CLOSE = '整侧站台门无法关闭',
I = 'I类信息',
II = 'II类信息',
III = 'III类信息',
IV = 'IV类信息',
}
enum saveAlertTypeData {
列车延误2分钟 = 'TRAIN_DELAY_2',
列车延误10分钟 = 'TRAIN_DELAY_10',
蓝显 = 'BLUE_DISPLAY',
站台门无关闭且锁紧信号 = 'PLATFORM_DOOR_WITHOUT_LOCKED_SIGNAL',
整侧站台门无法打开 = 'PLATFORM_DOOR_CANNOT_OPEN',
整侧站台门无法关闭 = 'PLATFORM_DOOR_CANNOT_CLOSE',
}
</script>

View File

@ -0,0 +1,363 @@
<template>
<draggable-dialog
seamless
title="报警统计"
:width="dialogWidth"
:height="dialogHeight"
>
<q-table
ref="tableRef"
:style="{ height: dialogHeight + 'px' }"
:rows="rows"
:columns="columnDefs"
row-key="index"
v-model:pagination="pagination"
:rows-per-page-options="[0]"
:loading="loading"
:filter="filter"
binary-state-sort
virtual-scroll
>
<template v-slot:top>
<q-form ref="myForm" @submit="onRequest" style="width: 100%">
<div class="q-gutter-md row justify-center items-start">
<q-select
dense
v-model="filter.lineId"
:options="optionsLineId"
emit-value
map-options
options-dense
label="线路ID"
style="width: 100px"
/>
<q-input
dense
v-model="filter.beginDateTime"
label="开始时间"
no-error-icon
mask="####-##-## ##:##:##"
hint="例如2023-09-05 16:05:09"
lazy-rules
:rules="[timeRangeValidation]"
:error="errorBeginTime"
:error-message="errorMessageBeginTime"
>
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-date
v-model="filter.beginDateTime"
mask="YYYY-MM-DD HH:mm:ss"
landscape
>
<div class="row items-center justify-end">
<q-btn
v-close-popup
label="关闭"
color="primary"
flat
/>
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
<template v-slot:append>
<q-icon name="access_time" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-time
v-model="filter.beginDateTime"
mask="YYYY-MM-DD HH:mm:ss"
with-seconds
landscape
format24h
>
<div class="row items-center justify-end">
<q-btn
v-close-popup
label="关闭"
color="primary"
flat
/>
</div>
</q-time>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-input
dense
v-model="filter.endDateTime"
label="结束时间"
no-error-icon
mask="####-##-## ##:##:##"
hint="例如2023-09-05 16:05:09"
lazy-rules
:rules="[timeRangeValidation]"
:error="errorEndTime"
:error-message="errorMessageEndTime"
>
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-date
v-model="filter.endDateTime"
mask="YYYY-MM-DD HH:mm:ss"
landscape
>
<div class="row items-center justify-end">
<q-btn
v-close-popup
label="关闭"
color="primary"
flat
/>
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
<template v-slot:append>
<q-icon name="access_time" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-time
v-model="filter.endDateTime"
mask="YYYY-MM-DD HH:mm:ss"
with-seconds
landscape
format24h
>
<div class="row items-center justify-end">
<q-btn
v-close-popup
label="关闭"
color="primary"
flat
/>
</div>
</q-time>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-select
dense
v-model="filter.alertTypes"
:options="typeOptions"
multiple
emit-value
map-options
options-dense
class="ellipsis"
label="类型"
style="width: 200px"
/>
<q-select
dense
v-model="filter.alertStatus"
:options="alertStatusOptions"
emit-value
map-options
options-dense
label="处理状态"
style="width: 100px"
/>
<q-btn color="primary" label="查询" type="submit" />
</div>
</q-form>
</template>
<template v-slot:body-cell-index="props">
<q-td :props="props">
<span>{{ props.rowIndex + 1 }}</span>
</q-td>
</template>
</q-table>
</draggable-dialog>
</template>
<script setup lang="ts">
import DraggableDialog from '../common/DraggableDialog.vue';
import { ref, reactive, computed } from 'vue';
import { useQuasar, type QTableColumn, QForm, date } from 'quasar';
import { IReportParams, recordAlarmReport } from 'src/api/AlertMock';
import {
showAlertTypeData,
saveAlertTypeData,
alertStatusOptions,
} from './alarmInfoEnum';
defineProps<{
optionsLineId: { label: string; value: number }[];
}>();
const $q = useQuasar();
const dialogWidth = window.screen.width * 0.6;
const dialogHeight = window.screen.height * 0.5;
const columnDefs: QTableColumn[] = [
{
name: 'index',
label: '编号',
field: 'index',
align: 'center',
},
{
name: 'alertType',
label: '故障类型',
field: (row) => {
if (row.alertType) {
return (showAlertTypeData as never)[row.alertType];
}
},
align: 'center',
},
{
name: 'counter',
label: '数量',
field: 'counter',
align: 'center',
},
];
const typeOptions = computed(() => {
const list: { label: string; value: string }[] = [];
// list.push({ label: '', value: '' });
for (let i in saveAlertTypeData) {
const obj = {
label: i,
value: saveAlertTypeData[i as keyof typeof saveAlertTypeData],
};
list.push(obj);
}
return list;
});
interface Ifilter extends IReportParams {
lineId: number;
}
const rows = reactive([]);
const filter = reactive<Ifilter>({
alertTypes: [],
lineId: 3,
beginDateTime: '',
endDateTime: '',
alertStatus: 999,
});
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 0,
});
function onRequest() {
myForm.value?.validate().then(async (res) => {
if (res) {
loading.value = true;
try {
const params: IReportParams = {};
if (filter.alertTypes?.length) {
Object.assign(params, { alertTypes: filter.alertTypes });
}
if (filter.beginDateTime) {
Object.assign(params, { beginDateTime: filter.beginDateTime });
}
if (filter.endDateTime) {
Object.assign(params, { endDateTime: filter.endDateTime });
}
if (filter.alertStatus != 999) {
Object.assign(params, { alertStatus: filter.alertStatus });
}
const response = await recordAlarmReport(filter.lineId, params);
pagination.value.rowsNumber = response.length;
pagination.value.rowsPerPage = response.length;
rows.splice(0, rows.length, ...(response as []));
} catch (err) {
$q.notify({
type: 'negative',
message: '无法获取报警统计列表',
});
} finally {
loading.value = false;
}
}
});
}
const myForm = ref<QForm | null>(null);
const errorBeginTime = ref(false);
const errorEndTime = ref(false);
const errorMessageBeginTime = ref('');
const errorMessageEndTime = ref('');
function timeRangeValidation() {
const Reg = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
if (filter.beginDateTime) {
if (
!date.isValid(filter.beginDateTime) ||
!Reg.test(filter.beginDateTime)
) {
errorBeginTime.value = true;
errorMessageBeginTime.value = '请输入正确的时间!';
return false;
} else {
filter.beginDateTime = date.formatDate(
filter.beginDateTime,
'YYYY-MM-DD HH:mm:ss'
);
}
}
if (filter.endDateTime) {
if (!date.isValid(filter.endDateTime) || !Reg.test(filter.endDateTime)) {
errorEndTime.value = true;
errorMessageEndTime.value = '请输入正确的时间!';
return false;
} else {
filter.endDateTime = date.formatDate(
filter.endDateTime,
'YYYY-MM-DD HH:mm:ss'
);
}
}
if (
filter.beginDateTime &&
filter.endDateTime &&
new Date(filter.endDateTime).getTime() <
new Date(filter.beginDateTime).getTime()
) {
errorBeginTime.value = true;
errorEndTime.value = true;
errorMessageBeginTime.value = '开始时间不能大于结束时间!';
errorMessageEndTime.value = '结束时间不能小于开始时间!';
return false;
}
errorBeginTime.value = false;
errorEndTime.value = false;
errorMessageBeginTime.value = '';
errorMessageEndTime.value = '';
return true;
}
</script>

View File

@ -1,64 +1,202 @@
<template>
<div>
<audio ref="audio">
<source src="../../assets/buzzer.mp3" type="audio/mpeg" />
<source :src="audioSrc" type="audio/mpeg" />
</audio>
</div>
</template>
<script setup lang="ts">
import { watch, onUnmounted, ref, onMounted } from 'vue';
import { useLineNetStore } from 'src/stores/line-net-store';
import { useQuasar } from 'quasar';
import { watch, onUnmounted, ref, toRaw } from 'vue';
import { AlarmInfo, useLineNetStore } from 'src/stores/line-net-store';
import { DialogChainObject, useQuasar } from 'quasar';
import alarmInfoDialog from 'src/components/alarm/alarmInfoDialog.vue';
import { showAlertTypeData } from './alarmInfoEnum';
import allLineBlue from '/alarmMusic/all-line-blue.mp3';
import atpcut from '/alarmMusic/atp-cut.mp3';
import blue from '/alarmMusic/blue.mp3';
import cannotClose from '/alarmMusic/cannot-close.mp3';
import cannotOpen from '/alarmMusic/cannot-open.mp3';
import orangeMost from '/alarmMusic/orange-most.mp3';
import orange from '/alarmMusic/orange.mp3';
import redMost from '/alarmMusic/red-most.mp3';
import red from '/alarmMusic/red.mp3';
import switchLostMost from '/alarmMusic/switch-lost-most.mp3';
import switchLost from '/alarmMusic/switch-lost.mp3';
import buzzer from '/alarmMusic/buzzer.mp3';
const lineNetStore = useLineNetStore();
const audio = ref();
const audioSrc = ref('');
const $q = useQuasar();
const dialogInstance = ref();
const playAble = ref(false);
const watchInteract = () => {
playAble.value = true;
document.removeEventListener('click', watchInteract);
document.removeEventListener('keydown', watchInteract);
};
let waitShowDialog: AlarmInfo[] = [];
watch(
() => lineNetStore.alarmInfo,
(val) => {
if (val.length && audio.value.paused) {
playAlarmMusic();
if (val.length) {
UpdataAlarmInfoList();
const hasShow = countHasShowFiveDialog();
if (!hasShow) {
const alarmType = val[0].alert_type;
alarm(alarmType, val[0].id);
playAlarmMusic(alarmType);
} else {
waitShowDialog.push(toRaw(lineNetStore.alarmInfo[0]));
}
}
if (val.length && !lineNetStore.alarmDialog) {
alarm();
}
},
{ deep: true }
}
);
function playAlarmMusic() {
if (playAble.value) {
watch(
() => lineNetStore.closeAllAlarmInfoDialog,
(val) => {
if (val) {
lineNetStore.closeAllAlarmInfoDialog = false;
closeAllDialog();
}
}
);
function playAlarmMusic(type: number) {
for (let i = 0; i < dialogInstance.length; i++) {
if (dialogInstance[i].show == false) {
dialogInstance.splice(i, 1);
i--;
}
}
if (lineNetStore.playAble && audio.value.paused) {
const alarmType = (showAlertTypeData as never)[type + ''];
const mapAlarmMusic = new Map([
['蓝显', blue],
['全线蓝显', allLineBlue],
['整侧站台门无法打开', cannotOpen],
['整侧站台门无法关闭', cannotClose],
['道岔失表', switchLost],
['道岔大面积失表', switchLostMost],
['计轴红光带', red],
['计轴大面积红光带', redMost],
['计轴橙光带', orange],
['计轴大面积橙光带', orangeMost],
['列车信号故障', atpcut],
]);
const music = mapAlarmMusic.get(alarmType);
if (music !== undefined) {
audioSrc.value = music;
} else {
audioSrc.value = buzzer;
}
audio.value.src = audioSrc.value;
audio.value.play();
}
}
function alarm() {
lineNetStore.alarmDialog = true;
dialogInstance.value = $q
.dialog({ component: alarmInfoDialog })
.onCancel(() => {
lineNetStore.alarmDialog = false;
});
//3
function timingPlayAlarmMusic(dialog: DialogChainObject) {
const timerIndex = dialogInstance.findIndex((item) => item.dialog == dialog);
clearTimeout(dialogInstance[timerIndex].timer);
dialogInstance[timerIndex].timer = setTimeout(() => {
for (let i = 0; i < dialogInstance.length; i++) {
if (
dialogInstance[i].show &&
!dialogInstance[i].hasHandle &&
dialogInstance[i].dialog == dialog
) {
playAlarmMusic(dialogInstance[i].alarmType);
timingPlayAlarmMusic(dialog);
}
}
}, 180000);
}
onMounted(() => {
document.addEventListener('click', watchInteract);
document.addEventListener('keydown', watchInteract);
});
const dialogInstance: {
dialog: DialogChainObject;
show: boolean;
alarmType: number;
timer: string | number | NodeJS.Timeout | undefined;
id: string;
hasHandle: boolean;
}[] = [];
onUnmounted(() => {
if (dialogInstance.value && lineNetStore.alarmDialog) {
dialogInstance.value.hide();
function countHasShowFiveDialog(): boolean {
let hasShow = 0;
for (let i = 0; i < dialogInstance.length; i++) {
if (dialogInstance[i].show) {
hasShow++;
if (hasShow > 4) break;
}
}
return hasShow > 4 ? true : false;
}
function alarm(alarmType: number, id: string, waitAlarmMeaasge?: AlarmInfo) {
const dialogInstanceItem = $q
.dialog({
component: alarmInfoDialog,
componentProps: {
waitAlarmMeaasge: waitAlarmMeaasge,
onHandle: (id: string) => {
for (let i = 0; i < dialogInstance.length; i++) {
if (dialogInstance[i].id == id) {
dialogInstance[i].hasHandle = true;
break;
}
}
},
},
})
.onCancel(() => {
alarmWaitDialog();
const index = dialogInstance.findIndex(
(item) => item.dialog == dialogInstanceItem
);
dialogInstance[index].show = false;
});
let timer: string | number | NodeJS.Timeout | undefined = undefined;
dialogInstance.push({
dialog: dialogInstanceItem,
show: true,
alarmType,
timer,
hasHandle: false,
id,
});
timingPlayAlarmMusic(dialogInstanceItem);
}
function alarmWaitDialog() {
if (countHasShowFiveDialog() && waitShowDialog.length) {
alarm(
waitShowDialog[0].alert_type,
waitShowDialog[0].id,
waitShowDialog[0]
);
playAlarmMusic(waitShowDialog[0].alert_type);
waitShowDialog.shift();
}
}
function closeAllDialog() {
if (dialogInstance.length) {
dialogInstance.forEach((item) => {
clearTimeout(item.timer);
if (item.show) {
item.dialog.hide();
}
});
}
waitShowDialog = [];
}
let timeout: string | number | NodeJS.Timeout | undefined;
function UpdataAlarmInfoList() {
clearTimeout(timeout);
timeout = setTimeout(() => {
lineNetStore.alarmInfoListTable?.requestServerInteraction();
}, 1000);
}
onUnmounted(() => {
clearTimeout(timeout);
closeAllDialog();
});
</script>

View File

@ -0,0 +1,264 @@
<template>
<draggable-dialog
v-model="showsetAlartText"
seamless
title="设置故障演示"
:width="300"
:height="0"
>
<template v-slot:footer>
<div>
<q-card class="q-gutter-sm q-px-sm q-mt-sm">
<q-form ref="myForm" @submit="onSubmit" @reset="onReset">
<q-input
outlined
readonly
label="线路ID"
v-model.number="setAlartTextData.lineId"
type="number"
lazy-rules
:rules="[(val) => val || '请输入线路ID']"
/>
<q-select
outlined
label="故障类型"
v-model="setAlartTextData.alertType"
:options="optionsAlertType"
:rules="[(val) => val.length > 0 || '请选择故障类型!']"
/>
<q-list bordered separator class="rounded-borders">
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-item-label> 框选的设备 </q-item-label>
<div class="q-gutter-sm row">
<q-chip
v-for="item in setAlartTextData.deviceCodes"
:key="item"
square
color="primary"
text-color="white"
removable
@remove="removeSelect(item)"
>
{{ item }}
</q-chip>
</div>
<q-btn
v-show="setAlartTextData.deviceCodes.length > 0"
style="width: 120px"
label="清空框选的设备"
color="red"
@click="clearSelect"
/>
</q-item-section>
</q-item>
</q-list>
<div class="q-gutter-sm q-pa-md row justify-center">
<q-btn
label="提交"
type="submit"
color="primary"
class="q-mr-md"
/>
<q-btn label="重置" type="reset" color="primary" />
</div>
</q-form>
</q-card>
</div>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import DraggableDialog from '../common/DraggableDialog.vue';
import { onMounted, onUnmounted, ref, watch } from 'vue';
import { JlGraphic } from 'jl-graphic';
import { Station } from 'src/graphics/station/Station';
import { useLineStore } from 'src/stores/line-store';
import { QForm, useQuasar } from 'quasar';
import { ApiError } from 'src/boot/axios';
import { mockAlertSet } from 'src/api/AlertMock';
import { isArraysEqual, saveAlertTypeData } from './alarmInfoEnum';
import { Section, SectionType } from 'src/graphics/section/Section';
import { LogicSection } from 'src/graphics/logicSection/LogicSection';
const lineStore = useLineStore();
const setAlartTextData = ref<{
lineId: string;
alertType: string;
deviceCodes: string[];
}>({
lineId: '',
alertType: '',
deviceCodes: [],
});
const optionsAlertType = [
'蓝显',
'全线蓝显',
'整侧站台门无法打开',
'整侧站台门无法关闭',
'道岔失表',
'计轴红光带',
'计轴大面积红光带',
'计轴橙光带',
'计轴大面积橙光带',
'列车信号故障',
];
const mapAlertType = new Map([
['蓝显', ['station']],
['全线蓝显', ['station']],
['整侧站台门无法打开', ['Platform']],
['整侧站台门无法关闭', ['Platform']],
['道岔失表', ['Turnout']],
['计轴红光带', ['Section']],
['计轴大面积红光带', ['Section']],
['计轴橙光带', ['Section']],
['计轴大面积橙光带', ['Section']],
['列车信号故障', ['LogicSection', 'Turnout']],
]);
let selectGraphic: JlGraphic[] = [];
watch(
() => lineStore.selectedGraphics,
(val) => {
if (val && val.length > 0 && setAlartTextData.value.alertType) {
const selectGraphicId = selectGraphic.map((g) => g.id);
const appSelectedGraphicsId = lineStore.selectedGraphics?.map(
(g) => g.id
);
if (
appSelectedGraphicsId !== undefined &&
isArraysEqual(selectGraphicId, appSelectedGraphicsId)
) {
return;
}
const deviceFilter = lineStore.selectedGraphics?.filter((g) => {
let select = false;
if (
g.type == Station.Type &&
(g as Station).datas.concentrationStations &&
setAlartTextData.value.alertType == '蓝显'
) {
select = true;
}
if (
(g.type !== Station.Type &&
mapAlertType
.get(setAlartTextData.value.alertType)
?.includes(g.type)) ||
(g.type == Section.Type &&
(g as Section).datas.sectionType === SectionType.TurnoutPhysical &&
mapAlertType
.get(setAlartTextData.value.alertType)
?.includes(LogicSection.Type))
) {
select = true;
}
return select;
}) as JlGraphic[];
if (
[
'道岔失表',
'计轴红光带',
'计轴橙光带',
'列车信号故障',
'整侧站台门无法打开',
'整侧站台门无法关闭',
].includes(setAlartTextData.value.alertType)
) {
if (deviceFilter[0] !== undefined) {
selectGraphic = [deviceFilter[0]];
}
} else {
selectGraphic.push(...deviceFilter);
}
selectGraphic = Array.from(new Set(selectGraphic));
lineStore.getLineApp().updateSelected(...selectGraphic);
setAlartTextData.value.deviceCodes = selectGraphic.map((g) => g.code);
}
}
);
onMounted(() => {
lineStore.getLineApp().emit('options-update', {
mouseToolOptions: {
boxSelect: true,
viewportDrag: true,
viewportDragLeft: false,
wheelZoom: true,
},
});
clearSelect();
onReset();
setAlartTextData.value.lineId = lineStore.lineId as unknown as string;
});
const myForm = ref<QForm | null>(null);
const showsetAlartText = ref(true);
const $q = useQuasar();
async function onSubmit() {
myForm.value?.validate().then(async (res) => {
if (res) {
try {
const params = {
lineId: +setAlartTextData.value.lineId,
alertType: (saveAlertTypeData as never)[
setAlartTextData.value.alertType + ''
],
deviceCodes: setAlartTextData.value.deviceCodes,
};
await mockAlertSet(params);
$q.notify({
type: 'positive',
message: '设置故障演示成功',
});
onReset();
} catch (err) {
const apiErr = err as ApiError;
$q.notify({
type: 'negative',
message: apiErr.title,
});
} finally {
showsetAlartText.value = false;
}
}
});
}
function removeSelect(code: string) {
const removeIndex = setAlartTextData.value.deviceCodes.findIndex(
(item) => item == code
);
selectGraphic.splice(removeIndex, 1);
setAlartTextData.value.deviceCodes.splice(removeIndex, 1);
lineStore.getLineApp().updateSelected(...selectGraphic);
}
function clearSelect() {
setAlartTextData.value.deviceCodes = [];
selectGraphic = [];
lineStore.getLineApp().updateSelected();
}
function onReset() {
setAlartTextData.value = {
lineId: lineStore.lineId as unknown as string,
alertType: '',
deviceCodes: [],
};
selectGraphic = [];
}
onUnmounted(() => {
lineStore.getLineApp().emit('options-update', {
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
viewportDragLeft: true,
wheelZoom: true,
},
});
});
</script>

View File

@ -0,0 +1,408 @@
<template>
<draggable-dialog
v-model="showsetAlartText"
seamless
title="设置故障测试"
:width="300"
:height="0"
>
<template v-slot:footer>
<div>
<q-card class="q-gutter-sm q-px-sm q-mt-sm">
<q-form ref="myForm" @submit="onSubmit" @reset="onReset">
<q-input
outlined
readonly
label="线路ID"
v-model.number="setAlartTextData.lineId"
type="number"
lazy-rules
:rules="[(val) => val || '请输入线路ID']"
/>
<q-select
outlined
label="故障类型"
v-model="setAlartTextData.alertType"
:options="optionsAlertType"
:rules="[(val) => val.length > 0 || '请选择故障类型!']"
@update:model-value="onChooseAlertType"
/>
<q-list bordered separator class="rounded-borders">
<q-expansion-item
bordered
expand-separator
v-for="(configItem, index) in setAlartTextData.groupList"
:key="configItem"
v-model="configItem.expanded"
:label="configItem.groupName"
@click="toggleItem(index)"
>
<q-card>
<q-item no-wrap class="column">
<q-input
v-if="setAlartTextData.alertType == '列车信号故障'"
outlined
label="车组号"
v-model="configItem.groupId"
lazy-rules
:rules="[(val) => val.length > 0 || '请输入车组号!']"
/>
<q-select
outlined
label="故障测试状态"
v-model="configItem.status"
:options="optionsStatus"
:rules="[(val) => val.length > 0 || '请选择故障类型!']"
map-options
emit-value
/>
<div class="q-gutter-sm row">
<q-chip
v-for="(item, selectIndex) in configItem.deviceInfos"
:key="item"
square
color="primary"
text-color="white"
removable
@remove="removeSelect(selectIndex)"
clickable
@click="clickSelectCenter(selectIndex)"
>
{{ item.deviceName }}
</q-chip>
</div>
<div>
<q-btn
v-show="configItem.deviceInfos.length > 0"
style="width: 100px"
label="清空选择"
color="red"
class="q-mr-md"
@click="clearAllSelect(index)"
/>
<q-btn
v-if="setAlartTextData.alertType == '列车信号故障'"
label="删除测试组"
color="secondary"
@click="deleteSelectConfig(index)"
/>
</div>
</q-item>
</q-card>
</q-expansion-item>
</q-list>
<q-btn
v-if="setAlartTextData.alertType == '列车信号故障'"
class="q-mt-md"
label="增加测试组"
color="secondary"
@click="addSelectConfig"
/>
<div class="q-gutter-sm q-pa-md row justify-center">
<q-btn
label="提交"
type="submit"
color="primary"
class="q-mr-md"
/>
<q-btn label="重置" type="reset" color="primary" />
</div>
</q-form>
</q-card>
</div>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import DraggableDialog from '../common/DraggableDialog.vue';
import { onMounted, onUnmounted, ref, watch } from 'vue';
import { JlGraphic } from 'jl-graphic';
import { Station } from 'src/graphics/station/Station';
import { useLineStore } from 'src/stores/line-store';
import { QForm, useQuasar } from 'quasar';
import { ApiError } from 'src/boot/axios';
import { mockLocalDemoTestSet } from 'src/api/AlertMock';
import { isArraysEqual, saveAlertTypeData } from './alarmInfoEnum';
const lineStore = useLineStore();
const setAlartTextData = ref<{
lineId: string;
alertType: string;
groupList: {
groupName: string;
groupId?: string;
status: string;
deviceInfos: {
deviceName: string;
deviceType: string;
}[];
expanded: boolean;
}[];
}>({
lineId: '',
alertType: '',
groupList: [
{
groupName: '测试组',
groupId: '',
status: '',
deviceInfos: [],
expanded: false,
},
],
});
const optionsAlertType = [
'蓝显',
'道岔失表',
'计轴红光带',
'计轴橙光带',
'列车信号故障',
];
const mapAlertType = new Map([
['蓝显', ['station']],
['道岔失表', ['Turnout']],
['计轴红光带', ['LogicSection', 'Turnout']],
['计轴橙光带', ['LogicSection', 'Turnout']],
['列车信号故障', ['LogicSection', 'Turnout']],
]);
enum DeviceType {
station = 'DEVICE_TYPE_RTU',
Turnout = 'DEVICE_TYPE_SWITCH',
LogicSection = 'DEVICE_TYPE_TRACK',
}
const optionsStatus = [
{ label: '正常', value: 'NORMAL' },
{ label: '设置', value: 'BEGIN' },
{ label: '报警', value: 'ALERT' },
];
let selectGraphic: JlGraphic[] = [];
watch(
() => lineStore.selectedGraphics,
(val) => {
if (
val &&
val.length > 0 &&
setAlartTextData.value.alertType &&
clickIndex !== null
) {
const selectGraphicId = selectGraphic.map((g) => g.id);
const appSelectedGraphicsId = lineStore.selectedGraphics?.map(
(g) => g.id
);
if (
appSelectedGraphicsId !== undefined &&
isArraysEqual(selectGraphicId, appSelectedGraphicsId)
) {
return;
}
const deviceFilter = lineStore.selectedGraphics?.filter((g) => {
let select = false;
if (
g.type == Station.Type &&
(g as Station).datas.concentrationStations &&
setAlartTextData.value.alertType == '蓝显'
) {
select = true;
}
if (
g.type !== Station.Type &&
mapAlertType.get(setAlartTextData.value.alertType)?.includes(g.type)
) {
select = true;
}
return select;
}) as JlGraphic[];
if (setAlartTextData.value.alertType !== '列车信号故障') {
selectGraphic.push(...deviceFilter);
} else if (deviceFilter.length) {
selectGraphic = [deviceFilter[0]];
}
selectGraphic = Array.from(new Set(selectGraphic));
lineStore.getLineApp().updateSelected(...selectGraphic);
setAlartTextData.value.groupList[clickIndex].deviceInfos = [];
selectGraphic.forEach((g) => {
setAlartTextData.value.groupList[clickIndex as number].deviceInfos.push(
{
deviceName: g.code,
deviceType: (DeviceType as never)[g.type + ''],
}
);
});
}
}
);
onMounted(() => {
lineStore.getLineApp().emit('options-update', {
mouseToolOptions: {
boxSelect: true,
viewportDrag: true,
viewportDragLeft: false,
wheelZoom: true,
},
});
onReset();
setAlartTextData.value.lineId = lineStore.lineId as unknown as string;
});
const myForm = ref<QForm | null>(null);
const showsetAlartText = ref(true);
const $q = useQuasar();
async function onSubmit() {
myForm.value?.validate().then(async (res) => {
if (res) {
const deviceInfos = setAlartTextData.value.groupList
.map((group) => {
const deviceInfo = group.deviceInfos.map((deviceInfo) => {
const status = group.status;
const groupId = group.groupId || '';
return {
deviceName: deviceInfo.deviceName,
deviceType: deviceInfo.deviceType,
status,
groupId,
};
});
return deviceInfo;
})
.flat();
try {
const params = {
lineId: +setAlartTextData.value.lineId,
deviceInfos,
};
const alertType = (saveAlertTypeData as never)[
setAlartTextData.value.alertType + ''
];
await mockLocalDemoTestSet(alertType, params);
$q.notify({
type: 'positive',
message: '设置故障测试成功',
});
onReset();
} catch (err) {
const apiErr = err as ApiError;
$q.notify({
type: 'negative',
message: apiErr.title,
});
} finally {
showsetAlartText.value = false;
}
}
});
}
let clickIndex: null | number = null;
function toggleItem(index: number) {
const lineApp = lineStore.getLineApp();
selectGraphic = [];
lineApp.updateSelected();
if (setAlartTextData.value.groupList[index].expanded == true) {
clickIndex = index;
const select: JlGraphic[] = [];
setAlartTextData.value.groupList[index].deviceInfos.forEach(
(deviceInfo) => {
const deviceType = (
Object.keys(DeviceType) as Array<keyof typeof DeviceType>
).find((key) => DeviceType[key] === deviceInfo.deviceType) as string;
const g = lineApp.queryStore.queryByCodeAndType(
deviceInfo.deviceName,
deviceType
) as JlGraphic;
select.push(g);
}
);
lineApp.updateSelected(...select);
} else {
clickIndex = null;
}
}
function clickSelectCenter(index: number) {
const lineApp = lineStore.getLineApp();
const clickTarget = setAlartTextData.value.groupList[clickIndex as number];
const deviceType = (
Object.keys(DeviceType) as Array<keyof typeof DeviceType>
).find(
(key) => DeviceType[key] === clickTarget.deviceInfos[index].deviceType
) as string;
const clickGraphic = lineApp.queryStore.queryByCodeAndType(
clickTarget.deviceInfos[index].deviceName,
deviceType
) as JlGraphic;
lineApp.makeGraphicCenterShow(clickGraphic);
}
function removeSelect(removeIndex: number) {
const clickTarget = setAlartTextData.value.groupList[clickIndex as number];
selectGraphic.splice(removeIndex, 1);
clickTarget.deviceInfos.splice(removeIndex, 1);
lineStore.getLineApp().updateSelected(...selectGraphic);
}
function clearAllSelect(index: number) {
setAlartTextData.value.groupList[index].deviceInfos = [];
selectGraphic = [];
lineStore.getLineApp().updateSelected();
}
function addSelectConfig() {
setAlartTextData.value.groupList.push({
groupName: '测试组',
groupId: '',
status: '',
deviceInfos: [],
expanded: false,
});
}
function deleteSelectConfig(index: number) {
setAlartTextData.value.groupList.splice(index, 1);
selectGraphic = [];
lineStore.getLineApp().updateSelected();
}
function onChooseAlertType() {
setAlartTextData.value.groupList = [
{
groupName: '测试组',
groupId: '',
status: '',
deviceInfos: [],
expanded: false,
},
];
}
function onReset() {
setAlartTextData.value = {
lineId: lineStore.lineId as unknown as string,
alertType: '',
groupList: [
{
groupName: '测试组',
groupId: '',
status: '',
deviceInfos: [],
expanded: false,
},
],
};
selectGraphic = [];
}
onUnmounted(() => {
lineStore.getLineApp().emit('options-update', {
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
viewportDragLeft: true,
wheelZoom: true,
},
});
});
</script>

View File

@ -1,8 +1,60 @@
<template>
<q-dialog
ref="dialogRef"
@hide="onHide"
v-bind="$attrs"
@show="emit('show')"
transitionShow="jump-up"
transitionHide="jump-down"
class="column"
>
<q-card
:style="{
transform: `translate3d(${offset.x}px, ${offset.y}px, 1px)`,
background: `${props.bgColor}`,
border: `${props.bgBorder}`,
}"
style="max-width: 2000px"
>
<q-bar
ref="headerRef"
class="non-selectable q-gutter-l"
style="
cursor: move;
border-top-right-radius: 0;
border-top-left-radius: 0;
"
:style="`height: ${props.titleHeight}px;background: ${props.titleColor}`"
>
<div
:style="`height: 100%; line-height: ${props.titleHeight}px; color:${props.fontColor};font-size: ${props.fontSize}px;`"
>
{{ props.title }}
</div>
<q-space />
<div style="margin-right: 10px"><slot name="titleButton"></slot></div>
<q-btn dense flat icon="sym_o_close" v-close-popup></q-btn>
</q-bar>
<q-scroll-area
:style="`width: ${props.width}px; height: ${props.height}px;`"
>
<slot></slot>
</q-scroll-area>
<div :style="`width: ${props.width}px`">
<slot name="footer"></slot>
</div>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import { QBar, useDialogPluginComponent } from 'quasar';
import { ref, onMounted, onUnmounted, reactive, withDefaults } from 'vue';
import { ref, onMounted, onUnmounted, reactive } from 'vue';
const emit = defineEmits([...useDialogPluginComponent.emits]);
const emit = defineEmits({
...useDialogPluginComponent.emitsObject,
show: () => true,
});
const props = withDefaults(
defineProps<{
@ -14,6 +66,7 @@ const props = withDefaults(
width?: number;
height?: number;
bgColor?: string;
bgBorder?: string;
}>(),
{
width: 500,
@ -36,6 +89,7 @@ const offset = reactive({
});
const start = { x: 0, y: 0 };
const startOffset = { x: 0, y: 0 };
onMounted(() => {
window.addEventListener('mousedown', onMouseDown);
@ -46,16 +100,24 @@ onUnmounted(() => {
});
function onMove(e: MouseEvent) {
[offset.x, offset.y] = [e.screenX - start.x, e.screenY - start.y];
let y = e.clientY > startOffset.y ? e.clientY : startOffset.y;
if (y > window.innerHeight - props.titleHeight + startOffset.y) {
y = window.innerHeight - props.titleHeight + startOffset.y;
}
[offset.x, offset.y] = [e.clientX - start.x, y - start.y];
}
function onMouseUp() {
window.removeEventListener('mousemove', onMove);
window.removeEventListener('mouseup', onMouseUp);
startOffset.x = 0;
startOffset.y = 0;
}
function onMouseDown(e: MouseEvent) {
if (headerRef.value?.$el !== e.target) return;
start.x = e.screenX - offset.x;
start.y = e.screenY - offset.y;
if (!e.target || !headerRef.value?.$el.contains(e.target)) return;
startOffset.x = e.offsetX;
startOffset.y = e.offsetY;
start.x = e.clientX - offset.x;
start.y = e.clientY - offset.y;
window.addEventListener('mousemove', onMove);
window.addEventListener('mouseup', onMouseUp);
}
@ -64,45 +126,3 @@ function onHide() {
onDialogHide();
}
</script>
<template>
<q-dialog
ref="dialogRef"
@hide="onHide"
v-bind="$attrs"
transitionShow="jump-up"
transitionHide="jump-down"
class="column"
>
<q-card
:style="{
transform: `translate3d(${offset.x}px, ${offset.y}px, 1px)`,
background: `${props.bgColor}`,
}"
style="max-width: 2000px"
>
<q-bar
ref="headerRef"
class="non-selectable q-gutter-l"
style="cursor: move"
:style="`height: ${props.titleHeight}px;background: ${props.titleColor}`"
>
<div
:style="`color:${props.fontColor};font-size: ${props.fontSize}px;`"
>
{{ props.title }}
</div>
<q-space />
<q-btn dense flat icon="sym_o_close" v-close-popup></q-btn>
</q-bar>
<q-scroll-area
:style="`width: ${props.width}px; height: ${props.height}px;`"
>
<slot></slot>
</q-scroll-area>
<div :style="`width: ${props.width}px`">
<slot name="footer"></slot>
</div>
</q-card>
</q-dialog>
</template>

View File

@ -19,9 +19,6 @@
<template v-if="drawStore.drawGraphicType === Station.Type">
<station-template></station-template>
</template>
<!-- <template v-if="drawStore.drawGraphicType === Train.Type">
<train-template></train-template>
</template> -->
</q-card-section>
</q-card>
</div>
@ -54,9 +51,6 @@
<station-line-property
v-if="drawStore.selectedGraphicType === StationLine.Type"
></station-line-property>
<!-- <train-property
v-if="drawStore.selectedGraphicType === Train.Type"
></train-property> -->
<iscs-fan-property
v-else-if="drawStore.selectedGraphicType === IscsFan.Type"
></iscs-fan-property>
@ -87,6 +81,11 @@
<LogicSectionProperty
v-else-if="drawStore.selectedGraphicType === LogicSection.Type"
/>
<concentrationDividingLine-property
v-else-if="
drawStore.selectedGraphicType === ConcentrationDividingLine.Type
"
/>
</q-card-section>
</template>
</q-card>
@ -96,6 +95,8 @@
<script setup lang="ts">
import LinkTemplate from './templates/LinkTemplate.vue';
import RectTemplate from './templates/RectTemplate.vue';
import ConcentrationDividingLineProperty from './properties/ConcentrationDividingLineProperty.vue';
import { ConcentrationDividingLine } from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
import PlatformTemplate from './templates/PlatformTemplate.vue';
import StationTemplate from './templates/StationTemplate.vue';
// import TrainTemplate from './templates/TrainTemplate.vue';

View File

@ -0,0 +1,64 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<q-dialog ref="dialogRef" style="width 800px;">
<q-card
style="max-width: 900px"
:style="{ width: `${80 * props.runLinePoints.length}px` }"
>
<q-card-section> <div class="text-h6">划定端点</div> </q-card-section>
<q-card-section class="q-pt-none">
<q-range
class="q-mt-xl"
v-model="model"
color="purple"
style="padding: 0px 30px; font-size: 10px"
markers
:marker-labels="objMarkerLabel"
:min="0"
:max="props.runLinePoints.length - 1"
/>
</q-card-section>
<q-card-actions align="right" class="text-primary">
<q-btn flat label="取消" @click="onDialogCancel" v-close-popup />
<q-btn flat label="确认" @click="onDialogOK(model)" v-close-popup />
</q-card-actions>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import { IPointData } from 'pixi.js';
import { useDialogPluginComponent } from 'quasar';
import { ref, onMounted } from 'vue';
const props = defineProps({
runLinePoints: {
type: Array<IPointData>,
required: true,
},
garyPointIndexs: {
type: Array<number>,
required: true,
},
});
const objMarkerLabel = (val: number) =>
`P${val}[${props.runLinePoints[val].x},${props.runLinePoints[val].y}]`;
const model = ref({
min: 0,
max: 0,
});
onMounted(() => {
if (props.garyPointIndexs.length) {
model.value = {
min: props.garyPointIndexs[0],
max: props.garyPointIndexs[props.garyPointIndexs.length - 1],
};
}
});
defineEmits([...useDialogPluginComponent.emits]);
const { dialogRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
</script>
<style scoped></style>

View File

@ -1,12 +1,6 @@
<template>
<q-form class="q-gutter-sm">
<q-input
outlined
readonly
v-model="axleCountingModel.id"
label="id"
hint=""
/>
<q-input outlined readonly v-model="axleCountingModel.id" label="id" />
<q-input
outlined
label="计轴名称"
@ -16,24 +10,29 @@
lazy-rules
autogrow
/>
<q-select
outlined
style="margin-top: 10px"
v-model="kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
<q-list bordered separator class="rounded-borders">
<q-item no-wrap class="q-gutter-y-sm column">
<div>公里标配置</div>
<q-select
outlined
style="margin-top: 10px"
v-model="axleCountingModel.kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="axleCountingModel.kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
</q-item>
</q-list>
<q-list bordered separator class="rounded-borders">
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
@ -72,17 +71,19 @@
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { AxleCountingData } from 'src/drawApp/graphics/AxleCountingInteraction';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { Section } from 'src/graphics/section/Section';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, onMounted, reactive, watch } from 'vue';
import { computed } from 'vue';
const drawStore = useDrawStore();
const axleCountingModel = reactive(new AxleCountingData());
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const { data: axleCountingModel, onUpdate } = useFormData(
new AxleCountingData(),
drawStore.getDrawApp()
);
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
{ label: '停车场', value: 'PARKING_LOT' },
@ -90,46 +91,6 @@ const CoordinateSystemOptions = [
{ label: '换线', value: 'TRANSFER' },
];
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == AxleCounting.Type) {
axleCountingModel.copyFrom(val.saveData() as AxleCountingData);
if (axleCountingModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
axleCountingModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = axleCountingModel.kilometerSystem.kilometer;
}
}
}
);
onMounted(() => {
const axleCounting = drawStore.selectedGraphic as AxleCounting;
if (axleCounting) {
axleCountingModel.copyFrom(axleCounting.saveData());
if (axleCountingModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
axleCountingModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = axleCountingModel.kilometerSystem.kilometer;
}
}
});
function onUpdate() {
const axleCounting = drawStore.selectedGraphic as AxleCounting;
axleCountingModel.kilometerSystem = {
coordinateSystem: kilometerSystem.coordinateSystem,
kilometer: kilometerSystem.kilometer,
};
if (axleCounting) {
drawStore
.getDrawApp()
.updateGraphicAndRecord(axleCounting, axleCountingModel);
}
}
const sectionRelations = computed(() => {
const axleCounting = drawStore.selectedGraphic as AxleCounting;
const sectionRelations =

View File

@ -0,0 +1,126 @@
<template>
<q-form class="q-gutter-sm">
<q-input
outlined
readonly
v-model="concentrationDividingLineModel.id"
label="id"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="concentrationDividingLineModel.refLeftStationId"
:options="centralizedStations"
emitValue
mapOptions
@update:model-value="onUpdate"
label="左边关联的集中站"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="concentrationDividingLineModel.refRightStationId"
:options="centralizedStations"
emitValue
mapOptions
@update:model-value="onUpdate"
label="右边关联的集中站"
/>
<q-toggle
v-model="
concentrationDividingLineModel.isOtherLineConcentrationDividingLine
"
label="是否与其它线的边界处"
emit-value
@update:model-value="onUpdate"
/>
<q-list bordered separator class="rounded-borders">
<q-item
v-for="sectionRelation in sectionRelations"
:key="sectionRelation.label"
>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-item-label> {{ sectionRelation.label }} </q-item-label>
<div class="q-gutter-sm row">
<q-chip
v-for="(item, index) in sectionRelation.refSectionInfo"
:key="index"
square
color="primary"
text-color="white"
>
{{ item }}
</q-chip>
</div>
</q-item-section>
</q-item>
</q-list>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { ConcentrationDividingLineData } from 'src/drawApp/graphics/ConcentrationDividingLineInteraction';
import { ConcentrationDividingLine } from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
import { Section } from 'src/graphics/section/Section';
import { Station } from 'src/graphics/station/Station';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const { data: concentrationDividingLineModel, onUpdate } = useFormData(
new ConcentrationDividingLineData(),
drawStore.getDrawApp()
);
const centralizedStations = ref<{ label: string; value: number }[]>([]);
const sectionRelations = computed(() => {
const refSectionInfo: { label: string; refSectionInfo: string[] }[] = [
{ label: '左边关联的设备', refSectionInfo: [] },
{ label: '右边关联的设备', refSectionInfo: [] },
];
enum devicePort {
'A',
'B',
'C',
}
const concentrationDividingLine =
drawStore.selectedGraphic as ConcentrationDividingLine;
concentrationDividingLine.datas.nodeConWithSecs.forEach((nodeConWithSec) => {
const refleftSection = nodeConWithSec.leftSection?.id
? `${
drawStore
.getDrawApp()
.queryStore.queryById<Section>(nodeConWithSec.leftSection.id).datas
.code
}(${devicePort[nodeConWithSec.leftSection.devicePort]})`
: '边界';
refSectionInfo[0].refSectionInfo.push(refleftSection);
const refRightSection = nodeConWithSec.rightSection?.id
? `${
drawStore
.getDrawApp()
.queryStore.queryById<Section>(nodeConWithSec.rightSection.id).datas
.code
}(${devicePort[nodeConWithSec.rightSection.devicePort]})`
: '边界';
refSectionInfo[1].refSectionInfo.push(refRightSection);
});
return refSectionInfo;
});
onMounted(() => {
const stations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type);
centralizedStations.value = [{ label: '', value: 0 }];
stations.forEach((station) => {
if (station.datas.concentrationStations || station.datas.depots) {
centralizedStations.value.push({
label: station.datas.name,
value: station.datas.id,
});
}
});
});
</script>

View File

@ -59,38 +59,13 @@
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { LinkData } from 'src/drawApp/graphics/LinkInteraction';
import { Link } from 'src/graphics/link/Link';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const linkModel = reactive(new LinkData());
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Link.Type) {
// console.log('link');
linkModel.copyFrom(val.saveData() as LinkData);
}
}
const { data: linkModel, onUpdate } = useFormData(
new LinkData(),
drawStore.getDrawApp()
);
onMounted(() => {
// console.log('link mounted');
const link = drawStore.selectedGraphic as Link;
if (link) {
linkModel.copyFrom(link.saveData());
}
});
function onUpdate() {
console.log('link 属性更新');
const link = drawStore.selectedGraphic as Link;
if (link) {
drawStore.getDrawApp().updateGraphicAndRecord(link, linkModel);
}
}
</script>

View File

@ -1,10 +1,15 @@
<template>
<q-form>
<q-input outlined readonly v-model="sectionModel.id" label="id" hint="" />
<q-input
outlined
readonly
v-model="sectionModel.code"
v-model="logicSectionModel.id"
label="id"
hint=""
/>
<q-input
outlined
v-model="logicSectionModel.code"
@blur="onUpdate"
label="编号"
/>
@ -12,26 +17,13 @@
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { LogicSectionData } from 'src/drawApp/graphics/LogicSectionInteraction';
import { LogicSection } from 'src/graphics/logicSection/LogicSection';
import { useDrawStore } from 'src/stores/draw-store';
import { shallowRef, watchEffect } from 'vue';
const drawStore = useDrawStore();
const sectionModel = shallowRef(new LogicSectionData());
watchEffect(() => {
const section = drawStore.selectedGraphic;
if (section && section instanceof LogicSection) {
sectionModel.value = section.saveData();
}
});
const onUpdate = () => {
const section = drawStore.selectedGraphic as LogicSection;
if (section) {
drawStore.getDrawApp().updateGraphicAndRecord(section, sectionModel.value);
}
};
const { data: logicSectionModel, onUpdate } = useFormData(
new LogicSectionData(),
drawStore.getDrawApp()
);
</script>

View File

@ -52,24 +52,17 @@
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { PathLineData } from 'src/drawApp/graphics/PathLineInteraction';
import { PathLine } from 'src/graphics/pathLine/PathLine';
import { useDrawStore } from 'src/stores/draw-store';
import { reactive, onMounted, watch } from 'vue';
import { reactive, onMounted } from 'vue';
import { getLineList } from 'src/api/LineInfoApi';
const drawStore = useDrawStore();
const pathLineModel = reactive(new PathLineData());
const lineList: { label: string; value: string }[] = reactive([]);
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == PathLine.Type) {
pathLineModel.copyFrom(val.saveData() as PathLineData);
}
}
const { data: pathLineModel, onUpdate } = useFormData(
new PathLineData(),
drawStore.getDrawApp()
);
const lineList: { label: string; value: string }[] = reactive([]);
onMounted(() => {
getLineList()
@ -81,16 +74,5 @@ onMounted(() => {
.catch((err) => {
console.error('获取线路列表失败:' + err.message);
});
const pathLine = drawStore.selectedGraphic as PathLine;
if (pathLine) {
pathLineModel.copyFrom(pathLine.saveData());
}
});
function onUpdate() {
const pathLine = drawStore.selectedGraphic as PathLine;
if (pathLine) {
drawStore.getDrawApp().updateGraphicAndRecord(pathLine, pathLineModel);
}
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="platformModel.id" label="id" hint="" />
<q-input outlined readonly v-model="platformModel.id" label="id" />
<q-input
outlined
label="站台名称"
@ -10,26 +10,30 @@
lazy-rules
autogrow
/>
<q-select
outlined
@blur="onUpdate"
v-model="hasDoor"
:options="optionsDoor"
<q-toggle
v-model="platformModel.hasdoor"
label="是否有屏蔽门"
emit-value
@update:model-value="onUpdate"
/>
<q-select
v-if="platformModel.hasdoor"
outlined
@blur="onUpdate"
v-model="direction"
v-model="platformModel.direction"
:options="optionsDirection"
label="方向"
map-options
emit-value
/>
<q-select
outlined
@blur="onUpdate"
v-model="upAndDown"
v-model="platformModel.up"
:options="optionsUpAndDown"
label="上下行"
map-options
emit-value
/>
<q-list bordered separator class="rounded-borders">
<q-item>
@ -42,89 +46,85 @@
</div>
</q-item-section>
</q-item>
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-item-label> 关联的物理区段 </q-item-label>
<div class="q-gutter-sm row">
<q-chip square color="primary" text-color="white">
{{ sectionName }}
</q-chip>
</div>
</q-item-section>
</q-item>
</q-list>
<q-select
outlined
v-model="platformModel.centralizedStation"
:options="centralizedStations"
emitValue
mapOptions
@update:model-value="onUpdate"
label="关联的集中站"
/>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { PlatformData } from 'src/drawApp/graphics/PlatformInteraction';
import { Platform } from 'src/graphics/platform/Platform';
import { Section } from 'src/graphics/section/Section';
import { Station } from 'src/graphics/station/Station';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref, watch } from 'vue';
import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const platformModel = reactive(new PlatformData());
const hasDoor = ref('是');
const optionsDoor = ['是', '否'];
const direction = ref('向上');
const upAndDown = ref('');
const optionsDirection = ['向上', '向下'];
const optionsUpAndDown = ['上行', '下行'];
const stationName = ref('');
enum showSelect {
= 'true',
= 'false',
向上 = 'up',
向下 = 'down',
}
enum showUp {
上行 = 'true',
下行 = 'false',
}
enum showSelectData {
true = '是',
false = '否',
up = '向上',
down = '向下',
}
enum showUpData {
true = '上行',
false = '下行',
}
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Platform.Type) {
platformModel.copyFrom(val.saveData() as PlatformData);
hasDoor.value = (showSelectData as never)[platformModel.hasdoor + ''];
direction.value = (showSelectData as never)[platformModel.direction];
upAndDown.value = (showUpData as never)[platformModel.up + ''];
if (platformModel.refStation) {
const refStation = val.queryStore.queryById<Station>(
platformModel.refStation
) as Station;
stationName.value = refStation.datas.name;
}
}
}
const { data: platformModel, onUpdate } = useFormData(
new PlatformData(),
drawStore.getDrawApp()
);
const stationName = computed(() => {
const platform = drawStore.selectedGraphic as Platform;
if (platformModel.refStation) {
const refStation = platform.queryStore.queryById<Station>(
platformModel.refStation
);
return refStation.datas.name;
}
return '';
});
const sectionName = computed(() => {
const platform = drawStore.selectedGraphic as Platform;
if (platformModel.refSectionId) {
const refSection = platform.queryStore.queryById<Section>(
platformModel.refSectionId
);
return refSection.datas.code;
}
return '';
});
const optionsDirection = [
{ label: '向上', value: 'up' },
{ label: '向下', value: 'down' },
];
const optionsUpAndDown = [
{ label: '上行', value: true },
{ label: '下行', value: false },
];
const centralizedStations = ref<{ label: string; value: number }[]>([]);
onMounted(() => {
const platform = drawStore.selectedGraphic as Platform;
if (platform) {
platformModel.copyFrom(platform.saveData());
hasDoor.value = (showSelectData as never)[platformModel.hasdoor + ''];
direction.value = (showSelectData as never)[platformModel.direction];
upAndDown.value = (showUpData as never)[platformModel.up + ''];
if (platformModel.refStation) {
const refStation = platform.queryStore.queryById<Station>(
platformModel.refStation
) as Station;
stationName.value = refStation.datas.name;
const stations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type);
centralizedStations.value = [{ label: '', value: 0 }];
stations.forEach((station) => {
if (station.datas.concentrationStations || station.datas.depots) {
centralizedStations.value.push({
label: station.datas.name,
value: station.datas.id,
});
}
}
});
});
function onUpdate() {
platformModel.hasdoor = JSON.parse((showSelect as never)[hasDoor.value]);
platformModel.direction = (showSelect as never)[direction.value];
platformModel.up = JSON.parse((showUp as never)[upAndDown.value]);
const platform = drawStore.selectedGraphic as Platform;
if (platform) {
drawStore.getDrawApp().updateGraphicAndRecord(platform, platformModel);
}
}
</script>

View File

@ -66,35 +66,13 @@
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { RectData } from 'src/drawApp/graphics/RectInteraction';
import { Rect } from 'src/graphics/rect/Rect';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const rectModel = reactive(new RectData());
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Rect.Type) {
rectModel.copyFrom(val.saveData() as RectData);
}
}
const { data: rectModel, onUpdate } = useFormData(
new RectData(),
drawStore.getDrawApp()
);
onMounted(() => {
const Rect = drawStore.selectedGraphic as Rect;
if (Rect) {
rectModel.copyFrom(Rect.saveData());
}
});
function onUpdate() {
const Rect = drawStore.selectedGraphic as Rect;
if (Rect) {
drawStore.getDrawApp().updateGraphicAndRecord(Rect, rectModel);
}
}
</script>

View File

@ -68,6 +68,30 @@
</q-icon>
</template>
</q-input>
<q-input
outlined
v-model="runLineModel.lineColor"
@blur="onUpdate"
label="线路背景色"
lazy-rules
:rules="[(val) => (val && val.length > 0) || '线路背景色不能为空']"
>
<template v-slot:append>
<q-icon name="colorize" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-color
v-model="runLineModel.lineColor"
@change="
(val) => {
runLineModel.lineColor = val;
onUpdate();
}
"
/>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<template :key="item" v-for="(item, index) in runLineModel.points">
<div style="display: flex; margin-top: 5px">
<q-input
@ -118,10 +142,11 @@
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { RunLineData } from 'src/drawApp/graphics/RunLineInteraction';
import { RunLine } from 'src/graphics/runLine/RunLine';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch, ref } from 'vue';
import { onMounted, reactive } from 'vue';
import { Point } from 'pixi.js';
import {
IStationLineData,
@ -130,20 +155,13 @@ import {
import { getLineList } from 'src/api/LineInfoApi';
const drawStore = useDrawStore();
const runLineModel = reactive(new RunLineData());
const { data: runLineModel, onUpdate } = useFormData(
new RunLineData(),
useDrawStore().getDrawApp()
);
const stationLines: IStationLineData[] = reactive([]);
const lineList: { label: string; value: string }[] = reactive([]);
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == RunLine.Type) {
runLineModel.copyFrom(val.saveData() as RunLineData);
}
}
);
onMounted(() => {
getLineList()
.then((res) => {
@ -154,31 +172,23 @@ onMounted(() => {
.catch((err) => {
console.error('获取线路列表失败:' + err.message);
});
const runLine = drawStore.selectedGraphic as RunLine;
const stations = drawStore
.getDrawApp()
.queryStore.queryByType(StationLine.Type) as StationLine[];
stations.forEach((item) => stationLines.push(item.datas));
if (runLine) {
runLineModel.copyFrom(runLine.saveData());
}
});
function onUpdate() {
const runLine = drawStore.selectedGraphic as RunLine;
if (runLine) {
drawStore.getDrawApp().updateGraphicAndRecord(runLine, runLineModel);
}
}
function generatePathLine() {
const runLine = drawStore.selectedGraphic as RunLine;
if (runLine) {
const points = runLineModel.points;
const points1: Point[] = [];
points.forEach((p) => points1.push(new Point(p.x, p.y)));
runLineModel.points.forEach((p) =>
points1.push(runLine.localToCanvasPoint(new Point(p.x, p.y)))
);
runLine.generatePathLine(points1);
}
}
function generateContainSta() {
const runLine = drawStore.selectedGraphic as RunLine;
if (runLine) {

View File

@ -1,6 +1,6 @@
<template>
<q-form>
<q-input outlined readonly v-model="sectionModel.id" label="id" hint="" />
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="sectionModel.id" label="id" />
<q-input
outlined
v-model="sectionModel.code"
@ -9,14 +9,17 @@
/>
<q-input
outlined
class="q-mt-lg"
v-model="sectionModel.destinationCode"
@blur="onUpdate"
label="目的地码"
/>
<q-checkbox
v-model="sectionModel.turning"
label="是否转换轨"
@update:model-value="onUpdate"
></q-checkbox>
<q-field
v-if="!isTurnoutPhysicalSection"
class="q-mt-lg"
outlined
label="关联区段"
readonly
@ -35,7 +38,6 @@
</q-field>
<q-field
v-if="!isTurnoutPhysicalSection"
class="q-mt-lg"
outlined
label="关联道岔"
readonly
@ -64,20 +66,33 @@
>
</template>
</q-field>
<q-select
outlined
v-model="sectionModel.centralizedStation"
:options="centralizedStations"
emitValue
mapOptions
@update:model-value="onUpdate"
label="关联的集中站"
/>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { SectionData } from 'src/drawApp/graphics/SectionInteraction';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { Section, SectionType } from 'src/graphics/section/Section';
import { Station } from 'src/graphics/station/Station';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, shallowRef, watchEffect } from 'vue';
import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const sectionModel = shallowRef(new SectionData());
const { data: sectionModel, onUpdate } = useFormData(
new SectionData(),
drawStore.getDrawApp()
);
const sectionRelations = computed(() => {
const section = drawStore.selectedGraphic as Section;
@ -87,12 +102,15 @@ const sectionRelations = computed(() => {
section,
Section.Type
);
return sectionRelations.map(
(relation) =>
`${relation.getRelationParam(section).param}: ${
return sectionRelations.map((relation) => {
if (relation.getRelationParam(section).param) {
return `${relation.getRelationParam(section).param}: ${
relation.getOtherGraphic<Section>(section).datas.code
}(${relation.getOtherRelationParam(section).param})`
);
}(${relation.getOtherRelationParam(section).param})`;
} else {
return relation.getOtherGraphic<Section>(section).datas.code;
}
});
});
const turnoutRelations = computed(() => {
@ -129,17 +147,21 @@ const axleCountingRelations = computed(() => {
(relation) => relation.getOtherGraphic<AxleCounting>(section).datas.code
);
});
watchEffect(() => {
const section = drawStore.selectedGraphic;
if (section && section instanceof Section) {
sectionModel.value = section.saveData();
}
});
const onUpdate = () => {
const section = drawStore.selectedGraphic as Section;
if (section) {
drawStore.getDrawApp().updateGraphicAndRecord(section, sectionModel.value);
}
};
const centralizedStations = ref<{ label: string; value: number }[]>([]);
onMounted(() => {
const stations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type);
centralizedStations.value = [{ label: '', value: 0 }];
stations.forEach((station) => {
if (station.datas.concentrationStations || station.datas.depots) {
centralizedStations.value.push({
label: station.datas.name,
value: station.datas.id,
});
}
});
});
</script>

View File

@ -16,13 +16,16 @@
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { SeparatorData } from 'src/drawApp/graphics/SeparatorInteraction';
import { Separator, separatorTypeEnum } from 'src/graphics/separator/Separator';
import { separatorTypeEnum } from 'src/graphics/separator/Separator';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
const drawStore = useDrawStore();
const separatorModel = reactive(new SeparatorData());
const { data: separatorModel, onUpdate } = useFormData(
new SeparatorData(),
drawStore.getDrawApp()
);
const typeOptions = [
{ label: '区段分隔符', value: separatorTypeEnum.section },
@ -30,28 +33,4 @@ const typeOptions = [
{ label: '左断路分隔符', value: separatorTypeEnum.endA },
{ label: '右断路分隔符', value: separatorTypeEnum.endB },
];
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Separator.Type) {
separatorModel.copyFrom(val.saveData() as SeparatorData);
}
}
);
onMounted(() => {
const Separator = drawStore.selectedGraphic as Separator;
if (Separator) {
separatorModel.copyFrom(Separator.saveData());
}
});
function onUpdate() {
const Separator = drawStore.selectedGraphic as Separator;
if (Separator) {
drawStore.getDrawApp().updateGraphicAndRecord(Separator, separatorModel);
}
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<q-form>
<q-input outlined readonly v-model="signalModel.id" label="id" hint="" />
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="signalModel.id" label="id" />
<q-input
outlined
v-model.number="signalModel.code"
@ -9,34 +9,106 @@
/>
<q-select
outlined
style="margin-top: 10px"
v-model="kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
v-model="refDevData.deviceType"
:options="DeviceTypeOptions"
readonly
map-options
emit-value
label="关联设备类型:"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
v-model="refDevData.code"
:readonly="true"
label="关联设备:"
></q-input>
<q-select
outlined
v-if="refDevData.deviceType === graphicData.RelatedRef.DeviceType.Turnout"
v-model="refDevData.devicePort"
:options="DevicePortOptions"
:readonly="true"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联设备端口:"
></q-select>
<q-list bordered separator class="rounded-borders">
<q-item no-wrap class="q-gutter-y-sm column">
<div>公里标配置</div>
<q-select
outlined
v-model="signalModel.kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
v-model.number="signalModel.kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
</q-item>
</q-list>
<q-select
outlined
v-model="signalModel.centralizedStation"
:options="centralizedStations"
emitValue
mapOptions
@update:model-value="onUpdate"
label="关联的集中站"
/>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { SignalData } from 'src/drawApp/graphics/SignalInteraction';
import { Signal } from 'src/graphics/signal/Signal';
import { Section } from 'src/graphics/section/Section';
import { Station } from 'src/graphics/station/Station';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, watch } from 'vue';
import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const signalModel = reactive(new SignalData());
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const { data: signalModel, onUpdate } = useFormData(
new SignalData(),
drawStore.getDrawApp()
);
const refDevData = computed(() => {
return signalModel.refDevice
? {
...signalModel.refDevice.toObject(),
code: drawStore
.getDrawApp()
.queryStore.queryById<Section | Turnout>(signalModel.refDevice.id)
.datas.code,
}
: {
id: 0,
deviceType: graphicData.RelatedRef.DeviceType.Section,
devicePort: graphicData.RelatedRef.DevicePort.A,
code: '',
};
});
const DeviceTypeOptions = [
{ label: '区段', value: graphicData.RelatedRef.DeviceType.Section },
{ label: '道岔', value: graphicData.RelatedRef.DeviceType.Turnout },
];
const DevicePortOptions = [
{ label: 'A端', value: graphicData.RelatedRef.DevicePort.A },
{ label: 'B端', value: graphicData.RelatedRef.DevicePort.B },
{ label: 'C端', value: graphicData.RelatedRef.DevicePort.C },
];
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
@ -44,42 +116,20 @@ const CoordinateSystemOptions = [
{ label: '正线', value: 'MAIN_LINE' },
{ label: '换线', value: 'TRANSFER' },
];
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Signal.Type) {
signalModel.copyFrom(val.saveData() as SignalData);
if (signalModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
signalModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = signalModel.kilometerSystem.kilometer;
}
}
}
);
const centralizedStations = ref<{ label: string; value: number }[]>([]);
onMounted(() => {
const signal = drawStore.selectedGraphic as Signal;
if (signal) {
signalModel.copyFrom(signal.saveData());
if (signalModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
signalModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = signalModel.kilometerSystem.kilometer;
const stations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type);
centralizedStations.value = [{ label: '', value: 0 }];
stations.forEach((station) => {
if (station.datas.concentrationStations || station.datas.depots) {
centralizedStations.value.push({
label: station.datas.name,
value: station.datas.id,
});
}
}
});
});
function onUpdate() {
const signal = drawStore.selectedGraphic as Signal;
signalModel.kilometerSystem = {
coordinateSystem: kilometerSystem.coordinateSystem,
kilometer: kilometerSystem.kilometer,
};
if (signal) {
drawStore.getDrawApp().updateGraphicAndRecord(signal, signalModel);
}
}
</script>

View File

@ -1,5 +1,5 @@
<template>
<q-form>
<q-form class="q-gutter-sm">
<q-input
outlined
readonly
@ -24,64 +24,42 @@
<q-select
outlined
@blur="onUpdate"
v-model="hasTransfer"
v-model="stationLineModel.hasTransfer"
:options="optionsCircle"
label="是否有换乘"
map-options
emit-value
/>
<q-select
outlined
v-model="stationLineModel.color"
:options="colorOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="站名颜色"
/>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { StationLineData } from 'src/drawApp/graphics/StationLineInteraction';
import { StationLine } from 'src/graphics/stationLine/StationLine';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref, watch } from 'vue';
import { graphicData } from 'src/protos/stationLayoutGraphics';
const drawStore = useDrawStore();
const stationLineModel = reactive(new StationLineData());
const hasTransfer = ref('是');
const optionsCircle = ['是', '否'];
enum showSelect {
= 'true',
= 'false',
}
enum showSelectData {
true = '是',
false = '否',
}
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == StationLine.Type) {
stationLineModel.copyFrom(val.saveData() as StationLineData);
hasTransfer.value = (showSelectData as never)[
stationLineModel.hasTransfer + ''
];
}
}
const { data: stationLineModel, onUpdate } = useFormData(
new StationLineData(),
drawStore.getDrawApp()
);
const optionsCircle = [
{ label: '是', value: true },
{ label: '否', value: false },
];
onMounted(() => {
const stationLine = drawStore.selectedGraphic as StationLine;
if (stationLine) {
stationLineModel.copyFrom(stationLine.saveData());
hasTransfer.value = (showSelectData as never)[
stationLineModel.hasTransfer + ''
];
}
});
function onUpdate() {
stationLineModel.hasTransfer = JSON.parse(
(showSelect as never)[hasTransfer.value]
);
const stationLine = drawStore.selectedGraphic as StationLine;
if (stationLine) {
drawStore
.getDrawApp()
.updateGraphicAndRecord(stationLine, stationLineModel);
}
}
const colorOptions = [
{ label: '橘黄色', value: graphicData.StationLine.stationColor.orange },
{ label: '灰色', value: graphicData.StationLine.stationColor.gray },
];
</script>

View File

@ -19,61 +19,74 @@
lazy-rules
autogrow
/>
<q-list bordered separator class="rounded-borders">
<q-item no-wrap class="q-gutter-y-sm column">
<div>公里标配置</div>
<q-select
outlined
style="margin-top: 10px"
v-model="stationModel.kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="stationModel.kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
</q-item>
</q-list>
<q-select
v-if="stationModel.concentrationStations"
outlined
style="margin-top: 10px"
v-model="kilometerSystem.coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
v-model="stationModel.manageStations"
label="集中站管理的车站"
multiple
:options="optionsStations"
map-options
emit-value
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="kilometerSystem.kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
<q-select
outlined
@blur="onUpdate"
v-model="hasControl"
:options="optionsControl"
<q-toggle
v-model="stationModel.hasControl"
label="是否有控制"
emit-value
@update:model-value="onUpdate"
/>
<q-select
outlined
@blur="onUpdate"
v-model="concentrationStations"
:options="optionsControl"
<q-toggle
v-model="stationModel.concentrationStations"
label="是否集中站"
emit-value
@update:model-value="onUpdate"
/>
<q-toggle
v-model="stationModel.depots"
label="是否车辆段"
emit-value
@update:model-value="onUpdate"
/>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { StationData } from 'src/drawApp/graphics/StationInteraction';
import { Station } from 'src/graphics/station/Station';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref, watch } from 'vue';
import { onMounted, watchEffect } from 'vue';
const drawStore = useDrawStore();
const stationModel = reactive(new StationData());
const hasControl = ref('是');
const concentrationStations = ref('否');
const optionsControl = ['是', '否'];
enum showSelect {
= 'true',
= 'false',
}
enum showSelectData {
true = '是',
false = '否',
}
const kilometerSystem = reactive({ coordinateSystem: '', kilometer: 0 });
const { data: stationModel, onUpdate } = useFormData(
new StationData(),
drawStore.getDrawApp()
);
let optionsStations: { label: string; value: number }[] = [];
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
@ -82,55 +95,22 @@ const CoordinateSystemOptions = [
{ label: '换线', value: 'TRANSFER' },
];
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Station.Type) {
stationModel.copyFrom(val.saveData() as StationData);
hasControl.value = (showSelectData as never)[
stationModel.hasControl + ''
];
concentrationStations.value = (showSelectData as never)[
stationModel.concentrationStations + ''
];
if (stationModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
stationModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = stationModel.kilometerSystem.kilometer;
}
}
}
);
onMounted(() => {
const station = drawStore.selectedGraphic as Station;
if (station) {
stationModel.copyFrom(station.saveData());
hasControl.value = (showSelectData as never)[stationModel.hasControl + ''];
concentrationStations.value = (showSelectData as never)[
stationModel.concentrationStations + ''
];
if (stationModel.kilometerSystem) {
kilometerSystem.coordinateSystem =
stationModel.kilometerSystem.coordinateSystem;
kilometerSystem.kilometer = stationModel.kilometerSystem.kilometer;
}
watchEffect(() => {
if (
stationModel.concentrationStations &&
!stationModel.manageStations.includes(stationModel.id)
) {
stationModel.manageStations.push(stationModel.id);
onUpdate();
}
});
function onUpdate() {
stationModel.hasControl = JSON.parse((showSelect as never)[hasControl.value]);
stationModel.concentrationStations = JSON.parse(
(showSelect as never)[concentrationStations.value]
);
stationModel.kilometerSystem = {
coordinateSystem: kilometerSystem.coordinateSystem,
kilometer: kilometerSystem.kilometer,
};
const station = drawStore.selectedGraphic as Station;
if (station) {
drawStore.getDrawApp().updateGraphicAndRecord(station, stationModel);
}
}
onMounted(() => {
optionsStations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type)
.map((g) => {
return { label: g.datas.name, value: g.datas.id };
});
});
</script>

View File

@ -1,84 +0,0 @@
<template>
<q-form>
<q-input outlined readonly v-model="trainModel.id" label="id" hint="" />
<q-input
outlined
v-model="trainModel.code"
label="车号"
hint=""
@blur="onUpdate"
/>
<q-select
outlined
@blur="onUpdate"
v-model="hasBorder"
:options="optionsDoor"
label="是否有边框"
/>
<q-select
outlined
@blur="onUpdate"
v-model="trainDirection"
:options="optionsDirection"
label="行驶方向"
/>
</q-form>
</template>
<script setup lang="ts">
import { TrainData } from 'src/drawApp/graphics/TrainInteraction';
import { Train } from 'src/graphics/train/Train';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref, watch } from 'vue';
const drawStore = useDrawStore();
const trainModel = reactive(new TrainData());
const hasBorder = ref('是');
const optionsDoor = ['是', '否'];
const trainDirection = ref('向左');
const optionsDirection = ['向左', '向右'];
enum showSelect {
= 'true',
= 'false',
向左 = 'left',
向右 = 'right',
}
enum showSelectData {
true = '是',
false = '否',
left = '向左',
right = '向右',
}
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == Train.Type) {
trainModel.copyFrom(val.saveData() as TrainData);
hasBorder.value = (showSelectData as never)[trainModel.hasBorder + ''];
trainDirection.value = (showSelectData as never)[
trainModel.trainDirection
];
}
}
);
onMounted(() => {
const train = drawStore.selectedGraphic as Train;
if (train) {
trainModel.copyFrom(train.saveData());
hasBorder.value = (showSelectData as never)[trainModel.hasBorder + ''];
trainDirection.value = (showSelectData as never)[trainModel.trainDirection];
}
});
function onUpdate() {
trainModel.hasBorder = JSON.parse((showSelect as never)[hasBorder.value]);
trainModel.trainDirection = (showSelect as never)[trainDirection.value];
const train = drawStore.selectedGraphic as Train;
if (train) {
drawStore.getDrawApp().updateGraphicAndRecord(train, trainModel);
}
}
</script>

View File

@ -36,7 +36,7 @@
</q-item>
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-item-label> 关联的道岔 </q-item-label>
<q-item-label> 关联的道岔物理区段 </q-item-label>
<div class="q-gutter-sm row">
<q-chip
v-for="item in relatedTurnout"
@ -55,42 +55,20 @@
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { TrainWindowData } from 'src/drawApp/graphics/TrainWindowInteraction';
import { LogicSection } from 'src/graphics/logicSection/LogicSection';
import { Section } from 'src/graphics/section/Section';
import { TrainWindow } from 'src/graphics/trainWindow/TrainWindow';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, onMounted, reactive, watch } from 'vue';
import { computed } from 'vue';
const drawStore = useDrawStore();
const trainWindowModel = reactive(new TrainWindowData());
drawStore.$subscribe;
watch(
() => drawStore.selectedGraphic,
(val) => {
if (val && val.type == TrainWindow.Type) {
trainWindowModel.copyFrom(val.saveData() as TrainWindowData);
}
}
const { data: trainWindowModel, onUpdate } = useFormData(
new TrainWindowData(),
drawStore.getDrawApp()
);
onMounted(() => {
const trainWindow = drawStore.selectedGraphic as TrainWindow;
if (trainWindow) {
trainWindowModel.copyFrom(trainWindow.saveData());
}
});
function onUpdate() {
const trainWindow = drawStore.selectedGraphic as TrainWindow;
if (trainWindow) {
drawStore
.getDrawApp()
.updateGraphicAndRecord(trainWindow, trainWindowModel);
}
}
const relatedLogicSection = computed((): LogicSection[] => {
if (
drawStore.selectedGraphic &&
@ -100,12 +78,14 @@ const relatedLogicSection = computed((): LogicSection[] => {
}
return [];
});
const relatedTurnout = computed((): Turnout[] => {
const relatedTurnout = computed((): Section[] => {
if (
drawStore.selectedGraphic &&
drawStore.selectedGraphic.type === 'TrainWindow'
) {
return (drawStore.selectedGraphic as TrainWindow).getRelatedTurnouts();
return (
drawStore.selectedGraphic as TrainWindow
).getRelatedTurnoutsSection();
}
return [];
});

View File

@ -1,48 +1,52 @@
<template>
<q-form>
<q-input outlined readonly v-model="turnoutModel.id" label="id" hint="" />
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="turnoutModel.id" label="id" />
<q-input
outlined
v-model="turnoutModel.code"
@blur="onUpdate"
label="编号"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="kilometerSystem[0].coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="kilometerSystem[0].kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="kilometerSystem[1].coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系2"
></q-select>
<q-input
outlined
style="margin-top: 10px"
v-model.number="kilometerSystem[1].kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
<q-list bordered separator class="rounded-borders">
<q-item no-wrap class="q-gutter-y-sm column">
<div>公里标配置</div>
<q-select
outlined
v-model="turnoutModel.kilometerSystem[0].coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系"
></q-select>
<q-input
outlined
v-model.number="turnoutModel.kilometerSystem[0].kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
</q-item>
<q-item no-wrap class="q-gutter-y-sm column">
<div>公里标配置</div>
<q-select
outlined
v-model="turnoutModel.kilometerSystem[1].coordinateSystem"
:options="CoordinateSystemOptions"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="坐标系2"
></q-select>
<q-input
outlined
v-model.number="turnoutModel.kilometerSystem[1].kilometer"
type="number"
@blur="onUpdate"
label="公里标(mm):"
/>
</q-item>
</q-list>
<q-field class="q-mt-lg" outlined label="关联区段" readonly stack-label>
<template #control>
<q-chip
@ -67,28 +71,38 @@
>
</template>
</q-field>
<q-select
outlined
v-model="turnoutModel.centralizedStation"
:options="centralizedStations"
emitValue
mapOptions
@update:model-value="onUpdate"
label="关联的集中站"
/>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { TurnoutData } from 'src/drawApp/graphics/TurnoutInteraction';
import { Section } from 'src/graphics/section/Section';
import { Station } from 'src/graphics/station/Station';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useDrawStore } from 'src/stores/draw-store';
import { computed, reactive, shallowRef, watchEffect } from 'vue';
import { computed, onMounted, ref } from 'vue';
const drawStore = useDrawStore();
const { data: turnoutModel, onUpdate } = useFormData(
new TurnoutData(),
drawStore.getDrawApp()
);
const CoordinateSystemOptions = [
{ label: '车辆段', value: 'DEPOT' },
{ label: '停车场', value: 'PARKING_LOT' },
{ label: '正线', value: 'MAIN_LINE' },
{ label: '换线', value: 'TRANSFER' },
];
const turnoutModel = shallowRef(new TurnoutData());
const kilometerSystem = reactive([
{ coordinateSystem: '', kilometer: 0 },
{ coordinateSystem: '', kilometer: 0 },
]);
const sectionRelations = computed(() => {
const turnout = drawStore.selectedGraphic as Turnout;
@ -98,12 +112,15 @@ const sectionRelations = computed(() => {
turnout,
Section.Type
);
return sectionRelations.map(
(relation) =>
`${relation.getRelationParam(turnout).param}: ${
return sectionRelations.map((relation) => {
if (relation.getRelationParam(turnout).param) {
return `${relation.getRelationParam(turnout).param}: ${
relation.getOtherGraphic<Section>(turnout).datas.code
}(${relation.getOtherRelationParam(turnout).param})`
);
}(${relation.getOtherRelationParam(turnout).param})`;
} else {
return relation.getOtherGraphic<Section>(turnout).datas.code;
}
});
});
const turnoutRelations = computed(() => {
@ -122,28 +139,20 @@ const turnoutRelations = computed(() => {
);
});
watchEffect(() => {
const turnout = drawStore.selectedGraphic;
if (turnout && turnout instanceof Turnout) {
turnoutModel.value = turnout.saveData();
if (turnoutModel.value.kilometerSystem.length > 0) {
kilometerSystem.forEach((ks, i) => {
ks.coordinateSystem =
turnoutModel.value.kilometerSystem[i].coordinateSystem;
ks.kilometer = turnoutModel.value.kilometerSystem[i].kilometer;
const centralizedStations = ref<{ label: string; value: number }[]>([]);
onMounted(() => {
const stations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type);
centralizedStations.value = [{ label: '', value: 0 }];
stations.forEach((station) => {
if (station.datas.concentrationStations || station.datas.depots) {
centralizedStations.value.push({
label: station.datas.name,
value: station.datas.id,
});
}
}
});
});
const onUpdate = () => {
const turnout = drawStore.selectedGraphic as Turnout;
turnoutModel.value.kilometerSystem = kilometerSystem.map((ks) => ({
coordinateSystem: ks.coordinateSystem,
kilometer: ks.kilometer,
}));
if (turnout) {
drawStore.getDrawApp().updateGraphicAndRecord(turnout, turnoutModel.value);
}
};
</script>

View File

@ -0,0 +1,302 @@
<template>
<div v-if="showRangeConfig">
<q-card class="q-gutter-sm q-pa-sm">
<q-card-section>
<div class="text-h6">{{ handleState }}</div>
</q-card-section>
<q-separator inset></q-separator>
<q-form ref="myForm" @submit="onSubmit" @reset="onReset">
<q-input
outlined
label="名称"
v-model="rangeConfig.areaName"
:rules="[(val) => val.trim() != '' || '名称不能为空']"
/>
<q-select
outlined
v-model="rangeConfig.deviceType"
:options="optionsType"
label="设备类型"
:map-options="true"
:emit-value="true"
:rules="[(val) => val.trim() != '' || '设备类型不能为空']"
/>
<q-select
outlined
v-model="rangeConfig.alertTypes"
label="故障类型"
multiple
:options="optionsAlertType"
:rules="[(val) => val.length > 0 || '故障类型不能为空']"
/>
<q-list bordered separator class="rounded-borders">
<q-item>
<q-item-section no-wrap class="q-gutter-y-sm column">
<q-item-label> 框选的设备 </q-item-label>
<div class="q-gutter-sm row">
<q-chip
v-for="item in device"
:key="item"
square
color="primary"
text-color="white"
removable
@remove="removeSelect(item)"
>
{{ item }}
</q-chip>
</div>
<q-btn
v-show="device.length > 0"
style="width: 120px"
label="清空框选的设备"
color="red"
@click="clearSelect"
/>
</q-item-section>
</q-item>
</q-list>
<div class="q-gutter-sm q-pa-md row justify-center">
<q-btn label="提交" type="submit" color="primary" class="q-mr-md" />
<q-btn label="重置" type="reset" color="primary" />
</div>
</q-form>
</q-card>
</div>
</template>
<script setup lang="ts">
// import { useLineStore } from 'src/stores/line-store';
import { reactive, ref, watch } from 'vue';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { Station } from 'src/graphics/station/Station';
import { Platform } from 'src/graphics/platform/Platform';
import { QForm, useQuasar } from 'quasar';
import { useRoute } from 'vue-router';
import {
deviceRangeSet,
IAreaConfigItem,
queryDeviceRangeById,
} from 'src/api/ConfigApi';
import { JlGraphic } from 'jl-graphic';
import { saveAlertTypeData, showAlertTypeData } from '../alarm/alarmInfoEnum';
import { Section } from 'src/graphics/section/Section';
import { useRangeConfigStore } from 'src/stores/range-config-store';
import { getRangeConfigApp } from 'src/drawApp/rangeConfigApp';
import { errorNotify } from 'src/utils/CommonNotify';
defineExpose({ searchById });
const route = useRoute();
const rangeConfigStore = useRangeConfigStore();
const $q = useQuasar();
const showRangeConfig = ref(true);
const rangeConfig = reactive<{
areaName: string;
deviceType: `${DeviceType}` | '';
device: number[];
alertTypes: string[];
}>({
areaName: '',
deviceType: '',
device: [],
alertTypes: [],
});
const device = ref<string[]>([]);
const handleState = ref('新建范围配置');
const optionsType = [
{ label: '轨道', value: Section.Type },
{ label: '道岔', value: Turnout.Type },
{ label: '集中站', value: Station.Type },
{ label: '站台', value: Platform.Type },
];
const optionsAlertType = [
'蓝显',
'全线蓝显',
'列车延误2分钟',
'列车延误10分钟',
'整侧站台门无关闭锁紧信号',
'整侧站台门无法打开',
'整侧站台门无法关闭',
'道岔均失表',
'道岔定位失表',
'道岔反位失表',
'计轴红光带',
'计轴大面积红光带',
'计轴橙光带',
'计轴大面积橙光带',
'道岔大面积失表',
'列车信号故障',
'一级联锁',
];
enum DeviceType {
station = 'DEVICE_TYPE_RTU',
Turnout = 'DEVICE_TYPE_SWITCH',
Section = 'DEVICE_TYPE_TRACK',
Platform = 'DEVICE_TYPE_PLATFORM',
}
enum DeviceTypeShow {
DEVICE_TYPE_RTU = 'station',
DEVICE_TYPE_SWITCH = 'Turnout',
DEVICE_TYPE_TRACK = 'Section',
DEVICE_TYPE_PLATFORM = 'Platform',
}
watch(
() => rangeConfig.alertTypes,
(alertTypes) => {
if (alertTypes[0] == '一级联锁') {
alertTypes.splice(1);
}
if (
alertTypes[0] !== '一级联锁' &&
alertTypes.slice(1).includes('一级联锁')
) {
for (let i = 0; i < alertTypes.length; i++) {
if (alertTypes[i] == '一级联锁') {
alertTypes.splice(i, 1);
break;
}
}
}
}
);
let selectGraphic: JlGraphic[] = [];
watch(
() => rangeConfigStore.selectedGraphics,
(val) => {
if (val && val.length > 0) {
const deviceFilter = rangeConfigStore.selectedGraphics?.filter((g) => {
let select = false;
if (
g.type == Station.Type &&
rangeConfig.deviceType == Station.Type &&
(g as Station).datas.concentrationStations
) {
select = true;
}
if (g.type == rangeConfig.deviceType && g.type !== Station.Type) {
select = true;
}
return select;
}) as JlGraphic[];
selectGraphic.push(...deviceFilter);
selectGraphic = Array.from(new Set(selectGraphic));
getRangeConfigApp().updateSelected(...selectGraphic);
device.value = selectGraphic.map((g) => g.code) as string[];
rangeConfig.device = selectGraphic.map((g) => g.id) as number[];
}
}
);
const myForm = ref<QForm | null>(null);
let editId: number;
let handle = ref('');
let handleError = ref('');
async function onSubmit() {
myForm.value?.validate().then(async (res) => {
let validataOfDevice = false;
if (rangeConfig.device.length) {
validataOfDevice = true;
} else {
errorNotify('请框选设备', '');
}
if (res && validataOfDevice) {
try {
const lineId = +route.params.id as number;
const alertTypes = rangeConfig.alertTypes.map(
(type) => (saveAlertTypeData as never)[type + '']
);
const params: IAreaConfigItem = {
lineId: lineId,
areaName: rangeConfig.areaName,
deviceType: (DeviceType as never)[rangeConfig.deviceType + ''],
alertTypes: alertTypes,
data: rangeConfig.device,
};
if (handleState.value == '新建范围配置') {
handle.value = '创建成功';
handleError.value = '创建失败';
await deviceRangeSet(params);
} else {
params.id = editId;
handle.value = '更新成功';
handleError.value = '更新失败';
await deviceRangeSet(params);
}
$q.notify({
type: 'positive',
message: handle.value,
});
onReset();
showRangeConfig.value = false;
} catch (err) {
$q.notify({
type: 'negative',
message: (err as { title: '' }).title,
});
} finally {
setTimeout(() => {
showRangeConfig.value = true;
}, 0);
}
}
});
}
async function searchById(id: number) {
try {
handleState.value = '编辑范围配置';
clearSelect();
editId = id;
const response = await queryDeviceRangeById(id);
rangeConfig.areaName = response.data.areaName;
rangeConfig.deviceType = (DeviceTypeShow as never)[
response.data.deviceType + ''
];
rangeConfig.alertTypes = response.data.alertTypes.map(
(type) => (showAlertTypeData as never)[type + '']
);
const select: JlGraphic[] = [];
response.data.data.forEach((id: number) => {
const g = getRangeConfigApp().queryStore.queryById(id);
select.push(g);
device.value.push(g.code);
});
getRangeConfigApp().updateSelected(...select);
} catch (err) {
$q.notify({
type: 'negative',
message: '没有需要编辑的详细信息',
});
}
}
function removeSelect(code: string) {
const removeIndex = device.value.findIndex((item) => item == code);
selectGraphic.splice(removeIndex, 1);
device.value.splice(removeIndex, 1);
rangeConfig.device.splice(removeIndex, 1);
getRangeConfigApp().updateSelected(...selectGraphic);
}
function clearSelect() {
device.value = [];
selectGraphic = [];
getRangeConfigApp().updateSelected();
}
function onReset() {
handleState.value = '新建范围配置';
rangeConfig.areaName = '';
rangeConfig.deviceType = '';
rangeConfig.alertTypes = [];
rangeConfig.device = [];
clearSelect();
}
</script>

View File

@ -0,0 +1,185 @@
<script setup lang="ts">
import {
IAreaConfigListItem,
getDeviceAreaList,
deleteDeviceArea,
} from 'src/api/ConfigApi';
import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import DraggableDialog from '../common/DraggableDialog.vue';
import { QTable, useQuasar } from 'quasar';
import { errorNotify } from 'src/utils/CommonNotify';
import { deviceTypeMap } from 'src/api/TrainApi';
const $q = useQuasar();
const lineId = useRoute().params.id as string;
const tableRef = ref<QTable>();
const columns: QTable['columns'] = [
{ name: 'id', label: 'ID', field: 'id', align: 'center' },
{ name: 'lineId', label: '线路ID', field: 'lineId', align: 'center' },
{
name: 'areaName',
label: '名称',
field: 'areaName',
align: 'center',
},
{
name: 'deviceType',
label: '设备类型',
field: (row) => deviceTypeMap[row.deviceType as keyof typeof deviceTypeMap],
align: 'center',
},
{ name: 'operations', label: '操作', field: 'operations', align: 'center' },
];
const rows = ref<IAreaConfigListItem[]>([]);
const loading = ref(false);
const pagination = ref({
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10,
});
const searchAreaName = ref('');
watch(
() => searchAreaName.value,
() => {
tableRef.value?.requestServerInteraction();
}
);
const onRequest: QTable['onRequest'] = async (props) => {
const { page, rowsPerPage } = props.pagination;
loading.value = true;
try {
const resp = await getDeviceAreaList({
lineId,
current: page,
size: rowsPerPage,
areaName: searchAreaName.value,
});
pagination.value.page = resp.current;
pagination.value.rowsNumber = resp.total;
pagination.value.rowsPerPage = resp.size;
rows.value = resp.records;
} catch (err) {
$q.notify({
type: 'negative',
message: '无法获取范围列表',
});
} finally {
loading.value = false;
}
};
const onDialogShow = () => {
tableRef.value?.requestServerInteraction();
};
const dialogRef = ref<InstanceType<typeof DraggableDialog>>();
const props = defineProps<{
onEditClick: (row: IAreaConfigListItem) => void;
}>();
function onEdit(row: IAreaConfigListItem) {
props.onEditClick(row);
}
function deleteData(row: IAreaConfigListItem) {
$q.dialog({ message: `确定删除 "${row.areaName}" 吗?`, cancel: true }).onOk(
async () => {
try {
await deleteDeviceArea(row.id);
} catch (err) {
errorNotify('删除失败:', err);
} finally {
tableRef.value?.requestServerInteraction();
}
}
);
}
</script>
<template>
<draggable-dialog
ref="dialogRef"
@show="onDialogShow"
title="范围列表"
:width="800"
:height="0"
>
<template v-slot:footer>
<q-table
ref="tableRef"
row-key="id"
v-model:pagination="pagination"
:loading="loading"
:rows="rows"
:columns="columns"
@request="onRequest"
:rows-per-page-options="[10, 20, 50, 100]"
>
<template v-slot:body-cell="props">
<q-td :props="props" class="custom-column">
{{ props.value }}
<q-tooltip
anchor="bottom middle"
v-if="props.value && props.value.length > 20"
>
<div class="message-tip">
{{ props.value }}
</div>
</q-tooltip>
</q-td>
</template>
<template v-slot:body-cell-operations="props">
<q-td :props="props">
<div class="q-gutter-sm row justify-center">
<q-btn color="primary" label="编辑" @click="onEdit(props.row)" />
<q-btn color="red" label="删除" @click="deleteData(props.row)" />
</div>
</q-td>
</template>
</q-table>
</template>
<template v-slot:titleButton>
<q-btn square color="purple" style="margin-right: 10px" icon="search">
<q-popup-edit
ref="popupEdit"
v-model="searchAreaName"
:cover="false"
:offset="[0, 10]"
v-slot="scope"
>
<q-input
color="accent"
v-model="scope.value"
label="区域名称"
dense
autofocus
@keyup.enter="scope.set"
>
<template v-slot:prepend>
<q-icon name="search" color="accent" />
</template>
</q-input>
</q-popup-edit>
</q-btn>
</template>
</draggable-dialog>
</template>
<style scoped>
.custom-column {
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.message-tip {
width: 300px;
overflow: auto;
line-height: 22px;
white-space: pre-wrap;
font-size: 14px;
}
</style>

View File

@ -0,0 +1,33 @@
<template>
<!-- 画布或图形对象属性 -->
<div v-if="lineStore.selectedGraphics !== null">
<q-card flat>
<q-card-section>
<div class="text-h6">
{{ lineStore.selectedGraphicType + ' 状态属性' }}
</div>
</q-card-section>
<q-separator inset></q-separator>
<template v-if="lineStore.selectedGraphics.length === 1">
<q-card-section>
<platform-property
v-if="lineStore.selectedGraphicType === Platform.Type"
></platform-property>
<station-property
v-if="lineStore.selectedGraphicType === Station.Type"
></station-property>
</q-card-section>
</template>
</q-card>
</div>
</template>
<script setup lang="ts">
import { useLineStore } from 'src/stores/line-store';
import { Platform } from 'src/graphics/platform/Platform';
import PlatformProperty from './deviceStates/PlatformProperty.vue';
import { Station } from 'src/graphics/station/Station';
import StationProperty from './deviceStates/StationProperty.vue';
const lineStore = useLineStore();
</script>

View File

@ -0,0 +1,247 @@
<template>
<q-form class="q-gutter-sm">
<q-input
outlined
readonly
v-model="lineStore.selectedGraphic.id"
label="id"
hint=""
/>
<q-input
outlined
label="站台名称"
readonly
@blur="onUpdate"
v-model="lineStore.selectedGraphic.datas.code"
/>
<q-select
outlined
@blur="onUpdate"
v-model="psdOpen"
:options="optionsChoose"
label="屏蔽门打开"
/>
<q-select
outlined
@blur="onUpdate"
v-model="psdCut"
:options="optionsChoose"
label="屏蔽门切除"
/>
<q-select
outlined
@blur="onUpdate"
v-model="emergstop"
:options="optionsChoose"
label="是否紧急关闭"
/>
<q-select
outlined
@blur="onUpdate"
v-model="trainberth"
:options="optionsChoose"
label="是否在站台停站"
/>
<q-select
v-if="lineStore.selectedGraphic.datas.up"
outlined
@blur="onUpdate"
v-model="upHold"
:options="optionsChoose"
label="是否上行车站扣车"
/>
<q-select
v-if="lineStore.selectedGraphic.datas.up"
outlined
@blur="onUpdate"
v-model="upOccHold"
:options="optionsChoose"
label="是否上行中心扣车"
/>
<q-select
v-if="!lineStore.selectedGraphic.datas.up"
outlined
@blur="onUpdate"
v-model="downHold"
:options="optionsChoose"
label="是否下行车站扣车"
/>
<q-select
v-if="!lineStore.selectedGraphic.datas.up"
outlined
@blur="onUpdate"
v-model="downOccHold"
:options="optionsChoose"
label="是否下行中心扣车"
/>
<q-select
v-if="lineStore.selectedGraphic.datas.up"
outlined
@blur="onUpdate"
v-model="upSkipstop"
:options="optionsChoose"
label="是否上行跳停"
/>
<q-select
v-if="!lineStore.selectedGraphic.datas.up"
outlined
@blur="onUpdate"
v-model="downSkipstop"
:options="optionsChoose"
label="是否下行跳停"
/>
<q-input
outlined
label="人工设置区间运行等级"
type="textarea"
@blur="onUpdate"
v-model="platformModel.nextSectionRunTime"
lazy-rules
autogrow
/>
<q-input
outlined
label="人工设置停站时间"
type="textarea"
@blur="onUpdate"
v-model="platformModel.stopTime"
lazy-rules
autogrow
/>
</q-form>
</template>
<script setup lang="ts">
import { PlatformState } from 'src/drawApp/graphics/PlatformInteraction';
import { Platform } from 'src/graphics/platform/Platform';
import { useLineStore } from 'src/stores/line-store';
import { onMounted, reactive, ref, watch } from 'vue';
import { mockPlatformApi, mockPlatformParams } from 'src/api/PlatformApi';
const lineStore = useLineStore();
const platformModel = reactive(new PlatformState());
const optionsChoose = ['是', '否'];
const psdOpen = ref('');
const psdCut = ref('');
const emergstop = ref('');
const trainberth = ref('');
const upHold = ref('');
const upOccHold = ref('');
const upSkipstop = ref('');
const downHold = ref('');
const downOccHold = ref('');
const downSkipstop = ref('');
enum showSelect {
= 'true',
= 'false',
}
enum showSelectData {
true = '是',
false = '否',
}
lineStore.$subscribe;
watch(
() => lineStore.selectedGraphic,
(val) => {
if (val && val.type == Platform.Type) {
platformModel.copyFrom((val as Platform).states as PlatformState);
psdOpen.value = (showSelectData as never)[platformModel.psdOpen + ''];
psdCut.value = (showSelectData as never)[platformModel.psdCut + ''];
emergstop.value = (showSelectData as never)[platformModel.emergstop + ''];
trainberth.value = (showSelectData as never)[
platformModel.trainberth + ''
];
upHold.value = (showSelectData as never)[platformModel.upHold + ''];
upOccHold.value = (showSelectData as never)[platformModel.upOccHold + ''];
upSkipstop.value = (showSelectData as never)[
platformModel.upSkipstop + ''
];
downHold.value = (showSelectData as never)[platformModel.downHold + ''];
downOccHold.value = (showSelectData as never)[
platformModel.downOccHold + ''
];
downSkipstop.value = (showSelectData as never)[
platformModel.downSkipstop + ''
];
}
}
);
onMounted(() => {
const platform = lineStore.selectedGraphic as Platform;
if (platform) {
platformModel.copyFrom((platform as Platform).states as PlatformState);
psdOpen.value = (showSelectData as never)[platformModel.psdOpen + ''];
psdCut.value = (showSelectData as never)[platformModel.psdCut + ''];
emergstop.value = (showSelectData as never)[platformModel.emergstop + ''];
trainberth.value = (showSelectData as never)[platformModel.trainberth + ''];
upHold.value = (showSelectData as never)[platformModel.upHold + ''];
upOccHold.value = (showSelectData as never)[platformModel.upOccHold + ''];
upSkipstop.value = (showSelectData as never)[platformModel.upSkipstop + ''];
downHold.value = (showSelectData as never)[platformModel.downHold + ''];
downOccHold.value = (showSelectData as never)[
platformModel.downOccHold + ''
];
downSkipstop.value = (showSelectData as never)[
platformModel.upSkipstop + ''
];
}
});
function onUpdate() {
const platform = lineStore.selectedGraphic as Platform;
platformModel.psdOpen = JSON.parse((showSelect as never)[psdOpen.value]);
platformModel.psdCut = JSON.parse((showSelect as never)[psdCut.value]);
platformModel.emergstop = JSON.parse((showSelect as never)[emergstop.value]);
platformModel.trainberth = JSON.parse(
(showSelect as never)[trainberth.value]
);
platformModel.upHold = JSON.parse((showSelect as never)[upHold.value]);
platformModel.upOccHold = JSON.parse((showSelect as never)[upOccHold.value]);
platformModel.upSkipstop = JSON.parse(
(showSelect as never)[upSkipstop.value]
);
platformModel.downHold = JSON.parse((showSelect as never)[downHold.value]);
platformModel.downOccHold = JSON.parse(
(showSelect as never)[downOccHold.value]
);
platformModel.downSkipstop = JSON.parse(
(showSelect as never)[downSkipstop.value]
);
const data: { [key: string]: boolean | number | string } = {
emergstop: false,
trainberth: false,
close: false,
upHold: false,
upOccHold: false,
downOccHold: false,
psdOpen: false,
psdCut: false,
upSkipstop: false,
downSkipstop: false,
upTrainSkipstop: false,
downTrainSkipstop: false,
downHold: false,
id: platform.id,
nextSectionRunTime: 0,
nextSectionRunLevel: 0,
stopTime: 0,
};
type keyData = 'emergstop' | 'trainberth';
Object.keys(data).forEach((i) => {
data[i] = platformModel[i as keyData] || data[i];
});
if (platform) {
mockPlatformApi(3, data as unknown as mockPlatformParams)
.then((res) => {
console.log(res, '---res--');
})
.catch((err) => {
console.log(err, '---err---');
});
}
}
</script>

View File

@ -0,0 +1,103 @@
<template>
<q-form class="q-gutter-sm">
<q-input
outlined
readonly
v-model="lineStore.selectedGraphic.id"
label="id"
hint=""
/>
<q-input
outlined
label="车站名称"
readonly
@blur="onUpdate"
v-model="lineStore.selectedGraphic.datas.name"
/>
<q-select
outlined
@blur="onUpdate"
v-model="controlChange"
:options="optionsChoose"
label="车站控制模式转换"
/>
<q-checkbox
v-model="stationModel.ipRtuStusDown"
label="是否通信中断"
@update:model-value="onUpdate"
/>
<q-checkbox
v-model="stationModel.ipRtuStusInLocalCtrl"
label="是否站控"
@update:model-value="onUpdate"
/>
</q-form>
</template>
<script setup lang="ts">
import { StationState } from 'src/drawApp/graphics/StationInteraction';
import { Station } from 'src/graphics/station/Station';
import { useLineStore } from 'src/stores/line-store';
import { onMounted, reactive, ref, watch } from 'vue';
import { mockStationApi } from 'src/api/PlatformApi';
const lineStore = useLineStore();
const stationModel = reactive(new StationState());
const optionsChoose = ['中控', '站控且允许转到中控', '站控且不允许转到中控'];
const controlChange = ref('');
lineStore.$subscribe;
watch(
() => lineStore.selectedGraphic,
(val) => {
if (val && val.type == Station.Type) {
stationModel.copyFrom((val as Station).states as StationState);
}
}
);
onMounted(() => {
const station = lineStore.selectedGraphic as Station;
if (station) {
stationModel.copyFrom((station as Station).states as StationState);
}
});
function onUpdate() {
const station = lineStore.selectedGraphic as Station;
const data = {
ipRtuStusDown: false,
ipRtuStusInLocalCtrl: false,
ipRtuStusInCentralCtrl: false,
ipRtuStusInEmergencyCtrl: false,
id: station.id,
};
const lineId = lineStore.lineId as number;
data.ipRtuStusDown = stationModel.ipRtuStusDown;
data.ipRtuStusInLocalCtrl = stationModel.ipRtuStusInLocalCtrl;
if (station) {
switch (controlChange.value) {
case '中控':
data.ipRtuStusInLocalCtrl = false;
data.ipRtuStusDown = false;
break;
case '站控且允许转到中控':
data.ipRtuStusInLocalCtrl = true;
data.ipRtuStusDown = false;
break;
case '站控且不允许转到中控':
data.ipRtuStusInLocalCtrl = true;
data.ipRtuStusDown = true;
break;
}
mockStationApi(lineId, data)
.then((res) => {
console.log(res, '---res--');
})
.catch((err) => {
console.log(err, '---err---');
});
}
}
</script>

View File

@ -0,0 +1,31 @@
import { HandleMessage, StompMessagingClient } from 'jl-graphic';
import { getJwtToken } from 'src/configs/TokenManage';
import { getWebsocketUrl } from 'src/configs/UrlManage';
export function webSocketConnect(destination: string, handler: HandleMessage) {
const socket = new StompMessagingClient({
wsUrl: `${getWebsocketUrl()}`,
token: getJwtToken() as string,
protocol: 'protobuf',
connectTimeout: 30 * 1000,
heartbeat: 60,
retryPeriod: 2 * 1000,
retryTimes: 100,
});
socket.on('connected', () => {
socket?.subscribe(destination, handler);
});
socket.on('disconnected', () => {
console.log('disconnected');
});
return socket;
}
export function closeWebSocketConnect(
socket: StompMessagingClient | null,
destination: string
) {
socket?.unsubscribe0(destination);
socket?.close();
socket = null;
}

View File

@ -1,15 +1,23 @@
function getHost(): string {
// return '192.168.3.7:9081';
// return '192.168.3.47:9081';
// return '192.168.3.37:9081';
// return '192.168.3.15:9081';
return '192.168.3.233:9081';
const base_api = process.env.API;
// console.log(process.env);
// console.log(' load env :' + process.env.NODE_ENV);
return base_api + '';
}
export function getHttpBase() {
return `http://${getHost()}`;
return process.env.HTTP + `${getHost()}` + process.env.NS;
}
export function getWebsocketUrl() {
return `ws://${getHost()}/ws-default`;
return process.env.WS + `${getHost()}`+ process.env.NS+'/ws-default';
}
export function getShowSetAlarmTextButton() {
let show = false;
const host = window.location.hostname;
if (process.env.NODE_ENV == 'development' || host == '192.168.3.233') {
show = true;
}
return show;
}

View File

@ -1 +1,4 @@
// app global css in SCSS form
.my-notif-class {
margin-top: 50px;
}

View File

@ -33,6 +33,9 @@ export class AxleCountingData
this.data.code = v;
}
get kilometerSystem(): KilometerSystem {
if (!this.data.kilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem();
}
return this.data.kilometerSystem;
}
set kilometerSystem(v: KilometerSystem) {

View File

@ -0,0 +1,77 @@
import * as pb_1 from 'google-protobuf';
import { GraphicDataBase } from './GraphicDataBase';
import {
IConcentrationDividingLineData,
ConcentrationDividingLine,
} from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData } from 'pixi.js';
export class ConcentrationDividingLineData
extends GraphicDataBase
implements IConcentrationDividingLineData
{
constructor(data?: graphicData.ConcentrationDividingLine) {
let concentrationDividingLine;
if (!data) {
concentrationDividingLine = new graphicData.ConcentrationDividingLine({
common: GraphicDataBase.defaultCommonInfo(
ConcentrationDividingLine.Type
),
});
} else {
concentrationDividingLine = data;
}
super(concentrationDividingLine);
}
public get data(): graphicData.ConcentrationDividingLine {
return this.getData<graphicData.ConcentrationDividingLine>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get points(): IPointData[] {
return this.data.points;
}
set points(points: IPointData[]) {
this.data.points = points.map(
(p) => new graphicData.Point({ x: p.x, y: p.y })
);
}
get refLeftStationId(): number {
return this.data.refLeftStationId;
}
set refLeftStationId(v: number) {
this.data.refLeftStationId = v;
}
get refRightStationId(): number {
return this.data.refRightStationId;
}
set refRightStationId(v: number) {
this.data.refRightStationId = v;
}
get nodeConWithSecs(): graphicData.NodeConWithSec[] {
return this.data.nodeConWithSecs;
}
set nodeConWithSecs(nodes: graphicData.NodeConWithSec[]) {
this.data.nodeConWithSecs = nodes;
}
get isOtherLineConcentrationDividingLine(): boolean {
return this.data.isOtherLineConcentrationDividingLine;
}
set isOtherLineConcentrationDividingLine(v: boolean) {
this.data.isOtherLineConcentrationDividingLine = v;
}
clone(): ConcentrationDividingLineData {
return new ConcentrationDividingLineData(this.data.cloneMessage());
}
copyFrom(data: ConcentrationDividingLineData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: ConcentrationDividingLineData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -6,14 +6,13 @@ import {
GraphicTransform,
IChildTransform,
IGraphicTransform,
} from 'src/jl-graphic';
} from 'jl-graphic';
// import { toStorageTransform } from '..';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData, Point } from 'pixi.js';
import { state } from 'src/protos/device_status';
export interface ICommonInfo {
id: string;
id: number;
graphicType: string;
transform: IGraphicTransform;
childTransforms: IChildTransform[];
@ -60,7 +59,7 @@ export abstract class GraphicDataBase implements GraphicData {
static defaultCommonInfo(graphicType: string): graphicData.CommonInfo {
return new graphicData.CommonInfo({
id: '',
id: 0,
graphicType: graphicType,
transform: new graphicData.Transform({
position: new graphicData.Point({ x: 0, y: 0 }),
@ -76,10 +75,10 @@ export abstract class GraphicDataBase implements GraphicData {
return this._data as D;
}
get id(): string {
get id(): number {
return this._data.common.id;
}
set id(v: string) {
set id(v: number) {
this._data.common.id = v;
}
get graphicType(): string {

View File

@ -3,20 +3,18 @@ import { IPointData, DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { ILinkData, Link } from 'src/graphics/link/Link';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import {
GraphicApp,
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
import {
ContextMenu,
MenuItemOptions,
addWayPoint,
clearWayPoint,
getWaypointRangeIndex,
PolylineEditPlugin,
removeLineWayPoint,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
} from 'jl-graphic';
export class LinkData extends GraphicDataBase implements ILinkData {
constructor(data?: graphicData.Link) {
@ -119,12 +117,12 @@ const EpEditMenu: ContextMenu = ContextMenu.init({
export class DrawLinkPlugin extends GraphicInteractionPlugin<Link> {
static Name = 'link_draw_right_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(DrawLinkPlugin.Name, app);
app.registerMenu(LinkEditMenu);
app.registerMenu(EpEditMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new DrawLinkPlugin(app);
}
filter(...grahpics: JlGraphic[]): Link[] | undefined {

View File

@ -10,15 +10,16 @@ import { graphicData } from 'src/protos/stationLayoutGraphics';
import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js';
import { state } from 'src/protos/device_status';
import {
GraphicApp,
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
MenuItemOptions,
ContextMenu,
} from 'jl-graphic';
import { LogicSectionGraphicHitArea } from 'src/graphics/logicSection/LogicSectionDrawAssistant';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { useLineStore } from 'src/stores/line-store';
import { setTrackStatus } from 'src/api/TurnoutApi';
import { successNotify } from 'src/utils/CommonNotify';
let menuItemHandler: (propName: keyof ILogicSectionState) => void;
@ -54,6 +55,10 @@ const blocked: MenuItemOptions = {
name: '轨道区段封锁 - blocked',
handler: () => menuItemHandler('blocked'),
};
const speedLimit: MenuItemOptions = {
name: '限速 - speedLimit',
handler: () => menuItemHandler('speedLimit'),
};
const LogicSectionMenu = ContextMenu.init({
name: 'LogicSection菜单',
@ -68,6 +73,7 @@ const LogicSectionMenu = ContextMenu.init({
atcInvalid,
overlap,
blocked,
speedLimit,
],
},
],
@ -75,25 +81,32 @@ const LogicSectionMenu = ContextMenu.init({
export class LogicSectionOperationPlugin extends GraphicInteractionPlugin<LogicSection> {
static Name = 'logic_section_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(LogicSectionOperationPlugin.Name, app);
app.registerMenu(LogicSectionMenu);
}
filter(...grahpics: JlGraphic[]): LogicSection[] | undefined {
return grahpics.filter((g): g is LogicSection => g instanceof LogicSection);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new LogicSectionOperationPlugin(app);
}
bind(g: LogicSection): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.lineGraphic.hitArea = new LogicSectionGraphicHitArea(g);
g.on('_leftclick', this.onLeftClick, this);
g.on('rightclick', this.onContextMenu, this);
}
unbind(g: LogicSection): void {
g.off('_leftclick', this.onLeftClick, this);
g.off('rightclick', this.onContextMenu);
}
onLeftClick(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const section = target.getGraphic() as LogicSection;
this.app.updateSelected(section);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const section = target.getGraphic() as LogicSection;
@ -141,10 +154,16 @@ export class LogicSectionOperationPlugin extends GraphicInteractionPlugin<LogicS
menuItemHandler = (propName) => {
const lineId = useLineStore().lineId?.toString();
if (!lineId) return;
console.log({ ...section.states });
let val: boolean | number;
if (propName !== 'speedLimit') {
val = !section.states[propName];
} else {
val = section.states[propName] > 0 ? 0 : 20;
successNotify(`限速设为${val}`);
}
setTrackStatus(lineId, {
...state,
[propName]: !section.states[propName],
[propName]: val,
});
};
LogicSectionMenu.open(e.global);
@ -295,6 +314,14 @@ export class LogicSectionState
public set limitType(value: LimitType) {
this.states.limitType = value;
}
// 集中站站号
public get rtuId(): number {
return this.states.rtuId;
}
public set rtuId(value: number) {
this.states.rtuId = value;
}
clone(): LogicSectionState {
return new LogicSectionState(this.states.cloneMessage());
}

View File

@ -7,13 +7,13 @@ import {
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_status';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import {
GraphicApp,
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
MenuItemOptions,
ContextMenu,
} from 'jl-graphic';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { mockPlatformApi } from 'src/api/PlatformApi';
import { useLineStore } from 'src/stores/line-store';
@ -59,12 +59,24 @@ export class PlatformData extends GraphicDataBase implements IPlatformData {
set up(v: boolean) {
this.data.up = v;
}
get refStation(): string {
get refStation(): number {
return this.data.refStation;
}
set refStation(v: string) {
set refStation(v: number) {
this.data.refStation = v;
}
get refSectionId(): number {
return this.data.refSectionId;
}
set refSectionId(v: number) {
this.data.refSectionId = v;
}
get centralizedStation(): number {
return this.data.centralizedStationId;
}
set centralizedStation(v: number) {
this.data.centralizedStationId = v;
}
clone(): PlatformData {
return new PlatformData(this.data.cloneMessage());
@ -188,6 +200,13 @@ export class PlatformState extends GraphicStateBase implements IPlatformState {
set stopTime(v: number) {
this.states.stopTime = v;
}
// 集中站站号
get rtuId(): number {
return this.states.rtuId;
}
set rtuId(value: number) {
this.states.rtuId = value;
}
get states(): state.Platform {
return this.getState<state.Platform>();
}
@ -202,86 +221,26 @@ export class PlatformState extends GraphicStateBase implements IPlatformState {
}
}
const holdConfig: MenuItemOptions = {
name: '扣车',
};
const removeHoldrConfig: MenuItemOptions = {
name: '取消扣车',
};
const batchHoldConfig: MenuItemOptions = {
name: '批量扣车',
};
const removeBatchHoldConfig: MenuItemOptions = {
name: '批量取消扣车',
};
const earlyDepartureConfig: MenuItemOptions = {
name: '提前发车',
};
const skipStopConfig: MenuItemOptions = {
name: '设置跳停',
};
const removeSkipStopConfig: MenuItemOptions = {
name: '取消跳停',
};
const dockTimeConfig: MenuItemOptions = {
name: '设置停站时间',
};
const operatingLevelConfig: MenuItemOptions = {
name: '设置运行等级',
};
const numberOfRegionalTrainsConfig: MenuItemOptions = {
name: '区间列车数量限制',
};
const removeNumberOfRegionalTrainsConfig: MenuItemOptions = {
name: '取消区间列车数量限制',
};
const platformMessadeConfig: MenuItemOptions = {
name: '站台详细信息',
const resetConfig: MenuItemOptions = {
name: '重置状态',
};
const PlatformOperateMenu: ContextMenu = ContextMenu.init({
name: '站台操作菜单',
groups: [
{
items: [
holdConfig,
removeHoldrConfig,
skipStopConfig,
removeSkipStopConfig,
],
},
],
});
const dispatchPlatformOperateMenu: ContextMenu = ContextMenu.init({
name: '调度仿真站台操作菜单',
groups: [
{
items: [
holdConfig,
removeHoldrConfig,
batchHoldConfig,
removeBatchHoldConfig,
earlyDepartureConfig,
skipStopConfig,
removeSkipStopConfig,
dockTimeConfig,
operatingLevelConfig,
numberOfRegionalTrainsConfig,
removeNumberOfRegionalTrainsConfig,
platformMessadeConfig,
],
items: [resetConfig],
},
],
});
export class PlatformOperateInteraction extends GraphicInteractionPlugin<Platform> {
static Name = 'platform_operate_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(PlatformOperateInteraction.Name, app);
app.registerMenu(PlatformOperateMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new PlatformOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): Platform[] | undefined {
@ -327,70 +286,8 @@ export class PlatformOperateInteraction extends GraphicInteractionPlugin<Platfor
nextSectionRunLevel: 0,
stopTime: 0,
};
holdConfig.handler = () => {
resetConfig.handler = () => {
const dataCopy = JSON.parse(JSON.stringify(data));
if (platform.datas.direction == 'down') {
//dataCopy.upHold = true; //上行方向车站扣车
dataCopy.trainberth = true; //列车停站
dataCopy.emergstop = true; //紧急关闭
dataCopy.upOccHold = true; //上行方向中心扣车
dataCopy.psdOpen = true;
dataCopy.nextSectionRunLevel = 2;
dataCopy.nextSectionRunTime = 10;
dataCopy.stopTime = 5;
} else {
dataCopy.downHold = true; //下行方向车站扣车
dataCopy.downOccHold = true; //下行方向中心扣车
dataCopy.psdCut = true;
}
mockPlatformApi(lineId, dataCopy)
.then((res) => {
console.log(res, '---res--');
})
.catch((err) => {
console.log(err, '---err---');
});
};
removeHoldrConfig.handler = () => {
const dataCopy = JSON.parse(JSON.stringify(data));
if (platform.datas.direction == 'down') {
dataCopy.upHold = false;
} else {
dataCopy.downHold = false;
}
mockPlatformApi(lineId, dataCopy)
.then((res) => {
console.log(res, '---res--');
})
.catch((err) => {
console.log(err, '---err---');
});
};
skipStopConfig.handler = () => {
const dataCopy = JSON.parse(JSON.stringify(data));
if (platform.datas.direction == 'down') {
dataCopy.upSkipstop = true; //上行方向跳停
} else {
dataCopy.downSkipstop = true; //下行方向跳停
dataCopy.nextSectionRunLevel = 2;
dataCopy.nextSectionRunTime = 10;
dataCopy.stopTime = 5;
}
mockPlatformApi(lineId, dataCopy)
.then((res) => {
console.log(res, '---res--');
})
.catch((err) => {
console.log(err, '---err---');
});
};
removeSkipStopConfig.handler = () => {
const dataCopy = JSON.parse(JSON.stringify(data));
if (platform.datas.direction == 'down') {
dataCopy.upSkipstop = false;
} else {
dataCopy.downSkipstop = false;
}
mockPlatformApi(lineId, dataCopy)
.then((res) => {
console.log(res, '---res--');

View File

@ -4,7 +4,7 @@ import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js';
import {
GraphicApp,
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
@ -128,12 +128,12 @@ const EpEditMenu: ContextMenu = ContextMenu.init({
export class DrawPolygonPlugin extends GraphicInteractionPlugin<Polygon> {
static Name = 'polygon_draw_right_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(DrawPolygonPlugin.Name, app);
app.registerMenu(PolygonEditMenu);
app.registerMenu(EpEditMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new DrawPolygonPlugin(app);
}
filter(...grahpics: JlGraphic[]): Polygon[] | undefined {

View File

@ -8,22 +8,21 @@ import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import {
GraphicInteractionPlugin,
GraphicApp,
IGraphicApp,
JlGraphic,
} from 'src/jl-graphic';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { FederatedMouseEvent, DisplayObject, IPointData } from 'pixi.js';
import {
ContextMenu,
MenuItemOptions,
addWayPoint,
clearWayPoint,
getWaypointRangeIndex,
PolylineEditPlugin,
removeLineWayPoint,
} from 'src/jl-graphic/plugins/GraphicEditPlugin';
} from 'jl-graphic';
import { FederatedMouseEvent, DisplayObject, IPointData } from 'pixi.js';
import { RunLineGraphicHitArea } from 'src/graphics/runLine/RunLineDrawAssistant';
import { Dialog } from 'quasar';
import SetDashLineDialog from '../../components/draw-app/dialogs/SetDashLineDialog.vue';
import SetGaryLineDialog from '../../components/draw-app/dialogs/SetGaryLineDialog.vue';
export class RunLineData extends GraphicDataBase implements IRunLineData {
constructor(data?: graphicData.RunLine) {
@ -72,10 +71,10 @@ export class RunLineData extends GraphicDataBase implements IRunLineData {
set containSta(v: string[]) {
this.data.containSta = v;
}
get linkPathLines(): string[] {
get linkPathLines(): number[] {
return this.data.linkPathLines;
}
set linkPathLines(v: string[]) {
set linkPathLines(v: number[]) {
this.data.linkPathLines = v;
}
get lineId(): string {
@ -90,6 +89,18 @@ export class RunLineData extends GraphicDataBase implements IRunLineData {
set dashPointIndexs(v: number[]) {
this.data.dashPointIndexs = v;
}
get grayPointIndexs(): number[] {
return this.data.grayPointIndexs;
}
set grayPointIndexs(v: number[]) {
this.data.grayPointIndexs = v;
}
get lineColor(): string {
return this.data.lineColor;
}
set lineColor(v: string) {
this.data.lineColor = v;
}
clone(): RunLineData {
return new RunLineData(this.data.cloneMessage());
}
@ -113,12 +124,20 @@ export const clearWaypointsConfig: MenuItemOptions = {
export const setDashLineConfig: MenuItemOptions = {
name: '设置虚线段',
};
export const setGrayLineConfig: MenuItemOptions = {
name: '设置灰线段',
};
const RunLineEditMenu: ContextMenu = ContextMenu.init({
name: '运行线编辑菜单',
groups: [
{
items: [addWaypointConfig, clearWaypointsConfig, setDashLineConfig],
items: [
addWaypointConfig,
clearWaypointsConfig,
setDashLineConfig,
setGrayLineConfig,
],
},
],
});
@ -133,12 +152,12 @@ const EpEditMenu: ContextMenu = ContextMenu.init({
export class DrawRunLinePlugin extends GraphicInteractionPlugin<RunLine> {
static Name = 'runline_draw_right_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(DrawRunLinePlugin.Name, app);
app.registerMenu(RunLineEditMenu);
app.registerMenu(EpEditMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new DrawRunLinePlugin(app);
}
filter(...grahpics: JlGraphic[]): RunLine[] | undefined {
@ -195,7 +214,7 @@ export class DrawRunLinePlugin extends GraphicInteractionPlugin<RunLine> {
};
setDashLineConfig.handler = () => {
Dialog.create({
title: '创建列车',
title: '设置虚线段',
message: '',
component: SetDashLineDialog,
componentProps: {
@ -215,17 +234,40 @@ export class DrawRunLinePlugin extends GraphicInteractionPlugin<RunLine> {
runLine.doRepaint();
});
};
setGrayLineConfig.handler = () => {
console.log(runLine.datas, '11111');
Dialog.create({
title: '设置灰线段',
message: '',
component: SetGaryLineDialog,
componentProps: {
runLinePoints: runLine.datas.points,
garyPointIndexs: runLine.datas.grayPointIndexs,
},
cancel: true,
persistent: true,
}).onOk((data: { min: number; max: number }) => {
const indexList = [];
if (data.min !== data.max) {
for (let i = data.min; i <= data.max; i++) {
indexList.push(i);
}
}
runLine.datas.grayPointIndexs = indexList;
runLine.doRepaint();
});
};
RunLineEditMenu.open(e.global);
}
}
export class RunLineOperateInteraction extends GraphicInteractionPlugin<RunLine> {
static Name = 'runLine_operate_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(RunLineOperateInteraction.Name, app);
app.registerMenu(EpEditMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new RunLineOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): RunLine[] | undefined {

View File

@ -2,7 +2,9 @@ import * as pb_1 from 'google-protobuf';
import { GraphicDataBase } from './GraphicDataBase';
import { ISectionData, Section } from 'src/graphics/section/Section';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IPointData } from 'pixi.js';
import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js';
import { GraphicInteractionPlugin, IGraphicApp, JlGraphic } from 'jl-graphic';
import { SectionGraphicHitArea } from 'src/graphics/section/SectionDrawAssistant';
export class SectionData extends GraphicDataBase implements ISectionData {
constructor(data?: graphicData.Section) {
@ -51,16 +53,16 @@ export class SectionData extends GraphicDataBase implements ISectionData {
set sectionType(type: graphicData.Section.SectionType) {
this.data.sectionType = type;
}
get axleCountings(): string[] {
return this.data.axleCountings;
get axleCountings(): number[] {
return this.data.axleCountings.map((a) => Number(a));
}
set axleCountings(axleCountings: string[]) {
this.data.axleCountings = axleCountings;
set axleCountings(axleCountings: number[]) {
this.data.axleCountings = axleCountings.map((a) => a.toString());
}
get children(): string[] {
get children(): number[] {
return this.data.children;
}
set children(children: string[]) {
set children(children: number[]) {
this.data.children = children;
}
get destinationCode(): string {
@ -69,6 +71,18 @@ export class SectionData extends GraphicDataBase implements ISectionData {
set destinationCode(destinationCode: string) {
this.data.destinationCode = destinationCode;
}
get turning(): boolean {
return this.data.turning;
}
set turning(v: boolean) {
this.data.turning = v;
}
get centralizedStation(): number {
return this.data.centralizedStationId;
}
set centralizedStation(v: number) {
this.data.centralizedStationId = v;
}
clone(): SectionData {
return new SectionData(this.data.cloneMessage());
}
@ -79,3 +93,30 @@ export class SectionData extends GraphicDataBase implements ISectionData {
return pb_1.Message.equals(this.data, other.data);
}
}
export class sectionOperationPlugin extends GraphicInteractionPlugin<Section> {
static Name = 'logic_section_menu';
constructor(app: IGraphicApp) {
super(sectionOperationPlugin.Name, app);
}
filter(...grahpics: JlGraphic[]): Section[] | undefined {
return grahpics.filter((g): g is Section => g instanceof Section);
}
static init(app: IGraphicApp) {
return new sectionOperationPlugin(app);
}
bind(g: Section): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.lineGraphic.hitArea = new SectionGraphicHitArea(g);
g.on('_leftclick', this.onLeftClick, this);
}
unbind(g: Section): void {
g.off('_leftclick', this.onLeftClick, this);
}
onLeftClick(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const section = target.getGraphic() as Section;
this.app.updateSelected(section);
}
}

View File

@ -9,15 +9,16 @@ import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import {
GraphicInteractionPlugin,
GraphicApp,
IGraphicApp,
JlGraphic,
} from 'src/jl-graphic';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
ContextMenu,
MenuItemOptions,
} from 'jl-graphic';
import { FederatedMouseEvent, DisplayObject } from 'pixi.js';
import { state } from 'src/protos/device_status';
import { mockSignalApi } from 'src/api/PlatformApi';
import { useLineStore } from 'src/stores/line-store';
import { SignalGraphicHitArea } from 'src/graphics/signal/SignalDrawAssistant';
export class SignalData extends GraphicDataBase implements ISignalData {
constructor(data?: graphicData.Signal) {
@ -46,12 +47,27 @@ export class SignalData extends GraphicDataBase implements ISignalData {
set mirror(v: boolean) {
this.data.mirror = v;
}
get refDevice(): graphicData.RelatedRef {
return this.data.refDevice;
}
set refDevice(v: graphicData.RelatedRef) {
this.data.refDevice = v;
}
get kilometerSystem(): KilometerSystem {
if (!this.data.kilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem();
}
return this.data.kilometerSystem;
}
set kilometerSystem(v: KilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem(v);
}
get centralizedStation(): number {
return this.data.centralizedStationId;
}
set centralizedStation(v: number) {
this.data.centralizedStationId = v;
}
clone(): SignalData {
return new SignalData(this.data.cloneMessage());
}
@ -215,6 +231,13 @@ export class SignalState extends GraphicStateBase implements ISignalState {
set lampFailure(v: boolean) {
this.states.lampFailure = v;
}
// 集中站站号
get rtuId(): number {
return this.states.rtuId;
}
set rtuId(value: number) {
this.states.rtuId = value;
}
get states(): state.Signal {
return this.getState<state.Signal>();
}
@ -275,11 +298,11 @@ const SignalOperateMenu: ContextMenu = ContextMenu.init({
});
export class DrawSignalInteraction extends GraphicInteractionPlugin<Signal> {
static Name = 'signal_draw_right_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(DrawSignalInteraction.Name, app);
app.registerMenu(SignalEditMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new DrawSignalInteraction(app);
}
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
@ -308,11 +331,11 @@ export class DrawSignalInteraction extends GraphicInteractionPlugin<Signal> {
export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
static Name = 'signal_operate_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(SignalOperateInteraction.Name, app);
app.registerMenu(SignalOperateMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new SignalOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
@ -324,6 +347,7 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
g.eventMode = 'static';
g.cursor = 'pointer';
g.selectable = true;
g.lampMainBody.hitArea = new SignalGraphicHitArea(g);
g.on('_rightclick', this.onContextMenu, this);
}

View File

@ -7,17 +7,17 @@ import {
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_status';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import {
GraphicApp,
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
MenuItemOptions,
ContextMenu,
} from 'jl-graphic';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { KilometerSystem } from 'src/graphics/signal/Signal';
import { useLineStore } from 'src/stores/line-store';
import { mockStationApi } from 'src/api/PlatformApi';
import { mockServerApi, mockStationApi } from 'src/api/PlatformApi';
export class StationData extends GraphicDataBase implements IStationData {
constructor(data?: graphicData.Station) {
@ -42,6 +42,9 @@ export class StationData extends GraphicDataBase implements IStationData {
this.data.code = v;
}
get kilometerSystem(): KilometerSystem {
if (!this.data.kilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem();
}
return this.data.kilometerSystem;
}
set kilometerSystem(v: KilometerSystem) {
@ -65,6 +68,18 @@ export class StationData extends GraphicDataBase implements IStationData {
set name(v: string) {
this.data.name = v;
}
get manageStations(): number[] {
return this.data.manageStations;
}
set manageStations(v: number[]) {
this.data.manageStations = v;
}
get depots(): boolean {
return this.data.depots;
}
set depots(v: boolean) {
this.data.depots = v;
}
clone(): StationData {
return new StationData(this.data.cloneMessage());
}
@ -88,7 +103,11 @@ export class StationState extends GraphicStateBase implements IStationState {
}
get code(): string {
return this.states.id;
if (this.states.id.length === 1) {
return '0' + this.states.id;
} else {
return this.states.id;
}
}
get ipRtuStusDown(): boolean {
return this.states.ipRtuStusDown;
@ -117,6 +136,13 @@ export class StationState extends GraphicStateBase implements IStationState {
get states(): state.Rtu {
return this.getState<state.Rtu>();
}
// 集中站站号
get rtuId(): number {
return this.states.rtuId;
}
set rtuId(value: number) {
this.states.rtuId = value;
}
clone(): StationState {
return new StationState(this.states.cloneMessage());
}
@ -128,32 +154,32 @@ export class StationState extends GraphicStateBase implements IStationState {
}
}
const powerUnlockConfig: MenuItemOptions = {
name: '上电解锁',
const resetConfig: MenuItemOptions = {
name: '重置状态',
};
const buleShow: MenuItemOptions = {
name: '蓝显',
};
const cancelBuleShow: MenuItemOptions = {
name: '取消蓝显',
};
const chainConfig: MenuItemOptions = {
name: '全站设置连锁自动触发',
};
const removeChainConfig: MenuItemOptions = {
name: '全站取消连锁自动触发',
};
const StationOperateMenu: ContextMenu = ContextMenu.init({
name: '车站操作菜单',
groups: [
{
items: [powerUnlockConfig, chainConfig, removeChainConfig],
items: [resetConfig, buleShow, cancelBuleShow],
},
],
});
export class StationOperateInteraction extends GraphicInteractionPlugin<Station> {
static Name = 'station_operate_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(StationOperateInteraction.Name, app);
app.registerMenu(StationOperateMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new StationOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): Station[] | undefined {
@ -187,34 +213,30 @@ export class StationOperateInteraction extends GraphicInteractionPlugin<Station>
ipRtuStusInEmergencyCtrl: false,
id: station.id,
};
powerUnlockConfig.handler = () => {
/* station.states.ipRtuStusInLocalCtrl = true;
station.doRepaint(); */
const dataCopy = JSON.parse(JSON.stringify(data));
dataCopy.ipRtuStusInLocalCtrl = true;
mockStationApi(lineId, dataCopy)
.then((res) => {
console.log(res, '---res--');
})
.catch((err) => {
console.log(err, '---err---');
});
buleShow.handler = () => {
const data = {
deviceType: 'DEVICE_TYPE_RTU',
messageId: 'DEVICE_STATUS_CHANGE',
lineId: 3,
rtuId: station.states.rtuId,
deviceName: station.states.rtuId + '',
deviceStatus: 32768,
};
mockServerApi(data);
};
chainConfig.handler = () => {
const dataCopy = JSON.parse(JSON.stringify(data));
dataCopy.ipRtuStusInLocalCtrl = true;
dataCopy.ipRtuStusDown = true;
mockStationApi(lineId, dataCopy)
.then((res) => {
console.log(res, '---res--');
})
.catch((err) => {
console.log(err, '---err---');
});
cancelBuleShow.handler = () => {
const data = {
deviceType: 'DEVICE_TYPE_RTU',
messageId: 'DEVICE_STATUS_CHANGE',
lineId: 3,
rtuId: station.states.rtuId,
deviceName: station.states.rtuId + '',
deviceStatus: 1,
};
mockServerApi(data);
};
removeChainConfig.handler = () => {
resetConfig.handler = () => {
const dataCopy = JSON.parse(JSON.stringify(data));
dataCopy.ipRtuStusInLocalCtrl = false;
mockStationApi(lineId, dataCopy)
.then((res) => {
console.log(res, '---res--');

View File

@ -43,6 +43,12 @@ export class StationLineData
set hideName(v: boolean) {
this.data.hideName = v;
}
get color(): graphicData.StationLine.stationColor {
return this.data.codeColor;
}
set color(v: graphicData.StationLine.stationColor) {
this.data.codeColor = v;
}
clone(): StationLineData {
return new StationLineData(this.data.cloneMessage());
}

View File

@ -4,14 +4,14 @@ import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_status';
import { train } from 'src/protos/train';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import {
GraphicApp,
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
VectorText,
} from 'src/jl-graphic';
MenuItemOptions,
ContextMenu,
} from 'jl-graphic';
import {
Color,
Container,
@ -69,6 +69,11 @@ export class TrainState extends GraphicStateBase implements ITrainState {
get code(): string {
return this.states.groupId;
}
get remove(): boolean {
const rtuIdArr = [81, 82];
const hasRtuId = rtuIdArr.includes(this.states.rtuId);
return hasRtuId;
}
get states(): train.TrainInfo {
return this.getState<train.TrainInfo>();
@ -194,12 +199,12 @@ export class TrainState extends GraphicStateBase implements ITrainState {
set rate(v: number) {
this.states.rate = v;
}
get remove(): train.TrainRemove {
return this.states.remove;
}
set remove(v: train.TrainRemove) {
this.states.remove = new train.TrainRemove(v);
}
// get remove(): train.TrainRemove {
// return this.states.remove;
// }
// set remove(v: train.TrainRemove) {
// this.states.remove = new train.TrainRemove(v);
// }
get block(): train.TrainBlock {
return this.states.block;
}
@ -269,13 +274,12 @@ const TrainOperateMenu: ContextMenu = ContextMenu.init({
export class TrainOperateInteraction extends GraphicInteractionPlugin<Train> {
static Name = 'train_operate_menu';
hoverLaber: TrainHoverLabel;
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(TrainOperateInteraction.Name, app);
this.hoverLaber = new TrainHoverLabel();
app.canvas.addChild(this.hoverLaber);
app.registerMenu(TrainOperateMenu);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new TrainOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): Train[] | undefined {
@ -290,7 +294,7 @@ export class TrainOperateInteraction extends GraphicInteractionPlugin<Train> {
this.onMouseHover(g);
};
g.trainbody.onmouseout = () => {
this.onMouseOut();
this.onMouseOut(g);
};
}
@ -304,13 +308,15 @@ export class TrainOperateInteraction extends GraphicInteractionPlugin<Train> {
onMouseHover(g: Train): void {
if (!this.hoverLaber.isShow) {
g.addChild(this.hoverLaber);
this.hoverLaber.doRepaint(g.states);
const bodyWh = g.trainbody.localBoundsToCanvasPoints();
this.hoverLaber.position.set(bodyWh[2].x, bodyWh[2].y);
const bodyWh = g.trainbody.getBodyWH();
this.hoverLaber.position.set(bodyWh.width / 2, bodyWh.height / 2);
}
}
onMouseOut(): void {
onMouseOut(g: Train): void {
if (this.hoverLaber.isShow) {
g.removeChild(this.hoverLaber);
this.hoverLaber.clear();
}
}
@ -430,6 +436,7 @@ const labelConsts = {
codeFontSize: 12,
};
class TrainHoverLabel extends Container {
static Type = 'TrainHoverLabel';
boxRact: Graphics = new Graphics();
sText: VectorText = new VectorText('');
isShow: boolean;
@ -446,7 +453,12 @@ class TrainHoverLabel extends Container {
fill: labelConsts.textColor,
fontSize: labelConsts.codeFontSize,
};
const text = `列车类型:计划车\n来 源:人工标记\n车 组 号:${states.groupId}\n表 号:${states.trainId}\n车 次 号:${states.globalId}`;
const codeA = states.groupId;
// const firstChar = codeA.substring(0, 1); // 获取首字符
// if (+firstChar == states.lineId) {
// codeA = codeA.substring(1); // 删除首字符是线路号的字符
// }
const text = `列车类型:计划车\n来 源:人工标记\n车 组 号:${codeA}\n表 号:${states.trainId}\n车 次 号:${states.globalId}\n线 路 号:${states.lineId}`;
this.sText.text = text;
this.sText.style = style;
const { width: codeWidth, height: codeHeight } =

View File

@ -31,10 +31,10 @@ export class TrainWindowData
set code(v: string) {
this.data.code = v;
}
get refDeviceId(): string[] {
get refDeviceId(): number[] {
return this.data.refDeviceId;
}
set refDeviceId(v: string[]) {
set refDeviceId(v: number[]) {
this.data.refDeviceId = v;
}
clone(): TrainWindowData {

View File

@ -10,18 +10,19 @@ import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js';
import { KilometerSystem } from 'src/graphics/signal/Signal';
import { state } from 'src/protos/device_status';
import {
GraphicApp,
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
} from 'src/jl-graphic';
ContextMenu,
MenuItemOptions,
} from 'jl-graphic';
import {
ForkHitArea,
TurnoutSectionHitArea,
} from 'src/graphics/turnout/TurnoutDrawAssistant';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { setSwitchStatus } from 'src/api/TurnoutApi';
import { useLineStore } from 'src/stores/line-store';
import { successNotify } from 'src/utils/CommonNotify';
let menuItemHandler: (propName: keyof ITurnoutState) => void;
@ -102,7 +103,10 @@ const ipSingleSwitchStusLostIndication: MenuItemOptions = {
name: '道岔失表示-ipSingleSwitchStusLostIndication',
handler: () => menuItemHandler('ipSingleSwitchStusLostIndication'),
};
const speedLimit: MenuItemOptions = {
name: '限速 - speedLimit',
handler: () => menuItemHandler('speedLimit'),
};
const TurnoutOperateMenu = ContextMenu.init({
name: 'Turnout操作菜单',
groups: [
@ -127,6 +131,7 @@ const TurnoutOperateMenu = ContextMenu.init({
ipSingleSwitchStusTsrBmReverse,
ipSingleSwitchStusBlocked2,
ipSingleSwitchStusLostIndication,
speedLimit,
],
},
],
@ -134,14 +139,14 @@ const TurnoutOperateMenu = ContextMenu.init({
export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
static Name = 'turnout_operate_menu';
constructor(app: GraphicApp) {
constructor(app: IGraphicApp) {
super(TurnoutOperationPlugin.Name, app);
app.registerMenu(TurnoutOperateMenu);
}
filter(...grahpics: JlGraphic[]): Turnout[] | undefined {
return grahpics.filter((g): g is Turnout => g instanceof Turnout);
}
static init(app: GraphicApp) {
static init(app: IGraphicApp) {
return new TurnoutOperationPlugin(app);
}
bind(g: Turnout): void {
@ -153,6 +158,7 @@ export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
sectionGraphic.cursor = 'pointer';
sectionGraphic.hitArea = new TurnoutSectionHitArea(sectionGraphic);
});
g.on('_leftclick', this.onLeftClick, this);
g.on('rightclick', this.onContextMenu, this);
}
unbind(g: Turnout): void {
@ -160,8 +166,14 @@ export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
g.graphics.sections.forEach((sectionGraphic) => {
sectionGraphic.eventMode = 'none';
});
g.off('_leftclick', this.onLeftClick, this);
g.on('rightclick', this.onContextMenu, this);
}
onLeftClick(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const section = target.getGraphic() as Turnout;
this.app.updateSelected(section);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const turnout = target.getGraphic() as Turnout;
@ -193,6 +205,7 @@ export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
ipSingleSwitchStusBlocked2: turnout.states.ipSingleSwitchStusBlocked2, // 道岔封锁
ipSingleSwitchStusLostIndication:
turnout.states.ipSingleSwitchStusLostIndication, // 道岔失表示
speedLimit: turnout.states.speedLimit,
};
(Object.keys(state) as unknown as (keyof ITurnoutState)[]).forEach(
(key: keyof ITurnoutState) => {
@ -220,10 +233,17 @@ export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
menuItemHandler = (propName) => {
const lineId = useLineStore().lineId?.toString();
if (!lineId) return;
let val: boolean | number;
if (propName !== 'speedLimit') {
val = !turnout.states[propName];
} else {
val = turnout.states[propName] > 0 ? 0 : 20;
successNotify(`限速设为${val}`);
}
setSwitchStatus(lineId, {
...state,
id: turnout.datas.code,
[propName]: !turnout.states[propName],
[propName]: val,
});
};
TurnoutOperateMenu.open(e.global);
@ -301,13 +321,24 @@ export class TurnoutData extends GraphicDataBase implements ITurnoutData {
this.data.pcRef = ref;
}
get kilometerSystem(): KilometerSystem[] {
return this.data.kilometerSystem;
return this.data.kilometerSystem.length > 0
? this.data.kilometerSystem
: (this.data.kilometerSystem = [
new graphicData.KilometerSystem(),
new graphicData.KilometerSystem(),
]);
}
set kilometerSystem(value: KilometerSystem[]) {
this.data.kilometerSystem = value.map(
(v) => new graphicData.KilometerSystem(v)
);
}
get centralizedStation(): number {
return this.data.centralizedStationId;
}
set centralizedStation(v: number) {
this.data.centralizedStationId = v;
}
clone(): TurnoutData {
return new TurnoutData(this.data.cloneMessage());
}
@ -446,8 +477,25 @@ export class TurnoutStates extends GraphicStateBase implements ITurnoutState {
public set ipSingleSwitchStusLostIndication(value: boolean) {
this.states.ipSingleSwitchStusLostIndication = value;
}
id?: string;
speedLimit?: number;
public get id(): string {
return this.states.id;
}
public set id(value: string) {
this.states.id = value;
}
// 集中站站号
public get rtuId(): number {
return this.states.rtuId;
}
public set rtuId(value: number) {
this.states.rtuId = value;
}
get speedLimit(): number {
return this.states.speedLimit;
}
set speedLimit(val: number) {
this.states.speedLimit = val;
}
get states(): state.Switch {
return this.getState<state.Switch>();
}

View File

@ -7,13 +7,14 @@ import { Signal, SignalTemplate } from 'src/graphics/signal/Signal';
import { SignalDraw } from 'src/graphics/signal/SignalDrawAssistant';
import {
CombinationKey,
GraphicApp,
GraphicData,
JlDrawApp,
IDrawApp,
KeyListener,
} from 'src/jl-graphic';
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
newDrawApp,
IGraphicStorage,
ContextMenu,
MenuItemOptions,
} from 'jl-graphic';
import { IscsFanData } from './graphics/IscsFanInteraction';
import { LinkData } from './graphics/LinkInteraction';
import { TrainData, TrainState } from './graphics/TrainInteraction';
@ -23,6 +24,12 @@ import {
SignalState,
} from './graphics/SignalInteraction';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import {
ConcentrationDividingLine,
ConcentrationDividingLineTemplate,
} from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
import { ConcentrationDividingLineData } from './graphics/ConcentrationDividingLineInteraction';
import { ConcentrationDividingLineDraw } from 'src/graphics/concentrationDividingLine/ConcentrationDividingLineDrawAssistant';
import { Rect, RectTemplate } from 'src/graphics/rect/Rect';
import { RectDraw } from 'src/graphics/rect/RectDrawAssistant';
import { RectData } from './graphics/RectInteraction';
@ -120,7 +127,7 @@ import { FederatedMouseEvent } from 'pixi.js';
// });
// }
function constructMenu(app: JlDrawApp): (e: FederatedMouseEvent) => void {
function constructMenu(app: IDrawApp): (e: FederatedMouseEvent) => void {
const UndoOptions: MenuItemOptions = {
name: '撤销',
};
@ -203,9 +210,9 @@ function constructMenu(app: JlDrawApp): (e: FederatedMouseEvent) => void {
};
return handleRightClick;
}
let drawApp: JlDrawApp | null = null;
let drawApp: IDrawApp | null = null;
export function getDrawApp(): JlDrawApp | null {
export function getDrawApp(): IDrawApp | null {
return drawApp;
}
@ -216,35 +223,18 @@ export function destroyDrawApp(): void {
}
}
export function initDrawApp(dom: HTMLElement): JlDrawApp {
drawApp = new JlDrawApp(dom);
export function initDrawApp(): IDrawApp {
drawApp = newDrawApp({
dataLoader: loadDrawDatas,
});
const app = drawApp;
//根据草稿图类型加载绘图工具
let drawAssistants: (
| PlatformDraw
| StationDraw
| SignalDraw
| TurnoutDraw
| RunLineDraw
| SectionDraw
| LogicSectionDraw
| StationLineDraw
| RectDraw
| TrainLineDraw
| PathLineDraw
| TrainWindowDraw
| TrainDraw
| OneClickGenerateDraw
| AxleCountingDraw
| SeparatorDraw
)[] = [];
const draftType = useDrawStore().$state.draftType;
if (draftType === 'Line') {
drawAssistants = [
new PlatformDraw(
app,
new PlatformTemplate(new PlatformData(), new PlatformState())
),
new PlatformDraw(
app,
new PlatformTemplate(new PlatformData(), new PlatformState())
),
new StationDraw(
app,
new StationTemplate(new StationData(), new StationState())
@ -273,11 +263,15 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
new AxleCountingTemplate(new AxleCountingData())
),
new SeparatorDraw(app, new SeparatorTemplate(new SeparatorData())),
];
new ConcentrationDividingLineDraw(
app,
new ConcentrationDividingLineTemplate(
new ConcentrationDividingLineData()
)
);
DrawSignalInteraction.init(app);
} else {
drawAssistants = [
new StationLineDraw(app, new StationLineTemplate(new StationLineData())),
new StationLineDraw(app, new StationLineTemplate(new StationLineData())),
new RectDraw(app, new RectTemplate(new RectData())),
new RunLineDraw(app, new RunLineTemplate(new RunLineData())),
new TrainLineDraw(
@ -285,14 +279,11 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
new ItrainLineTemplate(new TrainLineData(), new TrainLineState())
),
new PathLineDraw(app, new PathLineTemplate(new PathLineData())),
];
DrawRunLinePlugin.init(app);
DrawRunLinePlugin.init(app);
}
app.setOptions({ drawAssistants: drawAssistants });
const handleRIghtClick = constructMenu(app);
app.canvas.on('_rightclick', (e) => {
if (app._drawing) return;
if (app.drawing) return;
handleRIghtClick(e);
});
app.addKeyboardListener(
@ -308,7 +299,7 @@ export function initDrawApp(dom: HTMLElement): JlDrawApp {
return drawApp;
}
export function saveDrawToServer(app: JlDrawApp) {
export function saveDrawToServer(app: IDrawApp) {
const base64 = saveDrawDatas(app);
const drawStore = useDrawStore();
const id = drawStore.draftId;
@ -325,7 +316,7 @@ export function saveDrawToServer(app: JlDrawApp) {
}
// const StorageKey = 'graphic-storage';
export function saveDrawDatas(app: JlDrawApp) {
export function saveDrawDatas(app: IDrawApp) {
const storage = new graphicData.RtssGraphicStorage();
const canvasData = app.canvas.saveData();
storage.canvas = new graphicData.Canvas({
@ -385,22 +376,105 @@ export function saveDrawDatas(app: JlDrawApp) {
} else if (LogicSection.Type === g.type) {
const logicSectionData = (g as LogicSection).saveData();
storage.logicSections.push((logicSectionData as LogicSectionData).data);
} else if (g instanceof ConcentrationDividingLine) {
const concentrationDividingLineData = g.saveData();
storage.concentrationDividingLines.push(
(concentrationDividingLineData as ConcentrationDividingLineData).data
);
}
});
// storage.Platforms.forEach((item) => {
// item.common.nid = +item.common.id;
// item.nrefStation = +item.refStation;
// item.nrefSectionId = +item.refSectionId;
// });
// storage.axleCountings.forEach((item) => {
// item.common.nid = +item.common.id;
// item.axleCountingRef = item.axleCountingRef.map((child) => {
// child.nid = +child.id;
// return child;
// });
// });
// storage.iscsFans.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.links.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.logicSections.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.pathLines.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.polygons.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.rects.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.runLines.forEach((item) => {
// item.common.nid = +item.common.id;
// item.nlinkPathLines = item.linkPathLines.map((child) => +child);
// });
// storage.section.forEach((item) => {
// item.common.nid = +item.common.id;
// if (item.paRef) {
// item.paRef.nid = +item.paRef.id;
// }
// if (item.pbRef) {
// item.pbRef.nid = +item.pbRef.id;
// }
// item.nchildren = item.children.map((child) => +child);
// });
// storage.separators.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.signals.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.stationLines.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.stations.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.train.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.trainLines.forEach((item) => {
// item.common.nid = +item.common.id;
// });
// storage.trainWindows.forEach((item) => {
// item.common.nid = +item.common.id;
// item.nrefDeviceId = item.refDeviceId.map((child) => +child);
// });
// storage.turnouts.forEach((item) => {
// item.common.nid = +item.common.id;
// if (item.paRef) {
// item.paRef.nid = +item.paRef.id;
// }
// if (item.pbRef) {
// item.pbRef.nid = +item.pbRef.id;
// }
// if (item.pcRef) {
// item.pcRef.nid = +item.pcRef.id;
// }
// });
const base64 = fromUint8Array(storage.serialize());
console.log('保存数据', storage);
// localStorage.setItem(StorageKey, base64);
return base64;
}
export async function loadDrawDatas(app: GraphicApp) {
export async function loadDrawDatas(): Promise<IGraphicStorage> {
// localStorage.removeItem(StorageKey);
// const base64 = localStorage.getItem(StorageKey);
// console.log('加载数据', base64);
const drawStore = useDrawStore();
const id = drawStore.draftId;
if (!id) {
return;
throw new Error('获取数据异常未获取到草稿地图ID');
}
const { proto: base64 } = await getDraft(id);
if (base64) {
@ -408,7 +482,6 @@ export async function loadDrawDatas(app: GraphicApp) {
toUint8Array(base64)
);
console.log('加载数据', storage);
app.updateCanvas(storage.canvas);
const datas: GraphicData[] = [];
storage.links.forEach((link) => {
datas.push(new LinkData(link));
@ -461,8 +534,15 @@ export async function loadDrawDatas(app: GraphicApp) {
storage.trainWindows.forEach((trainWindow) => {
datas.push(new TrainWindowData(trainWindow));
});
app.loadGraphic(datas);
} else {
app.loadGraphic([]);
storage.concentrationDividingLines.forEach((concentrationDividingLine) => {
datas.push(new ConcentrationDividingLineData(concentrationDividingLine));
});
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
});
}
return Promise.resolve({
datas: [],
});
}

View File

@ -1,4 +1,11 @@
import { GraphicApp, GraphicData, GraphicState } from 'src/jl-graphic';
import {
ClientEngine,
GraphicData,
GraphicState,
IGraphicApp,
IGraphicStorage,
newGraphicApp,
} from 'jl-graphic';
import {
TrainData,
TrainOperateInteraction,
@ -29,7 +36,10 @@ import {
TurnoutStates,
} from './graphics/TurnoutInteraction';
import { Turnout, TurnoutTemplate } from 'src/graphics/turnout/Turnout';
import { SectionData } from './graphics/SectionInteraction';
import {
SectionData,
sectionOperationPlugin,
} from './graphics/SectionInteraction';
import { SectionTemplate } from 'src/graphics/section/Section';
import { getPublishMapInfoByLineId } from 'src/api/PublishApi';
import { graphicData } from 'src/protos/stationLayoutGraphics';
@ -50,11 +60,7 @@ import {
import { TrainWindowData } from './graphics/TrainWindowInteraction';
import { SeparatorTemplate } from 'src/graphics/separator/Separator';
import { SeparatorData } from './graphics/SeparatorInteraction';
let lineApp: GraphicApp | null = null;
import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu';
import { MenuItemOptions } from 'src/jl-graphic/ui/Menu';
import { ContextMenu, MenuItemOptions } from 'jl-graphic';
import {
LogicSection,
LogicSectionTemplate,
@ -64,21 +70,13 @@ import {
LogicSectionOperationPlugin,
LogicSectionState,
} from './graphics/LogicSectionInteraction';
import { alert } from 'src/protos/alertInfo';
import { Notify, QNotifyUpdateOptions } from 'quasar';
import { useLineNetStore } from 'src/stores/line-net-store';
import { QNotifyUpdateOptions, Notify } from 'quasar';
import { alert } from 'src/protos/alertInfo';
// const QuickJumpMenu = new ContextMenu({
// name: '快捷跳转',
// groups: [
// {
// items: [],
// },
// ],
// });
// let QuickJumpMenu: ContextMenu = new ContextMenu();
let lineApp: IGraphicApp | null = null;
export function getLineApp(): GraphicApp | null {
export function getLineApp() {
return lineApp;
}
@ -89,8 +87,27 @@ export function destroyLineApp(): void {
}
}
export function initLineApp(dom: HTMLElement): GraphicApp {
lineApp = new GraphicApp(dom);
export function initLineApp(): IGraphicApp {
if (lineApp) return lineApp;
lineApp = newGraphicApp({
interactiveGraphicTypeIncludes: [
Signal.Type,
Platform.Type,
Station.Type,
Train.Type,
LogicSection.Type,
Turnout.Type,
],
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
viewportDragLeft: true,
wheelZoom: true,
},
dataLoader: loadLineDatas,
});
const graphicTemplate = [
new TrainTemplate(new TrainData(), new TrainState()),
new SignalTemplate(new SignalData(), new SignalState()),
@ -104,67 +121,100 @@ export function initLineApp(dom: HTMLElement): GraphicApp {
new TrainWindowTemplate(new TrainWindowData()),
];
lineApp.registerGraphicTemplates(...graphicTemplate);
lineApp.setOptions({
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
wheelZoom: true,
},
interactiveTypeOptions: {
interactiveGraphicTypeIncludes: [
Signal.Type,
Platform.Type,
Station.Type,
Train.Type,
LogicSection.Type,
Turnout.Type,
],
},
});
SignalOperateInteraction.init(lineApp);
PlatformOperateInteraction.init(lineApp);
StationOperateInteraction.init(lineApp);
TrainOperateInteraction.init(lineApp);
TurnoutOperationPlugin.init(lineApp);
LogicSectionOperationPlugin.init(lineApp);
sectionOperationPlugin.init(lineApp);
lineApp.enableWsMassaging({
engine: ClientEngine.Stomp,
wsUrl: getWebsocketUrl(),
token: getJwtToken() as string,
});
let msgNotify: null | ((props?: QNotifyUpdateOptions | undefined) => void) =
null;
lineApp.on('websocket-connect-state-change', (connected) => {
if (!connected && !msgNotify) {
msgNotify = Notify.create({
type: 'negative',
timeout: 0,
position: 'top-right',
message: '与WebSocket服务连接断开',
classes: 'my-notif-class',
});
} else if (msgNotify && connected) {
msgNotify();
msgNotify = null;
}
});
lineApp.reload().then(() => {
if (!lineApp) return;
const quickJumpMenu = new ContextMenu({
name: '快捷跳转',
groups: [
{
items: lineApp.queryStore
.queryByType<Station>(Station.Type)
.map<MenuItemOptions>((station) => ({
name: station.datas.name ?? '',
handler: () => {
lineApp?.makeGraphicCenterShow(station);
},
})),
},
],
});
lineApp.registerMenu(quickJumpMenu);
lineApp.canvas.on('_rightclick', (e) => {
quickJumpMenu.open(e.global);
});
const axleCountings = lineApp.queryStore.queryByType<AxleCounting>(
AxleCounting.Type
);
axleCountings.forEach((axleCounting) => {
axleCounting.visible = false;
});
const trainWindows = lineApp.queryStore.queryByType<TrainWindow>(
TrainWindow.Type
);
trainWindows.forEach((trainWindow) => {
trainWindow.visible = false;
});
handleSubscribe(lineApp);
});
return lineApp;
}
export async function loadLineDatas(app: GraphicApp) {
export async function loadLineDatas(): Promise<IGraphicStorage> {
const lineStore = useLineStore();
const lineId = lineStore.lineId;
if (!lineId) {
return;
throw Error('请先选择线路');
}
const { proto: base64, name: lineName } = await getPublishMapInfoByLineId(
lineId,
'line'
);
lineStore.setLineName(lineName);
const datas: GraphicData[] = [];
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(
toUint8Array(base64)
);
console.log('加载数据', storage);
app.updateCanvas(storage.canvas);
const datas: GraphicData[] = [];
storage.Platforms.forEach((platform) => {
const g = new PlatformData(platform);
datas.push(g);
});
const quickJumpMenuItem: MenuItemOptions[] = [];
storage.stations.forEach((station) => {
datas.push(new StationData(station));
const item: MenuItemOptions = {
name: station.name,
handler: () => {
const g = app.queryStore.queryById(station.common.id);
if (g) {
app.makeGraphicCenterShow(g);
}
},
};
quickJumpMenuItem.push(item);
});
storage.train.forEach((train) => {
datas.push(new TrainData(train));
@ -190,96 +240,75 @@ export async function loadLineDatas(app: GraphicApp) {
storage.trainWindows.forEach((trainWindow) => {
datas.push(new TrainWindowData(trainWindow));
});
await app.loadGraphic(datas);
//隐藏计轴--和车次窗
const axleCountings = app.queryStore.queryByType<AxleCounting>(
AxleCounting.Type
);
axleCountings.forEach((axleCounting) => {
axleCounting.visible = false;
});
const trainWindows = app.queryStore.queryByType<TrainWindow>(
TrainWindow.Type
);
trainWindows.forEach((trainWindow) => {
trainWindow.visible = false;
});
const QuickJumpMenu = new ContextMenu({
name: '快捷跳转',
groups: [
{
items: quickJumpMenuItem,
},
],
});
app.registerMenu(QuickJumpMenu);
app.canvas.on('_rightclick', (e) => {
QuickJumpMenu.open(e.global);
});
app.enableWsMassaging({
wsUrl: `${getWebsocketUrl()}`,
token: getJwtToken() as string,
});
app.subscribe({
destination: `/queue/line/${lineId}/device`,
messageConverter: (message: Uint8Array) => {
const states: GraphicState[] = [];
const storage = state.WsLineMessage.deserialize(message);
storage.signal.forEach((item) => {
states.push(new SignalState(item));
});
storage.platform.forEach((item) => {
states.push(new PlatformState(item));
});
storage.rtu.forEach((item) => {
states.push(new StationState(item));
});
storage.switch.forEach((item) => {
states.push(new TurnoutStates(item));
});
storage.track.forEach((item) => {
states.push(new LogicSectionState(item));
});
return states;
},
});
app.subscribe({
destination: `/queue/line/${lineId}/train`,
messageConverter: (message: Uint8Array) => {
const states: GraphicState[] = [];
const trainStorage = state.WsLineTrainMessage.deserialize(message);
trainStorage.trainInfo.forEach((item) => {
states.push(new TrainState(item));
});
return states;
},
});
let msgNotify: null | ((props?: QNotifyUpdateOptions | undefined) => void) =
null;
app.on('websocket-connect-state-change', (connected) => {
if (!connected && !msgNotify) {
msgNotify = Notify.create({
type: 'negative',
timeout: 0,
position: 'top-right',
message: '通信链接已断开!',
});
} else if (msgNotify && connected) {
msgNotify();
msgNotify = null;
}
});
const lineNetStore = useLineNetStore();
app.subscribe({
destination: '/queue/xian/ncc/alert',
messageHandle: (message: Uint8Array) => {
const storage = alert.NccAlertInfoMessage.deserialize(message);
lineNetStore.setAlarmInfo(storage.messages as []);
},
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
});
} else {
app.loadGraphic([]);
return Promise.resolve({
datas: [],
});
}
}
function handleSubscribe(lineApp: IGraphicApp) {
const lineStore = useLineStore();
const lineId = lineStore.lineId;
lineApp.subscribe({
destination: `/queue/line/${lineId}/device`,
messageConverter: (message: Uint8Array) => {
const states: GraphicState[] = [];
const storage = state.WsLineMessage.deserialize(message);
storage.signal.forEach((item) => {
if (item.rtuId !== 81 && item.rtuId !== 82 && item.rtuId) {
states.push(new SignalState(item));
}
});
storage.platform.forEach((item) => {
if (item.rtuId !== 81 && item.rtuId !== 82 && item.rtuId) {
states.push(new PlatformState(item));
}
});
storage.rtu.forEach((item) => {
if (item.rtuId !== 81 && item.rtuId !== 82 && item.rtuId) {
states.push(new StationState(item));
}
});
storage.switch.forEach((item) => {
if (item.rtuId !== 81 && item.rtuId !== 82 && item.rtuId) {
states.push(new TurnoutStates(item));
}
});
storage.track.forEach((item) => {
if (item.rtuId !== 81 && item.rtuId !== 82 && item.rtuId) {
states.push(new LogicSectionState(item));
}
});
return states;
},
});
lineApp.subscribe({
destination: `/queue/line/${lineId}/train`,
createOnNotFound: { graphicTypes: [Train.Type] },
messageConverter: (message: Uint8Array) => {
const states: GraphicState[] = [];
const trainStorage = state.WsLineTrainMessage.deserialize(message);
// console.log(trainStorage, '222');
trainStorage.trainInfo.forEach((item) => {
// if (item.rtuId !== 81 && item.rtuId !== 82 && item.rtuId) {
if (item.rtuId) {
states.push(new TrainState(item));
}
});
return states;
},
});
const lineNetStore = useLineNetStore();
lineApp.subscribe({
destination: '/queue/xian/ncc/alert',
messageHandle: (message: Uint8Array) => {
const storage = alert.NccAlertInfoMessage.deserialize(message);
lineNetStore.setAlarmInfo(storage.messages as []);
},
});
}

View File

@ -1,4 +1,10 @@
import { GraphicApp, GraphicData, GraphicState } from 'src/jl-graphic';
import {
IGraphicApp,
GraphicData,
GraphicState,
newGraphicApp,
IGraphicStorage,
} from 'jl-graphic';
import { getPublishLineNet } from 'src/api/PublishApi';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { state } from 'src/protos/ws_message';
@ -28,11 +34,11 @@ import { toUint8Array } from 'js-base64';
import { getWebsocketUrl } from 'src/configs/UrlManage';
import { getJwtToken } from 'src/configs/TokenManage';
import { alert } from 'src/protos/alertInfo';
import { QNotifyUpdateOptions, Notify } from 'quasar';
import { Notify } from 'quasar';
let lineNetApp: GraphicApp | null = null;
let lineNetApp: IGraphicApp | null = null;
export function getLineNetApp(): GraphicApp | null {
export function getLineNetApp(): IGraphicApp | null {
return lineNetApp;
}
@ -43,8 +49,21 @@ export function destroyLineNetApp(): void {
}
}
export function initLineNetApp(dom: HTMLElement): GraphicApp {
lineNetApp = new GraphicApp(dom);
export function initLineNetApp(): IGraphicApp {
lineNetApp = newGraphicApp({
interactiveGraphicTypeIncludes: [
RunLine.Type,
StationLine.Type,
TrainLine.Type,
],
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
viewportDragLeft: true,
wheelZoom: true,
},
dataLoader: loadLineNetDatas,
});
const graphicTemplate = [
new RunLineTemplate(new RunLineData()),
new PathLineTemplate(new PathLineData()),
@ -52,36 +71,47 @@ export function initLineNetApp(dom: HTMLElement): GraphicApp {
new ItrainLineTemplate(new TrainLineData(), new TrainLineState()),
new RectTemplate(new RectData()),
];
lineNetApp.registerGraphicTemplates(...graphicTemplate);
lineNetApp.setOptions({
mouseToolOptions: {
boxSelect: false,
viewportDrag: true,
wheelZoom: true,
},
interactiveTypeOptions: {
interactiveGraphicTypeIncludes: [
RunLine.Type,
StationLine.Type,
TrainLine.Type,
],
},
lineNetApp.reload().then(() => {
if (!lineNetApp) return;
const pathLineList = lineNetApp.queryStore.queryByType(PathLine.Type);
pathLineList.forEach((pathLine) => {
pathLine.visible = false;
});
handleSubscribe(lineNetApp);
});
lineNetApp.registerGraphicTemplates(...graphicTemplate);
RunLineOperateInteraction.init(lineNetApp);
let msgNotify: ReturnType<Notify['create']> | null = null;
lineNetApp.on('websocket-connect-state-change', (connected) => {
if (!connected && !msgNotify) {
msgNotify = Notify.create({
type: 'negative',
timeout: 0,
position: 'top-right',
message: '与WebSocket服务连接断开',
classes: 'my-notif-class',
});
} else if (msgNotify && connected) {
msgNotify();
msgNotify = null;
}
});
return lineNetApp;
}
export async function loadLineNetDatas(app: GraphicApp) {
export async function loadLineNetDatas(): Promise<IGraphicStorage> {
const lineNetStore = useLineNetStore();
const { proto: base64, name: lineNetName } = await getPublishLineNet();
lineNetStore.setLineNetName(lineNetName);
const datas: GraphicData[] = [];
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(
toUint8Array(base64)
);
console.log('加载数据', storage);
app.updateCanvas(storage.canvas);
const datas: GraphicData[] = [];
storage.runLines.forEach((runLine) => {
const g = new RunLineData(runLine);
datas.push(g);
@ -102,49 +132,40 @@ export async function loadLineNetDatas(app: GraphicApp) {
const g = new RectData(rect);
datas.push(g);
});
await app.loadGraphic(datas);
const pathLineList = app.queryStore.queryByType(PathLine.Type);
pathLineList.forEach((pathLine) => {
pathLine.visible = false;
});
app.enableWsMassaging({
wsUrl: `${getWebsocketUrl()}`,
token: getJwtToken() as string,
});
app.subscribe({
destination: '/queue/lineNet',
messageConverter: (message: Uint8Array) => {
const storage = state.WsLineNetMessage.deserialize(message);
const states: GraphicState[] = [];
storage.offset.forEach((item) => {
states.push(new TrainLineState(item));
});
return states;
},
});
app.subscribe({
destination: '/queue/xian/ncc/alert',
messageHandle: (message: Uint8Array) => {
const storage = alert.NccAlertInfoMessage.deserialize(message);
lineNetStore.setAlarmInfo(storage.messages as []);
},
});
let msgNotify: null | ((props?: QNotifyUpdateOptions | undefined) => void) =
null;
app.on('websocket-connect-state-change', (connected) => {
if (!connected && !msgNotify) {
msgNotify = Notify.create({
type: 'negative',
timeout: 0,
position: 'top-right',
message: '通信链接已断开!',
});
} else if (msgNotify && connected) {
msgNotify();
msgNotify = null;
}
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
});
} else {
app.loadGraphic([]);
return Promise.resolve({
datas: [],
});
}
}
function handleSubscribe(lineNetApp: IGraphicApp) {
const lineNetStore = useLineNetStore();
lineNetApp.enableWsMassaging({
wsUrl: `${getWebsocketUrl()}`,
token: getJwtToken() as string,
});
lineNetApp.subscribe({
destination: '/queue/lineNet',
createOnNotFound: { graphicTypes: [TrainLine.Type] },
messageConverter: (message: Uint8Array) => {
const storage = state.WsLineNetMessage.deserialize(message);
const states: GraphicState[] = [];
storage.offset.forEach((item) => {
states.push(new TrainLineState(item));
});
return states;
},
});
lineNetApp.subscribe({
destination: '/queue/xian/ncc/alert',
messageHandle: (message: Uint8Array) => {
const storage = alert.NccAlertInfoMessage.deserialize(message);
lineNetStore.setAlarmInfo(storage.messages as []);
},
});
}

View File

@ -0,0 +1,210 @@
import {
LogicSection,
LogicSectionTemplate,
} from 'src/graphics/logicSection/LogicSection';
import { Platform, PlatformTemplate } from 'src/graphics/platform/Platform';
import { SectionTemplate } from 'src/graphics/section/Section';
import { Signal, SignalTemplate } from 'src/graphics/signal/Signal';
import { Station, StationTemplate } from 'src/graphics/station/Station';
import { Turnout, TurnoutTemplate } from 'src/graphics/turnout/Turnout';
import {
IGraphicApp,
GraphicData,
newGraphicApp,
MenuItemOptions,
ContextMenu,
IGraphicStorage,
} from 'jl-graphic';
import {
LogicSectionData,
LogicSectionState,
} from './graphics/LogicSectionInteraction';
import { SeparatorTemplate } from 'src/graphics/separator/Separator';
import { AxleCountingTemplate } from 'src/graphics/axleCounting/AxleCounting';
import { SignalData, SignalState } from './graphics/SignalInteraction';
import { PlatformData, PlatformState } from './graphics/PlatformInteraction';
import { StationData, StationState } from './graphics/StationInteraction';
import { TurnoutData, TurnoutStates } from './graphics/TurnoutInteraction';
import { SectionData } from './graphics/SectionInteraction';
import { SeparatorData } from './graphics/SeparatorInteraction';
import { AxleCountingData } from './graphics/AxleCountingInteraction';
import { getPublishMapInfoByLineId } from 'src/api/PublishApi';
import { useRangeConfigStore } from 'src/stores/range-config-store';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { toUint8Array } from 'js-base64';
let rangeConfigApp: IGraphicApp;
export function getRangeConfigApp() {
return rangeConfigApp;
}
export function initRangeConfigApp(lineId: number) {
rangeConfigApp = newGraphicApp({
mouseToolOptions: {
boxSelect: true,
viewportDrag: true,
wheelZoom: true,
},
interactiveGraphicTypeIncludes: [
Signal.Type,
Platform.Type,
Station.Type,
LogicSection.Type,
Turnout.Type,
],
dataLoader: () => loadRangeConfigDatas(lineId),
});
const graphicTemplate = [
new SignalTemplate(new SignalData(), new SignalState()),
new PlatformTemplate(new PlatformData(), new PlatformState()),
new StationTemplate(new StationData(), new StationState()),
new TurnoutTemplate(new TurnoutData(), new TurnoutStates()),
new SectionTemplate(new SectionData()),
new LogicSectionTemplate(new LogicSectionData(), new LogicSectionState()),
new SeparatorTemplate(new SeparatorData()),
new AxleCountingTemplate(new AxleCountingData()),
];
rangeConfigApp.registerGraphicTemplates(...graphicTemplate);
rangeConfigApp.reload().then(() => {
const QuickJumpMenu = new ContextMenu({
name: '快捷跳转',
groups: [
{
items: rangeConfigApp.queryStore
.queryByType<Station>(Station.Type)
.map<MenuItemOptions>((station) => ({
name: station.datas.name ?? '',
handler: () => {
rangeConfigApp?.makeGraphicCenterShow(station);
},
})),
},
],
});
rangeConfigApp.registerMenu(QuickJumpMenu);
rangeConfigApp.canvas.on('_rightclick', (e) => {
QuickJumpMenu.open(e.global);
});
});
return rangeConfigApp;
}
export async function loadRangeConfigDatas(
lineId: number
): Promise<IGraphicStorage> {
if (!lineId) throw Error('请先选择线路');
const store = useRangeConfigStore();
const { proto: base64, name: lineName } = await getPublishMapInfoByLineId(
lineId,
'line'
);
store.setLineName(lineName);
const datas: GraphicData[] = [];
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(
toUint8Array(base64)
);
console.log('加载数据', storage);
storage.Platforms.forEach((platform) => {
datas.push(new PlatformData(platform));
});
storage.stations.forEach((station) => {
datas.push(new StationData(station));
});
storage.turnouts.forEach((turnout) => {
datas.push(new TurnoutData(turnout));
});
storage.section.forEach((section) => {
datas.push(new SectionData(section));
});
storage.logicSections.forEach((section) => {
datas.push(new LogicSectionData(section));
});
storage.separators.forEach((separator) => {
datas.push(new SeparatorData(separator));
});
storage.axleCountings.forEach((axleCounting) => {
datas.push(new AxleCountingData(axleCounting));
});
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
});
} else {
return Promise.resolve({
datas: [],
});
}
}
export async function loadLineDatas(app: IGraphicApp) {
const store = useRangeConfigStore();
const lineId = store.lineId;
if (!lineId) return;
const { proto: base64, name: lineName } = await getPublishMapInfoByLineId(
lineId,
'line'
);
store.setLineName(lineName);
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(
toUint8Array(base64)
);
const datas: GraphicData[] = [];
storage.Platforms.forEach((platform) => {
const g = new PlatformData(platform);
datas.push(g);
});
const quickJumpMenuItem: MenuItemOptions[] = [];
storage.stations.forEach((station) => {
datas.push(new StationData(station));
const item: MenuItemOptions = {
name: station.name,
handler: () => {
const g = app.queryStore.queryById(station.common.id);
if (g) {
app.makeGraphicCenterShow(g);
}
},
};
quickJumpMenuItem.push(item);
});
storage.turnouts.forEach((turnout) => {
datas.push(new TurnoutData(turnout));
});
storage.section.forEach((section) => {
datas.push(new SectionData(section));
});
storage.logicSections.forEach((section) => {
datas.push(new LogicSectionData(section));
});
storage.separators.forEach((separator) => {
datas.push(new SeparatorData(separator));
});
storage.axleCountings.forEach((axleCounting) => {
datas.push(new AxleCountingData(axleCounting));
});
const QuickJumpMenu = new ContextMenu({
name: '快捷跳转',
groups: [
{
items: quickJumpMenuItem,
},
],
});
app.registerMenu(QuickJumpMenu);
app.canvas.on('_rightclick', (e) => {
QuickJumpMenu.open(e.global);
});
}
}
export function destroyRangeConfigApp(): void {
if (rangeConfigApp) {
rangeConfigApp.destroy();
}
}

View File

@ -1,5 +1,5 @@
import { Graphics } from 'pixi.js';
import { calculateMirrorPoint } from 'src/jl-graphic';
import { calculateMirrorPoint } from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { Turnout, TurnoutPort } from './turnout/Turnout';
import { Section, SectionPort } from './section/Section';
@ -77,7 +77,7 @@ export function drawArrow(
export function createRelatedRefProto(
type: string,
id: string,
id: number,
port?: TurnoutPort | SectionPort
) {
const typeMap = new Map([
@ -111,6 +111,6 @@ export function protoPort2Data(port: graphicData.RelatedRef.DevicePort) {
export interface IRelatedRefData {
deviceType: graphicData.RelatedRef.DeviceType; //关联的设备类型
id: string; //关联的设备ID
id: number; //关联的设备ID
devicePort: graphicData.RelatedRef.DevicePort; //关联的设备端口
}

View File

@ -5,7 +5,7 @@ import {
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'src/jl-graphic';
} from 'jl-graphic';
import { IRelatedRefData, protoPort2Data } from '../CommonGraphics';
import { KilometerSystem } from '../signal/Signal';

View File

@ -5,10 +5,10 @@ import {
GraphicDrawAssistant,
GraphicIdGenerator,
GraphicInteractionPlugin,
JlDrawApp,
IDrawApp,
JlGraphic,
distance2,
} from 'src/jl-graphic';
} from 'jl-graphic';
import {
IAxleCountingData,
@ -16,7 +16,7 @@ import {
AxleCountingTemplate,
AxleCountingConsts,
} from './AxleCounting';
import { Section, SectionPort, SectionType } from '../section/Section';
import { Section, SectionPort } from '../section/Section';
import { Turnout, TurnoutPort } from '../turnout/Turnout';
import { IRelatedRefData, createRelatedRefProto } from '../CommonGraphics';
import { Signal } from '../signal/Signal';
@ -42,8 +42,8 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
IAxleCountingData
> {
codeGraph: AxleCounting;
constructor(app: JlDrawApp, template: AxleCountingTemplate) {
super(app, template, 'sym_o_circle', '不展示');
constructor(app: IDrawApp, template: AxleCountingTemplate) {
super(app, template, 'sym_o_circle', '计轴');
this.codeGraph = this.graphicTemplate.new();
this.container.addChild(this.codeGraph);
AxleCountingInteraction.init(app);
@ -198,12 +198,6 @@ export class AxleCountingDraw extends GraphicDrawAssistant<
if (axleCountingPs.y > height.y) {
direction = -1;
}
if (
section.datas.sectionType === SectionType.Logic ||
section.datas.children.includes(refDevice.id)
) {
return;
}
if (refDevice.type == Section.Type || refDevice.type == Turnout.Type)
this.draw(
axleCountingPs,
@ -352,10 +346,10 @@ function buildAbsorbablePositions(
export class AxleCountingInteraction extends GraphicInteractionPlugin<AxleCounting> {
static Name = 'AxleCounting_transform';
constructor(app: JlDrawApp) {
constructor(app: IDrawApp) {
super(AxleCountingInteraction.Name, app);
}
static init(app: JlDrawApp) {
static init(app: IDrawApp) {
return new AxleCountingInteraction(app);
}
filter(...grahpics: JlGraphic[]): AxleCounting[] | undefined {

View File

@ -0,0 +1,224 @@
import { IPointData } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
calculateDistanceFromPointToLine,
getRectangleCenter,
ILineGraphic,
} from 'jl-graphic';
import { SectionGraphic } from './SectionGraphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { Section, SectionType } from '../section/Section';
import { arePolylinesIntersect } from './ConcentrationDividingLineUtils';
import { createRelatedRefProto } from '../CommonGraphics';
import { Turnout,TurnoutPort } from '../turnout/Turnout';
export interface IConcentrationDividingLineData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
get refLeftStationId(): number; //左边关联的集中站id
set refLeftStationId(v: number);
get refRightStationId(): number; //右边关联的集中站id
set refRightStationId(v: number);
get nodeConWithSecs(): graphicData.NodeConWithSec[]; // 集中区分割线与区段的交点
set nodeConWithSecs(nodes: graphicData.NodeConWithSec[]);
get isOtherLineConcentrationDividingLine(): boolean; //集中区分割线绘制在其它线的边界处
set isOtherLineConcentrationDividingLine(v: boolean);
clone(): IConcentrationDividingLineData;
copyFrom(data: IConcentrationDividingLineData): void;
eq(other: IConcentrationDividingLineData): boolean;
}
export const ConcentrationDividingLineConsts = {
lineColor: '#f00',
lineWidth: 2,
};
enum devicePort {
'A',
'B',
'C',
}
export class ConcentrationDividingLine
extends JlGraphic
implements ILineGraphic
{
static Type = 'ConcentrationDividingLine';
lineGraphic: SectionGraphic;
constructor() {
super(ConcentrationDividingLine.Type);
this.lineGraphic = new SectionGraphic();
this.transformSave = true;
this.addChild(this.lineGraphic);
}
get datas(): IConcentrationDividingLineData {
return this.getDatas<IConcentrationDividingLineData>();
}
get linePoints(): IPointData[] {
return this.datas.points;
}
set linePoints(points: IPointData[]) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
}
doRepaint() {
if (this.datas.points.length < 2) {
throw new Error('Link坐标数据异常');
}
this.lineGraphic.clear();
this.lineGraphic.points = this.datas.points;
this.lineGraphic.lineStyle(
ConcentrationDividingLineConsts.lineWidth,
ConcentrationDividingLineConsts.lineColor
);
this.lineGraphic.paint();
}
buildRelation() {
const nodeConWithSecs: graphicData.NodeConWithSec[] = [];
const sections = this.queryStore
.queryByType<Section>(Section.Type)
.filter((g) => g.datas.sectionType == SectionType.Physical);
const hasNodeSection = new Map<number, string>();
sections.forEach((section) => {
const changeSectionData = section.datas.points.map((point) =>
section.localToCanvasPoint(point)
);
const changeConcentrationDividingLineData = this.datas.points.map(
(point) => this.localToCanvasPoint(point)
);
const hasNode = arePolylinesIntersect(
changeSectionData,
changeConcentrationDividingLineData
);
if (hasNode) {
const minA = calculateDistanceFromPointToLine(
hasNode.segment2[0],
hasNode.segment2[1],
section.localToCanvasPoint(section.getStartPoint())
);
const minB = calculateDistanceFromPointToLine(
hasNode.segment2[0],
hasNode.segment2[1],
section.localToCanvasPoint(section.getEndPoint())
);
const relationParam = minA > minB ? TurnoutPort.B : TurnoutPort.A;
const portRefOtherDevice =
relationParam == 'A' ? section.datas.paRef : section.datas.pbRef;
if (
portRefOtherDevice?.id &&
!hasNodeSection.get(section.id) &&
!hasNodeSection.get(portRefOtherDevice.id)
) {
const refDevice = this.queryStore.queryById<Turnout | Section>(
portRefOtherDevice?.id
);
const [leftDevice, rightDevice] =
refDevice.localToCanvasPoint(
getRectangleCenter(refDevice.getLocalBounds())
).x <
section.localToCanvasPoint(
getRectangleCenter(section.getLocalBounds())
).x
? [
{
device: refDevice,
port: devicePort[
portRefOtherDevice.devicePort
] as TurnoutPort,
},
{ device: section, port: relationParam },
]
: [
{ device: section, port: relationParam },
{
device: refDevice,
port: devicePort[
portRefOtherDevice.devicePort
] as TurnoutPort,
},
];
hasNodeSection.set(leftDevice.device.id, '1');
hasNodeSection.set(rightDevice.device.id, '1');
nodeConWithSecs.push(
new graphicData.NodeConWithSec({
leftSection: createRelatedRefProto(
leftDevice.device.type,
leftDevice.device.id,
leftDevice.port
),
rightSection: createRelatedRefProto(
rightDevice.device.type,
rightDevice.device.id,
rightDevice.port
),
})
);
} else if (!hasNodeSection.get(section.id) && !portRefOtherDevice?.id) {
const [leftSectionId, rightSectionId] =
relationParam === 'A'
? [undefined, section.id]
: [section.id, undefined];
hasNodeSection.set(section.id, '1');
if (leftSectionId == undefined) {
nodeConWithSecs.push(
new graphicData.NodeConWithSec({
leftSection: undefined,
rightSection: createRelatedRefProto(
Section.Type,
rightSectionId,
TurnoutPort.A
),
})
);
} else {
nodeConWithSecs.push(
new graphicData.NodeConWithSec({
leftSection: createRelatedRefProto(
Section.Type,
leftSectionId,
TurnoutPort.B
),
rightSection: undefined,
})
);
}
}
}
});
nodeConWithSecs.sort((a, b) => {
const sectionAId = a.leftSection ? a.leftSection.id : a.rightSection.id;
const sectionA = this.queryStore.queryById<Section | Turnout>(sectionAId);
const sectionBId = b.leftSection ? b.leftSection.id : b.rightSection.id;
const sectionB = this.queryStore.queryById<Section | Turnout>(sectionBId);
return (
sectionA.localToCanvasPoint(
getRectangleCenter(sectionA.getLocalBounds())
).y -
sectionB.localToCanvasPoint(
getRectangleCenter(sectionB.getLocalBounds())
).y
);
});
this.datas.nodeConWithSecs = nodeConWithSecs;
}
}
export class ConcentrationDividingLineTemplate extends JlGraphicTemplate<ConcentrationDividingLine> {
constructor(dataTemplate: IConcentrationDividingLineData) {
super(ConcentrationDividingLine.Type, { dataTemplate });
}
new() {
const g = new ConcentrationDividingLine();
g.loadData(this.datas);
return g;
}
}

View File

@ -0,0 +1,212 @@
import {
IGraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
IDrawApp,
JlGraphic,
linePoint,
PolylineEditPlugin,
addWayPoint,
clearWayPoint,
MenuItemOptions,
ContextMenu
} from 'jl-graphic';
import {
IConcentrationDividingLineData,
ConcentrationDividingLine,
ConcentrationDividingLineConsts,
ConcentrationDividingLineTemplate,
} from './ConcentrationDividingLine';
import {
DisplayObject,
FederatedMouseEvent,
Graphics,
IHitArea,
Point,
} from 'pixi.js';
import { getWayLineIndex } from '../polygon/PolygonUtils';
export class ConcentrationDividingLineDraw extends GraphicDrawAssistant<
ConcentrationDividingLineTemplate,
IConcentrationDividingLineData
> {
points: Point[] = [];
graphic = new Graphics();
constructor(app: IDrawApp, template: ConcentrationDividingLineTemplate) {
super(app, template, 'sym_o_timeline', '集中区分割线');
this.container.addChild(this.graphic);
ConcentrationDividingLinePointEditPlugin.init(app, this);
}
bind(): void {
super.bind();
}
unbind(): void {
super.unbind();
}
onLeftDown(e: FederatedMouseEvent): void {
const { x, y } = this.toCanvasCoordinates(e.global);
const p = new Point(x, y);
this.points.push(p);
}
onRightClick(): void {
if (this.points.length < 2) {
this.finish();
return;
}
this.createAndStore(true);
}
onEsc(): void {
if (this.points.length < 2) {
this.finish();
return;
}
this.createAndStore(true);
}
redraw(p: Point): void {
if (this.points.length < 1) return;
this.graphic.clear();
this.graphic.lineStyle(
ConcentrationDividingLineConsts.lineWidth,
ConcentrationDividingLineConsts.lineColor
);
const ps = [...this.points];
ps.push(p);
ps.forEach((p, i) => {
if (i !== 0) {
this.graphic.lineTo(p.x, p.y);
} else {
this.graphic.moveTo(p.x, p.y);
}
});
}
prepareData(data: IConcentrationDividingLineData): boolean {
if (this.points.length < 2) {
console.log('ConcentrationDividingLine绘制因点不够取消绘制');
return false;
}
data.points = this.points;
return true;
}
clearCache(): void {
this.points = [];
this.graphic.clear();
}
}
export class ConcentrationDividingLineGraphicHitArea implements IHitArea {
concentrationDividingLine: ConcentrationDividingLine;
constructor(concentrationDividingLine: ConcentrationDividingLine) {
this.concentrationDividingLine = concentrationDividingLine;
}
contains(x: number, y: number): boolean {
for (
let i = 1;
i < this.concentrationDividingLine.datas.points.length;
i++
) {
const p1 = this.concentrationDividingLine.datas.points[i - 1];
const p2 = this.concentrationDividingLine.datas.points[i];
if (
linePoint(p1, p2, { x, y }, ConcentrationDividingLineConsts.lineWidth)
) {
return true;
}
}
return false;
}
}
const addWaypointConfig: MenuItemOptions = {
name: '添加路径点',
};
const clearWaypointsConfig: MenuItemOptions = {
name: '清除所有路径点',
};
const ConcentrationDividingLineEditMenu: ContextMenu = ContextMenu.init({
name: '集中区分割线编辑菜单',
groups: [
{
items: [addWaypointConfig, clearWaypointsConfig],
},
],
});
export class ConcentrationDividingLinePointEditPlugin extends GraphicInteractionPlugin<ConcentrationDividingLine> {
static Name = 'ConcentrationDividingLinePointDrag';
drawAssistant: ConcentrationDividingLineDraw;
constructor(app: IGraphicApp, da: ConcentrationDividingLineDraw) {
super(ConcentrationDividingLinePointEditPlugin.Name, app);
this.drawAssistant = da;
app.registerMenu(ConcentrationDividingLineEditMenu);
}
static init(app: IGraphicApp, da: ConcentrationDividingLineDraw) {
return new ConcentrationDividingLinePointEditPlugin(app, da);
}
filter(...grahpics: JlGraphic[]): ConcentrationDividingLine[] | undefined {
return grahpics.filter(
(g) => g.type == ConcentrationDividingLine.Type
) as ConcentrationDividingLine[];
}
bind(g: ConcentrationDividingLine): void {
g.lineGraphic.eventMode = 'static';
g.lineGraphic.cursor = 'pointer';
g.lineGraphic.hitArea = new ConcentrationDividingLineGraphicHitArea(g);
g.transformSave = true;
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: ConcentrationDividingLine): void {
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnselected, this);
g.off('_rightclick', this.onContextMenu, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const concentrationDividingLine =
target.getGraphic() as ConcentrationDividingLine;
this.app.updateSelected(concentrationDividingLine);
const p = concentrationDividingLine.screenToLocalPoint(e.global);
addWaypointConfig.handler = () => {
const linePoints = concentrationDividingLine.linePoints;
const { start, end } = getWayLineIndex(linePoints, p);
addWayPoint(concentrationDividingLine, false, start, end, p);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(concentrationDividingLine, false);
};
ConcentrationDividingLineEditMenu.open(e.global);
}
onSelected(g: DisplayObject): void {
const concentrationDividingLine = g as ConcentrationDividingLine;
let lep = concentrationDividingLine.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (!lep) {
lep = new PolylineEditPlugin(concentrationDividingLine);
concentrationDividingLine.addAssistantAppend(lep);
}
lep.showAll();
}
onUnselected(g: DisplayObject): void {
const concentrationDividingLine = g as ConcentrationDividingLine;
const lep =
concentrationDividingLine.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (lep) {
lep.hideAll();
}
}
}

View File

@ -0,0 +1,195 @@
import { IPointData } from 'pixi.js';
import { Section } from '../section/Section';
import { Turnout } from '../turnout/Turnout';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { IDrawApp, JlGraphic } from 'jl-graphic';
import { GraphicDataBase } from 'src/drawApp/graphics/GraphicDataBase';
import { TurnoutData } from 'src/drawApp/graphics/TurnoutInteraction';
import { SectionData } from 'src/drawApp/graphics/SectionInteraction';
import { SignalData } from 'src/drawApp/graphics/SignalInteraction';
import { Signal } from '../signal/Signal';
import { Platform } from '../platform/Platform';
import { PlatformData } from 'src/drawApp/graphics/PlatformInteraction';
//判断线段与线段有木有交点
export function isSegmentsIntersect(
segment1: IPointData[],
segment2: IPointData[]
) {
const [p1, p2] = segment1;
const [p3, p4] = segment2;
// 判断包围盒是否相交
if (
Math.max(p1.x, p2.x) < Math.min(p3.x, p4.x) ||
Math.min(p1.x, p2.x) > Math.max(p3.x, p4.x) ||
Math.max(p1.y, p2.y) < Math.min(p3.y, p4.y) ||
Math.min(p1.y, p2.y) > Math.max(p3.y, p4.y)
) {
return false;
}
// 计算向量叉积
const cross1 = crossProduct(p3, p1, p4);
const cross2 = crossProduct(p3, p2, p4);
const cross3 = crossProduct(p1, p3, p2);
const cross4 = crossProduct(p1, p4, p2);
if (cross1 * cross2 < 0 && cross3 * cross4 < 0) {
return true;
}
return false;
}
function crossProduct(p1: IPointData, p2: IPointData, p3: IPointData) {
return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
}
export function getSegmentsFromPolyline(polyline: IPointData[]) {
const segments = [];
for (let i = 0; i < polyline.length - 1; i++) {
const segment = [polyline[i], polyline[i + 1]];
segments.push(segment);
}
return segments;
}
//判断折线与折线有木有交点
export function arePolylinesIntersect(
polyline1: IPointData[],
polyline2: IPointData[]
) {
const segments1 = getSegmentsFromPolyline(polyline1);
const segments2 = getSegmentsFromPolyline(polyline2);
for (const segment1 of segments1) {
for (const segment2 of segments2) {
if (isSegmentsIntersect(segment1, segment2)) {
return { hasnode: true, segment1, segment2 };
}
}
}
return false;
}
//获取指定区间内的物理区段和道岔
export function findContainDevice(
refDevice: Section | Turnout,
refDevicePort: graphicData.RelatedRef.DevicePort,
containDeviceIds: number[],
drawApp: IDrawApp
) {
const devicePort = graphicData.RelatedRef.DevicePort;
containDeviceIds.push(refDevice.id);
switch (true) {
case refDevice instanceof Section:
const sectionPaorbRef =
refDevicePort == devicePort.B
? refDevice.datas.paRef
: refDevice.datas.pbRef;
if (sectionPaorbRef && !containDeviceIds.includes(sectionPaorbRef.id)) {
const pbRefDevice = drawApp.queryStore.queryById<Section | Turnout>(
sectionPaorbRef.id
);
findContainDevice(
pbRefDevice,
sectionPaorbRef.devicePort,
containDeviceIds,
drawApp
);
}
break;
//道岔需要分路--实际的走向
case refDevice instanceof Turnout:
const otherPorts = [devicePort.A, devicePort.B, devicePort.C].filter(
(port) => port !== refDevicePort
);
otherPorts.forEach((port) => {
switch (port) {
case devicePort.A:
const turnoutPaRef = refDevice.datas.paRef;
if (turnoutPaRef && !containDeviceIds.includes(turnoutPaRef.id)) {
const paRefDevice = drawApp.queryStore.queryById<
Section | Turnout
>(turnoutPaRef.id);
findContainDevice(
paRefDevice,
turnoutPaRef.devicePort,
containDeviceIds,
drawApp
);
}
break;
case devicePort.B:
const turnoutPbRef = refDevice.datas.pbRef;
if (turnoutPbRef && !containDeviceIds.includes(turnoutPbRef.id)) {
const pbRefDevice = drawApp.queryStore.queryById<
Section | Turnout
>(turnoutPbRef.id);
findContainDevice(
pbRefDevice,
turnoutPbRef.devicePort,
containDeviceIds,
drawApp
);
}
break;
case devicePort.C:
const turnoutPcRef = (refDevice as Turnout).datas.pcRef;
if (turnoutPcRef && !containDeviceIds.includes(turnoutPcRef.id)) {
const pcRefDevice = drawApp.queryStore.queryById<
Section | Turnout
>(turnoutPcRef.id);
findContainDevice(
pcRefDevice,
turnoutPcRef.devicePort,
containDeviceIds,
drawApp
);
}
break;
}
});
break;
}
}
export function handleCentralizedStationsData(
devices: JlGraphic[],
centralizedStation: number
) {
interface GraphicData {
centralizedStation: number;
}
const dataMap = new Map<string, GraphicDataBase>([
[Turnout.Type, new TurnoutData()],
[Section.Type, new SectionData()],
[Signal.Type, new SignalData()],
[Platform.Type, new PlatformData()],
]);
devices.forEach((device) => {
const data = dataMap.get(device.type);
if (data) {
data.copyFrom(device.saveData());
const dataCopy = data as GraphicDataBase & GraphicData;
dataCopy.centralizedStation = centralizedStation;
device.updateData(data);
}
});
}
//找到公共的元素
type findType = string | number;
export function findCommonElements(arrays: findType[][]) {
if (arrays.length === 0) {
return [];
}
const commonElements: findType[] = [];
arrays[0].forEach((element) => {
if (arrays.every((arr) => arr.includes(element))) {
commonElements.push(element);
}
});
return commonElements;
}

View File

@ -0,0 +1,57 @@
import { Graphics, IPointData } from 'pixi.js';
import { assertBezierPoints, convertToBezierParams } from 'jl-graphic';
export enum DevicePort {
A = 'A',
B = 'B',
C = 'C',
}
export class SectionGraphic extends Graphics {
static Type = 'SectionGraphic';
private _points: IPointData[] = [];
public get points(): IPointData[] {
return this._points;
}
public set points(value: IPointData[]) {
if (!this.isCurve) {
if (value.length < 2) {
throw Error('Polyline must have at least 2 points');
}
} else {
assertBezierPoints(value);
}
this._points = value;
}
private _segmentsCount = 10;
public get segmentsCount(): number {
return this._segmentsCount;
}
public set segmentsCount(value: number) {
if (value < 1) {
throw Error('segmentsCount must be at least 1');
}
this._segmentsCount = value;
}
isCurve = false;
constructor() {
super();
}
paint() {
if (this.isCurve) {
const bps = convertToBezierParams(this.points);
bps.forEach((bp) => {
this.drawBezierCurve(bp.p1, bp.p2, bp.cp1, bp.cp2, this.segmentsCount);
});
} else {
this.moveTo(this.points[0].x, this.points[0].y);
for (let i = 1; i < this.points.length; i++) {
this.lineTo(this.points[i].x, this.points[i].y);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More