Compare commits

...

200 Commits

Author SHA1 Message Date
joylink_fanyuhong
d843e81fd4 Merge branch 'master' of http://120.46.212.6:3000/joylink/rts-sim-testing-client 2024-03-21 09:12:31 +08:00
joylink_fanyuhong
82fabffdb8 同步 2024-03-21 09:11:46 +08:00
joylink_fanyuhong
ec135451d4 添加车库门盒子 2024-03-21 09:11:07 +08:00
joylink_zhaoerwei
22d3a1794a 驾驶台--状态数据结构和交互调整 2024-03-19 17:47:35 +08:00
joylink_zhaoerwei
9261a95f78 驾驶台相关 2024-03-19 14:20:53 +08:00
joylink_fanyuhong
eee398eaa1 列车连接操作&列车连接状态 2024-03-19 10:22:17 +08:00
joylink_zhaoerwei
1fa571f777 列车控制室相关 2024-03-15 16:41:38 +08:00
joylink_zhaoerwei
309931be31 增加列车驾驶台图--壳 2024-03-14 18:02:45 +08:00
joylink_zhaoerwei
b6c031d7b9 修改执行proto的文件名 2024-03-14 15:48:40 +08:00
joylink_zhaoerwei
875a566b38 防淹门一键关联集中站 2024-03-14 09:46:05 +08:00
2fb6f91372 修改submodule及依赖graphic-pixi 2024-03-13 19:09:24 +08:00
joylink_zhaoerwei
ef0637003a 洗车机和车库门继电器和一键关联集中站 2024-03-13 16:15:18 +08:00
joylink_fanyuhong
53f1be79e9 icon调整 2024-03-13 16:08:59 +08:00
joylink_fanyuhong
c640f3f85a 車庫門調整 2024-03-13 16:06:11 +08:00
joylink_fanyuhong
efb8140a29 防淹门颜色调整 2024-03-13 15:36:39 +08:00
joylink_fanyuhong
dd5f77d6f1 防淹门、车库门、洗车机调整 2024-03-13 15:31:26 +08:00
joylink_zhaoerwei
4314e0db79 可手动录入车库门洗车机继电器相关信息 2024-03-13 09:13:55 +08:00
joylink_zhaoerwei
db7911985a proto同步 2024-03-12 15:29:04 +08:00
joylink_fanyuhong
268a964ef0 添加速传输入和雷达输出 2024-03-12 15:21:43 +08:00
joylink_zhaoerwei
fe789210dc proto同步 2024-03-12 14:05:51 +08:00
joylink_zhaoerwei
3a7662d308 屏蔽门操作bug修复 2024-02-23 16:02:25 +08:00
joylink_zhaoerwei
f566a47718 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-23 15:34:06 +08:00
joylink_zhaoerwei
faee59bd55 屏蔽门重绘修复 2024-02-23 15:33:44 +08:00
joylink_fanyuhong
db3d424e53 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-22 18:39:09 +08:00
joylink_fanyuhong
52a7e89283 确认清除列车调整 2024-02-22 18:39:05 +08:00
joylink_zhaoerwei
a13833d8b8 场景只切换线路图和继电器图 2024-02-22 15:55:24 +08:00
joylink_fanyuhong
0b97ef6253 问题调整 2024-02-22 15:37:08 +08:00
joylink_fanyuhong
936ace948d 车尾设备位置计算调整 2024-02-21 09:23:18 +08:00
joylink_fanyuhong
935e12f264 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-20 17:42:53 +08:00
joylink_fanyuhong
8540e68711 非空判断调整 2024-02-20 17:42:49 +08:00
joylink_zhaoerwei
7cc534028b ibp处理鼠标离开和ibp灯的颜色 2024-02-20 15:11:24 +08:00
joylink_fanyuhong
f9782c1227 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-20 14:36:16 +08:00
joylink_fanyuhong
e5745dfc9f 注释mock 2024-02-20 14:35:23 +08:00
joylink_zhaoerwei
8cd833b466 psl和ibp相关按钮和订阅后端请求字段调整 2024-02-20 12:17:06 +08:00
joylink_fanyuhong
870c790c93 psl切换重复初始化调整 2024-02-20 10:37:46 +08:00
joylink_zhaoerwei
2e07f7413b 场景显示psl和ibp,屏蔽门状态面板、继电器吸起/落下统一改为Q/H 2024-02-20 09:56:56 +08:00
joylink_zhaoerwei
75b8f03e30 车站去掉关联的ibp盘 2024-02-19 18:26:12 +08:00
joylink_zhaoerwei
c3309c9266 场景中增加ibp和psl按钮的交互 2024-02-19 11:42:31 +08:00
joylink_zhaoerwei
086c5628ba 屏蔽门和车站状态面板修改 2024-02-19 10:57:07 +08:00
joylink_fanyuhong
d0121191f8 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-19 09:46:57 +08:00
joylink_fanyuhong
de11916836 233启用 2024-02-19 09:46:53 +08:00
joylink_zhaoerwei
8e16683b53 一键生成继电器bug修复,生成顺序不能乱修改 2024-02-19 08:56:42 +08:00
joylink_zhaoerwei
b58591efeb 站台继电器区段道岔状态面板修改 2024-02-18 17:28:46 +08:00
joylink_zhaoerwei
9681bd2b7b 屏蔽门增加有障碍物和强制状态显示 2024-02-18 15:36:21 +08:00
joylink_zhaoerwei
aa156e400c 增加一键生成继电器的数量,无人折返继电器(WRZFJ)和站台清客确认继电器就行(QKQRJ) 2024-02-18 12:19:11 +08:00
joylink_fanyuhong
2b0f794fd1 bjrtss=>bjrtsts 2024-02-18 09:46:03 +08:00
joylink_fanyuhong
b63df4acf4 测试环境调整为http、ws 2024-02-18 09:33:28 +08:00
joylink_fanyuhong
04c02e2a40 uri调整 2024-02-18 09:21:39 +08:00
df8eb7ad54 ibp盘增加网格背景+框架更新,增加画布网格 2024-02-07 13:54:40 +08:00
fan
b90c3e3bda Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-06 17:52:49 +08:00
fan
4200403e9a 列车Btm状态显示调整 2024-02-06 17:52:45 +08:00
8e6b0f6b77 绘制增加ipb和psl按钮 2024-02-06 16:28:32 +08:00
fan
aaf1c5df40 应答器状态显示调整 2024-02-06 15:02:02 +08:00
fan
863d52bf56 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-06 14:13:47 +08:00
fan
de876c4807 列车状态添加列车尾部位置和偏移显示 2024-02-06 14:13:42 +08:00
06efef16c7 去掉之前旁路的操作 2024-02-06 12:23:03 +08:00
fan
93e1f7992c Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-06 11:07:37 +08:00
fan
c019c19a33 应答器添加操作停止发送报文&取消停止发送报文 2024-02-06 11:07:33 +08:00
eeb9eef77c 旁路复位调整+更换psl按钮图 2024-02-06 09:25:56 +08:00
fan
98a128a4dd Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-05 15:01:42 +08:00
8b173bfc2b psl和ibp按钮增加旁路状态显示 2024-02-05 12:15:49 +08:00
b4b3012432 ibp盘按钮加旁路 2024-02-05 09:29:01 +08:00
joylink_fanyuhong
9558bea3a5 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-02-05 08:59:57 +08:00
joylink_fanyuhong
9458eca656 应答器停止发送报文暂提 2024-02-05 08:59:50 +08:00
joylink_fanyuhong
9612b27c76 应答器操作后显示调整 2024-02-05 08:59:15 +08:00
joylink_fanyuhong
63924eaaef 添加清除所有列车操作&清除列车操作添加二次确认 2024-02-04 17:38:07 +08:00
949b173603 psl旁路操作 2024-02-04 16:04:43 +08:00
joylink_fanyuhong
fd2e8bd975 仿真列车添加借口调整 2024-02-04 09:11:40 +08:00
fan
88d3f22a8e 应答器显示调整 2024-02-02 18:04:30 +08:00
fan
8839b38911 信号机应答器状态显示调整 2024-02-02 17:48:41 +08:00
joylink_zhaoerwei
a9e4416b0e 紧急关闭按钮添加地图Code和批量添加 2024-02-02 17:19:38 +08:00
fan
c487a649d4 仿真结束弹框调整 2024-01-30 17:29:01 +08:00
fan
9531f7bfa3 仿真异常弹出调整 2024-01-30 09:27:33 +08:00
joylink_zhaoerwei
2aebcf31b5 仿真状态枚举调整 2024-01-29 17:39:43 +08:00
joylink_zhaoerwei
a5c1277f23 驱采状态 2024-01-29 15:24:50 +08:00
fan
b71680772d Host调整 2024-01-29 14:17:34 +08:00
fan
05a29ea5a8 列车动力学参数调整 2024-01-29 14:17:00 +08:00
fan
6ddc51ecd7 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-29 13:09:26 +08:00
fan
e6b0557b1b 列车设置参数调整&状态展示调整 2024-01-29 13:09:20 +08:00
joylink_zhaoerwei
be5499e4ca 驱采状态代码备用 2024-01-26 18:01:44 +08:00
fan
77982dacd2 关联地图调整 2024-01-26 13:12:11 +08:00
fan
87d617c3e6 另存到草稿清空draftName 2024-01-26 11:01:40 +08:00
fan
f95e12cf3e Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-26 10:53:31 +08:00
fan
7b680de6de 另存到草稿调整 2024-01-26 10:53:26 +08:00
joylink_zhaoerwei
f6057003a6 框架版本复用+道岔bug修复 2024-01-26 10:39:09 +08:00
fan
e92f5600ee Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-25 17:01:39 +08:00
fan
0814ad6cac 信号机上下行配置调整 2024-01-25 17:01:34 +08:00
joylink_zhaoerwei
9da46fce2d 一键生成继电器图布局更改 2024-01-25 16:54:06 +08:00
joylink_zhaoerwei
6e556db5b0 框架版本回退,bug待修复 2024-01-25 16:02:27 +08:00
fan
a04acb38fa Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-25 14:45:41 +08:00
fan
5e3d7c3aea 删除lamp 2024-01-25 14:45:36 +08:00
joylink_zhaoerwei
b63c87335f 框架版本更新,解决屏蔽门矢量文字无法缩放 2024-01-25 10:03:22 +08:00
fan
d5f4efe6e6 信号机调整 2024-01-25 09:31:54 +08:00
fan
cb78231722 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-24 17:43:38 +08:00
fan
a709c1f395 应答器修改可变报文 2024-01-24 17:43:34 +08:00
joylink_zhaoerwei
e2db43b689 样式微调 2024-01-24 17:11:29 +08:00
fan
99374d8f49 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-24 17:01:59 +08:00
fan
49b9c83949 修改信号机实现方式 2024-01-24 17:01:56 +08:00
joylink_zhaoerwei
a487159ac0 屏蔽门bug修复 2024-01-24 16:56:57 +08:00
fan
0b3b8013ba 结束测试项目添加loading 2024-01-24 16:11:33 +08:00
fan
da6d8a2caf Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-24 16:03:53 +08:00
fan
c603b3ac55 应答器报文导入逻辑调整 2024-01-24 16:03:44 +08:00
joylink_zhaoerwei
ed834b114a 信号机和应答器调整 2024-01-24 16:02:13 +08:00
joylink_zhaoerwei
cde11aa2bb 继电器、道岔、区段、屏蔽门状态组件格式化统一及代码优化 2024-01-24 15:36:46 +08:00
joylink_zhaoerwei
fc8ddeecb7 屏蔽门调整 2024-01-24 14:17:17 +08:00
joylink_zhaoerwei
c64045452e 微调 2024-01-24 13:53:06 +08:00
fan
b9c20b93fd Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-24 13:39:56 +08:00
fan
ed298762cc 接口请求401时,认证失败弹框弹出后取消发送请求 2024-01-24 13:39:50 +08:00
joylink_zhaoerwei
3ae615df66 屏蔽门 2024-01-24 13:35:53 +08:00
joylink_zhaoerwei
8364677185 屏蔽门状态面板bug修复 2024-01-24 09:58:10 +08:00
joylink_zhaoerwei
c168d7b0cc 微调 2024-01-24 09:29:29 +08:00
joylink_zhaoerwei
834ba6931e 屏蔽门操作 2024-01-23 18:14:34 +08:00
joylink_zhaoerwei
e92fd12c31 区段操作修改 2024-01-23 16:45:12 +08:00
joylink_zhaoerwei
b15b78d735 根据状态显示表格字体颜色 2024-01-23 13:31:18 +08:00
fan
0f7dba3642 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-23 13:04:42 +08:00
fan
3bdff0950c 仿真状态提示调整 2024-01-23 13:04:35 +08:00
joylink_zhaoerwei
8b50e89bf9 仿真第三方接口状态信息 2024-01-23 11:27:45 +08:00
joylink_zhaoerwei
9ebe9b40e2 区段操作 2024-01-23 09:14:27 +08:00
joylink_zhaoerwei
522d5ac4f0 区段状态面板 2024-01-22 17:51:47 +08:00
joylink_zhaoerwei
da60b95807 区段操作初提交 2024-01-22 17:33:02 +08:00
fan
7f598e209c 列车检索&空白操作同步不能顶替弹出 2024-01-22 17:00:29 +08:00
fan
f7d95ed2c7 处理应答器报文清除空格 2024-01-22 14:00:55 +08:00
fan
5c78c1daca 信号机灯显调整 2024-01-22 13:31:29 +08:00
fan
d7cb1bb50a 固定用户报文参数名调整 2024-01-22 13:06:31 +08:00
fan
f9e06c5f09 应答器接口及状态显示调整 2024-01-22 11:30:11 +08:00
fan
2a217ed2f3 测试系统应答器显示名称 2024-01-22 10:05:54 +08:00
fan
9597f302f3 取消道岔添加列车操作 2024-01-22 09:37:20 +08:00
fan
8c22629234 host修改 2024-01-19 17:45:50 +08:00
fan
fcf9ea7983 操作弹框问题调整 2024-01-19 16:50:54 +08:00
fan
5c05f5d595 信号机状态枚举调整 2024-01-19 15:57:01 +08:00
fan
4290e66fe3 仿真操作调整 2024-01-19 15:51:14 +08:00
fan
e566724f8a 信号机调整 2024-01-19 14:10:13 +08:00
fan
288784c4bf Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-19 13:42:36 +08:00
fan
67956745e5 信号机调整暂提 2024-01-19 13:29:32 +08:00
joylink_zhaoerwei
076b500db5 操作面板调整+登录后改成跳转到测试管理界面 2024-01-19 13:19:01 +08:00
joylink_zhaoerwei
f83a11125b 微调 2024-01-19 11:20:34 +08:00
joylink_zhaoerwei
f1aaafeb67 道岔操作面板优化 2024-01-19 11:17:13 +08:00
fan
e0586c5738 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-19 11:14:42 +08:00
fan
9379ebfcc6 信号机调整暂提 2024-01-19 11:14:33 +08:00
joylink_zhaoerwei
e9ddf033a3 操作弹框自动关闭 2024-01-19 10:52:10 +08:00
joylink_zhaoerwei
fe46019070 操作弹框修改 2024-01-19 10:31:41 +08:00
fan
095c38f76a Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-19 09:20:55 +08:00
fan
26e68ae3a5 修改host 2024-01-19 09:20:50 +08:00
joylink_zhaoerwei
ea52fbf206 道岔操作弹框样式修改 2024-01-18 17:54:28 +08:00
fan
3e0752e352 列车显示信息问题调整 2024-01-18 17:36:51 +08:00
fan
0f1c65c6e6 参数名变更 2024-01-18 17:29:28 +08:00
fan
b46f8c71e4 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-18 16:58:38 +08:00
fan
bc295e6977 列车调整 2024-01-18 16:58:34 +08:00
joylink_zhaoerwei
394e6cf5ee 微调 2024-01-18 16:37:13 +08:00
fan
c29cb2411f host调整 2024-01-18 16:34:25 +08:00
fan
75b5e81ad4 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-18 16:33:25 +08:00
fan
3823eea337 参数名调整 2024-01-18 16:33:20 +08:00
joylink_zhaoerwei
50a940c245 道岔操作修改 2024-01-18 16:31:31 +08:00
fan
d781b6afd2 列车调整 2024-01-18 16:29:28 +08:00
fan
88a0cd9ec4 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-18 16:07:00 +08:00
fan
c76caa6b58 轮径调整 2024-01-18 16:06:55 +08:00
joylink_zhaoerwei
0f0d925488 道岔操作修改 2024-01-18 16:02:04 +08:00
joylink_zhaoerwei
71612e4613 道岔状态面板和继电器状态面板 2024-01-18 15:30:31 +08:00
fan
94fe367687 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-18 15:00:35 +08:00
fan
6a183f2347 列车状态显示调整 2024-01-18 15:00:31 +08:00
joylink_zhaoerwei
c762a5df55 道岔操作 2024-01-18 13:39:31 +08:00
fan
9cc9c96671 列车配置调整 2024-01-18 13:23:43 +08:00
fan
4bff283635 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-18 10:49:50 +08:00
fan
bebd538f01 列车调整 2024-01-18 10:49:45 +08:00
joylink_zhaoerwei
571b460780 切换场景状态面板重置,继电器操作取消禁用 2024-01-18 09:29:40 +08:00
joylink_zhaoerwei
79f3b05f39 区段复制优化 2024-01-17 18:02:18 +08:00
joylink_zhaoerwei
ae2e524059 道岔区段移动时可吸附到其它道岔区段的端点 2024-01-17 17:43:21 +08:00
joylink_zhaoerwei
58bbdeefda 区段复制优化(端点的偏移) 2024-01-17 13:37:24 +08:00
joylink_zhaoerwei
422eab1811 复制优化 2024-01-17 10:26:03 +08:00
fan
9b6adf3f76 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-16 17:53:06 +08:00
fan
1adb5c4647 添加设备检索 2024-01-16 17:53:00 +08:00
joylink_zhaoerwei
cdfaf6f3eb 框架版本修改+区段吸附(待优化) 2024-01-16 17:41:58 +08:00
fan
3a9d7c5f7d Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-16 16:13:20 +08:00
fan
0767750d2c 应答器状态调整 2024-01-16 16:13:16 +08:00
joylink_zhaoerwei
73300543e1 区段A键盘逻辑修改 2024-01-16 16:11:33 +08:00
fan
e822b6118a 应答器数据处理 2024-01-16 15:46:38 +08:00
fan
8e2d111570 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-16 13:24:19 +08:00
fan
b197c697f3 应答器调整 2024-01-16 13:24:12 +08:00
joylink_zhaoerwei
aff04379d7 增加车站拼音简写 2024-01-16 13:09:11 +08:00
joylink_zhaoerwei
9b2acf4659 框架引入版本修改 2024-01-15 17:23:40 +08:00
joylink_zhaoerwei
29583d4940 增加图形复制控制修改 2024-01-15 16:19:14 +08:00
fan
c90a49e076 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-15 15:16:48 +08:00
fan
9eca541c1f 信号机关灯=》灭灯 2024-01-15 15:16:10 +08:00
joylink_zhaoerwei
ade8346d3b 区段复制插件增加方式修改 2024-01-15 14:11:01 +08:00
joylink_zhaoerwei
0b0d6303cd 绘制复制针对区段增加A键盘操作--代码备用 2024-01-11 17:40:33 +08:00
fan
b08be32d1e 应答器报错信息提示调整 2024-01-11 13:53:31 +08:00
fan
1a3dd02c94 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-11 13:23:31 +08:00
fan
6dad42231d 应答器调整 2024-01-11 13:23:26 +08:00
joylink_zhaoerwei
fcc864241b 微调 2024-01-11 13:21:09 +08:00
joylink_zhaoerwei
4794c99fbf 吸附点逻辑修改,集中区分隔线也加上这个吸附逻辑,相邻点的x/y 2024-01-11 11:30:54 +08:00
fan
178c5758f2 233host调整 2024-01-11 10:30:30 +08:00
fan
a9df480265 应答器列表问题调整 2024-01-10 16:51:29 +08:00
fan
85e4f2da85 Merge branch 'master' of https://git.code.tencent.com/beijing-rtss-test/bj-rtss-client 2024-01-10 15:30:43 +08:00
fan
8fd0277338 应答器调整 2024-01-10 15:30:36 +08:00
joylink_zhaoerwei
81e5c23093 微调 2024-01-10 14:00:23 +08:00
joylink_zhaoerwei
fc23bb11d5 区段吸附点只要物理区段 2024-01-10 13:50:49 +08:00
joylink_zhaoerwei
347dec93d0 区段吸附点修改 2024-01-10 13:34:05 +08:00
joylink_zhaoerwei
ed5463a370 增加继电器操作 2024-01-09 14:44:40 +08:00
joylink_zhaoerwei
0f3b59254f 继电器操作修改 2024-01-09 13:57:14 +08:00
dong
f813cea9e9 代码调整 2024-01-05 13:21:18 +08:00
183 changed files with 20018 additions and 13049 deletions

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "bj-rtss-message"]
path = bj-rtss-message
url = ../bj-rtss-message.git
[submodule "rts-sim-testing-message"]
path = rts-sim-testing-message
url = http://120.46.212.6:3000/joylink/rts-sim-testing-message.git

@ -1 +0,0 @@
Subproject commit 999608fa88a430cba9bef8915f76993a0e4c6d8e

10502
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,12 +22,13 @@
"default-passive-events": "^2.0.0",
"echarts": "^5.4.3",
"google-protobuf": "^3.21.2",
"jl-graphic": "git+https://git.code.tencent.com/jl-framework/graphic-pixi.git#v0.1.3",
"jl-graphic": "git+http://120.46.212.6:3000/joylink/graphic-pixi.git#v0.1.11",
"js-base64": "^3.7.5",
"pinia": "^2.0.11",
"quasar": "^2.6.0",
"vue": "^3.0.0",
"vue-router": "^4.0.0"
"vue-router": "^4.0.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@quasar/app-vite": "^1.0.0",
@ -45,7 +46,7 @@
"typescript": "^4.5.4"
},
"engines": {
"node": "^18 || ^16 || ^14.19",
"node": "^20 || ^18 || ^16 || ^14.19",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
}

View File

@ -32,6 +32,11 @@
<path d="M14.4091 23V11.3636H18.3409C19.2538 11.3636 20 11.5284 20.5795 11.858C21.1629 12.1837 21.5947 12.625 21.875 13.1818C22.1553 13.7386 22.2955 14.3598 22.2955 15.0455C22.2955 15.7311 22.1553 16.3542 21.875 16.9148C21.5985 17.4754 21.1705 17.9223 20.5909 18.2557C20.0114 18.5852 19.2689 18.75 18.3636 18.75H15.5455V17.5H18.3182C18.9432 17.5 19.4451 17.392 19.8239 17.1761C20.2027 16.9602 20.4773 16.6686 20.6477 16.3011C20.822 15.9299 20.9091 15.5114 20.9091 15.0455C20.9091 14.5795 20.822 14.1629 20.6477 13.7955C20.4773 13.428 20.2008 13.1402 19.8182 12.9318C19.4356 12.7197 18.928 12.6136 18.2955 12.6136H15.8182V23H14.4091Z" fill="white"/>
<line y1="32" x2="35" y2="32" stroke="white" stroke-width="4"/>
</symbol>
<symbol id="icon-garage-door-box" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="33" height="32" stroke="white" stroke-width="2"/>
<path d="M17.1932 14C17.0838 13.6652 16.9396 13.3653 16.7607 13.1001C16.585 12.8317 16.3745 12.603 16.1293 12.4141C15.8873 12.2251 15.6122 12.081 15.304 11.9815C14.9957 11.8821 14.6577 11.8324 14.2898 11.8324C13.6866 11.8324 13.138 11.9882 12.6442 12.2997C12.1503 12.6113 11.7576 13.0703 11.4659 13.6768C11.1742 14.2834 11.0284 15.0275 11.0284 15.9091C11.0284 16.7907 11.1759 17.5348 11.4709 18.1413C11.7659 18.7479 12.1652 19.2069 12.669 19.5185C13.1728 19.83 13.7396 19.9858 14.3693 19.9858C14.9527 19.9858 15.4664 19.8615 15.9105 19.6129C16.358 19.361 16.706 19.0064 16.9545 18.549C17.2064 18.0883 17.3324 17.5464 17.3324 16.9233L17.7102 17.0028H14.6477V15.9091H18.5256V17.0028C18.5256 17.8414 18.3466 18.5705 17.9886 19.1903C17.634 19.8101 17.1435 20.2907 16.517 20.6321C15.8939 20.9702 15.178 21.1392 14.3693 21.1392C13.4678 21.1392 12.6757 20.9271 11.9929 20.5028C11.3134 20.0786 10.7831 19.4754 10.402 18.6932C10.0241 17.911 9.83523 16.983 9.83523 15.9091C9.83523 15.1037 9.94295 14.3795 10.1584 13.7365C10.3771 13.0902 10.6854 12.54 11.0831 12.0859C11.4808 11.6319 11.9515 11.2839 12.495 11.0419C13.0386 10.8 13.6368 10.679 14.2898 10.679C14.8267 10.679 15.3272 10.7602 15.7912 10.9226C16.2585 11.0817 16.6745 11.3087 17.0391 11.6037C17.407 11.8954 17.7135 12.245 17.9588 12.6527C18.2041 13.0571 18.3731 13.5062 18.4659 14H17.1932Z" fill="white"/>
<line y1="32" x2="35" y2="32" stroke="white" stroke-width="4"/>
</symbol>
<symbol id="icon-esb-button" viewBox="0 0 35 34" fill="none">
<rect x="1" y="1" width="33" height="32" stroke="white" stroke-width="2"/>
<line y1="32" x2="35" y2="32" stroke="white" stroke-width="4"/>
@ -75,4 +80,10 @@
<path d="M20 27H39" stroke="#FFFFFF"/>
<path d="M29 27V43" stroke="#FFFFFF"/>
</symbol>
<symbol id="icon-car-washing" viewBox="0 0 150 150" fill="none">
<rect x="45" y="3" width="60" height="144" fill="#FFFFFF" stroke="#FFFFFF"/>
</symbol>
<symbol id="icon-flood-gate" viewBox="0 0 129 139" fill="none">
<path fill-rule="evenodd" stroke="rgba(255, 255, 255, 1)" stroke-width="5" d="M0 1.5L61.5 1.5M61.5 1.5L123 1.5M61.5 1.5L61.5 137.5L0 137.5L123 137.5"/>
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

@ -0,0 +1 @@
Subproject commit a1534096aa1ed2566b93ffe7bfde76750de10a60

View File

@ -7,7 +7,7 @@ const os = require('os');
const { exec } = require('child_process');
const messageDir = resolve(__dirname, '../bj-rtss-message');
const messageDir = resolve(__dirname, '../rts-sim-testing-message');
const protoDir = resolve(messageDir, 'protos');
const destDir = resolve(__dirname, '../src/protos');

View File

@ -118,7 +118,8 @@ export async function getPublishMapInfoByLineId(
export function saveToDraft(
id: number,
data: {
name: string;
draftName: string;
category: string;
}
) {
return api.post(`${PublishUriBase}/saveAsDrafting/${id}`, data);

View File

@ -1,4 +1,6 @@
import { api } from 'src/boot/axios';
import { request } from 'src/protos/request';
import { TrainConfigData } from './TrainModelApi';
const UriBase = '/api/v1/simulation';
@ -20,6 +22,16 @@ export async function destroySimulation(data: { simulationId: string }) {
return response.data;
}
export interface TrainEnd {
radarCheckSpeedDiff: number;
radarCheckTime: number;
radarEnable: boolean;
speedSensorEnableA: boolean;
speedSensorEnableB: boolean;
accOutSpeed: number;
radarOutSpeed: number;
}
/**
*
* @param simulationId 仿id
@ -29,36 +41,43 @@ export async function destroySimulation(data: { simulationId: string }) {
* @param devicePort
* @param headOffset A端为偏移原点
* @param trainLength
* @param trainId
* @param trainSpeed
*/
export async function addTrain(data: {
simulationId: string;
mapId: number;
up: boolean;
id: number;
trainId: number;
trainSpeed: number;
devicePort?: string;
headOffset: number;
trainLength?: number;
configTrain: TrainConfigData;
trainEndsA: TrainEnd;
trainEndsB: TrainEnd;
}) {
const response = await api.post(`${UriBase}/train/add`, data);
return response.data;
}
/**
*
*
* @param id id
* @param simulationId 仿id
* @param trainLength
* @param wheelDiameter
*/
export async function updateTrain(data: {
id: string;
simulationId: string;
trainLength?: number;
wheelDiameter?: number;
}) {
const response = await api.post(`${UriBase}/train/update`, data);
return response.data;
}
// export async function updateTrain(data: {
// id: string;
// simulationId: string;
// trainLength?: number;
// wheelDiameter?: number;
// }) {
// const response = await api.post(`${UriBase}/train/update`, data);
// return response.data;
// }
/**
*
@ -74,22 +93,48 @@ export async function removeTrain(data: {
return response.data;
}
/**
*
*/
export async function removeAllTrain(data: {
simulationId: string;
mapId: number;
}) {
const response = await api.post(`${UriBase}/train/remove/all`, data);
return response.data;
}
export async function setAxleSectionState(data: {
simulationId: string;
mapId: number;
id: number;
operation: number;
deviceId: number;
operation: request.Section.Operation;
param?: {
mockDrst: boolean;
mockPdrst: boolean;
};
}) {
return await api.post(`${UriBase}/axleSection/operation`, data);
}
export async function setSignalState(data: {
// {
// simulationId: string;
// mapId: number;
// id: number;
// operation: number;
// aspect: number;
// }
export interface SignalOperationReq {
simulationId: string;
mapId: number;
id: number;
operation: number;
aspect: number;
}) {
deviceId: number;
operation: request.Signal.Operation;
param: {
force: request.Signal.Force;
dsList: request.Signal.DS[];
};
}
export async function setSignalState(data: SignalOperationReq) {
return await api.post(`${UriBase}/signal/operation`, data);
}
@ -98,6 +143,7 @@ export interface SetSwitchParams {
mapId: number;
deviceId: number;
operation: number;
param: { forcePosition: number };
}
export async function setSwitchPosition(data: SetSwitchParams) {
@ -109,7 +155,7 @@ export interface IbpButtonOperationParams {
down: boolean;
mapId: number;
simulationId: string;
stationId: number;
ibpId: number;
}
export async function ibpButtonOperation(params: IbpButtonOperationParams) {
return await api.post(`${UriBase}/ibp/btn/operation`, params);
@ -129,7 +175,7 @@ export async function esbButtonOperation(params: EsbButtonOperationParams) {
export interface IbpKeyOperationParams {
simulationId: string;
mapId: number;
stationId: number;
ibpId: number;
gear: number;
keyId: number;
}
@ -192,10 +238,10 @@ export async function getSimulationChannelName(): Promise<string> {
* @returns
*/
export async function setRelayState(data: {
id: number;
mapId: number;
simulationId: string;
td: boolean;
mapId: number;
deviceId: number;
operation: request.Relay.Operation;
}) {
return await api.post(`${UriBase}/relay/operation`, data);
}
@ -224,7 +270,7 @@ export async function getMapKilometerRange(
export async function pslOperate(data: {
simulationId: string;
mapId: number;
gateBoxId: number;
pslId: number;
buttonCode: string;
down: boolean;
}) {
@ -237,9 +283,150 @@ export async function screenDoorOperate(data: {
simulationId: string;
mapId: number;
deviceId: number;
operation: number;
asdCodes?: number[];
group?: number;
operation: request.Psd.Operation;
param: {
asdCodes: number[];
force: request.Psd.Force;
fault: request.Psd.Fault;
};
}) {
return await api.post(`${UriBase}/psd/operation`, data);
}
/**
*
*/
export async function updateMessageTransponder(data: {
simulationId: string;
mapId: number;
fixedTelegram: string;
fixedUserTelegram: string;
variableTelegram: string;
variableUserTelegram: string;
baliseId: number;
}) {
return await api.put(`${UriBase}/balise/telegram/modify`, data);
}
/**
*
*/
export async function resetMessageTransponder(data: {
simulationId: string;
mapId: number;
baliseId: number;
}) {
return await api.put(`${UriBase}/balise/telegram/reset`, data);
}
/**
*
*/
export async function updatePositionTransponder(data: {
simulationId: string;
mapId: number;
baliseId: number;
km: {
coordinateSystem: string;
kilometer: number;
direction: number;
};
}) {
return await api.put(`${UriBase}/balise/position/modify`, data);
}
/**
*
*/
export async function resetPositionTransponder(data: {
simulationId: string;
mapId: number;
baliseId: number;
}) {
return await api.put(`${UriBase}/balise/position/reset`, data);
}
/**
*
*/
export async function initTranspondersState(simulationId: string) {
return await api.put(`${UriBase}/balise/reset?simulationId=${simulationId}`);
}
export interface TrainConfig {
trainId: number;
length: number;
simulationId: string;
wheelDiameter: number;
configData: {
davisParamA: number;
davisParamB: number;
davisParamC: number;
curveResistanceParamR1: number;
curveResistanceParamR2: number;
curveResistanceParamR3: number;
curveResistanceParamR4: number;
jump: boolean;
revolvingMassParam: number;
slide: number;
slipA: number;
slipR: number;
slipD: number;
stopSign: number;
idlingA: number;
idlingR: number;
idlingD: number;
};
trainEndsA: {
radarCheckSpeedDiff: number;
radarCheckTime: number;
radarEnable: boolean;
speedSensorEnableA: boolean;
speedSensorEnableB: boolean;
accOutSpeed: number;
radarOutSpeed: number;
};
trainEndsB: {
radarCheckSpeedDiff: number;
radarCheckTime: number;
radarEnable: boolean;
speedSensorEnableA: boolean;
speedSensorEnableB: boolean;
accOutSpeed: number;
radarOutSpeed: number;
};
}
/** 列车参数修改 */
export async function updateTrainConfig(data: TrainConfig) {
return await api.post(`${UriBase}/train/config`, data);
}
/** 应答器停止发送报文 */
export async function stopTransponderTelegram(data: {
simulationId: string;
mapId: number;
baliseId: number;
}) {
return await api.put(`${UriBase}/balise/telegram/stop`, data);
}
/** 应答器取消停止发送报文 */
export async function sendTransponderTelegram(data: {
simulationId: string;
mapId: number;
baliseId: number;
}) {
return await api.put(`${UriBase}/balise/telegram/send`, data);
}
/** 获取列车可以连接平台列表 */
export async function getCanLinkPlatForm(id: string) {
return await api.get(`${UriBase}/train/conn/type/${id}`);
}
/** 修改列车连接 */
export async function updateTrainConn(data: {
id: string;
simulationId: string;
connType: number;
}) {
return await api.post(`${UriBase}/train/conn`, data);
}

View File

@ -27,15 +27,37 @@ export async function pageQuery(
return response.data;
}
export interface TrainConfigData {
davisParamA: number;
davisParamB: number;
davisParamC: number;
curveResistanceParamR1: number;
curveResistanceParamR2: number;
curveResistanceParamR3: number;
curveResistanceParamR4: number;
jump: boolean;
revolvingMassParam: number;
slide: number;
slipA: number;
slipR: number;
slipD: number;
stopSign: number;
idlingA: number;
idlingR: number;
idlingD: number;
}
export interface TrainCreateParams {
carriage_length: number;
description: string;
max_diameter: number;
min_diameter: number;
// max_diameter: number;
// min_diameter: number;
name: string;
total_length: number;
train_model: number;
train_sets: string;
trainConfigData?: TrainConfigData;
trainControlMapId: number;
}
/**

View File

@ -12,4 +12,4 @@
<path fill="#00B4FF"
d="M.5 251.9c29.6-.5 59.2-.8 88.8-1l88.7-.3 88.7.3 44.4.4 44.4.6-44.4.6-44.4.4-88.7.3-88.7-.3a7981 7981 0 01-88.8-1z" />
<path fill="none" d="M-565.2 324H-252v15.8h-313.2z" />
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -67,6 +67,9 @@ export class ApiError {
// for each client)
const api = axios.create({ baseURL: getHttpBase() });
let isOpenDialog = false; // 认证弹窗是否打开
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
export default boot(({ app, router }) => {
// for use inside Vue files (Options API) through this.$axios and this.$api
@ -74,6 +77,10 @@ export default boot(({ app, router }) => {
api.interceptors.request.use(
(config) => {
config.headers.Authorization = getJwtToken();
config.cancelToken = source.token;
if (isOpenDialog) {
source.cancel();
}
return config;
},
(err: AxiosError) => {

View File

@ -3,6 +3,7 @@
ref="dialogRef"
@hide="onHide"
v-bind="$attrs"
@show="emit('show')"
transitionShow="jump-up"
transitionHide="jump-down"
class="column"
@ -11,17 +12,22 @@
: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"
style="
cursor: move;
border-top-right-radius: 0;
border-top-left-radius: 0;
"
:style="`height: ${props.titleHeight}px;background: ${props.titleColor}`"
>
<div
:style="`color:${props.fontColor};font-size: ${props.fontSize}px;`"
:style="`height: 100%; line-height: ${props.titleHeight}px; color:${props.fontColor};font-size: ${props.fontSize}px;`"
>
{{ props.title }}
</div>
@ -45,7 +51,10 @@
import { QBar, useDialogPluginComponent } from 'quasar';
import { ref, onMounted, onUnmounted, reactive } from 'vue';
const emit = defineEmits([...useDialogPluginComponent.emits]);
const emit = defineEmits({
...useDialogPluginComponent.emitsObject,
show: () => true,
});
const props = withDefaults(
defineProps<{
@ -57,10 +66,11 @@ const props = withDefaults(
width?: number;
height?: number;
bgColor?: string;
bgBorder?: string;
}>(),
{
width: 500,
height: 600,
height: 800,
titleColor: 'rgb(25,118,210)',
titleHeight: 36,
fontSize: 20,
@ -68,7 +78,8 @@ const props = withDefaults(
}
);
const { dialogRef, onDialogHide } = useDialogPluginComponent();
const { dialogRef, onDialogHide /* , onDialogCancel, onDialogOK */ } =
useDialogPluginComponent();
const headerRef = ref<InstanceType<typeof QBar> | null>(null);
@ -78,6 +89,7 @@ const offset = reactive({
});
const start = { x: 0, y: 0 };
const startOffset = { x: 0, y: 0 };
onMounted(() => {
window.addEventListener('mousedown', onMouseDown);
@ -88,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);
}

View File

@ -39,12 +39,17 @@
<platform-property
v-if="drawStore.selectedGraphicType === Platform.Type"
></platform-property>
<ibpBox-property
v-if="drawStore.selectedGraphicType === IbpBox.Type"
></ibpBox-property>
<pslBox-property
v-if="drawStore.selectedGraphicType === PslBox.Type"
></pslBox-property>
<screenDoor-property
v-if="drawStore.selectedGraphicType === ScreenDoor.Type"
></screenDoor-property>
<station-property
v-if="drawStore.selectedGraphicType === Station.Type"
:ibpNameList="ibpNameList"
></station-property>
<!-- <train-property
v-if="drawStore.selectedGraphicType === Train.Type"
@ -90,7 +95,6 @@
></spks-switch-property>
<gated-box-property
v-else-if="drawStore.selectedGraphicType === GatedBox.Type"
:pslNameList="pslNameList"
></gated-box-property>
<esb-button-property
v-else-if="drawStore.selectedGraphicType === EsbButton.Type"
@ -135,6 +139,18 @@
drawStore.selectedGraphicType === ConcentrationDividingLine.Type
"
/>
<flood-gate-property
v-else-if="drawStore.selectedGraphicType === FloodGate.Type"
/>
<car-washing-property
v-else-if="drawStore.selectedGraphicType === CarWashing.Type"
></car-washing-property>
<garage-door-property
v-else-if="drawStore.selectedGraphicType === GarageDoor.Type"
></garage-door-property>
<garage-door-box-property
v-else-if="drawStore.selectedGraphicType === GarageDoorBox.Type"
></garage-door-box-property>
</q-card-section>
</template>
<template v-else-if="drawStore.selectedGraphics.length > 1">
@ -152,6 +168,10 @@ import PolygonProperty from './properties/PolygonProperty.vue';
import { Polygon } from 'src/graphics/polygon/Polygon';
import PlatformProperty from './properties/PlatformProperty.vue';
import { Platform } from 'src/graphics/platform/Platform';
import IbpBoxProperty from './properties/IbpBoxProperty.vue';
import { IbpBox } from 'src/graphics/ibpBox/IbpBox';
import PslBoxProperty from './properties/PslBoxProperty.vue';
import { PslBox } from 'src/graphics/pslBox/PslBox';
import ScreenDoorProperty from './properties/ScreenDoorProperty.vue';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import StationProperty from './properties/StationProperty.vue';
@ -196,7 +216,6 @@ import CurvatureKiloMarkerProperty from './properties/CurvatureKiloMarkerPropert
import { SlopeKiloMarker } from 'src/graphics/slopeKiloMarker/SlopeKiloMarker';
import { Slope } from 'src/graphics/slope/Slope';
import SlopeProperty from './properties/SlopeProperty.vue';
import { Link } from 'src/graphics/link/Link';
// import LinkProperty from './properties/LinkProperty.vue';
import { Curvature } from 'src/graphics/curvature/Curvature';
import CurvatureProperty from './properties/CurvatureProperty.vue';
@ -208,35 +227,16 @@ import { TrackSection } from 'src/graphics/trackSection/TrackSection';
import TrackLogicSectionProperty from './properties/TrackLogicSectionProperty.vue';
import { TrackLogicSection } from 'src/graphics/trackLogicSection/TrackLogicSection';
import MultipleSelectProperty from './properties/multipleSelectProperty.vue';
import { onMounted } from 'vue';
import { getPublishList } from 'src/api/PublishApi';
import { PictureType } from 'src/protos/picture';
import { DepartureTimer } from 'src/graphics/departureTimer/DepartureTimer';
import DepartureTimerProperty from './properties/DepartureTimerProperty.vue';
import FloodGateProperty from './properties/FloodGateProperty.vue';
import { FloodGate } from 'src/graphics/floodGate/FloodGate';
import GarageDoorProperty from './properties/GarageDoorProperty.vue';
import { GarageDoor } from 'src/graphics/garageDoor/GarageDoor';
import CarWashingProperty from './properties/CarWashingProperty.vue';
import { CarWashing } from 'src/graphics/carWashing/CarWashing';
import GarageDoorBoxProperty from './properties/GarageDoorBoxProperty.vue';
import { GarageDoorBox } from 'src/graphics/garageDoorBox/GarageDoorBox';
const drawStore = useDrawStore();
const ibpNameList: string[] = [];
const pslNameList: string[] = [];
onMounted(() => {
getPublishList({
type: PictureType.IBP,
category: drawStore.categoryType,
}).then((ibpMapList) => {
if (ibpMapList && ibpMapList.length) {
ibpMapList.forEach((item) => {
ibpNameList.push(item.name);
});
}
});
getPublishList({
type: PictureType.Psl,
category: drawStore.categoryType,
}).then((pslMapList) => {
if (pslMapList && pslMapList.length) {
pslMapList.forEach((item) => {
pslNameList.push(item.name);
});
}
});
});
</script>

View File

@ -0,0 +1,49 @@
<template>
<!-- 画布或图形对象属性 -->
<div v-if="tccDrawStore.selectedGraphics !== null">
<q-card flat>
<q-card-section>
<div class="text-h6">
{{ tccDrawStore.selectedObjName + ' 属性' }}
</div>
</q-card-section>
<q-separator inset></q-separator>
<template v-if="tccDrawStore.selectedGraphics.length === 0">
<q-card-section>
<canvas-tcc-property></canvas-tcc-property>
</q-card-section>
</template>
<template v-else-if="tccDrawStore.selectedGraphics.length === 1">
<q-card-section>
<tcc-button-property
v-if="tccDrawStore.selectedGraphicType === TccButton.Type"
/>
<tcc-text-property
v-if="tccDrawStore.selectedGraphicType === TextContent.Type"
/>
<tcc-key-property
v-else-if="tccDrawStore.selectedGraphicType === TccKey.Type"
/>
<tcc-handle-property
v-else-if="tccDrawStore.selectedGraphicType === TccHandle.Type"
/>
</q-card-section>
</template>
</q-card>
</div>
</template>
<script setup lang="ts">
import { useTccDrawStore } from 'src/stores/tcc-draw-store';
import CanvasTccProperty from './properties/CanvasTccProperty.vue';
import { TccButton } from 'src/graphics/tccButton/TccButton';
import TccButtonProperty from './properties/TccButtonProperty.vue';
import { TextContent } from 'src/graphics/textContent/TextContent';
import TccTextProperty from './properties/TccTextProperty.vue';
import { TccKey } from 'src/graphics/tccKey/TccKey';
import TccKeyProperty from './properties/TccKeyProperty.vue';
import { TccHandle } from 'src/graphics/tccHandle/TccHandle';
import TccHandleProperty from './properties/TccHandleProperty.vue';
const tccDrawStore = useTccDrawStore();
</script>

View File

@ -1,12 +1,16 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<q-dialog ref="dialogRef">
<draggable-dialog
seamless
title="添加列车"
v-model="showAddTrainOperation"
:width="300"
:height="525"
>
<q-card style="width: 300px">
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<div class="text-h6">添加列车</div>
<q-input
dense
outlined
readonly
:label="props.dev.type"
@ -14,7 +18,21 @@
/>
<q-input
type="number"
dense
outlined
label="列车编号"
v-model.number="trainId"
lazy-rules
/>
<q-input
type="number"
outlined
label="列车初始速度(km/h)"
:min="0"
v-model.number="trainSpeed"
lazy-rules
/>
<q-input
type="number"
outlined
:label="`列车偏移(mm)【长度${props.kmLength}mm】`"
:max="kmLength"
@ -26,7 +44,6 @@
<q-select
v-model="dir"
label="运行方向"
dense
outlined
:options="dirOptions"
emitValue
@ -37,7 +54,6 @@
<q-select
v-model="trainConfig"
label="列车配置"
dense
outlined
:options="trainConfigOption"
:option-label="
@ -55,39 +71,43 @@
</q-select>
<q-input
type="number"
dense
outlined
:label="`列车轮径(mm)【${
trainConfig ? trainConfig.min_diameter : ''
}-${trainConfig ? trainConfig.max_diameter : ''}mm`"
:max="trainConfig?.max_diameter"
:min="trainConfig?.min_diameter"
:label="`列车轮径(mm)【750-840mm】`"
:max="840"
:min="750"
v-model.number="wheelDiameter"
lazy-rules
:rules="wheelDiameterRules"
/>
<q-card-actions align="right" class="text-primary">
<q-btn flat label="取消" @click="onDialogCancel" v-close-popup />
<q-btn
flat
label="取消"
@click="showAddTrainOperation = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" :disable="!trainConfig" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</q-dialog>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm, useDialogPluginComponent } from 'quasar';
import { TrainConfigItem } from 'src/api/TrainModelApi';
import { QForm } from 'quasar';
import { TrainConfigData, TrainConfigItem } from 'src/api/TrainModelApi';
import { Section } from 'src/graphics/section/Section';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useLineStore } from 'src/stores/line-store';
import { computed, onMounted, ref } from 'vue';
import { computed, onMounted, ref, onUnmounted } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { addTrain } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
const props = defineProps({
dev: {
type: [Section, Turnout],
type: Section,
required: true,
},
kmLength: {
@ -108,10 +128,10 @@ const dirOptions = [
{ label: '上行', value: 1 },
{ label: '下行', value: 0 },
];
const trainSpeed = ref(0);
const trainId = ref(1);
defineEmits([...useDialogPluginComponent.emits]);
const { dialogRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
const showAddTrainOperation = ref(true);
const offsetRules = [
(val: string) => (val !== null && val !== '') || '偏移量不能为空!',
@ -128,12 +148,45 @@ const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
onDialogOK({
dir: dir.value,
offset: offset.value,
trainLength: trainConfig.value?.total_length,
if (!trainConfig.value) {
return;
}
const lineStore = useLineStore();
const params = {
simulationId: lineStore.simulationId || '',
mapId: lineStore.mapId || 0,
up: !!dir.value,
id: props.dev.datas.id,
headOffset: offset.value,
trainId: trainId.value,
trainSpeed: trainSpeed.value,
wheelDiameter: wheelDiameter.value,
trainLength: trainConfig.value.total_length,
configTrain: trainConfig.value.trainConfigData as TrainConfigData,
trainControlMapId: trainConfig.value.trainControlMapId,
trainEndsA: {
radarCheckSpeedDiff: 0,
radarCheckTime: 0,
radarEnable: true,
speedSensorEnableA: true,
speedSensorEnableB: true,
accOutSpeed: 0,
radarOutSpeed: 0,
},
trainEndsB: {
radarCheckSpeedDiff: 0,
radarCheckTime: 0,
radarEnable: true,
speedSensorEnableA: true,
speedSensorEnableB: true,
accOutSpeed: 0,
radarOutSpeed: 0,
},
};
addTrain(params).catch((err) => {
errorNotify(`添加列车失败!: ${err.title}`, err);
});
showAddTrainOperation.value = false;
}
});
}
@ -141,13 +194,7 @@ function onCreate() {
const wheelDiameter = ref(800);
const wheelDiameterRules = [
(val: string) => (val !== null && val !== '') || '列车轮径不能为空!',
(val: number) =>
(trainConfig.value &&
val >= trainConfig.value.min_diameter &&
val <= trainConfig.value.max_diameter) ||
`列车轮径在${trainConfig.value ? trainConfig.value.min_diameter : ''}${
trainConfig.value ? trainConfig.value.max_diameter : ''
}mm之间`,
(val: number) => (val >= 750 && val <= 840) || '列车轮径在750到840mm之间',
];
const trainConfigOption = computed(() => {
@ -158,15 +205,17 @@ const trainConfig = ref<TrainConfigItem | null>({
id: 0,
carriage_length: 0,
description: '',
max_diameter: 0,
min_diameter: 0,
name: '',
total_length: 0,
train_model: 0,
train_sets: '',
trainControlMapId: 0,
});
function setConfigVal(val: TrainConfigItem | null) {
trainConfig.value = val || null;
}
onUnmounted(() => {
lineStore.deviceOpreratDialogInstance = null;
});
</script>
<style scoped></style>

View File

@ -0,0 +1,251 @@
<template>
<draggable-dialog
seamless
title="驱采状态"
:width="dialogWidth"
:height="500"
>
<q-tabs
v-model="tab"
dense
active-color="primary"
indicator-color="primary"
align="justify"
narrow-indicator
>
<q-tab
v-for="(item, index) in tabList"
:key="index"
:name="item.value"
:label="item.label"
/>
</q-tabs>
<q-separator />
<q-tab-panels v-model="tab" animated keep-alive>
<template v-for="tabInfo in tabList" :key="tabInfo.label">
<q-tab-panel :name="tabInfo.value">
<div
class="row no-wrap"
v-for="row in showSetCellMessage.rows"
:key="row"
>
<div
class="ceil"
:class="{
CellGreen:
row > 1 &&
col > 1 &&
tabInfo.ListMap.get(`${row - 1}-${col - 1}`),
changeCellSize: col == 1,
CellRed:
row > 1 &&
col > 1 &&
tabInfo.ListMap.get(`${row - 1}-${col - 1}`) &&
tabInfo.stateMap.get(`${row - 1}-${col - 1}`),
}"
v-for="col in showSetCellMessage.cols"
:key="col"
@click="handleCellClick(row, col)"
>
<span v-if="row == 1 && col == 1"> 位置</span>
<span v-else-if="row == 1 || col == 1">
{{ row == 1 ? col - 1 : row - 1 }}</span
>
<div
v-else
@mouseover="onMouseOver"
@mouseleave="showTooltip = false"
>
{{ tabInfo.ListMap.get(`${row - 1}-${col - 1}`) }}
<q-tooltip
anchor="bottom middle"
self="bottom middle"
v-if="showTooltip"
>
{{ tabInfo.ListMap.get(`${row - 1}-${col - 1}`) }}
</q-tooltip>
</div>
</div>
</div>
</q-tab-panel>
</template>
</q-tab-panels>
</draggable-dialog>
</template>
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue';
import { useLineStore } from 'src/stores/line-store';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { relayCabinetGraphicData } from 'src/protos/relayCabinetLayoutGraphics';
import { refRelaysListMap, sceneCiCjQdListMap } from 'src/drawApp/relayScene';
import { Relay } from 'src/graphics/relay/Relay';
import { JlGraphic } from 'jl-graphic';
import { useTestManageStore } from 'src/stores/testManage-store';
const testManageStore = useTestManageStore();
const lineStore = useLineStore();
const tab = ref('CiCj');
const tabList = ref([
{
label: '采集状态',
value: 'CiCj',
ListMap: new Map<string, string>(),
stateMap: new Map<string, boolean>(),
},
{
label: '驱动状态',
value: 'CiQd',
ListMap: new Map<string, string>(),
stateMap: new Map<string, boolean>(),
},
]);
const setCellMessage = ref<{ rows: number; cols: number }>({
rows: 32,
cols: 8,
});
const showSetCellMessage = computed(() => {
return {
rows: setCellMessage.value.rows + 1,
cols: setCellMessage.value.cols + 1,
};
});
let ciCjList = sceneCiCjQdListMap.get(
`${lineStore.sceneName}+ciCjList`
) as relayCabinetGraphicData.CiCj;
let ciQdList = sceneCiCjQdListMap.get(
`${lineStore.sceneName}+ciQdList`
) as relayCabinetGraphicData.CiQd;
const dialogWidth = computed(() => {
return setCellMessage.value.cols * 134 + 85;
});
watch(
() => testManageStore.stationQc,
(val) => {
if (val) {
val.cjStates.forEach((state) => {
tabList.value[0].stateMap.set(
`${state.row + 1}-${state.col + 1}`,
state.on
);
});
val.qdStates.forEach((state) => {
tabList.value[1].stateMap.set(
`${state.row + 1}-${state.col + 1}`,
state.on
);
});
}
}
);
onMounted(() => {
setCellMessage.value.rows = ciCjList.dsCount;
setCellMessage.value.cols = ciCjList.cjList.length;
tabList.value[0].ListMap = updateCiCjListMap();
tabList.value[1].ListMap = updateCiQdListMap();
});
function updateCiCjListMap() {
const showCiCjListMap = new Map<string, string>();
ciCjList?.cjList.forEach((cjDataSet, i) => {
cjDataSet.bitList.forEach((cjData, j) => {
const ref = cjData.refRelays.map((refRelay) => {
const refDeviceData = refRelaysListMap.get(refRelay.relayId);
const relay = lineStore
.getLineApp()
.getScene(lineStore.sceneName)
.queryStore.queryById<Relay>(refRelay.relayId);
const pos =
refRelay.position == relayCabinetGraphicData.CjDataItem.PostionType.Q
? 'Q'
: 'H';
if (refDeviceData?.device) {
return `${refDeviceData.device}_${refDeviceData?.combinationtype}_${relay.datas.code}_${pos}`;
} else {
return `${refDeviceData?.combinationtype}_${relay.datas.code}_${pos}`;
}
});
showCiCjListMap.set(`${j + 1}-${i + 1}`, ref.join('/'));
});
});
return showCiCjListMap;
}
function updateCiQdListMap() {
const showCiQdListMap = new Map<string, string>();
ciQdList?.qdList.forEach((cjDataSet, i) => {
cjDataSet.bitList.forEach((cjData, j) => {
const ref = cjData.refRelays.map((refRelay) => {
const refDeviceData = refRelaysListMap.get(refRelay);
const relay = lineStore
.getLineApp()
.getScene(lineStore.sceneName)
.queryStore.queryById<Relay>(refRelay);
if (refDeviceData?.device) {
return `${refDeviceData.device}_${refDeviceData.combinationtype}_${relay.datas.code}`;
} else {
return `${refDeviceData?.combinationtype}_${relay.datas.code}`;
}
});
showCiQdListMap.set(`${j + 1}-${i + 1}`, ref.join('/'));
});
});
return showCiQdListMap;
}
function handleCellClick(row: number, col: number) {
if (row == 1 || col == 1) return;
const app = lineStore.getLineApp().getScene(lineStore.sceneName);
app.updateSelected();
const select: JlGraphic[] = [];
if (tab.value == 'CiCj') {
ciCjList.cjList[col - 2].bitList[row - 2].refRelays.forEach((relay) => {
const g = app.queryStore.queryById(relay.relayId) as Relay;
select.push(g);
});
} else {
ciQdList.qdList[col - 2].bitList[row - 2].refRelays.forEach((relayId) => {
const g = app.queryStore.queryById(relayId) as Relay;
select.push(g);
});
}
app.updateSelected(...select);
app.makeGraphicCenterShow(...select);
}
const showTooltip = ref(false);
function onMouseOver(e: MouseEvent) {
if ((e.target as HTMLElement).clientHeight > 30) {
showTooltip.value = true;
}
}
</script>
<style scoped>
.ceil {
width: 120px;
height: 30px;
border: solid 1px red;
margin: 7px;
cursor: pointer;
text-align: center;
line-height: 30px;
word-break: break-all;
overflow: hidden;
}
.changeCellSize {
width: 40px;
}
.CellGreen {
border: solid 1px green;
background-color: green;
}
.CellRed {
border: solid 1px red;
background-color: red;
}
</style>

View File

@ -66,6 +66,8 @@ const deviceTypeMap = {
8: '信号机故障报警仪',
9: '断路器',
10: '电源屏',
11: '车库门',
12: '洗车机',
};
const columns: QTable['columns'] = [
{

View File

@ -0,0 +1,167 @@
<template>
<DraggableDialog seamless :height="73" title="设备检索">
<q-card class="q-pa-sm">
<q-select
filled
v-model="deviceId"
label="设备检索"
use-input
hide-selected
fill-input
input-debounce="0"
:options="serachDeviceList"
:map-options="true"
:emit-value="true"
@filter="filterFn"
@update:model-value="onJump"
style="width: 450px"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey"> 无匹配数据 </q-item-section>
</q-item>
</template>
</q-select>
</q-card>
</DraggableDialog>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { IDrawApp, IGraphicApp } from 'jl-graphic';
import { Section } from 'src/graphics/section/Section';
import { Transponder } from 'src/graphics/transponder/Transponder';
import { Signal } from 'src/graphics/signal/Signal';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { Platform } from 'src/graphics/platform/Platform';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import { Station } from 'src/graphics/station/Station';
import { SpksSwitch } from 'src/graphics/spksSwitch/SpksSwitch';
import { GatedBox } from 'src/graphics/gatedBox/GatedBox';
import { EsbButton } from 'src/graphics/esbButton/EsbButton';
interface ItemData {
label: string;
value: number;
}
const props = defineProps<{
showDialog: boolean;
app: IDrawApp | IGraphicApp;
}>();
const deviceList = ref<ItemData[]>([]);
const deviceId = ref(0);
const serachDeviceList = ref<ItemData[]>([]);
onMounted(() => {
if (props.showDialog) {
// const graphicsList = props.app.queryStore.getAllGraphics();
const list: ItemData[] = [];
const qs = props.app.queryStore;
const sections = qs.queryByType<Section>(Section.Type);
sections.forEach((item) => {
let station = null;
if (item.datas.centralizedStations[0]) {
station = qs.queryById(item.datas.centralizedStations[0]);
}
list.push({
label: '区段' + item.code + (station ? '【' + station.code + '】' : ''),
value: item.id,
});
});
const transponders = qs.queryByType<Transponder>(Transponder.Type);
transponders.forEach((item) => {
let station = null;
if (item.datas.centralizedStations[0]) {
station = qs.queryById(item.datas.centralizedStations[0]);
}
list.push({
label:
'应答器' + item.code + (station ? '【' + station.code + '】' : ''),
value: item.id,
});
});
const signals = qs.queryByType<Signal>(Signal.Type);
signals.forEach((item) => {
let station = null;
if (item.datas.centralizedStations[0]) {
station = qs.queryById(item.datas.centralizedStations[0]);
}
list.push({
label:
'信号机' + item.code + (station ? '【' + station.code + '】' : ''),
value: item.id,
});
});
const turnouts = qs.queryByType<Turnout>(Turnout.Type);
turnouts.forEach((item) => {
let station = null;
if (item.datas.centralizedStations[0]) {
station = qs.queryById(item.datas.centralizedStations[0]);
}
list.push({
label: '道岔' + item.code + (station ? '【' + station.code + '】' : ''),
value: item.id,
});
});
// const axleCountings = props.app.queryStore.queryByType<AxleCounting>(
// AxleCounting.Type
// );
// axleCountings.forEach((item) => {
// list.push({ label: '' + item.code, value: item.id });
// });
const stations = qs.queryByType<Station>(Station.Type);
stations.forEach((item) => {
list.push({ label: '车站' + item.code, value: item.id });
});
const platforms = qs.queryByType<Platform>(Platform.Type);
platforms.forEach((item) => {
list.push({ label: item.code, value: item.id });
});
const screenDoors = qs.queryByType<ScreenDoor>(ScreenDoor.Type);
screenDoors.forEach((item) => {
list.push({ label: '屏蔽门' + item.code, value: item.id });
});
const gatedBoxs = qs.queryByType<GatedBox>(GatedBox.Type);
gatedBoxs.forEach((item) => {
list.push({ label: '门控箱' + item.code, value: item.id });
});
const esbButtons = qs.queryByType<EsbButton>(EsbButton.Type);
esbButtons.forEach((item) => {
list.push({ label: '紧急关闭' + item.code, value: item.id });
});
const spksSwitchs = qs.queryByType<SpksSwitch>(SpksSwitch.Type);
spksSwitchs.forEach((item) => {
list.push({ label: 'SPKS开关' + item.code, value: item.id });
});
deviceList.value = list;
serachDeviceList.value = list;
}
});
function filterFn(val: string, update: any) {
update(() => {
serachDeviceList.value = deviceList.value.filter((v) =>
v.label.includes(val)
);
});
}
function onJump(id: number) {
const device = props.app.queryStore.queryById(id);
props.app.makeGraphicCenterShow(device);
props.app.updateSelected(device);
}
</script>
<style scoped>
.text {
cursor: pointer;
color: #000;
padding: 5px;
}
.text:hover {
color: #09f;
}
</style>

View File

@ -0,0 +1,143 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
seamless
title="导入应答器报文数据"
v-model="showLoadTransData"
:width="300"
:height="249"
>
<q-card style="width: 300px">
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-select
v-model="stationId"
label="应答器所属车站"
outlined
:options="stationOptions"
emitValue
:rules="[(val) => !!val || '应答器所属车站不能为空!']"
mapOptions
hint=""
>
</q-select>
<q-file
outlined
accept=".xlsx,.xls"
label="应答器报文数据文件"
v-model="file"
:rules="[(val) => !!val || '导入文件不能为空']"
>
<template v-slot:prepend>
<q-icon name="attach_file" />
</template>
</q-file>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showLoadTransData = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { onMounted, ref } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { successNotify } from 'src/utils/CommonNotify';
import { Station } from 'src/graphics/station/Station';
import { useDrawStore } from 'src/stores/draw-store';
import * as XLSX from 'xlsx';
import { Transponder } from 'src/graphics/transponder/Transponder';
const drawStore = useDrawStore();
const stationId = ref<number>();
const stationOptions = ref<{ label: string; value: number }[]>([]);
const file = ref<File | null>(null);
const showLoadTransData = ref(true);
onMounted(() => {
const stations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type);
const list: { label: string; value: number }[] = [];
stations.forEach((sta) => {
list.push({ label: sta.datas.stationName, value: sta.datas.id });
});
stationOptions.value = list;
});
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
const station = drawStore
.getDrawApp()
.queryStore.queryById<Station>(stationId.value as number);
const stationNameAcronym = station.datas.stationNameAcronym;
const reader = new FileReader();
reader.onload = function (e: any) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const sheet = workbook.Sheets['应答器报文清单'];
const dataList = XLSX.utils.sheet_to_json(sheet) as {
[propname: string]: string;
}[];
const index = dataList.findIndex((data) =>
Object.values(data).includes('应答器编号')
);
const title = dataList[index];
const titleKeys = Object.keys(title);
const codeIndex = titleKeys.findIndex(
(key) => title[key] === '应答器名称'
);
const userMessageIndex = titleKeys.findIndex(
(key) => title[key] === '用户报文830bits'
);
const messageIndex = titleKeys.findIndex(
(key) => title[key] === '报文1023bits'
);
dataList.forEach((data, i) => {
if (i > index) {
const tranCode =
data[titleKeys[codeIndex]].split('_')[0] +
'_' +
stationNameAcronym;
const transpnder = drawStore
.getDrawApp()
.queryStore.queryByCodeAndType<Transponder>(
tranCode,
Transponder.Type
);
if (transpnder) {
const datas = transpnder.datas.clone();
datas.fixedTelegram = data[titleKeys[messageIndex]].replaceAll(
' ',
''
);
datas.fixedUserTelegram = data[
titleKeys[userMessageIndex]
].replaceAll(' ', '');
transpnder.updateData(datas);
}
}
});
showLoadTransData.value = false;
successNotify('导入应答器报文成功!');
};
if (file.value) {
reader.readAsArrayBuffer(file.value);
}
}
});
}
</script>
<style scoped></style>

View File

@ -0,0 +1,124 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
seamless
title="移动应答器位置"
v-model="showMoveTransponder"
:width="300"
:height="345"
>
<q-card style="width: 300px">
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-input
dense
outlined
readonly
label="应答器"
v-model="props.code"
/>
<q-input
outlined
style="margin-top: 10px"
v-model="props.coordinateSystem"
readonly
label="坐标系"
></q-input>
<q-input
outlined
style="margin-top: 10px"
v-model.number="km"
type="number"
label="公里标(mm):"
/>
<q-select
outlined
v-model="props.direction"
:options="directionOptions"
readonly
:map-options="true"
:emit-value="true"
label="方向"
></q-select>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showMoveTransponder = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { ref, onMounted, onUnmounted } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { useLineStore } from 'src/stores/line-store';
import { updatePositionTransponder } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
const props = defineProps({
code: {
type: String,
required: true,
},
coordinateSystem: {
type: String,
required: true,
},
kilometer: {
type: Number,
default: 0,
},
direction: {
type: Number,
required: true,
},
id: {
type: Number,
required: true,
},
});
const km = ref(0);
onMounted(() => {
km.value = props.kilometer;
});
const showMoveTransponder = ref(true);
const directionOptions = [
{ label: '左行', value: 0 },
{ label: '右行', value: 1 },
];
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
updatePositionTransponder({
simulationId,
mapId,
baliseId: props.id,
km: {
coordinateSystem: props.coordinateSystem,
kilometer: km.value,
direction: props.direction,
},
}).catch((e) => errorNotify('移动应答器失败:' + e.title, e));
showMoveTransponder.value = false;
}
});
}
onUnmounted(() => {
useLineStore().deviceOpreratDialogInstance = null;
});
</script>
<style scoped></style>

View File

@ -0,0 +1,179 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
v-model="showSectionOperation"
seamless
title="屏蔽门设置参数"
:width="380"
:height="0"
>
<template v-slot:footer>
<q-card>
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-input
dense
outlined
readonly
label="名称"
v-model="props.code"
/>
<div
class="q-gutter-sm"
style="border: 1px solid #ccc; border-radius: 3px"
>
<div>屏蔽门强制</div>
<q-radio
v-for="option in screenDoorForceOption"
:key="option.value"
v-model="screenDoorForce"
:val="option.value"
:label="option.label"
/>
</div>
<div
class="q-gutter-sm"
style="border: 1px solid #ccc; border-radius: 3px"
>
<div>设置故障</div>
<q-radio
v-for="option in screenDoorFaultOption"
:key="option.value"
v-model="screenDoorFault"
:val="option.value"
:label="option.label"
/>
</div>
<div
class="q-gutter-sm"
style="border: 1px solid #ccc; border-radius: 3px"
>
<div>选择子门</div>
<template :key="item" v-for="item in asdOptions">
<q-checkbox
v-model="asdCodes"
:val="item"
:label="item < 10 ? '0' + item : item + ''"
/>
</template>
</div>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showTurnoutOperation = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { screenDoorOperate } from 'src/api/Simulation';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { request } from 'src/protos/request';
import { useLineStore } from 'src/stores/line-store';
import { errorNotify } from 'src/utils/CommonNotify';
import { onMounted, onUnmounted, ref } from 'vue';
const props = defineProps({
id: {
type: Number,
required: true,
},
code: {
type: String,
required: true,
},
sonDoorAmount: {
type: Number,
required: true,
},
asdCodesProp: {
type: Array<number>,
required: true,
},
screenDoorForceProp: {
type: Number,
required: true,
},
screenDoorFaultProp: {
type: Number,
required: true,
},
});
const lineStore = useLineStore();
const showSectionOperation = ref(true);
const screenDoorForce = ref<request.Psd.Force>(0);
const screenDoorForceOption = [
{
label: '无强制',
value: request.Psd.Force.F_NONE,
},
{
label: '强制开门',
value: request.Psd.Force.F_ASD_KM,
},
{
label: '强制关门',
value: request.Psd.Force.F_ASD_GM,
},
];
const screenDoorFault = ref<request.Psd.Fault>(0);
const screenDoorFaultOption = [
{
label: '无故障',
value: request.Psd.Fault.FA_NONE,
},
{
label: '设置故障物',
value: request.Psd.Fault.FA_Obstacle,
},
];
const asdCodes = ref<number[]>([]);
const asdOptions = ref<number[]>([]);
onMounted(() => {
for (let i = 1; i <= props.sonDoorAmount; i++) {
asdOptions.value.push(i);
}
asdCodes.value = props.asdCodesProp;
screenDoorForce.value = props.screenDoorForceProp;
screenDoorFault.value = props.screenDoorFaultProp;
});
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
const obj = {
simulationId: lineStore?.simulationId || '',
mapId: lineStore.mapId as number,
deviceId: props.id,
operation: request.Psd.Operation.SetParams,
param: {
asdCodes: asdCodes.value,
force: screenDoorForce.value,
fault: screenDoorFault.value,
},
};
screenDoorOperate(obj).catch((e) =>
errorNotify('屏蔽门操作失败:' + e.title, e)
);
showSectionOperation.value = false;
}
});
}
onUnmounted(() => {
lineStore.deviceOpreratDialogInstance = null;
});
</script>
<style scoped></style>

View File

@ -0,0 +1,108 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
v-model="showSectionOperation"
seamless
title="区段设置参数"
:width="380"
:height="0"
>
<template v-slot:footer>
<q-card>
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-input
dense
outlined
readonly
label="名称"
v-model="props.code"
/>
<div
class="q-gutter-sm"
style="border: 1px solid #ccc; border-radius: 3px"
>
<div>模拟CI复位/预复位</div>
<q-toggle v-model="mockDrst" label="是否复位" />
<q-toggle v-model="mockPdrst" label="是否预复位" />
</div>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showTurnoutOperation = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { setAxleSectionState } from 'src/api/Simulation';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { request } from 'src/protos/request';
import { useLineStore } from 'src/stores/line-store';
import { errorNotify } from 'src/utils/CommonNotify';
import { onMounted, onUnmounted, ref } from 'vue';
const props = defineProps({
id: {
type: Number,
required: true,
},
code: {
type: String,
required: true,
},
axleDrst: {
type: Boolean,
required: true,
},
axlePdrst: {
type: Boolean,
required: true,
},
});
const lineStore = useLineStore();
const mockDrst = ref(false);
const mockPdrst = ref(false);
const showSectionOperation = ref(true);
onMounted(() => {
mockDrst.value = props.axleDrst;
mockPdrst.value = props.axlePdrst;
});
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
const obj = {
simulationId: lineStore?.simulationId || '',
mapId: lineStore.mapId as number,
deviceId: props.id,
operation: request.Section.Operation.SetParams,
param: {
mockDrst: mockDrst.value,
mockPdrst: mockPdrst.value,
},
};
setAxleSectionState(obj).catch((e) =>
errorNotify('区段操作失败:' + e.title, e)
);
showSectionOperation.value = false;
}
});
}
onUnmounted(() => {
lineStore.deviceOpreratDialogInstance = null;
});
</script>

View File

@ -0,0 +1,97 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
seamless
title="列车连接"
v-model="showLoadTransData"
:width="300"
:height="175"
>
<q-card style="width: 300px">
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-select
v-model="connType"
label="连接平台"
outlined
:options="connectOptions"
emitValue
:rules="[(val) => !!val || '连接平台不能为空!']"
mapOptions
hint=""
>
</q-select>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showLoadTransData = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { onMounted, ref } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { getCanLinkPlatForm, updateTrainConn } from 'src/api/Simulation';
import { successNotify, errorNotify } from 'src/utils/CommonNotify';
const props = defineProps({
simulationId: {
type: String,
required: true,
},
trainId: {
type: String,
required: true,
},
});
const connType = ref<number>(0);
const connectOptions = ref<{ label: string; value: number }[]>([]);
const showLoadTransData = ref(true);
onMounted(() => {
connectOptions.value = [];
getCanLinkPlatForm(props.simulationId)
.then((resp) => {
const list: { label: string; value: number }[] = [];
resp.data.forEach((element: { connType: number }) => {
if (element.connType === 1) {
list.push({ label: '半实物', value: 1 });
} else if (element.connType === 2) {
list.push({ label: 'PC仿真', value: 2 });
}
});
connectOptions.value = list;
})
.catch((e) => {
errorNotify('获取列车可连接第三方平台失败!', e);
});
});
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
updateTrainConn({
id: props.trainId + '',
simulationId: props.simulationId,
connType: connType.value,
})
.then(() => {
successNotify('列车连接成功!');
showLoadTransData.value = false;
})
.catch((e) => {
errorNotify('列车连接失败', e);
});
});
}
</script>
<style scoped></style>

View File

@ -0,0 +1,598 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
seamless
title="列车设置"
v-model="showTrainParamOperation"
:width="1000"
:height="722"
>
<q-card style="width: 1000px; height: auto">
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<div class="row">
<div class="col-6">
<div class="float-text">1</div>
<div class="stroke-box">
<div class="float-text">雷达</div>
<div class="stroke-box">
<div class="row">
<div class="col-6 q-px-sm">
<q-input
class="q-input-xm"
outlined
v-model.number="model.trainEndsA.radarCheckSpeedDiff"
clearable
@clear="() => (model.trainEndsA.radarCheckSpeedDiff = 0)"
label="雷达测速差值(m/s)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-sm"
outlined
v-model.number="model.trainEndsA.radarCheckTime"
clearable
@clear="() => (model.trainEndsA.radarCheckTime = 0)"
label="雷达检测时间(秒)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-xm"
outlined
v-model.number="model.trainEndsA.radarOutSpeed"
clearable
@clear="() => (model.trainEndsA.radarOutSpeed = 0)"
label="雷达速度输出(m/s)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsA.radarEnable"
label="雷达是否有效"
/>
</div>
</div>
</div>
<div class="float-text">速传</div>
<div class="stroke-box">
<div class="row">
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsA.speedSensorEnableA"
label="速传1是否有效"
/>
</div>
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsA.speedSensorEnableB"
label="速传2是否有效"
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-xm"
outlined
v-model.number="model.trainEndsA.accOutSpeed"
clearable
@clear="() => (model.trainEndsA.accOutSpeed = 0)"
label="速传速度输出(m/s)"
hint=""
/>
</div>
</div>
</div>
<div class="float-text">加速度计</div>
<div class="stroke-box" style="margin-bottom: 10px">
<div class="row">
<div class="col-6 q-px-sm">
<q-input
class="q-input-sm"
outlined
v-model.number="model.trainEndsA.accCheckSpeedDiff"
clearable
@clear="() => (model.trainEndsA.accCheckSpeedDiff = 0)"
label="加速度测速差值(米/秒)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-sm"
outlined
v-model.number="model.trainEndsA.accCheckTime"
clearable
@clear="() => (model.trainEndsA.accCheckTime = 0)"
label="加速度持续时间(秒)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsA.accEnable"
label="加速度计是否有效"
/>
</div>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="float-text">2</div>
<div class="stroke-box">
<div class="float-text">雷达</div>
<div class="stroke-box">
<div class="row">
<div class="col-6 q-px-sm">
<q-input
class="q-input-xm"
outlined
v-model.number="model.trainEndsB.radarCheckSpeedDiff"
clearable
@clear="() => (model.trainEndsB.radarCheckSpeedDiff = 0)"
label="雷达测速差值(m/s)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-sm"
outlined
v-model.number="model.trainEndsB.radarCheckTime"
clearable
@clear="() => (model.trainEndsB.radarCheckTime = 0)"
label="雷达检测时间(秒)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-xm"
outlined
v-model.number="model.trainEndsB.radarOutSpeed"
clearable
@clear="() => (model.trainEndsB.radarOutSpeed = 0)"
label="雷达速度输出(m/s)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsB.radarEnable"
label="雷达是否有效"
/>
</div>
</div>
</div>
<div class="float-text">速传</div>
<div class="stroke-box">
<div class="row">
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsB.speedSensorEnableA"
label="速传1是否有效"
/>
</div>
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsB.speedSensorEnableB"
label="速传2是否有效"
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-xm"
outlined
v-model.number="model.trainEndsB.accOutSpeed"
clearable
@clear="() => (model.trainEndsB.accOutSpeed = 0)"
label="速传速度输出(m/s)"
hint=""
/>
</div>
</div>
</div>
<div class="float-text">加速度计</div>
<div class="stroke-box" style="margin-bottom: 10px">
<div class="row">
<div class="col-6 q-px-sm">
<q-input
class="q-input-sm"
outlined
v-model.number="model.trainEndsB.accCheckSpeedDiff"
clearable
@clear="() => (model.trainEndsB.accCheckSpeedDiff = 0)"
label="加速度测速差值(米/秒)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-input
class="q-input-sm"
outlined
v-model.number="model.trainEndsB.accCheckTime"
clearable
@clear="() => (model.trainEndsB.accCheckTime = 0)"
label="加速度持续时间(秒)"
hint=""
/>
</div>
<div class="col-6 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.trainEndsB.accEnable"
label="加速度计是否有效"
/>
</div>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="float-text">基本参数</div>
<div class="stroke-box">
<div class="row">
<div class="col-3 q-px-sm">
<q-input
outlined
class="q-input--sm"
v-model.number="model.length"
label="列车长度(mm)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
class="q-input--sm"
v-model.number="model.wheelDiameter"
:label="`列车轮径(mm)【750-840mm】`"
:max="840"
:min="750"
:rules="wheelDiameterRules"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
class="q-input--sm"
v-model.number="model.configData.davisParamA"
label="基本阻力参数A"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.davisParamB"
label="基本阻力参数B"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.davisParamC"
label="基本阻力参数C"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.curveResistanceParamR1"
label="曲线阻力参数R1"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.curveResistanceParamR2"
label="曲线阻力参数R2"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.curveResistanceParamR3"
label="曲线阻力参数R3"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.curveResistanceParamR4"
label="曲线阻力参数R4"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.revolvingMassParam"
label="旋转质量参数"
hint=""
/>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="float-text">故障</div>
<div class="stroke-box">
<div class="row">
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.slide"
clearable
@clear="() => (model.configData.slide = 0)"
label="前溜/后溜(m/s)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.slipA"
clearable
@clear="() => (model.configData.slipA = 0)"
label="打滑加速度(m/s²)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.slipR"
clearable
@clear="() => (model.configData.slipR = 0)"
label="打滑冲击率(m/s³)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.slipD"
clearable
@clear="() => (model.configData.slipD = 0)"
label="打滑持续时间(ms)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.stopSign"
:default-value="0"
clearable
@clear="() => (model.configData.stopSign = 0)"
label="过标/欠标(mm)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.idlingA"
clearable
@clear="() => (model.configData.idlingA = 0)"
label="空转加速度(m/s²)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.idlingR"
clearable
@clear="() => (model.configData.idlingR = 0)"
label="空转冲击率(m/s³)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-input
outlined
v-model.number="model.configData.idlingD"
clearable
@clear="() => (model.configData.idlingD = 0)"
label="空转持续时间(ms)"
hint=""
/>
</div>
<div class="col-3 q-px-sm">
<q-checkbox
style="font-size: 12px"
v-model="model.configData.jump"
label="是否跳跃"
/>
</div>
</div>
</div>
</div>
</div>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showTrainParamOperation = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { Train } from 'src/graphics/train/Train';
import { ref, onMounted, reactive, onUnmounted } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { updateTrainConfig } from 'src/api/Simulation';
import { useLineStore } from 'src/stores/line-store';
import { errorNotify } from 'src/utils/CommonNotify';
const props = defineProps({
train: {
type: Train,
required: true,
},
});
const model = reactive({
trainId: 0,
simulationId: '',
trainEndsA: {
radarCheckSpeedDiff: 0,
radarCheckTime: 0,
radarEnable: true,
speedSensorEnableA: true,
speedSensorEnableB: true,
accEnable: true,
accCheckSpeedDiff: 0,
accCheckTime: 0,
accOutSpeed: 0,
radarOutSpeed: 0,
},
trainEndsB: {
radarCheckSpeedDiff: 0,
radarCheckTime: 0,
radarEnable: true,
speedSensorEnableA: true,
speedSensorEnableB: true,
accEnable: true,
accCheckSpeedDiff: 0,
accCheckTime: 0,
accOutSpeed: 0,
radarOutSpeed: 0,
},
configData: {
davisParamA: 0,
davisParamB: 0,
davisParamC: 0,
curveResistanceParamR1: 0,
curveResistanceParamR2: 0,
curveResistanceParamR3: 0,
curveResistanceParamR4: 0,
jump: false,
revolvingMassParam: 0,
slide: 0,
slipA: 0,
slipR: 0,
slipD: 0,
stopSign: 0,
idlingA: 0,
idlingR: 0,
idlingD: 0,
},
length: 0,
wheelDiameter: 0,
});
onMounted(() => {
initModel();
});
const wheelDiameterRules = [
(val: string) => (val !== null && val !== '') || '列车轮径不能为空!',
(val: number) => (val >= 750 && val <= 840) || '列车轮径在750到840mm之间',
];
const showTrainParamOperation = ref(true);
const myForm = ref<QForm | null>(null);
function initModel() {
const trainState = props.train.states;
model.trainEndsA = {
radarCheckSpeedDiff: trainState.aRadarCheckSpeedDiff,
radarCheckTime: trainState.aRadarCheckTime,
radarEnable: trainState.aRadarEnable,
speedSensorEnableA: trainState.aSpeedSensorEnableA,
speedSensorEnableB: trainState.aSpeedSensorEnableB,
accEnable: trainState.aAccEnable,
accCheckSpeedDiff: trainState.aAccCheckSpeedDiff,
accCheckTime: trainState.aAccCheckTime,
accOutSpeed: trainState.aAccOutSpeed,
radarOutSpeed: trainState.aRadarOutSpeed,
};
model.trainEndsB = {
radarCheckSpeedDiff: trainState.bRadarCheckSpeedDiff,
radarCheckTime: trainState.bRadarCheckTime,
radarEnable: trainState.bRadarEnable,
speedSensorEnableA: trainState.bSpeedSensorEnableA,
speedSensorEnableB: trainState.bSpeedSensorEnableB,
accEnable: trainState.bAccEnable,
accCheckSpeedDiff: trainState.bAccCheckSpeedDiff,
accCheckTime: trainState.bAccCheckTime,
accOutSpeed: trainState.bAccOutSpeed,
radarOutSpeed: trainState.bRadarOutSpeed,
};
model.configData = {
davisParamA: trainState.davisParamA,
davisParamB: trainState.davisParamB,
davisParamC: trainState.davisParamC,
curveResistanceParamR1: trainState.curveResistanceParamR1,
curveResistanceParamR2: trainState.curveResistanceParamR2,
curveResistanceParamR3: trainState.curveResistanceParamR3,
curveResistanceParamR4: trainState.curveResistanceParamR4,
jump: trainState.jump,
revolvingMassParam: trainState.revolvingMassParam,
slide: trainState.slide,
slipA: trainState.slipA,
slipR: trainState.slipR,
slipD: trainState.slipD,
stopSign: trainState.stopSign,
idlingA: trainState.idlingA,
idlingR: trainState.idlingR,
idlingD: trainState.idlingD,
};
model.length = trainState.trainLength;
model.wheelDiameter = trainState.wheelDiameter;
}
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
model.simulationId = useLineStore().simulationId || '';
model.trainId = +props.train.states.id;
updateTrainConfig(model).catch((err) => {
errorNotify('列车参数失败!', err);
});
showTrainParamOperation.value = false;
useLineStore().deviceOpreratDialogInstance = null;
}
});
}
onUnmounted(() => {
useLineStore().deviceOpreratDialogInstance = null;
});
</script>
<style scoped>
.stroke-box {
margin: 10px 10px 0;
border: 1px solid #ccc;
padding: 15px 5px 0;
border-radius: 1px;
}
.float-text {
background: #fff;
position: relative;
float: left;
left: 20px;
}
</style>

View File

@ -0,0 +1,262 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
seamless
title="信号机设置参数"
v-model="showSignalOperation"
:width="width"
:height="330"
>
<q-card class="q-m-a-sm">
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-input
dense
outlined
readonly
label="信号机名称"
v-model="props.code"
/>
<div
class="q-gutter-sm"
style="border: 1px solid #ccc; border-radius: 3px"
>
<div>信号机强制</div>
<q-radio
v-for="option in signalForceOptions"
:key="option.value"
v-model="signalForce"
:val="option.value"
:label="option.label"
/>
</div>
<div
class="q-gutter-sm"
style="border: 1px solid #ccc; border-radius: 3px"
>
<div>信号机断丝</div>
<q-checkbox
v-for="option in signalDsOptions"
:key="option.value"
v-model="signalDs"
:val="option.value"
:label="option.label"
/>
</div>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showSignalOperation = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { request } from 'src/protos/request';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { onMounted, ref, computed, onUnmounted } from 'vue';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useLineStore } from 'src/stores/line-store';
import { setSignalState } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
const props = defineProps({
id: {
type: Number,
required: true,
},
code: {
type: String,
required: true,
},
mt: {
type: Number,
required: true,
},
param: {
type: request.SignalParam,
required: true,
},
});
const width = computed(() => {
if (signalForceOptions.value.length === 6) {
return 530;
} else if (signalForceOptions.value.length === 5) {
return 450;
} else {
return 400;
}
});
const signalForce = ref<request.Signal.Force>(0);
const signalDs = ref<request.Signal.DS[]>([]);
interface SignalDsItem {
label: string;
value: request.Signal.DS;
}
const signalDsOptions = ref<SignalDsItem[]>([]);
const hDs = {
label: '红灯断丝',
value: request.Signal.DS.DS_H,
};
const uDs = {
label: '黄灯断丝',
value: request.Signal.DS.DS_U,
};
const lDs = {
label: '绿灯断丝',
value: request.Signal.DS.DS_L,
};
const aDs = {
label: '蓝灯断丝',
value: request.Signal.DS.DS_A,
};
const bDs = {
label: '白灯断丝',
value: request.Signal.DS.DS_B,
};
interface SignalForceItem {
label: string;
value: request.Signal.Force;
}
const signalForceOptions = ref<SignalForceItem[]>([]);
const noForce = {
label: '无强制',
value: request.Signal.Force.SF_NONE,
};
const mieDeng = {
label: '灭灯',
value: request.Signal.Force.SF_M,
};
const hongDeng = {
label: '红灯',
value: request.Signal.Force.SF_H,
};
const huangDeng = {
label: '黄灯',
value: request.Signal.Force.SF_U,
};
const lvDeng = {
label: '绿灯',
value: request.Signal.Force.SF_L,
};
const huanghongDeng = {
label: '黄红灯',
value: request.Signal.Force.SF_HU,
};
const lanDeng = {
label: '蓝灯',
value: request.Signal.Force.SF_A,
};
const baiDeng = {
label: '白灯',
value: request.Signal.Force.SF_B,
};
onMounted(() => {
signalDs.value = props.param.dsList;
signalForce.value = props.param.force;
switch (props.mt) {
case graphicData.Signal.Model.HL:
signalDsOptions.value = [hDs, lDs];
signalForceOptions.value = [noForce, mieDeng, hongDeng, lvDeng];
break;
case graphicData.Signal.Model.AB:
signalDsOptions.value = [aDs, bDs];
signalForceOptions.value = [noForce, mieDeng, lanDeng, baiDeng];
break;
case graphicData.Signal.Model.HBU_DU:
signalDsOptions.value = [hDs, bDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
baiDeng,
huangDeng,
];
break;
case graphicData.Signal.Model.HLU_FU:
signalDsOptions.value = [hDs, lDs];
signalForceOptions.value = [noForce, mieDeng, hongDeng, lvDeng];
break;
case graphicData.Signal.Model.HLU_DU_YY:
signalDsOptions.value = [hDs, lDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
lvDeng,
huangDeng,
huanghongDeng,
];
break;
case graphicData.Signal.Model.HLU_YY:
signalDsOptions.value = [hDs, lDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
lvDeng,
huanghongDeng,
];
break;
case graphicData.Signal.Model.HLU_FL_DU_YY:
signalDsOptions.value = [hDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
huangDeng,
huanghongDeng,
];
break;
case graphicData.Signal.Model.HLU_DU:
signalDsOptions.value = [hDs, lDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
lvDeng,
huangDeng,
];
break;
}
});
const showSignalOperation = ref(true);
const lineStore = useLineStore();
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
const obj = {
simulationId: lineStore.simulationId || '',
mapId: lineStore.mapId as number,
deviceId: props.id,
operation: request.Points.Operation.SetParams,
param: { force: signalForce.value, dsList: signalDs.value },
};
setSignalState(obj).catch((e) =>
errorNotify('信号机操作失败:' + e.title, e)
);
showSignalOperation.value = false;
}
});
}
onUnmounted(() => {
lineStore.deviceOpreratDialogInstance = null;
});
</script>
<style scoped></style>

View File

@ -0,0 +1,89 @@
<template>
<DraggableDialog seamless :height="73" title="列车检索">
<q-card class="q-pa-sm">
<q-select
filled
v-model="deviceId"
label="列车检索"
use-input
hide-selected
fill-input
input-debounce="0"
:options="serachTrainList"
:map-options="true"
:emit-value="true"
@filter="filterFn"
@update:model-value="onJump"
style="width: 450px"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey"> 无匹配数据 </q-item-section>
</q-item>
</template>
</q-select>
</q-card>
</DraggableDialog>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { IDrawApp, IGraphicApp } from 'jl-graphic';
import { Train } from 'src/graphics/train/Train';
interface ItemData {
label: string;
value: number;
}
const props = defineProps<{
showDialog: boolean;
app: IDrawApp | IGraphicApp;
}>();
const deviceList = ref<ItemData[]>([]);
const deviceId = ref(0);
const serachTrainList = ref<ItemData[]>([]);
onMounted(() => {
if (props.showDialog) {
const list: ItemData[] = [];
const qs = props.app.queryStore;
const trains = qs.queryByType<Train>(Train.Type);
trains.forEach((item) => {
list.push({
label: '列车' + item.states.id,
value: item.id,
});
});
deviceList.value = list;
serachTrainList.value = list;
}
});
function filterFn(val: string, update: any) {
update(() => {
serachTrainList.value = deviceList.value.filter((v) =>
v.label.includes(val)
);
});
}
function onJump(id: number) {
const device = props.app.queryStore.queryById(id);
props.app.makeGraphicCenterShow(device);
props.app.updateSelected(device);
}
</script>
<style scoped>
.text {
cursor: pointer;
color: #000;
padding: 5px;
}
.text:hover {
color: #09f;
}
</style>

View File

@ -0,0 +1,123 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
v-model="showTurnoutOperation"
seamless
title="道岔设置参数"
:width="380"
:height="0"
>
<template v-slot:footer>
<q-card>
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-input
dense
outlined
readonly
label="名称"
v-model="props.code"
/>
<div
class="q-gutter-sm"
style="border: 1px solid #ccc; border-radius: 3px"
>
<div>道岔强制</div>
<q-radio
v-for="option in turnoutForceOption"
:key="option.value"
v-model="turnoutForce"
:val="option.value"
:label="option.label"
/>
</div>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showTurnoutOperation = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { SetSwitchParams, setSwitchPosition } from 'src/api/Simulation';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { request } from 'src/protos/request';
import { useLineStore } from 'src/stores/line-store';
import { errorNotify } from 'src/utils/CommonNotify';
import { onMounted, onUnmounted, ref } from 'vue';
const props = defineProps({
id: {
type: Number,
required: true,
},
code: {
type: String,
required: true,
},
force: {
type: Number,
required: true,
},
});
const lineStore = useLineStore();
const showTurnoutOperation = ref(true);
const turnoutForce = ref<request.Points.Force>(0);
const turnoutForceOption = [
{
label: '无强制',
value: request.Points.Force.FP_NONE,
},
{
label: '定位',
value: request.Points.Force.FP_DW,
},
{
label: '反位',
value: request.Points.Force.FP_FW,
},
{
label: '失表',
value: request.Points.Force.FP_SB,
},
];
onMounted(() => {
turnoutForce.value = props.force;
});
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
const obj: SetSwitchParams = {
simulationId: lineStore?.simulationId || '',
mapId: lineStore.mapId as number,
deviceId: props.id,
operation: request.Points.Operation.SetParams,
param: { forcePosition: turnoutForce.value },
};
setSwitchPosition(obj).catch((e) =>
errorNotify('道岔操作失败:' + e.title, e)
);
showTurnoutOperation.value = false;
}
});
}
onUnmounted(() => {
lineStore.deviceOpreratDialogInstance = null;
});
</script>
<style scoped></style>

View File

@ -0,0 +1,220 @@
<!-- eslint-disable vue/no-mutating-props -->
<template>
<draggable-dialog
seamless
title="修改应答器报文"
v-model="showUpdateMessage"
:width="400"
:height="0"
>
<template v-slot:footer>
<q-card style="width: 400px">
<q-card-section>
<q-form ref="myForm" @submit="onCreate" class="q-gutter-md">
<q-input
dense
outlined
readonly
label="应答器"
v-model="props.code"
/>
<q-input
dense
outlined
label="固定用户报文"
autogrow
counter
:rules="[
(val) => {
return validateUserMessage(val);
},
]"
v-model="fixedUserTelegramData"
/>
<q-input
dense
outlined
label="固定报文"
autogrow
counter
:rules="[
(val) => {
return validateMessage(val);
},
]"
v-model="fixedTelegramData"
/>
<q-input
v-if="
props.type === TransponderTypeEnum.VB ||
props.type === TransponderTypeEnum.IB
"
dense
outlined
label="可变用户报文"
autogrow
counter
:rules="[
(val) => {
return validateVMessage(val);
},
]"
v-model="variableUserTelegramData"
/>
<q-input
v-if="
props.type === TransponderTypeEnum.VB ||
props.type === TransponderTypeEnum.IB
"
dense
outlined
label="可变报文"
autogrow
counter
:rules="[
(val) => {
return validateVMessage(val);
},
]"
v-model="variableTelegramData"
/>
<q-card-actions align="right" class="text-primary">
<q-btn
flat
label="取消"
@click="showUpdateMessage = false"
v-close-popup
/>
<q-btn flat label="确认" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { QForm } from 'quasar';
import { ref, onMounted, onUnmounted } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { useLineStore } from 'src/stores/line-store';
import { updateMessageTransponder } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
import { TransponderTypeEnum } from 'src/graphics/transponder/Transponder';
const props = defineProps({
id: {
type: Number,
required: true,
},
type: {
type: Number,
required: true,
},
code: {
type: String,
required: true,
},
fixedTelegram: {
type: String,
required: true,
},
fixedUserTelegram: {
type: String,
required: true,
},
variableTelegram: {
type: String,
default: '',
},
variableUserTelegram: {
type: String,
default: '',
},
});
const showUpdateMessage = ref(true);
const fixedTelegramData = ref('');
const fixedUserTelegramData = ref('');
const variableTelegramData = ref('');
const variableUserTelegramData = ref('');
onMounted(() => {
fixedTelegramData.value = props.fixedTelegram;
fixedUserTelegramData.value = props.fixedUserTelegram;
variableTelegramData.value = props.variableTelegram;
variableUserTelegramData.value = props.variableUserTelegram;
});
const myForm = ref<QForm | null>(null);
function onCreate() {
myForm.value?.validate().then(async (res) => {
if (res) {
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
updateMessageTransponder({
simulationId,
mapId,
baliseId: props.id,
fixedTelegram: fixedTelegramData.value,
fixedUserTelegram: fixedUserTelegramData.value,
variableTelegram: variableTelegramData.value,
variableUserTelegram: variableUserTelegramData.value,
}).catch((e) => errorNotify('修改应答器报文失败:' + e.title, e));
showUpdateMessage.value = false;
}
});
}
onUnmounted(() => {
useLineStore().deviceOpreratDialogInstance = null;
});
function validateUserMessage(val: string) {
if (val.length !== 208) {
return '报文长度应为208个字符';
}
return validateBMessage(val);
}
function validateMessage(val: string) {
if (val.length !== 256) {
return '报文长度应为256个字符';
}
return validateBMessage(val);
}
function validateVMessage(val: string) {
if (!val) {
return '请填写报文内容!';
}
if (val.length % 2 === 1) {
return '请填写报文内容数据长度应为偶数!';
}
return validateBMessage(val);
}
function validateBMessage(val: string) {
const list = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F',
];
const falg = val.split('').some((elem) => !list.includes(elem));
if (falg) {
return '报文格式错误字符应为【0-F】的十六进制数';
} else {
return true;
}
}
</script>
<style scoped></style>

View File

@ -43,30 +43,77 @@
</q-icon>
</template>
</q-input>
<q-toggle
v-model="canvas.gridBackground.hasGrid"
label="是否有网格背景"
emit-value
@update:model-value="onUpdate"
/>
<q-input
outlined
type="number"
v-if="canvas.gridBackground.hasGrid"
v-model.number="canvas.gridBackground.space"
@blur="onUpdate"
label="网格间距"
lazy-rules
:rules="[(val) => val >= 0 || '画布高必须大于0']"
/>
<q-input
outlined
v-if="canvas.gridBackground.hasGrid"
v-model="canvas.gridBackground.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
:model-value="canvas.gridBackground.lineColor"
@change="
(val) => {
canvas.gridBackground.lineColor = val;
onUpdate();
}
"
/>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</q-form>
</template>
<script setup lang="ts">
import { useIBPDrawStore } from 'src/stores/ibp-draw-store';
import { onMounted, onUnmounted, reactive } from 'vue';
import { onMounted, reactive } from 'vue';
const ibpDrawStore = useIBPDrawStore();
const canvas = reactive({
width: 1920,
height: 1080,
backgroundColor: '#ffffff',
backgroundColor: '#706e6e',
gridBackground: {
hasGrid: false,
lineColor: '#c2aeae',
space: 50,
},
});
onMounted(() => {
// console.log('mounted');
const jc = ibpDrawStore.getJlCanvas();
canvas.width = jc.properties.width;
canvas.height = jc.properties.height;
canvas.backgroundColor = jc.properties.backgroundColor;
});
onUnmounted(() => {
// console.log('unmounted');
setTimeout(() => {
const jc = ibpDrawStore.getJlCanvas();
canvas.width = jc.properties.width;
canvas.height = jc.properties.height;
canvas.backgroundColor = jc.properties.backgroundColor;
if (jc.properties.gridBackground) {
canvas.gridBackground = jc.properties.gridBackground;
}
onUpdate();
}, 100);
});
function onUpdate() {

View File

@ -0,0 +1,80 @@
<template>
<q-form>
<q-input
outlined
v-model.number="canvas.width"
@blur="onUpdate"
label="画布宽 *"
lazy-rules
:rules="[(val) => (val && val > 0) || '画布宽必须大于0']"
/>
<q-input
outlined
type="number"
v-model.number="canvas.height"
@blur="onUpdate"
label="画布高 *"
lazy-rules
:rules="[(val) => val > 0 || '画布高必须大于0']"
/>
<q-input
outlined
v-model="canvas.backgroundColor"
@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
:model-value="canvas.backgroundColor"
@change="
(val) => {
canvas.backgroundColor = val;
onUpdate();
}
"
/>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</q-form>
</template>
<script setup lang="ts">
import { useTccDrawStore } from 'src/stores/tcc-draw-store';
import { onMounted, onUnmounted, reactive } from 'vue';
const tccDrawStore = useTccDrawStore();
const canvas = reactive({
width: 1920,
height: 1080,
backgroundColor: '#ffffff',
});
onMounted(() => {
// console.log('mounted');
const jc = tccDrawStore.getJlCanvas();
canvas.width = jc.properties.width;
canvas.height = jc.properties.height;
canvas.backgroundColor = jc.properties.backgroundColor;
});
onUnmounted(() => {
// console.log('unmounted');
});
function onUpdate() {
// console.log('');
const app = tccDrawStore.getDrawApp();
app.updateCanvasAndRecord({
...canvas,
viewportTransform: app.canvas.properties.viewportTransform,
});
}
</script>

View File

@ -0,0 +1,100 @@
<template>
<q-form>
<q-input
outlined
readonly
v-model="carWashingModel.id"
label="id"
hint=""
/>
<q-input
outlined
class="q-mt-sm"
v-model="carWashingModel.code"
@blur="onUpdate"
label="名称"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="carWashingModel.linkSection"
:options="sectionList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联区段"
></q-select>
<q-field class="q-mt-lg" outlined label="所属集中站" stack-label>
<template #control>
<q-chip
color="primary"
text-color="white"
v-for="(id, index) in carWashingModel.centralizedStations"
:key="index"
removable
@remove="removeStation(index)"
square
>{{ getName(id) }}</q-chip
>
<q-btn round color="primary" size="xs" icon="add" @click="addStation" />
</template>
</q-field>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive } from 'vue';
import { Section } from 'src/graphics/section/Section';
import { CarWashingData } from 'src/drawApp/graphics/CarWashingInteraction';
import { Station } from 'src/graphics/station/Station';
import AddCentralizedStationDialog from '../dialogs/AddCentralizedStationDialog.vue';
import { useQuasar } from 'quasar';
const drawStore = useDrawStore();
const sectionList: { label: string; value: number }[] = reactive([]);
const { data: carWashingModel, onUpdate } = useFormData(
new CarWashingData(),
drawStore.getDrawApp()
);
onMounted(() => {
const sections = drawStore
.getDrawApp()
.queryStore.queryByType<Section>(Section.Type);
sections.forEach((p) => {
sectionList.push({
value: p.id,
label: `${p.datas.code}`,
});
});
});
function removeStation(index: number) {
carWashingModel.centralizedStations.splice(index, 1);
onUpdate();
}
const $q = useQuasar();
function addStation() {
$q.dialog({
title: '',
message: '',
component: AddCentralizedStationDialog,
cancel: true,
persistent: true,
}).onOk((data: number) => {
carWashingModel.centralizedStations.push(data);
onUpdate();
});
}
function getName(id: number) {
try {
const station = drawStore.getDrawApp().queryStore.queryById<Station>(id);
return station.datas.code;
} catch (error) {
return id;
}
}
</script>

View File

@ -0,0 +1,95 @@
<template>
<q-form>
<q-input outlined readonly v-model="floodGateModel.id" label="id" hint="" />
<q-input
outlined
class="q-mt-sm"
v-model="floodGateModel.code"
@blur="onUpdate"
label="名称"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="floodGateModel.linkSection"
:options="sectionList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联区段"
></q-select>
<q-field class="q-mt-lg" outlined label="所属集中站" stack-label>
<template #control>
<q-chip
color="primary"
text-color="white"
v-for="(id, index) in floodGateModel.centralizedStations"
:key="index"
removable
@remove="removeStation(index)"
square
>{{ getName(id) }}</q-chip
>
<q-btn round color="primary" size="xs" icon="add" @click="addStation" />
</template>
</q-field>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive } from 'vue';
import { Section } from 'src/graphics/section/Section';
import { FloodGateData } from 'src/drawApp/graphics/FloodGateInteraction';
import AddCentralizedStationDialog from '../dialogs/AddCentralizedStationDialog.vue';
import { useQuasar } from 'quasar';
import { Station } from 'src/graphics/station/Station';
const drawStore = useDrawStore();
const sectionList: { label: string; value: number }[] = reactive([]);
const { data: floodGateModel, onUpdate } = useFormData(
new FloodGateData(),
drawStore.getDrawApp()
);
onMounted(() => {
const sections = drawStore
.getDrawApp()
.queryStore.queryByType<Section>(Section.Type);
sections.forEach((p) => {
sectionList.push({
value: p.id,
label: `${p.datas.code}`,
});
});
});
function removeStation(index: number) {
floodGateModel.centralizedStations.splice(index, 1);
onUpdate();
}
const $q = useQuasar();
function addStation() {
$q.dialog({
title: '',
message: '',
component: AddCentralizedStationDialog,
cancel: true,
persistent: true,
}).onOk((data: number) => {
floodGateModel.centralizedStations.push(data);
onUpdate();
});
}
function getName(id: number) {
try {
const station = drawStore.getDrawApp().queryStore.queryById<Station>(id);
return station.datas.code;
} catch (error) {
return id;
}
}
</script>

View File

@ -0,0 +1,78 @@
<template>
<q-form>
<q-input
outlined
readonly
v-model="garageDoorBoxModel.id"
label="id"
hint=""
/>
<q-input
outlined
class="q-mt-sm"
v-model="garageDoorBoxModel.code"
@blur="onUpdate"
label="编号"
/>
<q-select
outlined
class="q-mt-sm"
style="margin-top: 10px"
v-model="garageDoorBoxModel.refGarageDoorId"
:options="garageDoorList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联屏蔽门"
></q-select>
<q-select
outlined
class="q-mt-sm"
@blur="onUpdate"
v-model="garageDoorBoxModel.refPslMapCode"
:options="pslNameList"
label="关联PSL地图"
/>
</q-form>
</template>
<script setup lang="ts">
import { GarageDoorBoxData } from 'src/drawApp/graphics/GarageDoorBoxInteraction';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref } from 'vue';
import { getPublishList } from 'src/api/PublishApi';
import { PictureType } from 'src/protos/picture';
import { GarageDoor } from 'src/graphics/garageDoor/GarageDoor';
const { data: garageDoorBoxModel, onUpdate } = useFormData(
new GarageDoorBoxData(),
useDrawStore().getDrawApp()
);
const garageDoorList: { label: string; value: number }[] = reactive([]);
const pslNameList = ref<string[]>([]);
onMounted(() => {
const list2: string[] = [];
getPublishList({
type: PictureType.Psl,
category: useDrawStore().categoryType,
}).then((pslMapList) => {
if (pslMapList && pslMapList.length) {
pslMapList.forEach((item) => {
list2.push(item.name);
});
}
pslNameList.value = list2;
});
const garageDoors = useDrawStore()
.getDrawApp()
.queryStore.queryByType<GarageDoor>(GarageDoor.Type);
garageDoors.forEach((p) => {
garageDoorList.push({
value: p.id,
label: `${p.datas.code}[${p.datas.id}]`,
});
});
});
</script>

View File

@ -0,0 +1,101 @@
<template>
<q-form>
<q-input
outlined
readonly
v-model="garageDoorModel.id"
label="id"
hint=""
/>
<q-input
outlined
class="q-mt-sm"
v-model="garageDoorModel.code"
@blur="onUpdate"
label="名称"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="garageDoorModel.linkSection"
:options="sectionList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联区段"
></q-select>
<q-field class="q-mt-lg" outlined label="所属集中站" stack-label>
<template #control>
<q-chip
color="primary"
text-color="white"
v-for="(id, index) in garageDoorModel.centralizedStations"
:key="index"
removable
@remove="removeStation(index)"
square
>{{ getName(id) }}</q-chip
>
<q-btn round color="primary" size="xs" icon="add" @click="addStation" />
</template>
</q-field>
</q-form>
</template>
<script setup lang="ts">
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive } from 'vue';
import { GarageDoorData } from 'src/drawApp/graphics/GarageDoorInteraction';
import { Section } from 'src/graphics/section/Section';
import AddCentralizedStationDialog from '../dialogs/AddCentralizedStationDialog.vue';
import { useQuasar } from 'quasar';
import { Station } from 'src/graphics/station/Station';
const drawStore = useDrawStore();
const sectionList: { label: string; value: number }[] = reactive([]);
const { data: garageDoorModel, onUpdate } = useFormData(
new GarageDoorData(),
drawStore.getDrawApp()
);
onMounted(() => {
const sections = drawStore
.getDrawApp()
.queryStore.queryByType<Section>(Section.Type);
sections.forEach((p) => {
sectionList.push({
value: p.id,
label: `${p.datas.code}`,
});
});
});
const $q = useQuasar();
function removeStation(index: number) {
garageDoorModel.centralizedStations.splice(index, 1);
onUpdate();
}
function addStation() {
$q.dialog({
title: '',
message: '',
component: AddCentralizedStationDialog,
cancel: true,
persistent: true,
}).onOk((data: number) => {
garageDoorModel.centralizedStations.push(data);
onUpdate();
});
}
function getName(id: number) {
try {
const station = drawStore.getDrawApp().queryStore.queryById<Station>(id);
return station.datas.code;
} catch (error) {
return id;
}
}
</script>

View File

@ -24,7 +24,7 @@
class="q-mt-sm"
@blur="onUpdate"
v-model="gatedBoxModel.refGatedBoxMapCode"
:options="props.pslNameList"
:options="pslNameList"
label="关联PSL地图"
/>
</q-form>
@ -34,24 +34,31 @@
import { GatedBoxData } from 'src/drawApp/graphics/GatedBoxInteraction';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, defineProps } from 'vue';
import { onMounted, reactive, ref } from 'vue';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import { getPublishList } from 'src/api/PublishApi';
import { PictureType } from 'src/protos/picture';
const { data: gatedBoxModel, onUpdate } = useFormData(
new GatedBoxData(),
useDrawStore().getDrawApp()
);
const props = defineProps({
pslNameList: {
type: Array,
required: true,
},
});
const screenDoorList: { label: string; value: number }[] = reactive([]);
const pslNameList = ref<string[]>([]);
onMounted(() => {
const list2: string[] = [];
getPublishList({
type: PictureType.Psl,
category: useDrawStore().categoryType,
}).then((pslMapList) => {
if (pslMapList && pslMapList.length) {
pslMapList.forEach((item) => {
list2.push(item.name);
});
}
pslNameList.value = list2;
});
const screenDoors = useDrawStore()
.getDrawApp()
.queryStore.queryByType<ScreenDoor>(ScreenDoor.Type);

View File

@ -0,0 +1,72 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="IbpBoxModel.id" label="id" />
<q-input
outlined
style="margin-top: 10px"
v-model="IbpBoxModel.code"
@blur="onUpdate"
label="编号"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="IbpBoxModel.refStationId"
:options="stationList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联车站"
/>
<q-select
outlined
class="q-mt-md"
@blur="onUpdate"
v-model="IbpBoxModel.refIbpMapCode"
:options="ibpNameList"
label="关联IBP地图"
/>
</q-form>
</template>
<script setup lang="ts">
import { getPublishList } from 'src/api/PublishApi';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { IbpBoxData } from 'src/drawApp/graphics/IbpBoxInteraction';
import { Station } from 'src/graphics/station/Station';
import { PictureType } from 'src/protos/picture';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref } from 'vue';
const drawStore = useDrawStore();
const { data: IbpBoxModel, onUpdate } = useFormData(
new IbpBoxData(),
drawStore.getDrawApp()
);
const stationList: { label: string; value: number }[] = reactive([]);
const ibpNameList = ref<string[]>([]);
onMounted(() => {
const list1: string[] = [];
getPublishList({
type: PictureType.IBP,
category: drawStore.categoryType,
}).then((ibpMapList) => {
if (ibpMapList && ibpMapList.length) {
ibpMapList.forEach((item) => {
list1.push(item.name);
});
ibpNameList.value = list1;
}
});
const stations = drawStore
.getDrawApp()
.queryStore.queryByType<Station>(Station.Type);
stations.forEach((p) => {
stationList.push({
value: p.id,
label: `${p.datas.code}`,
});
});
});
</script>

View File

@ -0,0 +1,72 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="IbpBoxModel.id" label="id" />
<q-input
outlined
style="margin-top: 10px"
v-model="IbpBoxModel.code"
@blur="onUpdate"
label="编号"
/>
<q-select
outlined
style="margin-top: 10px"
v-model="IbpBoxModel.refPlatformId"
:options="stationList"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="关联站台"
/>
<q-select
outlined
class="q-mt-md"
@blur="onUpdate"
v-model="IbpBoxModel.refPslMapCode"
:options="pslNameList"
label="关联PSL地图"
/>
</q-form>
</template>
<script setup lang="ts">
import { getPublishList } from 'src/api/PublishApi';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { PslBoxData } from 'src/drawApp/graphics/PslBoxInteraction';
import { Platform } from 'src/graphics/platform/Platform';
import { PictureType } from 'src/protos/picture';
import { useDrawStore } from 'src/stores/draw-store';
import { onMounted, reactive, ref } from 'vue';
const drawStore = useDrawStore();
const { data: IbpBoxModel, onUpdate } = useFormData(
new PslBoxData(),
drawStore.getDrawApp()
);
const stationList: { label: string; value: number }[] = reactive([]);
const pslNameList = ref<string[]>([]);
onMounted(() => {
const list2: string[] = [];
getPublishList({
type: PictureType.Psl,
category: useDrawStore().categoryType,
}).then((pslMapList) => {
if (pslMapList && pslMapList.length) {
pslMapList.forEach((item) => {
list2.push(item.name);
});
}
pslNameList.value = list2;
});
const platforms = drawStore
.getDrawApp()
.queryStore.queryByType<Platform>(Platform.Type);
platforms.forEach((p) => {
stationList.push({
value: p.id,
label: `${p.datas.code}`,
});
});
});
</script>

View File

@ -86,6 +86,8 @@ const optionsType = [
},
{ label: '断路器', value: graphicData.RelatedRef.DeviceType.Breakers },
{ label: '电源屏', value: graphicData.RelatedRef.DeviceType.PowerScreen },
{ label: '车库门', value: graphicData.RelatedRef.DeviceType.GarageDoor },
{ label: '洗车机', value: graphicData.RelatedRef.DeviceType.CarWashing },
];
const noShowType = [

View File

@ -32,14 +32,9 @@ const upDownOptions = [
];
function setSignalDirection(signal: Signal, v1: { x: number; y: number }) {
const p1 = signal.lampMainBody.getPositionOnCanvas();
const p2 = signal.lampMainBody.localToCanvasPoint(
new Point(
signal.lampMainBody.lamps[0].radiusX,
signal.lampMainBody.lamps[0].radiusY
)
);
const v2 = { x: p1.x - p2.x, y: p1.y - p2.y };
const b1 = signal.lampMainBody.lampPost.getBounds();
const b2 = signal.lampMainBody.lamps.getBounds();
const v2 = { x: b1.x - b2.x, y: b1.y - b2.y };
const dotProduct = v1.x * v2.x + v1.y * v2.y;
let length1 = Math.sqrt(v1.x * v1.x + v1.y * v1.y);
let length2 = Math.sqrt(v2.x * v2.x + v2.y * v2.y);

View File

@ -19,6 +19,15 @@
lazy-rules
autogrow
/>
<q-input
outlined
label="车站名拼音简写"
type="textarea"
@blur="onUpdate"
v-model="stationModel.stationNameAcronym"
lazy-rules
autogrow
/>
<q-list bordered separator class="rounded-borders">
<q-item no-wrap class="q-gutter-y-sm column">
<template v-if="stationModel.kilometerSystem">
@ -74,14 +83,6 @@
emit-value
@update:model-value="onUpdate"
/>
<q-select
outlined
class="q-mt-md"
@blur="onUpdate"
v-model="stationModel.refIbpMapCode"
:options="props.ibpNameList"
label="关联IBP地图"
/>
</q-form>
</template>
@ -90,17 +91,9 @@ 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 { defineProps, onMounted, watchEffect } from 'vue';
import { onMounted, watchEffect } from 'vue';
const drawStore = useDrawStore();
const props = defineProps({
ibpNameList: {
type: Array,
required: true,
},
});
const { data: stationModel, onUpdate } = useFormData(
new StationData(),
drawStore.getDrawApp()
@ -110,7 +103,6 @@ const directionOptions = [
{ label: '左行', value: 0 },
{ label: '右行', value: 1 },
];
let optionsStations: { label: string; value: number }[] = [];
watchEffect(() => {

View File

@ -0,0 +1,28 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="tccButtonModel.id" label="id" />
<q-input
outlined
v-model="tccButtonModel.code"
@blur="onUpdate"
label="紧急制动按钮"
lazy-rules
/>
<q-checkbox
v-model="tccButtonModel.isSelfReset"
label="是否自复位"
@update:model-value="onUpdate"
/>
</q-form>
</template>
<script setup lang="ts">
import { TccButtonData } from 'src/drawApp/graphics/TccButtonInteraction';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { useTccDrawStore } from 'src/stores/tcc-draw-store';
const { data: tccButtonModel, onUpdate } = useFormData(
new TccButtonData(),
useTccDrawStore().getDrawApp()
);
</script>

View File

@ -0,0 +1,24 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="tccHandleModel.id" label="id" />
<q-input
outlined
v-model="tccHandleModel.code"
@blur="onUpdate"
label="Tcc手柄"
lazy-rules
/>
</q-form>
</template>
<script setup lang="ts">
import { TccHandleData } from 'src/drawApp/graphics/TccHandleInteraction';
import { useTccDrawStore } from 'src/stores/tcc-draw-store';
import { useFormData } from 'src/components/DrawAppFormUtils';
const tccDrawStore = useTccDrawStore();
const { data: tccHandleModel, onUpdate } = useFormData(
new TccHandleData(),
tccDrawStore.getDrawApp()
);
</script>

View File

@ -0,0 +1,44 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="tccKeyModel.id" label="id" />
<q-input
outlined
v-model="tccKeyModel.code"
@blur="onUpdate"
label="Tcc钥匙"
lazy-rules
/>
<q-select
outlined
v-model="tccKeyModel.type"
:options="optionsKeyType"
:map-options="true"
:emit-value="true"
@update:model-value="onUpdate"
label="Tcc钥匙类型"
/>
</q-form>
</template>
<script setup lang="ts">
import { TccKeyData } from 'src/drawApp/graphics/TccKeyInteraction';
import { useTccDrawStore } from 'src/stores/tcc-draw-store';
import { useFormData } from 'src/components/DrawAppFormUtils';
import { tccGraphicData } from 'src/protos/tccGraphics';
const tccDrawStore = useTccDrawStore();
const { data: tccKeyModel, onUpdate } = useFormData(
new TccKeyData(),
tccDrawStore.getDrawApp()
);
const optionsKeyType = [
{
label: '司控器激活端',
value: tccGraphicData.TccKey.TccKeyType.driverControllerActivationClint,
},
{
label: '前后方向控制',
value: tccGraphicData.TccKey.TccKeyType.frontAndRearDirectionalControl,
},
];
</script>

View File

@ -0,0 +1,50 @@
<template>
<q-form class="q-gutter-sm">
<q-input outlined readonly v-model="textContentModel.id" label="id" />
<q-input
outlined
v-model="textContentModel.content"
@update:model-value="onUpdate"
label="TCC文字内容"
lazy-rules
/>
<q-input
outlined
v-model="textContentModel.color"
@blur="onUpdate"
label="TCC文字颜色"
lazy-rules
>
<template v-slot:append>
<q-icon name="colorize" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-color
@update:model-value="onUpdate"
v-model="textContentModel.color"
/>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-input
v-model.number="textContentModel.fontSize"
type="number"
outlined
@blur="onUpdate"
label="TCC文字大小"
lazy-rules
/>
</q-form>
</template>
<script setup lang="ts">
import { TccTextData } from 'src/drawApp/graphics/TccTextContentInteraction';
import { useTccDrawStore } from 'src/stores/tcc-draw-store';
import { useFormData } from 'src/components/DrawAppFormUtils';
const tccDrawStore = useTccDrawStore();
const { data: textContentModel, onUpdate } = useFormData(
new TccTextData(),
tccDrawStore.getDrawApp()
);
</script>

View File

@ -50,6 +50,22 @@
@update:model-value="onUpdate"
label="应答器类型"
></q-select>
<q-input
outlined
class="q-mt-md"
readonly
autogrow
v-model="transponderModel.fixedUserTelegram"
label="固定用户报文"
/>
<q-input
outlined
class="q-mt-md"
readonly
autogrow
v-model="transponderModel.fixedTelegram"
label="固定报文"
/>
<q-field class="q-mt-md" outlined label="关联区段" readonly stack-label>
<template #control>
<q-chip

View File

@ -25,6 +25,9 @@
<spks-switch-state
v-else-if="lineStore.selectedGraphicType === SpksSwitch.Type"
/>
<transponder-state
v-else-if="lineStore.selectedGraphicType === Transponder.Type"
></transponder-state>
</div>
</q-scroll-area>
</template>
@ -51,6 +54,8 @@ import ScreenDoorState from './states/ScreenDoorState.vue';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import SpksSwitchState from './states/SpksSwitchState.vue';
import { SpksSwitch } from 'src/graphics/spksSwitch/SpksSwitch';
import TransponderState from './states/TransponderState.vue';
import { Transponder } from 'src/graphics/transponder/Transponder';
const lineStore = useLineStore();
</script>

View File

@ -0,0 +1,88 @@
<template>
<draggable-dialog
ref="dialogRef"
@show="onDialogShow"
seamless
title="仿真第三方接口状态信息"
:width="300"
:height="0"
>
<template v-slot:footer>
<q-table
ref="tableRef"
row-key="id"
:rows="rows"
:columns="columns"
@request="onRequest"
hide-bottom
>
<template v-slot:body-cell-state="props">
<q-td :props="props">
<div :class="[props.row.state == 0 ? 'table-green' : 'table-red']">
{{ props.row.state == 0 ? '正常' : '异常' }}
</div>
</q-td>
</template>
</q-table>
</template>
</draggable-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import DraggableDialog from 'src/components/common/DraggableDialog.vue';
import { QTable } from 'quasar';
import { state } from 'src/protos/device_state';
import { useTestManageStore } from 'src/stores/testManage-store';
const testManageStore = useTestManageStore();
const dialogRef = ref<InstanceType<typeof DraggableDialog>>();
const tableRef = ref<QTable>();
enum Type {
'未定义',
'动力学',
'半实物列车',
}
const columns: QTable['columns'] = [
{
name: 'type',
label: '接口服务',
field: (row) => Type[row.type],
align: 'center',
},
{
name: 'state',
label: '服务状态',
field: (row) => (row.state == 0 ? '正常' : '异常'),
align: 'center',
},
];
const rows = ref<state.SimulationThirdPartyApiServiceState[]>([]);
watch(
() => testManageStore.connectInfo,
() => {
onDialogShow();
}
);
const onRequest: QTable['onRequest'] = async () => {
const datas = testManageStore.connectInfo?.states;
if (datas) {
rows.value = datas;
}
};
const onDialogShow = () => {
tableRef.value?.requestServerInteraction();
};
</script>
<style>
.table-red {
color: red;
}
.table-green {
color: green;
}
</style>

View File

@ -2,48 +2,181 @@
<q-card flat bordered>
<q-card-section class="flex justify-between">
<span class="text-h6">列车信息</span>
<q-btn color="primary" label="曲线图" @click="open" />
<div>
<!-- <q-btn
color="primary"
label="设置"
@click="setTrain"
style="margin-right: 10px"
/> -->
<q-btn-dropdown color="primary" label="操作">
<q-list>
<q-item
v-for="(item, index) in options"
:key="index"
clickable
v-close-popup
@click="doTrainOperation(item)"
>
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn
color="primary"
label="曲线图"
style="margin-left: 10px"
@click="open"
/>
</div>
</q-card-section>
<q-separator inset />
<q-list v-if="trainInfo" dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
<q-item-label
:style="{
color:
item.key === 'conn' || item.key === 'connType'
? trainInfo.conn
? '#0F0'
: '#F00'
: '',
}"
>{{ item.label }}</q-item-label
>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
<q-item-label
caption
:style="{
color:
item.key === 'conn' || item.key === 'connType'
? trainInfo.conn
? '#0F0'
: '#F00'
: '',
}"
>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label
>
</q-item-section>
</q-item>
<q-separator inset />
<q-item v-for="(item, index) in list2" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
<q-separator inset />
<q-item v-for="(item, index) in list3" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
<div class="q-gutter-y-md" style="max-width: 380px">
<q-tabs
v-model="tab"
inline-label
outside-arrows
mobile-arrows
class="bg-purple text-white shadow-2"
>
<q-tab name="tab1" label="动力学" />
<q-tab name="tab2" label="半实物" />
<q-tab name="tab3" label="速传" />
<q-tab name="tab4" label="雷达" />
<q-tab name="tab5" label="加速度计" />
<q-tab name="tab6" label="BTM" />
</q-tabs>
</div>
<q-separator />
<q-tab-panels v-model="tab" animated>
<q-tab-panel name="tab1">
<q-item v-for="(item, index) in list2" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-tab-panel>
<q-tab-panel name="tab2">
<q-item v-for="(item, index) in list3" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-tab-panel>
<q-tab-panel name="tab3">
<q-item v-for="(item, index) in list4" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-tab-panel>
<q-tab-panel name="tab4">
<q-item v-for="(item, index) in list5" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-tab-panel>
<q-tab-panel name="tab5">
<q-item v-for="(item, index) in list6" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-tab-panel>
<q-tab-panel name="tab6">
<q-item v-for="(item, index) in list7" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>
<div
style="word-wrap: break-word; width: 150px; text-align: right"
>
{{
item.formatFn
? item.formatFn(trainInfo[item.key])
: trainInfo[item.key]
}}
</div>
</q-item-label>
</q-item-section>
</q-item>
</q-tab-panel>
</q-tab-panels>
</q-list>
</q-card>
</template>
@ -53,20 +186,29 @@ import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted } from 'vue';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { Section } from 'src/graphics/section/Section';
import SetTrainParam from 'src/components/draw-app/dialogs/SetTrainParam.vue';
import { Dialog } from 'quasar';
import { state } from 'src/protos/device_state';
import SetTrainLink from 'src/components/draw-app/dialogs/SetTrainLink.vue';
import { useTccStore } from 'src/stores/tcc-store';
interface KeyType {
label: string;
key: keyof ITrainState;
formatFn?(v: ITrainState[keyof ITrainState]): string;
}
const tab = ref('tab1');
const lineStore = useLineStore();
const trainInfo = ref<ITrainState | null>();
const list: KeyType[] = [
{ label: '列车索引', key: 'id' },
{ label: '连接状态', key: 'conn', formatFn: connStateFormat },
{ label: '连接平台', key: 'connType', formatFn: connTypeFormat },
{ label: '列车长度', key: 'trainLength', formatFn: trainLengthFormat },
{ label: '车头所在设备', key: 'headDeviceId', formatFn: getDeviveName },
{ label: '车头所在设备的偏移量', key: 'headOffset', formatFn: offsetFormat },
{ label: '车尾所在设备', key: 'tailDeviceId', formatFn: getTailDeviveName },
{ label: '车尾所在设备的偏移量', key: 'tailOffset', formatFn: offsetFormat },
{ label: '是否上行', key: 'runDirection', formatFn: upFormat },
{ label: '车头方向是否上行', key: 'headDirection', formatFn: upFormat },
{
@ -111,14 +253,24 @@ const list2: KeyType[] = [
{ label: '坡道阻力', key: 'rampResistance', formatFn: resistanceFormat },
{ label: '曲线阻力', key: 'curveResistance', formatFn: resistanceFormat },
{ label: '列车运行速度', key: 'speed', formatFn: speedFormat },
{ label: '头车速传1速度值', key: 'headSensorSpeed1', formatFn: speedFormat },
{ label: '头车速传2速度值', key: 'headSensorSpeed2', formatFn: speedFormat },
{ label: '尾车速传1速度值', key: 'tailSensorSpeed1', formatFn: speedFormat },
{ label: '尾车速传2速度值', key: 'tailSensorSpeed2', formatFn: speedFormat },
{ label: '头车雷达速度值', key: 'headRadarSpeed', formatFn: speedFormat },
{ label: '尾车雷达速度值', key: 'tailRadarSpeed', formatFn: speedFormat },
// { label: '', key: 'udpInterruption', formatFn: upFormat },
{ label: '加速度', key: 'acceleration', formatFn: accelerationFormat },
{ label: '基本阻力参数A', key: 'davisParamA' },
{ label: '基本阻力参数B', key: 'davisParamB' },
{ label: '基本阻力参数C', key: 'davisParamC' },
{ label: '曲线阻力参数R1', key: 'curveResistanceParamR1' },
{ label: '曲线阻力参数R2', key: 'curveResistanceParamR2' },
{ label: '曲线阻力参数R3', key: 'curveResistanceParamR3' },
{ label: '曲线阻力参数R4', key: 'curveResistanceParamR4' },
{ label: '旋转质量参数', key: 'revolvingMassParam' },
{ label: '是否跳跃', key: 'jump', formatFn: upFormat },
{ label: '打滑加速度', key: 'slipA', formatFn: accelerationFormat },
{ label: '打滑冲击率', key: 'slipA', formatFn: chongjilvFormat },
{ label: '打滑持续时间', key: 'slipA', formatFn: haomiaoFormat },
{ label: '前溜/后溜', key: 'slide', formatFn: msFormat },
{ label: '过标/欠标', key: 'stopSign', formatFn: mmFormat },
{ label: '空转加速度', key: 'idlingA', formatFn: accelerationFormat },
{ label: '空转冲击率', key: 'idlingR', formatFn: chongjilvFormat },
{ label: '空转持续时间', key: 'idlingD', formatFn: haomiaoFormat },
];
const list3: KeyType[] = [
//
@ -176,6 +328,74 @@ const list3: KeyType[] = [
{ label: '整列车门关好', key: 'allDoorClose', formatFn: upFormat },
// { label: '', key: 'udpInterruption', formatFn: upFormat },
];
const list4: KeyType[] = [
// { label: '1', key: 'headSensorSpeed1', formatFn: speedFormat },
// { label: '2', key: 'headSensorSpeed2', formatFn: speedFormat },
// { label: '1', key: 'tailSensorSpeed1', formatFn: speedFormat },
// { label: '2', key: 'tailSensorSpeed2', formatFn: speedFormat },
{ label: '1端速传1是否有效', key: 'aSpeedSensorEnableA', formatFn: upFormat },
{ label: '1端速传2是否有效', key: 'aSpeedSensorEnableB', formatFn: upFormat },
{ label: '1端速度输出', key: 'aAccOutSpeed', formatFn: msFormat },
{ label: '2端速传1是否有效', key: 'bSpeedSensorEnableA', formatFn: upFormat },
{ label: '2端速传2是否有效', key: 'bSpeedSensorEnableB', formatFn: upFormat },
{ label: '2端速度输出', key: 'bAccOutSpeed', formatFn: msFormat },
];
const list5: KeyType[] = [
// { label: '', key: 'headRadarSpeed', formatFn: speedFormat },
// { label: '', key: 'tailRadarSpeed', formatFn: speedFormat },
{ label: '1端雷达是否有效', key: 'aRadarEnable', formatFn: upFormat },
{ label: '1端雷达测速差值', key: 'aRadarCheckSpeedDiff', formatFn: msFormat },
{
label: '1端雷达检测时间(秒)',
key: 'aRadarCheckTime',
formatFn: timeFormat,
},
{ label: '1端雷达速度输出', key: 'aRadarOutSpeed', formatFn: msFormat },
{ label: '2端雷达是否有效', key: 'bRadarEnable', formatFn: upFormat },
{ label: '2端雷达测速差值', key: 'bRadarCheckSpeedDiff', formatFn: msFormat },
{
label: '2端雷达检测时间',
key: 'bRadarCheckTime',
formatFn: timeFormat,
},
{ label: '2端雷达速度输出', key: 'bRadarOutSpeed', formatFn: msFormat },
];
const list6: KeyType[] = [
{ label: '加速度', key: 'acceleration', formatFn: accelerationFormat },
{ label: '1端加速度计是否有效', key: 'aAccEnable', formatFn: upFormat },
{ label: '1端加速度测速差值', key: 'aAccCheckSpeedDiff', formatFn: msFormat },
{
label: '1端加速度持续时间',
key: 'aAccCheckTime',
formatFn: timeFormat,
},
{ label: '2端加速度计是否有效', key: 'bAccEnable', formatFn: upFormat },
{ label: '2端加速度测速差值', key: 'bAccCheckSpeedDiff', formatFn: msFormat },
{
label: '2端加速度持续时间',
key: 'bAccCheckTime',
formatFn: timeFormat,
},
];
const list7: KeyType[] = [
{ label: '数据流水号', key: 'dataSerialNumber' },
{ label: '应答器计数', key: 'baliseCount' },
{ label: '报文计数器', key: 'messageCounter' },
{ label: '报文', key: 'telegram' },
];
function mmFormat(v: number) {
return v + 'mm';
}
function percentFormat(v: number) {
return v + '%';
}
function msFormat(v: number) {
return v + 'm/s';
}
function timeFormat(v: number) {
return v + 's';
}
function upFormat(v: boolean) {
return v ? '是' : '否';
}
@ -208,12 +428,31 @@ function speedFormat(v: number) {
}
function accelerationFormat(v: number) {
const n = floatDecimal(v);
return `${n} m/s`;
return `${n} m/s²`;
}
function chongjilvFormat(v: number) {
return `${v} m/s³`;
}
function haomiaoFormat(v: number) {
return `${v} ms`;
}
function trainLengthFormat(v: number) {
return `${v / 1000} m`;
}
function connStateFormat(v: boolean) {
return v ? '已连接' : '未连接';
}
function connTypeFormat(v: state.TrainConnState.TrainConnType) {
if (v === state.TrainConnState.TrainConnType.NONE) {
return '无';
} else if (v === state.TrainConnState.TrainConnType.PC_SIM) {
return 'PC仿真';
} else if (v === state.TrainConnState.TrainConnType.VOBC) {
return '半实物';
} else {
return '无';
}
}
function floatDecimal(v: number, x = 2) {
//
const n = v.toFixed(x);
@ -278,6 +517,28 @@ function getDeviveName() {
}
return name;
}
function getTailDeviveName() {
const headDeviceId = trainInfo.value?.tailDeviceId;
const devicePort = trainInfo.value?.tailDevicePort;
let dev: Turnout | Section | undefined;
let name = '';
if (devicePort) {
dev = turnouts.value.find((item) => {
return item.datas.id == headDeviceId;
}) as Turnout;
if (dev) {
name = `${dev?.datas.code}_${devicePort}`;
}
} else {
dev = sections.value.find((item) => {
return item.datas.id == headDeviceId;
}) as Section;
if (dev) {
name = `${dev?.datas.code}`;
}
}
return name;
}
watch(
() => lineStore.selectedGraphics,
@ -300,7 +561,8 @@ watch(
);
});
if (find) {
trainInfo.value.copyFrom(find);
// console.log(find, '1111');
trainInfo.value = find as ITrainState;
}
}
}
@ -336,4 +598,75 @@ function open() {
if (!trainInfo.value) return;
lineStore.setEchartsTrainId(trainInfo.value.id);
}
const options = [
{
label: '设置参数',
value: 1,
},
{
label: '列车连接',
value: 2,
},
{
label: '列车驾驶台',
value: 3,
},
];
function doTrainOperation(option: { label: string; value: number }) {
if (option.value == 1) {
setTrain();
} else if (option.value == 2) {
linkTrain();
} else if (option.value == 3) {
openTccDialog();
}
}
function linkTrain() {
if (!lineStore.selectedGraphics) return;
if (lineStore.deviceOpreratDialogInstance) return;
const train = lineStore.selectedGraphics[0] as Train;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '列车连接',
message: '',
component: SetTrainLink,
componentProps: {
trainId: train.code,
simulationId: lineStore.simulationId,
},
cancel: true,
persistent: true,
});
}
function setTrain() {
if (!lineStore.selectedGraphics) return;
if (lineStore.deviceOpreratDialogInstance) return;
const train = lineStore.selectedGraphics[0] as Train;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '列车设置',
message: '',
component: SetTrainParam,
componentProps: {
train: train,
},
cancel: true,
persistent: true,
});
}
function openTccDialog() {
const trainId = trainInfo.value?.id ? +trainInfo.value?.id : 0;
useTccStore().setTccParam(
trainId,
trainInfo.value?.trainControlMapId as number
);
}
</script>
<style lang="scss" scoped>
.q-item {
min-height: 32px;
}
</style>

View File

@ -1,78 +1,30 @@
<template>
<QCard flat bordered>
<QCardSection>
<q-card flat bordered>
<q-card-section>
<div class="text-h6">站台状态</div>
</QCardSection>
<QSeparator inset />
<QCardSection>
<QForm>
<QInput
outlined
readonly
v-model="platformState.id"
label="id"
hint=""
/>
<QInput
outlined
readonly
v-model.number="platformState.code"
label="名称"
/>
</QForm>
</QCardSection>
<QCardSection>
<QList dense bordered padding class="rounded-borders q-my-sm">
<QItem>
<QCheckbox
dense
v-model="platformState.empj"
outlined
label="EMP继电器状态"
disable
/>
</QItem>
<template v-if="isSpksInfoShow">
<QSeparator class="q-mt-sm" />
<QItemLabel header>Spks继电器状态</QItemLabel>
<QItem>
<QItemSection>
<QCheckbox
v-for="item in platformState.spksState"
:key="item.id"
dense
v-model="item.xh"
:label="item.code"
disable
/>
</QItemSection>
</QItem>
</template>
<template v-if="isMkxInfoShow">
<QSeparator class="q-mt-sm" />
<QItemLabel header
>门控箱继电器状态 ({{ platformState.mkxJState.code }})</QItemLabel
>
<QItem>
<QItemSection>
<QCheckbox
v-for="reply in platformState.mkxJState.replyState"
v-model="reply.xh"
:label="reply.code"
:key="reply.id"
dense
disable
/>
</QItemSection>
</QItem>
</template>
</QList>
</QCardSection>
</QCard>
</q-card-section>
<q-separator inset />
<q-card-section>
<q-list dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(platformState[item.key])
: platformState[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
</q-card>
</template>
<script setup lang="ts">
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, watchEffect, onUnmounted, computed } from 'vue';
import { ref, watch, watchEffect, onUnmounted } from 'vue';
import { Platform } from 'src/graphics/platform/Platform';
import { state } from 'src/protos/device_state';
import { PlatformState } from 'src/drawApp/graphics/PlatformInteraction';
@ -92,6 +44,28 @@ const platformState = ref<{
mkxJState: new state.MkxJState(),
});
interface KeyType {
label: string;
key: keyof PlatformState;
formatFn?(v: PlatformState[keyof PlatformState]): string;
}
const list: KeyType[] = [
{ label: '站台索引', key: 'id' },
{ label: '站台名称', key: 'code' },
{ label: 'EMP继电器状态', key: 'empj', formatFn: getEMPRelayState },
{ label: 'SPKSX旁路', key: 'spksState', formatFn: getSPKSXRelayState },
{ label: 'SPKS1', key: 'spksState', formatFn: getSPKS1RelayState },
{ label: 'SPKS3', key: 'spksState', formatFn: getSPKS3RelayState },
{ label: '站台确认继电器', key: 'mkxJState', formatFn: getConfirmRelayState },
{
label: '站台关门继电器',
key: 'mkxJState',
formatFn: getCloseSPKS1RelayState,
},
{ label: '站台开门继电器', key: 'mkxJState', formatFn: getOpenRelayState },
];
const stop = watchEffect(() => {
if (
lineStore.selectedGraphics?.length == 1 &&
@ -100,7 +74,7 @@ const stop = watchEffect(() => {
setPlatformState(lineStore.selectedGraphics[0] as Platform);
}
});
onUnmounted(stop);
watch(
() => lineStore.socketStates,
(val) => {
@ -122,21 +96,6 @@ watch(
}
);
const isSpksInfoShow = computed(() => {
const selected = lineStore.selectedGraphics;
if (!selected) return;
const platform = selected[0] as Platform;
console.log(platform.states);
return platform.states.spksState?.length !== 0;
});
const isMkxInfoShow = computed(() => {
const selected = lineStore.selectedGraphics;
if (!selected) return;
const platform = selected[0] as Platform;
return platform.states.mkxJState?.replyState?.length !== 0;
});
function setPlatformState(platform: Platform) {
platformState.value = {
id: platform.datas.id,
@ -146,4 +105,44 @@ function setPlatformState(platform: Platform) {
mkxJState: platform.states.mkxJState ?? new state.MkxJState(),
};
}
function getEMPRelayState(v: boolean) {
if (v) return 'Q';
return 'H';
}
function getSPKSXRelayState(spksState: state.ReplyState[]) {
if (spksState.find((item) => item.code == 'SPKSX旁路')?.xh) return 'Q';
return 'H';
}
function getSPKS1RelayState(spksState: state.ReplyState[]) {
if (spksState.find((item) => item.code == 'SPKS1')?.xh) return 'Q';
return 'H';
}
function getSPKS3RelayState(spksState: state.ReplyState[]) {
if (spksState.find((item) => item.code == 'SPKS3')?.xh) return 'Q';
return 'H';
}
function getConfirmRelayState(mkxJState: state.MkxJState) {
if (mkxJState.replyState.find((item) => item.code == '站台确认继电器')?.xh)
return 'Q';
return 'H';
}
function getCloseSPKS1RelayState(mkxJState: state.MkxJState) {
if (mkxJState.replyState.find((item) => item.code == '站台关门继电器')?.xh)
return 'Q';
return 'H';
}
function getOpenRelayState(mkxJState: state.MkxJState) {
if (mkxJState.replyState.find((item) => item.code == '站台开门继电器')?.xh)
return 'Q';
return 'H';
}
onUnmounted(stop);
</script>

View File

@ -1,5 +1,11 @@
<template>
<q-card flat bordered>
<q-card
flat
bordered
v-for="(item, index) in relayState"
:key="item.id"
style="margin-bottom: 10px"
>
<q-card-section class="flex justify-between">
<span class="text-h6">继电器状态</span>
<q-btn-dropdown color="primary" label="操作">
@ -9,7 +15,7 @@
:key="item.label"
clickable
v-close-popup
@click="changePosition(item.value)"
@click="changePosition(item.value, index)"
>
<q-item-section>{{ item.label }}</q-item-section>
</q-item>
@ -17,10 +23,21 @@
</q-btn-dropdown>
</q-card-section>
<q-separator inset />
<q-card-section class="q-gutter-sm">
<q-input outlined readonly v-model="relayState.id" label="id" />
<q-input outlined readonly v-model="relayState.code" label="名称" />
<q-checkbox disable v-model="relayState.xh" label="是否吸合" />
<q-card-section>
<q-list dense>
<q-item v-for="(item, i) in list" :key="i">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(relayState[index][item.key])
: relayState[index][item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
</q-card>
</template>
@ -32,29 +49,57 @@ import { useQuasar } from 'quasar';
import { ApiError } from 'src/boot/axios';
import { Relay } from 'src/graphics/relay/Relay';
import { RelayState } from 'src/drawApp/relayCabinetGraphics/RelayInteraction';
import { request } from 'src/protos/request';
const $q = useQuasar();
const lineStore = useLineStore();
const relayState = ref({
id: 0,
code: '',
xh: false,
});
const relayState = ref<
{
id: number;
code: string;
xh: boolean;
force: boolean;
}[]
>([
{
id: 0,
code: '',
xh: false,
force: false,
},
]);
let operateOptions: {
label: string;
value: boolean;
}[] = [];
let copySelectGraphic: Relay | null = null;
value: request.Relay.Operation;
}[] = [
{ label: '强制前接点位(吸起)', value: request.Relay.Operation.ForceQw },
{ label: ' 强制后接点位(落下)', value: request.Relay.Operation.ForceHw },
{ label: ' 取消强制', value: request.Relay.Operation.CancelForce },
];
let copySelectGraphic: Relay[] | null = null;
interface KeyType {
label: string;
key: keyof RelayState;
formatFn?(v: RelayState[keyof RelayState]): string;
}
const list: KeyType[] = [
{ label: '继电器索引', key: 'id' },
{ label: '继电器名称', key: 'code' },
{ label: '继电器状态', key: 'xh', formatFn: getRelayStateName },
{ label: '是否强制', key: 'force', formatFn: getName },
];
watch(
() => lineStore.selectedGraphics,
(val, oldVal) => {
if (oldVal?.length == 1 && oldVal[0] instanceof Relay) {
unSubscribeState(oldVal[0]);
if (oldVal && oldVal.length >= 1) {
unSubscribeState(oldVal as Relay[]);
}
if (val?.length == 1 && val[0] instanceof Relay) {
copySelectGraphic = toRaw(val[0]);
setNewRelayState(val[0]);
if (val && val.length >= 1) {
copySelectGraphic = toRaw(val as Relay[]);
initRelayState(val as Relay[]);
} else {
copySelectGraphic = null;
}
@ -63,44 +108,50 @@ watch(
onMounted(() => {
if (lineStore.selectedGraphics) {
setNewRelayState(lineStore.selectedGraphics[0] as Relay);
initRelayState(lineStore.selectedGraphics as Relay[]);
}
});
function setNewRelayState(relay: Relay) {
relayState.value = {
id: relay.datas.id,
code: relay.datas.code,
xh: relay.states.xh || false,
};
operateOptions = relay.states.xh
? [{ label: '驱动落下', value: false }]
: [{ label: '驱动吸起', value: true }];
subscribeState(relay);
function getRelayStateName(v: boolean) {
if (v) return 'Q';
return 'H';
}
function subscribeState(g: Relay) {
g.on('stateupdate', updateState);
function getName(v: boolean) {
if (v) return '是';
return '否';
}
function unSubscribeState(g: Relay) {
g.off('stateupdate', updateState);
function initRelayState(relays: Relay[]) {
copySelectGraphic = toRaw(relays);
relayState.value = [];
relays.forEach((relay) =>
relayState.value.push({
id: relay.datas.id,
code: relay.datas.code,
xh: relay.states.xh || false,
force: relay.states.force || false,
})
);
subscribeState(relays);
}
function updateState(newVal: RelayState) {
relayState.value.xh = newVal.states.xh || false;
operateOptions = newVal.states.xh
? [{ label: '驱动落下', value: false }]
: [{ label: '驱动吸起', value: true }];
for (let i = 0; i < relayState.value.length; i++) {
if (+newVal.code == relayState.value[i].id) {
relayState.value[i].xh = newVal.states.xh || false;
relayState.value[i].force = newVal.states.force || false;
}
}
}
function changePosition(td: boolean) {
function changePosition(operation: request.Relay.Operation, index: number) {
if (lineStore.simulationId) {
setRelayState({
id: relayState.value.id,
mapId: lineStore.mapId as number,
simulationId: lineStore.simulationId,
td,
mapId: lineStore.mapId as number,
deviceId: relayState.value[index].id,
operation,
})
.then(() => {
$q.notify({ type: 'positive', message: '修改继电器状态成功' });
@ -115,6 +166,18 @@ function changePosition(td: boolean) {
}
}
function subscribeState(g: Relay[]) {
g.forEach((item) => {
item.on('stateupdate', updateState);
});
}
function unSubscribeState(g: Relay[]) {
g.forEach((item) => {
item.off('stateupdate', updateState);
});
}
onUnmounted(() => {
if (copySelectGraphic) {
unSubscribeState(copySelectGraphic);

View File

@ -20,280 +20,128 @@
</q-card-section>
<q-separator inset />
<q-card-section>
<q-input
outlined
readonly
v-model="screenDoorState.code"
label="id"
hint=""
/>
<q-input outlined readonly v-model.number="code" label="名称" />
<q-checkbox
dense
style="margin-top: 10px"
v-model="screenDoorState.mgj"
outlined
label="屏蔽门关闭"
:disable="true"
/>
<template :key="item" v-for="item in screenDoorState.asdStates">
<q-list dense bordered padding class="rounded-borders q-my-sm">
<q-item>
<q-item-section>
<q-input
outlined
readonly
v-model.number="item.code"
label="门名称"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="item.kmdw"
outlined
label="开门到位(实际)"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="item.gmdw"
outlined
label="关门到位(实际)"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="item.mgj"
outlined
label="关闭(表示)"
:disable="true"
/>
</q-item-section>
</q-item>
</q-list>
</template>
<q-list dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(screenDoorState[item.key])
: screenDoorState[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
<q-separator inset />
<q-card-section>
<div>
<template :key="item.id" v-for="item in screenDoorState.asdStates">
<q-list dense>
<q-item v-for="(listItem, index) in smallDoorlist" :key="index">
<q-item-section>
<q-item-label>{{ listItem.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
listItem.formatFn
? listItem.formatFn(item[listItem.key])
: item[listItem.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
<q-separator inset />
</template>
</div>
</q-card-section>
<q-dialog v-model="selectAsd">
<q-card style="width: 400px; max-width: 80vw">
<q-card-section>
<div class="text-h6">请选择滑动门</div>
</q-card-section>
<q-card-section class="q-pt-none">
<template :key="item" v-for="item in asdOptions">
<q-checkbox
v-model="asdCodes"
:val="item"
:label="item < 10 ? '0' + item : item + ''"
/>
</template>
</q-card-section>
<q-card-actions align="right">
<q-btn
flat
label="确定"
color="primary"
@click="handleAsdOperation"
/>
<q-btn flat label="关闭" color="primary" @click="closeAsdOperation" />
</q-card-actions>
</q-card>
</q-dialog>
<!-- <q-card-actions align="center">
<q-btn label="修改" type="submit" color="primary" @click="submitState" />
<q-btn
label="重置"
type="reset"
color="primary"
flat
class="q-ml-sm"
@click="onReset"
/>
</q-card-actions> -->
</q-card>
</template>
<script setup lang="ts">
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted } from 'vue';
import { ref, watch, onMounted, onUnmounted, toRaw } from 'vue';
import { ScreenDoor } from 'src/graphics/screenDoor/ScreenDoor';
import { request } from 'src/protos/request';
// import { state } from 'src/protos/device_state';
import { screenDoorOperate } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
import { ScreenDoorState } from 'src/drawApp/graphics/ScreenDoorInteraction';
import ScreenDoorOperation from 'src/components/draw-app/dialogs/ScreenDoorOperation.vue';
import { Dialog } from 'quasar';
import { state } from 'src/protos/device_state';
// string code = 1; //
// bool kmdw = 2; //
// bool gmdw = 3; //
// bool mgj = 4; //
const lineStore = useLineStore();
const screenDoorState = ref<ScreenDoorState>(new ScreenDoorState());
const code = ref('');
const selectAsd = ref(false);
const asdCodes = ref<number[]>([]);
const asdOptions = ref<number[]>([]);
let asdOperation: null | request.Psd.Operation = null;
const operationOptions = ref<
{ label: string; value: request.Psd.Operation; group?: number }[]
>([]);
const options = [
// {
// label: '',
// value: request.Psd.Operation.Km,
// },
// {
// label: '',
// value: request.Psd.Operation.CancelKm,
// },
const sonDoorAmount = ref(0);
const operationOptions = [
{
label: '关门',
value: request.Psd.Operation.Gm,
label: '设置参数',
value: request.Psd.Operation.SetParams,
},
];
const screenDoorForce = ref<request.Psd.Force>(0);
const screenDoorForceOption = [
{
label: '无强制',
value: request.Psd.Force.F_NONE,
},
{
label: '取消关门',
value: request.Psd.Operation.CancelGm,
label: '强制开门',
value: request.Psd.Force.F_ASD_KM,
},
// {
// label: '',
// value: request.Psd.Operation.ForceKm,
// },
{
label: '强制关门',
value: request.Psd.Operation.Gm,
},
{
label: '滑动门无法开门',
value: request.Psd.Operation.AsdCannotOpen,
},
{
label: '取消滑动门无法开门',
value: request.Psd.Operation.CancelAsdCannotOpen,
},
{
label: '滑动门无法关闭',
value: request.Psd.Operation.AsdCannotClose,
},
{
label: '取消滑动门无法关闭',
value: request.Psd.Operation.CancelAsdCannotClose,
value: request.Psd.Force.F_ASD_GM,
},
];
const screenDoorFault = ref<request.Psd.Fault>(0);
const asdCodes = ref<number[]>([]);
const asdOptions = ref<number[]>([]);
let copySelectGraphic: ScreenDoor | null = null;
interface KeyType {
label: string;
key: keyof ScreenDoorState;
formatFn?(v: ScreenDoorState[keyof ScreenDoorState]): string;
}
const list: KeyType[] = [
{ label: '屏蔽门索引', key: 'id' },
{ label: '屏蔽门名称', key: 'code', formatFn: getNameFormat },
{ label: '屏蔽门关闭', key: 'mgj', formatFn: getName },
{ label: '间隙探测障碍物', key: 'zaw', formatFn: getName },
{ label: '屏蔽门强制', key: 'param', formatFn: getForceName },
{ label: '设置故障', key: 'param', formatFn: getFaultName },
];
interface smallDoorKeyType {
label: string;
key: keyof state.AsdState;
formatFn?(v: state.AsdState[keyof state.AsdState]): string;
}
const smallDoorlist: smallDoorKeyType[] = [
{ label: '门名称', key: 'code' },
{ label: '是否强制', key: 'force', formatFn: getName },
{ label: '关闭', key: 'mgj', formatFn: getName },
{ label: '有障碍物', key: 'zaw', formatFn: getName },
];
watch(
() => lineStore.selectedGraphics,
(val) => {
if (val?.length == 1 && val[0].type == ScreenDoor.Type) {
initScreenDoorState(val[0] as ScreenDoor);
(val, oldVal) => {
if (oldVal?.length == 1 && oldVal[0] instanceof ScreenDoor) {
unSubscribeState(oldVal[0]);
}
if (val?.length == 1 && val[0] instanceof ScreenDoor) {
copySelectGraphic = toRaw(val[0]);
initScreenDoorState(val[0]);
} else {
copySelectGraphic = null;
screenDoorState.value = new ScreenDoorState();
}
}
);
function initScreenDoorState(screenDoor: ScreenDoor) {
code.value = screenDoor.datas.code;
operationOptions.value = [];
asdOptions.value = [];
if (lineStore.screenDoorGroupList.length) {
lineStore.screenDoorGroupList.forEach((item) => {
operationOptions.value.push({
label: `${item.trainGroupAmount}编组开门`,
value: request.Psd.Operation.Km,
group: item.trainGroupAmount,
});
operationOptions.value.push({
label: `取消${item.trainGroupAmount}编组开门`,
value: request.Psd.Operation.CancelKm,
group: item.trainGroupAmount,
});
operationOptions.value.push({
label: `强制${item.trainGroupAmount}编组开门`,
value: request.Psd.Operation.ForceKm,
group: item.trainGroupAmount,
});
});
}
options.forEach((option) => {
operationOptions.value.push(option);
});
if (screenDoor.datas.sonDoorAmount) {
for (let i = 1; i <= screenDoor.datas.sonDoorAmount; i++) {
asdOptions.value.push(i);
}
}
screenDoorState.value = screenDoor.states.clone() as ScreenDoorState;
}
// function submitState() {
// if (lineStore.simulationId) {
// }
// }
// function onReset() {
// if (lineStore.selectedGraphics) {
// initScreenDoorState(lineStore.selectedGraphics[0] as ScreenDoor);
// }
// }
function doScreenDoorOperation(item: {
label: string;
value: request.Psd.Operation;
group?: number;
}) {
const list = [
request.Psd.Operation.CancelAsdCannotClose,
request.Psd.Operation.AsdCannotClose,
request.Psd.Operation.AsdCannotOpen,
request.Psd.Operation.CancelAsdCannotOpen,
];
if (list.includes(item.value)) {
selectAsd.value = true;
asdOperation = item.value;
} else {
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
screenDoorOperate({
simulationId,
mapId,
deviceId: +screenDoorState.value.code,
operation: item.value,
group: item.group,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
}
}
function closeAsdOperation() {
asdCodes.value = [];
selectAsd.value = false;
}
function handleAsdOperation() {
selectAsd.value = true;
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
screenDoorOperate({
simulationId,
mapId,
deviceId: +screenDoorState.value.code,
operation: asdOperation as request.Psd.Operation,
asdCodes: asdCodes.value,
})
.catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
})
.finally(() => {
asdCodes.value = [];
});
selectAsd.value = false;
}
onMounted(() => {
if (lineStore.selectedGraphics) {
@ -301,20 +149,84 @@ onMounted(() => {
}
});
watch(
() => lineStore.socketStates,
(val) => {
if (val && screenDoorState.value.code) {
const find = val.find((item) => {
return (
item.graphicType == ScreenDoor.Type &&
(item as ScreenDoorState).code == screenDoorState.value.code
);
});
if (find) {
screenDoorState.value = find.clone() as ScreenDoorState;
}
function getNameFormat() {
return code.value;
}
function getName(v: boolean) {
if (v) return '是';
return '否';
}
function getForceName() {
return (
screenDoorForceOption.find((item) => item.value == screenDoorForce.value)
?.label || ''
);
}
function getFaultName() {
if (screenDoorFault.value == 1) return '是';
return '否';
}
function initScreenDoorState(screenDoor: ScreenDoor) {
copySelectGraphic = toRaw(screenDoor);
code.value = screenDoor.datas.code;
asdOptions.value = [];
sonDoorAmount.value = screenDoor.datas.sonDoorAmount;
if (screenDoor.datas.sonDoorAmount) {
for (let i = 1; i <= screenDoor.datas.sonDoorAmount; i++) {
asdOptions.value.push(i);
}
}
);
updateState(screenDoor);
subscribeState(screenDoor);
}
function updateState(screenDoor: ScreenDoor) {
screenDoorState.value = screenDoor.states.clone() as ScreenDoorState;
asdCodes.value = screenDoorState.value.param.asdCodes;
screenDoorForce.value = screenDoorState.value.param.force;
screenDoorFault.value = screenDoorState.value.param.fault;
}
function doScreenDoorOperation(item: {
label: string;
value: request.Psd.Operation;
}) {
if (!lineStore.simulationId) return;
if (item.label == '设置参数') {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
component: ScreenDoorOperation,
componentProps: {
id: +screenDoorState.value.id,
code: code.value,
sonDoorAmount: sonDoorAmount.value,
asdCodesProp: screenDoorState.value.param.asdCodes,
screenDoorForceProp: screenDoorState.value.param.force,
screenDoorFaultProp: screenDoorState.value.param.fault,
},
cancel: true,
persistent: true,
}).onCancel(() => {
lineStore.deviceOpreratDialogInstance = null;
});
}
}
function subscribeState(g: ScreenDoor) {
g.on('stateupdate', updateState);
}
function unSubscribeState(g: ScreenDoor) {
g.off('stateupdate', updateState);
}
onUnmounted(() => {
if (copySelectGraphic) {
unSubscribeState(copySelectGraphic);
}
});
</script>

View File

@ -9,7 +9,7 @@
:key="index"
clickable
v-close-popup
@click="toDo(item)"
@click="doSectionOperation(item)"
>
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
@ -20,42 +20,17 @@
</q-card-section>
<q-separator inset />
<q-card-section>
<q-form>
<q-input
outlined
readonly
v-model="sectionState.id"
label="id"
hint=""
/>
<q-input
outlined
readonly
v-model.number="sectionState.code"
label="名称"
/>
</q-form>
<q-list dense bordered padding class="rounded-borders q-my-sm">
<q-item>
<q-list dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-checkbox
dense
v-model="sectionState.occupied"
outlined
label="是否占用"
:disable="true"
/>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="sectionState.axleFault"
outlined
label="是否计轴故障"
:disable="true"
/>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(sectionState[item.key])
: sectionState[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
@ -64,118 +39,151 @@
</template>
<script setup lang="ts">
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted } from 'vue';
import { Section, type ISectionState } from 'src/graphics/section/Section';
import { ref, watch, onMounted, onUnmounted, toRaw } from 'vue';
import { Section } from 'src/graphics/section/Section';
import { request } from 'src/protos/request';
import { Dialog } from 'quasar';
import SectionOperation from 'src/components/draw-app/dialogs/SectionOperation.vue';
import { setAxleSectionState } from 'src/api/Simulation';
import { useQuasar } from 'quasar';
import { ApiError } from 'src/boot/axios';
import { errorNotify } from 'src/utils/CommonNotify';
import { SectionStates } from 'src/drawApp/graphics/SectionInteraction';
const $q = useQuasar();
const lineStore = useLineStore();
const sectionState = ref({
id: 0,
code: '',
axleFault: false,
occupied: false,
axleDrst: false,
axlePdrst: false,
});
let copySelectGraphic: Section | null = null;
interface KeyType {
label: string;
key: keyof SectionStates;
formatFn?(v: SectionStates[keyof SectionStates]): string;
}
const list: KeyType[] = [
{ label: '轨道索引', key: 'id' },
{ label: '轨道名称', key: 'code' },
{ label: '是否占用', key: 'axleFault', formatFn: getName },
{ label: '是否计轴故障', key: 'occupied', formatFn: getName },
{ label: '是否计轴复位', key: 'axleDrst', formatFn: getName },
{ label: '是否计轴预复位', key: 'axlePdrst', formatFn: getName },
];
watch(
() => lineStore.selectedGraphics,
(val) => {
if (val?.length == 1 && val[0].type == Section.Type) {
setSectionState(val[0] as Section);
(val, oldVal) => {
if (oldVal?.length == 1 && oldVal[0] instanceof Section) {
unSubscribeState(oldVal[0]);
}
if (val?.length == 1 && val[0] instanceof Section) {
copySelectGraphic = toRaw(val[0]);
initSectionState(val[0] as Section);
} else {
copySelectGraphic = null;
sectionState.value = {
id: 0,
code: '',
axleFault: false,
occupied: false,
axleDrst: false,
axlePdrst: false,
};
}
}
);
function setSectionState(section: Section) {
onMounted(() => {
if (lineStore.selectedGraphics) {
initSectionState(lineStore.selectedGraphics[0] as Section);
}
});
function getName(v: boolean) {
if (v) return '是';
return '否';
}
function initSectionState(section: Section) {
copySelectGraphic = toRaw(section);
sectionState.value = {
id: section.datas.id,
code: section.datas.code,
axleFault: section.states.axleFault ?? false,
occupied: section.states.occupied ?? false,
axleDrst: section.states.axleDrst ?? false,
axlePdrst: section.states.axlePdrst ?? false,
};
subscribeState(section);
}
onMounted(() => {
if (lineStore.selectedGraphics) {
setSectionState(lineStore.selectedGraphics[0] as Section);
}
});
function updateState(newVal: Section) {
sectionState.value = {
id: newVal.id,
code: sectionState.value.code,
axleFault: newVal.states.axleFault ?? false,
occupied: newVal.states.occupied ?? false,
axleDrst: newVal.states.axleDrst ?? false,
axlePdrst: newVal.states.axlePdrst ?? false,
};
}
const options = [
{
label: '设置计轴直接复位',
value: request.Section.Operation.SetDrst,
label: '设置参数',
value: request.Section.Operation.SetParams,
},
{
label: '取消计轴直接复位',
value: request.Section.Operation.CancelDrst,
},
{
label: '设置计轴预复位',
value: request.Section.Operation.SetPdrst,
},
{
label: '取消计轴预复位',
value: request.Section.Operation.CancelPdrst,
},
{
label: '设置区段故障占用',
label: '设置故障占用',
value: request.Section.Operation.SetFaultOcc,
},
{
label: '取消区段故障占用',
value: request.Section.Operation.CancelFaultOcc,
},
];
function toDo(item: { label: string; value: number }) {
function doSectionOperation(item: { label: string; value: number }) {
if (!lineStore.simulationId) return;
const obj = {
simulationId: lineStore?.simulationId || '',
mapId: lineStore.mapId as number,
id: sectionState.value.id,
operation: item.value,
};
setAxleSectionState(obj)
// .then(() => {
// $q.notify({ type: 'positive', message: '' });
// })
.catch((err) => {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
if (item.label == '设置参数') {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
component: SectionOperation,
componentProps: {
id: sectionState.value.id,
code: sectionState.value.code,
axleDrst: sectionState.value.axleDrst,
axlePdrst: sectionState.value.axlePdrst,
},
cancel: true,
persistent: true,
}).onCancel(() => {
lineStore.deviceOpreratDialogInstance = null;
});
}
watch(
() => lineStore.socketStates,
(val) => {
if (val && sectionState.value.id) {
const find = val.find((item): item is SectionStates => {
return (
item.graphicType == Section.Type &&
(item as ISectionState).id == sectionState.value.id
);
});
if (find) {
sectionState.value = {
id: find.id,
code: find.code,
axleFault: find.axleFault,
occupied: find.occupied,
};
}
}
} else {
const obj = {
simulationId: lineStore?.simulationId || '',
mapId: lineStore.mapId as number,
deviceId: sectionState.value.id,
operation: request.Section.Operation.SetFaultOcc,
};
setAxleSectionState(obj).catch((e) =>
errorNotify('区段操作失败:' + e.title, e)
);
}
);
}
function subscribeState(g: Section) {
g.on('stateupdate', updateState);
}
function unSubscribeState(g: Section) {
g.off('stateupdate', updateState);
}
onUnmounted(() => {
if (copySelectGraphic) {
unSubscribeState(copySelectGraphic);
}
});
</script>

View File

@ -20,159 +20,183 @@
</q-card-section>
<q-separator inset />
<q-card-section>
<q-input
outlined
readonly
v-model="signalState.code"
label="id"
hint=""
/>
<q-input outlined readonly v-model="index" label="索引" hint="" />
<q-input outlined readonly v-model.number="code" label="名称" />
<q-select
v-model="signalState.aspect"
style="margin-top: 10px"
label="灯亮状态"
outlined
:options="aspectOptions"
emitValue
mapOptions
:disable="true"
>
</q-select>
<q-list dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(signalState[item.key])
: signalState[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
<!-- <q-card-actions align="center">
<q-btn label="修改" type="submit" color="primary" @click="submitState" />
<q-btn
label="重置"
type="reset"
color="primary"
flat
class="q-ml-sm"
@click="onReset"
/>
</q-card-actions> -->
</q-card>
</template>
<script setup lang="ts">
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted } from 'vue';
import { ref, watch, onMounted, onUnmounted, toRaw } from 'vue';
import { Signal } from 'src/graphics/signal/Signal';
import { request } from 'src/protos/request';
import { state } from 'src/protos/device_state';
import { setSignalState } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
import { SignalState } from 'src/drawApp/graphics/SignalInteraction';
import { Dialog } from 'quasar';
import SignalOperation from 'src/components/draw-app/dialogs/SignalOperation.vue';
import { request } from 'src/protos/request';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { state } from 'src/protos/device_state';
const lineStore = useLineStore();
const signalState = ref<SignalState>(new SignalState());
const code = ref('');
const index = ref(0);
interface SignalDsItem {
label: string;
value: request.Signal.DS;
}
const signalDsOptions = ref<SignalDsItem[]>([]);
const hDs = {
label: '红灯断丝',
value: request.Signal.DS.DS_H,
};
const uDs = {
label: '黄灯断丝',
value: request.Signal.DS.DS_U,
};
const lDs = {
label: '绿灯断丝',
value: request.Signal.DS.DS_L,
};
const aDs = {
label: '蓝灯断丝',
value: request.Signal.DS.DS_A,
};
const bDs = {
label: '白灯断丝',
value: request.Signal.DS.DS_B,
};
interface SignalForceItem {
label: string;
value: request.Signal.Force;
}
const signalForceOptions = ref<SignalForceItem[]>([]);
const noForce = {
label: '无强制',
value: request.Signal.Force.SF_NONE,
};
const mieDeng = {
label: '灭灯',
value: request.Signal.Force.SF_M,
};
const hongDeng = {
label: '红灯',
value: request.Signal.Force.SF_H,
};
const huangDeng = {
label: '黄灯',
value: request.Signal.Force.SF_U,
};
const lvDeng = {
label: '绿灯',
value: request.Signal.Force.SF_L,
};
const huanghongDeng = {
label: '黄红灯',
value: request.Signal.Force.SF_HU,
};
const lanDeng = {
label: '蓝灯',
value: request.Signal.Force.SF_A,
};
const baiDeng = {
label: '白灯',
value: request.Signal.Force.SF_B,
};
const aspectOptions = [
{ label: '无用值', value: 0 },
{ label: '物理灭灯', value: 1 },
{ label: '绿灯亮', value: 2 },
{ label: '红灯亮', value: 3 },
{ label: '黄灯亮', value: 4 },
{ label: '红黄灯亮', value: 5 },
{ label: '白灯亮', value: 6 },
{ label: '蓝灯亮', value: 7 },
{ label: '灭灯', value: state.Signal.Aspect.OFF },
{ label: '红灯亮', value: state.Signal.Aspect.H },
{ label: '绿灯亮', value: state.Signal.Aspect.L },
{ label: '黄灯亮', value: state.Signal.Aspect.U },
{ label: '红黄灯亮', value: state.Signal.Aspect.HU },
{ label: '白灯亮', value: state.Signal.Aspect.B },
{ label: '蓝灯亮', value: state.Signal.Aspect.A },
];
const options = [
{
label: '开红灯',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.Display,
},
},
{
label: '开绿灯',
value: {
aspect: state.Signal.Aspect.L,
operation: request.Signal.Operation.Display,
},
},
{
label: '开黄灯',
value: {
aspect: state.Signal.Aspect.U,
operation: request.Signal.Operation.Display,
},
},
{
label: '开引导',
value: {
aspect: state.Signal.Aspect.HU,
operation: request.Signal.Operation.Display,
},
},
{
label: '关灯',
value: {
aspect: state.Signal.Aspect.OFF,
operation: request.Signal.Operation.Display,
},
},
{
label: '设置红灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightHFaultDs,
},
},
{
label: '设置绿灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightLFaultDs,
},
},
{
label: '设置黄灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightUFaultDs,
},
},
{
label: '取消红灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightHCancelDs,
},
},
{
label: '取消绿灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightLCancelDs,
},
},
{
label: '取消黄灯断丝故障',
value: {
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.LightUCancelDs,
},
},
const options = [{ label: '设置参数' }];
let copySelectGraphic: Signal | null = null;
interface KeyType {
label: string;
key: keyof SignalState;
formatFn?(v: SignalState[keyof SignalState]): string;
}
const list: KeyType[] = [
{ label: '信号机索引', key: 'code' },
{ label: '信号机名称', key: 'code', formatFn: getNameFormat },
{ label: '灯亮状态', key: 'aspect', formatFn: getAspectName },
{ label: '信号机强制', key: 'param', formatFn: getForceName },
{ label: '信号机断丝', key: 'param', formatFn: getDsName },
];
function getNameFormat(v: number) {
if (v) {
return code.value;
}
return '';
}
function getAspectName(aspect: state.Signal.Aspect) {
return aspectOptions.find((item) => item.value == aspect)?.label || '';
}
function getForceName(param: request.SignalParam) {
return (
signalForceOptions.value.find((item) => item.value == param.force)?.label ||
''
);
}
function getDsName(param: request.SignalParam) {
let s = '';
signalDsOptions.value.forEach((item) => {
if (param.dsList.includes(item.value)) {
const label = s ? item.label + '、' : item.label;
s += label;
}
});
return s || '无';
}
watch(
() => lineStore.selectedGraphics,
(val) => {
if (val?.length == 1 && val[0].type == Signal.Type) {
(val, oldVal) => {
if (oldVal?.length == 1 && oldVal[0] instanceof Signal) {
unSubscribeState(oldVal[0]);
}
if (val?.length == 1 && val[0] instanceof Signal) {
copySelectGraphic = toRaw(val[0]);
initSignalState(val[0] as Signal);
} else {
copySelectGraphic = null;
signalState.value = new SignalState();
}
}
);
const mt = ref(0);
function initSignalState(signal: Signal) {
copySelectGraphic = toRaw(signal);
// index.value = signal.datas.index;
initOptions(signal.datas.mt);
mt.value = signal.datas.mt;
code.value = signal.datas.code;
signalState.value = signal.states.clone() as SignalState;
subscribeState(signal);
}
function updateState(newVal: SignalState) {
signalState.value = newVal.clone() as SignalState;
}
// function submitState() {
// if (lineStore.simulationId) {
@ -183,21 +207,26 @@ function initSignalState(signal: Signal) {
// initSignalState(lineStore.selectedGraphics[0] as Signal);
// }
// }
function doSignalOperation(item: {
label: string;
value: { aspect: state.Signal.Aspect; operation: request.Signal.Operation };
}) {
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
setSignalState({
simulationId,
mapId,
id: +signalState.value.code,
aspect: item.value.aspect,
operation: item.value.operation,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
function doSignalOperation(item: { label: string }) {
if (!lineStore.simulationId) return;
if (item.label == '设置参数') {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '道岔设置参数',
message: '',
component: SignalOperation,
componentProps: {
id: +signalState.value.code,
code: code.value,
mt: mt.value,
param: signalState.value.param,
},
cancel: true,
persistent: true,
}).onCancel(() => {
lineStore.deviceOpreratDialogInstance = null;
});
}
}
onMounted(() => {
@ -206,20 +235,97 @@ onMounted(() => {
}
});
watch(
() => lineStore.socketStates,
(val) => {
if (val && signalState.value.code) {
const find = val.find((item) => {
return (
item.graphicType == Signal.Type &&
(item as SignalState).code == signalState.value.code
);
});
if (find) {
signalState.value = find.clone() as SignalState;
}
}
function initOptions(mt: graphicData.Signal.Model) {
switch (mt) {
case graphicData.Signal.Model.HL:
signalDsOptions.value = [hDs, lDs];
signalForceOptions.value = [noForce, mieDeng, hongDeng, lvDeng];
break;
case graphicData.Signal.Model.AB:
signalDsOptions.value = [aDs, bDs];
signalForceOptions.value = [noForce, mieDeng, lanDeng, baiDeng];
break;
case graphicData.Signal.Model.HBU_DU:
signalDsOptions.value = [hDs, bDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
baiDeng,
huangDeng,
];
break;
case graphicData.Signal.Model.HLU_FU:
signalDsOptions.value = [hDs, lDs];
signalForceOptions.value = [noForce, mieDeng, hongDeng, lvDeng];
break;
case graphicData.Signal.Model.HLU_DU_YY:
signalDsOptions.value = [hDs, lDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
lvDeng,
huangDeng,
huanghongDeng,
];
break;
case graphicData.Signal.Model.HLU_YY:
signalDsOptions.value = [hDs, lDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
lvDeng,
huanghongDeng,
];
break;
case graphicData.Signal.Model.HLU_FL_DU_YY:
signalDsOptions.value = [hDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
huangDeng,
huanghongDeng,
];
break;
case graphicData.Signal.Model.HLU_DU:
signalDsOptions.value = [hDs, lDs, uDs];
signalForceOptions.value = [
noForce,
mieDeng,
hongDeng,
lvDeng,
huangDeng,
];
break;
}
);
}
function subscribeState(g: Signal) {
if (g) {
g.on('stateupdate', updateState);
}
}
function unSubscribeState(g: Signal) {
if (g) {
g.off('stateupdate', updateState);
}
}
onUnmounted(() => {
if (copySelectGraphic) {
unSubscribeState(copySelectGraphic);
}
});
</script>
<style scoped>
.border-box {
border: 1px solid #ccc;
border-radius: 3px;
margin-left: 0;
margin-top: 10px;
}
</style>

View File

@ -1,26 +1,24 @@
<template>
<q-card flat bordered>
<q-card-section class="row justify-between items-center q-pb-none">
<q-card-section class="flex justify-between">
<div class="text-h6">车站状态</div>
<q-btn color="primary" @click="openIbp">打开IBP</q-btn>
</q-card-section>
<q-separator inset />
<q-card-section>
<q-form>
<q-input
outlined
readonly
v-model="stationState.id"
label="id"
hint=""
/>
<q-input
outlined
readonly
v-model.number="stationState.code"
label="名称"
/>
</q-form>
<q-list dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(stationState[item.key])
: stationState[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card-section>
</q-card>
</template>
@ -28,10 +26,20 @@
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted } from 'vue';
import { Station } from 'src/graphics/station/Station';
import { useIbpStore } from 'src/stores/ibp-store';
import { StationState } from 'src/drawApp/graphics/StationInteraction';
const lineStore = useLineStore();
const stationState = ref({ id: 0, code: '' });
interface KeyType {
label: string;
key: keyof StationState;
formatFn?(v: StationState[keyof StationState]): string;
}
const list: KeyType[] = [
{ label: '车站索引', key: 'id' },
{ label: '车站名称', key: 'code' },
];
watch(
() => lineStore.selectedGraphics,
@ -47,14 +55,6 @@ watch(
}
);
function openIbp() {
const selected = lineStore.selectedGraphics;
if (!selected) return;
const station = selected[0] as Station;
if (!station) return;
useIbpStore().openIbpScene(station);
}
function setStationState(station: Station) {
stationState.value = {
id: station.datas.id,

View File

@ -0,0 +1,300 @@
<template>
<q-card flat bordered>
<q-card-section class="flex justify-between">
<div class="text-h6">应答器状态</div>
<q-btn-dropdown color="primary" label="操作">
<q-list>
<q-item
v-for="(item, index) in options"
:key="index"
clickable
v-close-popup
@click="doTransponderOperation(item.value)"
>
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</q-card-section>
<q-separator inset />
<q-card-section>
<q-list dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption>
<div
style="word-wrap: break-word; width: 150px; text-align: right"
>
{{
item.formatFn
? item.formatFn(transponderState[item.key])
: transponderState[item.key]
}}
</div>
</q-item-label>
</q-item-section>
</q-item>
<template
v-if="
transponderType === TransponderTypeEnum.VB ||
transponderType === TransponderTypeEnum.IB
"
>
<q-item v-for="(item, index) in list1" :key="index">
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label caption
><div
style="word-wrap: break-word; width: 150px; text-align: right"
>
{{
item.formatFn
? item.formatFn(transponderState[item.key])
: transponderState[item.key]
}}
</div></q-item-label
>
</q-item-section>
</q-item>
</template>
</q-list>
</q-card-section>
</q-card>
</template>
<script setup lang="ts">
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted, toRaw, onUnmounted } from 'vue';
import { errorNotify } from 'src/utils/CommonNotify';
import { TransponderState } from 'src/drawApp/graphics/TransponderInteraction';
import {
Transponder,
TransponderTypeEnum,
} from 'src/graphics/transponder/Transponder';
import MoveTransponder from 'src/components/draw-app/dialogs/MoveTransponder.vue';
import UpdateMessageTransponder from 'src/components/draw-app/dialogs/UpdateMessageTransponder.vue';
import { Dialog } from 'quasar';
import {
resetMessageTransponder,
resetPositionTransponder,
stopTransponderTelegram,
sendTransponderTelegram,
} from 'src/api/Simulation';
import { graphicData } from 'src/protos/stationLayoutGraphics';
const lineStore = useLineStore();
const transponderState = ref<TransponderState>(new TransponderState());
const code = ref('');
const type = ref(0);
const kilometer = ref(0);
enum TransponderOperation {
MovePosition = 1,
ResetPosition = 2,
ModifyMessage = 3,
ResetMessage = 4,
StopMessage = 5,
SendMessage = 6,
}
const options = [
{
label: '移动应答器位置',
value: TransponderOperation.MovePosition,
},
{
label: '复位应答器',
value: TransponderOperation.ResetPosition,
},
{
label: '修改报文',
value: TransponderOperation.ModifyMessage,
},
{
label: '重置报文',
value: TransponderOperation.ResetMessage,
},
{
label: '停止发送报文',
value: TransponderOperation.StopMessage,
},
{
label: '取消停止发送报文',
value: TransponderOperation.SendMessage,
},
];
const directionOptions = [
{ label: '左行', value: 0 },
{ label: '右行', value: 1 },
];
let copySelectGraphic: Transponder | null = null;
interface KeyType {
label: string;
key: keyof TransponderState;
formatFn?(v: TransponderState[keyof TransponderState]): string;
}
const list: KeyType[] = [
{ label: '应答器索引', key: 'code' },
{ label: '应答器名称', key: 'code', formatFn: getNameFormat },
{ label: '坐标系', key: 'km', formatFn: getCoordinateSystemFormat },
{ label: '公里标', key: 'km', formatFn: getKilometerFormat },
{ label: '方向', key: 'km', formatFn: getDirectionFormat },
{ label: '停止发送报文', key: 'work', formatFn: workFormat },
{ label: '固定用户报文', key: 'fixedUserTelegram' },
{ label: '固定报文', key: 'fixedTelegram' },
];
const list1: KeyType[] = [
{
label: '可变用户报文',
key: 'variableUserTelegram',
},
{ label: '可变报文', key: 'variableTelegram' },
];
function getNameFormat(v: string) {
return code.value || v;
}
function getCoordinateSystemFormat(v: graphicData.KilometerSystem) {
return v.coordinateSystem;
}
function getKilometerFormat(v: graphicData.KilometerSystem) {
return v.kilometer + 'mm';
}
function getDirectionFormat(v: graphicData.KilometerSystem) {
return (
directionOptions.find((item) => item.value == v.direction)?.label || ''
);
}
function workFormat(v: boolean) {
return v ? '否' : '是';
}
watch(
() => lineStore.selectedGraphics,
(val, oldVal) => {
if (oldVal?.length == 1 && oldVal[0] instanceof Transponder) {
unSubscribeState(oldVal[0]);
}
if (val?.length == 1 && val[0] instanceof Transponder) {
copySelectGraphic = toRaw(val[0]);
initTransponderState(val[0] as Transponder);
} else {
copySelectGraphic = null;
transponderState.value = new TransponderState();
}
}
);
const transponderType = ref();
function initTransponderState(transponder: Transponder) {
transponderType.value = transponder.datas.type;
copySelectGraphic = toRaw(transponder);
code.value = transponder.datas.code;
type.value = transponder.datas.type;
kilometer.value = transponder.states.km?.kilometer || 0;
transponderState.value = transponder.states.clone() as TransponderState;
subscribeState(transponder);
}
function updateState(newVal: TransponderState) {
transponderState.value = newVal.clone() as TransponderState;
kilometer.value = transponderState.value.km.kilometer;
}
function doTransponderOperation(operation: number) {
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
if (operation === TransponderOperation.MovePosition) {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '移动应答器位置',
message: '',
component: MoveTransponder,
componentProps: {
code: code.value,
coordinateSystem: transponderState.value.km?.coordinateSystem,
kilometer: transponderState.value.km?.kilometer,
direction: transponderState.value.km?.direction,
id: transponderState.value.id,
type: type.value,
variableTelegram: transponderState.value.variableTelegram,
variableUserTelegram: transponderState.value.variableUserTelegram,
},
cancel: true,
persistent: true,
});
} else if (operation === TransponderOperation.ResetPosition) {
resetPositionTransponder({
simulationId,
mapId,
baliseId: transponderState.value.id,
}).catch((e) => {
errorNotify('复位应答器失败:' + e.title, e);
});
} else if (operation === TransponderOperation.ModifyMessage) {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '修改应答器报文',
message: '',
component: UpdateMessageTransponder,
componentProps: {
code: code.value,
fixedTelegram: transponderState.value.fixedTelegram,
fixedUserTelegram: transponderState.value.fixedUserTelegram,
id: transponderState.value.id,
},
cancel: true,
persistent: true,
});
} else if (operation === TransponderOperation.ResetMessage) {
resetMessageTransponder({
simulationId,
mapId,
baliseId: transponderState.value.id,
}).catch((e) => errorNotify('重置应答器报文失败:' + e.title, e));
} else if (operation === TransponderOperation.StopMessage) {
stopTransponderTelegram({
simulationId,
mapId,
baliseId: transponderState.value.id,
}).catch((e) => errorNotify('停止应答器报文失败:' + e.title, e));
} else if (operation === TransponderOperation.SendMessage) {
sendTransponderTelegram({
simulationId,
mapId,
baliseId: transponderState.value.id,
}).catch((e) => errorNotify('取消停止应答器报文失败:' + e.title, e));
}
}
onMounted(() => {
if (lineStore.selectedGraphics) {
initTransponderState(lineStore.selectedGraphics[0] as Transponder);
}
});
function subscribeState(g: Transponder) {
if (g) {
g.on('stateupdate', updateState);
}
}
function unSubscribeState(g: Transponder) {
if (g) {
g.off('stateupdate', updateState);
}
}
onUnmounted(() => {
if (copySelectGraphic) {
unSubscribeState(copySelectGraphic);
}
});
</script>

View File

@ -9,7 +9,7 @@
:key="index"
clickable
v-close-popup
@click="toDo(item)"
@click="doTurnoutOperation(item)"
>
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
@ -20,183 +20,17 @@
</q-card-section>
<q-separator inset />
<q-card-section>
<q-input
dense
outlined
readonly
v-model="turnoutState.id"
label="id"
hint=""
/>
<q-input dense outlined readonly v-model="name" label="名称" hint="" />
<q-list dense bordered padding class="rounded-borders q-my-sm">
<q-item>
<q-list dense>
<q-item v-for="(item, index) in list" :key="index">
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.normal"
outlined
label="定位(表示)"
:disable="true"
/>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.reverse"
outlined
label="反位(表示)"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.dw"
outlined
label="定位(实际)"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.fw"
outlined
label="反位(实际)"
:disable="true"
/>
</q-item-section>
</q-item>
</q-list>
<q-list dense bordered padding class="rounded-borders q-my-sm">
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.force"
outlined
label="是否强制(屏蔽联锁驱动)"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.qdc"
outlined
label="联锁定操驱动"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.qfc"
outlined
label="联锁反操驱动"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.qyc"
outlined
label="联锁允许操驱动"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.dc"
outlined
label="是否定操"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.fc"
outlined
label="是否反操"
:disable="true"
/>
</q-item-section>
</q-item>
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.yc"
outlined
label="是否允许操作"
:disable="true"
/>
</q-item-section>
</q-item>
</q-list>
<q-list dense bordered padding class="rounded-borders q-my-sm">
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.sb"
outlined
label="是否有失表故障"
:disable="true"
/>
</q-item-section>
</q-item>
<!-- <q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.dwsb"
outlined
label="是否有定位失表故障"
:disable="true"
/>
</q-item-section>
</q-item> -->
<!-- <q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.fwsb"
outlined
label="是否有反位失表故障"
:disable="true"
/>
</q-item-section>
</q-item> -->
<q-item>
<q-item-section>
<q-checkbox
dense
v-model="turnoutState.jc"
outlined
label="是否有挤岔故障"
:disable="true"
/>
<q-item-section side>
<q-item-label caption>{{
item.formatFn
? item.formatFn(turnoutState[item.key])
: turnoutState[item.key]
}}</q-item-label>
</q-item-section>
</q-item>
</q-list>
@ -206,95 +40,156 @@
<script setup lang="ts">
import { Turnout } from 'src/graphics/turnout/Turnout';
import { useLineStore } from 'src/stores/line-store';
import { ref, watch, onMounted, onUnmounted } from 'vue';
import { SetSwitchParams, setSwitchPosition } from 'src/api/Simulation';
import { useQuasar } from 'quasar';
import { ApiError } from 'src/boot/axios';
import { request } from 'src/protos/request';
import { ref, watch, onMounted, onUnmounted, toRaw } from 'vue';
import { Dialog } from 'quasar';
import { TurnoutStates } from 'src/drawApp/graphics/TurnoutInteraction';
import { JlGraphic } from 'jl-graphic';
import TurnoutOperation from 'src/components/draw-app/dialogs/TurnoutOperation.vue';
import { request } from 'src/protos/request';
const $q = useQuasar();
const lineStore = useLineStore();
const turnoutState = ref<TurnoutStates>(new TurnoutStates());
const name = ref('');
const graphic = ref();
const forcePosition = ref<request.Points.Force>(0);
const turnoutForceOption = [
{
label: '无强制',
value: request.Points.Force.FP_NONE,
},
{
label: '定位',
value: request.Points.Force.FP_DW,
},
{
label: '反位',
value: request.Points.Force.FP_FW,
},
{
label: '失表',
value: request.Points.Force.FP_SB,
},
];
const options = [{ label: '设置参数' }];
let copySelectGraphic: Turnout | null = null;
interface KeyType {
label: string;
key: keyof TurnoutStates;
formatFn?(v: TurnoutStates[keyof TurnoutStates]): string;
}
const list: KeyType[] = [
{ label: '道岔索引', key: 'code' },
{ label: '道岔名称', key: 'code', formatFn: getNameFormat },
{ label: '定位(表示)', key: 'normal', formatFn: getName },
{ label: '反位(表示)', key: 'reverse', formatFn: getName },
{ label: '定位(实际)', key: 'dw', formatFn: getName },
{ label: '反位(实际)', key: 'fw', formatFn: getName },
{ label: '联锁定操驱动', key: 'qdc', formatFn: getName },
{ label: '联锁反操驱动', key: 'qfc', formatFn: getName },
{ label: '联锁允许操驱动', key: 'qyc', formatFn: getName },
{ label: '是否定操采集', key: 'dc', formatFn: getName },
{ label: '是否反操采集', key: 'fc', formatFn: getName },
{ label: '是否允许操作采集', key: 'yc', formatFn: getName },
{ label: '道岔强制', key: 'param', formatFn: getForceName },
];
watch(
() => lineStore.selectedGraphics,
(val, oldVal) => {
if (oldVal?.length == 1 && oldVal[0].type == Turnout.Type) {
unSubscribeState(oldVal[0] as JlGraphic);
if (oldVal?.length == 1 && oldVal[0] instanceof Turnout) {
unSubscribeState(oldVal[0]);
}
if (val?.length == 1 && val[0].type == Turnout.Type) {
graphic.value = val[0];
setTurnoutState(val[0] as Turnout);
if (val?.length == 1 && val[0] instanceof Turnout) {
copySelectGraphic = toRaw(val[0]);
initTurnoutState(val[0] as Turnout);
} else {
turnoutState.value = new TurnoutStates();
name.value = '';
graphic.value = null;
copySelectGraphic = null;
}
}
);
function setTurnoutState(turnout: Turnout) {
graphic.value = turnout;
turnoutState.value = turnout.states.clone() as TurnoutStates;
name.value = turnout.datas.code;
subscribeState(turnout as JlGraphic);
}
onMounted(() => {
if (lineStore.selectedGraphics) {
setTurnoutState(lineStore.selectedGraphics[0] as Turnout);
}
});
onUnmounted(() => {
if (graphic.value) {
unSubscribeState(graphic.value as JlGraphic);
initTurnoutState(lineStore.selectedGraphics[0] as Turnout);
}
});
const options = [
{ label: '定操', value: request.Turnout.Operation.DC },
{ label: '取消定操', value: request.Turnout.Operation.CancelDC },
{ label: '反操', value: request.Turnout.Operation.FC },
{ label: '取消反操', value: request.Turnout.Operation.CancelFC },
{ label: '设置失表故障', value: request.Turnout.Operation.SetSB },
{ label: '取消失表故障', value: request.Turnout.Operation.CancelSB },
{ label: '设置挤岔故障', value: request.Turnout.Operation.SetJC },
{ label: '取消挤岔故障', value: request.Turnout.Operation.CancelJC },
{ label: '强制定位', value: request.Turnout.Operation.ForceDw },
{ label: '强制反位', value: request.Turnout.Operation.ForceFw },
{ label: '取消强制', value: request.Turnout.Operation.CancelForce },
];
function toDo(item: { label: string; value: number }) {
if (!lineStore.simulationId) return;
const obj: SetSwitchParams = {
simulationId: lineStore?.simulationId || '',
mapId: lineStore.mapId as number,
deviceId: turnoutState.value.id,
operation: item.value,
};
setSwitchPosition(obj).catch((err) => {
const error = err as ApiError;
$q.notify({
type: 'negative',
message: error.title,
});
});
function getNameFormat(v: number) {
if (v) {
return name.value;
}
return '';
}
function subscribeState(g: JlGraphic) {
function getName(v: boolean) {
if (v) return '是';
return '否';
}
function getForceName(param: request.Points.Force) {
return turnoutForceOption.find((item) => item.value == param)?.label || '';
}
function initTurnoutState(turnout: Turnout) {
copySelectGraphic = toRaw(turnout);
turnoutState.value = turnout.states.clone() as TurnoutStates;
forcePosition.value = turnoutState.value.param?.forcePosition;
name.value = turnout.datas.code;
subscribeState(turnout);
}
function updateState(newVal: TurnoutStates) {
turnoutState.value = newVal.clone() as TurnoutStates;
forcePosition.value = turnoutState.value.param?.forcePosition;
}
function doTurnoutOperation(item: { label: string }) {
if (!lineStore.simulationId) return;
if (item.label == '设置参数') {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '道岔设置参数',
message: '',
component: TurnoutOperation,
componentProps: {
id: turnoutState.value.id,
code: name.value,
force: forcePosition.value,
},
cancel: true,
persistent: true,
}).onCancel(() => {
lineStore.deviceOpreratDialogInstance = null;
});
}
}
function subscribeState(g: Turnout) {
if (g) {
g.on('stateupdate', updateState);
}
}
function unSubscribeState(g: JlGraphic) {
function unSubscribeState(g: Turnout) {
if (g) {
g.off('stateupdate', updateState);
}
}
function updateState(newVal: TurnoutStates) {
turnoutState.value = newVal.clone() as TurnoutStates;
}
onUnmounted(() => {
if (copySelectGraphic) {
unSubscribeState(copySelectGraphic);
}
});
</script>
<style scoped>
.border-box {
border: 1px solid #ccc;
border-radius: 3px;
margin-left: 0;
margin-top: 10px;
}
</style>

View File

@ -1,21 +1,22 @@
function getHost(): string {
if (process.env.ENV_MODE == 'test') {
return 'test.joylink.club/bjrtss-server';
return 'test.joylink.club/bjrtsts-server';
} else if (process.env.ENV_MODE == 'publish') {
return 'joylink.club/bjrtss-server';
return 'joylink.club/bjrtsts-server';
}
// return '192.168.3.7:9091';
// return '192.168.3.47:9091';
// return '192.168.3.37:9091';
// return '192.168.3.15:9091';
// return '192.168.3.5:9091';
// return '192.168.33.207:9091'; // 张骞
// return '192.168.33.93:9091';
// return '192.168.3.37:9091'; //卫志宏
return '192.168.3.233:9091';
// return 'test.joylink.club/bjrtsts-service'; // 测试
return '192.168.33.233:9091';
}
export function getHttpBase() {
let protocol = 'http';
if (['test', 'publish'].includes(process.env.ENV_MODE as string)) {
if (['publish'].includes(process.env.ENV_MODE as string)) {
protocol = 'https';
}
return `${protocol}://${getHost()}`;
@ -23,17 +24,18 @@ export function getHttpBase() {
export function getWebsocketUrl() {
let protocol = 'ws';
let host = '192.168.3.233';
let host = '192.168.33.233';
// let host = 'test.joylink.club';
let port = '8083';
let url = `${protocol}://${host}:${port}`;
if (process.env.ENV_MODE == 'test') {
protocol = 'wss';
host = 'test.joylink.club/bjrtss-server';
// protocol = 'wss';
host = 'test.joylink.club/bjrtsts-server';
port = '';
url = `${protocol}://${host}`;
} else if (process.env.ENV_MODE == 'publish') {
protocol = 'wss';
host = 'joylink.club/bjrtss-server';
host = 'joylink.club/bjrtsts-server';
port = '';
url = `${protocol}://${host}`;
}

View File

@ -39,9 +39,9 @@ function handleSubscribe(ibpScene: IGraphicScene) {
const ibpStore = useIbpStore();
const simulationId = lineStore.simulationId;
const mapId = lineStore.mapId;
const stationId = ibpStore.stationId;
const ibpId = ibpStore.ibpId;
ibpScene.subscribe({
destination: `/rtsts/simulation/${simulationId}/ibp/${mapId}/${stationId}`,
destination: `/rtsts/simulation/${simulationId}/ibp/${mapId}/${ibpId}`,
messageConverter: (message: Uint8Array) => {
const states: GraphicState[] = [];

View File

@ -19,6 +19,12 @@ import { TrainWindow } from 'src/graphics/trainWindow/TrainWindow';
import { Transponder } from 'src/graphics/transponder/Transponder';
import { Turnout } from 'src/graphics/turnout/Turnout';
import { ConcentrationDividingLine } from 'src/graphics/concentrationDividingLine/ConcentrationDividingLine';
import { IbpBox } from 'src/graphics/ibpBox/IbpBox';
import { PslBox } from 'src/graphics/pslBox/PslBox';
import { GarageDoor } from 'src/graphics/garageDoor/GarageDoor';
import { CarWashing } from 'src/graphics/carWashing/CarWashing';
import { FloodGate } from 'src/graphics/floodGate/FloodGate';
import { GarageDoorBox } from 'src/graphics/garageDoorBox/GarageDoorBox';
export const drawCommonLayerList = [
// 图层列表 默认显示的图层defaultShow: true
@ -33,6 +39,8 @@ export const drawCommonLayerList = [
{ label: '停车位置标', value: StopPosition.Type, defaultShow: true },
{ label: 'Spks开关', value: SpksSwitch.Type, defaultShow: true },
{ label: '门控箱', value: GatedBox.Type, defaultShow: true },
{ label: 'Ibp盘', value: IbpBox.Type, defaultShow: true },
{ label: 'Psl盘', value: PslBox.Type, defaultShow: true },
{ label: '紧急关闭按钮', value: EsbButton.Type, defaultShow: true },
{ label: '应答器', value: Transponder.Type, defaultShow: true },
{ label: '车次窗', value: TrainWindow.Type, defaultShow: true },
@ -51,4 +59,8 @@ export const drawCommonLayerList = [
value: ConcentrationDividingLine.Type,
defaultShow: true,
},
{ label: '车库门', value: GarageDoor.Type, defaultShow: true },
{ label: '防淹门', value: FloodGate.Type, defaultShow: true },
{ label: '洗车机', value: CarWashing.Type, defaultShow: true },
{ label: '车库门设置', value: GarageDoorBox.Type, defaultShow: true },
];

View File

@ -1,7 +1,16 @@
import { TrainTemplate } from 'src/graphics/train/Train';
import { TrainDraw } from 'src/graphics/train/TrainDrawAssistant';
import { Signal, SignalTemplate } from 'src/graphics/signal/Signal';
import { GraphicData, IDrawApp, ContextMenu, MenuItemOptions } from 'jl-graphic';
import {
GraphicData,
IDrawApp,
ContextMenu,
MenuItemOptions,
KeyListener,
calculateDistanceFromPointToLine,
getRectangleCenter,
distance2,
} from 'jl-graphic';
import { TrainState } from './graphics/TrainInteraction';
import {
SignalData,
@ -21,6 +30,12 @@ import { PolygonDraw } from 'src/graphics/polygon/PolygonDrawAssistant';
import { Platform, PlatformTemplate } from 'src/graphics/platform/Platform';
import { PlatformData, PlatformState } from './graphics/PlatformInteraction';
import { PlatformDraw } from 'src/graphics/platform/PlatformDrawAssistant';
import { IbpBox, IbpBoxTemplate } from 'src/graphics/ibpBox/IbpBox';
import { IbpBoxData } from './graphics/IbpBoxInteraction';
import { IbpBoxDraw } from 'src/graphics/ibpBox/IbpBoxDrawAssistant';
import { PslBox, PslBoxTemplate } from 'src/graphics/pslBox/PslBox';
import { PslBoxData } from './graphics/PslBoxInteraction';
import { PslBoxDraw } from 'src/graphics/pslBox/PslBoxDrawAssistant';
import {
ScreenDoor,
ScreenDoorTemplate,
@ -81,6 +96,15 @@ import {
GatedBoxData,
DrawGatedBoxInteraction,
} from './graphics/GatedBoxInteraction';
import {
GarageDoorBox,
GarageDoorBoxTemplate,
} from 'src/graphics/garageDoorBox/GarageDoorBox';
import {
GarageDoorBoxData,
DrawGarageDoorBoxInteraction,
} from './graphics/GarageDoorBoxInteraction';
import { GarageDoorBoxDraw } from 'src/graphics/garageDoorBox/GarageDoorBoxAssistant';
// import { EsbButton, EsbButtonTemplate } from 'src/graphics/esbButton/EsbButton';
// import {
// EsbButtonData,
@ -95,7 +119,10 @@ import {
Transponder,
TransponderTemplate,
} from 'src/graphics/transponder/Transponder';
import { TransponderData } from './graphics/TransponderInteraction';
import {
TransponderData,
TransponderState,
} from './graphics/TransponderInteraction';
import { SlopeKiloMarkerDrawAssistant } from 'src/graphics/slopeKiloMarker/SlopeKiloMarkerDrawAssistant';
import {
SlopeKiloMarker,
@ -124,6 +151,21 @@ import { Dialog } from 'quasar';
import { useDrawStore } from 'src/stores/draw-store';
import { saveDraft } from 'src/api/DraftApi';
import { SignalDraw } from 'src/graphics/signal/SignalDrawAssistant';
import { CarWashingData } from './graphics/CarWashingInteraction';
import {
CarWashing,
CarWashingTemplate,
} from 'src/graphics/carWashing/CarWashing';
import { CarWashingDraw } from 'src/graphics/carWashing/CarWashingDrawAssistant';
import { FloodGateData } from './graphics/FloodGateInteraction';
import { FloodGate, FloodGateTemplate } from 'src/graphics/floodGate/FloodGate';
import { FloodGateDraw } from 'src/graphics/floodGate/FloodGateDrawAssistant';
import { GarageDoorData } from './graphics/GarageDoorInteraction';
import {
GarageDoor,
GarageDoorTemplate,
} from 'src/graphics/garageDoor/GarageDoor';
import { GarageDoorDraw } from 'src/graphics/garageDoor/GarageDoorDrawAssistant';
const UndoOptions: MenuItemOptions = {
name: '撤销',
@ -158,6 +200,8 @@ export function initCommonDrawApp(app: IDrawApp) {
app,
new PlatformTemplate(new PlatformData(), new PlatformState())
);
new IbpBoxDraw(app, new IbpBoxTemplate(new IbpBoxData()));
new PslBoxDraw(app, new PslBoxTemplate(new PslBoxData()));
new ScreenDoorDraw(
app,
new ScreenDoorTemplate(new ScreenDoorData(), new ScreenDoorState())
@ -181,10 +225,17 @@ export function initCommonDrawApp(app: IDrawApp) {
new OneClickGenerateDraw(app, new OneClickGenerateTemplate());
new AxleCountingDraw(app, new AxleCountingTemplate(new AxleCountingData()));
new SeparatorDraw(app, new SeparatorTemplate(new SeparatorData()));
new TransponderDraw(app, new TransponderTemplate(new TransponderData()));
new TransponderDraw(
app,
new TransponderTemplate(new TransponderData(), new TransponderState())
);
new StopPositionDraw(app, new StopPositionTemplate(new StopPositionData()));
new SpksSwitchDraw(app, new SpksSwitchTemplate(new SpksSwitchData()));
new GatedBoxDraw(app, new GatedBoxTemplate(new GatedBoxData()));
new GarageDoorBoxDraw(
app,
new GarageDoorBoxTemplate(new GarageDoorBoxData())
);
// new EsbButtonDraw(
// app,
// new EsbButtonTemplate(new EsbButtonData(), new EsbButtonState())
@ -205,10 +256,14 @@ export function initCommonDrawApp(app: IDrawApp) {
app,
new ConcentrationDividingLineTemplate(new ConcentrationDividingLineData())
);
new CarWashingDraw(app, new CarWashingTemplate(new CarWashingData()));
new FloodGateDraw(app, new FloodGateTemplate(new FloodGateData()));
new GarageDoorDraw(app, new GarageDoorTemplate(new GarageDoorData()));
DrawSignalInteraction.init(app);
DrawStopPositionInteraction.init(app);
DrawSpksSwitchInteraction.init(app);
DrawGatedBoxInteraction.init(app);
DrawGarageDoorBoxInteraction.init(app);
// DrawEsbButtonInteraction.init(app);
// 画布右键菜单
@ -241,6 +296,99 @@ export function initCommonDrawApp(app: IDrawApp) {
sectionCodePointList = [];
otherLineList = [];
});
// KeyA 用于区段复制--控制生成的区段位置
const graphicCopyPlugin = app.app.graphicCopyPlugin;
const copySectionListener = new KeyListener({
value: 'KeyA',
global: true,
onPress: () => {
graphicCopyPlugin.updateMoveLimit('sectionPointLimit');
},
});
graphicCopyPlugin.addGraphicControlers([
{
controlerList: [copySectionListener],
check: () => {
if (
graphicCopyPlugin.copys.length == 1 &&
graphicCopyPlugin.copys[0].type == Section.Type
)
return true;
return false;
},
moveLimitOption: {
moveLimitName: 'sectionPointLimit',
moveLimit: (e) => {
const mousePos = app.toCanvasCoordinates(e.global);
const selectSection = app.selectedGraphics[0] as Section;
let selectSectionLeft = selectSection.localToCanvasPoint(
selectSection.getStartPoint()
);
let selectSectionRight = selectSection.localToCanvasPoint(
selectSection.getEndPoint()
);
[selectSectionLeft, selectSectionRight] =
selectSectionLeft.x < selectSectionRight.x
? [selectSectionLeft, selectSectionRight]
: [selectSectionRight, selectSectionLeft];
//要移动到目标位的区段
const sections = app.queryStore.queryByType<Section>(Section.Type);
const minDistanceSection = sections.reduce((prev, cur) => {
const prevDistance = calculateDistanceFromPointToLine(
prev.localToCanvasPoint(prev.getStartPoint()),
prev.localToCanvasPoint(prev.getEndPoint()),
mousePos
);
const curDistance = calculateDistanceFromPointToLine(
cur.localToCanvasPoint(cur.getStartPoint()),
cur.localToCanvasPoint(cur.getEndPoint()),
mousePos
);
return prevDistance > curDistance ||
(prevDistance == curDistance &&
distance2(
prev.localToCanvasPoint(prev.getStartPoint()),
mousePos
) >
distance2(
cur.localToCanvasPoint(cur.getStartPoint()),
mousePos
))
? cur
: prev;
});
const minDistanceRefSectionsPos =
minDistanceSection.localToCanvasPoint(
getRectangleCenter(
minDistanceSection.lineGraphic.getLocalBounds()
)
);
let minDistanceSectionLeft = minDistanceSection.localToCanvasPoint(
minDistanceSection.getStartPoint()
);
let minDistanceSectionRight = minDistanceSection.localToCanvasPoint(
minDistanceSection.getEndPoint()
);
[minDistanceSectionLeft, minDistanceSectionRight] =
minDistanceSectionLeft.x < minDistanceSectionRight.x
? [minDistanceSectionLeft, minDistanceSectionRight]
: [minDistanceSectionRight, minDistanceSectionLeft];
if (mousePos.x > minDistanceRefSectionsPos.x) {
graphicCopyPlugin.container.position.x =
minDistanceSectionRight.x - selectSectionLeft.x;
graphicCopyPlugin.container.position.y =
minDistanceSectionRight.y - selectSectionLeft.y;
} else {
graphicCopyPlugin.container.position.x =
minDistanceSectionLeft.x - selectSectionRight.x;
graphicCopyPlugin.container.position.y =
minDistanceSectionLeft.y - selectSectionRight.y;
}
},
},
},
]);
}
export function loadCommonDrawDatas(
@ -258,6 +406,12 @@ export function loadCommonDrawDatas(
storage.Platforms.forEach((platform) => {
datas.push(new PlatformData(platform));
});
storage.ibpBoxs.forEach((ibpBox) => {
datas.push(new IbpBoxData(ibpBox));
});
storage.pslBoxs.forEach((pslBox) => {
datas.push(new PslBoxData(pslBox));
});
storage.screenDoors.forEach((screenDoor) => {
datas.push(new ScreenDoorData(screenDoor));
});
@ -291,6 +445,9 @@ export function loadCommonDrawDatas(
storage.gateBoxs.forEach((gatedBox) => {
datas.push(new GatedBoxData(gatedBox));
});
storage.garageDoorBoxes.forEach((garageDoorBox) => {
datas.push(new GarageDoorBoxData(garageDoorBox));
});
// storage.esbButtons.forEach((esbButton) => {
// datas.push(new EsbButtonData(esbButton));
// });
@ -315,6 +472,15 @@ export function loadCommonDrawDatas(
storage.concentrationDividingLines.forEach((concentrationDividingLine) => {
datas.push(new ConcentrationDividingLineData(concentrationDividingLine));
});
storage.floodGates.forEach((flood) => {
datas.push(new FloodGateData(flood));
});
storage.carWashings.forEach((carWashing) => {
datas.push(new CarWashingData(carWashing));
});
storage.garageDoors.forEach((garageDoor) => {
datas.push(new GarageDoorData(garageDoor));
});
return datas;
}
@ -322,7 +488,9 @@ export function saveCommonDrawDatas(app: IDrawApp) {
const storage = new graphicData.RtssGraphicStorage();
const canvasData = app.canvas.saveData();
storage.canvas = new graphicData.Canvas({
...canvasData,
width: canvasData.width,
height: canvasData.height,
backgroundColor: canvasData.backgroundColor,
viewportTransform: toStorageTransform(canvasData.viewportTransform),
});
const graphics = app.queryStore.getAllGraphics();
@ -330,6 +498,12 @@ export function saveCommonDrawDatas(app: IDrawApp) {
if (Platform.Type === g.type) {
const platformData = (g as Platform).saveData();
storage.Platforms.push((platformData as PlatformData).data);
} else if (IbpBox.Type === g.type) {
const ibpBoxData = (g as IbpBox).saveData();
storage.ibpBoxs.push((ibpBoxData as IbpBoxData).data);
} else if (PslBox.Type === g.type) {
const pslBoxData = (g as PslBox).saveData();
storage.pslBoxs.push((pslBoxData as PslBoxData).data);
} else if (Station.Type === g.type) {
const stationData = (g as Station).saveData();
storage.stations.push((stationData as StationData).data);
@ -366,6 +540,11 @@ export function saveCommonDrawDatas(app: IDrawApp) {
// } else if (EsbButton.Type === g.type) {
// const esbButtonData = (g as EsbButton).saveData();
// storage.esbButtons.push((esbButtonData as EsbButtonData).data);
} else if (GarageDoorBox.Type === g.type) {
const garageDoorBoxData = (g as GarageDoorBox).saveData();
storage.garageDoorBoxes.push(
(garageDoorBoxData as GarageDoorBoxData).data
);
} else if (Transponder.Type === g.type) {
const transponderData = (g as Transponder).saveData();
storage.transponders.push((transponderData as TransponderData).data);
@ -393,6 +572,15 @@ export function saveCommonDrawDatas(app: IDrawApp) {
storage.concentrationDividingLines.push(
(concentrationDividingLineData as ConcentrationDividingLineData).data
);
} else if (g instanceof CarWashing) {
const carWashingData = g.saveData();
storage.carWashings.push((carWashingData as CarWashingData).data);
} else if (g instanceof FloodGate) {
const floodGateData = g.saveData();
storage.floodGates.push((floodGateData as FloodGateData).data);
} else if (g instanceof GarageDoor) {
const garageDoorData = g.saveData();
storage.garageDoors.push((garageDoorData as GarageDoorData).data);
}
});
// storage.Platforms.forEach((item) => {

View File

@ -0,0 +1,88 @@
import * as pb_1 from 'google-protobuf';
import { FederatedMouseEvent } from 'pixi.js';
import {
CarWashing,
ICarWashingData,
} from 'src/graphics/carWashing/CarWashing';
import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
export class CarWashingData extends GraphicDataBase implements ICarWashingData {
constructor(data?: graphicData.CarWashing) {
let carWashing;
if (!data) {
carWashing = new graphicData.CarWashing({
common: GraphicDataBase.defaultCommonInfo(CarWashing.Type),
});
} else {
carWashing = data;
}
super(carWashing);
}
public get data(): graphicData.CarWashing {
return this.getData<graphicData.CarWashing>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get linkSection(): number {
return this.data.linkSection;
}
set linkSection(v: number) {
this.data.linkSection = v;
}
get centralizedStations(): number[] {
return this.data.centralizedStations;
}
set centralizedStations(v: number[]) {
this.data.centralizedStations = v;
}
clone(): CarWashingData {
return new CarWashingData(this.data.cloneMessage());
}
copyFrom(data: CarWashingData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: CarWashingData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class CarWashingOperationInteraction extends GraphicInteractionPlugin<CarWashing> {
static Name = 'car_washing_operation';
constructor(scene: IGraphicScene) {
super(CarWashingOperationInteraction.Name, scene);
}
static init(scene: IGraphicScene) {
return new CarWashingOperationInteraction(scene);
}
filter(...grahpics: JlGraphic[]): CarWashing[] | undefined {
return grahpics.filter((g): g is CarWashing => g.type === CarWashing.Type);
}
bind(g: CarWashing): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.on('mousedown', this.onPress, this);
}
unbind(g: CarWashing): void {
g.eventMode = 'none';
g.cursor = 'default';
g.off('mousedown', this.onPress, this);
}
onPress(e: FederatedMouseEvent) {
const g = e.target as CarWashing;
g.on('mouseleave', this.onRelease, this);
g.on('mouseup', this.onRelease, this);
}
onRelease(e: FederatedMouseEvent) {
const g = e.target as CarWashing;
g.off('mouseleave', this.onRelease, this);
g.off('mouseup', this.onRelease, this);
}
}

View File

@ -66,7 +66,8 @@ export class EsbButtonData extends GraphicDataBase implements IEsbButtonData {
export class EsbButtonState
extends GraphicStateBase
implements IEsbButtonState {
implements IEsbButtonState
{
constructor(data?: state.ButtonState) {
let ibpButtonState;
if (data) {

View File

@ -0,0 +1,85 @@
import * as pb_1 from 'google-protobuf';
import { FederatedMouseEvent } from 'pixi.js';
import { FloodGate, IFloodGateData } from 'src/graphics/floodGate/FloodGate';
import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
export class FloodGateData extends GraphicDataBase implements IFloodGateData {
constructor(data?: graphicData.FloodGate) {
let floodGate;
if (!data) {
floodGate = new graphicData.FloodGate({
common: GraphicDataBase.defaultCommonInfo(FloodGate.Type),
});
} else {
floodGate = data;
}
super(floodGate);
}
public get data(): graphicData.FloodGate {
return this.getData<graphicData.FloodGate>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get linkSection(): number {
return this.data.linkSection;
}
set linkSection(v: number) {
this.data.linkSection = v;
}
get centralizedStations(): number[] {
return this.data.centralizedStations;
}
set centralizedStations(v: number[]) {
this.data.centralizedStations = v;
}
clone(): FloodGateData {
return new FloodGateData(this.data.cloneMessage());
}
copyFrom(data: FloodGateData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: FloodGateData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class FloodGateOperationInteraction extends GraphicInteractionPlugin<FloodGate> {
static Name = 'flood_gate_operation';
constructor(scene: IGraphicScene) {
super(FloodGateOperationInteraction.Name, scene);
}
static init(scene: IGraphicScene) {
return new FloodGateOperationInteraction(scene);
}
filter(...grahpics: JlGraphic[]): FloodGate[] | undefined {
return grahpics.filter((g): g is FloodGate => g.type === FloodGate.Type);
}
bind(g: FloodGate): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.on('mousedown', this.onPress, this);
}
unbind(g: FloodGate): void {
g.eventMode = 'none';
g.cursor = 'default';
g.off('mousedown', this.onPress, this);
}
onPress(e: FederatedMouseEvent) {
const g = e.target as FloodGate;
g.on('mouseleave', this.onRelease, this);
g.on('mouseup', this.onRelease, this);
}
onRelease(e: FederatedMouseEvent) {
const g = e.target as FloodGate;
g.off('mouseleave', this.onRelease, this);
g.off('mouseup', this.onRelease, this);
}
}

View File

@ -0,0 +1,150 @@
import * as pb_1 from 'google-protobuf';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import {
GarageDoorBox,
IGarageDoorBox,
} from 'src/graphics/garageDoorBox/GarageDoorBox';
import {
IGraphicApp,
GraphicInteractionPlugin,
JlGraphic,
IGraphicScene,
MenuItemOptions,
ContextMenu,
} from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { usePslStore } from 'src/stores/psl-store';
export class GarageDoorBoxData
extends GraphicDataBase
implements IGarageDoorBox
{
constructor(data?: graphicData.GarageDoorBox) {
let garageDoorBox;
if (!data) {
garageDoorBox = new graphicData.GarageDoorBox({
common: GraphicDataBase.defaultCommonInfo(GarageDoorBox.Type),
});
} else {
garageDoorBox = data;
}
super(garageDoorBox);
}
public get data(): graphicData.GarageDoorBox {
return this.getData<graphicData.GarageDoorBox>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get flip(): boolean {
return this.data.flip;
}
set flip(v: boolean) {
this.data.flip = v;
}
get refGarageDoorId(): number {
return this.data.refGarageDoorId;
}
set refGarageDoorId(v: number) {
this.data.refGarageDoorId = v;
}
get refPslMapCode(): string {
return this.data.refPslMapCode;
}
set refPslMapCode(v: string) {
this.data.refPslMapCode = v;
}
clone(): GarageDoorBoxData {
return new GarageDoorBoxData(this.data.cloneMessage());
}
copyFrom(data: GarageDoorBoxData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: GarageDoorBoxData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
const flipConfig: MenuItemOptions = {
name: '上下翻转',
};
const GarageDoorBoxEditMenu: ContextMenu = ContextMenu.init({
name: '设置车库门编辑菜单',
groups: [
{
items: [flipConfig],
},
],
});
export class DrawGarageDoorBoxInteraction extends GraphicInteractionPlugin<GarageDoorBox> {
static Name = 'garage_door_box_draw_right_menu';
constructor(app: IGraphicApp) {
super(DrawGarageDoorBoxInteraction.Name, app);
app.registerMenu(GarageDoorBoxEditMenu);
}
static init(app: IGraphicApp) {
return new DrawGarageDoorBoxInteraction(app);
}
filter(...grahpics: JlGraphic[]): GarageDoorBox[] | undefined {
return grahpics
.filter((g) => g.type === GarageDoorBox.Type)
.map((g) => g as GarageDoorBox);
}
bind(g: GarageDoorBox): void {
g.on('_rightclick', this.onContextMenu, this);
}
unbind(g: GarageDoorBox): void {
g.off('_rightclick', this.onContextMenu, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const garageDoorBox = target.getGraphic() as GarageDoorBox;
this.app.updateSelected(garageDoorBox);
flipConfig.handler = () => {
garageDoorBox.datas.flip = !garageDoorBox.datas.flip;
garageDoorBox.repaint();
};
GarageDoorBoxEditMenu.open(e.global);
}
}
export class GarageDoorBoxOperateInteraction extends GraphicInteractionPlugin<GarageDoorBox> {
static Name = 'garage_door_box_operate_menu';
constructor(app: IGraphicScene) {
super(GarageDoorBoxOperateInteraction.Name, app);
}
static init(app: IGraphicScene) {
return new GarageDoorBoxOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): GarageDoorBox[] | undefined {
return grahpics
.filter((g) => g.type === GarageDoorBox.Type)
.map((g) => g as GarageDoorBox);
}
bind(g: GarageDoorBox): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.on('_leftclick', this.onLeftClick, this);
}
unbind(g: GarageDoorBox): void {
g.eventMode = 'none';
g.off('_leftclick', this.onLeftClick, this);
}
onLeftClick(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const garageDoorBox = target.getGraphic() as GarageDoorBox;
usePslStore().setPslParam(
garageDoorBox.datas.id,
garageDoorBox.datas.refPslMapCode
);
}
}

View File

@ -0,0 +1,88 @@
import * as pb_1 from 'google-protobuf';
import { FederatedMouseEvent } from 'pixi.js';
import {
GarageDoor,
IGarageDoorData,
} from 'src/graphics/garageDoor/GarageDoor';
import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
export class GarageDoorData extends GraphicDataBase implements IGarageDoorData {
constructor(data?: graphicData.GarageDoor) {
let garageDoor;
if (!data) {
garageDoor = new graphicData.GarageDoor({
common: GraphicDataBase.defaultCommonInfo(GarageDoor.Type),
});
} else {
garageDoor = data;
}
super(garageDoor);
}
public get data(): graphicData.GarageDoor {
return this.getData<graphicData.GarageDoor>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get linkSection(): number {
return this.data.linkSection;
}
set linkSection(v: number) {
this.data.linkSection = v;
}
get centralizedStations(): number[] {
return this.data.centralizedStations;
}
set centralizedStations(v: number[]) {
this.data.centralizedStations = v;
}
clone(): GarageDoorData {
return new GarageDoorData(this.data.cloneMessage());
}
copyFrom(data: GarageDoorData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: GarageDoorData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class GarageDoorOperationInteraction extends GraphicInteractionPlugin<GarageDoor> {
static Name = 'garage_door_operation';
constructor(scene: IGraphicScene) {
super(GarageDoorOperationInteraction.Name, scene);
}
static init(scene: IGraphicScene) {
return new GarageDoorOperationInteraction(scene);
}
filter(...grahpics: JlGraphic[]): GarageDoor[] | undefined {
return grahpics.filter((g): g is GarageDoor => g.type === GarageDoor.Type);
}
bind(g: GarageDoor): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.on('mousedown', this.onPress, this);
}
unbind(g: GarageDoor): void {
g.eventMode = 'none';
g.cursor = 'default';
g.off('mousedown', this.onPress, this);
}
onPress(e: FederatedMouseEvent) {
const g = e.target as GarageDoor;
g.on('mouseleave', this.onRelease, this);
g.on('mouseup', this.onRelease, this);
}
onRelease(e: FederatedMouseEvent) {
const g = e.target as GarageDoor;
g.off('mouseleave', this.onRelease, this);
g.off('mouseup', this.onRelease, this);
}
}

View File

@ -6,11 +6,7 @@ import {
IIbpButtonState,
} from 'src/graphics/IBPButton/IBPButton';
import { ibpGraphicData } from 'src/protos/ibpGraphics';
import {
GraphicInteractionPlugin,
IGraphicScene,
JlGraphic,
} from 'jl-graphic';
import { GraphicInteractionPlugin, IGraphicScene, JlGraphic } from 'jl-graphic';
import { FederatedMouseEvent } from 'pixi.js';
import { state } from 'src/protos/device_state';
import { useIbpStore } from 'src/stores/ibp-store';
@ -67,7 +63,8 @@ export class IBPButtonData extends GraphicDataBase implements IIBPButtonData {
export class IbpButtonState
extends GraphicStateBase
implements IIbpButtonState {
implements IIbpButtonState
{
constructor(data?: state.ButtonState) {
let ibpButtonState;
if (data) {
@ -109,6 +106,7 @@ export class IbpButtonState
// IbpScene使用
export class IbpButtonInteraction extends GraphicInteractionPlugin<IBPButton> {
static Name = 'ibp_button_operate_menu';
isMouseDown = false;
constructor(app: IGraphicScene) {
super(IbpButtonInteraction.Name, app);
}
@ -132,6 +130,7 @@ export class IbpButtonInteraction extends GraphicInteractionPlugin<IBPButton> {
g.off('mouseleave', this.onMouseLeave);
}
onMouseDown(e: FederatedMouseEvent) {
this.isMouseDown = true;
const g = e.target as IBPButton;
const changeState = useIbpStore().ibpButtonOperation;
if (g.datas.isSelfReset) {
@ -141,6 +140,7 @@ export class IbpButtonInteraction extends GraphicInteractionPlugin<IBPButton> {
}
}
onMouseUp(e: FederatedMouseEvent) {
this.isMouseDown = false;
const changeState = useIbpStore().ibpButtonOperation;
const g = e.target as IBPButton;
if (g.datas.isSelfReset) {
@ -148,10 +148,13 @@ export class IbpButtonInteraction extends GraphicInteractionPlugin<IBPButton> {
}
}
onMouseLeave(e: FederatedMouseEvent) {
const changeState = useIbpStore().ibpButtonOperation;
const g = e.target as IBPButton;
if (g.datas.isSelfReset) {
changeState(g.datas.id, false);
if (this.isMouseDown) {
const changeState = useIbpStore().ibpButtonOperation;
const g = e.target as IBPButton;
if (g.datas.isSelfReset) {
changeState(g.datas.id, false);
}
this.isMouseDown = false;
}
}
}

View File

@ -0,0 +1,88 @@
import * as pb_1 from 'google-protobuf';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { IbpBox, IIbpBox } from 'src/graphics/ibpBox/IbpBox';
import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { Station } from 'src/graphics/station/Station';
import { useIbpStore } from 'src/stores/ibp-store';
export class IbpBoxData extends GraphicDataBase implements IIbpBox {
constructor(data?: graphicData.IbpBox) {
let ibpBox;
if (!data) {
ibpBox = new graphicData.IbpBox({
common: GraphicDataBase.defaultCommonInfo(IbpBox.Type),
});
} else {
ibpBox = data;
}
super(ibpBox);
}
public get data(): graphicData.IbpBox {
return this.getData<graphicData.IbpBox>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get refStationId(): number {
return this.data.refStationId;
}
set refStationId(v: number) {
this.data.refStationId = v;
}
get refIbpMapCode(): string {
return this.data.refIbpMapCode;
}
set refIbpMapCode(v: string) {
this.data.refIbpMapCode = v;
}
clone(): IbpBoxData {
return new IbpBoxData(this.data.cloneMessage());
}
copyFrom(data: IbpBoxData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: IbpBoxData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class IbpBoxOperateInteraction extends GraphicInteractionPlugin<IbpBox> {
static Name = 'Ibp_box_operate_menu';
constructor(app: IGraphicScene) {
super(IbpBoxOperateInteraction.Name, app);
}
static init(app: IGraphicScene) {
return new IbpBoxOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): IbpBox[] | undefined {
return grahpics
.filter((g) => g.type === IbpBox.Type)
.map((g) => g as IbpBox);
}
bind(g: IbpBox): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.on('_leftclick', this.onLeftClick, this);
}
unbind(g: IbpBox): void {
g.eventMode = 'none';
g.off('_leftclick', this.onLeftClick, this);
}
onLeftClick(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const ibpBox = target.getGraphic() as IbpBox;
const station = this.app.queryStore.queryById<Station>(
ibpBox.datas.refStationId
);
useIbpStore().openIbpScene(station, ibpBox.datas.refIbpMapCode, ibpBox.id);
}
}

View File

@ -3,11 +3,7 @@ import { IIbpKeyData, IIbpKeyState, IbpKey } from 'src/graphics/ibpKey/IbpKey';
import { ibpGraphicData } from 'src/protos/ibpGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_state';
import {
GraphicInteractionPlugin,
IGraphicScene,
JlGraphic,
} from 'jl-graphic';
import { GraphicInteractionPlugin, IGraphicScene, JlGraphic } from 'jl-graphic';
import { type FederatedMouseEvent } from 'pixi.js';
import { useIbpStore } from 'src/stores/ibp-store';

View File

@ -0,0 +1,83 @@
import * as pb_1 from 'google-protobuf';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { PslBox, IPslBox } from 'src/graphics/pslBox/PslBox';
import { GraphicInteractionPlugin, JlGraphic, IGraphicScene } from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { usePslStore } from 'src/stores/psl-store';
export class PslBoxData extends GraphicDataBase implements IPslBox {
constructor(data?: graphicData.PslBox) {
let pslBox;
if (!data) {
pslBox = new graphicData.PslBox({
common: GraphicDataBase.defaultCommonInfo(PslBox.Type),
});
} else {
pslBox = data;
}
super(pslBox);
}
public get data(): graphicData.PslBox {
return this.getData<graphicData.PslBox>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get refPlatformId(): number {
return this.data.refPlatformId;
}
set refPlatformId(v: number) {
this.data.refPlatformId = v;
}
get refPslMapCode(): string {
return this.data.refPslMapCode;
}
set refPslMapCode(v: string) {
this.data.refPslMapCode = v;
}
clone(): PslBoxData {
return new PslBoxData(this.data.cloneMessage());
}
copyFrom(data: PslBoxData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: PslBoxData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class PslBoxOperateInteraction extends GraphicInteractionPlugin<PslBox> {
static Name = 'Psl_box_operate_menu';
constructor(app: IGraphicScene) {
super(PslBoxOperateInteraction.Name, app);
}
static init(app: IGraphicScene) {
return new PslBoxOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): PslBox[] | undefined {
return grahpics
.filter((g) => g.type === PslBox.Type)
.map((g) => g as PslBox);
}
bind(g: PslBox): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.on('_leftclick', this.onLeftClick, this);
}
unbind(g: PslBox): void {
g.eventMode = 'none';
g.off('_leftclick', this.onLeftClick, this);
}
onLeftClick(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const pslBox = target.getGraphic() as PslBox;
usePslStore().setPslParam(pslBox.datas.id, pslBox.datas.refPslMapCode);
}
}

View File

@ -4,11 +4,7 @@ import {
IPslButtonState,
PslButton,
} from 'src/graphics/pslButton/pslButton';
import {
GraphicInteractionPlugin,
IGraphicScene,
JlGraphic,
} from 'jl-graphic';
import { GraphicInteractionPlugin, IGraphicScene, JlGraphic } from 'jl-graphic';
import { pslGraphicData } from 'src/protos/pslGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { pslOperate } from 'src/api/Simulation';
@ -65,7 +61,8 @@ export class PslButtonData extends GraphicDataBase implements IPslButtonData {
}
export class PslButtonState
extends GraphicStateBase
implements IPslButtonState {
implements IPslButtonState
{
constructor(proto?: state.ButtonState) {
let states;
if (proto) {
@ -136,7 +133,7 @@ export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslBut
onMouseDown(e: FederatedMouseEvent) {
const simulationId = useLineStore().simulationId;
const mapId = useLineStore().mapId;
const gateBoxId = usePslStore().gatedBoxId;
const pslId = usePslStore().pslId;
const target = e.target as DisplayObject;
const pslButton = target.getGraphic() as PslButton;
if (!simulationId || !mapId) {
@ -146,7 +143,7 @@ export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslBut
simulationId,
mapId,
buttonCode: pslButton.datas.code,
gateBoxId: gateBoxId,
pslId: pslId,
down: !pslButton.states.down,
})
.then(() => {
@ -160,7 +157,7 @@ export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslBut
onMouseUp(e: FederatedMouseEvent) {
const simulationId = useLineStore().simulationId;
const mapId = useLineStore().mapId;
const gateBoxId = usePslStore().gatedBoxId;
const pslId = usePslStore().pslId;
const target = e.target as DisplayObject;
const pslButton = target.getGraphic() as PslButton;
if (!simulationId || !mapId || !pslButton.datas.isSelfReset) {
@ -170,7 +167,7 @@ export class PslButtonOperateInteraction extends GraphicInteractionPlugin<PslBut
simulationId,
mapId,
buttonCode: pslButton.datas.code,
gateBoxId: gateBoxId,
pslId: pslId,
down: false,
})
.then(() => {

View File

@ -9,11 +9,17 @@ import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_state';
import { useLineStore } from 'src/stores/line-store';
import {
ContextMenu,
GraphicInteractionPlugin,
IGraphicScene,
JlGraphic,
MenuItemOptions,
} from 'jl-graphic';
import { loadScreenDoorConfig } from '../commonApp';
import { Dialog } from 'quasar';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import ScreenDoorOperation from 'src/components/draw-app/dialogs/ScreenDoorOperation.vue';
import { request } from 'src/protos/request';
export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
constructor(data?: graphicData.ScreenDoor) {
@ -60,7 +66,8 @@ export class ScreenDoorData extends GraphicDataBase implements IScreenDoorData {
export class ScreenDoorState
extends GraphicStateBase
implements IScreenDoorState {
implements IScreenDoorState
{
constructor(proto?: state.PsdState) {
let states;
if (proto) {
@ -73,6 +80,12 @@ export class ScreenDoorState
get code(): string {
return this.states.id + '';
}
get id(): number {
return this.states.id;
}
set id(id: number) {
this.states.id = id;
}
get asdStates(): state.AsdState[] {
return this.states.asdStates;
}
@ -85,6 +98,18 @@ export class ScreenDoorState
set mgj(v: boolean) {
this.states.mgj = v;
}
get zaw() {
return this.states.zaw;
}
set zaw(v: boolean) {
this.states.zaw = v;
}
get param(): request.PsdParam {
return this.states.param;
}
set param(param: request.PsdParam) {
this.states.param = param;
}
get states(): state.PsdState {
return this.getState<state.PsdState>();
}
@ -99,11 +124,21 @@ export class ScreenDoorState
}
}
const setSceenDoorParam: MenuItemOptions = { name: '设置参数' };
const sceenDoorOperateMenu: ContextMenu = ContextMenu.init({
name: '屏蔽门操作菜单',
groups: [
{
items: [setSceenDoorParam],
},
],
});
export class ScreenDoorOperateInteraction extends GraphicInteractionPlugin<ScreenDoor> {
static Name = 'screen_door_operate_menu';
constructor(app: IGraphicScene) {
super(ScreenDoorOperateInteraction.Name, app);
// app.registerMenu();
app.registerMenu(sceenDoorOperateMenu);
}
static init(app: IGraphicScene) {
return new ScreenDoorOperateInteraction(app);
@ -118,14 +153,40 @@ export class ScreenDoorOperateInteraction extends GraphicInteractionPlugin<Scree
g.cursor = 'pointer';
g.selectable = true;
g.on('_leftclick', this.onLeftClick, this);
g.on('rightclick', this.onContextMenu, this);
}
unbind(g: ScreenDoor): void {
g.selectable = false;
g.eventMode = 'none';
g.off('_leftclick', this.onLeftClick, this);
g.off('rightclick', this.onContextMenu, this);
}
onLeftClick() {
useLineStore().stateProCountIncrease();
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const screenDoor = target.getGraphic<ScreenDoor>();
if (!screenDoor) return;
this.app.updateSelected(screenDoor);
const lineStore = useLineStore();
setSceenDoorParam.handler = async () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
component: ScreenDoorOperation,
componentProps: {
id: screenDoor.id,
code: screenDoor.datas.code,
sonDoorAmount: screenDoor.datas.sonDoorAmount,
asdCodesProp: screenDoor.states.param.asdCodes,
screenDoorForceProp: screenDoor.states.param.force,
screenDoorFaultProp: screenDoor.states.param.fault,
},
cancel: true,
persistent: true,
});
};
sceenDoorOperateMenu.open(e.global);
}
}

View File

@ -17,14 +17,15 @@ import {
} from 'jl-graphic';
import { useLineStore } from 'src/stores/line-store';
import { SectionGraphicHitArea } from 'src/graphics/section/SectionDrawAssistant';
import { Dialog, Notify } from 'quasar';
import { Dialog } from 'quasar';
import AddTrainDialog from '../../components/draw-app/dialogs/AddTrainDialog.vue';
import { addTrain } from 'src/api/Simulation';
import { successNotify } from '../../utils/CommonNotify';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { ApiError } from 'src/boot/axios';
import { state } from 'src/protos/device_state';
import { getKmDistance } from '../lineScene';
import SectionOperation from 'src/components/draw-app/dialogs/SectionOperation.vue';
import { request } from 'src/protos/request';
import { setAxleSectionState } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
export class SectionData extends GraphicDataBase implements ISectionData {
constructor(data?: graphicData.Section) {
@ -163,6 +164,18 @@ export class SectionStates extends GraphicStateBase implements ISectionState {
set axleFault(axleFault: boolean) {
this.states.axleFault = axleFault;
}
get axleDrst(): boolean {
return this.states.axleDrst;
}
set axleDrst(axleDrst: boolean) {
this.states.axleDrst = axleDrst;
}
get axlePdrst(): boolean {
return this.states.axlePdrst;
}
set axlePdrst(axlePdrst: boolean) {
this.states.axlePdrst = axlePdrst;
}
get states(): state.SectionState {
return this.getState<state.SectionState>();
}
@ -180,11 +193,13 @@ export class SectionStates extends GraphicStateBase implements ISectionState {
const addTrainConfig: MenuItemOptions = {
name: '添加列车',
};
const setSectionParam: MenuItemOptions = { name: '设置参数' };
const setFaultOcc: MenuItemOptions = { name: '设置故障占用' };
const SectionOperateMenu: ContextMenu = ContextMenu.init({
name: '区段操作菜单',
groups: [
{
items: [addTrainConfig],
items: [setSectionParam, setFaultOcc, addTrainConfig],
},
],
});
@ -234,9 +249,33 @@ export class SectionOperateInteraction extends GraphicInteractionPlugin<Section>
const section = target.getGraphic<Section>();
if (!section || section.datas.sectionType != SectionType.Physical) return;
this.app.updateSelected(section);
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
addTrainConfig.disabled = !useLineStore().trainConfigList;
const lineStore = useLineStore();
setSectionParam.handler = async () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
component: SectionOperation,
componentProps: {
id: section.id,
code: section.datas.code,
axleDrst: section.states.axleDrst,
axlePdrst: section.states.axlePdrst,
},
cancel: true,
persistent: true,
});
};
setFaultOcc.handler = async () => {
const obj = {
simulationId: lineStore?.simulationId || '',
mapId: lineStore.mapId as number,
deviceId: section.id,
operation: request.Section.Operation.SetFaultOcc,
};
setAxleSectionState(obj).catch((e) =>
errorNotify('区段操作失败:' + e.title, e)
);
};
addTrainConfig.disabled = !lineStore.trainConfigList;
addTrainConfig.handler = () => {
const relations =
section.relationManage.getRelationsOfGraphicAndOtherType(
@ -251,7 +290,7 @@ export class SectionOperateInteraction extends GraphicInteractionPlugin<Section>
if (
(other.datas.axleCountingRef.length > 1 &&
other.datas.type ==
graphicData.AxleCounting.TypeDetectionPoint.AxleCounting) ||
graphicData.AxleCounting.TypeDetectionPoint.AxleCounting) ||
other.datas.axleCountingRef.length == 1
) {
if (rp.getParam() == 'A') {
@ -263,44 +302,15 @@ export class SectionOperateInteraction extends GraphicInteractionPlugin<Section>
}
});
const d = getKmDistance(BKm, AKm);
Dialog.create({
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '创建列车',
message: '',
component: AddTrainDialog,
componentProps: { dev: section, kmLength: d },
cancel: true,
persistent: true,
}).onOk(
(data: {
offset: number;
dir: 1 | 0;
trainLength: string;
wheelDiameter: number;
}) => {
const params = {
simulationId,
mapId,
up: !!data.dir,
id: section.datas.id,
headOffset: data.offset,
wheelDiameter: data.wheelDiameter,
};
if (data.trainLength) {
Object.assign(params, { trainLength: +data.trainLength });
}
addTrain(params)
.then(() => {
successNotify('添加列车成功!');
})
.catch((err) => {
const error = err as ApiError;
Notify.create({
type: 'negative',
message: `添加列车失败!: ${error.title}`,
});
});
}
);
});
};
SectionOperateMenu.open(e.global);
}

View File

@ -18,9 +18,9 @@ import { FederatedMouseEvent, DisplayObject } from 'pixi.js';
import { state } from 'src/protos/device_state';
import { useLineStore } from 'src/stores/line-store';
import { SignalGraphicHitArea } from 'src/graphics/signal/SignalDrawAssistant';
import { setSignalState } from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
import { request } from 'src/protos/request';
import { Dialog } from 'quasar';
import SignalOperation from 'src/components/draw-app/dialogs/SignalOperation.vue'
export class SignalData extends GraphicDataBase implements ISignalData {
constructor(data?: graphicData.Signal) {
@ -112,6 +112,12 @@ export class SignalState extends GraphicStateBase implements ISignalState {
set aspect(v: number) {
this.states.aspect = v;
}
get param(): request.SignalParam {
return this.states.param;
}
set param(v: request.SignalParam) {
this.states.param = v;
}
get states(): state.SignalState {
return this.getState<state.SignalState>();
}
@ -129,22 +135,9 @@ export class SignalState extends GraphicStateBase implements ISignalState {
const mirrorFlipConfig: MenuItemOptions = {
name: '镜像翻转',
};
const signalRedConfig: MenuItemOptions = {
name: '开红灯',
};
const signalGreenConfig: MenuItemOptions = {
name: '开绿灯',
};
const signalYellowConfig: MenuItemOptions = {
name: '开黄灯',
};
const signalGuideConfig: MenuItemOptions = {
name: '开引导',
};
const signalCloseConfig: MenuItemOptions = {
name: '关灯',
};
const setSignalParam: MenuItemOptions = {
name: '设置参数'
}
const SignalEditMenu: ContextMenu = ContextMenu.init({
name: '信号机编辑菜单',
groups: [
@ -158,11 +151,12 @@ const SignalOperateMenu: ContextMenu = ContextMenu.init({
groups: [
{
items: [
signalRedConfig,
signalGreenConfig,
signalYellowConfig,
signalGuideConfig,
signalCloseConfig,
setSignalParam
// signalRedConfig,
// signalGreenConfig,
// signalYellowConfig,
// signalGuideConfig,
// signalCloseConfig,
],
},
],
@ -236,63 +230,24 @@ export class SignalOperateInteraction extends GraphicInteractionPlugin<Signal> {
const target = e.target as DisplayObject;
const signal = target.getGraphic() as Signal;
this.app.updateSelected(signal);
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
signalCloseConfig.handler = () => {
setSignalState({
simulationId,
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.OFF,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
const lineStore = useLineStore();
setSignalParam.handler = () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '信号机设置参数',
message: '',
component: SignalOperation,
componentProps: {
id: signal.datas.id,
code: signal.datas.code,
mt: signal.datas.mt,
param: signal.states.param,
},
cancel: true,
persistent: true,
});
};
signalRedConfig.handler = () => {
setSignalState({
simulationId,
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.H,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
};
signalGreenConfig.handler = () => {
setSignalState({
simulationId,
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.L,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
};
signalYellowConfig.handler = () => {
setSignalState({
simulationId,
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.U,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
};
signalGuideConfig.handler = () => {
setSignalState({
simulationId,
mapId,
id: signal.datas.id,
aspect: state.Signal.Aspect.HU,
operation: request.Signal.Operation.Display,
}).catch((err) => {
errorNotify('操作失败', { message: err.origin.response.data.title });
});
};
}
SignalOperateMenu.open(e.global);
}
}

View File

@ -7,11 +7,7 @@ import {
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_state';
import {
IGraphicScene,
GraphicInteractionPlugin,
JlGraphic,
} from 'jl-graphic';
import { IGraphicScene, GraphicInteractionPlugin, JlGraphic } from 'jl-graphic';
import { KilometerSystem } from 'src/graphics/signal/Signal';
import { useLineStore } from 'src/stores/line-store';
@ -43,6 +39,12 @@ export class StationData extends GraphicDataBase implements IStationData {
set stationName(v: string) {
this.data.stationName = v;
}
get stationNameAcronym(): string {
return this.data.stationNameAcronym;
}
set stationNameAcronym(v: string) {
this.data.stationNameAcronym = v;
}
get kilometerSystem(): KilometerSystem {
if (!this.data.kilometerSystem) {
this.data.kilometerSystem = new graphicData.KilometerSystem();
@ -58,12 +60,6 @@ export class StationData extends GraphicDataBase implements IStationData {
set concentrationStations(v: boolean) {
this.data.concentrationStations = v;
}
get refIbpMapCode(): string {
return this.data.refIbpMapCode;
}
set refIbpMapCode(v: string) {
this.data.refIbpMapCode = v;
}
get depots(): boolean {
return this.data.depots;
}

View File

@ -0,0 +1,122 @@
import * as pb_1 from 'google-protobuf';
import { GraphicInteractionPlugin, IGraphicScene, JlGraphic } from 'jl-graphic';
import { tccGraphicData } from 'src/protos/tccGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { useLineStore } from 'src/stores/line-store';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { useTccStore } from 'src/stores/tcc-store';
import { state } from 'src/protos/device_state';
import {
ITccButtonData,
ITccButtonState,
TccButton,
} from 'src/graphics/tccButton/TccButton';
export class TccButtonData extends GraphicDataBase implements ITccButtonData {
constructor(data?: tccGraphicData.TccButton) {
let tccButton;
if (data) {
tccButton = data;
} else {
tccButton = new tccGraphicData.TccButton({
common: GraphicDataBase.defaultCommonInfo(TccButton.Type),
});
}
super(tccButton);
}
public get data(): tccGraphicData.TccButton {
return this.getData<tccGraphicData.TccButton>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get isSelfReset(): boolean {
return this.data.isSelfReset;
}
set isSelfReset(v: boolean) {
this.data.isSelfReset = v;
}
clone(): TccButtonData {
return new TccButtonData(this.data.cloneMessage());
}
copyFrom(data: TccButtonData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: TccButtonData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class TccButtonState
extends GraphicStateBase
implements ITccButtonState
{
constructor(proto?: state.TrainControlState.EmergentButton) {
let states;
if (proto) {
states = proto;
} else {
states = new state.TrainControlState.EmergentButton();
}
super(states, TccButton.Type);
}
get code(): string {
return this.states.id + '';
}
get down(): boolean {
return this.states.passed;
}
set down(v: boolean) {
this.states.passed = v;
}
get states(): state.TrainControlState.EmergentButton {
return this.getState<state.TrainControlState.EmergentButton>();
}
clone(): TccButtonState {
return new TccButtonState(this.states.cloneMessage());
}
copyFrom(data: GraphicStateBase): void {
pb_1.Message.copyInto(data._state, this._state);
}
eq(data: GraphicStateBase): boolean {
return pb_1.Message.equals(this._state, data._state);
}
}
export class TccButtonOperateInteraction extends GraphicInteractionPlugin<TccButton> {
static Name = 'tcc_button_operate_menu';
constructor(app: IGraphicScene) {
super(TccButtonOperateInteraction.Name, app);
}
static init(app: IGraphicScene) {
return new TccButtonOperateInteraction(app);
}
filter(...grahpics: JlGraphic[]): TccButton[] | undefined {
return grahpics
.filter((g) => g.type === TccButton.Type)
.map((g) => g as TccButton);
}
bind(g: TccButton): void {
g._tccButton.eventMode = 'static';
g._tccButton.cursor = 'pointer';
g._tccButton.on('_leftclick', this.onClick);
}
unbind(g: TccButton): void {
g._tccButton.eventMode = 'none';
g._tccButton.off('_leftclick', this.onClick);
}
onClick(e: FederatedMouseEvent): void {
const target = e.target as DisplayObject;
const tccButton = target.getGraphic<TccButton>();
if (!tccButton) return;
tccButton.states.down = !tccButton.states.down;
tccButton.doRepaint();
console.log(tccButton.states.down);
}
}

View File

@ -0,0 +1,147 @@
import * as pb_1 from 'google-protobuf';
import {
ITccHandleData,
ITccHandleState,
TccHandle,
} from 'src/graphics/tccHandle/TccHandle';
import { tccGraphicData } from 'src/protos/tccGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_state';
import { GraphicInteractionPlugin, IGraphicScene, JlGraphic } from 'jl-graphic';
import { type FederatedMouseEvent, DisplayObject } from 'pixi.js';
import { useTccStore } from 'src/stores/tcc-store';
export class TccHandleData extends GraphicDataBase implements ITccHandleData {
constructor(data?: tccGraphicData.TccHandle) {
let tccHandle;
if (data) {
tccHandle = data;
} else {
tccHandle = new tccGraphicData.TccHandle({
common: GraphicDataBase.defaultCommonInfo(TccHandle.Type),
});
}
super(tccHandle);
}
public get data(): tccGraphicData.TccHandle {
return this.getData<tccGraphicData.TccHandle>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
clone(): TccHandleData {
return new TccHandleData(this.data.cloneMessage());
}
copyFrom(data: TccHandleData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: TccHandleData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class TccHandleState
extends GraphicStateBase
implements ITccHandleState
{
constructor(data?: state.TrainControlState.PushHandler) {
let tccHandleState;
if (data) {
tccHandleState = data;
} else {
tccHandleState = new state.TrainControlState.PushHandler();
}
super(tccHandleState, TccHandle.Type);
}
get code(): string {
return this.states.id + '';
}
get states(): state.TrainControlState.PushHandler {
return this.getState<state.TrainControlState.PushHandler>();
}
get gear(): number {
return this.states.val;
}
set gear(v: number) {
this.states.val = v;
}
clone(): TccHandleState {
return new TccHandleState(this.states.cloneMessage());
}
copyFrom(data: GraphicStateBase): void {
pb_1.Message.copyInto(data._state, this._state);
}
eq(data: GraphicStateBase): boolean {
return pb_1.Message.equals(this._state, data._state);
}
}
export class TccHandleInteraction extends GraphicInteractionPlugin<TccHandle> {
static Name = 'TccHandleInteraction';
isMouseDown = false;
mouseDownBeginPos = 0;
mouseDownTccHandleBeginPos = 0;
constructor(app: IGraphicScene) {
super(TccHandleInteraction.Name, app);
}
static init(app: IGraphicScene) {
return new TccHandleInteraction(app);
}
filter(...grahpics: JlGraphic[]): TccHandle[] | undefined {
return grahpics.filter((g): g is TccHandle => g instanceof TccHandle);
}
bind(g: TccHandle): void {
g._tccHandle.eventMode = 'static';
g._tccHandle.cursor = 'Move';
g._tccHandle.onmousedown = (e) => {
this.onMouseDown(e);
};
g._tccHandle.onmouseup = () => {
this.isMouseDown = false;
};
g.onmousemove = (e) => {
this.onMouseMove(e);
};
g.onmouseleave = () => {
this.isMouseDown = false;
};
}
unbind(g: TccHandle): void {
g._tccHandle.eventMode = 'none';
g._tccHandle.onmousedown = null;
g._tccHandle.onmouseup = null;
g.onmousemove = null;
g.onmouseleave = null;
}
onMouseDown(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const tccHandle = target.getGraphic<TccHandle>();
if (!tccHandle) return;
this.isMouseDown = true;
this.mouseDownBeginPos = e.clientY;
this.mouseDownTccHandleBeginPos = tccHandle._tccHandle.y;
}
onMouseMove(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const tccHandle = target.getGraphic<TccHandle>();
if (!tccHandle) return;
if (
this.isMouseDown &&
tccHandle._tccHandle.y > -145 &&
tccHandle._tccHandle.y < 145
) {
tccHandle._tccHandle.y =
this.mouseDownTccHandleBeginPos + e.clientY - this.mouseDownBeginPos;
if (tccHandle._tccHandle.y >= 145) {
tccHandle._tccHandle.y = 144;
} else if (tccHandle._tccHandle.y <= -145) {
tccHandle._tccHandle.y = -144;
}
}
}
}

View File

@ -0,0 +1,209 @@
import * as pb_1 from 'google-protobuf';
import { ITccKeyData, ITccKeyState, TccKey } from 'src/graphics/tccKey/TccKey';
import { tccGraphicData } from 'src/protos/tccGraphics';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { state } from 'src/protos/device_state';
import { GraphicInteractionPlugin, IGraphicScene, JlGraphic } from 'jl-graphic';
import { type FederatedMouseEvent, DisplayObject, Point } from 'pixi.js';
import { useTccStore } from 'src/stores/tcc-store';
export class TccKeyData extends GraphicDataBase implements ITccKeyData {
constructor(data?: tccGraphicData.TccKey) {
let tccKey;
if (data) {
tccKey = data;
} else {
tccKey = new tccGraphicData.TccKey({
common: GraphicDataBase.defaultCommonInfo(TccKey.Type),
});
}
super(tccKey);
}
public get data(): tccGraphicData.TccKey {
return this.getData<tccGraphicData.TccKey>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get type(): tccGraphicData.TccKey.TccKeyType {
return this.data.type;
}
set type(v: tccGraphicData.TccKey.TccKeyType) {
this.data.type = v;
}
clone(): TccKeyData {
return new TccKeyData(this.data.cloneMessage());
}
copyFrom(data: TccKeyData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: TccKeyData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}
export class TccKeyState extends GraphicStateBase implements ITccKeyState {
constructor(data?: state.TrainControlState.DirectionKeySwitch) {
let tccKeyState;
if (data) {
tccKeyState = data;
} else {
tccKeyState = new state.TrainControlState.DirectionKeySwitch();
}
super(tccKeyState, TccKey.Type);
}
get code(): string {
return this.states.id + '';
}
get states(): state.TrainControlState.DirectionKeySwitch {
return this.getState<state.TrainControlState.DirectionKeySwitch>();
}
get position(): number {
return this.states.val;
}
set position(v: number) {
this.states.val = v;
}
clone(): TccKeyState {
return new TccKeyState(this.states.cloneMessage());
}
copyFrom(data: GraphicStateBase): void {
pb_1.Message.copyInto(data._state, this._state);
}
eq(data: GraphicStateBase): boolean {
return pb_1.Message.equals(this._state, data._state);
}
}
export class TccKeyInteraction extends GraphicInteractionPlugin<TccKey> {
static Name = 'TccKeyInteraction';
isMouseDown = false;
changeOnce = false;
mouseDownBeginPos = new Point();
constructor(app: IGraphicScene) {
super(TccKeyInteraction.Name, app);
}
static init(app: IGraphicScene) {
return new TccKeyInteraction(app);
}
filter(...grahpics: JlGraphic[]): TccKey[] | undefined {
return grahpics.filter((g): g is TccKey => g instanceof TccKey);
}
bind(g: TccKey): void {
g._tccKey.eventMode = 'static';
g._tccKey.cursor = 'pointer';
if (
g.datas.type ==
tccGraphicData.TccKey.TccKeyType.driverControllerActivationClint
) {
g._tccKey.on('_leftclick', this.onClick);
} else {
g._tccKey.onmousedown = (e) => {
this.onMouseDown(e);
};
g._tccKey.onmouseup = () => {
this.isMouseDown = false;
this.changeOnce = false;
};
g.onmousemove = (e) => {
this.onMousemove(e);
};
g.onmouseleave = () => {
this.isMouseDown = false;
this.changeOnce = false;
};
}
}
unbind(g: TccKey): void {
g._tccKey.eventMode = 'none';
if (
g.datas.type ==
tccGraphicData.TccKey.TccKeyType.driverControllerActivationClint
) {
g._tccKey.off('_leftclick', this.onClick);
} else {
g._tccKey.onmousedown = null;
g._tccKey.onmouseup = null;
g.onmousemove = null;
g.onmouseleave = null;
}
}
onClick(e: FederatedMouseEvent): void {
const target = e.target as DisplayObject;
const tccKey = target.getGraphic<TccKey>();
if (!tccKey) return;
tccKey.state.position = tccKey?.state.position == 0 ? 1 : 0;
tccKey.doRepaint();
}
onMouseDown(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const tccKey = target.getGraphic<TccKey>();
if (!tccKey) return;
this.isMouseDown = true;
this.mouseDownBeginPos = tccKey
.getGraphicApp()
.getScene('tcc')
.toCanvasCoordinates(e.global);
}
onMousemove(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const tccKey = target.getGraphic<TccKey>();
if (!tccKey) return;
if (this.isMouseDown) {
const mouseEndPos = tccKey
.getGraphicApp()
.getScene('tcc')
.toCanvasCoordinates(e.global);
const { angle, direction } = calculateAngleAndDirection(
this.mouseDownBeginPos,
tccKey.position,
mouseEndPos
);
if (
direction == 'ssz' &&
((angle > 45 && !this.changeOnce) || (angle > 90 && this.changeOnce)) &&
(tccKey._tccKey.rotation == -Math.PI / 4 ||
tccKey._tccKey.rotation == 0)
) {
this.changeOnce = true;
tccKey._tccKey.rotation += Math.PI / 4;
}
if (
direction == 'nsz' &&
((angle > 45 && !this.changeOnce) || (angle > 90 && this.changeOnce)) &&
(tccKey._tccKey.rotation == Math.PI / 4 || tccKey._tccKey.rotation == 0)
) {
this.changeOnce = true;
tccKey._tccKey.rotation -= Math.PI / 4;
}
}
}
}
function calculateAngleAndDirection(
pointA: Point,
pointO: Point,
pointB: Point
) {
const vectorAO = { x: pointA.x - pointO.x, y: pointA.y - pointO.y };
const vectorOB = { x: pointB.x - pointO.x, y: pointB.y - pointO.y };
const dotProduct = vectorAO.x * vectorOB.x + vectorAO.y * vectorOB.y;
const magnitudeAO = Math.sqrt(vectorAO.x ** 2 + vectorAO.y ** 2);
const magnitudeOB = Math.sqrt(vectorOB.x ** 2 + vectorOB.y ** 2);
const angle =
Math.acos(dotProduct / (magnitudeAO * magnitudeOB)) * (180 / Math.PI);
const crossProduct = vectorAO.x * vectorOB.y - vectorAO.y * vectorOB.x;
let rotationDirection = '';
if (crossProduct > 0) {
rotationDirection = 'ssz';
} else {
rotationDirection = 'nsz';
}
return { angle: angle, direction: rotationDirection };
}

View File

@ -0,0 +1,59 @@
import * as pb_1 from 'google-protobuf';
import {
ITextContentData,
TextContent,
} from 'src/graphics/textContent/TextContent';
import { tccGraphicData } from 'src/protos/tccGraphics';
import { GraphicDataBase } from './GraphicDataBase';
export class TccTextData extends GraphicDataBase implements ITextContentData {
constructor(data?: tccGraphicData.TccText) {
let tccText;
if (data) {
tccText = data;
} else {
tccText = new tccGraphicData.TccText({
common: GraphicDataBase.defaultCommonInfo(TextContent.Type),
});
}
super(tccText);
}
public get data(): tccGraphicData.TccText {
return this.getData<tccGraphicData.TccText>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
get content(): string {
return this.data.content;
}
set content(v: string) {
this.data.content = v;
}
get color(): string {
return this.data.color;
}
set color(v: string) {
this.data.color = v;
}
get fontSize(): number {
return this.data.fontSize;
}
set fontSize(v: number) {
this.data.fontSize = v;
}
clone(): TccTextData {
return new TccTextData(this.data.cloneMessage());
}
copyFrom(data: TccTextData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: TccTextData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -10,10 +10,12 @@ import {
ContextMenu,
} from 'jl-graphic';
import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { removeTrain, updateTrain } from 'src/api/Simulation';
import { removeTrain } from 'src/api/Simulation';
import { useLineStore } from 'src/stores/line-store';
import { successNotify, errorNotify } from '../../utils/CommonNotify';
import { Dialog } from 'quasar';
import SetTrainParam from 'src/components/draw-app/dialogs/SetTrainParam.vue';
import SetTrainLink from 'src/components/draw-app/dialogs/SetTrainLink.vue';
export class TrainState extends GraphicStateBase implements ITrainState {
constructor(proto?: state.TrainMapState) {
let states;
@ -395,6 +397,285 @@ export class TrainState extends GraphicStateBase implements ITrainState {
set vobcInterruption(v: boolean) {
this.states.vobcInterruption = v;
}
get davisParamA(): number {
return +this.states.trainDynamicConfig.davisParamA;
}
set davisParamA(v: number) {
this.states.trainDynamicConfig.davisParamA = v + '';
}
get davisParamB(): number {
return +this.states.trainDynamicConfig.davisParamB;
}
set davisParamB(v: number) {
this.states.trainDynamicConfig.davisParamB = v + '';
}
get davisParamC(): number {
return +this.states.trainDynamicConfig.davisParamC;
}
set davisParamC(v: number) {
this.states.trainDynamicConfig.davisParamC = v + '';
}
get curveResistanceParamR1(): number {
return +this.states.trainDynamicConfig.curveResistanceParamR1;
}
set curveResistanceParamR1(v: number) {
this.states.trainDynamicConfig.curveResistanceParamR1 = v + '';
}
get curveResistanceParamR2(): number {
return +this.states.trainDynamicConfig.curveResistanceParamR2;
}
set curveResistanceParamR2(v: number) {
this.states.trainDynamicConfig.curveResistanceParamR2 = v + '';
}
get curveResistanceParamR3(): number {
return +this.states.trainDynamicConfig.curveResistanceParamR3;
}
set curveResistanceParamR3(v: number) {
this.states.trainDynamicConfig.curveResistanceParamR3 = v + '';
}
get curveResistanceParamR4(): number {
return +this.states.trainDynamicConfig.curveResistanceParamR4;
}
set curveResistanceParamR4(v: number) {
this.states.trainDynamicConfig.curveResistanceParamR4 = v + '';
}
get revolvingMassParam(): number {
return +this.states.trainDynamicConfig.revolvingMassParam;
}
set revolvingMassParam(v: number) {
this.states.trainDynamicConfig.revolvingMassParam = v + '';
}
get jump(): boolean {
return this.states.trainDynamicConfig.jump;
}
set jump(v: boolean) {
this.states.trainDynamicConfig.jump = v;
}
get slipA(): number {
return +this.states.trainDynamicConfig.slipA;
}
set slipA(v: number) {
this.states.trainDynamicConfig.slipA = v + '';
}
get slipR(): number {
return +this.states.trainDynamicConfig.slipR;
}
set slipR(v: number) {
this.states.trainDynamicConfig.slipR = v + '';
}
get slipD(): number {
return this.states.trainDynamicConfig.slipD;
}
set slipD(v: number) {
this.states.trainDynamicConfig.slipD = v;
}
get slide(): number {
return +this.states.trainDynamicConfig.slide;
}
set slide(v: number) {
this.states.trainDynamicConfig.slide = v + '';
}
get idlingA(): number {
return +this.states.trainDynamicConfig.idlingA;
}
set idlingA(v: number) {
this.states.trainDynamicConfig.idlingA = v + '';
}
get idlingR(): number {
return +this.states.trainDynamicConfig.idlingR;
}
set idlingR(v: number) {
this.states.trainDynamicConfig.idlingR = v + '';
}
get idlingD(): number {
return this.states.trainDynamicConfig.idlingD;
}
set idlingD(v: number) {
this.states.trainDynamicConfig.idlingD = v;
}
get stopSign(): number {
return this.states.trainDynamicConfig.stopSign;
}
set stopSign(v: number) {
this.states.trainDynamicConfig.stopSign = v;
}
get aSpeedSensorEnableA(): boolean {
return this.states.trainEndsA.speedSensorEnableA;
}
set aSpeedSensorEnableA(v: boolean) {
this.states.trainEndsA.speedSensorEnableA = v;
}
get aSpeedSensorEnableB(): boolean {
return this.states.trainEndsA.speedSensorEnableB;
}
set aSpeedSensorEnableB(v: boolean) {
this.states.trainEndsA.speedSensorEnableB = v;
}
get aRadarEnable(): boolean {
return this.states.trainEndsA.radarEnable;
}
set aRadarEnable(v: boolean) {
this.states.trainEndsA.radarEnable = v;
}
get aRadarCheckSpeedDiff(): number {
return +this.states.trainEndsA.radarCheckSpeedDiff;
}
set aRadarCheckSpeedDiff(v: number) {
this.states.trainEndsA.radarCheckSpeedDiff + '';
}
get aRadarCheckTime(): number {
return this.states.trainEndsA.radarCheckTime;
}
set aRadarCheckTime(v: number) {
this.states.trainEndsA.radarCheckTime = v;
}
get bSpeedSensorEnableA(): boolean {
return this.states.trainEndsB.speedSensorEnableA;
}
set bSpeedSensorEnableA(v: boolean) {
this.states.trainEndsB.speedSensorEnableA = v;
}
get bSpeedSensorEnableB(): boolean {
return this.states.trainEndsB.speedSensorEnableB;
}
set bSpeedSensorEnableB(v: boolean) {
this.states.trainEndsB.speedSensorEnableB = v;
}
get bRadarEnable(): boolean {
return this.states.trainEndsB.radarEnable;
}
set bRadarEnable(v: boolean) {
this.states.trainEndsB.radarEnable;
}
get bRadarCheckSpeedDiff(): number {
return +this.states.trainEndsB.radarCheckSpeedDiff;
}
set bRadarCheckSpeedDiff(v: number) {
this.states.trainEndsB.radarCheckSpeedDiff = v + '';
}
get bRadarCheckTime(): number {
return this.states.trainEndsB.radarCheckTime;
}
set bRadarCheckTime(v: number) {
this.states.trainEndsB.radarCheckTime = v;
}
get aAccEnable(): boolean {
return this.states.trainEndsA.accEnable;
}
set aAccEnable(v: boolean) {
this.states.trainEndsA.accEnable = v;
}
get aAccCheckTime(): number {
return this.states.trainEndsA.accCheckTime;
}
set aAccCheckTime(v: number) {
this.states.trainEndsA.accCheckTime = v;
}
get aAccCheckSpeedDiff(): number {
return +this.states.trainEndsA.accCheckSpeedDiff;
}
set aAccCheckSpeedDiff(v: number) {
this.states.trainEndsA.accCheckSpeedDiff = v + '';
}
get aAccOutSpeed(): number {
return this.states.trainEndsA.accOutSpeed;
}
set aAccOutSpeed(v: number) {
this.states.trainEndsA.accOutSpeed = v;
}
get aRadarOutSpeed(): number {
return this.states.trainEndsA.radarOutSpeed;
}
set aRadarOutSpeed(v: number) {
this.states.trainEndsA.radarOutSpeed = v;
}
get bAccEnable(): boolean {
return this.states.trainEndsB.accEnable;
}
set bAccEnable(v: boolean) {
this.states.trainEndsB.accEnable = v;
}
get bAccCheckTime(): number {
return this.states.trainEndsB.accCheckTime;
}
set bAccCheckTime(v: number) {
this.states.trainEndsB.accCheckTime = v;
}
get bAccCheckSpeedDiff(): number {
return +this.states.trainEndsB.accCheckSpeedDiff;
}
set bAccCheckSpeedDiff(v: number) {
this.states.trainEndsB.accCheckSpeedDiff = v + '';
}
get bAccOutSpeed(): number {
return this.states.trainEndsB.accOutSpeed;
}
set bAccOutSpeed(v: number) {
this.states.trainEndsB.accOutSpeed = v;
}
get bRadarOutSpeed(): number {
return this.states.trainEndsB.radarOutSpeed;
}
set bRadarOutSpeed(v: number) {
this.states.trainEndsB.radarOutSpeed = v;
}
get tailDeviceId(): number {
return this.states.tailDeviceId;
}
set tailDeviceId(v: number) {
this.states.tailDeviceId = v;
}
get tailDevicePort(): string {
return this.states.tailDevicePort;
}
set tailDevicePort(v: string) {
this.states.tailDevicePort = v;
}
get tailOffset(): number {
return this.states.tailOffset;
}
set tailOffset(v: number) {
this.states.tailOffset = v;
}
get dataSerialNumber(): number {
return this.states.btmState?.dataSerialNumber;
}
set dataSerialNumber(v: number) {
this.states.btmState.dataSerialNumber = v;
}
get baliseCount(): number {
return this.states.btmState?.baliseCount;
}
set baliseCount(v: number) {
this.states.btmState.baliseCount = v;
}
get messageCounter(): number {
return this.states.btmState?.messageCounter;
}
set messageCounter(v: number) {
this.states.btmState.messageCounter = v;
}
get telegram(): string {
return this.states.btmState?.telegram;
}
set telegram(v: string) {
this.states.btmState.telegram = v;
}
get conn(): boolean {
return this.states.connState.conn;
}
set conn(v: boolean) {
this.states.connState.conn = v;
}
get connType(): state.TrainConnState.TrainConnType {
return this.states.connState.connType;
}
set connType(v: state.TrainConnState.TrainConnType) {
this.states.connState.connType = v;
}
get trainControlMapId(): number {
return this.states.connState.TrainControlMapId;
}
clone(): TrainState {
return new TrainState(this.states.cloneMessage());
}
@ -406,8 +687,14 @@ export class TrainState extends GraphicStateBase implements ITrainState {
}
}
const wheelDiameterChange: MenuItemOptions = {
name: '列车轮径调整',
// const wheelDiameterChange: MenuItemOptions = {
// name: '列车轮径调整',
// };
const TrainParam: MenuItemOptions = {
name: '设置参数',
};
const TrainLink: MenuItemOptions = {
name: '列车连接',
};
const removeTrainConfig: MenuItemOptions = {
name: '清除列车',
@ -416,7 +703,7 @@ const TrainOperateMenu: ContextMenu = ContextMenu.init({
name: '列车操作菜单',
groups: [
{
items: [wheelDiameterChange, removeTrainConfig],
items: [TrainParam, TrainLink, removeTrainConfig],
},
],
});
@ -457,45 +744,51 @@ export class TrainOperateInteraction extends GraphicInteractionPlugin<Train> {
const lineStore = useLineStore();
const simulationId = lineStore.simulationId || '';
const mapId = lineStore.mapId as number;
wheelDiameterChange.disabled = !useLineStore().trainConfigList;
wheelDiameterChange.handler = () => {
Dialog.create({
title: '列车轮径调整',
message: '列车轮径(mm)【770-840mm】, 请调整!',
prompt: {
model: train.states.wheelDiameter + '',
isValid: (val) => +val >= 770 && +val <= 840,
type: 'number',
TrainParam.handler = () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '列车设置',
message: '',
component: SetTrainParam,
componentProps: {
train: train,
},
cancel: true,
persistent: true,
}).onOk((data) => {
const params = {
id: train.states.id,
});
};
TrainLink.handler = () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '列车连接',
message: '',
component: SetTrainLink,
componentProps: {
trainId: train.code,
simulationId: simulationId,
wheelDiameter: +data,
};
updateTrain(params)
.then(() => {
successNotify('列车轮径调整成功!');
})
.catch((err) => {
errorNotify('列车轮径调整失败!', err);
});
},
cancel: true,
persistent: true,
});
};
removeTrainConfig.handler = () => {
removeTrain({
simulationId,
mapId,
trainId: train.code,
})
.then(() => {
successNotify('移除列车成功!');
Dialog.create({
title: '确认',
message: `确认清除【${train.states.id}】列车吗?`,
cancel: true,
}).onOk(async () => {
removeTrain({
simulationId,
mapId,
trainId: train.code,
})
.catch((err) => {
errorNotify('移除列车失败!', err);
});
.then(() => {
successNotify('移除列车成功!');
})
.catch((err) => {
errorNotify('移除列车失败!', err);
});
});
};
TrainOperateMenu.open(e.global);

View File

@ -1,17 +1,37 @@
import * as pb_1 from 'google-protobuf';
import {
ITransponderData,
ITransponderState,
Transponder,
TransponderTypeEnum,
} from 'src/graphics/transponder/Transponder';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { GraphicDataBase } from './GraphicDataBase';
import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase';
import { KilometerSystem } from 'src/graphics/signal/Signal';
import {
ContextMenu,
GraphicInteractionPlugin,
IGraphicScene,
JlGraphic,
MenuItemOptions,
} from 'jl-graphic';
import { FederatedMouseEvent, DisplayObject } from 'pixi.js';
import { useLineStore } from 'src/stores/line-store';
import { Dialog } from 'quasar';
import MoveTranspondere from '../../components/draw-app/dialogs/MoveTransponder.vue';
import UpdateMessageTransponder from '../../components/draw-app/dialogs/UpdateMessageTransponder.vue';
import {
resetMessageTransponder,
resetPositionTransponder,
stopTransponderTelegram,
sendTransponderTelegram
} from 'src/api/Simulation';
import { errorNotify } from 'src/utils/CommonNotify';
import { state } from 'src/protos/device_state';
export class TransponderData
extends GraphicDataBase
implements ITransponderData
{
implements ITransponderData {
constructor(data?: graphicData.Transponder) {
let transponder;
if (!data) {
@ -54,12 +74,18 @@ export class TransponderData
set centralizedStations(v: number[]) {
this.data.centralizedStations = v;
}
get fixedTelegram(): Uint8Array {
get fixedTelegram(): string {
return this.data.fixedTelegram;
}
set fixedTelegram(v: Uint8Array) {
set fixedTelegram(v: string) {
this.data.fixedTelegram = v;
}
get fixedUserTelegram(): string {
return this.data.fixedUserTelegram;
}
set fixedUserTelegram(v: string) {
this.data.fixedUserTelegram = v;
}
get type(): TransponderTypeEnum {
return this.data.type;
}
@ -76,3 +102,210 @@ export class TransponderData
return pb_1.Message.equals(this.data, other.data);
}
}
const movePosition: MenuItemOptions = { name: '移动应答器位置' };
const recoverPosition: MenuItemOptions = { name: '复位应答器' };
const modifyMessage: MenuItemOptions = { name: '修改报文' };
const resetMessage: MenuItemOptions = { name: '重置报文' };
const stopSendMessage: MenuItemOptions = { name: '停止发送报文' };
const cancelStopSendMessage: MenuItemOptions = { name: '取消停止发送报文' };
const TransponderOperationMenu: ContextMenu = ContextMenu.init({
name: '应答器操作',
groups: [
{
items: [
movePosition,
recoverPosition,
modifyMessage,
resetMessage,
stopSendMessage,
cancelStopSendMessage,
],
},
],
});
export class TransponderState
extends GraphicStateBase
implements ITransponderState {
constructor(proto?: state.BaliseState) {
let states;
if (proto) {
states = proto;
} else {
states = new state.BaliseState();
}
super(states, Transponder.Type);
}
get code(): string {
return this.states.id + '';
}
get id(): number {
return this.states.id;
}
set id(id: number) {
this.states.id = id;
}
get km(): graphicData.KilometerSystem {
return this.states.km
? this.states.km
: new graphicData.KilometerSystem({
coordinateSystem: '',
kilometer: 0,
direction: 0,
});
}
set km(v: graphicData.KilometerSystem) {
this.states.km = new graphicData.KilometerSystem(v);
}
get fixedTelegram(): string {
return this.states.fixedTelegram;
}
set fixedTelegram(v: string) {
this.states.fixedTelegram = v;
}
get fixedUserTelegram(): string {
return this.states.fixedUserTelegram;
}
set fixedUserTelegram(v: string) {
this.states.fixedUserTelegram = v;
}
get variableTelegram(): string {
return this.states.variableTelegram;
}
set variableTelegram(v: string) {
this.states.variableTelegram = v;
}
get variableUserTelegram(): string {
return this.states.variableUserTelegram;
}
set variableUserTelegram(v: string) {
this.states.variableUserTelegram = v;
}
get work(): boolean {
return this.states.work;
}
set work(v: boolean) {
this.states.work = v;
}
get states(): state.BaliseState {
return this.getState<state.BaliseState>();
}
clone(): TransponderState {
return new TransponderState(this.states.cloneMessage());
}
copyFrom(data: GraphicStateBase): void {
pb_1.Message.copyInto(data._state, this._state);
}
eq(data: GraphicStateBase): boolean {
return pb_1.Message.equals(this._state, data._state);
}
}
export class TransponderOperationPlugin extends GraphicInteractionPlugin<Transponder> {
static Name = 'transponder_operate_menu';
constructor(app: IGraphicScene) {
super(TransponderOperationPlugin.Name, app);
app.registerMenu(TransponderOperationMenu);
}
static init(app: IGraphicScene) {
return new TransponderOperationPlugin(app);
}
filter(...grahpics: JlGraphic[]): Transponder[] | undefined {
return grahpics.filter<Transponder>(
(g): g is Transponder => g instanceof Transponder
);
}
bind(g: Transponder): void {
g.polygonGraphic.eventMode = 'static';
g.polygonGraphic.cursor = 'pointer';
g.polygonGraphic.scalable = true;
g.labelGraphic.eventMode = 'static';
g.selectable = true;
g.on('_rightclick', this.onContextMenu);
}
unbind(g: Transponder): void {
g.polygonGraphic.eventMode = 'none';
g.polygonGraphic.scalable = false;
g.polygonGraphic.rotatable = false;
g.labelGraphic.eventMode = 'none';
g.selectable = false;
g.off('_rightclick', this.onContextMenu);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const transponder = target.getGraphic<Transponder>();
if (!transponder) return;
const lineStore = useLineStore();
const simulationId = lineStore.simulationId || '';
const mapId = lineStore.mapId as number;
TransponderOperationMenu.open(e.global);
movePosition.handler = async () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '移动应答器位置',
message: '',
component: MoveTranspondere,
componentProps: {
code: transponder.datas.code,
coordinateSystem: transponder.states.km?.coordinateSystem,
kilometer: transponder.states.km?.kilometer,
direction: transponder.states.km?.direction,
id: transponder.datas.id,
},
cancel: true,
persistent: true,
});
};
recoverPosition.handler = () => {
resetPositionTransponder({
simulationId,
mapId,
baliseId: transponder.datas.id,
}).catch((e) => {
errorNotify('复位应答器失败:' + e.title, e);
});
};
modifyMessage.handler = () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '修改应答器报文',
message: '',
component: UpdateMessageTransponder,
componentProps: {
code: transponder.datas.code,
fixedTelegram: transponder.states.fixedTelegram,
fixedUserTelegram: transponder.states.fixedUserTelegram,
id: transponder.datas.id,
type: transponder.datas.type,
variableTelegram: transponder.states.variableTelegram,
variableUserTelegram: transponder.states.variableUserTelegram,
},
cancel: true,
persistent: true,
});
};
resetMessage.handler = () => {
resetMessageTransponder({
simulationId,
mapId,
baliseId: transponder.datas.id,
}).catch((e) => errorNotify('重置应答器报文失败:' + e.title, e));
};
stopSendMessage.handler = () => {
stopTransponderTelegram({
simulationId,
mapId,
baliseId: transponder.datas.id,
}).catch((e) => errorNotify('停止发送应答器报文失败:' + e.title, e));
};
cancelStopSendMessage.handler = () => {
sendTransponderTelegram({
simulationId,
mapId,
baliseId: transponder.datas.id,
}).catch((e) => errorNotify('取消停止发送应答器报文失败:' + e.title, e));
};
}
}

View File

@ -22,15 +22,12 @@ import {
TurnoutSectionHitArea,
} from 'src/graphics/turnout/TurnoutDrawAssistant';
import { useLineStore } from 'src/stores/line-store';
import { setSwitchPosition } from 'src/api/Simulation';
import { Dialog, Notify } from 'quasar';
import AddTrainDialog from '../../components/draw-app/dialogs/AddTrainDialog.vue';
import { addTrain } from 'src/api/Simulation';
import { successNotify } from 'src/utils/CommonNotify';
import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import { Dialog } from 'quasar';
// import AddTrainDialog from '../../components/draw-app/dialogs/AddTrainDialog.vue';
// import { AxleCounting } from 'src/graphics/axleCounting/AxleCounting';
import TurnoutOperation from 'src/components/draw-app/dialogs/TurnoutOperation.vue';
// import { getKmDistance } from '../lineScene';
import { request } from 'src/protos/request';
import { ApiError } from 'src/boot/axios';
import { getKmDistance } from '../lineScene';
function getDefaultEndPoint() {
return {
@ -40,16 +37,15 @@ function getDefaultEndPoint() {
};
}
const setNormalPosition: MenuItemOptions = { name: '定操' };
const setReversePosition: MenuItemOptions = { name: '反操' };
const setTurnoutParam: MenuItemOptions = { name: '设置参数' };
const addTrainConfig: MenuItemOptions = {
name: '添加列车',
};
// const addTrainConfig: MenuItemOptions = {
// name: '添加列车',
// };
const TurnoutOperationMenu: ContextMenu = ContextMenu.init({
name: 'Turnout操作',
groups: [{ items: [setNormalPosition, setReversePosition, addTrainConfig] }],
groups: [{ items: [setTurnoutParam] }],
});
export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
@ -93,105 +89,75 @@ export class TurnoutOperationPlugin extends GraphicInteractionPlugin<Turnout> {
const target = e.target as DisplayObject;
const turnout = target.getGraphic<Turnout>();
if (!turnout) return;
const lineStore = useLineStore();
this.app.updateSelected(turnout);
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
const setPosition = async (val: number) => {
await setSwitchPosition({
simulationId,
mapId,
deviceId: turnout.datas.id,
operation: val,
});
};
setNormalPosition.handler = async () => {
await setPosition(request.Turnout.Operation.DC);
};
setReversePosition.handler = async () => {
await setPosition(request.Turnout.Operation.FC);
};
const port = (target as TurnoutSection).port;
addTrainConfig.disabled = !port || !useLineStore().trainConfigList;
addTrainConfig.handler = () => {
const relations =
turnout.relationManage.getRelationsOfGraphicAndOtherType(
turnout,
AxleCounting.Type
);
const findAc = relations.find((item) => {
const rp = item.getRelationParam(turnout);
const orp = item.getOtherRelationParam(turnout as Turnout);
const ac = orp.g as AxleCounting;
return (
rp.getParam() == port &&
((ac.datas.axleCountingRef.length > 1 &&
ac.datas.type ==
graphicData.AxleCounting.TypeDetectionPoint.AxleCounting) ||
ac.datas.axleCountingRef.length == 1)
);
});
const oKm = turnout.datas.kilometerSystem;
let pKm;
if (findAc) {
const other = findAc.getOtherGraphic(turnout) as AxleCounting;
pKm = other.datas.kilometerSystem;
} else {
const relations =
turnout.relationManage.getRelationsOfGraphicAndOtherType(
turnout,
Turnout.Type
);
const findT = relations.find((item) => {
const rp = item.getRelationParam(turnout);
return rp.getParam() == port;
});
if (findT) {
const other = findT.getOtherGraphic(turnout) as Turnout;
pKm = other.datas.kilometerSystem;
}
}
const d = getKmDistance(pKm, oKm);
Dialog.create({
title: '创建列车',
setTurnoutParam.handler = async () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
title: '道岔设置参数',
message: '',
component: AddTrainDialog,
componentProps: { dev: turnout, kmLength: d },
component: TurnoutOperation,
componentProps: {
id: turnout.id,
code: turnout.datas.code,
force: turnout.states.param.forcePosition,
},
cancel: true,
persistent: true,
}).onOk(
(data: {
offset: number;
dir: 1 | 0;
trainLength: string;
wheelDiameter: number;
}) => {
const params = {
simulationId,
mapId,
up: !!data.dir,
id: turnout.datas.id,
devicePort: port,
headOffset: data.offset,
wheelDiameter: data.wheelDiameter,
};
if (data.trainLength) {
Object.assign(params, { trainLength: +data.trainLength });
}
addTrain(params)
.then(() => {
successNotify('添加列车成功!');
})
.catch((err) => {
const error = err as ApiError;
Notify.create({
type: 'negative',
message: `添加列车失败!: ${error.title}`,
});
});
}
);
});
};
// const port = (target as TurnoutSection).port;
// addTrainConfig.disabled = !port || !lineStore.trainConfigList;
// addTrainConfig.handler = () => {
// const relations =
// turnout.relationManage.getRelationsOfGraphicAndOtherType(
// turnout,
// AxleCounting.Type
// );
// const findAc = relations.find((item) => {
// const rp = item.getRelationParam(turnout);
// const orp = item.getOtherRelationParam(turnout as Turnout);
// const ac = orp.g as AxleCounting;
// return (
// rp.getParam() == port &&
// ((ac.datas.axleCountingRef.length > 1 &&
// ac.datas.type ==
// graphicData.AxleCounting.TypeDetectionPoint.AxleCounting) ||
// ac.datas.axleCountingRef.length == 1)
// );
// });
// const oKm = turnout.datas.kilometerSystem;
// let pKm;
// if (findAc) {
// const other = findAc.getOtherGraphic(turnout) as AxleCounting;
// pKm = other.datas.kilometerSystem;
// } else {
// const relations =
// turnout.relationManage.getRelationsOfGraphicAndOtherType(
// turnout,
// Turnout.Type
// );
// const findT = relations.find((item) => {
// const rp = item.getRelationParam(turnout);
// return rp.getParam() == port;
// });
// if (findT) {
// const other = findT.getOtherGraphic(turnout) as Turnout;
// pKm = other.datas.kilometerSystem;
// }
// }
// const d = getKmDistance(pKm, oKm);
// if (lineStore.deviceOpreratDialogInstance) return;
// lineStore.deviceOpreratDialogInstance = Dialog.create({
// title: '创建列车',
// message: '',
// component: AddTrainDialog,
// componentProps: { dev: turnout, kmLength: d },
// cancel: true,
// persistent: true,
// });
// };
TurnoutOperationMenu.open(e.global);
}
}
@ -349,35 +315,11 @@ export class TurnoutStates extends GraphicStateBase implements ITurnoutState {
set fw(v: boolean) {
this.states.fw = v;
}
get force(): boolean {
return this.states.force;
get param(): request.PointsParam {
return this.states.param;
}
set force(v: boolean) {
this.states.force = v;
}
get sb(): boolean {
return this.states.sb;
}
set sb(v: boolean) {
this.states.sb = v;
}
get dwsb(): boolean {
return this.states.dwsb;
}
set dwsb(v: boolean) {
this.states.dwsb = v;
}
get fwsb(): boolean {
return this.states.fwsb;
}
set fwsb(v: boolean) {
this.states.fwsb = v;
}
get jc(): boolean {
return this.states.jc;
}
set jc(v: boolean) {
this.states.jc = v;
set param(param: request.PointsParam) {
this.states.param = param;
}
get qdc(): boolean {
return this.states.qdc;

View File

@ -5,7 +5,9 @@ import {
GraphicData,
IDrawApp,
KeyListener,
newDrawApp, MenuItemOptions, ContextMenu
newDrawApp,
MenuItemOptions,
ContextMenu,
} from 'jl-graphic';
import { ibpGraphicData } from 'src/protos/ibpGraphics';
import { useIBPDrawStore } from 'src/stores/ibp-draw-store';
@ -147,7 +149,10 @@ export function saveIBPDrawDatas(app: IDrawApp) {
const storage = new ibpGraphicData.IBPGraphicStorage();
const canvasData = app.canvas.saveData();
storage.canvas = new graphicData.Canvas({
...canvasData,
width: canvasData.width,
height: canvasData.height,
backgroundColor: canvasData.backgroundColor,
gridBackground: new graphicData.Grid(canvasData.gridBackground),
viewportTransform: toStorageTransform(canvasData.viewportTransform),
});

View File

@ -34,6 +34,10 @@ export function initLineApp(): IGraphicApp {
destination: `/rtsts/simulation/${simulationId}/state`,
messageHandle: testManage.socketHandler,
});
lineApp.subscribe({
destination: `/rtsts/simulation/${simulationId}/tpis`,
messageHandle: testManage.socketHandlerConnectInfo,
});
return lineApp;
}
@ -47,10 +51,10 @@ export function addSceneList(sceneList: ISceneName[]) {
case SceneToPictureType.relayScene: // 继电器
s = initRelayScene;
break;
default:
case SceneToPictureType.lineScene:
s = initLineScene;
}
if (lineApp) {
if (lineApp && s) {
s(lineApp, getSceneName(scene));
} else {
console.log('没有lineApp');

View File

@ -21,6 +21,27 @@ import {
Signal,
KilometerSystem,
} from 'src/graphics/signal/Signal';
import {
FloodGateData,
FloodGateOperationInteraction,
} from './graphics/FloodGateInteraction';
import { FloodGate, FloodGateTemplate } from 'src/graphics/floodGate/FloodGate';
import {
CarWashingData,
CarWashingOperationInteraction,
} from './graphics/CarWashingInteraction';
import {
CarWashing,
CarWashingTemplate,
} from 'src/graphics/carWashing/CarWashing';
import {
GarageDoorData,
GarageDoorOperationInteraction,
} from './graphics/GarageDoorInteraction';
import {
GarageDoor,
GarageDoorTemplate,
} from 'src/graphics/garageDoor/GarageDoor';
import {
PlatformData,
PlatformOperateInteraction,
@ -55,6 +76,7 @@ import {
} from './graphics/SectionInteraction';
import { Section, SectionTemplate } from 'src/graphics/section/Section';
import { getPublishMapInfoByLineId } from 'src/api/PublishApi';
import { initTranspondersState } from 'src/api/Simulation';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { useLineStore } from 'src/stores/line-store';
import { toUint8Array } from 'js-base64';
@ -89,7 +111,7 @@ import {
} from './graphics/SectionLinkInteraction';
import { AxleCountingSectionData } from './graphics/AxleCountingSectionInteraction';
import { LogicSectionData } from './graphics/LogicSectionInteraction';
import { Notify, QNotifyUpdateOptions } from 'quasar';
import { Notify, QNotifyUpdateOptions, Dialog } from 'quasar';
import {
StopPosition,
StopPositionTemplate,
@ -106,6 +128,11 @@ import {
SpksSwitchOperationInteraction,
} from './graphics/SpksSwitchInteraction';
import { GatedBoxData } from './graphics/GatedBoxInteraction';
import { GarageDoorBoxData } from './graphics/GarageDoorBoxInteraction';
import {
GarageDoorBox,
GarageDoorBoxTemplate,
} from 'src/graphics/garageDoorBox/GarageDoorBox';
import {
EsbButtonData,
EsbButtonOperationInteraction,
@ -115,7 +142,11 @@ import {
Transponder,
TransponderTemplate,
} from 'src/graphics/transponder/Transponder';
import { TransponderData } from './graphics/TransponderInteraction';
import {
TransponderData,
TransponderOperationPlugin,
TransponderState,
} from './graphics/TransponderInteraction';
import {
SlopeKiloMarker,
SlopeKiloMarkerTemplate,
@ -143,6 +174,7 @@ import {
} from 'src/graphics/trackLogicSection/TrackLogicSection';
import { TrackLogicSectionData } from './graphics/TrackLogicSectionInteraction';
import { GatedBoxOperateInteraction } from './graphics/GatedBoxInteraction';
import { GarageDoorBoxOperateInteraction } from './graphics/GarageDoorBoxInteraction';
import { CategoryType } from 'src/components/CategoryType';
import {
AutoReturnBox,
@ -153,16 +185,47 @@ import {
AutoReturnBoxOperationInteraction,
AutoReturnBoxState,
} from './graphics/AutoReturnBoxInteraction';
import { errorNotify, successNotify } from 'src/utils/CommonNotify';
import { removeAllTrain } from 'src/api/Simulation';
import { ApiError } from 'src/boot/axios';
import { IbpBox, IbpBoxTemplate } from 'src/graphics/ibpBox/IbpBox';
import { PslBox, PslBoxTemplate } from 'src/graphics/pslBox/PslBox';
import {
PslBoxData,
PslBoxOperateInteraction,
} from './graphics/PslBoxInteraction';
import {
IbpBoxData,
IbpBoxOperateInteraction,
} from './graphics/IbpBoxInteraction';
const showOptions: MenuItemOptions = {
name: '显示控制',
};
const initTranspondersOptions: MenuItemOptions = {
name: '应答器一键恢复',
};
const searchDeviceOptions: MenuItemOptions = {
name: '设备检索',
};
const searchTrainOptions: MenuItemOptions = {
name: '列车检索',
};
const clearAllTrainOptions: MenuItemOptions = {
name: '清除所有列车',
};
const DefaultCanvasMenu = new ContextMenu({
name: '图层选择',
groups: [
{
items: [showOptions],
items: [
showOptions,
initTranspondersOptions,
searchDeviceOptions,
searchTrainOptions,
clearAllTrainOptions,
],
},
],
});
@ -182,6 +245,8 @@ export const layerList = [
{ label: '停车位置标', value: StopPosition.Type, defaultShow: true },
{ label: 'Spks开关', value: SpksSwitch.Type, defaultShow: true },
{ label: '门控箱', value: GatedBox.Type, defaultShow: true },
{ label: 'Ibp盘', value: IbpBox.Type, defaultShow: true },
{ label: 'Psl盘', value: PslBox.Type, defaultShow: true },
{ label: '紧急关闭按钮', value: EsbButton.Type, defaultShow: true },
{ label: '应答器', value: Transponder.Type, defaultShow: true },
// { label: 'Link', value: Link.Type, defaultShow: false },
@ -195,6 +260,10 @@ export const layerList = [
{ label: '轨道区段', value: TrackSection.Type, defaultShow: false },
{ label: '轨道逻辑区段', value: TrackLogicSection.Type, defaultShow: false },
{ label: '自动折返按钮箱', value: AutoReturnBox.Type, defaultShow: true },
{ label: '车库门', value: GarageDoor.Type, defaultShow: true },
{ label: '防淹门', value: FloodGate.Type, defaultShow: true },
{ label: '洗车机', value: CarWashing.Type, defaultShow: true },
{ label: '车库门设置', value: GarageDoorBox.Type, defaultShow: true },
];
let lineScene: IGraphicScene;
@ -248,7 +317,9 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
new SpksSwitchTemplate(new SpksSwitchData()),
new GatedBoxTemplate(new GatedBoxData()),
new EsbButtonTemplate(new EsbButtonData(), new EsbButtonState()),
new TransponderTemplate(new TransponderData()),
new IbpBoxTemplate(new IbpBoxData()),
new PslBoxTemplate(new PslBoxData()),
new TransponderTemplate(new TransponderData(), new TransponderState()),
new SlopeKiloMarkerTemplate(new SlopeKiloMarkerData()),
// new LinkTemplate(new LinkData()),
new TrainWindowTemplate(new TrainWindowData()),
@ -261,6 +332,10 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
new AutoReturnBoxData(),
new AutoReturnBoxState()
),
new CarWashingTemplate(new CarWashingData()),
new GarageDoorTemplate(new GarageDoorData()),
new FloodGateTemplate(new FloodGateData()),
new GarageDoorBoxTemplate(new GarageDoorBoxData()),
];
lineScene.registerGraphicTemplates(...graphicTemplate);
SignalOperateInteraction.init(lineScene);
@ -271,9 +346,16 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
SectionOperateInteraction.init(lineScene);
TrainOperateInteraction.init(lineScene);
TurnoutOperationPlugin.init(lineScene);
TransponderOperationPlugin.init(lineScene);
EsbButtonOperationInteraction.init(lineScene);
SpksSwitchOperationInteraction.init(lineScene);
AutoReturnBoxOperationInteraction.init(lineScene);
PslBoxOperateInteraction.init(lineScene);
IbpBoxOperateInteraction.init(lineScene);
CarWashingOperationInteraction.init(lineScene);
GarageDoorOperationInteraction.init(lineScene);
FloodGateOperationInteraction.init(lineScene);
GarageDoorBoxOperateInteraction.init(lineScene);
if (categoryType === CategoryType.TH) {
GatedBoxOperateInteraction.init(lineScene);
}
@ -284,6 +366,41 @@ export function initLineScene(lineApp: IGraphicApp, sceneName: string) {
showOptions.handler = () => {
lineStore.setShowLayerDialog(true);
};
initTranspondersOptions.handler = () => {
if (!lineStore.simulationId) {
return;
}
initTranspondersState(lineStore.simulationId).catch((e) =>
errorNotify('一键恢复应答器失败!', e)
);
};
searchDeviceOptions.handler = () => {
lineStore.setShowDeviceSearch(true);
};
searchTrainOptions.handler = () => {
lineStore.setShowTrainSearch(true);
};
clearAllTrainOptions.handler = () => {
if (!lineStore.simulationId) {
return;
}
Dialog.create({
title: '确认',
message: '确认清除所有列车吗?',
cancel: true,
}).onOk(async () => {
try {
await removeAllTrain({
simulationId: lineStore.simulationId || '',
mapId: lineStore.mapId || 0,
});
successNotify('清除所有列车成功!');
} catch (err) {
const error = err as ApiError;
errorNotify('清除所有列车失败!', error.title);
}
});
};
DefaultCanvasMenu.open(e.global);
});
lineScene.on('postdataloaded', () => {
@ -339,6 +456,11 @@ function handleSubscribe(lineScene: IGraphicScene) {
states.push(new PlatformState(item));
}
});
storage.allStatus.baliseState.forEach((item) => {
if (item.id) {
states.push(new TransponderState(item));
}
});
storage.allStatus.trainState.forEach((item) => {
// 列车
if (!item.show) {
@ -423,10 +545,10 @@ function ControlShowType(lineScene: IGraphicScene) {
} else {
g.visible = false;
}
if (g.type == Transponder.Type) {
// 应答器不显示名称
(g as Transponder).labelGraphic.visible = false;
}
// if (g.type == Transponder.Type) {
// // 应答器不显示名称
// (g as Transponder).labelGraphic.visible = false;
// }
});
lineStore.setShowLayer(showTypeList);
}
@ -523,6 +645,24 @@ export async function loadLineDatas(): Promise<IGraphicStorage> {
storage.autoReturnBoxs.forEach((autoReturnBox) => {
datas.push(new AutoReturnBoxData(autoReturnBox));
});
storage.ibpBoxs.forEach((ibpBox) => {
datas.push(new IbpBoxData(ibpBox));
});
storage.pslBoxs.forEach((pslBox) => {
datas.push(new PslBoxData(pslBox));
});
storage.carWashings.forEach((carWashing) => {
datas.push(new CarWashingData(carWashing));
});
storage.garageDoors.forEach((garageDoor) => {
datas.push(new GarageDoorData(garageDoor));
});
storage.floodGates.forEach((floodGate) => {
datas.push(new FloodGateData(floodGate));
});
storage.garageDoorBoxes.forEach((garageDoorBox) => {
datas.push(new GarageDoorBoxData(garageDoorBox));
});
// const linkIdGenerator = new IdGenerator(Link.Type);
// storage.CalculateLink.forEach((link) => {
// const g = new LinkData(link);

View File

@ -5,7 +5,9 @@ import {
IGraphicStorage,
KeyListener,
newDrawApp,
GraphicData, ContextMenu, MenuItemOptions
GraphicData,
ContextMenu,
MenuItemOptions,
} from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { pslGraphicData } from 'src/protos/pslGraphics';
@ -164,7 +166,9 @@ export function savePslDrawDatas(app: IDrawApp) {
const storage = new pslGraphicData.PslGraphicStorage();
const canvasData = app.canvas.saveData();
storage.canvas = new graphicData.Canvas({
...canvasData,
width: canvasData.width,
height: canvasData.height,
backgroundColor: canvasData.backgroundColor,
viewportTransform: toStorageTransform(canvasData.viewportTransform),
});
const graphics = app.queryStore.getAllGraphics();

View File

@ -60,7 +60,7 @@ function handleSubscribe(pslScene: IGraphicScene) {
const pslStore = usePslStore();
const simulationId = lineStore.simulationId;
const mapId = lineStore.mapId;
const pslId = pslStore.gatedBoxId;
const pslId = pslStore.pslId;
const app = pslScene;
app.subscribe({
destination: `/rtsts/simulation/${simulationId}/psl/${mapId}/${pslId}`,

View File

@ -15,6 +15,7 @@ import { DisplayObject, FederatedMouseEvent } from 'pixi.js';
import { setRelayState } from 'src/api/Simulation';
import { ApiError } from 'src/boot/axios';
import { errorNotify, successNotify } from 'src/utils/CommonNotify';
import { request } from 'src/protos/request';
export class RelayData extends GraphicDataBase implements IRelayData {
constructor(data?: relayCabinetGraphicData.Relay) {
@ -78,6 +79,12 @@ export class RelayState extends GraphicStateBase implements IRelayState {
set xh(xh: boolean) {
this.states.xh = xh;
}
get force(): boolean {
return this.states.force;
}
set force(force: boolean) {
this.states.force = force;
}
get states(): state.ReplyState {
return this.getState<state.ReplyState>();
}
@ -92,14 +99,15 @@ export class RelayState extends GraphicStateBase implements IRelayState {
}
}
const setOpen: MenuItemOptions = { name: '驱动落下' };
const setClose: MenuItemOptions = { name: '驱动吸起' };
const setOpen: MenuItemOptions = { name: '强制后接点位(落下)' };
const setClose: MenuItemOptions = { name: '强制前接点位(吸起)' };
const cancelForce: MenuItemOptions = { name: '取消强制' };
export class RelayOperationPlugin extends GraphicInteractionPlugin<Relay> {
static Name = 'relay_operate_menu';
relayOperationMenu: ContextMenu = ContextMenu.init({
name: 'Relay操作',
groups: [{ items: [setOpen, setClose] }],
groups: [{ items: [setOpen, setClose, cancelForce] }],
});
constructor(app: IGraphicScene) {
@ -135,14 +143,12 @@ export class RelayOperationPlugin extends GraphicInteractionPlugin<Relay> {
this.app.updateSelected(relay);
const simulationId = useLineStore().simulationId || '';
const mapId = useLineStore().mapId as number;
setOpen.disabled = !relay.states.xh;
setClose.disabled = relay.states.xh;
const changeRelayState = async (td: boolean) => {
const changeRelayState = async (operation: request.Relay.Operation) => {
setRelayState({
id: relay.datas.id,
mapId,
simulationId,
td,
mapId,
deviceId: relay.datas.id,
operation,
})
.then(() => {
successNotify('修改继电器状态成功');
@ -153,10 +159,13 @@ export class RelayOperationPlugin extends GraphicInteractionPlugin<Relay> {
});
};
setOpen.handler = () => {
changeRelayState(false);
changeRelayState(request.Relay.Operation.ForceHw);
};
setClose.handler = () => {
changeRelayState(true);
changeRelayState(request.Relay.Operation.ForceQw);
};
cancelForce.handler = () => {
changeRelayState(request.Relay.Operation.CancelForce);
};
this.relayOperationMenu.open(e.global);
}

View File

@ -205,7 +205,9 @@ export function saveDrawDatas(app: IDrawApp) {
const storage = new relayCabinetGraphicData.RelayCabinetGraphicStorage();
const canvasData = app.canvas.saveData();
storage.canvas = new graphicData.Canvas({
...canvasData,
width: canvasData.width,
height: canvasData.height,
backgroundColor: canvasData.backgroundColor,
viewportTransform: toStorageTransform(canvasData.viewportTransform),
});
const graphics = app.queryStore.getAllGraphics();

View File

@ -1,10 +1,12 @@
import {
ContextMenu,
GraphicData,
GraphicQueryStore,
GraphicState,
IGraphicApp,
IGraphicScene,
IGraphicStorage,
MenuItemOptions,
} from 'jl-graphic';
import { getPublishMapInfoByLineId } from 'src/api/PublishApi';
import { useLineStore } from 'src/stores/line-store';
@ -24,7 +26,27 @@ import {
} from 'src/graphics/phaseFailureProtector/PhaseFailureProtector';
import { PhaseFailureProtectorData } from './relayCabinetGraphics/PhaseFailureProtectorInteraction';
import { state } from 'src/protos/device_state';
import { Notify, QNotifyUpdateOptions } from 'quasar';
import { Dialog, Notify, QNotifyUpdateOptions } from 'quasar';
import CiCjQdListStateDialog from 'src/components/draw-app/dialogs/CiCjQdListStateDialog.vue';
import { useTestManageStore } from 'src/stores/testManage-store';
const testManageStore = useTestManageStore();
const CiCjQdListState: MenuItemOptions = {
name: '驱采状态',
};
const canvasMenu = new ContextMenu({
name: '图层选择',
groups: [
{
items: [CiCjQdListState],
},
],
});
export const refRelaysListMap = new Map<
number,
{ combinationtype: string; device: string }
>();
export function initRelayScene(lineApp: IGraphicApp, sceneName: string) {
// 继电器
@ -46,28 +68,33 @@ export function initRelayScene(lineApp: IGraphicApp, sceneName: string) {
];
relayScene.registerGraphicTemplates(...relayGraphicTemplate);
RelayOperationPlugin.init(relayScene);
updataOnChangeScene(relayScene);
relayScene.on('postdataloaded', () => {
handleSubscribe(relayScene);
const map = new Map<number, string>();
refRelaysList.forEach((device) => {
device.combinationtypes.forEach((combinationtype) => {
combinationtype.refRelays.forEach((relayId) => {
map.set(relayId, device.code);
refRelaysListMap.set(relayId, {
combinationtype: combinationtype.code,
device: device.code,
});
});
});
});
const relays = relayScene.queryStore.queryByType<Relay>(Relay.Type);
relays.forEach((relay) => {
relay.refDevice.text = map.get(relay.id)?.replace(/_/g, '\n') as string;
relay.refDevice.text = refRelaysListMap
.get(relay.id)
?.device.replace(/_/g, '\n') as string;
});
const phaseFailureProtectors =
relayScene.queryStore.queryByType<PhaseFailureProtector>(
PhaseFailureProtector.Type
);
phaseFailureProtectors.forEach((phaseFailureProtector) => {
phaseFailureProtector.refDevice.text = map
.get(phaseFailureProtector.id)
?.replace(/_/g, '\n') as string;
phaseFailureProtector.refDevice.text = refRelaysListMap.get(
phaseFailureProtector.id
)?.device as string;
});
});
lineApp.on('destroy', () => {
@ -75,6 +102,24 @@ export function initRelayScene(lineApp: IGraphicApp, sceneName: string) {
});
}
export function updataOnChangeScene(relayScene: IGraphicScene) {
relayScene.registerMenu(canvasMenu);
relayScene.canvas.on('_rightclick', (e) => {
const lineStore = useLineStore();
CiCjQdListState.handler = async () => {
if (lineStore.deviceOpreratDialogInstance) return;
lineStore.deviceOpreratDialogInstance = Dialog.create({
component: CiCjQdListStateDialog,
cancel: true,
persistent: true,
}).onCancel(() => {
lineStore.deviceOpreratDialogInstance = null;
});
};
canvasMenu.open(e.global);
});
}
function handleSubscribe(relayScene: IGraphicScene) {
const lineStore = useLineStore();
const simulationId = lineStore.simulationId;
@ -92,6 +137,7 @@ function handleSubscribe(relayScene: IGraphicScene) {
states.push(new RelayState(relayState));
}
});
testManageStore.setStationQc(storage.allStatus.stationQc);
} else {
storage.varStatus.updatedReply.forEach((relayState) => {
if (relayState.id) {
@ -123,7 +169,6 @@ function handleSubscribe(relayScene: IGraphicScene) {
});
}
let refRelaysList: relayCabinetGraphicData.DeviceRelateRelay[] = [];
async function loadRelayDatas(): Promise<IGraphicStorage> {
const lineStore = useLineStore();
const mapId = lineStore.mapId;
@ -148,6 +193,8 @@ async function loadRelayDatas(): Promise<IGraphicStorage> {
datas.push(new PhaseFailureProtectorData(phaseFailureProtector));
});
refRelaysList = storage.deviceRelateRelayList;
sceneCiCjQdListMap.set(`${lineStore.sceneName}+ciCjList`, storage.ciCjList);
sceneCiCjQdListMap.set(`${lineStore.sceneName}+ciQdList`, storage.ciQdList);
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
@ -158,3 +205,11 @@ async function loadRelayDatas(): Promise<IGraphicStorage> {
});
}
}
//关联继电器列表
let refRelaysList: relayCabinetGraphicData.DeviceRelateRelay[] = [];
//采集列表和驱动列表
export const sceneCiCjQdListMap = new Map<
string,
relayCabinetGraphicData.CiCj | relayCabinetGraphicData.CiQd
>();

226
src/drawApp/tccApp.ts Normal file
View File

@ -0,0 +1,226 @@
import { fromUint8Array, toUint8Array } from 'js-base64';
import {
CombinationKey,
IDrawApp,
IGraphicStorage,
KeyListener,
newDrawApp,
GraphicData,
ContextMenu,
MenuItemOptions,
} from 'jl-graphic';
import { graphicData } from 'src/protos/stationLayoutGraphics';
import { tccGraphicData } from 'src/protos/tccGraphics';
import { saveDraft, getDraft } from 'src/api/DraftApi';
import { useTccDrawStore } from 'src/stores/tcc-draw-store';
import { successNotify, errorNotify } from '../utils/CommonNotify';
import { toStorageTransform } from './graphics/GraphicDataBase';
import { Dialog } from 'quasar';
import { checkMapData } from 'src/api/Simulation';
import { TccButtonData, TccButtonState } from './graphics/TccButtonInteraction';
import { TccButtonDraw } from 'src/graphics/tccButton/TccButtonDrawAssistant';
import { TccButton, TccButtonTemplate } from 'src/graphics/tccButton/TccButton';
import {
TextContent,
TextContentTemplate,
} from 'src/graphics/textContent/TextContent';
import { TccTextData } from './graphics/TccTextContentInteraction';
import { TextContentDraw } from 'src/graphics/textContent/TextContentDrawAssistant';
import { TccKeyDraw } from 'src/graphics/tccKey/TccKeyDrawAssistant';
import { TccKey, TccKeyTemplate } from 'src/graphics/tccKey/TccKey';
import { TccKeyData, TccKeyState } from './graphics/TccKeyInteraction';
import { TccHandleDraw } from 'src/graphics/tccHandle/TccHandleDrawAssistant';
import { TccHandle, TccHandleTemplate } from 'src/graphics/tccHandle/TccHandle';
import { TccHandleData, TccHandleState } from './graphics/TccHandleInteraction';
const UndoOptions: MenuItemOptions = {
name: '撤销',
};
const RedoOptions: MenuItemOptions = {
name: '重做',
};
const SelectAllOptions: MenuItemOptions = {
name: '全选',
};
export const DefaultCanvasMenu = new ContextMenu({
name: '绘制-画布菜单',
groups: [
{
items: [UndoOptions, RedoOptions],
},
{
items: [SelectAllOptions],
},
],
});
let drawApp: IDrawApp | null = null;
export function getTccDrawApp(): IDrawApp | null {
return drawApp;
}
export function destroyTccDrawApp(): void {
if (drawApp) {
drawApp.destroy();
drawApp = null;
}
}
export function initTccDrawApp(): IDrawApp {
drawApp = newDrawApp({
dataLoader: loadTccDrawDatas,
});
const app = drawApp;
//根据草稿图类型加载绘图工具
new TccButtonDraw(
app,
new TccButtonTemplate(new TccButtonData(), new TccButtonState())
);
new TextContentDraw(app, new TextContentTemplate(new TccTextData()));
new TccKeyDraw(
drawApp,
new TccKeyTemplate(new TccKeyData(), new TccKeyState())
);
new TccHandleDraw(
drawApp,
new TccHandleTemplate(new TccHandleData(), new TccHandleState())
);
// 画布右键菜单
app.registerMenu(DefaultCanvasMenu);
app.canvas.on('_rightclick', (e) => {
if (app.drawing) return;
UndoOptions.disabled = !app.opRecord.hasUndo;
RedoOptions.disabled = !app.opRecord.hasRedo;
UndoOptions.handler = () => {
app.opRecord.undo();
};
RedoOptions.handler = () => {
app.opRecord.redo();
};
SelectAllOptions.handler = () => {
app.selectAllGraphics();
};
DefaultCanvasMenu.open(e.global);
});
app.addKeyboardListener(
new KeyListener({
value: 'KeyS',
global: true,
combinations: [CombinationKey.Ctrl],
onPress: () => {
saveTccDrawToServer(app);
},
})
);
return drawApp;
}
export function checkTccDataToServer(app: IDrawApp) {
const base64 = saveTccDrawDatas(app);
checkMapData({ mapProto: base64 })
.then((res) => {
if (res.data.success) {
successNotify('校验数据成功!');
} else {
let message = '';
res.data.errors.forEach((err: string) => {
message += `<div>${err};<div>`;
});
Dialog.create({
title: '校验失败',
message: message,
html: true,
persistent: true,
ok: {
ali: 'center',
},
});
}
})
.catch((err) => {
errorNotify(err.message, err);
});
}
export function saveTccDrawToServer(app: IDrawApp) {
const base64 = saveTccDrawDatas(app);
const tccDrawStore = useTccDrawStore();
const id = tccDrawStore.draftId;
if (!id) {
return;
}
saveDraft(id as number, { proto: base64 })
.then(() => {
successNotify('保存数据成功!');
})
.catch((err) => {
errorNotify(err.message, err);
});
}
export function saveTccDrawDatas(app: IDrawApp) {
const storage = new tccGraphicData.TccGraphicStorage();
const canvasData = app.canvas.saveData();
storage.canvas = new graphicData.Canvas({
width: canvasData.width,
height: canvasData.height,
backgroundColor: canvasData.backgroundColor,
viewportTransform: toStorageTransform(canvasData.viewportTransform),
});
const graphics = app.queryStore.getAllGraphics();
graphics.forEach((g) => {
if (g instanceof TccButton) {
storage.tccButtons.push(g.saveData<TccButtonData>().data);
} else if (g instanceof TextContent) {
storage.tccTexts.push(g.saveData<TccTextData>().data);
} else if (g instanceof TccKey) {
storage.tccKeys.push(g.saveData<TccKeyData>().data);
} else if (g instanceof TccHandle) {
storage.tccHandles.push(g.saveData<TccHandleData>().data);
}
});
const base64 = fromUint8Array(storage.serialize());
console.log('保存数据', storage);
return base64;
}
export async function loadTccDrawDatas(): Promise<IGraphicStorage> {
// console.log('加载数据', base64);
const tccDrawStore = useTccDrawStore();
const id = tccDrawStore.draftId;
if (!id) {
throw new Error('获取数据异常为获取到草稿地图ID');
}
const { proto: base64 } = await getDraft(id);
if (base64) {
const storage = tccGraphicData.TccGraphicStorage.deserialize(
toUint8Array(base64)
);
// app.updateCanvas(storage.canvas);
const datas: GraphicData[] = [];
storage.tccButtons.forEach((tccButton) => {
datas.push(new TccButtonData(tccButton));
});
storage.tccKeys.forEach((tccKey) => {
datas.push(new TccKeyData(tccKey));
});
storage.tccHandles.forEach((tccHandle) => {
datas.push(new TccHandleData(tccHandle));
});
storage.tccTexts.forEach((tccText) => {
datas.push(new TccTextData(tccText));
});
return {
canvasProperty: storage.canvas,
datas: datas,
};
} else {
return Promise.resolve({
datas: [],
});
}
}

125
src/drawApp/tccScene.ts Normal file
View File

@ -0,0 +1,125 @@
import {
GraphicData,
GraphicState,
IGraphicApp,
IGraphicScene,
IGraphicStorage,
} from 'jl-graphic';
import { getPublishMapInfoById } from 'src/api/PublishApi';
import { useTccStore } from 'src/stores/tcc-store';
import { toUint8Array } from 'js-base64';
import { useLineStore } from 'src/stores/line-store';
import { state } from 'src/protos/device_state';
import {
TccButtonData,
TccButtonOperateInteraction,
TccButtonState,
} from './graphics/TccButtonInteraction';
import { tccGraphicData } from 'src/protos/tccGraphics';
import { TccButtonTemplate } from 'src/graphics/tccButton/TccButton';
import { TextContentTemplate } from 'src/graphics/textContent/TextContent';
import { TccTextData } from './graphics/TccTextContentInteraction';
import { TccKeyTemplate } from 'src/graphics/tccKey/TccKey';
import {
TccKeyData,
TccKeyInteraction,
TccKeyState,
} from './graphics/TccKeyInteraction';
import { TccHandleTemplate } from 'src/graphics/tccHandle/TccHandle';
import {
TccHandleData,
TccHandleInteraction,
TccHandleState,
} from './graphics/TccHandleInteraction';
export function initTccScene(lineApp: IGraphicApp, sceneName: string) {
const tccScene = lineApp.initScene(sceneName, {
dataLoader: loadTccDatas,
mouseToolOptions: {
boxSelect: false,
wheelZoom: false,
},
});
const graphicTemplate = [
new TccButtonTemplate(new TccButtonData(), new TccButtonState()),
new TextContentTemplate(new TccTextData()),
new TccKeyTemplate(new TccKeyData(), new TccKeyState()),
new TccHandleTemplate(new TccHandleData(), new TccHandleState()),
];
TccButtonOperateInteraction.init(tccScene);
TccKeyInteraction.init(tccScene);
TccHandleInteraction.init(tccScene);
tccScene.registerGraphicTemplates(...graphicTemplate);
tccScene.on('postdataloaded', () => {
handleSubscribe(tccScene);
});
return tccScene;
}
function handleSubscribe(tccScene: IGraphicScene) {
const lineStore = useLineStore();
const tccStore = useTccStore();
const simulationId = lineStore.simulationId;
const tccId = tccStore.tccId;
const app = tccScene;
app.subscribe({
destination: `/rtsts/simulation/${simulationId}/train/control/${tccId}`,
messageConverter: (message: Uint8Array) => {
const states: GraphicState[] = [];
const storage = state.TrainControlState.deserialize(message);
if (storage.ebutton) {
states.push(new TccButtonState(storage.ebutton));
}
if (storage.dirKey) {
states.push(new TccKeyState(storage.dirKey));
}
storage?.driverKey.forEach((driverKey) => {
const data = new state.TrainControlState.DirectionKeySwitch({
id: driverKey.id,
val: driverKey.val ? 1 : 0,
});
states.push(new TccKeyState(data));
});
if (storage.pushHandler) {
states.push(new TccHandleState(storage.pushHandler));
}
return states;
},
graphicQueryer: (state, store) => {
return store.queryById(+state.code);
},
});
}
async function loadTccDatas(): Promise<IGraphicStorage> {
const tccStore = useTccStore();
const { proto: base64 } = await getPublishMapInfoById(
tccStore.trainControlMapId
);
if (base64) {
const storage = tccGraphicData.TccGraphicStorage.deserialize(
toUint8Array(base64)
);
const datas: GraphicData[] = [];
storage.tccButtons.forEach((tccButton) => {
datas.push(new TccButtonData(tccButton));
});
storage.tccKeys.forEach((tccKey) => {
datas.push(new TccKeyData(tccKey));
});
storage.tccHandles.forEach((tccHandle) => {
datas.push(new TccHandleData(tccHandle));
});
storage.tccTexts.forEach((tccText) => {
datas.push(new TccTextData(tccText));
});
return Promise.resolve({
canvasProperty: storage.canvas,
datas: datas,
});
} else {
return Promise.resolve({
datas: [],
});
}
}

View File

@ -45,6 +45,9 @@ export class IBPButton extends JlGraphic {
this.sprite.anchor.set(0.5);
this.addChild(this.sprite);
}
get code(): string {
return this.datas.code;
}
get datas() {
return this.getDatas<IIBPButtonData>();
}

View File

@ -58,6 +58,10 @@ export class Arrow extends JlGraphic implements ILineGraphic {
this.arrowGraphic.endFill();
}
get code(): string {
return this.datas.code;
}
get datas(): IArrowData {
return this.getDatas<IArrowData>();
}

View File

@ -45,6 +45,9 @@ export class AutoReturnBox extends JlGraphic {
this.addChild(this.circleBody);
this.codeGraph.name = 'atb_code';
}
get code(): string {
return this.datas.code;
}
get datas(): IAutoReturnBoxData {
return this.getDatas<IAutoReturnBoxData>();
}

View File

@ -94,7 +94,9 @@ export class AxleCounting extends JlGraphic {
this.kilometerGraph.name = 'kilometer';
this.direction = direction;
}
get code(): string {
return this.datas.code;
}
get datas(): IAxleCountingData {
return this.getDatas<IAxleCountingData>();
}

View File

@ -55,7 +55,9 @@ export class AxleCountingSection extends JlGraphic {
this.addChild(this.lineGraphic);
this.addChild(this.labelGraphic);
}
get code(): string {
return this.datas.code;
}
get datas(): IAxleCountingSectionData {
return this.getDatas<IAxleCountingSectionData>();
}

View File

@ -0,0 +1,89 @@
import { Graphics } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'jl-graphic';
export interface ICarWashingData extends GraphicData {
get code(): string;
set code(v: string);
get linkSection(): number;
set linkSection(v: number);
get centralizedStations(): number[];
set centralizedStations(v: number[]);
clone(): ICarWashingData;
copyFrom(data: ICarWashingData): void;
eq(other: ICarWashingData): boolean;
}
const carWashingConsts = {
codeFontSize: 12,
codeColor: 0xffffff,
bodyRectLineColor: 0xffffff,
bodyRectLineWidth: 2,
bodyRectWidth: 10,
bodyRectHeight: 20,
bodyColor: 0x000000,
};
export class CarWashing extends JlGraphic {
static Type = 'carWashing';
codeGraph: VectorText = new VectorText('');
rectBody: Graphics = new Graphics();
constructor() {
super(CarWashing.Type);
this.addChild(this.codeGraph);
this.addChild(this.rectBody);
this.codeGraph.name = 'carw_code';
}
get code(): string {
return this.datas.code;
}
get datas(): ICarWashingData {
return this.getDatas<ICarWashingData>();
}
doRepaint(): void {
const codeGraph = this.codeGraph;
codeGraph.text = this.datas.code;
codeGraph.style.fill = carWashingConsts.codeColor;
codeGraph.setVectorFontSize(carWashingConsts.codeFontSize);
codeGraph.anchor.set(0.5);
const codeTransform = this.datas?.childTransforms?.find(
(item) => item.name === 'carw_code'
);
if (codeTransform) {
const position = codeTransform?.transform.position;
const rotation = codeTransform?.transform?.rotation;
codeGraph.position.set(position?.x, position?.y);
codeGraph.rotation = rotation || 0;
} else {
codeGraph.position.set(0, -30);
}
this.rectBody.clear();
this.rectBody.beginFill(carWashingConsts.bodyColor, 0);
this.rectBody.lineStyle(
carWashingConsts.bodyRectLineWidth,
carWashingConsts.bodyRectLineColor
);
this.rectBody.drawRect(
-carWashingConsts.bodyRectWidth / 2,
-carWashingConsts.bodyRectHeight / 2,
carWashingConsts.bodyRectWidth,
carWashingConsts.bodyRectHeight
);
this.rectBody.endFill();
}
}
export class CarWashingTemplate extends JlGraphicTemplate<CarWashing> {
constructor(dataTemplate: ICarWashingData) {
super(CarWashing.Type, { dataTemplate });
}
new(): CarWashing {
const carWashing = new CarWashing();
carWashing.loadData(this.datas);
return carWashing;
}
}

View File

@ -0,0 +1,128 @@
import { DisplayObject, FederatedMouseEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
IDrawApp,
JlGraphic,
} from 'jl-graphic';
import { CarWashing, CarWashingTemplate, ICarWashingData } from './CarWashing';
export interface ICarWashingDataDrawOptions {
newData: () => ICarWashingData;
}
export class CarWashingDraw extends GraphicDrawAssistant<
CarWashingTemplate,
ICarWashingData
> {
_carWashing: CarWashing | null = null;
constructor(app: IDrawApp, template: CarWashingTemplate) {
super(
app,
template,
'svguse:../../drawIcon.svg#icon-car-washing',
'洗车机CarWashing'
);
CarWashingInteraction.init(app);
}
public get carWashing(): CarWashing {
if (!this._carWashing) {
this._carWashing = this.graphicTemplate.new();
this._carWashing.loadData(this.graphicTemplate.datas);
this.container.addChild(this._carWashing);
}
return this._carWashing;
}
onLeftUp(e: FederatedMouseEvent): void {
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
this.createAndStore(true);
}
redraw(p: Point): void {
this.carWashing.repaint();
this.container.position.set(p.x, p.y);
}
prepareData(data: ICarWashingData): boolean {
data.transform = this.container.saveTransform();
data.code = 'CarWash';
return true;
}
}
/**
* 线
* @param carWashing
*/
function buildAbsorbablePositions(
carWashing: CarWashing
): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const carWashings = carWashing.queryStore.queryByType<CarWashing>(
CarWashing.Type
);
const canvas = carWashing.getCanvas();
carWashings.forEach((item) => {
if (item.id === carWashing.id) {
return;
}
const ala = new AbsorbableLine(
new Point(item.x, 0),
new Point(item.x, canvas.height)
);
const alb = new AbsorbableLine(
new Point(0, item.y),
new Point(canvas.width, item.y)
);
aps.push(ala);
aps.push(alb);
});
return aps;
}
export class CarWashingInteraction extends GraphicInteractionPlugin<CarWashing> {
static Name = 'car_washing_transform';
constructor(app: IDrawApp) {
super(CarWashingInteraction.Name, app);
}
static init(app: IDrawApp) {
return new CarWashingInteraction(app);
}
filter(...grahpics: JlGraphic[]): CarWashing[] | undefined {
return grahpics
.filter((g) => g.type === CarWashing.Type)
.map((g) => g as CarWashing);
}
bind(g: CarWashing): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
g.codeGraph.draggable = true;
g.codeGraph.selectable = true;
g.codeGraph.rotatable = true;
g.codeGraph.transformSave = true;
g.codeGraph.eventMode = 'static';
g.on('transformstart', this.transformstart, this);
}
unbind(g: CarWashing): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
g.codeGraph.draggable = false;
g.codeGraph.selectable = false;
g.codeGraph.rotatable = false;
g.codeGraph.transformSave = false;
g.codeGraph.eventMode = 'none';
g.off('transformstart', this.transformstart, this);
}
transformstart(e: GraphicTransformEvent) {
const target = e.target as DisplayObject;
const carWashing = target.getGraphic() as CarWashing;
carWashing.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(carWashing),
});
}
}

View File

@ -54,7 +54,9 @@ export class ConcentrationDividingLine
this.transformSave = true;
this.addChild(this.lineGraphic);
}
get code(): string {
return this.datas.code;
}
get datas(): IConcentrationDividingLineData {
return this.getDatas<IConcentrationDividingLineData>();
}

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