Compare commits

...

100 Commits

Author SHA1 Message Date
lijun 609d97ddbd 添加正在运行定时器,添加显示上次成功时间 2025-12-14 16:02:26 +08:00
lijun 8121c1ce7c 修改更新用户信息的选项方式 2025-10-19 00:06:35 +08:00
lijun 9843b925dd 修改权限部分显示方式 2025-10-18 22:54:18 +08:00
lijun 2a49524615 修改权限 2025-10-18 14:44:54 +08:00
lijun 476b51edbb 修改权限 2025-10-18 14:24:41 +08:00
lijun 3fafc002e3 修复密码登录问题 2025-10-17 20:32:58 +08:00
lijun d0180115bf 调整文件编辑 2025-10-16 20:25:21 +08:00
lijun 1705d6d763 修复user请求问题 2025-10-16 20:22:02 +08:00
lijun dc76811e15 修复device请求问题 2025-10-16 20:13:42 +08:00
lijun 3c22de6e2f 添加cid正在运行项目查询 2025-09-20 14:48:08 +08:00
lijun 0da522c90b 修改请求中body带token 2025-09-14 14:29:20 +08:00
lijun 318ecc2578 修复cidlog日志输出问题,删除不用域名 2025-09-12 20:06:08 +08:00
junleea 7ebe4a0952 修复cid加载锁定问题 2025-08-10 14:25:34 +08:00
junleea f13aabd082 修改时间格式显示,添加shell运行错误状态 2025-08-03 18:19:43 +08:00
junleea 513faea916 修改时间格式显示,添加shell运行错误状态 2025-08-03 18:05:18 +08:00
junleea b5073c1948 修改时间格式显示,添加shell运行错误状态 2025-08-03 17:37:07 +08:00
junleea 8c4f04d821 修改时间格式显示,添加shell运行错误状态 2025-08-03 17:27:29 +08:00
junleea 296ba34b38 修改获取好友请求 2025-08-02 14:10:02 +08:00
junleea 1e54834c15 修改shell部分 2025-07-30 23:25:31 +08:00
junleea 759b24fe43 修改shelllist状态提示 2025-07-29 19:49:37 +08:00
junleea 7a24b3efc2 修改cid加载问题 2025-07-27 23:25:58 +08:00
junleea 0bf5f0a1d4 修复登录问题 2025-07-26 16:48:36 +08:00
junleea 7cf85e8bdb 添加阿里云服务器 2025-06-11 14:02:59 +08:00
junleea 2a477d18ca 添加阿里云服务器 2025-06-11 14:02:34 +08:00
junleea 42fabb0179 添加阿里云服务器 2025-06-11 13:49:51 +08:00
junleea 138c26add1 添加阿里云服务器 2025-06-11 13:43:35 +08:00
junleea 4d568bbc0b 添加阿里云服务器 2025-06-11 13:40:39 +08:00
junleea a14f8a8d93 添加阿里云服务器 2025-06-11 13:39:46 +08:00
junleea 9ed8f050e3 登录跳转统一登录平台 2025-06-10 12:57:21 +08:00
junleea 6b0ec18722 cid日志添加分页 2025-06-08 13:11:17 +08:00
junleea 7f3a258ebd cid执行日志获取刷新限制 2025-06-08 12:59:51 +08:00
junleea f7c690bad7 修改监控摄像头设备表格显示状态 2025-06-06 16:21:57 +08:00
junleea e2ebe67184 添加monitor部分增删改查 2025-06-06 16:19:41 +08:00
junleea 747e1d1895 添加命令删除,修改命令部分页面 2025-06-06 15:12:30 +08:00
junleea 3d5acbe68a 修复部分输出问题,修改登录页面问题 2025-06-04 14:03:00 +08:00
junleea 271ecb19ab 添加项目之间跳转,无需重复登录 2025-06-03 18:46:01 +08:00
junleea d1ea903c7b 添加项目之间跳转,无需重复登录 2025-06-03 18:07:11 +08:00
junleea 8eb0daa25a 修改无感刷新 2025-06-03 11:53:39 +08:00
junleea 400a40cb9c 添加无感刷新 2025-06-02 19:02:46 +08:00
junleea cf042ea5d1 用户中心部分添加无感刷新 2025-06-02 18:39:17 +08:00
junleea 52a8d03bf4 修复cid添加请求问题 2025-06-02 16:51:07 +08:00
junleea cf0577f70c 修改文件及cid部分请求及显示问题 2025-06-02 14:58:53 +08:00
junleea d6264ad44e 对文件列表添加加载 2025-06-02 14:37:51 +08:00
junleea cfe1eb8f3b 修改请求数据,修改页面逻辑,添加服务器 2025-06-02 14:07:33 +08:00
junleea be0a4a0a74 添加cid前端请求数据时加载动画 2025-05-29 17:32:48 +08:00
junleea 2dfd5ac7ae 添加阿里云服务器执行命令及附属 2025-04-29 14:05:14 +08:00
junleea 06037f56ad 修复执行时间小数保留,修复其它不正常显示问题 2025-04-23 18:45:43 +08:00
junleea 3b874137d7 修改运行时间输出 2025-03-27 20:24:05 +08:00
junleea ce1bd569a3 添加cid日志查看运行时间 2025-03-27 14:47:12 +08:00
junleea d3296797ce 使用原始流,登录功能修改 2025-03-26 11:29:47 +08:00
junleea fa50b581e0 添加shell执行命令分发 2025-03-11 16:05:47 +08:00
junleea 6da564fcea 实时查看接口使用视频流服务 2025-01-18 21:24:49 +08:00
junleea 4927c5a710 修复输入头像问题 2025-01-06 20:27:46 +08:00
junleea 132fa10ce4 修复用户信息显示 2025-01-06 20:25:54 +08:00
junleea e06dfcb0fe 添加配置文件增删改查 2025-01-04 22:45:04 +08:00
junleea e41b5ef5ff 添加avatar修改、聊天显示头像,聊天有消息提前 2025-01-01 18:44:48 +08:00
junleea 3f16b7a0b8 文件发送前先查找是否存在,防止反复提交文件进行校验 2024-12-28 13:44:08 +08:00
junleea 0b35eb17af 文件发送显示 2024-12-27 21:42:52 +08:00
junleea 6036a772fd 聊天信息最大宽度 2024-12-27 21:37:36 +08:00
junleea afaea81a31 添加发送文件功能,文件md5值计算 2024-12-27 21:31:39 +08:00
junleea cc424f3062 添加发送文件功能 2024-12-27 20:03:36 +08:00
junleea 3597c23525 实时播放版本2 2024-12-26 16:23:53 +08:00
junleea 2083456ca5 实时播放修改显示位置 2024-12-26 15:35:40 +08:00
junleea d6aa73cba4 添加redis查看 2024-12-21 19:09:24 +08:00
junleea 4ad46ac69d 添加redis查看 2024-12-21 18:07:42 +08:00
junleea 50595df30a 修复登录后,菜单未正确显示问题 2024-12-18 23:42:34 +08:00
junleea 0471fd0169 添加视频删除功能,修改视频播放功能 2024-12-18 15:23:15 +08:00
junleea 9f6251ff1a 菜单问题 2024-12-06 17:33:50 +08:00
junleea 7ec0490577 修复菜单不正常打开 2024-12-04 20:20:43 +08:00
junleea 108c590d95 菜单根据权限显示 2024-12-04 20:02:00 +08:00
junleea 4c976c5a34 修复退出登录问题,修复部分用户布局 2024-12-04 15:35:53 +08:00
junleea 651b1afb3b 重新设置菜单按钮,修复部分错误 2024-12-04 15:21:45 +08:00
junleea ee77bbf130 cid删除通知 2024-11-24 16:15:47 +08:00
junleea 6511b431ae cid添加定时运行任务 2024-11-24 15:53:40 +08:00
junleea 9336042b3b 添加删除确认,修改操作信息 2024-11-23 16:21:13 +08:00
junleea 07cee69631 修复登录错误提示 2024-11-07 21:06:00 +08:00
junleea 4f55a5070a 修复未登录未正确跳出问题 2024-11-06 22:03:52 +08:00
junleea 120e5c6167 异步加载ip,修复实时视频退出wss未关闭 2024-10-26 14:34:28 +08:00
junleea 647afd9e94 发布版本请求地址 2024-10-25 18:34:11 +08:00
junleea 08f559c80e 添加修改群信息功能 2024-10-25 18:30:40 +08:00
junleea 782b831334 搜索视频时间使用时间戳 2024-10-25 18:12:07 +08:00
junleea 4f735d82f7 群成员管理,同意加入群功能 2024-10-07 17:20:19 +08:00
junleea b795f89b86 权限修改用户信息,给用户授权 2024-10-06 16:46:46 +08:00
junleea 8a306bdee2 修复群组查询,设备查询 2024-10-04 13:11:12 +08:00
junleea a4d11ecf9e cid添加选择服务器功能 2024-10-03 16:15:26 +08:00
junleea 9257458d85 消息前端渲染md 2024-10-02 20:57:46 +08:00
junleea 4802a22196 顶部菜单功能,聊天wss关闭 2024-10-02 19:16:26 +08:00
junleea a3f524e345 修复群消息为到底部,添加删除群及修改群信息 2024-10-02 19:09:32 +08:00
junleea 260bd5a5d9 双服务器设置,视频、设备ipv6服务 2024-10-02 18:16:29 +08:00
junleea 3c22ca29a8 添加请求加入群聊功能 2024-08-20 16:00:21 +08:00
junleea ea4a1b7773 修改在线加密聊天无法进入,视频文件大小显示错误问题 2024-08-19 18:16:10 +08:00
junleea 0741f83a0f 修改聊天功能 2024-08-17 14:08:42 +08:00
junleea 776a5f64e7 添加群聊及管理群组信息 2024-08-16 15:24:25 +08:00
junleea 19c671de8b 添加获取历史消息,添加消息提示 2024-08-13 11:46:05 +08:00
junleea 2f68ef1f1d 修复视频搜索bug 2024-08-10 12:19:11 +08:00
junleea b98d3313f5 修复用户搜索问题,添加用户接受好友 2024-08-09 21:24:39 +08:00
junleea 2ac513bda8 添加好友请求,通知修改 2024-08-08 21:06:39 +08:00
junleea 1c9a259ca2 聊天功能基本完成 2024-08-08 18:04:45 +08:00
junleea ba268f1422 添加聊天功能,目前不能实时获取对方发送消息,将提示修改为el 2024-08-08 14:23:41 +08:00
junleea 955e379333 修改提示 2024-08-07 16:22:53 +08:00
44 changed files with 6602 additions and 870 deletions

484
package-lock.json generated
View File

@ -12,9 +12,13 @@
"cors": "^2.8.5",
"crypto-js": "^4.2.0",
"element-plus": "^2.4.4",
"highlight.js": "^11.11.1",
"js-cookie": "^3.0.5",
"js-md5": "^0.8.3",
"markdown-it": "^14.1.0",
"qrcode": "^1.5.3",
"spark-md5": "^3.0.2",
"video_ca": "file:",
"video.js": "^8.9.0",
"vue": "^3.3.11",
"vue-cookies": "^1.8.3",
@ -66,9 +70,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz",
"integrity": "sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [
"ppc64"
],
@ -82,9 +86,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.11.tgz",
"integrity": "sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [
"arm"
],
@ -98,9 +102,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz",
"integrity": "sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [
"arm64"
],
@ -114,9 +118,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.11.tgz",
"integrity": "sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [
"x64"
],
@ -130,9 +134,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz",
"integrity": "sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [
"arm64"
],
@ -146,9 +150,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz",
"integrity": "sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
@ -162,9 +166,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz",
"integrity": "sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [
"arm64"
],
@ -178,9 +182,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz",
"integrity": "sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [
"x64"
],
@ -194,9 +198,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz",
"integrity": "sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [
"arm"
],
@ -210,9 +214,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz",
"integrity": "sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [
"arm64"
],
@ -226,9 +230,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz",
"integrity": "sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [
"ia32"
],
@ -242,9 +246,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz",
"integrity": "sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [
"loong64"
],
@ -258,9 +262,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz",
"integrity": "sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [
"mips64el"
],
@ -274,9 +278,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz",
"integrity": "sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [
"ppc64"
],
@ -290,9 +294,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz",
"integrity": "sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [
"riscv64"
],
@ -306,9 +310,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz",
"integrity": "sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [
"s390x"
],
@ -322,9 +326,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz",
"integrity": "sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [
"x64"
],
@ -338,9 +342,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz",
"integrity": "sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [
"x64"
],
@ -354,9 +358,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz",
"integrity": "sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [
"x64"
],
@ -370,9 +374,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz",
"integrity": "sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [
"x64"
],
@ -386,9 +390,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz",
"integrity": "sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [
"arm64"
],
@ -402,9 +406,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz",
"integrity": "sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [
"ia32"
],
@ -418,9 +422,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz",
"integrity": "sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [
"x64"
],
@ -471,9 +475,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.4.tgz",
"integrity": "sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
"cpu": [
"arm"
],
@ -484,9 +488,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.4.tgz",
"integrity": "sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
"cpu": [
"arm64"
],
@ -497,9 +501,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.4.tgz",
"integrity": "sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
"cpu": [
"arm64"
],
@ -510,9 +514,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.4.tgz",
"integrity": "sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
"cpu": [
"x64"
],
@ -523,9 +527,22 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.4.tgz",
"integrity": "sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
"cpu": [
"arm"
],
@ -536,9 +553,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.4.tgz",
"integrity": "sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
"cpu": [
"arm64"
],
@ -549,9 +566,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.4.tgz",
"integrity": "sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
"cpu": [
"arm64"
],
@ -561,10 +578,23 @@
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.4.tgz",
"integrity": "sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
"cpu": [
"riscv64"
],
@ -574,10 +604,23 @@
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.4.tgz",
"integrity": "sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
"cpu": [
"x64"
],
@ -588,9 +631,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.4.tgz",
"integrity": "sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
"cpu": [
"x64"
],
@ -601,9 +644,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.4.tgz",
"integrity": "sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
"cpu": [
"arm64"
],
@ -614,9 +657,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.4.tgz",
"integrity": "sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
"cpu": [
"ia32"
],
@ -627,9 +670,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.4.tgz",
"integrity": "sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
"cpu": [
"x64"
],
@ -640,9 +683,9 @@
]
},
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"dev": true
},
"node_modules/@types/lodash": {
@ -968,6 +1011,11 @@
"node": ">= 8"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
@ -979,11 +1027,11 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dependencies": {
"follow-redirects": "^1.15.4",
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@ -1011,12 +1059,12 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@ -1208,9 +1256,9 @@
}
},
"node_modules/esbuild": {
"version": "0.19.11",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.11.tgz",
"integrity": "sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==",
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true,
"hasInstallScript": true,
"bin": {
@ -1220,29 +1268,29 @@
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.19.11",
"@esbuild/android-arm": "0.19.11",
"@esbuild/android-arm64": "0.19.11",
"@esbuild/android-x64": "0.19.11",
"@esbuild/darwin-arm64": "0.19.11",
"@esbuild/darwin-x64": "0.19.11",
"@esbuild/freebsd-arm64": "0.19.11",
"@esbuild/freebsd-x64": "0.19.11",
"@esbuild/linux-arm": "0.19.11",
"@esbuild/linux-arm64": "0.19.11",
"@esbuild/linux-ia32": "0.19.11",
"@esbuild/linux-loong64": "0.19.11",
"@esbuild/linux-mips64el": "0.19.11",
"@esbuild/linux-ppc64": "0.19.11",
"@esbuild/linux-riscv64": "0.19.11",
"@esbuild/linux-s390x": "0.19.11",
"@esbuild/linux-x64": "0.19.11",
"@esbuild/netbsd-x64": "0.19.11",
"@esbuild/openbsd-x64": "0.19.11",
"@esbuild/sunos-x64": "0.19.11",
"@esbuild/win32-arm64": "0.19.11",
"@esbuild/win32-ia32": "0.19.11",
"@esbuild/win32-x64": "0.19.11"
"@esbuild/aix-ppc64": "0.21.5",
"@esbuild/android-arm": "0.21.5",
"@esbuild/android-arm64": "0.21.5",
"@esbuild/android-x64": "0.21.5",
"@esbuild/darwin-arm64": "0.21.5",
"@esbuild/darwin-x64": "0.21.5",
"@esbuild/freebsd-arm64": "0.21.5",
"@esbuild/freebsd-x64": "0.21.5",
"@esbuild/linux-arm": "0.21.5",
"@esbuild/linux-arm64": "0.21.5",
"@esbuild/linux-ia32": "0.21.5",
"@esbuild/linux-loong64": "0.21.5",
"@esbuild/linux-mips64el": "0.21.5",
"@esbuild/linux-ppc64": "0.21.5",
"@esbuild/linux-riscv64": "0.21.5",
"@esbuild/linux-s390x": "0.21.5",
"@esbuild/linux-x64": "0.21.5",
"@esbuild/netbsd-x64": "0.21.5",
"@esbuild/openbsd-x64": "0.21.5",
"@esbuild/sunos-x64": "0.21.5",
"@esbuild/win32-arm64": "0.21.5",
"@esbuild/win32-ia32": "0.21.5",
"@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/escape-html": {
@ -1256,9 +1304,9 @@
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
@ -1280,9 +1328,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
@ -1378,6 +1426,14 @@
"process": "^0.11.10"
}
},
"node_modules/highlight.js": {
"version": "11.11.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/immutable": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
@ -1482,6 +1538,14 @@
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
"integrity": "sha512-ps3I9jAdNtRpJrbBvQjpzyFbss/skHqzS+eu4RxKLaEAtFqkjZaB6TZMSivPbLxf4K7VI4SjR0P5mRCX5+Q25A=="
},
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@ -1548,6 +1612,27 @@
"node": ">=12"
}
},
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="
},
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
@ -1726,9 +1811,9 @@
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@ -1762,9 +1847,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.33",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
"version": "8.4.47",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"funding": [
{
"type": "opencollective",
@ -1781,8 +1866,8 @@
],
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
"picocolors": "^1.1.0",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@ -1801,6 +1886,14 @@
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"engines": {
"node": ">=6"
}
},
"node_modules/qrcode": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz",
@ -1849,12 +1942,12 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"node_modules/rollup": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.4.tgz",
"integrity": "sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==",
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
"@types/estree": "1.0.6"
},
"bin": {
"rollup": "dist/bin/rollup"
@ -1864,19 +1957,22 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.9.4",
"@rollup/rollup-android-arm64": "4.9.4",
"@rollup/rollup-darwin-arm64": "4.9.4",
"@rollup/rollup-darwin-x64": "4.9.4",
"@rollup/rollup-linux-arm-gnueabihf": "4.9.4",
"@rollup/rollup-linux-arm64-gnu": "4.9.4",
"@rollup/rollup-linux-arm64-musl": "4.9.4",
"@rollup/rollup-linux-riscv64-gnu": "4.9.4",
"@rollup/rollup-linux-x64-gnu": "4.9.4",
"@rollup/rollup-linux-x64-musl": "4.9.4",
"@rollup/rollup-win32-arm64-msvc": "4.9.4",
"@rollup/rollup-win32-ia32-msvc": "4.9.4",
"@rollup/rollup-win32-x64-msvc": "4.9.4",
"@rollup/rollup-android-arm-eabi": "4.24.0",
"@rollup/rollup-android-arm64": "4.24.0",
"@rollup/rollup-darwin-arm64": "4.24.0",
"@rollup/rollup-darwin-x64": "4.24.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
"@rollup/rollup-linux-arm-musleabihf": "4.24.0",
"@rollup/rollup-linux-arm64-gnu": "4.24.0",
"@rollup/rollup-linux-arm64-musl": "4.24.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
"@rollup/rollup-linux-riscv64-gnu": "4.24.0",
"@rollup/rollup-linux-s390x-gnu": "4.24.0",
"@rollup/rollup-linux-x64-gnu": "4.24.0",
"@rollup/rollup-linux-x64-musl": "4.24.0",
"@rollup/rollup-win32-arm64-msvc": "4.24.0",
"@rollup/rollup-win32-ia32-msvc": "4.24.0",
"@rollup/rollup-win32-x64-msvc": "4.24.0",
"fsevents": "~2.3.2"
}
},
@ -1962,13 +2058,18 @@
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/spark-md5": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz",
"integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="
},
"node_modules/string-split-by": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string-split-by/-/string-split-by-1.0.0.tgz",
@ -2013,6 +2114,11 @@
"node": ">=8.0"
}
},
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="
},
"node_modules/url-toolkit": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz",
@ -2026,6 +2132,10 @@
"node": ">= 0.8"
}
},
"node_modules/video_ca": {
"resolved": "",
"link": true
},
"node_modules/video.js": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-8.9.0.tgz",
@ -2076,14 +2186,14 @@
}
},
"node_modules/vite": {
"version": "5.0.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.0.11.tgz",
"integrity": "sha512-XBMnDjZcNAw/G1gEiskiM1v6yzM4GE5aMGvhWTlHAYYhxb7S3/V1s3m2LDHa8Vh6yIWYYB0iJwsEaS523c4oYA==",
"version": "5.4.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
"integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"dev": true,
"dependencies": {
"esbuild": "^0.19.3",
"postcss": "^8.4.32",
"rollup": "^4.2.0"
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
"rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
@ -2102,6 +2212,7 @@
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
@ -2119,6 +2230,9 @@
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"stylus": {
"optional": true
},

View File

@ -13,9 +13,13 @@
"cors": "^2.8.5",
"crypto-js": "^4.2.0",
"element-plus": "^2.4.4",
"highlight.js": "^11.11.1",
"js-cookie": "^3.0.5",
"js-md5": "^0.8.3",
"markdown-it": "^14.1.0",
"qrcode": "^1.5.3",
"spark-md5": "^3.0.2",
"video_ca": "file:",
"video.js": "^8.9.0",
"vue": "^3.3.11",
"vue-cookies": "^1.8.3",

103
src/api/chat.js Normal file
View File

@ -0,0 +1,103 @@
import request from '@/utils/request.js'
export const getFriendListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/im/get_friend_list', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
}
);
}
export const getGroupFriendListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/im/get_group_req_user', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
}
);
}
export const getFriendReqService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
request.defaults.headers["token"] = Data.token.value;
return request.post('/im/get_friend_request', params, {
headers: {
'token': Data.token,
}
})
}
export const getGroupUsersListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/im/get_group_users_info', params, {
headers: {
'token': data.token, // 将 token <20><>换为您的令牌值
}
}
);
}
export const getMessageService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/im/get_message', params, {
headers: {
'token': data.token // 将 token 替换为您的令牌值
}
}
);
};
export const sendMessageService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/im/send_message', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
}
);
};
export const addGroupService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/im/create_group', params, { "headers": { 'token': data.token },'Content-Type': 'application/json' });
}

View File

@ -1,65 +1,95 @@
import request from '@/utils/request.js'
import request from '@/utils/request.js';
import request_aliyun from '@/utils/aliyun_erver.js';
import { createRequestInstance } from '@/utils/req_base.js';
export const runCIDService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == 'token') continue;
params.append(key, data[key])
}
return request.post('/cid/run', params, { "headers": { 'token': data.token } });
let request1 = getRequest();
let token = data.token;
const { token: _, ...requestData } = data;
return request1.post('/cid/run', requestData, { "headers": { 'token': token } });
}
export const updateCIDService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if (key == 'token') continue;
params.append(key, data[key])
}
return request.post('/cid/update', params, { "headers": { 'token': data.token } });
// const params = new URLSearchParams();
// for (let key in data) {
// if (key == 'token') continue;
// params.append(key, data[key])
// }
let request1 = getRequest();
let token = data.token;
const { token: _, ...requestData } = data;
return request1.post('/cid/update', requestData, { "headers": { 'token': token } });
}
export const deleteCIDService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
params.append(key, data[key])
}
return request.post('/cid/delete', params, { "headers": { 'token': data.token } });
// const params = new URLSearchParams();
// for (let key in data) {
// params.append(key, data[key])
// }
let request1 =getRequest();
let token = data.token;
const { token: _, ...requestData } = data;
return request1.post('/cid/delete', requestData, { "headers": { 'token': token } });
}
export const addCIDService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
params.append(key, data[key])
}
return request.post('/cid/create', params, { "headers": { 'token': data.token },'Content-Type': 'application/json' });
// const params = new URLSearchParams();
// for (let key in data) {
// params.append(key, data[key])
// }
let request1 = getRequest();
let token = data.token;
delete data.token;
return request1.post('/cid/create', data, { "headers": { 'token': token }, 'Content-Type': 'application/json' });
}
export const getCIDListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/cid/list', params, {
let request1 = getRequest();
let token = data.token;
const { token: _, ...requestData } = data;
return request1.post('/cid/list', requestData, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
'token': token, // 将 token 替换为您的令牌值
}
}
);
// request.headers["Content-Type"] = "application/json";
}
export const getCIDLogListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/cid/log', params, {
let request1 = getRequest();
let token = data.token;
const { token: _, ...requestData } = data;
return request1.post('/cid/log', requestData, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
'token': token, // 将 token 替换为您的令牌值
}
}
);
}
function getRequest() {
let server = localStorage.getItem('cid_server');
let request1 = null;
if (server === "tx.ljsea.top") {
request1 = request;
} else if (server === "js.ljsea.top") {
request1 = request_aliyun;
}else{
console.log("Using custom server:", server);
request1 = createRequestInstance("https://"+server)
}
return request1;
}
export function getCIDRuningListService(data) {
let request1 = getRequest();
let path = '/cid/running?type=' + data.type;
return request1.get(path, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
})
}

View File

@ -1,45 +1,50 @@
import request from '@/utils/request.js'
import request2 from '@/utils/gs_req.js';
export const restartDeviceService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/device/restart', params, { "headers": { 'token': data.token } });
return request2.post('/device/restart', params, { "headers": { 'token': data.token } });
}
export const updateDeviceService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/device/update_device', params, { "headers": { 'token': data.token } });
return request2.post('/device/update_device', params, { "headers": { 'token': data.token } });
}
export const deleteDeviceService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/device/delete_device', params, { "headers": { 'token': data.token } });
return request2.post('/device/delete_device', params, { "headers": { 'token': data.token } });
}
export const addDeviceService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/device/add_device', params, { "headers": { 'token': data.token },'Content-Type': 'application/json' });
return request2.post('/device/add_device', params, { "headers": { 'token': data.token },'Content-Type': 'application/json' });
}
export const getDeviceListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/device/get_device_list', params, {
request2.defaults.headers["token"] = data.token.value;
return request2.post('/device/get_device_list', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}

71
src/api/file.js Normal file
View File

@ -0,0 +1,71 @@
import request from '@/utils/request.js'
import { createRequestInstance } from '@/utils/req_base.js';
import request_aliyun from '@/utils/aliyun_erver.js';
export const updateConfigFileService = (data) => {
let params={};
for (let key in data) {
if (key === 'token') continue;
params[key] = data[key];
}
let request1 = getRequest();
return request1.post('/file/config_update', params, { "headers": { 'token': data.token } });
}
export const deleteConfigFileService = (data) => {
let request1 = getRequest();
return request1.post('/file/config_delete', data, { "headers": { 'token': data.token } });
}
export const addConfigFileService = (data) => {
let params={};
for (let key in data) {
if (key === 'token') continue;
params[key] = data[key];
}
let request1 = getRequest();
return request1.post('/file/config_add', params, { "headers": { 'token': data.token },'Content-Type': 'application/json' });
}
export const getConfigFileListService = (data) => {
let params={};
for (let key in data) {
if (key === 'token') continue;
params[key] = data[key];
}
// request.headers["Content-Type"] = "application/json
let request1 = getRequest();
request1.defaults.headers["token"] = data.token.value;
return request1.post('/file/config_search', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
}
);
}
// function getRequest() {
// let server = localStorage.getItem('config_file_server');
// let request1 = null;
// if (server === "tx.ljsea.top") {
// request1 = request;
// } else {
// request1 = request2;
// }
// return request1;
// }
function getRequest() {
let server = localStorage.getItem('config_file_server');
let request1 = null;
if (server === "tx.ljsea.top") {
request1 = request;
} else if (server === "js.ljsea.top") {
request1 = request_aliyun;
}else{
console.log("Using custom server:", server);
request1 = createRequestInstance("https://"+server)
}
return request1;
}

62
src/api/group.js Normal file
View File

@ -0,0 +1,62 @@
import request from '@/utils/request.js'
export const deleteGroupService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/device/delete_device', params, { "headers": { 'token': data.token } });
}
export const updateGroupService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/im/update_group', params, { "headers": { 'token': data.token } });
}
export const addDeviceService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/device/add_device', params, { "headers": { 'token': data.token },'Content-Type': 'application/json' });
}
export const getGroupListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/im/get_group', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
}
);
}
export const getGroupReqService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/im/get_group', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
}
);
}

View File

@ -3,6 +3,7 @@ import request from '@/utils/request.js'
export const getImKeyService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/im/get_imKey', params,{

45
src/api/shell.js Normal file
View File

@ -0,0 +1,45 @@
import request from '@/utils/request.js'
export const updateConfigShellService = (data) => {
const params = new URLSearchParams();
const jsonString = encodeURIComponent(JSON.stringify(data));
params.append('data', jsonString);
return request.post('/shell/update', params, { "headers": { 'token': data.token } });
}
export const deleteConfigShellService = (data) => {
let reqData={
"shells": data.shells,
}
return request.post('/shell/delete', reqData, { "headers": { 'token': data.token } });
}
export const addConfigShellService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key === 'token'){
continue;
}
params.append(key, data[key])
}
return request.post('/shell/create', params, { "headers": { 'token': data.token },'Content-Type': 'application/json' });
}
export const getConfigShellListService = (data) => {
const params = new URLSearchParams();
for (let d in data) {
if(d == "token") continue;
params.append(d, data[d]);
}
// request.headers["Content-Type"] = "application/json
let request1 = request;
request1.defaults.headers["token"] = data.token.value;
return request1.post('/shell/list', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}
}
);
}

71
src/api/tool.js Normal file
View File

@ -0,0 +1,71 @@
import request from '@/utils/request.js'
import request2 from '@/utils/gs_req.js';
export const GetRedisInfoService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
let request1 = getRequest();
return request1.post('/tool/get_redis', params,{
headers: {
'token': Data.token, // 闂佽绻愭蹇涘箯閿燂拷 token 闂備礁鎼ú锔锯偓绗涘啰鏆﹂柛娆忣槺閳绘棃鏌i幋鐏活亝绂嶉崼鏇熺厽闁靛ǹ鍎遍褔鏌熼煬鎻掆偓婵嬪箖瑜忔禒锔炬喆閿濆懍澹曢梺璺ㄥ櫐閹凤拷
}
})
}
function getRequest() {
let server = localStorage.getItem('cid_server');
let request1 = null;
if (server === "tx.ljsea.top") {
request1 = request;
} else {
request1 = request2;
}
return request1;
}
export const UploadFileService = (formData,token) => {
//let request1 = getRequest();
return request.post('/tool/upload', formData,{
headers: {
'Content-Type': 'multipart/form-data',
'token': token,
}
})
}
export const GetFileInfoByMd5Service = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
//let request1 = getRequest();
return request.post('/tool/file_list', params,{
headers: {
'token': Data.token,
}
})
}
export const GetMonitorDeviceInfoService = (Data) => {
return request.get('/tool/get_monitor_list')
}
export const UpdateMonitorDeviceInfoService = (Data) => {
return request.post('/tool/update_monitor', Data,{
headers: {
'token': Data.token, // 闂佽绻愭蹇涘箯閿燂拷 token 闂備礁鎼ú锔锯偓绗涘啰鏆﹂柛娆忣槺閳绘棃鏌i幋鐏活亝绂嶉崼鏇熺厽闁靛ǹ鍎遍褔鏌熼煬鎻掆偓婵嬪箖瑜忔禒锔炬喆閿濆懍澹曢梺璺ㄥ櫐閹凤拷
}
})
}
export const DelMonitorDeviceInfoService = (Data) => {
return request.post('/tool/del_monitor', Data,{
headers: {
'token': Data.token, // 闂佽绻愭蹇涘箯閿燂拷 token 闂備礁鎼ú锔锯偓绗涘啰鏆﹂柛娆忣槺閳绘棃鏌i幋鐏活亝绂嶉崼鏇熺厽闁靛ǹ鍎遍褔鏌熼煬鎻掆偓婵嬪箖瑜忔禒锔炬喆閿濆懍澹曢梺璺ㄥ櫐閹凤拷
}
})
}

View File

@ -1,4 +1,4 @@
import request from '@/utils/request.js'
import request from '@/utils/uc_req.js';
import md5 from 'js-md5';
export const loginService = (loginData) => {
@ -6,7 +6,7 @@ export const loginService = (loginData) => {
loginData = loginData._value;
for (let key in loginData) {
if (key === "username") {
//正则表达式判断邮箱
//濮濓絽鍨悰銊ㄦ彧瀵繐鍨介弬顓㈠仏缁狅拷
if (RegExp(/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/).test(loginData[key])) {
loginData['email'] = loginData[key]
loginData[key] = ''
@ -40,14 +40,122 @@ export const getUUIDService = (registerData) => {
return request.post('/user/uuid', params)
}
export const addGroupRequestService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/im/send_message', params,{
headers: {
'token': Data.token, // 鐏忥拷 token 閺囨寧宕叉稉鐑樺亶閻ㄥ嫪鎶ら悧灞解偓锟<E58193>
}
})
}
export const getFriendReqService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/im/get_friend_request', params, {
headers: {
'token': Data.token, // 鐏忥拷 token 閺囨寧宕叉稉鐑樺亶閻ㄥ嫪鎶ら悧灞解偓锟<E58193>
}
})
}
export const GetUserInfoService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/user/info', params, {
headers: {
'Authorization': "Bearer " + Data.token ,
}
})
}
//閸掔娀娅庢總钘夊几閹存牞鈧懐鍏㈢紒锟<E7B492>
export const DelFGService =(Data) =>{
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/im/del_friend_or_group', params, {
headers: {
'token': Data.token, // 鐏忥拷 token 閺囨寧宕叉稉鐑樺亶閻ㄥ嫪鎶ら悧灞解偓锟<E58193>
}
})
}
export const updateUserInfoService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/user/update', params, {
headers: {
'token': Data.token, // 鐏忥拷 token 閿熸枻鎷烽幑顫礋閹劎娈戞禒銈囧閸婏拷
}
})
}
export const acceptInviteService =(Data)=> {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/im/accept_invite', params, {
headers: {
'token': Data.token, // 鐏忥拷 token 閺囨寧宕叉稉鐑樺亶閻ㄥ嫪鎶ら悧灞解偓锟<E58193>
}
})
}
export const rejectInviteService =(Data)=> {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/im/reject_invite', params, {
headers: {
'token': Data.token, // 鐏忥拷 token 閺囨寧宕叉稉鐑樺亶閻ㄥ嫪鎶ら悧灞解偓锟<E58193>
}
})
}
export const SearchUserService = (Data) => {
const params = new URLSearchParams();
for (let key in Data) {
if(key == "token") continue;
params.append(key, Data[key])
}
return request.post('/user/search', params,{
headers: {
'token': Data.token, // 将 token 替换为您的令牌值
'token': Data.token, // 鐏忥拷 token 閺囨寧宕叉稉鐑樺亶閻ㄥ嫪鎶ら悧灞解偓锟<E58193>
}
})
}
export const getUserTokenCode = (Data) => {
return request.get('/user/get_token_code', {
headers: {
'Authorization': `Bearer ${Data.token}`, // 使用 Bearer 认证方式
}
})
}
export const getTokenByCode = (Data) => {
let url = '/user/get_token_by_code' + "?code=" + Data.code
return request.get(url, {
headers: {
'Authorization': `Bearer ${Data.token}`, // 使用 Bearer 认证方式
}
})
}

View File

@ -1,18 +1,29 @@
import request from '@/utils/request.js'
import request2 from '@/utils/gs_req.js';
export const playVideoService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/video', params, Headers = { 'Accept': 'application/vnd.apple.mpegurl','token': data.token });
return request2.post('/video', params, Headers = { 'Accept': 'application/vnd.apple.mpegurl','token': data.token });
}
export const delayVideoService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request.post('/video/delay', params, { headers : {'token': data.token }});
return request2.post('/video/delay', params, { headers : {'token': data.token }});
}
export const deleteVideoService = (data) => {
const params = new URLSearchParams();
for (let key in data) {
if(key == "token") continue;
params.append(key, data[key])
}
return request2.post('/video/delete', params, { headers : {'token': data.token }});
}
export const quashVideoService = (data) => {
@ -20,7 +31,20 @@ export const quashVideoService = (data) => {
for (let key in data) {
params.append(key, data[key])
}
return request.post('/video/quash_option', params, { headers : {'token': data.token }});
return request2.post('/video/quash_option', params, { headers : {'token': data.token }});
}
function getTimeString(time) {
let date = new Date(time);
// 提取年、月、日、时、分、秒
const year = date.getFullYear();
const month = (''+(date.getMonth() + 1)).slice(-2); // 月份是从0开始的所以要加1
const day = ('0' + date.getDate()).slice(-2);
const hour = ('0' + date.getHours()).slice(-2);
const minute = ('0' + date.getMinutes()).slice(-2);
const second = ('0' + date.getSeconds()).slice(-2);
// 重新组合并返回格式化的日期时间字符串
return `${year}/${month}/${day} ${hour}:${minute}:${second}`;
}
export const getVideoListService = (data) => {
@ -29,16 +53,29 @@ export const getVideoListService = (data) => {
for (let key in data) {
if (key === 'entrydate' && data[key].length > 0) {
if (hour === "33") {
let begin = data[key][0].toLocaleString().slice(0, 10) + " 00:00:00"; //begin=data[key][0].toLocaleString().slice(0,10)+hour+":00:00";
params.append("begin", begin);
let end = data[key][1].toLocaleString().slice(0, 10) + " 23:59:59";
params.append("end", end);
let b1=Date.parse(data[key][0]);
let b2=Date.parse(data[key][1]);
let begin = getTimeString(b1).toString().slice(0, 10) + " 00:00:00"; //begin=data[key][0].toLocaleString().slice(0,10)+hour+":00:00";
//alert(begin)
let end = getTimeString(b2).toString().slice(0, 10) + " 23:59:59";
//转为时间戳
let end_date = Date.parse(end)/1000;
let begin_date = Date.parse(begin)/1000;
params.append("begin", begin_date);
params.append("end", end_date);
continue;
} else {
let begin = data[key][0].toLocaleString().slice(0, 10) + hour + ":00:00"; //begin=data[key][0].toLocaleString().slice(0,10)+hour+":00:00";
params.append("begin", begin);
let end = data[key][1].toLocaleString().slice(0, 10) + hour + ":59:59";
params.append("end", end);
let b1=Date.parse(data[key][0]);
let b2=Date.parse(data[key][1]);
let begin = getTimeString(b1).toString().slice(0, 10) + " "+hour + ":00:00"; //begin=data[key][0].toLocaleString().slice(0,10)+hour+":00:00";
//params.append("begin", begin);
let end = getTimeString(b2).toString().slice(0, 10) + " "+hour + ":59:59";
console.log("begin:",begin);
let end_date = Date.parse(end)/1000;
let begin_date = Date.parse(begin)/1000;
params.append("begin", begin_date);
params.append("end", end_date);
continue;
}
@ -46,8 +83,8 @@ export const getVideoListService = (data) => {
params.append(key, data[key])
}
// request.headers["Content-Type"] = "application/json";
request.defaults.headers["token"] = data.token.value;
return request.post('/video/get_video_list', params, {
request2.defaults.headers["token"] = data.token.value;
return request2.post('/video/get_video_list', params, {
headers: {
'token': data.token, // 将 token 替换为您的令牌值
}

BIN
src/assets/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
src/assets/img/img.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
src/assets/img/login-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

1
src/assets/img/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 144.08 128.61"><title>&#x8D44;&#x6E90; 82</title><path d="M72.23 128.61c-7.1-.23-11.51-3.72-14.76-9.36C48 102.87 38.43 86.59 29.1 70.16a36 36 0 0 1-4.47-11.35A14.61 14.61 0 0 1 34 42.51c7.49-2.71 15.71-.21 19.67 6.43 7.52 12.56 14.77 25.27 22.12 37.92 3 5.17 5.89 10.43 9 15.51 5 8 3.45 18-4.22 23.31-2.3 1.62-5.52 1.99-8.34 2.93z" fill="#2ef2e9"/><path d="M72.66.33c6-.57 10.39 2.6 13.51 8C95.61 24.69 105 41.1 114.52 57.4c3.9 6.65-.28 17.13-6.39 20.44-8.93 4.83-17.88 1.28-21.86-5.62C76.82 55.86 67.14 39.62 58.11 23 52.06 12 59.61.24 72.66.33z" fill="#fa6663"/><path d="M144.08 15.83c-.58 8.62-6.73 15.57-15.51 15.66-9.31.09-16.87-7-16.95-15.62S119 0 127.87 0c9.13.09 16.22 7 16.21 15.83z" fill="#fbb355"/><path d="M16.24 31.5C7 31.33-.19 24.42 0 15.8.19 7.5 7.19-.06 14.64 0c10.53.08 18.27 6.73 17.61 15.9-.64 8.96-6.25 15.28-16.01 15.6z" fill="#8a56c2"/></svg>

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -6,8 +6,12 @@ import 'element-plus/dist/index.css'
import App from './App.vue'
import router from '@/router'
import globalData from '@/utils/global.js'
import Menu from '@/views/Menu.vue'
// import VideoPlayer from '@/views/Video.vue'
const app=createApp(App);
app.component('Menu',Menu);
// app.component('VideoPlayer',VideoPlayer);
app.provide('globalData',globalData);
app.use(router).use(ElementPlus).mount('#app');

View File

@ -9,6 +9,14 @@ import ImVue from "@/views/Im.vue";
import CIDListVue from "@/views/CIDList.vue";
import CIDLog from "@/views/CIDLog.vue";
import DeviceRealVP from "@/views/DeviceRealVP.vue";
import Chat from "@/views/Chat.vue"
import Group from "@/views/Group.vue"
import File from "@/views/FileList.vue"
import Shell from "@/views/ShellList.vue"
import callback from "@/views/callback.vue";
import projectSelect from "@/views/project-select.vue";
const routes = [
{
@ -51,11 +59,41 @@ const routes = [
name: 'CID',
component: CIDListVue
},
{
path: "/group",
name: "Group",
component: Group
},
{
path: '/cidlog',
name: 'CIDLog',
component: CIDLog
},
{
path:"/chat",
name:"chat",
component:Chat
},
{
path:"/file",
name:"file",
component:File
},
{
path:"/shell",
name:"shell",
component:Shell
},
{
path: '/callback',
name: 'callback',
component: callback
},
{
path: '/projectSelect',
name: 'projectSelect',
component: projectSelect
},
{
path: '/',
redirect: '/login'

46
src/utils/aliyun_erver.js Normal file
View File

@ -0,0 +1,46 @@
import axios from "axios";
import router from "@/router/index.js";
import { ElMessage } from 'element-plus';
//const baseURL = "https://gep.ljsea.xyz/";
//const baseURL= "http://localhost:8083";
//const baseURL="https://pm.ljsea.top";
const baseURL2 = "https://js.ljsea.top/";
const request_aliyun = axios.create({
baseURL: baseURL2,
});
request_aliyun.interceptors.response.use(
result => {
if(result.status!==200 ){
router.push("/login")
}
if(result.data.message==="NOT_LOGIN"|| [2, 3, 4].includes(result.data.code)){
//alert("登录失效,请重新登录!")
ElMessage.error('登录失效,请重新登录!');
localStorage.removeItem("token");
router.push("/login")
return
}
if(result.data.code == 7){
//alert("该用户已存在,请重新输入!");
ElMessage.error('该用户已存在,请重新输入!');
return null
}
if(result.data.code == 1){
//alert("请求失败,请稍后重试!");
ElMessage.error('请求失败,请稍后重试!');
}else{
return result.data
}
},
error => {
//alert("请求失败,请稍后重试!");
ElMessage.error('请求失败,请稍后重试!');
return Promise.reject(error);
}
)
export default request_aliyun;

93
src/utils/gs_req.js Normal file
View File

@ -0,0 +1,93 @@
import axios from "axios";
import router from "@/router/index.js";
import { ElMessage } from 'element-plus';
//const baseURL = "https://gep.ljsea.xyz/";
//const baseURL= "http://localhost:8083";
//const baseURL="https://pm.ljsea.top";
const baseURL = "https://gep.ljsea.top/";
let isRefreshing = false;
let requests = [];
const request = axios.create({
baseURL: baseURL,
});
// 请求拦截器 - 添加token
request.interceptors.request.use(
config => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
config.headers.token = token;
}
return config;
}
);
// 响应拦截器
request.interceptors.response.use(
result => {
if(result.status !== 200) {
router.push("/login");
}
if(result.data.message === "NOT_LOGIN" || [2, 3, 4].includes(result.data.code)) {
// 检测到token过期
if (isRefreshing == false) {
isRefreshing = true;
// 这里需要替换为实际的refresh token请求
return axios.post('https://uc.ljsea.top/user/refresh_token', {
refresh_token: localStorage.getItem("refresh_token")
},{
headers: {
'Authorization': `Bearer ${localStorage.getItem("refresh_token")}`
}
}).then(res => {
const token = res.data["data"]["access_token"];
localStorage.setItem("token", token);
//alert("token: " + token);
// 重试所有挂起的请求
requests.forEach(cb => cb(token));
requests = [];
isRefreshing = false;
// 重试当前请求
const config = result.config;
config.headers.Authorization = `Bearer ${token}`;
return request(config);
}).catch(err => {
// 刷新token失败跳转登录
ElMessage.error('登录已过期,请重新登录!');
router.push("/login");
return Promise.reject(err);
});
} else if (isRefreshing) {
// 正在刷新token将请求放入队列
return new Promise(resolve => {
requests.push(token => {
//alert("new token: " + token);
result.config.headers.Authorization = `Bearer ${token}`;
result.config.headers.token = token;
resolve(request(result.config));
});
});
}
}
if(result.data.code == 7) {
ElMessage.error('该用户已存在,请重新输入!');
return null;
}
if(result.data.code == 1) {
ElMessage.error('请求失败,请稍后重试!');
} else {
return result.data;
}
}
);
export default request;

99
src/utils/req_base.js Normal file
View File

@ -0,0 +1,99 @@
import axios from "axios";
import router from "@/router/index.js";
import { ElMessage } from 'element-plus';
let isRefreshing = false;
let requests = [];
// 错误处理函数
const handleResponseError = (result) => {
if (result.status !== 200) {
router.push("/login");
}
if (result.data.message === "NOT_LOGIN" || [2, 3, 4].includes(result.data.code)) {
// 检测到token过期
if (isRefreshing == false) {
isRefreshing = true;
// 这里需要替换为实际的refresh token请求
return axios.post('https://uc.ljsea.top/user/refresh_token', {
refresh_token: localStorage.getItem("refresh_token")
},{
headers: {
'Authorization': `Bearer ${localStorage.getItem("refresh_token")}`
}
}).then(res => {
const token = res.data["data"]["access_token"];
localStorage.setItem("token", token);
// 重试所有挂起的请求
requests.forEach(cb => cb(token));
requests = [];
isRefreshing = false;
// 重试当前请求
const config = result.config;
config.headers.Authorization = `Bearer ${token}`;
return request(config);
}).catch(err => {
// 刷新token失败跳转登录
ElMessage.error('登录已过期,请重新登录!');
router.push("/login");
return Promise.reject(err);
});
} else if (isRefreshing) {
// 正在刷新token将请求放入队列
return new Promise(resolve => {
requests.push(token => {
result.config.headers.Authorization = `Bearer ${token}`;
resolve(request(result.config));
});
});
}
}
if (result.data.code === 7) {
ElMessage.error('该用户已存在,请重新输入!');
return null;
}
if (result.data.code === 1) {
ElMessage.error('请求失败,请稍后重试!');
}
return result.data;
};
// 请求实例缓存
const instances = new Map();
// 请求工厂函数(单例模式)
export const createRequestInstance = (baseURL, config = {}) => {
// 检查是否已存在该域名的实例
if (instances.has(baseURL)) {
return instances.get(baseURL);
}
// 创建新实例
const instance = axios.create({
baseURL,
timeout: 10000, // 默认超时时间
headers: {
'Content-Type': 'application/json'
},
...config
});
// 添加响应拦截器
instance.interceptors.response.use(
result => handleResponseError(result),
error => {
ElMessage.error('请求失败,请稍后重试!');
return Promise.reject(error);
}
);
// 缓存实例
instances.set(baseURL, instance);
return instance;
};
// 默认导出原有的阿里云请求实例
export default createRequestInstance("https://tx.ljsea.top/");

View File

@ -1,39 +1,94 @@
import axios from "axios";
import router from "@/router/index.js";
const baseURL = "https://gep.ljsea.xyz/";
//const baseURL= "http://localhost:8082";
import { ElMessage } from 'element-plus';
//const baseURL = "https://gep.ljsea.top/";
const baseURL = "https://tx.ljsea.top/";
//const baseURL= "http://localhost:8083";
//const baseURL="https://pm.ljsea.top";
//const baseURL = "https://gep.ljsea.xyz/";
let isRefreshing = false;
let requests = [];
const request = axios.create({
baseURL: baseURL,
});
// 请求拦截器 - 添加token
request.interceptors.request.use(
config => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
config.headers.token = token;
}
return config;
}
);
// 响应拦截器
request.interceptors.response.use(
result => {
if(result.status !== 200) {
router.push("/login")
router.push("/login");
}
if(result.data.message==="NOT_LOGIN"||result.data.code==2 || result.data.code ===3 ||result.data.code ===4){
alert("登录失效,请重新登录!")
localStorage.removeItem("token");
router.push("/login")
return
if(result.data.message === "NOT_LOGIN" || [2, 3, 4].includes(result.data.code)) {
// 检测到token过期
if (isRefreshing == false) {
isRefreshing = true;
// 这里需要替换为实际的refresh token请求
return axios.post('https://uc.ljsea.top/user/refresh_token', {
refresh_token: localStorage.getItem("refresh_token")
},{
headers: {
'Authorization': `Bearer ${localStorage.getItem("refresh_token")}`
}
}).then(res => {
const token = res.data["data"]["access_token"];
localStorage.setItem("token", token);
//alert("token: " + token);
// 重试所有挂起的请求
requests.forEach(cb => cb(token));
requests = [];
isRefreshing = false;
// 重试当前请求
const config = result.config;
config.headers.Authorization = `Bearer ${token}`;
return request(config);
}).catch(err => {
// 刷新token失败跳转登录
ElMessage.error('登录已过期,请重新登录!');
router.push("/login");
return Promise.reject(err);
});
} else if (isRefreshing) {
// 正在刷新token将请求放入队列
return new Promise(resolve => {
requests.push(token => {
//alert("new token: " + token);
result.config.headers.Authorization = `Bearer ${token}`;
result.config.headers.token = token;
resolve(request(result.config));
});
});
}
}
if(result.data.code == 7) {
alert("该用户已存在,请重新输入!");
return null
ElMessage.error('该用户已存在,请重新输入!');
return null;
}
if(result.data.code == 1) {
alert("请求失败,请稍后重试!");
ElMessage.error('请求失败,请稍后重试!');
} else {
return result.data
return result.data;
}
},
error => {
alert("请求失败,请稍后重试!");
return Promise.reject(error);
}
)
request.interceptors.request.use(
);
)
export default request;

94
src/utils/uc_req.js Normal file
View File

@ -0,0 +1,94 @@
import axios from "axios";
import router from "@/router/index.js";
import { ElMessage } from 'element-plus';
//const baseURL = "https://gep.ljsea.top/";
const baseURL = "https://uc.ljsea.top/";
//const baseURL= "http://localhost:8083";
//const baseURL="https://pm.ljsea.top";
//const baseURL = "https://gep.ljsea.xyz/";
let isRefreshing = false;
let requests = [];
const request = axios.create({
baseURL: baseURL,
});
// 请求拦截器 - 添加token
request.interceptors.request.use(
config => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
config.headers.token = token;
}
return config;
}
);
// 响应拦截器
request.interceptors.response.use(
result => {
if(result.status !== 200) {
ElMessage.error('请求失败,请稍后重试!');
router.push("/login");
}
if(result.data.message === "NOT_LOGIN" || [2, 3, 4].includes(result.data.code)) {
// 检测到token过期
if (isRefreshing == false) {
isRefreshing = true;
// 这里需要替换为实际的refresh token请求
return axios.post('https://uc.ljsea.top/user/refresh_token', {
refresh_token: localStorage.getItem("refresh_token")
},{
headers: {
'Authorization': `Bearer ${localStorage.getItem("refresh_token")}`
}
}).then(res => {
const token = res.data["data"]["access_token"];
localStorage.setItem("token", token);
//alert("token: " + token);
// 重试所有挂起的请求
requests.forEach(cb => cb(token));
requests = [];
isRefreshing = false;
// 重试当前请求
const config = result.config;
config.headers.Authorization = `Bearer ${token}`;
return request(config);
}).catch(err => {
// 刷新token失败跳转登录
ElMessage.error('登录已过期,请重新登录!');
router.push("/login");
return Promise.reject(err);
});
} else if (isRefreshing) {
// 正在刷新token将请求放入队列
return new Promise(resolve => {
requests.push(token => {
//alert("new token: " + token);
result.config.headers.Authorization = `Bearer ${token}`;
result.config.headers.token = token;
resolve(request(result.config));
});
});
}
}
if(result.data.code == 7) {
ElMessage.error('该用户已存在,请重新输入!');
return null;
}
if(result.data.code == 1) {
ElMessage.error('请求失败,请稍后重试!');
} else {
return result.data;
}
}
);
export default request;

View File

@ -5,20 +5,28 @@ import { getCIDListService } from "@/api/cid.js";
import { runCIDService } from "@/api/cid.js";
import { addCIDService } from "@/api/cid.js";
import { deleteCIDService } from "@/api/cid.js";
import { updateCIDService } from "@/api/cid.js";
import { updateCIDService,getCIDRuningListService } from "@/api/cid.js";
import router from "@/router/index.js";
import Menu from "@/views/Menu.vue";
import {ElMessage, ElLoading} from "element-plus";
export default {
data() {
return {
tableLoading: false,
ip: "",
tableData: [],
timer: null, //
tokenData: {
server: localStorage.getItem("cid_server") || "gep.ljsea.xyz",
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
},
runningData: [],
runningDialogVisible: false,
addDialogVisible: false,
updateDialogVisible: false,
searchForm: {
@ -27,14 +35,23 @@ export default {
},
addForm: {
name: "",
time: 0,
url: "",
script: "",
token: localStorage.getItem("token"),
},
server_list: [
{ label: "gep.ljsea.top", value: "gep.ljsea.top" },
{ label: "gst.ljsea.top", value: "gst.ljsea.top" },
{ label: "tx.ljsea.top", value: "tx.ljsea.top" },
{ label: "js.ljsea.top", value: "js.ljsea.top" },
{label: "as.ljsea.top", value: "as.ljsea.top"},
],
updateForm: {
id:0,
cidtoken:"",
name: "",
time:0,
url: "",
script: "",
auth_id: -1,
@ -43,23 +60,42 @@ export default {
};
},
watch: {
// runningDialogVisible
runningDialogVisible(newVal) {
if (newVal) {
//
this.timer = setInterval(() => {
this.GetCIDRuningList();
}, 1000);
} else {
//
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
}
}
},
// methods
//
methods: {
async getDeviceList() {
async getCIDList() {
this.tableLoading = true;
let result = {};
try {
result = await getCIDListService(this.tokenData);
let data = result.data;
this.tableData = data;
} catch (e) {
console.log(e);
} finally {
this.tableLoading = false;
}
let data = result.data;
this.tableData = data;
},
onSubmit() {
getDeviceList({ token: token });
getCIDList({ token: token });
},
handleSizeChange() {
alert("每页记录数变化" + val);
@ -70,6 +106,12 @@ export default {
//
async runCID(index) {
const loading = ElLoading.service({
lock: true,
text: '执行中',
background: 'rgba(0, 0, 0, 0.7)',
});
try {
var id = this.tableData[index].ID;
var run_data = {
id: id,
@ -77,15 +119,17 @@ export default {
userId: this.tokenData.userId,
token: this.tokenData.token,
};
try {
var d_re = await runCIDService(run_data);
if (d_re.code == 0) {
alert("操作成功");
ElMessage.success("操作成功");
} else {
alert("操作失败");
ElMessage.error("操作失败");
}
} catch (e) {
console.log(e);
} finally {
loading.close();
this.tableLoading = false;
}
},
toRunCIDLog(index) {
@ -94,23 +138,36 @@ export default {
router.push("/cidlog");
},
async deleteCID(index) {
//
if (!confirm("是否删除")) {
return;
}
const loading = ElLoading.service({
lock: true,
text: '删除中',
background: 'rgba(0, 0, 0, 0.7)',
});
try {
var id = this.tableData[index].ID;
var delete_data = {
id: id,
userId: this.tokenData.userId,
token: this.tokenData.token,
};
try {
var d_re = await deleteCIDService(delete_data);
if (d_re.code == 0) {
alert("删除成功");
ElMessage.success("删除成功");
//
this.getDeviceList();
this.getCIDList();
} else {
alert("操作失败");
ElMessage.error("操作失败");
}
} catch (e) {
console.log(e);
} finally {
loading.close();
this.tableLoading = false;
}
},
async updateButtonCID(index) {
@ -118,37 +175,74 @@ export default {
this.updateForm.name = this.tableData[index].Name;
this.updateForm.url = this.tableData[index].Url;
this.updateForm.script = this.tableData[index].Script;
this.updateForm.time = this.tableData[index].Time;
this.updateForm.cidtoken = this.tableData[index].Token;
this.updateForm.id = id;
this.updateDialogVisible= true;
},
async addCID() {
this.addDialogVisible = false;
const loading = ElLoading.service({
lock: true,
text: '添加中',
background: 'rgba(0, 0, 0, 0.7)',
});
let result = {};
try {
this.addForm.time = parseInt(this.addForm.time);
result = await addCIDService(this.addForm);
if (result.code == 0) {
alert("添加成功");
ElMessage.success("添加成功");
this.getCIDList()
} else {
alert("添加失败");
ElMessage.error("添加失败");
}
} catch (e) {
console.log(e);
} finally {
loading.close();
this.tableLoading = false;
}
},
async updateCID() {
this.updateDialogVisible = false;
const loading = ElLoading.service({
lock: true,
text: '更新中',
background: 'rgba(0, 0, 0, 0.7)',
});
let result = {};
try {
this.updateForm.time = parseInt(this.updateForm.time);
result = await updateCIDService(this.updateForm);
if (result.code == 0) {
alert("修改成功");
this.getDeviceList()
ElMessage.success("修改成功");
this.getCIDList()
} else {
alert("修改失败");
ElMessage.error("修改失败");
}
} catch (e) {
console.log(e);
} finally {
loading.close();
this.tableLoading = false;
}
},
async GetCIDRuningList(){
let req = {
token: this.tokenData.token,
type: 0,
}
try{
let result = await getCIDRuningListService(req);
if(result.code == 0){
this.runningData = result.data;
this.runningDialogVisible = true;
}else{
ElMessage.error("获取失败");
}
}catch(e){
console.log(e)
}
},
async getIpClient() {
@ -161,6 +255,10 @@ export default {
console.error(error);
}
},
handleServerChange(){
localStorage.setItem("cid_server", this.tokenData.server);
this.getCIDList()
},
handleMenuSelect(val) {
router.push(val);
},
@ -187,38 +285,23 @@ export default {
router.push("/login");
}
// console.log("mounted");
await this.getIpClient();
this.getDeviceList();
this.getIpClient();
this.getCIDList();
},
//
beforeUnmount() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
};
</script>
<template>
<div>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/videoList')"
>视频列表</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/device')"
>设备管理</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/User')"
>用户</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/cid')"
>集成部署</el-button
>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>集成部署项目</el-header
@ -231,7 +314,7 @@ export default {
<el-button
class="el-button--danger"
type="primary"
@click="getDeviceList()"
@click="getCIDList()"
>查询</el-button
>
</el-form-item>
@ -240,6 +323,23 @@ export default {
>添加集成项目</el-button
>
</el-form-item>
<el-form-item>
<el-select allow-create filterable v-model="tokenData.server" @change="handleServerChange">
<el-option
v-for="item in server_list"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="GetCIDRuningList()"
>正在运行</el-button
>
</el-form-item>
<el-form-item>
<el-dialog
v-model="addDialogVisible"
@ -264,9 +364,20 @@ export default {
<el-form-item label="仓库地址" prop="device_ip">
<el-input v-model="addForm.url" style="width: 600px" autocomplete="on"></el-input>
</el-form-item>
<el-form-item label="定时执行时间" prop="time">
<el-select v-model="addForm.time">
<el-option label="30s" value="30"></el-option>
<el-option label="1分钟" value="60"></el-option>
<el-option label="1小时" value="3600"></el-option>
<el-option label="1天" value="86400"></el-option>
</el-select>
自定义时间
<el-input type="textarea" v-model="addForm.time" autocomplete="on" style="width: 600px" />
</el-form-item>
<el-form-item label="脚本内容" prop="device_status">
<el-input type="textarea" v-model="addForm.script" style="width: 600px" :autosize="{ minRows: 4, maxRows: 8 }" />
</el-form-item>
</el-form>
<!-- 底部区域 -->
<template #footer>
@ -311,7 +422,18 @@ export default {
</el-form-item>
<el-form-item label="外部回调Token" prop="device_status">
<el-input v-model="updateForm.cidtoken" style="width: 600px" />
回调地址https://gep.ljsea.xyz/cid/callback?token={{updateForm.cidtoken}}&id={{updateForm.id}}
回调地址https://{{tokenData.server}}/cid/callback?token={{updateForm.cidtoken}}&id={{updateForm.id}}
</el-form-item>
<el-form-item label="定时执行时间" prop="time">
<el-select v-model="updateForm.time">
<el-option label="30s" value="30"></el-option>
<el-option label="1分钟" value="60"></el-option>
<el-option label="1小时" value="3600"></el-option>
<el-option label="1天" value="86400"></el-option>
</el-select>
自定义时间
<el-input type="textarea" v-model="updateForm.time" autocomplete="on" style="width: 600px" />
</el-form-item>
</el-form>
<!-- 底部区域 -->
@ -326,11 +448,29 @@ export default {
</span>
</template>
</el-dialog>
<el-dialog
v-model="runningDialogVisible"
title="正在运行项目"
width="50%"
:before-close="handleClose"
>
<el-table
:data="runningData"
stripe
width="90%"
fit
>
<el-table-column prop="id" label="CID" width="150"></el-table-column>
<el-table-column prop="cid" label="名称" width="150"></el-table-column>
<el-table-column prop="start_time" label="开始时间" width="300">
</el-table-column>
</el-table>
</el-dialog>
</el-form-item>
</el-form>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="tableData" width="100%" border>
<el-table :data="tableData" width="100%" v-loading="tableLoading">
:row-style="this.tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
@ -346,11 +486,19 @@ export default {
<el-table-column
prop="Script"
label="脚本消息"
show-overflow-tooltip
width="250"
></el-table-column>
<el-table-column
prop="Token"
label="回调Token"
show-overflow-tooltip
width="100"
></el-table-column>
<el-table-column
prop="last_success"
label="上次成功"
show-overflow-tooltip
width="100"
></el-table-column>
<el-table-column label="操作" width="350">

View File

@ -7,12 +7,17 @@ import { addCIDService } from "@/api/cid.js";
import { deleteCIDService } from "@/api/cid.js";
import { updateCIDService } from "@/api/cid.js";
import router from "@/router/index.js";
import Menu from "@/views/Menu.vue";
export default {
data() {
return {
ip: "",
tableData: [],
currentPageData: [],
loading: false,
pageSize: 10,
currentPage: 1,
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
@ -34,26 +39,57 @@ export default {
// methods
//
methods: {
roundNumber(number, decimals) {
let num = 3.14159;
let result = Math.round(number * 100) / 100;
return result;
},
async getCIDLogList() {
let result = {};
this.loading = true;
try {
this.tokenData.id = parseInt(this.tokenData.id);
result = await getCIDLogListService(this.tokenData);
this.loading = false;
} catch (e) {
console.log(e);
this.loading = false;
}
let data = result.data;
for(var i=0;i<data.length;i++){
data[i].RunTime = Math.round(data[i].RunTime * 100) / 100;
}
this.tableData = data;
for(let i = 0;i<this.tableData.length;i++) {
this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt);
this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt)
//console.log('this.ConfigFileList:',this.ConfigFileList);
}
this.handleCurrentChange(1);
},
formattedTime(isoTime) {
const date = new Date(isoTime);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
onSubmit() {
getDeviceList({ token: token });
},
handleSizeChange() {
alert("每页记录数变化" + val);
handleSizeChange(val) {
this.pageSize = val;
},
handleCurrentChange() {
alert("页码发生变化" + val);
handleCurrentChange(val) {
this.currentPage = val;
this.currentPageData = this.tableData.slice(
(this.currentPage - 1) * this.pageSize,
this.currentPage * this.pageSize
);
},
//
@ -98,11 +134,18 @@ export default {
},
async updateButtonLogCID(index) {
this.updateDialogVisible = true;
var id = this.tableData[index].ID;
this.updateForm.create_time = this.tableData[index].CreatedAt;
this.updateForm.script = this.tableData[index].Script;
this.updateForm.end = this.tableData[index].Log;
this.updateForm.error = this.tableData[index].Error;
// var id = this.tableData[index].ID;
// this.updateForm.create_time = this.tableData[index].CreatedAt;
// this.updateForm.script = this.tableData[index].Script;
// this.updateForm.end = this.tableData[index].Log;
// this.updateForm.error = this.tableData[index].Error;
// this.updateForm.RunTime = this.tableData[index].RunTime;
var id = this.currentPageData[index].ID;
this.updateForm.create_time = this.currentPageData[index].CreatedAt;
this.updateForm.script = this.currentPageData[index].Script;
this.updateForm.end = this.currentPageData[index].Log;
this.updateForm.error = this.currentPageData[index].Error;
this.updateForm.RunTime = this.currentPageData[index].RunTime;
},
async getIpClient() {
try {
@ -140,7 +183,7 @@ export default {
router.push("/login");
}
// console.log("mounted");
await this.getIpClient();
this.getIpClient();
this.getCIDLogList();
},
};
@ -148,30 +191,7 @@ export default {
<template>
<div>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/videoList')"
>视频列表</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/device')"
>设备管理</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/User')"
>用户</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/cid')"
>集成部署</el-button
>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>集成部署项目日志{{ tokenData.id }}</el-header
@ -185,6 +205,7 @@ export default {
class="el-button--danger"
type="primary"
@click="getCIDLogList()"
:disabled="loading"
>刷新</el-button
>
</el-form-item>
@ -209,16 +230,29 @@ export default {
autocomplete="on"
style="width: 600px"
></el-input>
</el-form-item>
<el-col>
<el-form-item label="执行时间" prop="run_time">
<el-input
v-model="updateForm.RunTime"
autocomplete="on"
style="width: 100px"
></el-input>
</el-form-item>
</el-col>
<el-form-item label="脚本内容" prop="script">
<el-input type="textarea" v-model="updateForm.script" style="width: 600px" :autosize="{ minRows: 4, maxRows: 8 }" />
<el-input type="textarea" v-model="updateForm.script" style="width: 700px" :autosize="{ minRows: 4, maxRows: 8 }" />
</el-form-item>
<el-form-item label="执行结果" prop="end">
<el-input type="textarea" v-model="updateForm.end" style="width: 600px" :autosize="{ minRows: 4, maxRows: 8 }" />
<el-input type="textarea" v-model="updateForm.end" style="width: 700px" :autosize="{ minRows: 4, maxRows: 8 }" />
</el-form-item>
<el-col>
<el-form-item label="错误内容" prop="error">
<el-input type="textarea" v-model="updateForm.error" style="width: 600px" :autosize="{ minRows: 4, maxRows: 8 }" />
<el-input type="textarea" v-model="updateForm.error" style="width: 700px" :autosize="{ minRows: 4, maxRows: 8 }" />
</el-form-item>
</el-col>
</el-form>
<!-- 底部区域 -->
<template #footer>
@ -233,29 +267,42 @@ export default {
</el-form>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="tableData" width="100%" border>
<el-table
:data="currentPageData"
width="100%"
v-loading="loading"
element-loading-text="数据加载中..."
>
:row-style="this.tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="100"
show-overflow-tooltip
width="200"
></el-table-column>
<el-table-column
prop="Script"
label="执行脚本"
width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="Log"
label="运行日志"
width="180"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="Error"
label="错误信息"
width="250"
></el-table-column>
<el-table-column
prop="RunTime"
label="运行时间(s)"
width="80"
></el-table-column>
<el-table-column label="操作" width="350">
<template #default="scope">
<el-button
@ -271,14 +318,15 @@ export default {
<br />
<!-- 分页条 -->
<!-- Pagination 分页 -->
<!-- <el-pagination
background
layout="total,sizes, prev, pager, next, jumper"
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="1000"
></el-pagination> -->
:current-page="currentPage"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.length">
</el-pagination>
</el-main>
</el-container>
</el-container>

902
src/views/Chat.vue Normal file
View File

@ -0,0 +1,902 @@
<template>
<el-dialog
title="图片发送"
v-model="sendImgDialogVisible"
width="60%"
height="60%"
center
>
<!-- 图片输入 -->
<input type="file" @change="handleFileUpload" />
<el-button type="primary" size="default" @click="sendImageOrVideo"
>发送</el-button
>
</el-dialog>
<el-container
class="layout-container-demo"
style="height: 700px; width: 1000px"
>
<el-aside width="200px">
<el-input
placeholder="请输入用户姓名"
v-model="searchName"
@input="filterUsers"
></el-input>
<el-scrollbar>
<el-menu :default-openeds="['1', '3']">
<el-sub-menu index="1">
<template #title>
<el-icon> <message /> </el-icon>
</template>
<el-scrollbar height="300px">
<el-menu-item-group v-for="user in filteredUsers" :key="user.id">
<el-menu-item
:index="String(user.id)"
@click="handleGetMessage(user.id)"
style="height: 40px"
>
<el-avatar style="float: left" :src="user.avatar"></el-avatar>
{{ user.name }}
<span v-if="hasUnreadMsg[user.id]" class="unread-dot"></span>
</el-menu-item>
</el-menu-item-group>
</el-scrollbar>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><icon-menu /></el-icon>
群组
</template>
<el-scrollbar height="250px">
<el-menu-item-group v-for="item in groupList" :key="item.ID">
<!-- <template #title>Group 1</template> -->
<el-menu-item
:index="String(item.GroupName)"
@click="handleGetGroupMessage(item.ID)"
>{{ item.GroupName }}</el-menu-item
>
<span
v-if="hasUnreadMsg[`g_${item.ID}`]"
class="unread-dot"
></span>
<!-- <el-menu-item index="2-2">Option 2</el-menu-item> -->
</el-menu-item-group>
</el-scrollbar>
</el-sub-menu>
</el-menu>
</el-scrollbar>
</el-aside>
<el-container width="800px">
<el-header style="text-align: right; font-size: 12px">
<div class="toolbar">
<el-button type="primary" size="mini" @click.prevent="getHistory()"
>历史消息</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/user')"
>返回</el-button
>
<el-text class="mx-1" type="primary"
>目前:{{ cur_user_name }}</el-text
>
<div>
<span style="margin-right: 10px; margin-left: 10px">{{
username
}}</span>
<el-avatar size="default" fit="fit" :src="tokenData.avatar"></el-avatar>
</div>
</div>
</el-header>
<el-main style="margin-top: 1px">
<el-scrollbar
class="chat-room"
id="chat-room"
ref="chatRoom"
height="600px"
style="margin-top: 1px"
always
>
<div
v-for="item in MsgList"
:key="item.ID"
style="margin-top: 10px; margin-bottom: 20px"
>
<!-- 左边 -->
<div
v-if="
uid == item.ToUserID &&
item.FromUserID == cur_user_id &&
cur_group_id == 0
"
style="margin-left: 10px; margin-bottom: 8px"
>
<el-row class="row-bg" type="flex" align="middle">
<!-- <el-avatar size="default" fit="fit">{{
cur_user_name
}}</el-avatar> -->
<el-avatar size="default" :src="cur_user_avatar"></el-avatar>
<span style="margin-left: 10px"
>{{ cur_user_name }} : {{ formatTime(item.CreatedAt) }}</span
>
</el-row>
<el-row>
<el-col :span="1000" :offset="1" class="msg">
<!-- {{ item.Msg }} -->
<div v-html="renderMarkdown(item.Msg)"></div>
</el-col>
</el-row>
</div>
<div
v-if="cur_group_id != 0 && uid != item.FromUserID"
style="margin-left: 10px; margin-bottom: 8px"
>
<el-row class="row-bg" type="flex" align="middle">
<el-avatar size="default" fit="fit">{{ item.name }}</el-avatar>
<span style="margin-left: 10px"
>{{ item.name }} : {{ formatTime(item.CreatedAt) }}</span
>
</el-row>
<el-row>
<el-col
:span="1000"
:offset="1"
class="msg"
style="max-width: 50%"
>
<!-- {{ item.Msg }} -->
<div
v-html="renderMarkdown(item.Msg)"
style="max-width: 50%"
></div>
</el-col>
</el-row>
</div>
<!-- 右边 -->
<div
v-if="uid == item.FromUserID && item.ToUserID == cur_user_id"
style="margin-right: 10px; margin-bottom: 8px"
>
<el-row class="row-bg" type="flex" justify="end" align="middle">
<span style="margin-right: 10px">
{{ tokenData.username }} :
{{ formatTime(item.CreatedAt) }}</span
>
<el-avatar size="default" :src="tokenData.avatar"></el-avatar>
</el-row>
<el-row justify="end">
<el-col
:span="1000"
class="msg2"
style="margin-right: 20px; max-width: 50%"
>
<!-- {{ item.Msg }} -->
<div
v-html="renderMarkdown(item.Msg)"
style="max-width: 50%"
></div>
</el-col>
</el-row>
</div>
</div>
</el-scrollbar>
</el-main>
<div></div>
<div>
<el-row
class="row-bg"
type="flex"
justify="space-around"
align="middle"
>
<el-button
type="primary"
size="default"
@click="SendImage"
class="send-image-button-bg"
>
文件发送
</el-button>
<el-col :span="20">
<el-input
type="textarea"
style="width: 100%"
rows="1"
autofocus
@keyup.enter="handleSendBtnClick"
placeholder="请输入消息按Enter发送"
v-model="currentMsg"
></el-input>
</el-col>
<el-col :span="2">
<el-button
class="sendBtn"
@click="handleSendBtnClick"
type="primary"
size="default"
>
发送
</el-button>
</el-col>
</el-row>
</div>
</el-container>
</el-container>
</template>
<script>
import axios from "axios";
import { inject } from "vue";
import { ref } from "vue";
import { getFriendListService } from "@/api/chat.js";
import { getMessageService } from "@/api/chat.js";
import { sendMessageService } from "@/api/chat.js";
import { UploadFileService } from "@/api/tool.js";
import { GetFileInfoByMd5Service } from "@/api/tool.js";
import {
ElAvatar,
ElDropdown,
ElDropdownItem,
ElDropdownMenu,
ElIcon,
ElMenu,
ElMenuItem,
ElMenuItemGroup,
ElScrollbar,
ElRow,
ElCol,
ElButton,
} from "element-plus";
import { Menu as IconMenu, Message, Setting } from "@element-plus/icons-vue";
import router from "@/router/index.js";
import { ElMessage } from "element-plus";
import MarkdownIt from "markdown-it";
import CryptoJS from "crypto-js";
export default {
data() {
return {
ip: "",
tableData: [],
sendImgDialogVisible: false,
file: null,
file_md5: "",
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
avatar:
localStorage.getItem("avatar") === ""
? "https://gep.ljsea.top/tool/file/9f29cc99-1054-4aff-ab37-e7c0016dd1b5.jpeg"
: localStorage.getItem("avatar"),
},
username: localStorage.getItem("username"),
userList: [],
filteredUsers: [], //
to_user_id: 0,
cur_user_id: 0,
cur_group_id: 0,
msg_type: 1,
searchName: "", //
history_cnt: 1,
md: new MarkdownIt(), //md
cur_user_name: "",
cur_user_avatar: "",
eventSource: null, //
uid: localStorage.getItem("userId"),
currentMsg: "",
MsgList: [],
groupList: [],
hasUnreadMsg: {}, // , keyidvaluetrue/false
};
},
// methods
//
methods: {
async handleSelectUser() {
let result = {};
try {
result = await getFriendListService(this.tokenData);
} catch (e) {
console.log(e);
}
let data = result.data;
this.userList = data.friends;
for (let i = 0; i < data.friends.length; i++) {
this.userList[i].avatar = data.friends[i].avatar ===""?"https://gep.ljsea.top/tool/file/9f29cc99-1054-4aff-ab37-e7c0016dd1b5.jpeg" : data.friends[i].avatar;
this.hasUnreadMsg[data.friends[i].id] = false;
}
console.log("avatar: " + this.userList[0].avatar);
for (let i = 0; i < data.groups.length; i++) {
this.hasUnreadMsg["g_" + data.groups[i].ID] = false;
}
this.groupList = data.groups;
},
filterUsers() {
this.filteredUsers = this.userList.filter((user) => {
return user.name.toLowerCase().includes(this.searchName.toLowerCase());
});
},
getHistory() {
this.history_cnt++;
this.handleGetMessage(this.cur_user_id);
},
async handleGetGroupMessage(id) {
this.cur_group_id = id;
this.cur_user_id = 0;
this.to_user_id = 0;
this.msg_type = 2;
this.hasUnreadMsg["g_" + id] = false;
let result = {};
try {
let req = {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
group_id: id,
index: this.history_cnt,
type: 2,
};
result = await getMessageService(req);
} catch (e) {
console.log(e);
}
let data = result.data;
if (data === undefined || data === null) {
ElMessage({
message: "无消息!",
type: "error",
});
this.MsgList = [];
return;
}
data.sort((a, b) => {
const dateA = new Date(a.CreatedAt);
const dateB = new Date(b.CreatedAt);
//
return dateA - dateB;
});
this.MsgList = data;
if (this.history_cnt <= 2) {
this.scrollToBottom();
}
},
async handleGetMessage(id) {
let result = {};
if (this.to_user_id != id) {
this.history_cnt = 2;
}
this.to_user_id = id;
this.cur_user_id = id;
this.cur_group_id = 0;
this.msg_type = 1;
console.log("uid:", this.uid, "\tcur_user_id:", this.cur_user_id);
for (let i = 0; i < this.userList.length; i++) {
if (this.userList[i].id === id) {
this.cur_user_name = this.userList[i].name;
this.cur_user_avatar =
this.userList[i].avatar === ""
? "https://gep.ljsea.top/tool/file/9f29cc99-1054-4aff-ab37-e7c0016dd1b5.jpeg"
: this.userList[i].avatar;
break;
}
}
this.hasUnreadMsg[id] = false;
try {
let req = {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
from_user_id: id,
to_user_id: localStorage.getItem("userId"),
index: this.history_cnt,
type: this.msg_type,
};
result = await getMessageService(req);
} catch (e) {
console.log(e);
}
let data = result.data;
if (data === undefined) {
ElMessage({
message: "消息获取失败!",
type: "error",
});
return;
}
//data sort by created time
// for (let i = 0; i < data.length; i++) {
// for (let j = i + 1; j < data.length; j++) {
// if (data[i].CreatedAt > data[j].CreatedAt) {
// let temp = data[i];
// data[i] = data[j];
// data[j] = temp;
// }
// }
// }
data.sort((a, b) => {
const dateA = new Date(a.CreatedAt);
const dateB = new Date(b.CreatedAt);
//
return dateA - dateB;
});
this.MsgList = data;
if (this.history_cnt <= 2) {
this.scrollToBottom();
}
},
formatTime(time) {
let date = new Date(time);
//
const year = date.getFullYear();
const month = ("0" + (date.getMonth() + 1)).slice(-2); // 01
const day = ("0" + date.getDate()).slice(-2);
const hour = ("0" + date.getHours()).slice(-2);
const minute = ("0" + date.getMinutes()).slice(-2);
const second = ("0" + date.getSeconds()).slice(-2);
//
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
},
renderMarkdown(markdown) {
// 使 MarkdownIt Markdown HTML
return this.md.render(markdown);
},
SendImage() {
this.sendImgDialogVisible = true;
},
connectWebSocket() {
// WebSocket
let _this = this;
if (typeof WebSocket == "undefined") {
console.log("浏览器不支持WebSocket");
} else {
console.log("浏览器支持WebSocket");
let socketUrl =
"wss://tx.ljsea.top/im/ws_v2?to_user_id=" +
this.to_user_id +
"&token=" +
this.tokenData.token;
// console.log("socketUrl:", socketUrl);
if (this.socket != null) {
this.socket.close();
this.socket = null;
}
// websocket
this.socket = new WebSocket(socketUrl);
//
this.socket.onopen = function () {
this.loading = false;
//alert("");
ElMessage({
message: "连接成功",
type: "success",
});
};
this.socket.onerror = (error) => {
console.error("WebSocket Error:", error);
};
//
this.socket.onclose = function () {
//alert("!");
ElMessage({
message: "连接已关闭",
type: "error",
});
};
//
this.socket.onmessage = async function (msg) {
//console.log("====" + msg.data);
let data = JSON.parse(msg.data); // json
// console.log("====" + data);
// json
console.log("data.type:", data.type);
if (data.type == "msg") {
//
// console.log("====" + JSON.stringify(msg.data));
console.log("msg_:", data.data);
console.log("hasUnreadMsg:", _this.hasUnreadMsg);
let msg_data = JSON.parse(data.data);
_this.MsgList.push(msg_data);
if (msg_data.GroupID === 0) {
//msg_data.GroupID === 0,
if (msg_data.FromUserID !== _this.cur_user_id) {
//
_this.hasUnreadMsg[msg_data.FromUserID] = true;
//
for (let i = 0; i < _this.userList.length; i++) {
if (_this.userList[i].id === msg_data.FromUserID) {
let temp = _this.userList[i];
_this.userList.splice(i, 1); //
_this.userList.unshift(temp); //
break;
}
}
}
} else {
if (msg_data.GroupID !== _this.cur_group_id) {
//
_this.hasUnreadMsg["g_" + msg_data.GroupID] = true;
//
for (let i = 0; i < _this.groupList.length; i++) {
if (_this.groupList[i].ID === msg_data.GroupID) {
let temp = _this.groupList[i];
_this.groupList.splice(i, 1); //
_this.groupList.unshift(temp); //
break;
}
}
}
}
_this.scrollToBottom();
//console.log("msglist:", _this.MsgList);
//
} else if (data.type == "check") {
//alert("线");
//console.log(data.type);
}
};
}
},
async connectSSE() {
if (!!window.EventSource) {
this.eventSource = new EventSource(
"https://gep.ljsea.xyz/im/sse_msg?token=" + this.tokenData.token
);
let this_ = this;
this.eventSource.onopen = function (event) {
console.log("连接已建立!");
};
this.eventSource.onmessage = function (event) {
console.log(event.data);
let msg = JSON.parse(event.data);
if (msg.type !== "check") {
alert(msg);
this_.MsgList.push(msg);
}
};
this.eventSource.onerror = (error) => {
//
this.connectSSE();
if (this.eventSource.readyState === EventSource.CLOSED) {
//console.log('Connection was closed by the server.');
ElMessage({
message: "连接已关闭!:" + error,
type: "error",
});
// Optionally, try to reconnect
} else {
//console.error('EventSource failed:', error);
ElMessage({
message: "连接失败!服务器无法实时推送消息!",
type: "error",
});
// Handle error
}
};
} else {
ElMessage({
message: "您的浏览器不支持SSE",
type: "error",
});
}
},
scrollToBottom() {
this.$nextTick(() => {
const scrollbar = this.$refs.chatRoom.$el.querySelector(
".el-scrollbar__wrap"
);
if (scrollbar) {
scrollbar.scrollTop = scrollbar.scrollHeight;
}
});
},
async handleSendBtnClick() {
if (this.currentMsg == "" || this.currentMsg === null) {
ElMessage.error("消息不能为空!");
return;
}
let result = {};
try {
let req = {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
from_user_id: localStorage.getItem("userId"),
to_user_id: this.to_user_id,
group_id: this.cur_group_id,
msg: this.currentMsg,
type: this.msg_type,
};
result = await sendMessageService(req);
if (result.code !== 0) {
ElMessage({
message: "消息发送失败!",
type: "error",
});
}
let msg = {
ID: result.Data,
FromUserID: localStorage.getItem("userId"),
ToUserID: this.to_user_id,
GroupID: this.cur_group_id,
Msg: this.currentMsg,
CreatedAt: new Date(),
};
this.MsgList.push(msg);
this.scrollToBottom();
} catch (e) {
console.log(e);
}
this.currentMsg = "";
},
async getIpClient() {
try {
const response = await axios.get("https://ipinfo.io/json");
this.ip = response.data.ip;
localStorage.setItem("ip", this.ip);
//console.log(response);
} catch (error) {
console.error(error);
}
},
handleFileSelect() {
let mdt_ = "";
if (this.file) {
try {
const reader = new FileReader();
reader.onloadend = function (e) {
if (e.target.readyState === FileReader.DONE) {
const arrayBuffer = e.target.result;
const spark = new SparkMD5.ArrayBuffer();
spark.append(arrayBuffer);
md5Value.value = spark.end();
}
};
reader.readAsArrayBuffer(this.file);
} catch (error) {
console.error("计算MD5值出错:", error);
}
}
},
handleMenuSelect(val) {
router.push(val);
//websocket
if (this.socket != null) {
this.socket.close();
}
},
handleFileUpload(e) {
this.file = e.target.files[0];
console.log("file has been selected:", this.file);
},
readFileAndCalculateMD5() {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const wordArray = CryptoJS.lib.WordArray.create(event.target.result);
const md5Hash = CryptoJS.MD5(wordArray);
const md5Str = md5Hash.toString(CryptoJS.enc.Hex);
//console.log("onload: " + md5Str);
this.file_md5 = md5Str;
resolve(md5Str);
};
reader.onerror = (error) => {
reject(error);
};
reader.readAsArrayBuffer(this.file);
});
},
async sendImageOrVideo() {
if (this.file == null) {
alert("请先选择要上传的文件");
return;
}
//
try {
let result = {};
this.file_md5 = await this.readFileAndCalculateMD5(this.file);
//console.log("md5:",this.file_md5);
let md5_result = await GetFileInfoByMd5Service({
md5: this.file_md5,
token: this.tokenData.token,
type: 1,
});
if (md5_result.code === 0) {
result = md5_result;
} else {
let formData = new FormData();
formData.append("file", this.file);
//console.log("add file: " + this.file);
formData.append("upload_type", "1");
formData.append("md5", this.file_md5);
formData.append("auth_type", "public");
//console.log("formData:",formData);
result = await UploadFileService(formData, this.tokenData.token);
if (result.code !== 0) {
ElMessage.error("上传文件失败,请稍后再试");
return;
}
}
let resp_data = result.data;
//console.log("resp:",resp_data);
let url = "https://gep.ljsea.top/tool/file/" + resp_data.FileStoreName;
let msg_ = "";
//markdown
let fileType = this.file.name.split(".")[1];
if (!["jpg", "jpeg", "png", "gif", "mp4"].includes(fileType)) {
//alert('');
msg_ = `文件:[${resp_data.FileName}](${url})`;
} else {
msg_ = `![${resp_data.FileName}](${url})`;
}
let req = {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
from_user_id: localStorage.getItem("userId"),
to_user_id: this.to_user_id,
group_id: this.cur_group_id,
msg: msg_,
type: this.msg_type,
};
result = await sendMessageService(req);
if (result.code !== 0) {
ElMessage({
message: "消息发送失败!",
type: "error",
});
}
let msg = {
ID: result.data.id,
FromUserID: localStorage.getItem("userId"),
ToUserID: this.to_user_id,
GroupID: this.cur_group_id,
Msg: msg_,
CreatedAt: new Date(),
};
console.log("msg:", msg);
this.MsgList.push(msg);
this.scrollToBottom();
this.sendImgDialogVisible = false;
} catch (error) {
ElMessage.error("上传文件时出现网络错误,请稍后再试");
console.error(error);
}
},
toVideoList() {
router.push("/videoList");
},
//
tableRowClassName({ row, rowIndex }) {
if (row.human === 1) {
return {
background: "#488aff",
};
} else {
return "";
}
},
},
//
//
async mounted() {
let now = new Date();
if (localStorage.getItem("token") === null) {
router.push("/login");
}
// console.log("mounted");
await this.getIpClient();
await this.handleSelectUser();
this.filteredUsers = this.userList;
//await this.connectSSE();
this.connectWebSocket();
this.handleGetMessage(this.userList[0].id);
},
onUnmounted() {
if (this.eventSource) {
this.eventSource.close();
}
console.log("unmounted chat");
},
};
</script>
<style scoped>
.layout-container-demo .el-header {
position: relative;
/* background-color: var(--el-color-primary-light-7); */
color: var(--el-text-color-primary);
}
.layout-container-demo .el-aside {
color: var(--el-text-color-primary);
/* background: var(--el-color-primary-light-8); */
}
.layout-container-demo .el-menu {
border-right: none;
}
.layout-container-demo .el-main {
padding: 0;
}
.layout-container-demo .toolbar {
display: inline-flex;
align-items: center;
justify-content: center;
height: 100%;
right: 5px;
}
.msg {
background-color: #73d1f3;
/* box-shadow: rgba(18, 23, 45, 0.6) 0px 8px 24px; */
border-radius: 4px;
padding: 10px;
font-size: 18px;
line-height: 16px;
/* width: auto; */
/* max-width: 330px; */
margin-top: 20px;
color: white;
}
.msg2 {
background-color: #12b7f5;
/* box-shadow: rgba(18, 23, 45, 0.6) 0px 8px 24px; */
border-radius: 4px;
padding: 10px;
font-size: 18px;
line-height: 16px;
/* width: auto; */
/* max-width: 330px; */
margin-top: 20px;
color: white;
}
.unread-dot {
position: absolute;
top: 0;
right: 0;
width: 8px;
height: 8px;
background-color: red;
border-radius: 50%;
transform: translate(50%, -50%);
}
.send-image-button-bg {
background-image: url(../assets/img.jpg);
background-size: cover;
background-repeat: no-repeat;
}
</style>

View File

@ -7,8 +7,14 @@ import { addDeviceService } from "@/api/device.js";
import { deleteDeviceService } from "@/api/device.js";
import { updateDeviceService } from "@/api/device.js";
import router from "@/router/index.js";
import { ElMessage } from 'element-plus';
import Menu from "@/views/Menu.vue";
import VideoStream from "@/views/DeviceRealVPV2.vue";
export default {
components: {
VideoStream,
},
data() {
return {
ip: "",
@ -21,6 +27,8 @@ export default {
},
addDialogVisible: false,
updateDialogVisible: false,
deviceStreamDialogVisible: false,
playing_device: "",
searchForm: {
hour: 0,
entrydate: [],
@ -93,9 +101,11 @@ export default {
try {
var d_re = await restartDeviceService(restart_data);
if (d_re.code == 0) {
alert("重启成功");
//alert("");
ElMessage.success('重启成功');
} else {
alert("操作失败");
ElMessage.fail('操作失败');
}
} catch (e) {
console.log(e);
@ -104,9 +114,17 @@ export default {
playRealVp(index) {
var id = this.tableData[index].ID;
localStorage.setItem("realvp_device_id", id);
router.push("/deviceRealVP");
// router.push("/deviceRealVP");
this.playing_device = id + " " + this.tableData[index].DeviceName;
this.deviceStreamDialogVisible = true;
},
async deleteDevice(index) {
//
if (!confirm("确定删除吗?")) {
return;
}
var id = this.tableData[index].ID;
var delete_data = {
id: id,
@ -116,11 +134,13 @@ export default {
try {
var d_re = await deleteDeviceService(delete_data);
if (d_re.code == 0) {
alert("删除成功");
//alert("");
ElMessage.success('删除成功');
//
this.getDeviceList();
} else {
alert("操作失败");
//alert("");
ElMessage.fail("操作失败");
}
} catch (e) {
console.log(e);
@ -144,9 +164,11 @@ export default {
try {
result = await addDeviceService(this.addForm);
if (result.code == 0) {
alert("添加成功");
ElMessage.success("添加成功");
this.getDeviceList()
} else {
alert("添加失败");
//alert("");
ElMessage.error("添加失败")
}
} catch (e) {
console.log(e);
@ -158,7 +180,8 @@ export default {
try {
result = await updateDeviceService(this.updateForm);
if (result.code == 0) {
alert("修改成功");
//alert("");
ElMessage.success("修改成功");
this.getDeviceList()
} else {
alert("修改失败");
@ -178,7 +201,8 @@ export default {
try {
var d_re = await restartDeviceService(restart_data);
if (d_re.code == 0) {
alert("重启成功");
//alert("");
ElMessage.success("重启成功");
} else {
alert("操作失败");
}
@ -222,7 +246,7 @@ export default {
router.push("/login");
}
// console.log("mounted");
await this.getIpClient();
//this.getIpClient();
this.getDeviceList();
},
};
@ -230,30 +254,7 @@ export default {
<template>
<div>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/videoList')"
>视频列表</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/device')"
>设备管理</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/User')"
>用户</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/cid')"
>集成部署</el-button
>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>监控设备列表</el-header
@ -332,6 +333,20 @@ export default {
</template>
</el-dialog>
</el-form-item>
<el-form-item>
<el-dialog
title="实时播放"
v-model="deviceStreamDialogVisible"
width="60%"
height="60%"
center
>
<div>
视频播放({{playing_device }})
<VideoStream v-if="deviceStreamDialogVisible"></VideoStream>
</div>
</el-dialog>
</el-form-item>
<el-form-item>
<el-dialog
@ -410,7 +425,15 @@ export default {
prop="DeviceStatus"
label="设备状态"
width="80"
></el-table-column>
>
<template #default="scope">
<el-tag
:type="scope.row.DeviceStatus === '在线' ? 'success' : 'danger'"
>{{ scope.row.DeviceStatus === "在线" ? '在线' : '离线' }}</el-tag
>
</template>
</el-table-column>
<el-table-column
prop="DeviceType"
label="设备类型"

View File

@ -1,18 +1,19 @@
<template>
<el-button
<!-- <el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/device')"
>设备</el-button
>
> -->
<div>
<!-- 使用:src绑定base64图片 -->
<img :src="base64Image" alt="Base64 Image" />
<img :src="base64Image" alt="Base64 Image" width="100%" height ="100%"/>
</div>
</template>
<script>
import { ref, onMounted, inject, onUnmounted } from "vue";
import router from "@/router/index.js";
import { ElMessage } from 'element-plus';
export default {
data() {
return {
@ -35,6 +36,7 @@ export default {
},
methods: {
handleMenuSelect(val) {
this.socket.close();
router.push(val);
},
connectWebSocket() {
@ -60,14 +62,16 @@ export default {
//
this.socket.onopen = function () {
this.loading = false;
alert("连接成功");
//alert("");
ElMessage.success("连接成功!");
};
this.socket.onerror = (error) => {
console.error("WebSocket Error:", error);
};
//
this.socket.onclose = function () {
alert("连接已关闭!");
//alert("!");
ElMessage.success("连接已关闭!");
router.push("/user");
};
//
@ -80,10 +84,6 @@ export default {
_this.base64Image = 'data:image/png;base64,'+data.data
// console.log("====" + msg.data);
} else if (data.type == "offline") {
alert("对方已下线");
_this.socket.close();
router.push("/user");
}
};
}
@ -98,6 +98,9 @@ export default {
onUnmounted() {
this.socket.close();
},
beforeUnmount() {
this.socket.close();
},
};
</script>
<style>

View File

@ -0,0 +1,68 @@
<template>
<div>
<img ref="imagePlayer" alt="实时图像" width="100%" height="100%"/>
</div>
</template>
<script>
export default {
data() {
return {
imagePlayer: null,
socket: null,
device_id: localStorage.getItem("realvp_device_id"),
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
to_user_id: this.to_user_id,
},
};
},
mounted() {
this.imagePlayer = this.$refs.imagePlayer;
this.initWebSocket();
},
methods: {
initWebSocket() {
let socketUrl =
"wss://gep.ljsea.top/device/get_real_time_image?device_id=" + //wss://gep.ljsea.top/device/get_real_time_image?device_id= wss://vps.ljsea.top/tool/video_real_time?device_id=
this.device_id +
"&token=" +
this.tokenData.token;
this.socket = new WebSocket(socketUrl);
this.socket.onopen = () => {
console.log('WebSocket连接成功');
};
this.socket.onmessage = (event) => {
const blob = new Blob([event.data], { type: 'image/jpeg' });
const objectURL = URL.createObjectURL(blob);
this.imagePlayer.src = objectURL;
};
this.socket.onclose = () => {
console.log('WebSocket连接关闭');
this.imagePlayer.src = "";
};
this.socket.onerror = (error) => {
console.error('WebSocket出现错误:', error);
};
},
},
beforeUnmount() {
if (this.socket) {
this.socket.onmessage = null;
console.log('关闭WebSocket连接');
this.socket.close();
window.location.reload();
}
},
};
</script>
<style scoped>
img {
width: 100%;
margin: 0 auto;
}
</style>

553
src/views/FileList.vue Normal file
View File

@ -0,0 +1,553 @@
<script>
import axios from "axios";
import router from "@/router/index.js";
import Cookies from "js-cookie";
import { autoResizerProps, ElMessage } from "element-plus";
import CryptoJS from "crypto-js";
import Menu from "@/views/Menu.vue";
import { getConfigFileListService } from "@/api/file.js";
import { addConfigFileService } from "@/api/file.js";
import { deleteConfigFileService } from "@/api/file.js";
import { updateConfigFileService } from "@/api/file.js";
export default {
data() {
return {
ip: "",
tableData: [],
search_id: 2002,
ConfigFileUpdateForm: {},
keyword: "",
updateDialogVisible: false,
addConfigFileVisible: false,
ConfigFileCurrentPageData: [],
pageSize: 10,
currentPage: 1,
upload_file: null, //
file_md5: "", //md5
addForm: {
file_name: "",
file_path: "",
},
loading: false, //
server_list: [
{ label: "js.ljsea.top", value: "js.ljsea.top" },
{ label: "tx.ljsea.top", value: "tx.ljsea.top" },
{ label: "gep.ljsea.top", value: "gep.ljsea.top" },
{ label: "as.ljsea.top", value: "as.ljsea.top" },
{ label: 'al.ljsea.top', value: "al.ljsea.top" }
],
role: "",
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
id: 2002,
server: localStorage.getItem('config_file_server')||"gep.ljsea.top",
keyword: "",
},
};
},
// methods
//
methods: {
async getConfigFileList() {
this.loading = true;
let result = {};
try {
//search_id
let req = {
token: this.tokenData.token,
type: "all",
};
result = await getConfigFileListService(req);
let data = result.data;
if (data !== undefined && data !== null) {
this.tableData = data;
}
} catch (e) {
console.log(e);
ElMessage.error("获取文件列表失败");
} finally {
this.loading = false;
}
for(let i = 0;i<this.tableData.length;i++) {
this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt);
this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt)
//console.log('this.ConfigFileList:',this.ConfigFileList);
}
this.currentPageData();
},
addConfigFileV() {
this.addConfigFileVisible = true;
},
handleServerChange() {
localStorage.setItem("config_file_server", this.tokenData.server);
this.getConfigFileList();
},
async addConfigFile() {
this.loading = true;
this.addDialogVisible = false;
let result = {};
try {
let req = {
token: this.tokenData.token,
file_name: this.addForm.file_name,
file_path: this.addForm.file_path,
};
result = await addConfigFileService(req);
if (result.code == 0) {
ElMessage.success("添加成功");
this.getConfigFileList();
this.addConfigFileVidibale = false;
} else {
ElMessage.error("添加失败");
}
} catch (e) {
console.log(e);
ElMessage.error("添加配置文件失败");
} finally {
this.loading = false;
}
},
async deleteConfigFile(index) {
//
let isDelete = confirm("是否删除?");
if (!isDelete) {
return;
}
let is_delete_file = confirm("是否删除文件?");
this.loading = true;
let result = {};
try {
let req = {
token: this.tokenData.token,
id: this.ConfigFileCurrentPageData[index].ID,
del_file: is_delete_file,
};
result = await deleteConfigFileService(req);
if (result.code == 0) {
ElMessage.success("删除成功");
this.getConfigFileList();
} else {
ElMessage.error("删除失败");
}
} catch (e) {
console.log(e);
ElMessage.error("删除配置文件失败");
} finally {
this.loading = false;
}
},
async updateConfigFile(index) {
console.log("index:", index);
let cf = this.ConfigFileCurrentPageData[index];
let req = {
token: this.tokenData.token,
id: cf.ID,
type: "one",
};
let result = await getConfigFileListService(req);
let data = result.data;
this.ConfigFileUpdateForm = data[0];
this.updateDialogVisible = true;
},
handleAvatarFileUpload(e) {
this.avatar_file = e.target.files[0];
//
if (!this.avatar_file.type.startsWith("image/")) {
ElMessage.error("请选择图片文件");
this.avatar_file = null;
return;
}
this.uploadAvatarFile();
},
readFileAndCalculateMD5() {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const wordArray = CryptoJS.lib.WordArray.create(event.target.result);
const md5Hash = CryptoJS.MD5(wordArray);
const md5Str = md5Hash.toString(CryptoJS.enc.Hex);
//console.log("onload: " + md5Str);
this.file_md5 = md5Str;
resolve(md5Str);
};
reader.onerror = (error) => {
reject(error);
};
reader.readAsArrayBuffer(this.avatar_file);
});
},
formattedTime(isoTime) {
const date = new Date(isoTime);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
async uploadFile() {
if (this.avatar_file == null) {
alert("请先选择要上传的文件");
return;
}
try {
let result = {};
this.file_md5 = await this.readFileAndCalculateMD5(this.avatar_file);
//console.log("md5:",this.file_md5);
let md5_result = await GetFileInfoByMd5Service({
md5: this.file_md5,
token: this.tokenData.token,
type: 1,
});
if (md5_result.code === 0) {
result = md5_result;
} else {
let formData = new FormData();
formData.append("file", this.avatar_file);
//console.log("add file: " + this.file);
formData.append("upload_type", "1");
formData.append("md5", this.file_md5);
formData.append("auth_type", "public");
//console.log("formData:",formData);
result = await UploadFileService(formData, this.tokenData.token);
if (result.code !== 0) {
ElMessage.error("上传文件失败,请稍后再试");
return;
}
}
let resp_data = result.data;
//console.log("resp:",resp_data);
let url = "https://gep.ljsea.top/tool/file/" + resp_data.FileStoreName;
this.UserUpdateForm.avatar = url;
//
await this.updateUserInfo();
} catch (error) {
ElMessage.error("上传文件时出现网络错误,请稍后再试");
console.error(error);
}
},
async updateConfigFileInfo() {
this.loading = true;
let result = {};
try {
let req = {
token: this.tokenData.token,
id: this.ConfigFileUpdateForm.id,
content: this.ConfigFileUpdateForm.content,
};
for (var key in this.UserUpdateForm) {
req[key] = this.UserUpdateForm[key];
}
result = await updateConfigFileService(req);
if (result.code === 0) {
ElMessage.success("更新成功");
this.updateDialogVisible = false;
} else {
ElMessage.error("更新失败");
}
} catch (e) {
console.log(e);
ElMessage.error("更新配置文件失败");
} finally {
this.loading = false;
}
},
onSubmit() {
getConfigFileList();
},
currentPageData() {
this.ConfigFileCurrentPageData = this.tableData.slice(
(this.currentPage - 1) * this.pageSize,
this.currentPage * this.pageSize
);
},
handleSizeChange(val) {
//console.log(` ${val} `);
this.pageSize = val;
this.currentPageData();
},
handleCurrentChange(val) {
//console.log(`: ${val}`);
this.currentPage = val;
this.currentPageData();
},
async displayMyInfo() {
await this.getMyUserInfo(this.tokenData.user_id);
this.updateDialogVisible = true;
},
async displayUserInfo(id) {
await this.getMyUserInfo(id);
this.updateDialogVisible = true;
},
handleMenuSelect(val) {
router.push(val);
},
toVideoList() {
router.push("/videoList");
},
//
tableRowClassName({ row, rowIndex }) {
if (row.human === 1) {
return {
background: "#488aff",
};
} else {
return "";
}
},
},
//
//
async mounted() {
let now = new Date();
if (localStorage.getItem("token") === null) {
router.push("/login");
}
await this.getConfigFileList();
//await this.getMyUserInfo(localStorage.getItem("userId"));
},
};
</script>
<template>
<div>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>文件</el-header
>
<el-container>
<el-main>
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
<el-dialog
v-model="updateDialogVisible"
title="编辑配置文件"
width="60%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="updateFormRef"
:model="ConfigFileUpdateForm"
:rules="UserUpdateFormRules"
label-width="70px"
>
<!-- row -->
<el-row>
<el-col :span="12">
<el-form-item label="ID">
<el-input
v-model="ConfigFileUpdateForm.id"
disabled
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="文件名称">
<el-input
v-model="ConfigFileUpdateForm.file_name"
disabled
></el-input>
</el-form-item>
</el-col>
<el-col :span="32">
<el-form-item label="文件路径">
<el-input
v-model="ConfigFileUpdateForm.file_path"
disabled
style="width: 512px"
></el-input>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="文件内容" prop="device_status">
<el-input
type="textarea"
v-model="ConfigFileUpdateForm.content"
style="width: 800px"
:autosize="{ minRows: 4, maxRows: 24 }"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="updateDialogVisible = false"
>取消</el-button
>
<el-button type="primary" @click="updateConfigFileInfo()"
>确定</el-button
>
</span>
</template>
</el-dialog>
</el-form-item>
<!-- 表单 -->
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
@click="getConfigFileList()"
>查询</el-button
>
</el-form-item>
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
@click="addConfigFileV()"
>添加配置文件</el-button
>
</el-form-item>
<!-- 选择服务器 -->
<el-form-item>
<el-select
v-model="tokenData.server"
filterable allow-create
@change="handleServerChange"
>
<el-option v-for="item in server_list" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-form>
</el-form>
<el-dialog
v-model="addConfigFileVisible"
title="添加配置文件"
width="50%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="addFormRef"
:model="addForm"
:rules="addFormRules"
label-width="70px"
>
<el-row>
<el-form-item label="文件名称" prop="file_name">
<el-input
v-model="addForm.file_name"
autocomplete="on"
></el-input>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="文件路径" prop="file_path">
<el-input
v-model="addForm.file_path"
autocomplete="on"
></el-input>
</el-form-item>
</el-row>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="addConfigFileVidibale = false"
>取消</el-button
>
<el-button type="primary" @click="addConfigFile()"
>确定</el-button
>
</span>
</template>
</el-dialog>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table
:data="ConfigFileCurrentPageData"
width="100%"
v-loading="loading"
element-loading-text="加载中..."
element-loading-background="rgba(240, 242, 245, 0.8)"
>
:row-style="this.tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
prop="FileName"
label="文件名称"
width="120"
></el-table-column>
<el-table-column
prop="FilePath"
label="文件路径"
width="180"
></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="160"
></el-table-column>
<el-table-column
prop="UpdatedAt"
label="上次更新"
width="160"
></el-table-column>
<el-table-column
prop="AuthID"
label="创建用户ID"
width="100"
></el-table-column>
<el-table-column label="操作" width="200">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="updateConfigFile(scope.$index)"
>编辑</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="deleteConfigFile(scope.$index)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页条 -->
<!-- Pagination 分页 -->
<el-pagination
background
layout="total,sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="10"
></el-pagination>
</el-main>
</el-container>
</el-container>
</div>
</template>
<style scoped>
.blueRowbg {
background: "#488aff";
}
</style>

759
src/views/Group.vue Normal file
View File

@ -0,0 +1,759 @@
<script>
import axios from "axios";
import { inject } from "vue";
import { getGroupListService } from "@/api/group.js";
import { updateGroupService } from "@/api/group.js";
import { restartDeviceService } from "@/api/device.js";
import { addDeviceService } from "@/api/device.js";
import {sendMessageService } from "@/api/chat.js";
import {getGroupFriendListService } from "@/api/chat.js";
import {acceptInviteService } from "@/api/user.js";
import { rejectInviteService } from "@/api/user.js";
import { getFriendListService } from "@/api/chat.js";
import { getGroupUsersListService } from "@/api/chat.js";
import { addGroupService} from "@/api/chat.js";
import {DelFGService} from "@/api/user.js";
import { updateDeviceService } from "@/api/device.js";
import router from "@/router/index.js";
import { ElMessage } from 'element-plus';
import Menu from "@/views/Menu.vue";
export default {
data() {
return {
ip: "",
FriendsTableIsDisplay:false,
tableData: [],
group_id:0,
is_del_group_user:false,
GroupRequestIsDisplay : false,
GroupRequestList:[],
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
},
addDialogVisible: false,
updateDialogVisible: false,
searchForm: {
hour: 0,
entrydate: [],
},
add_groups:[],
addForm: {
group_name: "",
group_info: "",
group_type: "",
group_icon:"",
auth_id: -1,
token: localStorage.getItem("token"),
},
updateForm: {
id:0,
group_name: "",
group_info: "",
group_type: "",
group_icon:"",
auth_id: -1,
token: localStorage.getItem("token"),
},
};
},
// methods
//
methods: {
async getGroupList() {
let result = {};
let add_res ={};
try {
result = await getGroupListService(this.tokenData);
add_res = await getFriendListService(this.tokenData);
} catch (e) {
console.log(e);
}
let data = result.data;
let m ={};
for(let i=0;i<data.length;i++){
m[data[i].ID] = data[i];
}
let add_resu = add_res.data.groups;
let temp =[];
for(let i=0;i<add_resu.length;i++){
if(m[add_resu[i].ID] === undefined){
temp.push(add_resu[i]);
}
}
this.add_groups = temp;
// for(let d in data){
// let res = JSON.parse(d);
// console.log("res=",res);
// this.tableData.push(res);
// }
// console.log(this.tableData);
this.tableData = data;
},
onSubmit() {
getGroupList({ token: token });
},
handleSizeChange() {
alert("每页记录数变化" + val);
},
handleCurrentChange() {
alert("页码发生变化" + val);
},
//
async displayFriends(index){
this.group_id = this.tableData[index].ID;
let result ={}
try{
result = await getFriendListService(this.tokenData);
if(result.code ===0){
this.FriendsGList = result.data.friends;
this.GroupList=result.data.groups;
this.FriendsTableIsDisplay = true;
this.is_del_group_user=false;
}else{
ElMessage.error("获取好友列表失败");
}
}catch(e){
console.log(e);
}
},
async displayGroupUsersInfo(index){
this.group_id = this.tableData[index].ID;
let result ={}
try{
let req={
token: this.tokenData.token,
group_id: this.group_id,
}
result = await getGroupUsersListService(req);
if(result.code ===0){
this.FriendsGList = result.data;
this.FriendsTableIsDisplay = true;
this.is_del_group_user=true;
}else{
ElMessage.error("获取群用户列表失败");
}
}catch(e){
console.log(e);
}
},
//
async inviteUser(index) {
var id = this.tableData[index].ID;
var restart_data = {
id: id,
option: "one",
ip: this.ip,
userId: this.tokenData.userId,
token: this.tokenData.token,
};
try {
var d_re = await restartDeviceService(restart_data);
if (d_re.code == 0) {
ElMessage.success('重启成功');
} else {
alert("操作失败");
ElMessage.fail('操作失败');
}
} catch (e) {
console.log(e);
}
},
async deleteGroup(index) {
var id = this.tableData[index].ID;
var delete_data = {
group_id: id,
type:3,//
userId: this.tokenData.userId,
token: this.tokenData.token,
};
try {
var d_re = await DelFGService(delete_data);
if (d_re.code == 0) {
//alert("");
ElMessage.success('删除成功');
//
this.getGroupList();
} else {
//alert("");
ElMessage.fail("操作失败");
}
} catch (e) {
console.log(e);
}
},
async updateButtonGroup(index) {
var id = this.tableData[index].ID;
this.group_id = id;
this.updateForm.group_name = this.tableData[index].GroupName;
this.updateForm.group_info = this.tableData[index].GroupInfo;
this.updateForm.group_type = this.tableData[index].GroupType;
this.updateForm.group_icon = this.tableData[index].GroupIcon;
this.updateForm.auth_id = this.tableData[index].AuthID;
this.updateForm.id = id;
this.updateDialogVisible= true;
},
async addGroup() {
this.addDialogVisible = false;
let result = {};
try {
result = await addGroupService(this.addForm);
if (result.code == 0) {
ElMessage.success("添加成功");
this.getGroupList();
} else {
//alert("");
ElMessage.error("添加失败")
}
} catch (e) {
console.log(e);
}
},
async updateGroup() {
this.updateDialogVisible = false;
let result = {};
try {
result = await updateGroupService(this.updateForm);
if (result.code == 0) {
//alert("");
ElMessage.success("修改成功");
this.getGroupList();
} else {
alert("修改失败");
}
} catch (e) {
console.log(e);
}
},
async inviteFriendAddGroup(index){
var id = this.FriendsGList[index].id;
let req={
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
from_user_id:localStorage.getItem("userId"),
to_user_id:id,
group_id:this.group_id,
msg:this.currentMsg,
type:6,
}
try {
var d_re = await sendMessageService(req);
if (d_re.code == 0) {
//alert("");
ElMessage.success("邀请成功");
} else {
//alert("");
ElMessage.error("操作失败:"+d_re.error);
}
} catch (e) {
console.log(e);
}
},
async delGroupUser(index){
var id = this.FriendsGList[index].id;
let req={
token: localStorage.getItem("token"),
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
group_id: this.group_id,
msg: "踢出群聊",
type: 4,
}
if (id === parseInt(req.userId)){
ElMessage.error("不能删除自己,若自己要退出,请解散群聊!")
return
}
try {
var d_re = await DelFGService(req);
if (d_re.code == 0) {
//alert("");
ElMessage.success("删除成功");
} else {
//alert("");
ElMessage.error("操作失败:"+d_re.error);
}
} catch (e) {
console.log(e);
}
},
async getIpClient() {
try {
const response = await axios.get("https://ipinfo.io/json");
this.ip = response.data.ip;
localStorage.setItem("ip", this.ip);
//console.log(response);
} catch (error) {
console.error(error);
}
},
async displayGroupReq(){
let result ={}
try{
let req={
token:this.tokenData.token,
type:1
}
result =await getGroupFriendListService(req)
if(result.code ===0){
this.GroupRequestList = result.data;
this.GroupRequestIsDisplay = true;
}else{
ElMessage.error("获取好友请求列表失败");
}
}catch(e){
console.log(e);
}
},
//退
async DelFriendsOrGroup(index){
//
if (!confirm("确定退出吗?")) {
return;
}
var id = this.add_groups[index].ID;
let result ={}
try{
result =await DelFGService({
token: localStorage.getItem("token"),
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
group_id: id,
msg: "退出群聊",
type: 2,
});
if(result.code ===0){
ElMessage.success("退出群聊成功");
this.getGroupList();
}else{
ElMessage.error("退出群聊失败");
}
}catch(e){
console.log(e);
}
},
async AcceptFriendsOrGroup(index){
var id = this.GroupRequestList[index].id;
var im_id = this.GroupRequestList[index].im_id;
let result ={}
try{
result =await acceptInviteService({
token: localStorage.getItem("token"),
id: im_id,
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
group_id: this.GroupRequestList[index].group_id,
msg: "接受加入群组请求",
index: 1,
type: 2,
});
if(result.code ===0){
ElMessage.success("接受请求成功");
this.displayGroupReq();
}else{
ElMessage.error("接受请求失败");
}
}catch(e){
console.log(e);
}
},
async RefuseFriendsOrGroup(index){
var id = this.GroupRequestList[index].id;
var im_id = this.GroupRequestList[index].im_id;
let result ={}
try{
result =await rejectInviteService({
token: localStorage.getItem("token"),
id: im_id,
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
group_id: this.GroupRequestList[index].group_id,
msg: "接受加入群组请求",
index: 1,
type: 2,
});
if(result.code ===0){
ElMessage.success("接受请求成功");
this.displayGroupReq();
}else{
ElMessage.error("接受请求失败");
}
}catch(e){
console.log(e);
}
},
handleMenuSelect(val) {
router.push(val);
},
toVideoList() {
router.push("/videoList");
},
//
tableRowClassName({ row, rowIndex }) {
if (row.human === 1) {
return {
background: "#488aff",
};
} else {
return "";
}
},
},
//
//
async mounted() {
let now = new Date();
if (localStorage.getItem("token") === null) {
router.push("/login");
}
// console.log("mounted");
this.getIpClient();
this.getGroupList();
},
};
</script>
<template>
<div>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>群组</el-header
>
<el-container>
<el-main>
<!-- 表单 -->
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
@click="getGroupList()"
>查询</el-button
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="addDialogVisible = true"
>建群</el-button
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="displayGroupReq()"
>请求加入群聊请求</el-button
>
</el-form-item>
<el-form-item>
<el-dialog
v-model="addDialogVisible"
title="建群"
width="50%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="addFormRef"
:model="addForm"
:rules="addFormRules"
label-width="70px"
>
<el-form-item label="名称" prop="device_name">
<el-input
v-model="addForm.group_name"
autocomplete="on"
></el-input>
</el-form-item>
<el-form-item label="描述" prop="info">
<el-input v-model="addForm.group_info"></el-input>
</el-form-item>
<el-form-item label="类型" prop="type">
<el-input v-model="addForm.group_type"></el-input>
</el-form-item>
<el-form-item label="icon" prop="device_info">
<el-input v-model="addForm.group_icon"></el-input>
</el-form-item>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="addDialogVisible = false"
>取消</el-button
>
<el-button type="primary" @click="addGroup()"
>确定</el-button
>
</span>
</template>
</el-dialog>
</el-form-item>
<el-form-item>
<el-dialog
v-model="updateDialogVisible"
title="修改群信息"
width="50%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="updateFormRef"
:model="updateForm"
:rules="updateFormRules"
label-width="70px"
>
<el-form-item label="名称" prop="group_name">
<el-input
v-model="updateForm.group_name"
autocomplete="on"
></el-input>
</el-form-item>
<el-form-item label="群信息" prop="group_info">
<el-input v-model="updateForm.group_info"></el-input>
</el-form-item>
<el-form-item label="群类型" prop="group_type">
<el-input v-model="updateForm.group_type"></el-input>
</el-form-item>
<el-form-item label="群Icon" prop="group_icon">
<el-input v-model="updateForm.group_icon"></el-input>
</el-form-item>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="updateDialogVisible = false"
>取消</el-button
>
<el-button type="primary" @click="updateGroup()"
>确定</el-button
>
</span>
</template>
</el-dialog>
</el-form-item>
</el-form>
<el-dialog
title="成员列表"
width="40%"
v-model="FriendsTableIsDisplay"
center>
<el-table :data="FriendsGList" width="100%">
<el-table-column prop="id" label="id" width="80"></el-table-column>
<el-table-column
prop="name"
label="名称"
width="100"
></el-table-column>
<el-table-column
prop="email"
label="用户邮箱"
width="180"
></el-table-column>
<el-table-column>
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="inviteFriendAddGroup(scope.$index)"
v-if="is_del_group_user === false"
>邀请</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="delGroupUser(scope.$index)"
v-if="is_del_group_user === true"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-dialog
title="加入群组请求"
width="50%"
v-model="GroupRequestIsDisplay"
center>
<el-table :data="GroupRequestList" width="100%">
<el-table-column prop="id" label="id" width="80"></el-table-column>
<el-table-column
prop="name"
label="名称"
width="100"
></el-table-column>
<el-table-column
prop="email"
label="用户邮箱"
width="180"
></el-table-column>
<el-table-column
prop="group_id"
label="群id"
width="180"
></el-table-column>
<el-table-column>
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="AcceptFriendsOrGroup(scope.$index)"
>同意请求</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="RefuseFriendsOrGroup(scope.$index)"
>拒绝请求</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<h>
我建的群组
</h>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="tableData" width="100%" border>
:row-style="this.tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
prop="GroupName"
label="名称"
width="100"
></el-table-column>
<el-table-column
prop="GroupInfo"
label="描述"
width="180"
></el-table-column>
<el-table-column
prop="GroupType"
label="类型"
width="120"
></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="120"
></el-table-column>
<el-table-column
prop="UpdatedAt"
label="更新时间"
width="120"
></el-table-column>
<el-table-column label="操作" width="350">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="displayFriends(scope.$index)"
>邀请</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="displayGroupUsersInfo(scope.$index)"
>成员管理</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="updateButtonGroup(scope.$index)"
>修改</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="deleteGroup(scope.$index)"
>删除</el-button
>
<!-- <el-button type="danger" size="mini">删除</el-button> -->
</template>
</el-table-column>
</el-table>
<br />
<h>
我加入的群组列表
</h>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="add_groups" width="100%" border>
:row-style="this.tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
prop="GroupName"
label="名称"
width="100"
></el-table-column>
<el-table-column
prop="GroupInfo"
label="描述"
width="180"
></el-table-column>
<el-table-column
prop="GroupType"
label="类型"
width="120"
></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="120"
></el-table-column>
<el-table-column
prop="UpdatedAt"
label="更新时间"
width="120"
></el-table-column>
<el-table-column label="操作" width="350">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="DelFriendsOrGroup(scope.$index)"
>退出群聊</el-button
>
<!-- <el-button type="danger" size="mini">删除</el-button> -->
</template>
</el-table-column>
</el-table>
<br />
<!-- 分页条 -->
<!-- Pagination 分页 -->
<!-- <el-pagination
background
layout="total,sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="1000"
></el-pagination> -->
</el-main>
</el-container>
</el-container>
</div>
</template>
<style>
.blueRowbg {
background: "#488aff";
}
</style>

View File

@ -55,6 +55,7 @@ import router from "@/router/index.js";
import * as crypto from "crypto";
import CryptoJS from "crypto-js";
import { ElLoading } from "element-plus";
import { ElMessage } from 'element-plus';
import Cookies from "js-cookie";
export default {
data() {
@ -142,7 +143,11 @@ export default {
if (this.cnt > 10) {
//
this.stopInterval();
alert("连接失败,请重试!");
//alert("");
ElMessage({
message: "连接失败,请重试!",
type: "error",
})
router.push("/user");
}
return;
@ -168,7 +173,8 @@ export default {
if (this.cnt > 30) {
//
this.stopInterval();
confirm("连接失败,请重试!");
//confirm("");
ElMessage.error("连接失败,请重试!");
router.push("/user");
}
}
@ -272,7 +278,7 @@ export default {
} else {
console.log("浏览器支持WebSocket");
let socketUrl =
"wss://gep.ljsea.xyz/im/ws?to_user_id=" +
"wss://tx.ljsea.top/im/ws?to_user_id=" +
this.to_user_id +
"&token=" +
this.tokenData.token;
@ -287,21 +293,29 @@ export default {
//
this.socket.onopen = function () {
this.loading=false
alert("连接成功");
//alert("");
ElMessage({
message: "连接成功",
type: "success",
})
};
this.socket.onerror = (error) => {
console.error("WebSocket Error:", error);
};
//
this.socket.onclose = function () {
alert("连接已关闭!");
//alert("!");
ElMessage({
message: "连接已关闭",
type: "error",
})
router.push("/user");
};
//
this.socket.onmessage = async function (msg) {
//console.log("====" + msg.data);
let data = JSON.parse(msg.data); // json
console.log("收到数据====" + data);
//console.log("====" + data);
// json
if (data.type == "msg") { //
data.data = await _this.decryptAES(
@ -314,7 +328,11 @@ export default {
//
_this.createContent(_this.to_user_name, null, data.data);
}else if (data.type == "offline"){
alert("对方已下线");
//alert("线");
ElMessage({
message: "对方已下线",
type: "error",
})
_this.socket.close();
router.push("/user");
}

View File

@ -1,120 +1,105 @@
<template>
<el-row class="loginPage">
<!-- element-plus login form -->
<el-form
ref="form"
size="large"
autocomplete="false"
:model="loginData"
:rules="rules"
v-if="isLogin === true"
>
<el-form-item>
<h1>登录</h1>
</el-form-item>
<div class="login-bg">
<div class="login-container">
<div class="login-header">
<img class="logo mr10" src="../assets/img/logo.svg" alt="" />
<div class="login-title">综合系统</div>
</div>
<el-form :model="param" :rules="rules" ref="login" size="large">
<el-form-item prop="username">
<el-input
placeholder="请输入用户名或邮箱"
v-model="loginData.username"
></el-input>
<el-input v-model="param.username" placeholder="用户名或邮箱">
<template #prepend>
<el-icon>
<User />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
placeholder="请输入密码"
type="password"
v-model="loginData.password"
></el-input>
placeholder="密码"
v-model="param.password"
@keyup.enter="submitForm(login)"
>
<template #prepend>
<el-icon>
<Lock />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item>
<!-- <div class="pwd-tips">
<el-checkbox class="pwd-checkbox" v-model="checked" label="记住密码" />
<el-link type="primary" @click="$router.push('/reset-pwd')">忘记密码</el-link>
</div> -->
<el-button
class="button"
class="login-btn"
type="primary"
auto-insert-space
@click="login"
size="large"
@click="onLogin"
>登录</el-button
>
</el-form-item>
<el-form-item class="flex">
<el-link @click="isLogin = false"> 注册 </el-link>
</el-form-item>
<!-- <p class="login-text">
没有账号<el-link type="primary" @click="$router.push('/register')">立即注册</el-link>
</p> -->
</el-form>
<!-- element-plus register form -->
<el-form
ref="form"
size="large"
autocomplete="false"
:model="registerData"
:rules="rules"
v-if="isLogin === false"
>
<el-form-item>
<h1>注册</h1>
</el-form-item>
<el-form-item prop="username">
<el-input
placeholder="请输入用户名"
v-model="registerData.username"
></el-input>
</el-form-item>
<el-form-item prop="email">
<el-input
placeholder="请输入邮箱"
v-model="registerData.email"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
placeholder="请输入密码"
type="password"
v-model="registerData.password"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
placeholder="请再次输入密码"
type="password"
v-model="registerData.repassword"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onRegister" auto-insert-space
>注册</el-button
>
</el-form-item>
<el-form-item class="flex">
<el-link @click="isLogin = true"> 返回 </el-link>
</el-form-item>
</el-form>
</el-row>
<div>
<div>二维码状态: {{ qr_status }}</div>
<canvas ref="qrCodeCanvas"></canvas>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, inject, onUnmounted } from "vue";
import axios from "axios";
import {
getQRService,
getUUIDService,
loginService,
registerService,
} from "@/api/user.js";
import router from "@/router/index.js";
import VueQr from "vue-qr"; //
import QRCode from "qrcode";
import { ref, reactive, inject, onMounted } from "vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { loginService } from "@/api/user.js";
import { GetUserInfoService } from "@/api/user.js";
const isLogin = ref(true);
const qrCodeCanvas = ref(null);
//
const lgStr = localStorage.getItem("login-param");
const defParam = lgStr ? JSON.parse(lgStr) : null;
const globalData = inject("globalData");
//
const checked = ref(lgStr ? true : false);
// ID
const intervalId = ref(null);
var uuid = "";
const router = useRouter();
//
const param = reactive({
username: defParam ? defParam.username : "",
password: defParam ? defParam.password : "",
});
onMounted(async () => {
//
let res = await getMyUserInfo(localStorage.getItem("userId"));
if(res.code === 0){
//
router.push("/user");
}else{
window.location.href = "https://sv.ljsea.top/#/login?site=gs-vp"; //https://sv.ljsea.top/
}
});
//
const rules = {
username: [
{
required: true,
message: "请输入用户名",
trigger: "blur",
},
],
password: [
{
required: true,
message: "请输入密码",
trigger: "blur",
},
],
};
//
const login = ref(null);
const qr_status = ref("未被扫描");
//
var loginData = ref({
username: "",
@ -123,218 +108,119 @@ var loginData = ref({
ip: "",
});
const registerData = ref({
username: "",
email: "",
password: "",
repassword: "",
});
//
const rules = {
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{
min: 6,
max: 20,
message: "密码长度在 6 到 20 个字符",
trigger: "blur",
},
],
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{
min: 5,
max: 20,
message: "用户名长度在 6 到 20 个字符",
trigger: "blur",
},
],
email: [{}],
};
onMounted(() => {
init();
startInterval();
const token = localStorage.getItem("token");
if (token !== null) {
isLogin.value = true; //
router.push("/videoList"); //
// UID uid.value
}
});
onUnmounted(() => {
stopInterval();
});
//
const startInterval = () => {
if (intervalId.value) {
//
return;
}
intervalId.value = setInterval(getQRStatus, 2000);
};
//
const stopInterval = () => {
if (intervalId.value) {
clearInterval(intervalId.value);
intervalId.value = null; // ID
}
};
const creatQrCode = async () => {
console.log("creatQrCode:", uuid);
var qrcode = new qrcode(this.$refs.qrCodeUrl, {
text: uuid, //
width: 100,
height: 100,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H,
});
};
//
const login = async () => {
const onLogin = async () => {
console.log("params:", param);
loginData.value.username = param.username;
loginData.value.password = param.password;
loginData.value.fingerprint = "cc913e1ef0c3a6fd2a5e5b55a7063e46";
let result = await loginService(loginData);
globalData.token = result.data;
localStorage.setItem("token", result.data.token);
localStorage.setItem("userId", result.data.id);
localStorage.setItem("username", result.data.username);
let now = new Date();
localStorage.setItem("end_time", now.setDate(now.getHours() + 12)); //
//token.value= result.data;
router.push("/videoList");
};
//
const onRegister = async () => {
//
if (registerData.value.password !== registerData.value.repassword) {
alert("两次密码不一致");
console.log("login result:", result);
if (result.code !== 0) {
//alert(result.message);
ElMessage.error("登录失败!用户名或密码错误");
return;
}
//
let email = registerData.value.email;
let reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
if (!reg.test(email)) {
alert("邮箱格式不正确");
return;
}
let result = await registerService(registerData);
if (result !== null) {
globalData.token = result.data;
localStorage.setItem("token", result.data.token);
localStorage.setItem("userId", result.data.id);
localStorage.setItem("token", result.data.access_token);
localStorage.setItem("userId", result.data.user_id);
localStorage.setItem("username", result.data.username);
let now = new Date();
localStorage.setItem("end_time", now.setDate(now.getHours() + 12)); //
localStorage.setItem("refresh_token", result.data.refresh_token);
await getMyUserInfo(result.data.user_id);
//token.value= result.data;
router.push("/videoList");
}
};
const generateQRCode = () => {
//
const data = uuid;
// canvas DOM
if (qrCodeCanvas.value) {
const canvas = qrCodeCanvas.value;
const ctx = canvas.getContext("2d");
// canvas
canvas.width = 256;
canvas.height = 256;
// 使 qrcode
QRCode.toCanvas(
canvas,
data,
{
width: 256,
height: 256,
color: {
dark: "#000000",
light: "#ffffff",
},
},
function (error) {
if (error) console.error(error);
console.log("二维码已生成");
}
);
}
};
const getUUID = async () => {
const getMyUserInfo = async (id) => {
let result = {};
try {
const response = await getUUIDService({
device: "windows",
address: localStorage.getItem("address"),
ip: localStorage.getItem("ip"),
});
uuid = response.data.toString();
let uid = uuid.toString();
//await creatQrCode(uid);
generateQRCode(uuid);
} catch (error) {
console.log(error);
let tokenData = {
token: localStorage.getItem("token"),
id: id,
};
result = await GetUserInfoService(tokenData);
if (result.code === 0) {
//console.log("token data:",this.tokenData)
localStorage.setItem("video_func", result.data.VideoFunc > 0 ? "true" : "false");
localStorage.setItem("device_func", result.data.DeviceFunc > 0 ? "true" : "false");
localStorage.setItem("cid_func", result.data.CIDFunc > 0 ? "true" : "false");
localStorage.setItem("role", result.data.Role === "admin" ? "admin" : "user");
//alert("video_func:" + localStorage.getItem("video_func")+" type:" +typeof(localStorage.getItem("video_func")));
router.push("/user");
}
} catch (e) {
console.log(e);
}
return result;
};
const getQRStatus = async () => {
let result = await getQRService({ uuid: uuid });
if (result.code === 0) {
if (result.data === "0") {
} else if (result.data === "1") {
qr_status.value = "等待确认";
} else {
globalData.token = result.data;
localStorage.setItem("token", result.data.token);
localStorage.setItem("userId", result.data.id);
localStorage.setItem("username", result.data.username);
let now = new Date();
localStorage.setItem("end_time", now.setDate(now.getHours() + 12)); //
//token.value= result.data;
router.push("/videoList");
}
} else {
alert(result.message);
}
};
const getIpClient = async () => {
try {
const response = await axios.get("https://ip.zxinc.org/api.php?type=json");
loginData.value.ip = response.data.data.myip;
localStorage.setItem("ip", response.data.data.myip);
localStorage.setItem("city", response.data.data.country);
localStorage.setItem("address", response.data.data.location);
// console.log("ip:",response.data.ip);
// console.log("login ip:",loginData.ip);
// console.log(response.data);
// console.log(loginData);
} catch (error) {
console.error(error);
}
};
const init = async () => {
getIpClient();
await getUUID();
};
const register = async () => {
let result = registerService(registerData.value);
if (result.code === 0) {
alert(result.message);
} else {
alert(result.message);
}
};
//
</script>
<style scoped>
canvas {
border: 1px solid #000;
.login-bg {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
/* background: url(../assets/img/login-bg.jpg) center/cover no-repeat; */
}
.login-header {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 40px;
}
.logo {
width: 35px;
}
.login-title {
font-size: 22px;
color: #333;
font-weight: bold;
}
.login-container {
width: 450px;
border-radius: 5px;
background: #fff;
padding: 40px 50px 50px;
box-sizing: border-box;
}
.pwd-tips {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
margin: -10px 0 10px;
color: #787878;
}
.pwd-checkbox {
height: auto;
}
.login-btn {
display: block;
width: 100%;
}
.login-tips {
font-size: 12px;
color: #999;
}
.login-text {
display: flex;
align-items: center;
margin-top: 20px;
font-size: 14px;
color: #787878;
}
</style>

107
src/views/Menu.vue Normal file
View File

@ -0,0 +1,107 @@
<template>
<el-button
v-if="func_permissions.video"
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/videoList')"
>视频列表</el-button
>
<el-button
v-if="func_permissions.device"
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/device')"
>设备管理</el-button
>
<el-button
v-if="func_permissions.cid"
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/cid')"
>集成部署</el-button
>
<el-button
v-if="func_permissions.role"
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/file')"
>文件</el-button
>
<el-button
v-if="func_permissions.role"
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/shell')"
>执行命令</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/User')"
>用户</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/chat')"
>聊天</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/group')"
>群组</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/projectSelect')"
>项目选择</el-button
>
<el-button
type="primary"
size="mini"
class="el-button--danger"
@click="logout()"
>退出登录</el-button
>
</template>
<script>
import { GetUserInfoService } from "@/api/user.js";
export default {
data() {
return {
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
id: 2002,
keyword: "",
},
func_permissions: {
video: localStorage.getItem("video_func") === "true", //stringboolean
device: localStorage.getItem("device_func") === "true", //stringboolean
cid: localStorage.getItem("cid_func") === "true", //stringboolean
role: localStorage.getItem("role") === "admin", //stringboolean
},
};
},
methods: {
handleMenuSelect(path) {
//this.getMyUserInfo();
this.$router.push(path);
},
logout() {
//退
if (!confirm("确定退出登录吗?")) {
return;
}
//退
localStorage.clear();
this.$router.push("/login");
},
},
};
</script>

724
src/views/ShellList.vue Normal file
View File

@ -0,0 +1,724 @@
<script>
import router from "@/router/index.js";
import { ElMessage } from "element-plus";
import Menu from "@/views/Menu.vue";
import { getConfigShellListService } from "@/api/shell.js";
import { addConfigShellService } from "@/api/shell.js";
import { deleteConfigShellService } from "@/api/shell.js";
import { updateConfigShellService } from "@/api/shell.js";
import { GetMonitorDeviceInfoService } from "@/api/tool.js";
import { UpdateMonitorDeviceInfoService } from "@/api/tool.js";
import { DelMonitorDeviceInfoService } from "@/api/tool.js";
export default {
data() {
return {
ip: "",
tableData: [],
loading: false,
search_id: 2002,
dialogVisible: false,
ConfigShellUpdateForm: {},
keyword: "",
updateDialogVisible: false,
addConfigFileVisible: false,
ConfigFileCurrentPageData: [],
pageSize: 10,
currentPage: 1,
upload_file: null, //
file_md5: "", //md5
addForm: {
shell_name: "",
shel_content: "",
server:""
},
serverList: [
{ label: "家里服务器", value: "home_server" },
{ label: "腾讯服务器", value: "tx_vp_server" },
// { label: "", value: "aliyun_vp_server" },
{ label:"azure服务器", value:"azure_vp_server" },
{ label: '阿里云成都服务器', value: "aliyun_chengdu_vp_server"}
],
monitor_list: [],
monitor_add_update_visible: false,
monitor_update_add: {},
role: "",
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
username: localStorage.getItem("username"),
id: 2002,
server: "gep.ljsea.top",
keyword: "",
},
};
},
// methods
//
methods: {
async getConfigFileList() {
let result = {};
this.loading = true;
try {
//search_id
let req = {
token: this.tokenData.token,
type: "all",
};
result = await getConfigShellListService(req);
} catch (e) {
console.log(e);
} finally {
this.loading = false;
}
let data = result.data;
if (data !== undefined && data !== null) {
this.tableData = data;
}
for(let i = 0;i<this.tableData.length;i++) {
this.tableData[i].UpdatedAt = this.formattedTime(this.tableData[i].UpdatedAt);
this.tableData[i].CreatedAt = this.formattedTime(this.tableData[i].CreatedAt)
//console.log('this.ConfigFileList:',this.ConfigFileList);
}
this.currentPageData();
},
addConfigFileV() {
this.addConfigFileVisible = true;
},
handleServerChange() {
localStorage.setItem("config_file_server", this.tokenData.server);
this.getConfigFileList();
},
async addConfigFile() {
this.addDialogVisible = false;
let result = {};
try {
let req = {
token: this.tokenData.token,
shell_name: this.addForm.shell_name,
shell_content: this.addForm.shell_content,
server: this.addForm.server
};
result = await addConfigShellService(req);
if (result.code == 0) {
ElMessage.success("添加成功");
this.getConfigFileList();
this.addConfigFileVisible = false;
} else {
//alert("");
ElMessage.error("添加失败");
}
} catch (e) {
console.log(e);
}
},
async updateConfigShellInfo() {
let result = {};
try {
let d={}
// for (var key in this.ConfigShellUpdateForm) {
// d[key] = this.ConfigShellUpdateForm[key];
// }
let req = {
token: this.tokenData.token,
shells: [{"id":this.ConfigShellUpdateForm.ID,"shell_result":this.ConfigShellUpdateForm.ShellResult,"status":this.ConfigShellUpdateForm.Status}],
};
result = await updateConfigShellService(req);
if (result.code === 0) {
ElMessage.success("更新成功");
this.updateDialogVisible = false;
} else {
ElMessage.error("更新失败");
}
} catch (e) {
console.log(e);
}
},
async deleteConfigFile(index) {
//
let isDelete = confirm("是否删除?");
if (!isDelete) {
return;
}
let result = {};
try {
let req = {
token: this.tokenData.token,
shells: [{"id":this.ConfigFileCurrentPageData[index].ID}],
};
console.log("req:", req);
result = await deleteConfigShellService(req);
if (result.code == 0) {
ElMessage.success("删除成功");
this.getConfigFileList();
} else {
ElMessage.error("删除失败");
}
} catch (e) {
console.log(e);
}
},
formattedTime(isoTime) {
const date = new Date(isoTime);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
async updateConfigShell(index) {
//console.log("index:", index);
let cf = this.ConfigFileCurrentPageData[index];
// console.log("cf:", cf);
// let req = {
// token: this.tokenData.token,
// id: cf.ID,
// type: "one",
// };
// let result = await getConfigShellListService(req);
// let data = result.data;
this.ConfigShellUpdateForm = cf;
this.updateDialogVisible = true;
},
showMonitorList() {
this.dialogVisible = true;
this.getMonitorDeviceList();
},
async createAgain(index) {
let cf = this.ConfigFileCurrentPageData[index];
this.addForm.shell_name = cf.ShellName;
this.addForm.shell_content = cf.ShellContent;
this.addForm.server = cf.Server;
await this.addConfigFile();
},
onSubmit() {
getConfigFileList();
},
currentPageData() {
this.ConfigFileCurrentPageData = this.tableData.slice(
(this.currentPage - 1) * this.pageSize,
this.currentPage * this.pageSize
);
},
handleSizeChange(val) {
//console.log(` ${val} `);
this.pageSize = val;
this.currentPageData();
},
handleCurrentChange(val) {
//console.log(`: ${val}`);
this.currentPage = val;
this.currentPageData();
},
async displayMyInfo() {
await this.getMyUserInfo(this.tokenData.user_id);
this.updateDialogVisible = true;
},
async displayUserInfo(id) {
await this.getMyUserInfo(id);
this.updateDialogVisible = true;
},
handleMenuSelect(val) {
router.push(val);
},
toVideoList() {
router.push("/videoList");
},
async getMonitorDeviceList(){
try {
let req = {
token: this.tokenData.token,
type: "all",
};
let result = await GetMonitorDeviceInfoService(req);
if (result.code === 0) {
this.monitor_list = result.data;
console.log("monitor_list:", this.monitor_list);
this.dialogVisible = true; //
} else {
ElMessage.error("获取设备列表失败");
}
} catch (e) {
console.log(e);
}
},
updateMonitorShow(index) {
this.monitor_add_update_visible = true;
this.monitor_update_add = { ...this.monitor_list[index] }; //
},
//
async addUpdateMonitor(){
let req = {
"token": this.tokenData.token,
"devices": [this.monitor_update_add],
};
req.devices[0].expire =parseInt(req.devices[0].expire);
try{
let result = await UpdateMonitorDeviceInfoService(req);
if (result.code === 0) {
ElMessage.success("设备信息更新成功");
this.monitor_add_update_visible = false;
} else {
ElMessage.error("设备信息更新失败");
}
}catch (e) {
console.log(e);
}
},
async DelMonitor(index) {
let isDelete = confirm("是否删除?");
if (!isDelete) {
return;
}
let req = {
token: this.tokenData.token,
devices: [this.monitor_list[index]],
};
try {
let result = await DelMonitorDeviceInfoService(req);
if (result.code === 0) {
ElMessage.success("设备删除成功");
this.getMonitorDeviceList();
} else {
ElMessage.error("设备删除失败");
}
} catch (e) {
console.log(e);
}
},
//
tableRowClassName({ row, rowIndex }) {
switch (row.Status) {
case 0:
return 'rgba(243, 243, 248, 0.1)'; //
case 1:
return 'rgba(0, 0, 255, 0.5)'; //
case 2:
return 'rgba(0, 0, 255, 0.9)'; //
default:
return 'transparent'; //
}
},
},
//
//
async mounted() {
let now = new Date();
if (localStorage.getItem("token") === null) {
router.push("/login");
}
await this.getConfigFileList();
//await this.getMyUserInfo(localStorage.getItem("userId"));
},
};
</script>
<template>
<div>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>命令分发</el-header
>
<el-container>
<el-main>
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
<el-dialog
v-model="updateDialogVisible"
title="编辑配置"
width="60%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="updateFormRef"
:model="ConfigShellUpdateForm"
:rules="UserUpdateFormRules"
label-width="70px"
>
<!-- row -->
<el-row>
<el-col :span="12">
<el-form-item label="ID">
<el-input
v-model="ConfigShellUpdateForm.ID"
disabled
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="名称">
<el-input
v-model="ConfigShellUpdateForm.ShellName"
disabled
></el-input>
</el-form-item>
</el-col>
<el-col :span="32">
<el-form-item label="内容">
<el-input
v-model="ConfigShellUpdateForm.ShellContent"
disabled
type="textarea"
style="width: 512px"
></el-input>
</el-form-item>
</el-col>
<el-col>
<el-form-item label="运行结果" prop="shell_result">
<el-input
type="textarea"
v-model="ConfigShellUpdateForm.ShellResult"
style="width: 600px"
:autosize="{ minRows: 4, maxRows: 8 }"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="updateDialogVisible = false"
>取消</el-button
>
<el-button type="primary" @click="updateConfigShellInfo()"
>确定</el-button
>
</span>
</template>
</el-dialog>
</el-form-item>
<!-- 表单 -->
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
:disabled="loading"
@click="getConfigFileList()"
>查询</el-button
>
</el-form-item>
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
@click="addConfigFileV()"
>创建命令</el-button
>
</el-form-item>
<el-form-item>
<el-button
class="el-button--danger"
type="primary"
@click="getMonitorDeviceList()"
>设备监控</el-button
>
</el-form-item>
</el-form>
</el-form>
<el-dialog
v-model="addConfigFileVisible"
title="创建命令"
width="50%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="addFormRef"
:model="addForm"
:rules="addFormRules"
label-width="70px"
>
<el-row>
<el-form-item label="名称" prop="shell_name">
<el-input
v-model="addForm.shell_name"
autocomplete="on"
></el-input>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="内容" prop="file_path">
<el-input
type="textarea"
v-model="addForm.shell_content"
autocomplete="on"
style="width: 600px"
:autosize="{ minRows: 4, maxRows: 8 }"
></el-input>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="服务器" prop="server">
<el-select v-model="addForm.server" filterable allow-create>
<el-option
v-for="item in serverList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-row>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="addConfigFileVisible = false"
>取消</el-button
>
<el-button type="primary" @click="addConfigFile()"
>确定</el-button
>
</span>
</template>
</el-dialog>
<el-dialog
v-model="monitor_add_update_visible"
title="编辑监控"
width="50%"
@close="handleClose">
<el-form
ref="monitorUpdateFormRef"
:model="monitor_update_add"
:rules="UserUpdateFormRules"
label-width="70px"
>
<el-row>
<el-form-item label="设备" prop="id">
<el-input
v-model="monitor_update_add.id"
></el-input>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="状态" prop="status">
<el-select v-model="monitor_update_add.status">
<el-option label="在线" value="1"></el-option>
<el-option label="离线" value="0"></el-option>
</el-select>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="过期时间" prop="expire">
<el-input
v-model="monitor_update_add.expire"
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
></el-input>
</el-form-item>
</el-row>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="monitor_add_update_visible = false"
>取消</el-button
>
<el-button type="primary" @click="addUpdateMonitor()"
>确定</el-button
>
</span>
</template>
</el-dialog>
<el-dialog
v-model="dialogVisible"
title="设备状态监控"
width="50%"
@close="handleClose"
>
<el-button type="primary" @click="monitor_add_update_visible = true">添加</el-button>
<el-table
:data="monitor_list"
stripe
width="90%"
fit
>
<el-table-column prop="id" label="设备" width="150"></el-table-column>
<el-table-column prop="status" label="状态" width="150">
<template #default="scope">
<el-tag
:type="scope.row.status === '1' ? 'success' : 'danger'"
>{{ scope.row.status === "1" ? '在线' : '离线' }}</el-tag
>
</template>
</el-table-column>
<el-table-column prop="expire" label="过期时间" width="150">
</el-table-column>
<el-table-column label="操作" width="270">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="updateMonitorShow(scope.$index)"
>编辑</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="DelMonitor(scope.$index)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</el-dialog>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="ConfigFileCurrentPageData" width="100%" v-loading="loading">
:row-style="tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
prop="ShellName"
label="命令名称"
width="120"
></el-table-column>
<el-table-column
prop="ShellContent"
label="命令内容"
show-overflow-tooltip
width="120"
></el-table-column>
<el-table-column
prop="Status"
label="状态"
width="100"
>
<template #default="scope">
<el-tag
v-if="scope.row.Status === 0"
>任务提交</el-tag
>
<el-tag
v-if="scope.row.Status === 1"
type="warning"
>正在运行</el-tag>
<el-tag
v-if="scope.row.Status === 2"
type="success"
>执行成功</el-tag>
<el-tag
v-if="scope.row.Status === 3"
type="danger"
>执行出错</el-tag>
</template>
</el-table-column>
<el-table-column
prop="ShellRuntime"
label="SR"
width="50"
>
<template #default="scope">
<!-- 转为秒两位小数-->
{{ Math.round(scope.row.ShellRuntime * 100) / 100 }}
</template>
</el-table-column>
<el-table-column
prop="ShellDuration"
label="SD"
width="50"
>
<template #default="scope">
<!-- 转为秒两位小数-->
{{ Math.round(scope.row.ShellDuration * 100) / 100 }}
</template>
</el-table-column>
<el-table-column
prop="Server"
label="服务器"
width="100"
></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="160"
></el-table-column>
<el-table-column
prop="UpdatedAt"
label="上次更新"
width="160"
></el-table-column>
<!-- <el-table-column
prop="AuthID"
label="创建用户ID"
width="40"
></el-table-column> -->
<el-table-column label="操作" width="270">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="updateConfigShell(scope.$index)"
>编辑</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="deleteConfigFile(scope.$index)"
>删除</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="createAgain(scope.$index)"
>再次执行</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页条 -->
<!-- Pagination 分页 -->
<el-pagination
background
layout="total,sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:total="tableData.length"
></el-pagination>
</el-main>
</el-container>
</el-container>
</div>
</template>
<style>
.blueRowbg {
background: "#488aff";
}
</style>

View File

@ -1,15 +1,44 @@
<script>
import axios from "axios";
import { SearchUserService } from "@/api/user.js";
import { getFriendReqService } from "@/api/chat.js";
import {updateUserInfoService} from "@/api/user.js";
import {acceptInviteService } from "@/api/user.js";
import { rejectInviteService } from "@/api/user.js";
import { addGroupRequestService } from "@/api/user.js";
import {GetUserInfoService} from "@/api/user.js";
import { GetRedisInfoService } from "@/api/tool.js";
import {DelFGService} from "@/api/user.js";
import router from "@/router/index.js";
import { UploadFileService } from "@/api/tool.js";
import {GetFileInfoByMd5Service } from "@/api/tool.js";
import Cookies from "js-cookie";
import { getFriendListService } from "@/api/chat.js";
import {sendMessageService} from "@/api/chat.js";
import { ElMessage } from 'element-plus';
import CryptoJS from 'crypto-js';
import Menu from "@/views/Menu.vue";
export default {
data() {
return {
ip: "",
tableData: [],
search_id: 2002,
UserUpdateForm:{},
keyword: "",
FriendsRequestIsDisplay:false,
updateDialogVisible: false,
FriendsGRequestList:[],
FriendsTableIsDisplay:false,
RedisIsDisplay:false,
avatar_file: null,
file_md5: "",
RedisList:[],
FriendsGList:[],
GroupList:[],
groups:[],
role: "",
tokenData: {
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
@ -27,8 +56,23 @@ export default {
async getUserList() {
let result = {};
try {
this.tokenData.id = this.search_id;
//search_id
if(isNaN(this.search_id)){
//
this.keyword = this.search_id;
this.tokenData.id = -1;
this.tokenData.keyword = this.keyword;
}else if(isFinite(this.search_id)){
//ID
this.tokenData.id = this.search_id;
this.tokenData.keyword = "";
}else{
//
ElMessage.error("输入错误,请输入数字或者关键字");
return;
}
Cookies.set("search_id", this.search_id);
Cookies.set("keyword", this.keyword);
result = await SearchUserService(this.tokenData);
@ -37,6 +81,261 @@ export default {
}
let data = result.data;
this.tableData = data;
this.groups= result.group;
},
async setUserPermission(index) {
var id = this.tableData[index].ID;
await this.displayUserInfo(id);
},
async requestFriend(index) {
var id = this.tableData[index].ID;
var name = this.tableData[index].Name;
let result ={}
try{
result =await sendMessageService({
token: localStorage.getItem("token"),
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
msg: "请求加好友",
type: 4,
});
if(result.code ===0){
ElMessage.success("请求发送成功");
}else{
ElMessage.error("请求发送失败,请检查是否已经发送过请求或者对方已经是好友");
}
}catch(e){
console.log(e);
}
},
//
async displayFriends(){
let result ={}
try{
result = await getFriendListService(this.tokenData);
if(result.code ===0){
this.FriendsGList = result.data.friends;
this.GroupList=result.data.groups;
this.FriendsTableIsDisplay = true;
}else{
ElMessage.error("获取好友列表失败");
}
}catch(e){
console.log(e);
}
},
//
async DelFriendsOrGroup(index){
//
if (!confirm("确定删除吗?")) {
return;
}
var id = this.FriendsGList[index].id;
var name = this.FriendsGList[index].name;
let result ={}
try{
result =await DelFGService({
token: localStorage.getItem("token"),
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
msg: "删除好友",
type: 1,
});
if(result.code ===0){
ElMessage.success("删除好友成功");
this.displayFriends();
}else{
ElMessage.error("删除好友失败");
}
}catch(e){
console.log(e);
}
},
async addGroupRequest(index){
var group_id=this.groups[index].ID;
let result={}
let req={
token: localStorage.getItem("token"),
from_user_id: localStorage.getItem("userId"),
to_user_id: 0,
group_id: group_id,
msg: "请求加入群组",
type: 5,
}
try{
result = await addGroupRequestService(req);
console.log(result.code);
if(result.code === 0){
ElMessage.success("请求发送成功");
}else{
ElMessage.error("操作失败已有请求或者已经是群组成员");
}
}catch(e){
ElMessage.error("操作失败已有请求或者已经是群组成员");
}
},
//
async AcceptFriendsOrGroup(index){
var id = this.FriendsGRequestList[index].id;
var im_id = this.FriendsGRequestList[index].im_id;
var name = this.FriendsGRequestList[index].name;
let result ={}
try{
result =await acceptInviteService({
token: localStorage.getItem("token"),
id: im_id,
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
msg: "接受好友请求",
index: 1,
type: 1,
});
if(result.code ===0){
ElMessage.success("接受好友请求成功");
this.displayFriendReq()
}else{
ElMessage.error("接受好友请求失败");
}
}catch(e){
console.log(e);
}
},
handleAvatarFileUpload(e) {
this.avatar_file = e.target.files[0];
//
if (!this.avatar_file.type.startsWith("image/")) {
ElMessage.error("请选择图片文件");
this.avatar_file = null;
return;
}
//this.UserUpdateForm.avatar = URL.createObjectURL(this.avatar_file);
this.uploadAvatarFile();
},
readFileAndCalculateMD5() {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const wordArray = CryptoJS.lib.WordArray.create(event.target.result);
const md5Hash = CryptoJS.MD5(wordArray);
const md5Str = md5Hash.toString(CryptoJS.enc.Hex);
//console.log("onload: " + md5Str);
this.file_md5 = md5Str;
resolve(md5Str);
};
reader.onerror = (error) => {
reject(error);
};
reader.readAsArrayBuffer(this.avatar_file);
});
},
async uploadAvatarFile(){
if (this.avatar_file == null) {
alert('请先选择要上传的文件');
return;
}
try {
let result={};
this.file_md5 = await this.readFileAndCalculateMD5(this.avatar_file);
//console.log("md5:",this.file_md5);
let md5_result = await GetFileInfoByMd5Service({"md5":this.file_md5,token:this.tokenData.token,"type":1});
if(md5_result.code === 0){
result = md5_result;
}else{
let formData = new FormData();
formData.append('file', this.avatar_file);
//console.log("add file: " + this.file);
formData.append('upload_type', "1");
formData.append('md5', this.file_md5);
formData.append('auth_type', "public");
//console.log("formData:",formData);
result = await UploadFileService(formData,this.tokenData.token);
if (result.code!== 0) {
ElMessage.error('上传文件失败,请稍后再试');
return;
}
}
let resp_data = result.data;
//console.log("resp:",resp_data);
let url = "https://tx.ljsea.top/tool/file/"+resp_data.FileStoreName;
this.UserUpdateForm.avatar = url;
//
await this.updateUserInfo();
} catch (error) {
ElMessage.error('上传文件时出现网络错误,请稍后再试');
console.error(error);
}
},
async updateUserInfo(){
let result ={}
try{
let req={};
req.token=localStorage.getItem("token");
for(var key in this.UserUpdateForm){
req[key] = this.UserUpdateForm[key];
}
result = await updateUserInfoService(req)
if (result.code === 0) {
ElMessage.success("更新成功");
this.updateDialogVisible = false;
} else {
ElMessage.error("更新失败");
}
}catch(e){
console.log(e);
}
},
async RefuseFriendsOrGroup(index){
var id = this.FriendsGRequestList[index].id;
var im_id = this.FriendsGRequestList[index].im_id;
var name = this.FriendsGRequestList[index].name;
let result ={}
try{
result =await rejectInviteService({
token: localStorage.getItem("token"),
id: im_id,
from_user_id: localStorage.getItem("userId"),
to_user_id: id,
msg: "拒绝好友请求",
index: 1,
type: 1,
});
if(result.code ===0){
ElMessage.success("拒绝请求成功");
this.displayFriendReq()
}else{
ElMessage.error("拒绝请求失败");
}
}catch(e){
console.log(e);
}
},
//
async displayFriendReq(){
let result ={}
try{
result =await getFriendReqService(this.tokenData)
if(result.code ===0){
this.FriendsGRequestList = result.data;
this.FriendsRequestIsDisplay = true;
}else{
ElMessage.error("获取好友请求列表失败");
}
}catch(e){
console.log(e);
}
},
onSubmit() {
getUserList({ token: token });
@ -47,23 +346,78 @@ export default {
handleCurrentChange() {
alert("页码发生变化" + val);
},
startChat(index){
//
async startChat(index) {
var id = this.tableData[index].ID;
var name = this.tableData[index].Name;
// var user_data = {
// to_user_id: id,
// to_user_name: this.tableData[index].Name,
// };
//
if(id == localStorage.getItem("userId")){
alert("不能和自己聊天");
return;
}
localStorage.setItem("to_user_id", id);
localStorage.setItem("to_user_name", name);
localStorage.setItem("to_user_id", this.tableData[index].ID);
localStorage.setItem("to_user_name", this.tableData[index].Name);
router.push("/im");
},
async getMyUserInfo(id){
let result = {};
try{
//
this.tokenData.id = id;
if(this.tokenData.id === undefined){
this.tokenData.id = localStorage.getItem("userId");
}
result = await GetUserInfoService(this.tokenData)
if(result.code ===0){
this.UserUpdateForm.id = result.data.ID;
this.UserUpdateForm.name = result.data.Name;
this.UserUpdateForm.email = result.data.Email;
this.UserUpdateForm.redis = result.data.Redis;
this.UserUpdateForm.run = result.data.Run;
this.UserUpdateForm.upload = result.data.Upload;
this.UserUpdateForm.age = result.data.Age;
this.UserUpdateForm.avatar = result.data.Avatar === "" ? "https://gep.ljsea.top/tool/file/9f29cc99-1054-4aff-ab37-e7c0016dd1b5.jpeg":result.data.Avatar;
this.UserUpdateForm.role = result.data.Role;
this.UserUpdateForm.gender = result.data.Gender;
this.UserUpdateForm.create_time = result.data.CreatedAt;
this.UserUpdateForm.update_time = result.data.UpdatedAt;
this.UserUpdateForm.video_func = result.data.VideoFunc;
this.UserUpdateForm.device_func = result.data.DeviceFunc;
this.UserUpdateForm.cid_func = result.data.CIDFunc;
//console.log("token data:",this.tokenData)
if(result.data.ID === parseInt(this.tokenData.userId)){
this.role = result.data.Role;
localStorage.setItem("video_func", result["data"].VideoFunc > 0 ? "true" : "false");
localStorage.setItem("device_func", result["data"].DeviceFunc > 0 ? "true" : "false");
localStorage.setItem("cid_func", result["data"].CIDFunc > 0 ? "true" : "false");
localStorage.setItem("avatar",result.data.Avatar);
//console.log("my role:",this.role);
}
}
}catch(e){
console.log(e);
}
},
async displayMyInfo() {
await this.getMyUserInfo(this.tokenData.user_id)
this.updateDialogVisible= true;
},
async displayRedisInfo(){
let result ={}
let req={
token: localStorage.getItem("token"),
option: "all",
}
try{
result = await GetRedisInfoService(req)
if(result.code ===0){
this.RedisList = result.data;
this.RedisIsDisplay = true;
}else{
ElMessage.error("获取Redis数据失败");
}
}catch(e){
console.log(e);
}
},
async displayUserInfo(id) {
await this.getMyUserInfo(id)
this.updateDialogVisible= true;
},
handleMenuSelect(val) {
@ -87,10 +441,11 @@ export default {
//
//
async mounted() {
let now = new Date();
if (localStorage.getItem("token") === null) {
router.push("/login");
}
await this.getMyUserInfo(localStorage.getItem("userId"));
this.search_id = Cookies.get("search_id")?Cookies.get("search_id"):2002;
this.keyword = Cookies.get("keyword")?Cookies.get("keyword"):"";
},
@ -99,58 +454,147 @@ export default {
<template>
<div>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/videoList')"
>视频列表</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/device')"
>设备管理</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/User')"
>用户</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/cid')"
>集成部署</el-button
>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>用户搜索列表</el-header
>
<el-container>
<el-main>
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-col :span="8">
<!-- 搜索与添加区域 -->
<el-input
placeholder="请输入ID"
placeholder="请输入ID或关键字"
v-model="search_id"
clearable
@clear="getUserList"
>
</el-input>
<el-input
placeholder="请输入关键字"
v-model="keyword"
clearable
@clear="getUserList"
>
</el-input>
<template #append>
<el-button @click="getUserList"
><el-icon><search /></el-icon
></el-button>
</template>
</el-col>
<el-form-item>
<el-button type="primary" @click="displayFriends()"
>好友列表</el-button
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="displayFriendReq()"
>好友请求</el-button
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="displayMyInfo()"
>我的信息</el-button
>
</el-form-item>
<el-form-item v-if = "role === 'admin'">
<el-button type="primary" @click="displayRedisInfo()"
>Redis</el-button
>
</el-form-item>
<el-form-item>
<el-dialog
v-model="updateDialogVisible"
title="我的信息"
width="60%"
:before-close="handleClose"
>
<!-- 内容主体区域 -->
<el-form
ref="updateFormRef"
:model="UserUpdateForm"
:rules="UserUpdateFormRules"
label-width="70px"
>
<el-form-item label="ID" prop="id">
<el-input
disabled
v-model="UserUpdateForm.id"
autocomplete="on"
></el-input>
</el-form-item>
<el-row>
<el-form-item label="头像" prop="name">
<el-avatar :size="80" :src="UserUpdateForm.avatar"></el-avatar>
<!-- 选择图片 -->
<input type="file" @change="handleAvatarFileUpload"/>
</el-form-item>
</el-row>
<el-form-item label="用户名" prop="name">
<el-input
v-model="UserUpdateForm.name"
autocomplete="on"
></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="UserUpdateForm.email" disabled></el-input>
</el-form-item>
<el-form-item label="Age" prop="age">
<el-input v-model="UserUpdateForm.age"></el-input>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-input v-model="UserUpdateForm.gender"></el-input>
</el-form-item>
<el-form-item label="运行权限" prop="run">
<el-switch v-model="UserUpdateForm.run" :active-value="1" :inactive-value="-1" v-if="role === 'admin'"></el-switch>
</el-form-item>
<el-form-item label="redis权限" prop="redis">
<el-switch v-model="UserUpdateForm.redis" :active-value="1" :inactive-value="-1" v-if="role === 'admin'"></el-switch>
</el-form-item>
<el-form-item label="上传权限" prop="upload">
<el-switch v-model="UserUpdateForm.upload" :active-value="1" :inactive-value="-1" v-if="role === 'admin'"></el-switch>
</el-form-item>
<el-form-item label="用户权限" prop="role">
<!-- <el-input v-model="UserUpdateForm.role" v-if="role === 'admin'"></el-input> -->
<el-input v-model="UserUpdateForm.role" disabled v-if="role !== 'admin'"></el-input>
<el-select v-model="UserUpdateForm.role" v-if="role === 'admin'">
<el-option label="admin" value="admin">管理员</el-option>
<el-option label="user" value="user">普通用户</el-option>
</el-select>
<!-- <el-selector v-model="UserUpdateForm.role" disabled v-if="role !== 'admin'">
<el-option label="admin" value="admin"></el-option>
<el-option label="user" value="user"></el-option>
</el-selector> -->
</el-form-item>
<el-form-item label="视频管理" prop="video_func">
<el-switch v-model="UserUpdateForm.video_func" :active-value="1" :inactive-value="-1" v-if="role === 'admin'"></el-switch>
</el-form-item>
<el-form-item label="设备管理" prop="device_func">
<el-switch v-model="UserUpdateForm.device_func" :active-value="1" :inactive-value="-1" v-if="role === 'admin'"></el-switch>
</el-form-item>
<el-form-item label="集成部署" prop="cid_func">
<el-switch v-model="UserUpdateForm.cid_func" :active-value="1" :inactive-value="-1" v-if="role === 'admin'"></el-switch>
</el-form-item>
<el-form-item label="注册时间" prop="create_time">
<el-input v-model="UserUpdateForm.create_time" disabled></el-input>
</el-form-item>
<el-form-item label="上次修改" prop="update_time">
<el-input v-model="UserUpdateForm.update_time" disabled></el-input>
</el-form-item>
</el-form>
<!-- 底部区域 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="updateDialogVisible = false"
>取消</el-button
>
<el-button type="primary" @click="updateUserInfo()"
>确定</el-button
>
</span>
</template>
</el-dialog>
</el-form-item>
<!-- 表单 -->
<el-form :inline="true" :model="tokenData" class="demo-form-inline">
<el-form-item>
@ -162,6 +606,122 @@ export default {
>
</el-form-item>
</el-form>
</el-form>
<el-dialog
title="好友请求"
width="50%"
v-model="FriendsRequestIsDisplay"
center>
<el-table :data="FriendsGRequestList" width="100%">
<el-table-column prop="id" label="id" width="80"></el-table-column>
<el-table-column
prop="name"
label="名称"
width="100"
></el-table-column>
<el-table-column
prop="email"
label="用户邮箱"
width="180"
></el-table-column>
<el-table-column
prop="age"
label="用户Age"
width="120"
></el-table-column>
<el-table-column>
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="AcceptFriendsOrGroup(scope.$index)"
>同意请求</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="RefuseFriendsOrGroup(scope.$index)"
>拒绝请求</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-dialog
title="用户好友"
width="40%"
v-model="FriendsTableIsDisplay"
center>
<el-table :data="FriendsGList" width="100%">
<el-table-column prop="id" label="id" width="80"></el-table-column>
<el-table-column
prop="name"
label="名称"
width="100"
></el-table-column>
<el-table-column
prop="email"
label="用户邮箱"
width="180"
></el-table-column>
<el-table-column>
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="DelFriendsOrGroup(scope.$index)"
>删除好友或群组</el-button
>
</template>
</el-table-column>
</el-table>
</el-dialog>
<el-dialog
title="Redis数据"
width="60%"
v-model="RedisIsDisplay"
center>
<el-table :data="RedisList" width="100%">
<el-table-column
prop="Key"
label="Key"
width="120"
></el-table-column>
<el-table-column
prop="Value"
label="Value"
width="480"
></el-table-column>
<el-table-column
prop="Type"
label="Type"
width="100"
></el-table-column>
<el-table-column
prop="Expire"
label="Expire(s)"
width="100"
></el-table-column>
<el-table-column>
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="DelFriendsOrGroup(scope.$index)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="tableData" width="100%" border>
@ -185,9 +745,9 @@ export default {
<el-table-column
prop="Gender"
label="用户性别"
width="80"
width="100"
></el-table-column>
<el-table-column label="操作" width="300">
<el-table-column label="操作" width="400">
<template #default="scope">
<el-button
type="primary"
@ -195,6 +755,70 @@ export default {
@click.prevent="startChat(scope.$index)"
>聊天</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="requestFriend(scope.$index)"
>请求加好友</el-button
>
<!-- 如果有权限可设置用户权限 -->
<v-if v-if="role === 'admin'">
<el-button
type="primary"
size="mini"
@click.prevent="setUserPermission(scope.$index)"
>设置权限</el-button
>
</v-if>
<!-- <el-button type="danger" size="mini">删除</el-button> -->
</template>
</el-table-column>
</el-table>
<br />
<h>
群组列表
</h>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="groups" width="100%" border>
:row-style="this.tableRowClassName"
<el-table-column prop="ID" label="id" width="80"></el-table-column>
<el-table-column
prop="GroupName"
label="名称"
width="100"
></el-table-column>
<el-table-column
prop="GroupInfo"
label="描述"
width="180"
></el-table-column>
<el-table-column
prop="GroupType"
label="类型"
width="120"
></el-table-column>
<el-table-column
prop="CreatedAt"
label="创建时间"
width="120"
></el-table-column>
<el-table-column
prop="UpdatedAt"
label="更新时间"
width="120"
></el-table-column>
<el-table-column label="操作" width="350">
<template #default="scope">
<el-button
type="primary"
size="mini"
@click.prevent="addGroupRequest(scope.$index)"
>请求加入</el-button
>
<!-- <el-button type="danger" size="mini">删除</el-button> -->
</template>
</el-table-column>

View File

@ -18,6 +18,7 @@ const videoPlayer = ref(null);
const myPlayer = ref(null);
const route = useRoute();
const router = useRouter();
console.log("video player")
if(localStorage.getItem('token')===null) {
router.push("/login");
}
@ -60,8 +61,8 @@ onUnmounted(() => {
</script>
<style lang="scss" scoped>
.video_wrap {
width: 100vw;
height: 100vh;
width: 50vw;
height: 60vh;
position: relative;
.backIndex {

View File

@ -1,17 +1,30 @@
<script>
import axios from "axios";
import { getVideoListService, quashVideoService } from "@/api/video.js";
import {
getVideoListService,
quashVideoService,
deleteVideoService,
} from "@/api/video.js";
import { delayVideoService } from "@/api/video.js";
import router from "@/router/index.js";
import Cookies from "js-cookie";
import { ElMessage } from "element-plus";
import Menu from "@/views/Menu.vue";
import VideoPlayer from "@/views/Video.vue";
export default {
components: {
VideoPlayer,
},
data() {
return {
ip: "",
tableData: [],
file_sum_size: 0,
dialogVisible: false,
playing_video : "",
tokenData: {
id: -1,
token: localStorage.getItem("token"),
ip: localStorage.getItem("ip"),
userId: localStorage.getItem("userId"),
@ -47,7 +60,7 @@ export default {
for (let i = 0; i < len; i++) {
//this.file_sum_size += parseFloat(data[i].file_size);
data[i].file_size = parseFloat(data[i].file_size / 1024 / 1024).toFixed(
data[i].FileSize = parseFloat(data[i].FileSize / 1024 / 1024).toFixed(
2
);
}
@ -66,10 +79,11 @@ export default {
//
let result = await quashVideoService(this.tokenData);
if (result.code == 0) {
alert(result.message);
//alert(result.message);
ElMessage.success("操作成功!");
this.getVideoList();
} else {
alert("操作失败");
ElMessage.error("操作失败!");
}
},
onSubmit() {
@ -82,12 +96,37 @@ export default {
alert("页码发生变化" + val);
},
playVideo(index) {
this.dialogVisible = true;
// localStorage.setItem("is_to_play", "1");
var id = this.tableData[index].ID;
var name = this.tableData[index].VideoName;
localStorage.setItem("video_id", id);
localStorage.setItem("video_name", name);
//alert("id=" + id + " name=" + name);
router.push("/video");
this.playing_video = "id: " + id + " ; name: " + name;
components.updated();
// //alert("id=" + id + " name=" + name);
//router.push("/video");
},
async deleteVideo(index) {
//
if (!confirm("是否删除?")) {
return;
}
var id = this.tableData[index].ID;
let req = {
id: id,
userId: this.tokenData.userId,
token: this.tokenData.token,
type: "del_with_logic",
};
let result = await deleteVideoService(req);
if (result.code == 0) {
//alert(result.message);
ElMessage.success("操作成功!");
this.getVideoList();
} else {
ElMessage.error("操作失败!");
}
},
async downloadVideo(index) {
var id = this.tableData[index].ID;
@ -133,6 +172,7 @@ export default {
URL.revokeObjectURL(videoUrl);
} catch (error) {
console.error("下载视频时发生错误:", error);
ElMessage.error("下载视频时发生错误");
}
},
async delayVideo(index) {
@ -149,9 +189,11 @@ export default {
try {
var d_re = await delayVideoService(delay_data);
if (d_re.code == 0) {
alert(d_re.message);
//alert(d_re.message);
ElMessage.success(d_re.message);
} else {
alert("操作失败");
ElMessage.error("操作失败");
//alert("");
}
} catch (e) {
console.log(e);
@ -211,12 +253,11 @@ export default {
router.push("/login");
}
// console.log("mounted");
await this.getIpClient();
this.getIpClient();
// if( Cookies.get("entrydate")){
// console.log("entrydate:",Cookies.get("entrydate"));
// this.tokenData.entrydate = [Object(Cookies.get("entrydate")[0]),Object(Cookies.get("entrydate")[1])];
// }
this.getVideoList();
},
};
@ -224,21 +265,7 @@ export default {
<template>
<div>
<el-button type="primary" size="mini" @click.prevent="handleMenuSelect('/videoList')"
>视频列表</el-button
>
<el-button type="primary" size="mini" @click.prevent="handleMenuSelect('/device')"
>设备管理</el-button
>
<el-button type="primary" size="mini" @click.prevent="handleMenuSelect('/User')"
>用户</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="handleMenuSelect('/cid')"
>集成部署</el-button
>
<Menu></Menu>
<el-container style="height: 700px; border: 1px solid #eee">
<el-header style="font-size: 40px; background-color: rgb(238, 241, 246)"
>监控视频列表</el-header
@ -287,11 +314,15 @@ export default {
</el-select>
<el-form-item>
指定视频ID:
<el-col :span="8">
<el-input
placeholder="指定视频ID"
v-model="tokenData.id"
></el-input>
</el-col>
<el-button type="primary" @click="getVideoList()">查询</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="logout()">退出登录</el-button>
</el-form-item>
<el-form-item>
<el-button
class="el-button--danger"
@ -300,11 +331,6 @@ export default {
>全部延迟删除</el-button
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="toDeviceM()"
>设备信息</el-button
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="quashOption()"
>撤销操作</el-button
@ -315,6 +341,20 @@ export default {
</el-form-item> -->
</el-form>
<el-dialog
title="视频播放"
v-model="dialogVisible"
width="60%"
height="60%"
center
>
<div>
视频播放({{playing_video }})
<VideoPlayer v-if="dialogVisible"></VideoPlayer>
</div>
</el-dialog>
<!-- 表格 :row-style="this.tableRowClassName"-->
<el-table :data="tableData" width="100%" border>
:row-style="this.tableRowClassName"
@ -332,17 +372,17 @@ export default {
<el-table-column
prop="CreateTime"
label="开始时间"
width="180"
width="160"
></el-table-column>
<el-table-column
prop="EndTime"
label="结束时间"
width="180"
width="160"
></el-table-column>
<el-table-column
prop="DeleteTime"
label="预期删除时间"
width="180"
width="160"
></el-table-column>
<el-table-column
prop="FileSize"
@ -354,7 +394,7 @@ export default {
label="摄像头"
width="50"
></el-table-column>
<el-table-column label="操作" width="300">
<el-table-column label="操作" width="330">
<template #default="scope">
<el-button
type="primary"
@ -374,6 +414,12 @@ export default {
@click.prevent="downloadVideo(scope.$index)"
>下载</el-button
>
<el-button
type="primary"
size="mini"
@click.prevent="deleteVideo(scope.$index)"
>删除</el-button
>
<!-- <el-button type="danger" size="mini">删除</el-button> -->
</template>

View File

@ -1,36 +1,113 @@
<template>
<div>
<video ref="videoPlayer" class="video-js"></video>
<div class="video_wrap">
<video
width="100%"
height="100%"
ref="videoPlayer"
muted="muted"
class="video-js video"
></video>
</div>
</template>
<script>
import videojs from 'video.js';
<script setup>
import { onUnmounted, ref, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import videojs from "video.js";
import "video.js/dist/video-js.css";
const videoPlayer = ref(null);
const myPlayer = ref(null);
export default {
name: 'VideoPlayer',
props: {
options: {
type: Object,
default() {
return {};
}
}
},
name: "VideoPlayer",
props: {},
data() {
return {
player: null
},
methods: {
playVideoA(){
nextTick(() => {
myPlayer.value = videojs(videoPlayer.value, {
// poster: "//vjs.zencdn.net/v/oceans.png",//
controls: true, //
autoplay: true, //
sources: [
{
src:
"https://gep.ljsea.top/video/mp4?filename=" +
localStorage.getItem("video_name") +
"&id=" +
localStorage.getItem("video_id") +
"&ip=" +
localStorage.getItem("ip")+
"&userId=" +
localStorage.getItem("userId") +
"&token=" +
localStorage.getItem("token"), //
type: localStorage.getItem("video_name").split('.')[1]==="m3u8" ?"application/vnd.apple.mpegurl":"video/mp4",
},
],
controlBar: {
remainingTimeDisplay: {
displayNegative: false,
}
},
mounted() {
this.player = videojs(this.$refs.videoPlayer, this.options, () => {
this.player.log('onPlayerReady', this);
playbackRates: [0.5, 1, 1.5, 2], //
});
});
}
},
beforeDestroy() {
if (this.player) {
this.player.dispose();
onMounted(){
this.playVideoA();
},
onUnmounted(){
if (myPlayer.value) {
myPlayer.value.dispose();
}
}
}
// export default VideoPlayer;
</script>
<style lang="scss" scoped>
.video_wrap {
width: "80%";
height: "80%";
position: relative;
.backIndex {
position: absolute;
top: 0;
left: 0;
height: 50px;
width: 100%;
line-height: 50px;
background: rgba(0, 0, 0, 0.5);
z-index: 99;
padding-left: 10px;
font-size: 20px;
font-weight: 400;
opacity: 0;
transition: all 0.3s;
color: white;
&:hover {
opacity: 1;
}
span {
cursor: pointer;
}
}
.video {
height: 100%;
width: 100%;
}
::v-deep(.vjs-big-play-button) {
margin-left: 45%;
margin-top: 20%;
}
}
</style>

104
src/views/VideoStream.vue Normal file
View File

@ -0,0 +1,104 @@
<template>
<div>
<video ref="videoPlayer" autoplay playsinline></video>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
videoPlayer: null,
source: null, // axiosCancelToken.source便
};
},
mounted() {
this.videoPlayer = this.$refs.videoPlayer;
this.startVideoStream();
},
methods: {
startVideoStream() {
//let url = "https://gep.ljsea.top/device/video_feed?" +"&device_id=" +localStorage.getItem("realvp_device_id") +"&token=" +localStorage.getItem("token"); //
const deviceId = localStorage.getItem("realvp_device_id"); // id
const token = localStorage.getItem("token"); // token
const url = `https://gep.ljsea.top/device/video_feed?device_id=${deviceId}&token=${token}`;
this.source = axios.CancelToken.source();
axios
.get(url, {
responseType: "arraybuffer",
cancelToken: this.source.token,
})
.then((response) => {
console.log("获取视频流成功");
const reader = response.data
.pipeThrough(new window.TextDecoderStream())
.getReader();
const processData = () => {
reader.read().then(({ done, value }) => {
if (done) {
return;
}
const dataString = new window.TextDecoder().decode(value);
const parts = dataString.split("\r\n");
//
const hasFrameMarker = parts.some((part) =>
part.startsWith("--frame")
);
const hasContentTypeMarker = parts.some(
(part) => part === "Content-Type: image/jpeg"
);
if (!hasFrameMarker || !hasContentTypeMarker) {
console.error("视频流数据格式不符合预期,无法解析");
return;
}
parts.forEach((part) => {
if (part.startsWith("--frame")) {
const imageData = [];
let isImageData = false;
parts.forEach((subPart) => {
if (isImageData) {
imageData.push(subPart);
}
if (subPart === "Content-Type: image/jpeg") {
isImageData = true;
}
});
const imageBlob = new Blob(imageData, { type: "image/jpeg" });
const objectURL = URL.createObjectURL(imageBlob);
this.videoPlayer.src = objectURL;
}
});
processData();
});
};
processData();
})
.catch((error) => {
if (axios.isCancel(error)) {
console.log("请求已取消");
} else {
console.error("获取视频流出错:", error);
}
});
},
},
beforeUnmount() {
if (this.source) {
this.source.cancel("组件即将销毁,取消视频流请求");
}
},
};
</script>
<style scoped>
video {
width: 100%;
max-width: 800px;
margin: 0 auto;
}
</style>

76
src/views/callback.vue Normal file
View File

@ -0,0 +1,76 @@
<template>
<div>
<p>回调页面加载授权信息中...</p>
</div>
</template>
<script lang="ts" setup>
//query
import { useRouter, useRoute } from 'vue-router';
import { onMounted } from 'vue';
import { getTokenByCode } from '@/api/user.js';
import { GetUserInfoService } from "@/api/user.js";
import { ElMessage } from 'element-plus';
const route = useRoute();
const router = useRouter();
interface UserToken {
access_token: string; // 访
refresh_token: string; //
user_id: number; // ID
username: string; //
email: string; //
}
onMounted(async () => {
// query
const queryParams = route.query;
console.log('Received query parameters:', queryParams);
let code = queryParams.code;
//alert('Received code: ' + code);
if (code) {
let req = {
code: code,
};
await getTokenByCode(req).then(async (res: any) => {
if (res.code === 0) {
ElMessage.success('获取Token成功');
let userTokenInfo: UserToken = res.data;
localStorage.setItem("token", userTokenInfo.access_token);
localStorage.setItem("refresh_token", userTokenInfo.refresh_token);
localStorage.setItem("userId", userTokenInfo.user_id.toString());
localStorage.setItem("username", userTokenInfo.username);
await getMyUserInfo(userTokenInfo.user_id);
} else {
console.error('获取Token失败:', res.message);
ElMessage.error('获取Token失败: ' + res.message);
}
}).catch((error: any) => {
console.error('请求错误:', error);
});
}
});
const getMyUserInfo = async (id) => {
let result = {};
try {
let tokenData = {
token: localStorage.getItem("token"),
id: id,
};
result = await GetUserInfoService(tokenData);
//alert("get_user_info:" + JSON.stringify(result));
if (result['code'] === 0) {
//console.log("token data:",this.tokenData)
localStorage.setItem("video_func", result["data"].VideoFunc > 0 ? "true" : "false");
localStorage.setItem("device_func", result["data"].DeviceFunc > 0 ? "true" : "false");
localStorage.setItem("cid_func", result["data"].CIDFunc > 0 ? "true" : "false");
localStorage.setItem("role", result['data']['Role']);
router.push("/user");
}
} catch (e) {
console.log(e);
}
};
</script>

View File

@ -0,0 +1,126 @@
<template>
<div class="project-container">
<h1 class="title">选择要跳转项目</h1>
<div class="project-list">
<el-card
v-for="project in projects"
:key="project.id"
class="project-card"
@click="handleSelect(project)"
>
<div class="card-content">
<el-avatar :size="60" :src="project.avatar" />
<div class="project-info">
<h3>{{ project.name }}</h3>
<p class="description">{{ project.description }}</p>
</div>
</div>
</el-card>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import {getUserTokenCode} from '@/api/user'
import { ElMessage } from 'element-plus'
interface Project {
id: string
name: string
description: string
avatar: string
path: string
}
const router = useRouter()
//
const projects = ref<Project[]>([
{
id: '1',
name: 'SAW系统',
description: '毕业设计及相关项目',
avatar: 'https://www.ljsea.top/wp-content/uploads/2025/06/ljsea.jpg',
path: 'https://sv.ljsea.top/#/callback' //path: 'https://gs.ljsea.top/callback'
},
])
const GetTokenCode =async () => {
let req ={
token: localStorage.getItem('token') || ''
}
await getUserTokenCode(req).then((res: any) => {
if (res.code === 0) {
if (res.data.code === '') {
ElMessage.error('获取失败');
return;
}
//alert(':'+res.data.code);
localStorage.setItem('tokenCode', res.data.code);
} else {
console.error('获取Token失败:', res.message);
}
}).catch((error: any) => {
console.error('请求错误:', error);
});
}
const handleSelect = async (project: Project) => {
await GetTokenCode();
let url = project.path + '?code=' + localStorage.getItem('tokenCode');
window.open(url);
}
</script>
<style scoped>
.project-container {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.title {
text-align: center;
margin-bottom: 30px;
color: #333;
}
.project-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.project-card {
cursor: pointer;
transition: transform 0.3s, box-shadow 0.3s;
}
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.card-content {
display: flex;
align-items: center;
padding: 15px;
}
.project-info {
margin-left: 15px;
}
.project-info h3 {
margin: 0 0 8px 0;
color: #333;
}
.description {
margin: 0;
color: #666;
font-size: 14px;
}
</style>

View File

@ -0,0 +1,358 @@
<template>
<transition name="slide">
<div class="side-panel">
<button @click="handleClose" class="close-btn"></button>
<el-button type="primary" @click="UpdateFileCOntent">保存修改</el-button>
<div class="content">
<h2>{{ fileName }}</h2>
<div class="editor-container">
<textarea
ref="textareaRef"
v-model="localContent"
@input="handleInput"
@scroll="handleScroll"
spellcheck="false"
></textarea>
<pre class="highlight-container" ref="highlightRef"><code v-html="highlightedCode"></code></pre>
</div>
</div>
</div>
</transition>
</template>
<script setup lang="ts">
import { ref, watch, nextTick, onMounted } from "vue";
import { updateConfigFileService } from "@/api/file";
import { ElMessage } from "element-plus";
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css';
const props = defineProps({
content: {
type: String,
default: "",
},
show: {
type: Boolean,
default: false,
},
fileName: {
type: String,
default: "编辑代码",
},
fileID: {
type: Number,
default: 0,
},
});
const emit = defineEmits<{
(e: "close"): void;
}>();
const textareaRef = ref<HTMLTextAreaElement | null>(null);
const highlightRef = ref<HTMLElement | null>(null);
const localContent = ref(props.content);
const highlightedCode = ref('');
//
const detectLanguage = (fileName: string) => {
const extension = fileName.split('.').pop()?.toLowerCase();
const languageMap: Record<string, string> = {
'js': 'javascript',
'jsx': 'javascript',
'ts': 'typescript',
'tsx': 'typescript',
'html': 'html',
'css': 'css',
'scss': 'scss',
'less': 'less',
'py': 'python',
'java': 'java',
'php': 'php',
'go': 'go',
'rb': 'ruby',
'rs': 'rust',
'c': 'c',
'cpp': 'cpp',
'cs': 'csharp',
'json': 'json',
'md': 'markdown',
'xml': 'xml',
'yaml': 'yaml',
'yml': 'yaml',
'sh': 'bash',
'bash': 'bash',
'sql': 'sql',
};
return extension && languageMap[extension] ? languageMap[extension] : 'plaintext';
};
//
const highlightCode = () => {
if (!localContent.value) {
highlightedCode.value = '';
return;
}
const language = detectLanguage(props.fileName);
try {
if (language !== 'plaintext') {
const highlighted = hljs.highlight(localContent.value, { language });
highlightedCode.value = highlighted.value;
} else {
//
const highlighted = hljs.highlightAuto(localContent.value);
highlightedCode.value = highlighted.value;
}
} catch (error) {
console.error('Highlight error:', error);
// HTML
highlightedCode.value = localContent.value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
};
//
const handleInput = () => {
highlightCode();
nextTick(() => {
if (textareaRef.value && highlightRef.value) {
//
highlightRef.value.scrollTop = textareaRef.value.scrollTop;
highlightRef.value.scrollLeft = textareaRef.value.scrollLeft;
}
});
};
//
const handleScroll = () => {
if (textareaRef.value && highlightRef.value) {
highlightRef.value.scrollTop = textareaRef.value.scrollTop;
highlightRef.value.scrollLeft = textareaRef.value.scrollLeft;
}
};
// props.content
watch(
() => props.content,
(newVal) => {
localContent.value = newVal;
highlightCode();
}
);
// textarea
watch(
() => props.show,
async (newVal) => {
if (newVal) {
await nextTick();
textareaRef.value?.focus();
highlightCode();
}
}
);
//
onMounted(() => {
highlightCode();
});
const handleClose = () => {
emit("close");
};
const UpdateFileCOntent = async () => {
let req = {
token: localStorage.getItem("token"),
id: props.fileID,
content: localContent.value,
};
try {
let result = await updateConfigFileService(req);
if (result["code"] === 0) {
ElMessage.success("修改成功");
} else {
ElMessage.error("修改失败");
}
} catch (e) {
console.log(e);
}
};
</script>
<style scoped lang="css">
.side-panel {
position: fixed;
top: 0;
right: 0;
width: 70%;
height: 100%;
background-color: #282c34;
z-index: 1001;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.3);
padding: 20px;
display: flex;
flex-direction: column;
color: #abb2bf;
}
.close-btn {
position: absolute;
top: 10px;
right: 10px;
width: 30px;
height: 30px;
background: none;
border: none;
cursor: pointer;
z-index: 1;
}
.close-btn::before,
.close-btn::after {
content: '';
position: absolute;
width: 20px;
height: 2px;
background-color: #abb2bf;
top: 50%;
left: 50%;
transition: background-color 0.2s;
}
.close-btn::before {
transform: translate(-50%, -50%) rotate(45deg);
}
.close-btn::after {
transform: translate(-50%, -50%) rotate(-45deg);
}
.close-btn:hover::before,
.close-btn:hover::after {
background-color: #61afef;
}
.content {
flex: 1;
display: flex;
flex-direction: column;
margin-top: 20px;
}
.content h2 {
color: #e5e5e5;
margin-bottom: 15px;
}
.editor-container {
position: relative;
flex: 1;
border-radius: 4px;
background-color: #282c34;
overflow: hidden;
}
.editor-container textarea {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 12px;
border: 1px solid #3e4451;
border-radius: 4px;
resize: none;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
line-height: 1.5;
color: transparent;
background-color: transparent;
caret-color: #61afef;
z-index: 2;
white-space: pre;
overflow: auto;
tab-size: 2;
}
.editor-container textarea:focus {
outline: none;
border-color: #61afef;
}
.highlight-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 12px;
margin: 0;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
line-height: 1.5;
pointer-events: none;
overflow: auto;
z-index: 1;
white-space: pre;
tab-size: 2;
background-color: #282c34;
}
.highlight-container code {
font-family: inherit;
}
/* 滚动条样式 */
.editor-container textarea::-webkit-scrollbar,
.highlight-container::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.editor-container textarea::-webkit-scrollbar-track,
.highlight-container::-webkit-scrollbar-track {
background: #21252b;
}
.editor-container textarea::-webkit-scrollbar-thumb,
.highlight-container::-webkit-scrollbar-thumb {
background: #3e4451;
border-radius: 4px;
}
.editor-container textarea::-webkit-scrollbar-thumb:hover,
.highlight-container::-webkit-scrollbar-thumb:hover {
background: #4b5363;
}
/* 保存按钮样式 */
:deep(.el-button--primary) {
background-color: #61afef;
border-color: #61afef;
}
:deep(.el-button--primary:hover) {
background-color: #528bbc;
border-color: #528bbc;
}
.slide-enter-active,
.slide-leave-active {
transition: transform 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
transform: translateX(100%);
}
</style>