Compare commits
4 Commits
main
...
cdf778df93
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdf778df93 | ||
|
|
8761b5e45e | ||
|
|
62c642643d | ||
|
|
cd0bc86803 |
2
.env
2
.env
@@ -19,7 +19,7 @@ VITE_LAMP_PASSWORD = fjoc(1KHP(Ls&Bje)C
|
|||||||
VITE_LAMP_AUTHORIZATION = Y3VlZGVzX2FkbWluOmN1ZWRlc19hZG1pbl9zZWNyZXQ=
|
VITE_LAMP_AUTHORIZATION = Y3VlZGVzX2FkbWluOmN1ZWRlc19hZG1pbl9zZWNyZXQ=
|
||||||
|
|
||||||
# 当需要重置localStorage时, 修改此变量
|
# 当需要重置localStorage时, 修改此变量
|
||||||
VITE_STORAGE_VERSION = 5
|
VITE_STORAGE_VERSION = 3
|
||||||
|
|
||||||
# 调试码
|
# 调试码
|
||||||
VITE_DEBUG_CODE = ndm_debug
|
VITE_DEBUG_CODE = ndm_debug
|
||||||
|
|||||||
141
README.md
141
README.md
@@ -40,145 +40,18 @@ pnpm build
|
|||||||
|
|
||||||
在执行 `pnpm build` 之前,你可以在 `package.json` 中修改 `version` 字段,将其设置为你期望的版本号,构建完成后,项目的根目录中除了 `dist` 目录外,还会生成三个压缩包,文件名的格式统一为 `ndm-web-platform_v<version>_<datetime>`,文件格式则分别为 `zip`、`tar`、`tar.gz`。
|
在执行 `pnpm build` 之前,你可以在 `package.json` 中修改 `version` 字段,将其设置为你期望的版本号,构建完成后,项目的根目录中除了 `dist` 目录外,还会生成三个压缩包,文件名的格式统一为 `ndm-web-platform_v<version>_<datetime>`,文件格式则分别为 `zip`、`tar`、`tar.gz`。
|
||||||
|
|
||||||
## 业务结构
|
|
||||||
|
|
||||||
所有业务相关的页面都在 `src/pages` 目录下,路由配置在 `src/router/index.ts` 文件,除登录页之外,其余页面都作为 `src/layouts/app-layout.vue` 的子路由。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
src/
|
|
||||||
router/
|
|
||||||
index.ts # 路由配置文件
|
|
||||||
layouts/
|
|
||||||
app-layout.vue # 布局
|
|
||||||
pages/
|
|
||||||
login/
|
|
||||||
login-page.vue # 登录页面
|
|
||||||
station/
|
|
||||||
station-page.vue # 车站状态页面(首页)
|
|
||||||
device/
|
|
||||||
device-page.vue # 设备诊断页面
|
|
||||||
alarm/
|
|
||||||
alarm-ignore-page.vue # 告警忽略管理页面
|
|
||||||
alarm-log-page.vue # 设备告警记录页面
|
|
||||||
log/
|
|
||||||
call-log-page.vue # 上级调用日志页面
|
|
||||||
vimp-log-page.vue # 视频平台日志页面
|
|
||||||
permission/
|
|
||||||
permission-page.vue # 权限管理页面
|
|
||||||
error/
|
|
||||||
not-found-page.vue # 404 页面
|
|
||||||
```
|
|
||||||
|
|
||||||
## 数据轮询
|
|
||||||
|
|
||||||
由于后端服务的架构限制,需要前端向所有车站服务依次发送请求来获取数据,需要获取的数据包含车站状态、设备数据以及告警数据,因此需要设计一套数据轮询方案,定期从所有车站服务获取数据。
|
|
||||||
|
|
||||||
在项目中,`src/composables/query/` 目录下是所有数据轮询相关的代码,其中与业务相关的代码主要包括:
|
|
||||||
|
|
||||||
- `use-line-stations-query.ts`: 查询所有车站
|
|
||||||
- `use-line-devices-query.ts`: 查询所有设备
|
|
||||||
- `use-line-alarms-query.ts`: 查询所有告警
|
|
||||||
- `use-user-permission-query.ts`: 查询用户权限
|
|
||||||
|
|
||||||
在描述整个数据轮询流程之前,我们要明确项目中必须存在的几个关键概念:
|
|
||||||
|
|
||||||
- 车站相关:车站query + 车站store
|
|
||||||
- 设备相关:设备query + 设备store
|
|
||||||
- 告警相关:告警query + 告警store
|
|
||||||
- 权限相关:权限query + 权限store
|
|
||||||
|
|
||||||
整个数据轮询流程采用“单点驱动 + 变更监听 + 级联触发”的模式,如下图所示。
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
1. 轮询入口:车站query
|
|
||||||
- 触发条件:以120秒的周期自动轮询车站列表
|
|
||||||
- 数据流向:车站store
|
|
||||||
2. 核心调度:权限query
|
|
||||||
- 触发条件:车站query执行后触发
|
|
||||||
- 数据流向:权限store,并计算当前用户在各车站的权限
|
|
||||||
- 数据监听:监听车站和权限变化,触发设备query和告警query
|
|
||||||
3. 设备query & 告警query
|
|
||||||
- 触发条件:被动触发,由权限query主动调用
|
|
||||||
- 数据流向:设备store & 告警store
|
|
||||||
|
|
||||||
## 调试模式
|
## 调试模式
|
||||||
|
|
||||||
在设置面板中有一系列与调试模式有关的设置项,主要用于开发和故障排查。
|
在调试模式中,用户可以查看设备的原始诊断数据,也可以对轮询器进行控制,或者启用离线开发模式,系统不会自动调用一些主动触发的请求。
|
||||||
|
|
||||||
### 开启方式
|
### 开启调试模式
|
||||||
|
|
||||||
调试模式默认隐藏,通过以下方式开启:
|
在非登录页的任意页面中,使用键盘组合键 `Ctrl+Alt+D`,系统会弹出一个输入框,输入环境变量 `.env` 中的 `VITE_DEBUG_CODE` 对应的值即可开启调试模式,如需关闭调试模式,再次使用上述组合键并点击 `确认` 按钮即可。
|
||||||
|
|
||||||
1. 使用快捷键 `Ctrl + Alt + D` 唤起验证弹窗
|
注意调试模式与其内部的功能之间没有联动关系,例如在开启调试模式后可以关闭轮询或者启用离线开发模式,但是在关闭调试模式后,轮询不会重新被开启,离线开发模式也不会被关闭,因此在关闭离线开发模式前,请务必确保系统处于正确的运行状态下。
|
||||||
2. 输入授权码进行验证(授权码对应环境变量 `.env` 中的 `VITE_DEBUG_CODE`)
|
|
||||||
3. 验证通过后,在“系统设置”面板中会出现 **调试** 分组
|
|
||||||
|
|
||||||
### 设置项说明
|
### 关于离线开发模式
|
||||||
|
|
||||||
#### 数据设置
|
由于离线开发模式涉及到登录操作,因此项目中将离线开发模式暴露到了全局变量 `window.$offlineDev` 中,允许在登录页中直接开启离线开发模式。
|
||||||
|
|
||||||
- **显示设备原始数据**
|
如果你第一次启动这个项目,系统在正常情况下会先跳转至登录页,此时如果希望开启离线模式,可以直接打开浏览器的开发者工具,在控制台输入 `window.$offlineDev.value = true` 即可,系统会直接跳转到首页。
|
||||||
- 控制是否在设备详情页显示“原始数据”标签页
|
|
||||||
- 开启后可查看设备接口返回的原始 JSON 数据,便于排查字段缺失或格式错误
|
|
||||||
|
|
||||||
#### 网络设置
|
|
||||||
|
|
||||||
- **轮询车站**
|
|
||||||
- 控制是否定时拉取车站状态,进而触发权限、设备及告警数据的更新
|
|
||||||
- 关闭后将暂停所有业务数据的自动轮询机制
|
|
||||||
- **主动请求**
|
|
||||||
- 控制组件挂载时是否自动发起数据请求
|
|
||||||
- 涵盖设备在线状态检测、用户登录验证等逻辑,关闭后组件在初始化时将不再自动拉取数据
|
|
||||||
- **订阅消息**
|
|
||||||
- 控制是否通过 WebSocket (STOMP) 接收实时告警或状态推送
|
|
||||||
- 关闭后将不再处理后端推送的实时消息
|
|
||||||
- **模拟用户**
|
|
||||||
- 开启后使用内置的超管用户绕过登录
|
|
||||||
- 开启时会自动进入调试模式,便于开发环境快速测试
|
|
||||||
|
|
||||||
#### 数据库设置
|
|
||||||
|
|
||||||
- **直接操作本地数据库**
|
|
||||||
- 控制某些业务逻辑(如交换机端口、安防箱回路)是否直接读写本地 IndexedDB
|
|
||||||
- 用于在无后端环境或特定测试场景下验证本地数据逻辑
|
|
||||||
|
|
||||||
## 离线开发
|
|
||||||
|
|
||||||
项目支持在无后端服务的情况下正常启动,具体操作取决于你的本地环境是否已有历史数据。
|
|
||||||
|
|
||||||
### 场景一:已有本地缓存
|
|
||||||
|
|
||||||
如果你的浏览器曾接入过现场环境,IndexedDB 中已保存了车站、设备等数据,只需在设置中关闭网络请求即可进入离线模式:
|
|
||||||
|
|
||||||
1. 开启调试模式(`Ctrl + Alt + D`)。
|
|
||||||
2. 在“网络设置”中,关闭 **轮询车站**、**主动请求** 和 **订阅消息**。
|
|
||||||
3. 此时平台将停止向后端发起请求,直接展示本地缓存的历史数据。
|
|
||||||
|
|
||||||
### 场景二:全新环境启动(新人推荐)
|
|
||||||
|
|
||||||
如果你是首次拉取项目且无法连接后端,需要按以下步骤操作:
|
|
||||||
|
|
||||||
1. **模拟登录**
|
|
||||||
在登录页按 `F12` 打开控制台,输入以下命令强制进入平台:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
window.$mockUser.value = true;
|
|
||||||
```
|
|
||||||
|
|
||||||
执行后平台将自动完成以下操作:
|
|
||||||
- 注入测试 Token 和管理员身份信息
|
|
||||||
- 关闭所有网络请求(轮询、主动请求、消息订阅)
|
|
||||||
- 开启调试模式
|
|
||||||
- 自动跳转至平台首页
|
|
||||||
|
|
||||||
2. **导入模拟数据**
|
|
||||||
进入平台后,页面默认为空。需导入预设数据以填充内容:
|
|
||||||
- 打开“系统设置”(已自动开启调试模式)。
|
|
||||||
- 在 **调试** -> **数据库设置** 中,勾选 **直接操作本地数据库**。
|
|
||||||
- 点击该选项下方的 **导入数据** 按钮。
|
|
||||||
- 依次导入项目根目录 `docs/data/` 下的三个文件:
|
|
||||||
- `ndm-station-store.json`(车站数据)
|
|
||||||
- `ndm-device-store.json`(设备数据)
|
|
||||||
- `ndm-alarm-store.json`(告警数据)
|
|
||||||
> **注意**:每次导入一个文件后,平台会自动刷新页面以应用数据。请等待刷新完成后,重新打开设置面板导入下一个文件。
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 MiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,203 +0,0 @@
|
|||||||
{
|
|
||||||
"stations": [
|
|
||||||
{
|
|
||||||
"code": "1075",
|
|
||||||
"name": "吴中路控制中心",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.128.10",
|
|
||||||
"occ": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1001",
|
|
||||||
"name": "虹桥火车站",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.129.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1002",
|
|
||||||
"name": "虹桥2号航站楼",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.131.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1003",
|
|
||||||
"name": "虹桥一号航站楼",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.133.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1004",
|
|
||||||
"name": "上海动物园",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.135.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1005",
|
|
||||||
"name": "龙溪路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.137.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1006",
|
|
||||||
"name": "水城路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.139.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1007",
|
|
||||||
"name": "伊犁路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.141.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1008",
|
|
||||||
"name": "宋园路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.143.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1009",
|
|
||||||
"name": "虹桥路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.145.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1010",
|
|
||||||
"name": "交通大学",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.147.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1011",
|
|
||||||
"name": "图书馆",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.149.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1012",
|
|
||||||
"name": "陕西南路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.151.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1013",
|
|
||||||
"name": "新天地",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.153.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1014",
|
|
||||||
"name": "老西门",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.155.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1015",
|
|
||||||
"name": "豫园",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.157.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1016",
|
|
||||||
"name": "南京东路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.159.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1017",
|
|
||||||
"name": "天潼路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.161.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1018",
|
|
||||||
"name": "四川北路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.163.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1019",
|
|
||||||
"name": "海伦路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.165.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1020",
|
|
||||||
"name": "邮电新村",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.167.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1021",
|
|
||||||
"name": "四平路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.169.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1022",
|
|
||||||
"name": "同济大学",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.171.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1023",
|
|
||||||
"name": "国权路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.173.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1024",
|
|
||||||
"name": "五角场",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.175.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1025",
|
|
||||||
"name": "江湾体育场",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.177.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1026",
|
|
||||||
"name": "三门路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.179.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1027",
|
|
||||||
"name": "殷高东路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.181.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1028",
|
|
||||||
"name": "新江湾城",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.183.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1029",
|
|
||||||
"name": "航中路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.185.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1030",
|
|
||||||
"name": "紫藤路",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.187.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1031",
|
|
||||||
"name": "龙柏新村",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.189.10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "1032",
|
|
||||||
"name": "吴中路基地",
|
|
||||||
"online": true,
|
|
||||||
"ip": "10.18.244.10"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
"es-toolkit": "^1.41.0",
|
"es-toolkit": "^1.41.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lucide-vue-next": "^0.562.0",
|
|
||||||
"naive-ui": "^2.43.1",
|
"naive-ui": "^2.43.1",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"pinia-plugin-persistedstate": "^4.7.1",
|
"pinia-plugin-persistedstate": "^4.7.1",
|
||||||
@@ -41,6 +40,8 @@
|
|||||||
"@tsconfig/node22": "^22.0.2",
|
"@tsconfig/node22": "^22.0.2",
|
||||||
"@types/crypto-js": "^4.2.2",
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@types/node": "^22.18.11",
|
"@types/node": "^22.18.11",
|
||||||
|
"@vicons/antd": "^0.13.0",
|
||||||
|
"@vicons/ionicons5": "^0.13.0",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^5.1.1",
|
"@vitejs/plugin-vue-jsx": "^5.1.1",
|
||||||
"@vue/eslint-config-prettier": "^10.2.0",
|
"@vue/eslint-config-prettier": "^10.2.0",
|
||||||
@@ -57,5 +58,5 @@
|
|||||||
"vite-plugin-vue-devtools": "^8.0.3",
|
"vite-plugin-vue-devtools": "^8.0.3",
|
||||||
"vue-tsc": "^3.1.3"
|
"vue-tsc": "^3.1.3"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
|
"packageManager": "pnpm@10.20.0+sha512.cf9998222162dd85864d0a8102e7892e7ba4ceadebbf5a31f9c2fce48dfce317a9c53b9f6464d1ef9042cba2e02ae02a9f7c143a2b438cd93c91840f0192b9dd"
|
||||||
}
|
}
|
||||||
|
|||||||
28
pnpm-lock.yaml
generated
28
pnpm-lock.yaml
generated
@@ -44,9 +44,6 @@ importers:
|
|||||||
localforage:
|
localforage:
|
||||||
specifier: ^1.10.0
|
specifier: ^1.10.0
|
||||||
version: 1.10.0
|
version: 1.10.0
|
||||||
lucide-vue-next:
|
|
||||||
specifier: ^0.562.0
|
|
||||||
version: 0.562.0(vue@3.5.24(typescript@5.9.3))
|
|
||||||
naive-ui:
|
naive-ui:
|
||||||
specifier: ^2.43.1
|
specifier: ^2.43.1
|
||||||
version: 2.43.1(vue@3.5.24(typescript@5.9.3))
|
version: 2.43.1(vue@3.5.24(typescript@5.9.3))
|
||||||
@@ -78,6 +75,12 @@ importers:
|
|||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.18.11
|
specifier: ^22.18.11
|
||||||
version: 22.19.1
|
version: 22.19.1
|
||||||
|
'@vicons/antd':
|
||||||
|
specifier: ^0.13.0
|
||||||
|
version: 0.13.0
|
||||||
|
'@vicons/ionicons5':
|
||||||
|
specifier: ^0.13.0
|
||||||
|
version: 0.13.0
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.0.1(vite@7.2.2(@types/node@22.19.1)(jiti@2.6.1)(sass@1.94.0)(tsx@4.20.6))(vue@3.5.24(typescript@5.9.3))
|
version: 6.0.1(vite@7.2.2(@types/node@22.19.1)(jiti@2.6.1)(sass@1.94.0)(tsx@4.20.6))(vue@3.5.24(typescript@5.9.3))
|
||||||
@@ -842,6 +845,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
|
resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
|
'@vicons/antd@0.13.0':
|
||||||
|
resolution: {integrity: sha512-yrUGoUSz2BbGupk9ghQOahc04n5H3MwUDM9pVPsLh9U1uqB47oRWZvYRiZaT1JKPqgTgSE6BXcVw4i9MOF4M+g==}
|
||||||
|
|
||||||
|
'@vicons/ionicons5@0.13.0':
|
||||||
|
resolution: {integrity: sha512-zvZKBPjEXKN7AXNo2Na2uy+nvuv6SP4KAMQxpKL2vfHMj0fSvuw7JZcOPCjQC3e7ayssKnaoFVAhbYcW6v41qQ==}
|
||||||
|
|
||||||
'@vitejs/plugin-vue-jsx@5.1.1':
|
'@vitejs/plugin-vue-jsx@5.1.1':
|
||||||
resolution: {integrity: sha512-uQkfxzlF8SGHJJVH966lFTdjM/lGcwJGzwAHpVqAPDD/QcsqoUGa+q31ox1BrUfi+FLP2ChVp7uLXE3DkHyDdQ==}
|
resolution: {integrity: sha512-uQkfxzlF8SGHJJVH966lFTdjM/lGcwJGzwAHpVqAPDD/QcsqoUGa+q31ox1BrUfi+FLP2ChVp7uLXE3DkHyDdQ==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
@@ -1627,11 +1636,6 @@ packages:
|
|||||||
lru-cache@5.1.1:
|
lru-cache@5.1.1:
|
||||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||||
|
|
||||||
lucide-vue-next@0.562.0:
|
|
||||||
resolution: {integrity: sha512-LN0BLGKMFulv0lnfK29r14DcngRUhIqdcaL0zXTt2o0oS9odlrjCGaU3/X9hIihOjjN8l8e+Y9G/famcNYaI7Q==}
|
|
||||||
peerDependencies:
|
|
||||||
vue: '>=3.0.1'
|
|
||||||
|
|
||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
@@ -2867,6 +2871,10 @@ snapshots:
|
|||||||
'@typescript-eslint/types': 8.46.4
|
'@typescript-eslint/types': 8.46.4
|
||||||
eslint-visitor-keys: 4.2.1
|
eslint-visitor-keys: 4.2.1
|
||||||
|
|
||||||
|
'@vicons/antd@0.13.0': {}
|
||||||
|
|
||||||
|
'@vicons/ionicons5@0.13.0': {}
|
||||||
|
|
||||||
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.2.2(@types/node@22.19.1)(jiti@2.6.1)(sass@1.94.0)(tsx@4.20.6))(vue@3.5.24(typescript@5.9.3))':
|
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.2.2(@types/node@22.19.1)(jiti@2.6.1)(sass@1.94.0)(tsx@4.20.6))(vue@3.5.24(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.28.5
|
'@babel/core': 7.28.5
|
||||||
@@ -3693,10 +3701,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist: 3.1.1
|
yallist: 3.1.1
|
||||||
|
|
||||||
lucide-vue-next@0.562.0(vue@3.5.24(typescript@5.9.3)):
|
|
||||||
dependencies:
|
|
||||||
vue: 3.5.24(typescript@5.9.3)
|
|
||||||
|
|
||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import { dateZhCN, NConfigProvider, NDialogProvider, NLoadingBarProvider, NMessa
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { themeMode, mockUser } = storeToRefs(settingStore);
|
const { themeMode, offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
// 允许通过控制台启用离线开发模式 (登录页适用)
|
// 允许通过控制台启用离线开发模式 (登录页适用)
|
||||||
window.$mockUser = mockUser;
|
window.$offlineDev = offlineDev;
|
||||||
|
|
||||||
useVersionCheckQuery();
|
useVersionCheckQuery();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useUserStore } from '@/stores';
|
import { useUserStore } from '@/stores';
|
||||||
import { createHttpClient, getAppEnvConfig } from '@/utils';
|
import { getAppEnvConfig, RequestClient } from '@/utils';
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
export const ndmClient = createHttpClient({
|
export const ndmClient = new RequestClient({
|
||||||
requestInterceptor: async (config) => {
|
requestInterceptor: async (config) => {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
|
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
|
||||||
@@ -25,7 +25,7 @@ export const ndmClient = createHttpClient({
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
await userStore.lampLogin(stationCode);
|
await userStore.lampLogin(stationCode);
|
||||||
error.config.headers.token = userStore.lampLoginResultRecord?.[stationCode]?.token ?? '';
|
error.config.headers.token = userStore.lampLoginResultRecord?.[stationCode]?.token ?? '';
|
||||||
return ndmClient.clientInstance(error.config);
|
return ndmClient.requestInstance(error.config);
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import { useUserStore } from '@/stores';
|
import { useUserStore } from '@/stores';
|
||||||
import { createHttpClient, getAppEnvConfig } from '@/utils';
|
import { getAppEnvConfig, RequestClient } from '@/utils';
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
|
||||||
export const userClient = createHttpClient({
|
export const userClient = new RequestClient({
|
||||||
requestInterceptor: (config) => {
|
requestInterceptor: (config) => {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
|
const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ export interface NdmSwitchPortInfo {
|
|||||||
|
|
||||||
lastChangeTime: string;
|
lastChangeTime: string;
|
||||||
|
|
||||||
opticalTemperature?: number;
|
opticalTemperature: number;
|
||||||
opticalVoltage?: number;
|
opticalVoltage: number;
|
||||||
opticalBiasCurrent?: number;
|
opticalBiasCurrent: number;
|
||||||
opticalReceivePower?: number;
|
opticalReceivePower: number;
|
||||||
opticalTransmitPower?: number;
|
opticalTransmitPower: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,4 @@ export interface Station {
|
|||||||
name: string;
|
name: string;
|
||||||
online: boolean;
|
online: boolean;
|
||||||
ip: string;
|
ip: string;
|
||||||
occ?: boolean; // 是否为控制中心
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '@/apis';
|
|
||||||
import type { Nullable, Optional } from '@/types';
|
|
||||||
|
|
||||||
export interface BaseEmployee extends BaseModel {
|
|
||||||
userId: string;
|
|
||||||
realName: string;
|
|
||||||
defUser: Nullable<
|
|
||||||
{
|
|
||||||
username: string;
|
|
||||||
nickName: string;
|
|
||||||
} & BaseModel
|
|
||||||
>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type BaseEmployeeResultVO = Nullable<BaseEmployee>;
|
|
||||||
|
|
||||||
export type BaseEmployeeSaveVO = Partial<Omit<BaseEmployee, ReduceForSaveVO>>;
|
|
||||||
|
|
||||||
export type BaseEmployeeUpdateVO = Optional<Omit<BaseEmployee, ReduceForUpdateVO>>;
|
|
||||||
|
|
||||||
export type BaseEmployeePageQuery = Partial<Omit<BaseEmployee, ReduceForPageQuery>>;
|
|
||||||
@@ -1 +1,3 @@
|
|||||||
export * from './base-employee';
|
export * from './model';
|
||||||
|
export * from './page';
|
||||||
|
export * from './reduce';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Nullable, Optional } from '@/types';
|
import type { Nullable, Optional } from '@/types';
|
||||||
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../schema';
|
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base';
|
||||||
import type { NdmAlarmHost } from './alarm';
|
import type { NdmAlarmHost } from './alarm';
|
||||||
import type { NdmSecurityBox, NdmSwitch } from './other';
|
import type { NdmSecurityBox, NdmSwitch } from './other';
|
||||||
import type { NdmNvr } from './storage';
|
import type { NdmNvr } from './storage';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export * from './ndm-call-log';
|
export * from './ndm-call-log';
|
||||||
export * from './ndm-device-alarm-log';
|
export * from './ndm-device-alarm-log';
|
||||||
export * from './ndm-device-alarm-snap-log';
|
|
||||||
export * from './ndm-icmp-log';
|
export * from './ndm-icmp-log';
|
||||||
export * from './ndm-record-check';
|
export * from './ndm-record-check';
|
||||||
export * from './ndm-snmp-log';
|
export * from './ndm-snmp-log';
|
||||||
|
|||||||
@@ -2,38 +2,11 @@ import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO
|
|||||||
import type { Nullable } from '@/types';
|
import type { Nullable } from '@/types';
|
||||||
|
|
||||||
export interface NdmCallLog extends BaseModel {
|
export interface NdmCallLog extends BaseModel {
|
||||||
/**
|
|
||||||
* 调用者国标码
|
|
||||||
*/
|
|
||||||
sourceGbId: string;
|
sourceGbId: string;
|
||||||
/**
|
|
||||||
* 用户所属类别
|
|
||||||
*/
|
|
||||||
sourceType: string;
|
|
||||||
/**
|
|
||||||
* 被调用设备国标码
|
|
||||||
*/
|
|
||||||
targetGbId: string;
|
targetGbId: string;
|
||||||
/**
|
|
||||||
* 被调用设备名称
|
|
||||||
*/
|
|
||||||
targetName: string;
|
|
||||||
/**
|
|
||||||
* 调用方法
|
|
||||||
*/
|
|
||||||
method: string;
|
method: string;
|
||||||
/**
|
|
||||||
* message类型
|
|
||||||
*/
|
|
||||||
messageType: string;
|
messageType: string;
|
||||||
/**
|
|
||||||
* 操作类型
|
|
||||||
*/
|
|
||||||
cmdType: string;
|
cmdType: string;
|
||||||
/**
|
|
||||||
* 日志类型
|
|
||||||
*/
|
|
||||||
logType: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NdmCallLogResultVO = Nullable<NdmCallLog>;
|
export type NdmCallLogResultVO = Nullable<NdmCallLog>;
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '@/apis';
|
|
||||||
import type { Nullable } from '@/types';
|
|
||||||
|
|
||||||
export interface NdmDeviceAlarmSnapLog extends BaseModel {
|
|
||||||
absoluteFilePath: string;
|
|
||||||
path: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NdmDeviceAlarmSnapLogResultVO = Nullable<NdmDeviceAlarmSnapLog>;
|
|
||||||
|
|
||||||
export type NdmDeviceAlarmSnapLogSaveVO = Partial<Omit<NdmDeviceAlarmSnapLog, ReduceForSaveVO>>;
|
|
||||||
|
|
||||||
export type NdmDeviceAlarmSnapLogUpdateVO = Partial<Omit<NdmDeviceAlarmSnapLog, ReduceForUpdateVO>>;
|
|
||||||
|
|
||||||
export type NdmDeviceAlarmSnapLogPageQuery = Partial<Omit<NdmDeviceAlarmSnapLog, ReduceForPageQuery>>;
|
|
||||||
@@ -2,57 +2,18 @@ import type { BaseModel, ReduceForSaveVO, ReduceForUpdateVO, ReduceForPageQuery
|
|||||||
import type { Nullable } from '@/types';
|
import type { Nullable } from '@/types';
|
||||||
|
|
||||||
export interface NdmVimpLog extends BaseModel {
|
export interface NdmVimpLog extends BaseModel {
|
||||||
/**
|
|
||||||
* 请求IP
|
|
||||||
*/
|
|
||||||
requestIp: string;
|
requestIp: string;
|
||||||
/**
|
|
||||||
* 操作内容
|
|
||||||
*/
|
|
||||||
description: string;
|
description: string;
|
||||||
/**
|
|
||||||
* 类路径
|
|
||||||
*/
|
|
||||||
classPath: string;
|
classPath: string;
|
||||||
/**
|
|
||||||
* 函数名
|
|
||||||
*/
|
|
||||||
methodName: string;
|
methodName: string;
|
||||||
/**
|
|
||||||
* 起始时间
|
|
||||||
*/
|
|
||||||
startTime: string;
|
startTime: string;
|
||||||
/**
|
|
||||||
* 结束时间
|
|
||||||
*/
|
|
||||||
endTime: string;
|
endTime: string;
|
||||||
/**
|
|
||||||
* 消耗时间
|
|
||||||
*/
|
|
||||||
consumedTime: string;
|
consumedTime: string;
|
||||||
/**
|
|
||||||
* 操作参数
|
|
||||||
*/
|
|
||||||
params: string;
|
params: string;
|
||||||
/**
|
|
||||||
* 操作结果
|
|
||||||
*/
|
|
||||||
result: string;
|
result: string;
|
||||||
/**
|
|
||||||
* 请求类型
|
|
||||||
*/
|
|
||||||
httpMethod: string;
|
httpMethod: string;
|
||||||
/**
|
|
||||||
* 请求用户
|
|
||||||
*/
|
|
||||||
userId: string;
|
userId: string;
|
||||||
/**
|
|
||||||
* 日志类型
|
|
||||||
*/
|
|
||||||
logType: number;
|
logType: number;
|
||||||
/**
|
|
||||||
* 目标国标码
|
|
||||||
*/
|
|
||||||
targetCode: string;
|
targetCode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
export * from './ndm-permission';
|
|
||||||
export * from './ndm-security-box';
|
export * from './ndm-security-box';
|
||||||
export * from './ndm-switch';
|
export * from './ndm-switch';
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO, Station } from '@/apis';
|
|
||||||
import type { PermissionType } from '@/enums';
|
|
||||||
import type { Nullable, Optional } from '@/types';
|
|
||||||
|
|
||||||
export interface NdmPermission extends BaseModel {
|
|
||||||
/**
|
|
||||||
* 员工ID
|
|
||||||
*/
|
|
||||||
employeeId: string;
|
|
||||||
/**
|
|
||||||
* 服务器IP地址
|
|
||||||
*/
|
|
||||||
ipAddress: string;
|
|
||||||
/**
|
|
||||||
* 站号
|
|
||||||
*/
|
|
||||||
stationCode: Station['code'];
|
|
||||||
/**
|
|
||||||
* 站名
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
|
||||||
* 权限类型
|
|
||||||
*/
|
|
||||||
type: PermissionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NdmPermissionResultVO = Nullable<NdmPermission>;
|
|
||||||
|
|
||||||
export type NdmPermissionSaveVO = Partial<Omit<NdmPermission, ReduceForSaveVO>>;
|
|
||||||
|
|
||||||
export type NdmPermissionUpdateVO = Optional<Omit<NdmPermission, ReduceForUpdateVO>>;
|
|
||||||
|
|
||||||
export type NdmPermissionPageQuery = Partial<Omit<NdmPermission, ReduceForPageQuery>>;
|
|
||||||
@@ -1,3 +1 @@
|
|||||||
export * from './invite-stream-type';
|
|
||||||
export * from './send-rtp-info';
|
|
||||||
export * from './snap-result';
|
export * from './snap-result';
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export type InviteStreamType = 'PLAY' | 'PLAYBACK' | 'DOWNLOAD' | 'PUSH' | 'PROXY' | 'CLOUD_RECORD_PUSH' | 'CLOUD_RECORD_PROXY';
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import type { InviteStreamType } from '@/apis';
|
|
||||||
import type { Nullable } from '@/types';
|
|
||||||
|
|
||||||
export type SendRtpInfo = Nullable<{
|
|
||||||
ip: string;
|
|
||||||
port: number;
|
|
||||||
ssrc: string;
|
|
||||||
platformId: string;
|
|
||||||
deviceId: string;
|
|
||||||
channelId: string;
|
|
||||||
app: string;
|
|
||||||
streamId: string;
|
|
||||||
/**
|
|
||||||
* 推流状态
|
|
||||||
* 0 等待设备推流上来
|
|
||||||
* 1 等待上级平台回复ack
|
|
||||||
* 2 推流中
|
|
||||||
*/
|
|
||||||
status: number;
|
|
||||||
/**
|
|
||||||
* 是否为tcp
|
|
||||||
*/
|
|
||||||
tcp: boolean;
|
|
||||||
/**
|
|
||||||
* 是否为tcp主动模式
|
|
||||||
*/
|
|
||||||
tcpActive: boolean;
|
|
||||||
localPort: number;
|
|
||||||
mediaServerId: string;
|
|
||||||
serverId: string;
|
|
||||||
callId: string;
|
|
||||||
fromTag: string;
|
|
||||||
toTag: string;
|
|
||||||
/**
|
|
||||||
* 发送时,rtp的pt(uint8_t),不传时默认为96
|
|
||||||
*/
|
|
||||||
pt: number;
|
|
||||||
/**
|
|
||||||
* 发送时,rtp的负载类型。为true时,负载为ps;为false时,为es;
|
|
||||||
*/
|
|
||||||
usePs: boolean;
|
|
||||||
/**
|
|
||||||
* 当usePs 为false时,有效。为1时,发送音频;为0时,发送视频;不传时默认为0
|
|
||||||
*/
|
|
||||||
onlyAudio: boolean;
|
|
||||||
/**
|
|
||||||
* 是否开启rtcp保活
|
|
||||||
*/
|
|
||||||
rtcp: boolean;
|
|
||||||
playType: InviteStreamType;
|
|
||||||
}>;
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
export * from './base';
|
export * from './base';
|
||||||
export * from './biz';
|
export * from './biz';
|
||||||
export * from './common';
|
export * from './common';
|
||||||
export * from './schema';
|
|
||||||
export * from './system';
|
export * from './system';
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export * from './model';
|
|
||||||
export * from './page';
|
|
||||||
export * from './reduce';
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import type { BaseEmployeePageQuery, BaseEmployeeResultVO, PageParams, PageResult } from '@/apis';
|
|
||||||
import { userClient } from '@/apis/client';
|
|
||||||
import { unwrapResponse } from '@/utils';
|
|
||||||
|
|
||||||
export const pageBaseEmployeeApi = async (pageQuery: PageParams<BaseEmployeePageQuery>, options?: { signal?: AbortSignal }) => {
|
|
||||||
const { signal } = options ?? {};
|
|
||||||
const client = userClient;
|
|
||||||
const endpoint = '/api/base/baseEmployee/page';
|
|
||||||
const resp = await client.post<PageResult<BaseEmployeeResultVO>>(endpoint, pageQuery, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const detailBaseEmployeeApi = async (id: string, options?: { signal?: AbortSignal }) => {
|
|
||||||
const { signal } = options ?? {};
|
|
||||||
const client = userClient;
|
|
||||||
const endpoint = `/api/base/baseEmployee/detail`;
|
|
||||||
const resp = await client.get<BaseEmployeeResultVO>(endpoint, { params: { id }, signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './base-employee';
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { initStationDevices, ndmClient, userClient, type Station, type StationDevices } from '@/apis';
|
import { initStationDevices, ndmClient, userClient, type StationDevices } from '@/apis';
|
||||||
import { unwrapResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const getAllDevicesApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const getAllDevicesApi = async (options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ndmClient, userClient, type Station } from '@/apis';
|
import { ndmClient, userClient, type Station } from '@/apis';
|
||||||
import { unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const resetMonitorScheduleApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const resetMonitorScheduleApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
@@ -7,5 +7,5 @@ export const resetMonitorScheduleApi = async (options?: { stationCode?: Station[
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmConstant/anyTenant/resetMonitorSchedule`;
|
const endpoint = `${prefix}/api/ndm/ndmConstant/anyTenant/resetMonitorSchedule`;
|
||||||
const resp = await client.get<void>(endpoint, { signal });
|
const resp = await client.get<void>(endpoint, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ndmClient, userClient, type Station } from '@/apis';
|
import { ndmClient, userClient, type Station } from '@/apis';
|
||||||
import { unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const verifyApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const verifyApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
@@ -7,5 +7,5 @@ export const verifyApi = async (options?: { stationCode?: Station['code']; signa
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmKeepAlive/verify`;
|
const endpoint = `${prefix}/api/ndm/ndmKeepAlive/verify`;
|
||||||
const resp = await client.post<void>(endpoint, {}, { retRaw: true, timeout: 5000, signal });
|
const resp = await client.post<void>(endpoint, {}, { retRaw: true, timeout: 5000, signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,5 +6,4 @@ export * from './icmp';
|
|||||||
export * from './log';
|
export * from './log';
|
||||||
export * from './storage';
|
export * from './storage';
|
||||||
export * from './other';
|
export * from './other';
|
||||||
export * from './upper-ndm';
|
|
||||||
export * from './video';
|
export * from './video';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export * from './ndm-call-log';
|
export * from './ndm-call-log';
|
||||||
export * from './ndm-device-alarm-log';
|
export * from './ndm-device-alarm-log';
|
||||||
export * from './ndm-device-alarm-snap-log';
|
|
||||||
export * from './ndm-icmp-log';
|
export * from './ndm-icmp-log';
|
||||||
export * from './ndm-snmp-log';
|
export * from './ndm-snmp-log';
|
||||||
export * from './ndm-record-check';
|
export * from './ndm-record-check';
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
import {
|
|
||||||
ndmClient,
|
|
||||||
userClient,
|
|
||||||
type NdmDeviceAlarmSnapLogPageQuery,
|
|
||||||
type NdmDeviceAlarmSnapLogResultVO,
|
|
||||||
type NdmDeviceAlarmSnapLogSaveVO,
|
|
||||||
type NdmDeviceAlarmSnapLogUpdateVO,
|
|
||||||
type PageParams,
|
|
||||||
type PageResult,
|
|
||||||
type Station,
|
|
||||||
} from '@/apis';
|
|
||||||
import { unwrapResponse } from '@/utils';
|
|
||||||
|
|
||||||
export const pageDeviceAlarmSnapLogApi = async (pageQuery: PageParams<NdmDeviceAlarmSnapLogPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmDeviceAlarmSnapLog/page`;
|
|
||||||
const resp = await client.post<PageResult<NdmDeviceAlarmSnapLogResultVO>>(endpoint, pageQuery, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const detailDeviceAlarmSnapLogApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmDeviceAlarmSnapLog/detail`;
|
|
||||||
const resp = await client.get<NdmDeviceAlarmSnapLogResultVO>(endpoint, { params: { id }, signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const saveDeviceAlarmSnapLogApi = async (saveVO: NdmDeviceAlarmSnapLogSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmDeviceAlarmSnapLog`;
|
|
||||||
const resp = await client.post<NdmDeviceAlarmSnapLogResultVO>(endpoint, saveVO, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateDeviceAlarmSnapLogApi = async (updateVO: NdmDeviceAlarmSnapLogUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmDeviceAlarmSnapLog`;
|
|
||||||
const resp = await client.put<NdmDeviceAlarmSnapLogResultVO>(endpoint, updateVO, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteDeviceAlarmSnapLogApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmDeviceAlarmSnapLog`;
|
|
||||||
const resp = await client.delete<boolean>(endpoint, ids, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ndmClient, userClient, type ClientChannel, type NdmNvrResultVO, type NdmRecordCheck, type Station } from '@/apis';
|
import { ndmClient, userClient, type ClientChannel, type NdmNvrResultVO, type NdmRecordCheck } from '@/apis';
|
||||||
import { unwrapResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
export const getChannelListApi = async (ndmNvr: NdmNvrResultVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const getChannelListApi = async (ndmNvr: NdmNvrResultVO, options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -12,7 +12,7 @@ export const getChannelListApi = async (ndmNvr: NdmNvrResultVO, options?: { stat
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRecordCheckApi = async (ndmNvr: NdmNvrResultVO, lastDays: number, gbCodeList: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const getRecordCheckApi = async (ndmNvr: NdmNvrResultVO, lastDays: number, gbCodeList: string[], options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -27,7 +27,7 @@ export const getRecordCheckApi = async (ndmNvr: NdmNvrResultVO, lastDays: number
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reloadRecordCheckApi = async (channel: ClientChannel, dayOffset: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const reloadRecordCheckApi = async (channel: ClientChannel, dayOffset: number, options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -37,7 +37,7 @@ export const reloadRecordCheckApi = async (channel: ClientChannel, dayOffset: nu
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const reloadAllRecordCheckApi = async (dayOffset: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const reloadAllRecordCheckApi = async (dayOffset: number, options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -48,13 +48,3 @@ export const reloadAllRecordCheckApi = async (dayOffset: number, options?: { sta
|
|||||||
if (!data) throw new Error(`${data}`);
|
if (!data) throw new Error(`${data}`);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const batchExportRecordCheckApi = async (params: { checkDuration: number; gapSeconds: number; stationCode: Station['code'][] }, options?: { signal?: AbortSignal }) => {
|
|
||||||
const { signal } = options ?? {};
|
|
||||||
const { checkDuration, gapSeconds, stationCode } = params;
|
|
||||||
const client = userClient;
|
|
||||||
const endpoint = `/api/ndm/ndmRecordCheck/batchExportByTemplate`;
|
|
||||||
const resp = await client.post<Blob>(endpoint, { checkDuration, gapSeconds, stationCode }, { responseType: 'blob', retRaw: true, signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from './ndm-permission';
|
|
||||||
export * from './ndm-security-box';
|
export * from './ndm-security-box';
|
||||||
export * from './ndm-service-available';
|
export * from './ndm-service-available';
|
||||||
export * from './ndm-switch';
|
export * from './ndm-switch';
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
import {
|
|
||||||
ndmClient,
|
|
||||||
userClient,
|
|
||||||
type NdmPermissionPageQuery,
|
|
||||||
type NdmPermissionResultVO,
|
|
||||||
type NdmPermissionSaveVO,
|
|
||||||
type NdmPermissionUpdateVO,
|
|
||||||
type PageParams,
|
|
||||||
type PageResult,
|
|
||||||
type Station,
|
|
||||||
} from '@/apis';
|
|
||||||
import type { PermissionTypeEnum } from '@/enums';
|
|
||||||
import { unwrapResponse } from '@/utils';
|
|
||||||
|
|
||||||
export const permissionTypesApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmPermission/types`;
|
|
||||||
const resp = await client.get<PermissionTypeEnum>(endpoint, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const pagePermissionApi = async (pageQuery: PageParams<NdmPermissionPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmPermission/page`;
|
|
||||||
const resp = await client.post<PageResult<NdmPermissionResultVO>>(endpoint, pageQuery, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const detailPermissionApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmPermission/detail`;
|
|
||||||
const resp = await client.get<NdmPermissionResultVO>(endpoint, { params: { id }, signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const savePermissionApi = async (saveVO: NdmPermissionSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmPermission`;
|
|
||||||
const resp = await client.post<NdmPermissionResultVO>(endpoint, saveVO, { signal });
|
|
||||||
const result = unwrapResponse(resp);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updatePermissionApi = async (updateVO: NdmPermissionUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmPermission`;
|
|
||||||
const resp = await client.put<NdmPermissionResultVO>(endpoint, updateVO, { signal });
|
|
||||||
const result = unwrapResponse(resp);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deletePermissionApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmPermission`;
|
|
||||||
const resp = await client.delete<boolean>(endpoint, ids, { signal });
|
|
||||||
const result = unwrapResponse(resp);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const modifyPermissionApi = async (params: { employeeId: string; saveList: NdmPermissionSaveVO[]; removeList: string[] }, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmPermission/modify`;
|
|
||||||
const resp = await client.post<boolean>(endpoint, params, { signal });
|
|
||||||
const result = unwrapResponse(resp);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
type PageResult,
|
type PageResult,
|
||||||
type Station,
|
type Station,
|
||||||
} from '@/apis';
|
} from '@/apis';
|
||||||
import { unwrapResponse, unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const pageSecurityBoxApi = async (pageQuery: PageParams<NdmSecurityBoxPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const pageSecurityBoxApi = async (pageQuery: PageParams<NdmSecurityBoxPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
@@ -90,7 +90,7 @@ export const probeSecurityBoxApi = async (ids: string[], options?: { stationCode
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/probeByIds`;
|
const endpoint = `${prefix}/api/ndm/ndmSecurityBox/probeByIds`;
|
||||||
const resp = await client.post<void>(endpoint, ids, { signal });
|
const resp = await client.post<void>(endpoint, ids, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const turnCitcuitStatusApi = async (ipAddress: string, circuitIndex: number, status: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const turnCitcuitStatusApi = async (ipAddress: string, circuitIndex: number, status: number, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
import { ndmClient, userClient, type MediaServerStatus, type SendRtpInfo, type Station } from '@/apis';
|
import { ndmClient, userClient, type MediaServerStatus, type Station } from '@/apis';
|
||||||
import { unwrapResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const getAllPushApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
|
||||||
const { stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmServiceAvailable/mediaServer/getAllPush`;
|
|
||||||
const resp = await client.get<SendRtpInfo[]>(endpoint, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isMediaServerAliveApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const isMediaServerAliveApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import {
|
|||||||
type PageResult,
|
type PageResult,
|
||||||
type Station,
|
type Station,
|
||||||
} from '@/apis';
|
} from '@/apis';
|
||||||
import { unwrapResponse, unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const pageSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const pageSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : ndmClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSwitch/page`;
|
const endpoint = `${prefix}/api/ndm/ndmSwitch/page`;
|
||||||
const resp = await client.post<PageResult<NdmSwitchResultVO>>(endpoint, pageQuery, { signal });
|
const resp = await client.post<PageResult<NdmSwitchResultVO>>(endpoint, pageQuery, { signal });
|
||||||
@@ -24,7 +24,7 @@ export const pageSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, o
|
|||||||
|
|
||||||
export const detailSwitchApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const detailSwitchApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : ndmClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSwitch/detail`;
|
const endpoint = `${prefix}/api/ndm/ndmSwitch/detail`;
|
||||||
const resp = await client.get<NdmSwitchResultVO>(endpoint, { params: { id }, signal });
|
const resp = await client.get<NdmSwitchResultVO>(endpoint, { params: { id }, signal });
|
||||||
@@ -34,7 +34,7 @@ export const detailSwitchApi = async (id: string, options?: { stationCode?: Stat
|
|||||||
|
|
||||||
export const saveSwitchApi = async (saveVO: NdmSwitchSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const saveSwitchApi = async (saveVO: NdmSwitchSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : ndmClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSwitch`;
|
const endpoint = `${prefix}/api/ndm/ndmSwitch`;
|
||||||
const resp = await client.post<NdmSwitchResultVO>(endpoint, saveVO, { signal });
|
const resp = await client.post<NdmSwitchResultVO>(endpoint, saveVO, { signal });
|
||||||
@@ -44,7 +44,7 @@ export const saveSwitchApi = async (saveVO: NdmSwitchSaveVO, options?: { station
|
|||||||
|
|
||||||
export const updateSwitchApi = async (updateVO: NdmSwitchUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const updateSwitchApi = async (updateVO: NdmSwitchUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : ndmClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSwitch`;
|
const endpoint = `${prefix}/api/ndm/ndmSwitch`;
|
||||||
const resp = await client.put<NdmSwitchResultVO>(endpoint, updateVO, { signal });
|
const resp = await client.put<NdmSwitchResultVO>(endpoint, updateVO, { signal });
|
||||||
@@ -54,7 +54,7 @@ export const updateSwitchApi = async (updateVO: NdmSwitchUpdateVO, options?: { s
|
|||||||
|
|
||||||
export const deleteSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const deleteSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : ndmClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSwitch`;
|
const endpoint = `${prefix}/api/ndm/ndmSwitch`;
|
||||||
const resp = await client.delete<boolean>(endpoint, ids, { signal });
|
const resp = await client.delete<boolean>(endpoint, ids, { signal });
|
||||||
@@ -64,7 +64,7 @@ export const deleteSwitchApi = async (ids: string[], options?: { stationCode?: S
|
|||||||
|
|
||||||
export const exportSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const exportSwitchApi = async (pageQuery: PageParams<NdmSwitchPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : ndmClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSwitch/defaultExportByTemplate`;
|
const endpoint = `${prefix}/api/ndm/ndmSwitch/defaultExportByTemplate`;
|
||||||
const resp = await client.post<Blob>(endpoint, pageQuery, { responseType: 'blob', retRaw: true, signal });
|
const resp = await client.post<Blob>(endpoint, pageQuery, { responseType: 'blob', retRaw: true, signal });
|
||||||
@@ -86,9 +86,9 @@ export const importSwitchApi = async (file: File, options?: { stationCode?: Stat
|
|||||||
|
|
||||||
export const probeSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const probeSwitchApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : ndmClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSwitch/probeByIds`;
|
const endpoint = `${prefix}/api/ndm/ndmSwitch/probeByIds`;
|
||||||
const resp = await client.post<void>(endpoint, ids, { signal });
|
const resp = await client.post<void>(endpoint, ids, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ndmClient, userClient, type ImportMsg, type NdmNvrPageQuery, type NdmNvrResultVO, type NdmNvrSaveVO, type NdmNvrUpdateVO, type PageParams, type PageResult, type Station } from '@/apis';
|
import { ndmClient, userClient, type ImportMsg, type NdmNvrPageQuery, type NdmNvrResultVO, type NdmNvrSaveVO, type NdmNvrUpdateVO, type PageParams, type PageResult, type Station } from '@/apis';
|
||||||
import { unwrapResponse, unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const pageNvrPageApi = async (pageQuery: PageParams<NdmNvrPageQuery>, options?: { stationCode: Station['code']; signal?: AbortSignal }) => {
|
export const pageNvrPageApi = async (pageQuery: PageParams<NdmNvrPageQuery>, options?: { stationCode: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
@@ -79,7 +79,7 @@ export const probeNvrApi = async (ids: string[], options?: { stationCode?: Stati
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmNvr/probeByIds`;
|
const endpoint = `${prefix}/api/ndm/ndmNvr/probeByIds`;
|
||||||
const resp = await client.post<void>(endpoint, ids, { signal });
|
const resp = await client.post<void>(endpoint, ids, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const syncNvrChannelsApi = async (options?: { stationCode?: string; signal?: AbortSignal }) => {
|
export const syncNvrChannelsApi = async (options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
@@ -88,5 +88,5 @@ export const syncNvrChannelsApi = async (options?: { stationCode?: string; signa
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmNvr/syncNvrChannels`;
|
const endpoint = `${prefix}/api/ndm/ndmNvr/syncNvrChannels`;
|
||||||
const resp = await client.get<void>(endpoint, { signal });
|
const resp = await client.get<void>(endpoint, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from './upper-ndm';
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { ndmClient, userClient, type Station } from '@/apis';
|
|
||||||
import { unwrapResponse } from '@/utils';
|
|
||||||
|
|
||||||
export async function snapStatusApi(method: 'get', options?: { stationCode?: Station['code']; signal?: AbortSignal }): Promise<boolean>;
|
|
||||||
export async function snapStatusApi(method: 'post', options: { doSnap: boolean; stationCode?: Station['code']; signal?: AbortSignal }): Promise<boolean>;
|
|
||||||
export async function snapStatusApi(method: 'get' | 'post', options?: { doSnap?: boolean; stationCode?: Station['code']; signal?: AbortSignal }) {
|
|
||||||
const { doSnap, stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/anyTenant/snapStatus`;
|
|
||||||
if (method === 'get') {
|
|
||||||
const resp = await client.get<boolean>(endpoint, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
} else {
|
|
||||||
const resp = await client.post<boolean>(endpoint, doSnap, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,5 +3,4 @@ export * from './ndm-camera-ignore';
|
|||||||
export * from './ndm-decoder';
|
export * from './ndm-decoder';
|
||||||
export * from './ndm-keyboard';
|
export * from './ndm-keyboard';
|
||||||
export * from './ndm-media-server';
|
export * from './ndm-media-server';
|
||||||
export * from './ndm-snap';
|
|
||||||
export * from './ndm-video-server';
|
export * from './ndm-video-server';
|
||||||
|
|||||||
@@ -1,17 +1,7 @@
|
|||||||
import {
|
import { ndmClient, userClient, type NdmCameraIgnorePageQuery, type NdmCameraIgnoreResultVO, type NdmCameraIgnoreSaveVO, type NdmCameraIgnoreUpdateVO, type PageParams, type PageResult } from '@/apis';
|
||||||
ndmClient,
|
|
||||||
userClient,
|
|
||||||
type NdmCameraIgnorePageQuery,
|
|
||||||
type NdmCameraIgnoreResultVO,
|
|
||||||
type NdmCameraIgnoreSaveVO,
|
|
||||||
type NdmCameraIgnoreUpdateVO,
|
|
||||||
type PageParams,
|
|
||||||
type PageResult,
|
|
||||||
type Station,
|
|
||||||
} from '@/apis';
|
|
||||||
import { unwrapResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const pageCameraIgnoreApi = async (pageQuery: PageParams<NdmCameraIgnorePageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const pageCameraIgnoreApi = async (pageQuery: PageParams<NdmCameraIgnorePageQuery>, options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -21,7 +11,7 @@ export const pageCameraIgnoreApi = async (pageQuery: PageParams<NdmCameraIgnoreP
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const detailCameraIgnoreApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const detailCameraIgnoreApi = async (id: string, options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -31,7 +21,7 @@ export const detailCameraIgnoreApi = async (id: string, options?: { stationCode?
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveCameraIgnoreApi = async (saveVO: NdmCameraIgnoreSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const saveCameraIgnoreApi = async (saveVO: NdmCameraIgnoreSaveVO, options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -41,7 +31,7 @@ export const saveCameraIgnoreApi = async (saveVO: NdmCameraIgnoreSaveVO, options
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateCameraIgnoreApi = async (updateVO: NdmCameraIgnoreUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const updateCameraIgnoreApi = async (updateVO: NdmCameraIgnoreUpdateVO, options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
@@ -51,7 +41,7 @@ export const updateCameraIgnoreApi = async (updateVO: NdmCameraIgnoreUpdateVO, o
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteCameraIgnoreApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const deleteCameraIgnoreApi = async (ids: string[], options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export const getCameraSnapApi = async (deviceId: string, options?: { signal?: Ab
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const syncCameraApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const syncCameraApi = async (options?: { stationCode?: string; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
const client = stationCode ? ndmClient : userClient;
|
const client = stationCode ? ndmClient : userClient;
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
type PageResult,
|
type PageResult,
|
||||||
type Station,
|
type Station,
|
||||||
} from '@/apis';
|
} from '@/apis';
|
||||||
import { unwrapResponse, unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const pageDecoderApi = async (pageQuery: PageParams<NdmDecoderPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const pageDecoderApi = async (pageQuery: PageParams<NdmDecoderPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
@@ -90,5 +90,5 @@ export const probeDecoderApi = async (ids: string[], options?: { stationCode?: S
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmDecoder/probeByIds`;
|
const endpoint = `${prefix}/api/ndm/ndmDecoder/probeByIds`;
|
||||||
const resp = await client.post<void>(endpoint, ids, { signal });
|
const resp = await client.post<void>(endpoint, ids, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
type PageResult,
|
type PageResult,
|
||||||
type Station,
|
type Station,
|
||||||
} from '@/apis';
|
} from '@/apis';
|
||||||
import { unwrapResponse, unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const postNdmMediaServerPage = async (pageQuery: PageParams<NdmMediaServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const postNdmMediaServerPage = async (pageQuery: PageParams<NdmMediaServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
@@ -90,5 +90,5 @@ export const probeMediaServerApi = async (ids: string[], options?: { stationCode
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmMediaServer/probeByIds`;
|
const endpoint = `${prefix}/api/ndm/ndmMediaServer/probeByIds`;
|
||||||
const resp = await client.post<void>(endpoint, ids, { signal });
|
const resp = await client.post<void>(endpoint, ids, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { ndmClient, userClient, type Station } from '@/apis';
|
|
||||||
import { unwrapResponse } from '@/utils';
|
|
||||||
|
|
||||||
export async function retentionDaysApi(method: 'get', options?: { stationCode?: Station['code']; signal?: AbortSignal }): Promise<number>;
|
|
||||||
export async function retentionDaysApi(method: 'post', options: { days: number; stationCode?: Station['code']; signal?: AbortSignal }): Promise<number>;
|
|
||||||
export async function retentionDaysApi(method: 'get' | 'post', options?: { days?: number; stationCode?: Station['code']; signal?: AbortSignal }) {
|
|
||||||
const { days, stationCode, signal } = options ?? {};
|
|
||||||
const client = stationCode ? ndmClient : userClient;
|
|
||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
|
||||||
const endpoint = `${prefix}/api/ndm/ndmSnap/retentionDays`;
|
|
||||||
if (method === 'get') {
|
|
||||||
const resp = await client.get<number>(endpoint, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
} else {
|
|
||||||
const resp = await client.post<number>(endpoint, days, { signal });
|
|
||||||
const data = unwrapResponse(resp);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
type PageResult,
|
type PageResult,
|
||||||
type Station,
|
type Station,
|
||||||
} from '@/apis';
|
} from '@/apis';
|
||||||
import { unwrapResponse, unwrapVoidResponse } from '@/utils';
|
import { unwrapResponse } from '@/utils';
|
||||||
|
|
||||||
export const pageVideoServerApi = async (pageQuery: PageParams<NdmVideoServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
export const pageVideoServerApi = async (pageQuery: PageParams<NdmVideoServerPageQuery>, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => {
|
||||||
const { stationCode, signal } = options ?? {};
|
const { stationCode, signal } = options ?? {};
|
||||||
@@ -90,5 +90,5 @@ export const probeVideoServerApi = async (ids: string[], options?: { stationCode
|
|||||||
const prefix = stationCode ? `/${stationCode}` : '';
|
const prefix = stationCode ? `/${stationCode}` : '';
|
||||||
const endpoint = `${prefix}/api/ndm/ndmVideoServer/probeByIds`;
|
const endpoint = `${prefix}/api/ndm/ndmVideoServer/probeByIds`;
|
||||||
const resp = await client.post<void>(endpoint, ids, { signal });
|
const resp = await client.post<void>(endpoint, ids, { signal });
|
||||||
unwrapVoidResponse(resp);
|
unwrapResponse(resp);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
export * from './base';
|
|
||||||
export * from './biz';
|
export * from './biz';
|
||||||
export * from './system';
|
export * from './system';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ClockCheckIcon, CpuIcon, HardDriveIcon, MemoryStickIcon } from 'lucide-vue-next';
|
import { ClockCircleOutlined, CodeOutlined, FireOutlined, SaveOutlined } from '@vicons/antd';
|
||||||
import { NCard, NFlex, NIcon, NProgress, type ProgressStatus } from 'naive-ui';
|
import { NCard, NFlex, NIcon, NProgress, type ProgressStatus } from 'naive-ui';
|
||||||
import { computed, toRefs } from 'vue';
|
import { computed, toRefs } from 'vue';
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ const props = defineProps<{
|
|||||||
const { cpuUsage, memUsage, diskUsage, runningTime, cpuUsageLabel, memUsageLabel, diskUsageLabel, runningTimeLabel } = toRefs(props);
|
const { cpuUsage, memUsage, diskUsage, runningTime, cpuUsageLabel, memUsageLabel, diskUsageLabel, runningTimeLabel } = toRefs(props);
|
||||||
|
|
||||||
const showCard = computed(() => {
|
const showCard = computed(() => {
|
||||||
return Object.values({ cpuUsage, memUsage, diskUsage, runningTime }).some((refValue) => !!refValue.value);
|
return Object.values({ cpuUsage, memUsage, diskUsage, runningTime }).some((value) => !!value);
|
||||||
});
|
});
|
||||||
|
|
||||||
const cpuPercent = computed(() => {
|
const cpuPercent = computed(() => {
|
||||||
@@ -54,22 +54,22 @@ const getProgressStatus = (percent: number): ProgressStatus => {
|
|||||||
<template #default>
|
<template #default>
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<NFlex v-if="cpuUsage" style="width: 100%" align="center" :wrap="false">
|
<NFlex v-if="cpuUsage" style="width: 100%" align="center" :wrap="false">
|
||||||
<NIcon :component="CpuIcon" />
|
<NIcon :component="FireOutlined" />
|
||||||
<span style="word-break: keep-all">{{ cpuUsageLabel || 'CPU' }}</span>
|
<span style="word-break: keep-all">{{ cpuUsageLabel || 'CPU' }}</span>
|
||||||
<NProgress :percentage="cpuPercent" :status="getProgressStatus(cpuPercent)">{{ cpuPercent }}%</NProgress>
|
<NProgress :percentage="cpuPercent" :status="getProgressStatus(cpuPercent)">{{ cpuPercent }}%</NProgress>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
<NFlex v-if="memUsage" style="width: 100%" align="center" :wrap="false">
|
<NFlex v-if="memUsage" style="width: 100%" align="center" :wrap="false">
|
||||||
<NIcon :component="MemoryStickIcon" />
|
<NIcon :component="CodeOutlined" />
|
||||||
<span style="word-break: keep-all">{{ memUsageLabel || '内存' }}</span>
|
<span style="word-break: keep-all">{{ memUsageLabel || '内存' }}</span>
|
||||||
<NProgress :percentage="memPercent" :status="getProgressStatus(memPercent)">{{ memPercent }}%</NProgress>
|
<NProgress :percentage="memPercent" :status="getProgressStatus(memPercent)">{{ memPercent }}%</NProgress>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
<NFlex v-if="diskUsage" style="width: 100%" align="center" :wrap="false">
|
<NFlex v-if="diskUsage" style="width: 100%" align="center" :wrap="false">
|
||||||
<NIcon :component="HardDriveIcon" />
|
<NIcon :component="SaveOutlined" />
|
||||||
<span style="word-break: keep-all">{{ diskUsageLabel || '磁盘' }}</span>
|
<span style="word-break: keep-all">{{ diskUsageLabel || '磁盘' }}</span>
|
||||||
<NProgress :percentage="diskPercent" :status="getProgressStatus(diskPercent)">{{ diskPercent }}%</NProgress>
|
<NProgress :percentage="diskPercent" :status="getProgressStatus(diskPercent)">{{ diskPercent }}%</NProgress>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
<NFlex v-if="runningTime" style="width: 100%" align="center" :wrap="false">
|
<NFlex v-if="runningTime" style="width: 100%" align="center" :wrap="false">
|
||||||
<NIcon :component="ClockCheckIcon" />
|
<NIcon :component="ClockCircleOutlined" />
|
||||||
<span>{{ runningTimeLabel || '运行时间' }}</span>
|
<span>{{ runningTimeLabel || '运行时间' }}</span>
|
||||||
<span>{{ formattedRunningTime }}</span>
|
<span>{{ formattedRunningTime }}</span>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { DEVICE_TYPE_LITERALS, DEVICE_TYPE_NAMES, tryGetDeviceType } from '@/enu
|
|||||||
import { useDeviceStore } from '@/stores';
|
import { useDeviceStore } from '@/stores';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
|
import { ApiOutlined, ReloadOutlined } from '@vicons/antd';
|
||||||
import { isCancel } from 'axios';
|
import { isCancel } from 'axios';
|
||||||
import destr from 'destr';
|
import destr from 'destr';
|
||||||
import { LinkIcon, RotateCwIcon } from 'lucide-vue-next';
|
|
||||||
import { NButton, NCard, NFlex, NIcon, NTag, NTooltip } from 'naive-ui';
|
import { NButton, NCard, NFlex, NIcon, NTag, NTooltip } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed, inject, onBeforeUnmount, ref, toRefs } from 'vue';
|
import { computed, inject, onBeforeUnmount, ref, toRefs } from 'vue';
|
||||||
@@ -152,7 +152,7 @@ onBeforeUnmount(() => {
|
|||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton size="small" quaternary circle :loading="probing" @click="() => probeDevice()">
|
<NButton size="small" quaternary circle :loading="probing" @click="() => probeDevice()">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="LinkIcon" />
|
<NIcon :component="ApiOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
</template>
|
||||||
@@ -164,7 +164,7 @@ onBeforeUnmount(() => {
|
|||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton size="small" quaternary circle :loading="loading" @click="() => detailDevice()">
|
<NButton size="small" quaternary circle :loading="loading" @click="() => detailDevice()">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="RotateCwIcon" />
|
<NIcon :component="ReloadOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,58 +1,34 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getChannelListApi, getRecordCheckApi, reloadAllRecordCheckApi, reloadRecordCheckApi, type NdmNvrResultVO, type RecordItem, type Station } from '@/apis';
|
import { getChannelListApi, getRecordCheckApi, reloadAllRecordCheckApi, reloadRecordCheckApi, type NdmNvrResultVO, type NdmRecordCheck, type RecordItem, type Station } from '@/apis';
|
||||||
import { exportRecordDiagCsv, transformRecordChecks } from '@/helpers';
|
import { exportRecordDiagCsv, transformRecordChecks } from '@/helpers';
|
||||||
import { useSettingStore } from '@/stores';
|
import { useStationStore } from '@/stores';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
|
import { DownloadOutlined, ReloadOutlined } from '@vicons/antd';
|
||||||
import { isCancel } from 'axios';
|
import { isCancel } from 'axios';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { DownloadIcon, RotateCwIcon } from 'lucide-vue-next';
|
|
||||||
import { NButton, NCard, NFlex, NIcon, NPagination, NPopconfirm, NPopover, NRadioButton, NRadioGroup, NTooltip, useThemeVars } from 'naive-ui';
|
import { NButton, NCard, NFlex, NIcon, NPagination, NPopconfirm, NPopover, NRadioButton, NRadioGroup, NTooltip, useThemeVars } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed, onBeforeUnmount, ref, toRefs, watch } from 'vue';
|
import { computed, onBeforeUnmount, onMounted, ref, toRefs, watch } from 'vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
ndmDevice: NdmNvrResultVO;
|
ndmDevice: NdmNvrResultVO;
|
||||||
station: Station;
|
station: Station;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
|
||||||
const { activeRequests } = storeToRefs(settingStore);
|
|
||||||
|
|
||||||
const themeVars = useThemeVars();
|
const themeVars = useThemeVars();
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const stationStore = useStationStore();
|
||||||
|
const { stations } = storeToRefs(stationStore);
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
|
const recordChecks = ref<NdmRecordCheck[]>([]);
|
||||||
|
|
||||||
const lossInput = ref<number>(0);
|
const lossInput = ref<number>(0);
|
||||||
|
|
||||||
const abortController = ref<AbortController>(new AbortController());
|
|
||||||
|
|
||||||
const NVR_RECORD_CHECK_KEY = 'nvr_record_check_query';
|
|
||||||
|
|
||||||
const {
|
|
||||||
data: recordChecks,
|
|
||||||
isFetching: loading,
|
|
||||||
refetch: refetchRecordChecks,
|
|
||||||
} = useQuery({
|
|
||||||
queryKey: computed(() => [NVR_RECORD_CHECK_KEY, ndmDevice.value.id, ndmDevice.value.lastDiagTime]),
|
|
||||||
enabled: computed(() => activeRequests.value),
|
|
||||||
refetchInterval: 30 * 1000,
|
|
||||||
gcTime: 0,
|
|
||||||
queryFn: async ({ signal }) => {
|
|
||||||
const checks = await getRecordCheckApi(ndmDevice.value, 90, [], { stationCode: station.value.code, signal });
|
|
||||||
return checks;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
watch(activeRequests, (active) => {
|
|
||||||
if (!active) {
|
|
||||||
queryClient.cancelQueries({ queryKey: [NVR_RECORD_CHECK_KEY] });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const recordDiags = computed(() => {
|
const recordDiags = computed(() => {
|
||||||
return transformRecordChecks(recordChecks.value ?? []).filter((recordDiag) => {
|
return transformRecordChecks(recordChecks.value).filter((recordDiag) => {
|
||||||
if (lossInput.value === 0) {
|
if (lossInput.value === 0) {
|
||||||
return true;
|
return true;
|
||||||
} else if (lossInput.value === 1) {
|
} else if (lossInput.value === 1) {
|
||||||
@@ -64,6 +40,26 @@ const recordDiags = computed(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const abortController = ref<AbortController>(new AbortController());
|
||||||
|
|
||||||
|
const { mutate: getRecordCheckByParentId, isPending: loading } = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
abortController.value.abort();
|
||||||
|
abortController.value = new AbortController();
|
||||||
|
const checks = await getRecordCheckApi(ndmDevice.value, 90, [], { stationCode: station.value.code, signal: abortController.value.signal });
|
||||||
|
return checks;
|
||||||
|
},
|
||||||
|
onSuccess: (checks) => {
|
||||||
|
recordChecks.value = checks;
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
if (isCancel(error)) return;
|
||||||
|
console.error(error);
|
||||||
|
const errorFeedback = parseErrorFeedback(error);
|
||||||
|
window.$message.error(errorFeedback);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const { mutate: reloadAllRecordCheck, isPending: reloading } = useMutation({
|
const { mutate: reloadAllRecordCheck, isPending: reloading } = useMutation({
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
abortController.value.abort();
|
abortController.value.abort();
|
||||||
@@ -82,7 +78,9 @@ const { mutate: reloadAllRecordCheck, isPending: reloading } = useMutation({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onExportRecordCheck = () => {
|
const onExportRecordCheck = () => {
|
||||||
exportRecordDiagCsv(recordDiags.value, station.value.name);
|
const code = station.value.code;
|
||||||
|
const stationName = stations.value.find((station) => station.code === code)?.name ?? '';
|
||||||
|
exportRecordDiagCsv(recordDiags.value, stationName);
|
||||||
};
|
};
|
||||||
|
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
@@ -123,7 +121,7 @@ const { mutate: reloadRecordCheckByGbId } = useMutation({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
refetchRecordChecks();
|
getRecordCheckByParentId();
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (isCancel(error)) return;
|
if (isCancel(error)) return;
|
||||||
@@ -133,6 +131,19 @@ const { mutate: reloadRecordCheckByGbId } = useMutation({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getRecordCheckByParentId();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => ndmDevice.value.id,
|
||||||
|
(devieDbId) => {
|
||||||
|
if (devieDbId) {
|
||||||
|
getRecordCheckByParentId();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
abortController.value.abort();
|
abortController.value.abort();
|
||||||
});
|
});
|
||||||
@@ -157,9 +168,9 @@ onBeforeUnmount(() => {
|
|||||||
<NFlex>
|
<NFlex>
|
||||||
<NTooltip trigger="hover">
|
<NTooltip trigger="hover">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton size="small" quaternary circle :loading="loading" @click="() => refetchRecordChecks()">
|
<NButton size="small" quaternary circle :loading="loading" @click="() => getRecordCheckByParentId()">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="RotateCwIcon" />
|
<NIcon :component="ReloadOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
</template>
|
||||||
@@ -171,7 +182,7 @@ onBeforeUnmount(() => {
|
|||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton size="small" quaternary circle @click="onExportRecordCheck">
|
<NButton size="small" quaternary circle @click="onExportRecordCheck">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="DownloadIcon" />
|
<NIcon :component="DownloadOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -13,17 +13,15 @@ import {
|
|||||||
type Station,
|
type Station,
|
||||||
} from '@/apis';
|
} from '@/apis';
|
||||||
import { SecurityBoxCircuitLinkModal } from '@/components';
|
import { SecurityBoxCircuitLinkModal } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { SELECT_DEVICE_FN_INJECTION_KEY } from '@/constants';
|
import { SELECT_DEVICE_FN_INJECTION_KEY } from '@/constants';
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useDeviceStore, useSettingStore } from '@/stores';
|
import { useDeviceStore, useSettingStore } from '@/stores';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
|
import { PoweroffOutlined } from '@vicons/antd';
|
||||||
import { watchImmediate } from '@vueuse/core';
|
import { watchImmediate } from '@vueuse/core';
|
||||||
import { isCancel } from 'axios';
|
import { isCancel } from 'axios';
|
||||||
import destr from 'destr';
|
import destr from 'destr';
|
||||||
import { cloneDeep, isFunction } from 'es-toolkit';
|
import { cloneDeep, isFunction } from 'es-toolkit';
|
||||||
import { PowerIcon } from 'lucide-vue-next';
|
|
||||||
import { NButton, NCard, NDescriptions, NDescriptionsItem, NDropdown, NFlex, NIcon, NPopconfirm, NPopover, NSwitch, NTag, useThemeVars, type DropdownOption, type TagProps } from 'naive-ui';
|
import { NButton, NCard, NDescriptions, NDescriptionsItem, NDropdown, NFlex, NIcon, NPopconfirm, NPopover, NSwitch, NTag, useThemeVars, type DropdownOption, type TagProps } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed, inject, ref, toRefs } from 'vue';
|
import { computed, inject, ref, toRefs } from 'vue';
|
||||||
@@ -40,9 +38,7 @@ const deviceStore = useDeviceStore();
|
|||||||
const { lineDevices } = storeToRefs(deviceStore);
|
const { lineDevices } = storeToRefs(deviceStore);
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { useLocalDB } = storeToRefs(settingStore);
|
const { offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station, circuits } = toRefs(props);
|
const { ndmDevice, station, circuits } = toRefs(props);
|
||||||
|
|
||||||
@@ -227,7 +223,6 @@ const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
|||||||
const onContextmenu = (payload: PointerEvent, circuitIndex: number) => {
|
const onContextmenu = (payload: PointerEvent, circuitIndex: number) => {
|
||||||
payload.stopPropagation();
|
payload.stopPropagation();
|
||||||
payload.preventDefault();
|
payload.preventDefault();
|
||||||
if (!hasPermission(station.value.code, PERMISSION_TYPE_LITERALS.OPERATION)) return;
|
|
||||||
const { clientX, clientY } = payload;
|
const { clientX, clientY } = payload;
|
||||||
contextmenu.value = { x: clientX, y: clientY, circuitIndex };
|
contextmenu.value = { x: clientX, y: clientY, circuitIndex };
|
||||||
showContextmenu.value = true;
|
showContextmenu.value = true;
|
||||||
@@ -263,8 +258,8 @@ const { mutate: unlinkDevice } = useMutation({
|
|||||||
delete modifiedUpperLinkDescription.downstream?.[circuitIndex];
|
delete modifiedUpperLinkDescription.downstream?.[circuitIndex];
|
||||||
modifiedUpperDevice.linkDescription = JSON.stringify(modifiedUpperLinkDescription);
|
modifiedUpperDevice.linkDescription = JSON.stringify(modifiedUpperLinkDescription);
|
||||||
|
|
||||||
// 3. 发起update请求并获取最新的设备详情(使用本地数据库时直接修改本地数据)
|
// TODO: 3. 发起update请求并获取最新的设备详情(离线模式下直接修改本地数据)
|
||||||
if (useLocalDB.value) {
|
if (offlineDev.value) {
|
||||||
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
||||||
}
|
}
|
||||||
const stationCode = station.value.code;
|
const stationCode = station.value.code;
|
||||||
@@ -318,7 +313,7 @@ const { mutate: unlinkDevice } = useMutation({
|
|||||||
<NFlex align="center">
|
<NFlex align="center">
|
||||||
<NTag class="pointer-cursor" size="small" :type="getCircuitStatusTagType(circuit)">
|
<NTag class="pointer-cursor" size="small" :type="getCircuitStatusTagType(circuit)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="PowerIcon" />
|
<NIcon :component="PoweroffOutlined" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<span>{{ getCircuitStatusText(circuit) }}</span>
|
<span>{{ getCircuitStatusText(circuit) }}</span>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const show = defineModel<boolean>('show', { default: false });
|
|||||||
const deviceStore = useDeviceStore();
|
const deviceStore = useDeviceStore();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { useLocalDB } = storeToRefs(settingStore);
|
const { offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { ndmDevice, station, circuitIndex } = toRefs(props);
|
const { ndmDevice, station, circuitIndex } = toRefs(props);
|
||||||
|
|
||||||
@@ -68,9 +68,7 @@ const { mutate: linkPortToDevice, isPending: linking } = useMutation({
|
|||||||
const lowerDeviceDbId = lowerDevice.value?.id;
|
const lowerDeviceDbId = lowerDevice.value?.id;
|
||||||
if (!lowerDeviceDbId) throw new Error('该设备没有ID');
|
if (!lowerDeviceDbId) throw new Error('该设备没有ID');
|
||||||
|
|
||||||
// 0. 检查是否会导致循环关联,
|
// 0. 检查上游设备的linkDescription的downstream字段是否存在某个端口已经关联下游设备
|
||||||
if (upperDeviceDbId === lowerDeviceDbId) throw new Error('不能关联到自身');
|
|
||||||
// 以及检查上游设备的linkDescription的downstream字段是否存在某个端口已经关联下游设备
|
|
||||||
const duplicated = Object.entries(upperDeviceLinkDescription.value?.downstream ?? {}).find(([, deviceStoreIndex]) => {
|
const duplicated = Object.entries(upperDeviceLinkDescription.value?.downstream ?? {}).find(([, deviceStoreIndex]) => {
|
||||||
return deviceStoreIndex.deviceDbId === lowerDeviceDbId;
|
return deviceStoreIndex.deviceDbId === lowerDeviceDbId;
|
||||||
});
|
});
|
||||||
@@ -150,8 +148,8 @@ const { mutate: linkPortToDevice, isPending: linking } = useMutation({
|
|||||||
}
|
}
|
||||||
modifiedLowerDevice.linkDescription = JSON.stringify(modifiedLowerDeviceLinkDescription);
|
modifiedLowerDevice.linkDescription = JSON.stringify(modifiedLowerDeviceLinkDescription);
|
||||||
|
|
||||||
// 3. 发起update请求并获取最新的设备详情(使用本地数据库时直接修改本地数据)
|
// TODO: 3. 发起update请求并获取最新的设备详情(离线模式下直接修改本地数据)
|
||||||
if (useLocalDB.value) {
|
if (offlineDev.value) {
|
||||||
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
||||||
}
|
}
|
||||||
const stationCode = station.value.code;
|
const stationCode = station.value.code;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DropletIcon, FanIcon, ShieldIcon, ThermometerIcon, ZapIcon } from 'lucide-vue-next';
|
import { ThunderboltOutlined } from '@vicons/antd';
|
||||||
|
import { ApertureOutline, LockOpenOutline, ThermometerOutline, WaterOutline } from '@vicons/ionicons5';
|
||||||
import { NCard, NFlex, NIcon, NTag } from 'naive-ui';
|
import { NCard, NFlex, NIcon, NTag } from 'naive-ui';
|
||||||
import { computed, toRefs } from 'vue';
|
import { computed, toRefs } from 'vue';
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ const formattedFanSpeeds = computed(() => {
|
|||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<NTag>
|
<NTag>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="ThermometerIcon" />
|
<NIcon :component="ThermometerOutline" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<span>温度: {{ temperature }}℃</span>
|
<span>温度: {{ temperature }}℃</span>
|
||||||
@@ -59,7 +60,7 @@ const formattedFanSpeeds = computed(() => {
|
|||||||
</NTag>
|
</NTag>
|
||||||
<NTag>
|
<NTag>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="DropletIcon" />
|
<NIcon :component="WaterOutline" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<span>湿度: {{ humidity }}%</span>
|
<span>湿度: {{ humidity }}%</span>
|
||||||
@@ -67,7 +68,7 @@ const formattedFanSpeeds = computed(() => {
|
|||||||
</NTag>
|
</NTag>
|
||||||
<NTag>
|
<NTag>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="FanIcon" />
|
<NIcon :component="ApertureOutline" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<span>风扇: {{ formattedFanSpeeds }}</span>
|
<span>风扇: {{ formattedFanSpeeds }}</span>
|
||||||
@@ -75,7 +76,7 @@ const formattedFanSpeeds = computed(() => {
|
|||||||
</NTag>
|
</NTag>
|
||||||
<NTag :type="getStatusTagType(accessControlStatus)">
|
<NTag :type="getStatusTagType(accessControlStatus)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="ShieldIcon" />
|
<NIcon :component="LockOpenOutline" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<span>门禁: {{ accessControlStatus }}</span>
|
<span>门禁: {{ accessControlStatus }}</span>
|
||||||
@@ -83,7 +84,7 @@ const formattedFanSpeeds = computed(() => {
|
|||||||
</NTag>
|
</NTag>
|
||||||
<NTag :type="getStatusTagType(lightningProtectionStatus)">
|
<NTag :type="getStatusTagType(lightningProtectionStatus)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="ZapIcon" />
|
<NIcon :component="ThunderboltOutlined" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<span>防雷: {{ lightningProtectionStatus }}</span>
|
<span>防雷: {{ lightningProtectionStatus }}</span>
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { detailDeviceApi, updateDeviceApi, type LinkDescription, type NdmDeviceResultVO, type NdmSwitchLinkDescription, type NdmSwitchPortInfo, type NdmSwitchResultVO, type Station } from '@/apis';
|
import { detailDeviceApi, updateDeviceApi, type LinkDescription, type NdmDeviceResultVO, type NdmSwitchLinkDescription, type NdmSwitchPortInfo, type NdmSwitchResultVO, type Station } from '@/apis';
|
||||||
import { SwitchPortLinkModal } from '@/components';
|
import { SwitchPortLinkModal } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { SELECT_DEVICE_FN_INJECTION_KEY } from '@/constants';
|
import { SELECT_DEVICE_FN_INJECTION_KEY } from '@/constants';
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { getPortStatusValue, transformPortSpeed } from '@/helpers';
|
import { getPortStatusValue, transformPortSpeed } from '@/helpers';
|
||||||
import { useDeviceStore, useSettingStore } from '@/stores';
|
import { useDeviceStore, useSettingStore } from '@/stores';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
@@ -27,9 +25,7 @@ const deviceStore = useDeviceStore();
|
|||||||
const { lineDevices } = storeToRefs(deviceStore);
|
const { lineDevices } = storeToRefs(deviceStore);
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { useLocalDB } = storeToRefs(settingStore);
|
const { offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station, ports } = toRefs(props);
|
const { ndmDevice, station, ports } = toRefs(props);
|
||||||
|
|
||||||
@@ -176,7 +172,6 @@ const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
|||||||
const onContextmenu = (payload: PointerEvent, port: NdmSwitchPortInfo) => {
|
const onContextmenu = (payload: PointerEvent, port: NdmSwitchPortInfo) => {
|
||||||
payload.stopPropagation();
|
payload.stopPropagation();
|
||||||
payload.preventDefault();
|
payload.preventDefault();
|
||||||
if (!hasPermission(station.value.code, PERMISSION_TYPE_LITERALS.OPERATION)) return;
|
|
||||||
const { clientX, clientY } = payload;
|
const { clientX, clientY } = payload;
|
||||||
contextmenu.value = { x: clientX, y: clientY, port };
|
contextmenu.value = { x: clientX, y: clientY, port };
|
||||||
showContextmenu.value = true;
|
showContextmenu.value = true;
|
||||||
@@ -213,8 +208,8 @@ const { mutate: unlinkDevice } = useMutation({
|
|||||||
delete modifiedUpperLinkDescription.downstream?.[port.portName];
|
delete modifiedUpperLinkDescription.downstream?.[port.portName];
|
||||||
modifiedUpperDevice.linkDescription = JSON.stringify(modifiedUpperLinkDescription);
|
modifiedUpperDevice.linkDescription = JSON.stringify(modifiedUpperLinkDescription);
|
||||||
|
|
||||||
// 3. 发起update请求并获取最新的设备详情(使用本地数据库时直接修改本地数据)
|
// TODO: 3. 发起update请求并获取最新的设备详情(离线模式下直接修改本地数据)
|
||||||
if (useLocalDB.value) {
|
if (offlineDev.value) {
|
||||||
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
||||||
}
|
}
|
||||||
const stationCode = station.value.code;
|
const stationCode = station.value.code;
|
||||||
@@ -286,11 +281,11 @@ onBeforeUnmount(() => {
|
|||||||
<NDescriptionsItem label="上行速率">{{ transformPortSpeed(port, 'in') }}</NDescriptionsItem>
|
<NDescriptionsItem label="上行速率">{{ transformPortSpeed(port, 'in') }}</NDescriptionsItem>
|
||||||
<NDescriptionsItem label="下行速率">{{ transformPortSpeed(port, 'out') }}</NDescriptionsItem>
|
<NDescriptionsItem label="下行速率">{{ transformPortSpeed(port, 'out') }}</NDescriptionsItem>
|
||||||
<NDescriptionsItem label="总速率">{{ transformPortSpeed(port, 'total') }}</NDescriptionsItem>
|
<NDescriptionsItem label="总速率">{{ transformPortSpeed(port, 'total') }}</NDescriptionsItem>
|
||||||
<NDescriptionsItem v-if="!!port.opticalTemperature && port.opticalTemperature >= 0" label="光模块温度">{{ port.opticalTemperature }} ℃</NDescriptionsItem>
|
<NDescriptionsItem v-if="port.opticalTemperature >= 0" label="光模块温度">{{ port.opticalTemperature }} ℃</NDescriptionsItem>
|
||||||
<NDescriptionsItem v-if="!!port.opticalVoltage && port.opticalVoltage >= 0" label="光模块电压">{{ port.opticalVoltage }} mV</NDescriptionsItem>
|
<NDescriptionsItem v-if="port.opticalVoltage >= 0" label="光模块电压">{{ port.opticalVoltage }} mV</NDescriptionsItem>
|
||||||
<NDescriptionsItem v-if="!!port.opticalBiasCurrent && port.opticalBiasCurrent >= 0" label="光模块偏置电流">{{ port.opticalBiasCurrent }} μA</NDescriptionsItem>
|
<NDescriptionsItem v-if="port.opticalBiasCurrent >= 0" label="光模块偏置电流">{{ port.opticalBiasCurrent }} μA</NDescriptionsItem>
|
||||||
<NDescriptionsItem v-if="!!port.opticalReceivePower && port.opticalReceivePower >= 0" label="光模块接收功率">{{ port.opticalReceivePower / 100 }} dBm</NDescriptionsItem>
|
<NDescriptionsItem v-if="port.opticalReceivePower >= 0" label="光模块接收功率">{{ port.opticalReceivePower / 100 }} dBm</NDescriptionsItem>
|
||||||
<NDescriptionsItem v-if="!!port.opticalTransmitPower && port.opticalTransmitPower >= 0" label="光模块发送功率">{{ port.opticalTransmitPower / 100 }} dBm</NDescriptionsItem>
|
<NDescriptionsItem v-if="port.opticalTransmitPower >= 0" label="光模块发送功率">{{ port.opticalTransmitPower / 100 }} dBm</NDescriptionsItem>
|
||||||
<NDescriptionsItem label="关联设备">
|
<NDescriptionsItem label="关联设备">
|
||||||
<span v-if="getLowerDeviceByPort(port)" style="text-decoration: underline; cursor: pointer" @click="() => navigateToLowerDevice(port)">
|
<span v-if="getLowerDeviceByPort(port)" style="text-decoration: underline; cursor: pointer" @click="() => navigateToLowerDevice(port)">
|
||||||
{{ getLowerDeviceByPort(port)?.name || '-' }}
|
{{ getLowerDeviceByPort(port)?.name || '-' }}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const show = defineModel<boolean>('show', { default: false });
|
|||||||
const deviceStore = useDeviceStore();
|
const deviceStore = useDeviceStore();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { useLocalDB } = storeToRefs(settingStore);
|
const { offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { ndmDevice, station, port } = toRefs(props);
|
const { ndmDevice, station, port } = toRefs(props);
|
||||||
|
|
||||||
@@ -78,9 +78,7 @@ const { mutate: linkPortToDevice, isPending: linking } = useMutation({
|
|||||||
const lowerDeviceDbId = lowerDevice.value?.id;
|
const lowerDeviceDbId = lowerDevice.value?.id;
|
||||||
if (!lowerDeviceDbId) throw new Error('该设备没有ID');
|
if (!lowerDeviceDbId) throw new Error('该设备没有ID');
|
||||||
|
|
||||||
// 0. 检查是否会导致循环关联,
|
// 0. 检查上游设备的linkDescription的downstream字段是否存在某个端口已经关联下游设备
|
||||||
if (upperDeviceDbId === lowerDeviceDbId) throw new Error('不能关联到自身');
|
|
||||||
// 以及检查上游设备的linkDescription的downstream字段是否存在某个端口已经关联下游设备
|
|
||||||
const duplicated = Object.entries(upperDeviceLinkDescription.value?.downstream ?? {}).find(([, deviceStoreIndex]) => {
|
const duplicated = Object.entries(upperDeviceLinkDescription.value?.downstream ?? {}).find(([, deviceStoreIndex]) => {
|
||||||
return deviceStoreIndex.deviceDbId === lowerDeviceDbId;
|
return deviceStoreIndex.deviceDbId === lowerDeviceDbId;
|
||||||
});
|
});
|
||||||
@@ -160,8 +158,8 @@ const { mutate: linkPortToDevice, isPending: linking } = useMutation({
|
|||||||
}
|
}
|
||||||
modifiedLowerDevice.linkDescription = JSON.stringify(modifiedLowerDeviceLinkDescription);
|
modifiedLowerDevice.linkDescription = JSON.stringify(modifiedLowerDeviceLinkDescription);
|
||||||
|
|
||||||
// 3. 发起update请求并获取最新的设备详情(使用本地数据库时直接修改本地数据)
|
// TODO: 3. 发起update请求并获取最新的设备详情(离线模式下直接修改本地数据)
|
||||||
if (useLocalDB.value) {
|
if (offlineDev.value) {
|
||||||
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
return { upperDevice: modifiedUpperDevice, lowerDevice: modifiedLowerDevice };
|
||||||
}
|
}
|
||||||
const stationCode = station.value.code;
|
const stationCode = station.value.code;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmAlarmHostResultVO, Station } from '@/apis';
|
import type { NdmAlarmHostResultVO, Station } from '@/apis';
|
||||||
import { AlarmHostCurrentDiag, AlarmHostHistoryDiag, AlarmHostUpdate, DeviceRawCard } from '@/components';
|
import { AlarmHostCurrentDiag, AlarmHostHistoryDiag, AlarmHostUpdate, DeviceRawCard } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmCameraResultVO, Station } from '@/apis';
|
import type { NdmCameraResultVO, Station } from '@/apis';
|
||||||
import { CameraCurrentDiag, CameraHistoryDiag, CameraUpdate, DeviceRawCard } from '@/components';
|
import { CameraCurrentDiag, CameraHistoryDiag, CameraUpdate, DeviceRawCard } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { activeRequests } = storeToRefs(settingStore);
|
const { offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ const QUERY_KEY = 'camera-installation-area-query';
|
|||||||
|
|
||||||
const { data: installationArea } = useQuery({
|
const { data: installationArea } = useQuery({
|
||||||
queryKey: computed(() => [QUERY_KEY, ndmDevice.value.gbCode, station.value.code]),
|
queryKey: computed(() => [QUERY_KEY, ndmDevice.value.gbCode, station.value.code]),
|
||||||
enabled: computed(() => activeRequests.value),
|
enabled: computed(() => !offlineDev.value),
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
const UNKNOWN_NAME = '-';
|
const UNKNOWN_NAME = '-';
|
||||||
@@ -107,8 +107,8 @@ const { data: installationArea } = useQuery({
|
|||||||
return `${tier1Area.name}-${tier2Area.name}`;
|
return `${tier1Area.name}-${tier2Area.name}`;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
watch(activeRequests, (active) => {
|
watch(offlineDev, (offline) => {
|
||||||
if (!active) {
|
if (offline) {
|
||||||
queryClient.cancelQueries({ queryKey: [QUERY_KEY] });
|
queryClient.cancelQueries({ queryKey: [QUERY_KEY] });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmDecoderResultVO, Station } from '@/apis';
|
import type { NdmDecoderResultVO, Station } from '@/apis';
|
||||||
import { DecoderCurrentDiag, DecoderHistoryDiag, DecoderUpdate, DeviceRawCard } from '@/components';
|
import { DecoderCurrentDiag, DecoderHistoryDiag, DecoderUpdate, DeviceRawCard } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmKeyboardResultVO, Station } from '@/apis';
|
import type { NdmKeyboardResultVO, Station } from '@/apis';
|
||||||
import { DeviceRawCard, KeyboardCurrentDiag, KeyboardHistoryDiag, KeyboardUpdate } from '@/components';
|
import { DeviceRawCard, KeyboardCurrentDiag, KeyboardHistoryDiag, KeyboardUpdate } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmNvrResultVO, Station } from '@/apis';
|
import type { NdmNvrResultVO, Station } from '@/apis';
|
||||||
import { DeviceRawCard, NvrCurrentDiag, NvrHistoryDiag, NvrUpdate } from '@/components';
|
import { DeviceRawCard, NvrCurrentDiag, NvrHistoryDiag, NvrUpdate } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmSecurityBoxResultVO, Station } from '@/apis';
|
import type { NdmSecurityBoxResultVO, Station } from '@/apis';
|
||||||
import { DeviceRawCard, SecurityBoxCurrentDiag, SecurityBoxHistoryDiag, SecurityBoxUpdate } from '@/components';
|
import { DeviceRawCard, SecurityBoxCurrentDiag, SecurityBoxHistoryDiag, SecurityBoxUpdate } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import ServerAlive from './server-alive.vue';
|
|||||||
import ServerCard from './server-card.vue';
|
import ServerCard from './server-card.vue';
|
||||||
import ServerCurrentDiag from './server-current-diag.vue';
|
import ServerCurrentDiag from './server-current-diag.vue';
|
||||||
import ServerHistoryDiag from './server-history-diag.vue';
|
import ServerHistoryDiag from './server-history-diag.vue';
|
||||||
import ServerStreamPush from './server-stream-push.vue';
|
|
||||||
import ServerUpdate from './server-update.vue';
|
import ServerUpdate from './server-update.vue';
|
||||||
|
|
||||||
export { ServerAlive, ServerCard, ServerCurrentDiag, ServerHistoryDiag, ServerUpdate, ServerStreamPush };
|
export { ServerAlive, ServerCard, ServerCurrentDiag, ServerHistoryDiag, ServerUpdate };
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { activeRequests } = storeToRefs(settingStore);
|
const { offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ const MEDIA_SERVER_ALIVE_QUERY_KEY = 'media-server-alive-query';
|
|||||||
const VIDEO_SERVER_ALIVE_QUERY_KEY = 'video-server-alive-query';
|
const VIDEO_SERVER_ALIVE_QUERY_KEY = 'video-server-alive-query';
|
||||||
const { data: isMediaServerAlive } = useQuery({
|
const { data: isMediaServerAlive } = useQuery({
|
||||||
queryKey: computed(() => [MEDIA_SERVER_ALIVE_QUERY_KEY, ndmDevice.value.id, ndmDevice.value.lastDiagTime]),
|
queryKey: computed(() => [MEDIA_SERVER_ALIVE_QUERY_KEY, ndmDevice.value.id, ndmDevice.value.lastDiagTime]),
|
||||||
enabled: computed(() => activeRequests.value && deviceType.value === DEVICE_TYPE_LITERALS.ndmMediaServer),
|
enabled: computed(() => !offlineDev.value && deviceType.value === DEVICE_TYPE_LITERALS.ndmMediaServer),
|
||||||
refetchInterval: 30 * 1000,
|
refetchInterval: 30 * 1000,
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
@@ -35,15 +35,15 @@ const { data: isMediaServerAlive } = useQuery({
|
|||||||
});
|
});
|
||||||
const { data: isSipServerAlive } = useQuery({
|
const { data: isSipServerAlive } = useQuery({
|
||||||
queryKey: computed(() => [VIDEO_SERVER_ALIVE_QUERY_KEY, ndmDevice.value.id, ndmDevice.value.lastDiagTime]),
|
queryKey: computed(() => [VIDEO_SERVER_ALIVE_QUERY_KEY, ndmDevice.value.id, ndmDevice.value.lastDiagTime]),
|
||||||
enabled: computed(() => activeRequests.value && deviceType.value === DEVICE_TYPE_LITERALS.ndmVideoServer),
|
enabled: computed(() => !offlineDev.value && deviceType.value === DEVICE_TYPE_LITERALS.ndmVideoServer),
|
||||||
refetchInterval: 30 * 1000,
|
refetchInterval: 30 * 1000,
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
return await isSipServerAliveApi({ stationCode: station.value.code, signal });
|
return await isSipServerAliveApi({ stationCode: station.value.code, signal });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
watch(activeRequests, (active) => {
|
watch(offlineDev, (offline) => {
|
||||||
if (!active) {
|
if (offline) {
|
||||||
queryClient.cancelQueries({ queryKey: [MEDIA_SERVER_ALIVE_QUERY_KEY] });
|
queryClient.cancelQueries({ queryKey: [MEDIA_SERVER_ALIVE_QUERY_KEY] });
|
||||||
queryClient.cancelQueries({ queryKey: [VIDEO_SERVER_ALIVE_QUERY_KEY] });
|
queryClient.cancelQueries({ queryKey: [VIDEO_SERVER_ALIVE_QUERY_KEY] });
|
||||||
}
|
}
|
||||||
@@ -56,29 +56,20 @@ watch(activeRequests, (active) => {
|
|||||||
<span>服务状态</span>
|
<span>服务状态</span>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<template v-if="!activeRequests">
|
<div v-if="deviceType === DEVICE_TYPE_LITERALS.ndmMediaServer">
|
||||||
<span>-</span>
|
<span>流媒体服务状态:</span>
|
||||||
</template>
|
<template v-if="!!isMediaServerAlive">
|
||||||
<template v-else>
|
<NTag size="small" :type="isMediaServerAlive.online ? 'success' : 'error'">{{ isMediaServerAlive.online ? '在线' : '离线' }}</NTag>
|
||||||
<template v-if="deviceType === DEVICE_TYPE_LITERALS.ndmMediaServer">
|
|
||||||
<span>流媒体服务状态:</span>
|
|
||||||
<template v-if="!!isMediaServerAlive">
|
|
||||||
<NTag size="small" :type="isMediaServerAlive.online ? 'success' : 'error'">{{ isMediaServerAlive.online ? '在线' : '离线' }}</NTag>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<span>-</span>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-if="deviceType === DEVICE_TYPE_LITERALS.ndmVideoServer">
|
<span v-else>-</span>
|
||||||
<span>信令服务状态:</span>
|
</div>
|
||||||
<template v-if="isSipServerAlive !== undefined">
|
<div v-if="deviceType === DEVICE_TYPE_LITERALS.ndmVideoServer">
|
||||||
<NTag size="small" :type="isSipServerAlive ? 'success' : 'error'">{{ isSipServerAlive ? '在线' : '离线' }}</NTag>
|
<span>信令服务状态:</span>
|
||||||
</template>
|
<template v-if="isSipServerAlive !== undefined">
|
||||||
<template v-else>
|
<NTag size="small" :type="isSipServerAlive ? 'success' : 'error'">{{ isSipServerAlive ? '在线' : '离线' }}</NTag>
|
||||||
<span>-</span>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
</template>
|
<span v-else>-</span>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmServerResultVO, Station } from '@/apis';
|
import type { NdmServerResultVO, Station } from '@/apis';
|
||||||
import { DeviceRawCard, ServerCurrentDiag, ServerHistoryDiag, ServerUpdate } from '@/components';
|
import { DeviceRawCard, ServerCurrentDiag, ServerHistoryDiag, ServerUpdate } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type NdmServerDiagInfo, type NdmServerResultVO, type Station } from '@/apis';
|
import { type NdmServerDiagInfo, type NdmServerResultVO, type Station } from '@/apis';
|
||||||
import { DeviceHardwareCard, DeviceHeaderCard, ServerAlive, ServerStreamPush } from '@/components';
|
import { DeviceHardwareCard, DeviceHeaderCard, ServerAlive } from '@/components';
|
||||||
import destr from 'destr';
|
import destr from 'destr';
|
||||||
import { NFlex } from 'naive-ui';
|
import { NFlex } from 'naive-ui';
|
||||||
import { computed, toRefs } from 'vue';
|
import { computed, toRefs } from 'vue';
|
||||||
@@ -30,7 +30,6 @@ const runningTime = computed(() => lastDiagInfo.value?.commInfo?.系统运行时
|
|||||||
<DeviceHeaderCard :ndm-device="ndmDevice" :station="station" />
|
<DeviceHeaderCard :ndm-device="ndmDevice" :station="station" />
|
||||||
<DeviceHardwareCard running-time-label="服务器运行时间" :cpu-usage="cpuUsage" :mem-usage="memUsage" :disk-usage="diskUsage" :running-time="runningTime" />
|
<DeviceHardwareCard running-time-label="服务器运行时间" :cpu-usage="cpuUsage" :mem-usage="memUsage" :disk-usage="diskUsage" :running-time="runningTime" />
|
||||||
<ServerAlive :ndm-device="ndmDevice" :station="station" />
|
<ServerAlive :ndm-device="ndmDevice" :station="station" />
|
||||||
<ServerStreamPush :ndm-device="ndmDevice" :station="station" />
|
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { getAllPushApi, type NdmServerResultVO, type Station } from '@/apis';
|
|
||||||
import { DEVICE_TYPE_LITERALS, tryGetDeviceType } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
|
||||||
import { useQuery, useQueryClient } from '@tanstack/vue-query';
|
|
||||||
import { NCard, NCollapse, NCollapseItem, NFlex, NTag, NText } from 'naive-ui';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { computed, toRefs, watch } from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
ndmDevice: NdmServerResultVO;
|
|
||||||
station: Station;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
|
||||||
const { activeRequests } = storeToRefs(settingStore);
|
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
|
||||||
|
|
||||||
const deviceType = computed(() => tryGetDeviceType(ndmDevice.value.deviceType));
|
|
||||||
|
|
||||||
const showCard = computed(() => deviceType.value === DEVICE_TYPE_LITERALS.ndmMediaServer);
|
|
||||||
|
|
||||||
const SERVER_STREAM_PUSH_KEY = 'server-stream-push-query';
|
|
||||||
|
|
||||||
const { data: streamPushes } = useQuery({
|
|
||||||
queryKey: computed(() => [SERVER_STREAM_PUSH_KEY, ndmDevice.value.id, ndmDevice.value.lastDiagTime]),
|
|
||||||
enabled: computed(() => activeRequests.value && showCard.value),
|
|
||||||
refetchInterval: 30 * 1000,
|
|
||||||
gcTime: 0,
|
|
||||||
queryFn: async ({ signal }) => {
|
|
||||||
const streamPushes = await getAllPushApi({ stationCode: station.value.code, signal });
|
|
||||||
return streamPushes;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
watch(activeRequests, (active) => {
|
|
||||||
if (!active) {
|
|
||||||
queryClient.cancelQueries({ queryKey: [SERVER_STREAM_PUSH_KEY] });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interface StreamPushStat {
|
|
||||||
ip: string;
|
|
||||||
port: number | null;
|
|
||||||
ssrc: string | null;
|
|
||||||
channelIds: string[];
|
|
||||||
}
|
|
||||||
const streamPushStat = computed(() => {
|
|
||||||
const stat: StreamPushStat[] = [];
|
|
||||||
streamPushes.value?.forEach((push) => {
|
|
||||||
if (!push.ip || !push.channelId) return;
|
|
||||||
const existIndex = stat.findIndex((item) => item.ip === push.ip);
|
|
||||||
if (existIndex === -1) {
|
|
||||||
stat.push({ ip: push.ip, port: push.port, ssrc: push.ssrc, channelIds: [push.channelId] });
|
|
||||||
} else {
|
|
||||||
const statItem = stat[existIndex];
|
|
||||||
if (!statItem) return;
|
|
||||||
statItem.channelIds.push(push.channelId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return stat;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NCard v-if="showCard" hoverable size="small">
|
|
||||||
<template #header>
|
|
||||||
<span>推流统计</span>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<template v-if="!activeRequests">
|
|
||||||
<span>-</span>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<NFlex vertical>
|
|
||||||
<NText depth="3">共 {{ streamPushStat.length }} 个推流目标</NText>
|
|
||||||
<NCollapse v-if="streamPushStat.length > 0">
|
|
||||||
<NCollapseItem v-for="{ ip, port, ssrc, channelIds } in streamPushStat" :key="`${ip}:${port}:${ssrc}`" :name="`${ip}:${port}:${ssrc}`">
|
|
||||||
<template #header>
|
|
||||||
<span>{{ ip }}</span>
|
|
||||||
</template>
|
|
||||||
<template #header-extra>
|
|
||||||
<span>{{ channelIds.length }} 路</span>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<NFlex>
|
|
||||||
<NTag v-for="channelId in channelIds" :key="channelId" size="small" type="info" :bordered="false">{{ channelId }}</NTag>
|
|
||||||
</NFlex>
|
|
||||||
</template>
|
|
||||||
</NCollapseItem>
|
|
||||||
</NCollapse>
|
|
||||||
</NFlex>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</NCard>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { NdmSwitchResultVO, Station } from '@/apis';
|
import type { NdmSwitchResultVO, Station } from '@/apis';
|
||||||
import { DeviceRawCard, SwitchCurrentDiag, SwitchHistoryDiag, SwitchUpdate } from '@/components';
|
import { DeviceRawCard, SwitchCurrentDiag, SwitchHistoryDiag, SwitchUpdate } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { useSettingStore } from '@/stores';
|
import { useSettingStore } from '@/stores';
|
||||||
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
import { NCard, NPageHeader, NScrollbar, NTab, NTabs } from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -18,9 +16,7 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { showDeviceRawData } = storeToRefs(settingStore);
|
const { debugModeEnabled } = storeToRefs(settingStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { ndmDevice, station } = toRefs(props);
|
const { ndmDevice, station } = toRefs(props);
|
||||||
|
|
||||||
@@ -35,8 +31,8 @@ const activeTabName = ref('当前诊断');
|
|||||||
const onTabChange = (name: string) => {
|
const onTabChange = (name: string) => {
|
||||||
activeTabName.value = name;
|
activeTabName.value = name;
|
||||||
};
|
};
|
||||||
watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
watch([ndmDevice, debugModeEnabled], ([newDevice, enabled], [oldDevice]) => {
|
||||||
if (newDevice.id !== oldDevice.id || (!showRaw && activeTabName.value === '原始数据')) {
|
if (newDevice.id !== oldDevice.id || !enabled) {
|
||||||
activeTabName.value = '当前诊断';
|
activeTabName.value = '当前诊断';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -49,8 +45,8 @@ watch([ndmDevice, showDeviceRawData], ([newDevice, showRaw], [oldDevice]) => {
|
|||||||
<NTabs :value="activeTabName" @update:value="onTabChange">
|
<NTabs :value="activeTabName" @update:value="onTabChange">
|
||||||
<NTab name="当前诊断">当前诊断</NTab>
|
<NTab name="当前诊断">当前诊断</NTab>
|
||||||
<NTab name="历史诊断">历史诊断</NTab>
|
<NTab name="历史诊断">历史诊断</NTab>
|
||||||
<NTab v-if="hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)" name="修改设备">修改设备</NTab>
|
<NTab name="修改设备">修改设备</NTab>
|
||||||
<NTab v-if="showDeviceRawData" name="原始数据">原始数据</NTab>
|
<NTab v-if="debugModeEnabled" name="原始数据">原始数据</NTab>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { initStationDevices, type NdmDeviceResultVO, type NdmNvrResultVO, type Station } from '@/apis';
|
import { initStationDevices, type NdmDeviceResultVO, type NdmNvrResultVO, type Station } from '@/apis';
|
||||||
import { useDeviceTree, usePermission, type UseDeviceTreeReturn } from '@/composables';
|
import { useDeviceTree, type UseDeviceTreeReturn } from '@/composables';
|
||||||
import { DEVICE_TYPE_NAMES, DEVICE_TYPE_LITERALS, tryGetDeviceType, type DeviceType, PERMISSION_TYPE_LITERALS } from '@/enums';
|
import { DEVICE_TYPE_NAMES, DEVICE_TYPE_LITERALS, tryGetDeviceType, type DeviceType } from '@/enums';
|
||||||
import { isNvrCluster } from '@/helpers';
|
import { isNvrCluster } from '@/helpers';
|
||||||
import { useDeviceStore, usePermissionStore } from '@/stores';
|
import { useDeviceStore, useStationStore } from '@/stores';
|
||||||
import { watchDebounced, watchImmediate } from '@vueuse/core';
|
import { watchImmediate } from '@vueuse/core';
|
||||||
import destr from 'destr';
|
import destr from 'destr';
|
||||||
import { isFunction } from 'es-toolkit';
|
import { isFunction } from 'es-toolkit';
|
||||||
import {
|
import {
|
||||||
@@ -27,7 +27,7 @@ import {
|
|||||||
type TreeProps,
|
type TreeProps,
|
||||||
} from 'naive-ui';
|
} from 'naive-ui';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed, h, nextTick, onBeforeUnmount, onMounted, ref, toRefs, useTemplateRef, watch, type CSSProperties } from 'vue';
|
import { computed, h, nextTick, onBeforeUnmount, ref, toRefs, useTemplateRef, watch, type CSSProperties } from 'vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
/**
|
/**
|
||||||
@@ -60,22 +60,20 @@ const { station, events, syncRoute, devicePrefixLabel } = toRefs(props);
|
|||||||
|
|
||||||
const themeVars = useThemeVars();
|
const themeVars = useThemeVars();
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
// 设备选择
|
// 设备选择
|
||||||
selectedStationCode,
|
selectedStationCode,
|
||||||
selectedDeviceType,
|
selectedDeviceType,
|
||||||
selectedDevice,
|
selectedDevice,
|
||||||
syncFromRoute,
|
|
||||||
syncToRoute,
|
|
||||||
selectDevice,
|
selectDevice,
|
||||||
// 设备管理
|
// 设备管理
|
||||||
exportDevice,
|
exportDevice,
|
||||||
exportDeviceTemplate,
|
exportDeviceTemplate,
|
||||||
importDevice,
|
importDevice,
|
||||||
deleteDevice,
|
deleteDevice,
|
||||||
} = useDeviceTree();
|
} = useDeviceTree({
|
||||||
|
syncRoute: computed(() => !!syncRoute.value),
|
||||||
|
});
|
||||||
|
|
||||||
// 将 `selectDevice` 函数暴露给父组件
|
// 将 `selectDevice` 函数暴露给父组件
|
||||||
emit('exposeSelectDeviceFn', selectDevice);
|
emit('exposeSelectDeviceFn', selectDevice);
|
||||||
@@ -89,9 +87,8 @@ const onSelectDevice = (device: NdmDeviceResultVO, stationCode: Station['code'])
|
|||||||
emit('afterSelectDevice', device, stationCode);
|
emit('afterSelectDevice', device, stationCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
const permissionStore = usePermissionStore();
|
const stationStore = useStationStore();
|
||||||
const stations = computed(() => permissionStore.stations.VIEW ?? []);
|
const { stations } = storeToRefs(stationStore);
|
||||||
|
|
||||||
const deviceStore = useDeviceStore();
|
const deviceStore = useDeviceStore();
|
||||||
const { lineDevices } = storeToRefs(deviceStore);
|
const { lineDevices } = storeToRefs(deviceStore);
|
||||||
|
|
||||||
@@ -223,17 +220,13 @@ const nodeProps: TreeProps['nodeProps'] = ({ option }) => {
|
|||||||
payload.stopPropagation();
|
payload.stopPropagation();
|
||||||
payload.preventDefault();
|
payload.preventDefault();
|
||||||
|
|
||||||
// 如果事件列表不包含 `manage`,则直接结束逻辑
|
// 仅当事件列表包含 `manage` 时才显示右键菜单
|
||||||
if (!events.value?.includes('manage')) return;
|
if (!events.value?.includes('manage')) return;
|
||||||
|
|
||||||
|
const { clientX, clientY } = payload;
|
||||||
const stationCode = option['stationCode'] as Station['code'];
|
const stationCode = option['stationCode'] as Station['code'];
|
||||||
|
|
||||||
// 仅当用户在该车站拥有操作权限时才显示右键菜单
|
|
||||||
if (!hasPermission(stationCode, PERMISSION_TYPE_LITERALS.OPERATION)) return;
|
|
||||||
|
|
||||||
const deviceType = option['deviceType'] as DeviceType | undefined;
|
const deviceType = option['deviceType'] as DeviceType | undefined;
|
||||||
const device = option['device'] as NdmDeviceResultVO | undefined;
|
const device = option['device'] as NdmDeviceResultVO | undefined;
|
||||||
const { clientX, clientY } = payload;
|
|
||||||
contextmenu.value = { x: clientX, y: clientY, stationCode, deviceType, device };
|
contextmenu.value = { x: clientX, y: clientY, stationCode, deviceType, device };
|
||||||
showContextmenu.value = true;
|
showContextmenu.value = true;
|
||||||
},
|
},
|
||||||
@@ -259,7 +252,7 @@ const renderIcmpStatistics = (onlineCount: number, offlineCount: number, count:
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
const renderDeviceNodePrefix = (device: NdmDeviceResultVO, stationCode: Station['code']) => {
|
const renderDeviceNodePrefix = (device: NdmDeviceResultVO, stationCode: Station['code']) => {
|
||||||
const renderViewDeviceButton = (device: NdmDeviceResultVO, stationCode: Station['code']) => {
|
const renderViewDeviceButton = (device: NdmDeviceResultVO, stationCode: string) => {
|
||||||
if (!devicePrefixLabel.value) return null;
|
if (!devicePrefixLabel.value) return null;
|
||||||
return h(
|
return h(
|
||||||
NButton,
|
NButton,
|
||||||
@@ -484,38 +477,11 @@ const onLocateDeviceTree = async () => {
|
|||||||
|
|
||||||
animated.value = true;
|
animated.value = true;
|
||||||
};
|
};
|
||||||
|
// 渲染全线设备树时,当选择的设备发生变化,则定位设备树
|
||||||
// 当选择的设备发生变化时,定位设备树,并同步选中状态到路由参数
|
|
||||||
// 暂时不考虑多次执行的问题,因为当选择的设备在设备树视口内时,不会发生滚动
|
// 暂时不考虑多次执行的问题,因为当选择的设备在设备树视口内时,不会发生滚动
|
||||||
watch(selectedDevice, async (newDevice, oldDevice) => {
|
watch(selectedDevice, async () => {
|
||||||
if (!!station.value) return;
|
if (!!station.value) return;
|
||||||
if (newDevice?.id === oldDevice?.id) return;
|
await onLocateDeviceTree();
|
||||||
// console.log('selectedDevice changed');
|
|
||||||
onLocateDeviceTree();
|
|
||||||
syncToRoute();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 当全线设备发生变化时,从路由参数同步选中状态
|
|
||||||
// 但lineDevices是shallowRef,因此需要深度侦听才能获取内部变化,
|
|
||||||
// 而单纯的深度侦听又可能会引发性能问题,因此尝试使用防抖侦听
|
|
||||||
watchDebounced(
|
|
||||||
lineDevices,
|
|
||||||
(newLineDevices) => {
|
|
||||||
if (syncRoute.value) {
|
|
||||||
// console.log('lineDevices changed');
|
|
||||||
syncFromRoute(newLineDevices);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
debounce: 500,
|
|
||||||
deep: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (syncRoute.value) {
|
|
||||||
syncFromRoute(lineDevices.value);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,27 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { retentionDaysApi, snapStatusApi, type LineAlarms, type LineDevices, type Station, type VersionInfo } from '@/apis';
|
import type { LineAlarms, LineDevices, Station, VersionInfo } from '@/apis';
|
||||||
import { ThemeSwitch } from '@/components';
|
import { ThemeSwitch } from '@/components';
|
||||||
import { usePermission } from '@/composables';
|
|
||||||
import { NDM_ALARM_STORE_ID, NDM_DEVICE_STORE_ID, NDM_STATION_STORE_ID } from '@/constants';
|
import { NDM_ALARM_STORE_ID, NDM_DEVICE_STORE_ID, NDM_STATION_STORE_ID } from '@/constants';
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
import { usePollingStore, useSettingStore } from '@/stores';
|
||||||
import { useSettingStore, useStationStore } from '@/stores';
|
|
||||||
import { downloadByData, getAppEnvConfig, parseErrorFeedback, sleep } from '@/utils';
|
import { downloadByData, getAppEnvConfig, parseErrorFeedback, sleep } from '@/utils';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
|
import { DeleteOutlined, ExportOutlined, ImportOutlined } from '@vicons/antd';
|
||||||
import { useEventListener } from '@vueuse/core';
|
import { useEventListener } from '@vueuse/core';
|
||||||
import axios, { isCancel } from 'axios';
|
import axios from 'axios';
|
||||||
import destr from 'destr';
|
import destr from 'destr';
|
||||||
import { isFunction } from 'es-toolkit';
|
import { isFunction } from 'es-toolkit';
|
||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
import { DownloadIcon, Trash2Icon, UploadIcon } from 'lucide-vue-next';
|
import { NButton, NDivider, NDrawer, NDrawerContent, NDropdown, NFlex, NFormItem, NIcon, NInput, NInputNumber, NModal, NSwitch, NText, type DropdownOption } from 'naive-ui';
|
||||||
import { NButton, NButtonGroup, NDivider, NDrawer, NDrawerContent, NDropdown, NFlex, NFormItem, NIcon, NInput, NInputNumber, NModal, NSwitch, NText, type DropdownOption } from 'naive-ui';
|
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
const show = defineModel<boolean>('show', { default: false });
|
const show = defineModel<boolean>('show', { default: false });
|
||||||
|
|
||||||
const stationStore = useStationStore();
|
|
||||||
const { stations } = storeToRefs(stationStore);
|
|
||||||
|
|
||||||
const occStation = computed(() => stations.value.find((station) => !!station.occ));
|
|
||||||
|
|
||||||
const settingsStore = useSettingStore();
|
const settingsStore = useSettingStore();
|
||||||
const { menuCollpased, stationGridCols, debugMode, showDeviceRawData, pollingStations, activeRequests, subscribeMessages, mockUser, useLocalDB } = storeToRefs(settingsStore);
|
const { menuCollpased, stationGridCols, debugModeEnabled, offlineDev } = storeToRefs(settingsStore);
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const versionInfo = ref<VersionInfo>({ version: '', buildTime: '' });
|
const versionInfo = ref<VersionInfo>({ version: '', buildTime: '' });
|
||||||
|
|
||||||
@@ -46,83 +40,6 @@ const { mutate: getVersionInfo } = useMutation({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const abortControllers = ref({
|
|
||||||
retentionDays: new AbortController(),
|
|
||||||
snapStatus: new AbortController(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const retentionDays = ref(0);
|
|
||||||
const { mutate: getRetentionDays, isPending: retentionDaysLoading } = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
abortControllers.value.retentionDays.abort();
|
|
||||||
abortControllers.value.retentionDays = new AbortController();
|
|
||||||
const signal = abortControllers.value.retentionDays.signal;
|
|
||||||
const days = await retentionDaysApi('get', { signal });
|
|
||||||
return days;
|
|
||||||
},
|
|
||||||
onSuccess: (days) => {
|
|
||||||
retentionDays.value = days;
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (isCancel(error)) return;
|
|
||||||
console.error(error);
|
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
|
||||||
window.$message.error(errorFeedback);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const { mutate: saveRetentionDays, isPending: retentionDaysSaving } = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
abortControllers.value.retentionDays.abort();
|
|
||||||
abortControllers.value.retentionDays = new AbortController();
|
|
||||||
const signal = abortControllers.value.retentionDays.signal;
|
|
||||||
await retentionDaysApi('post', { days: retentionDays.value, signal });
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (isCancel(error)) return;
|
|
||||||
console.error(error);
|
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
|
||||||
window.$message.error(errorFeedback);
|
|
||||||
// 修改失败,刷新 retentionDays
|
|
||||||
getRetentionDays();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const snapStatus = ref(false);
|
|
||||||
const { mutate: getSnapStatus, isPending: snapStatusLoading } = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
abortControllers.value.snapStatus.abort();
|
|
||||||
abortControllers.value.snapStatus = new AbortController();
|
|
||||||
const signal = abortControllers.value.snapStatus.signal;
|
|
||||||
const status = await snapStatusApi('get', { signal });
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
onSuccess: (status) => {
|
|
||||||
snapStatus.value = status;
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (isCancel(error)) return;
|
|
||||||
console.error(error);
|
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
|
||||||
window.$message.error(errorFeedback);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const { mutate: saveSnapStatus, isPending: snapStatusSaving } = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
abortControllers.value.snapStatus.abort();
|
|
||||||
abortControllers.value.snapStatus = new AbortController();
|
|
||||||
const signal = abortControllers.value.snapStatus.signal;
|
|
||||||
await snapStatusApi('post', { doSnap: snapStatus.value, signal });
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (isCancel(error)) return;
|
|
||||||
console.error(error);
|
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
|
||||||
window.$message.error(errorFeedback);
|
|
||||||
// 修改失败,刷新 snapStatus
|
|
||||||
getSnapStatus();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const showDebugCodeModal = ref(false);
|
const showDebugCodeModal = ref(false);
|
||||||
const debugCode = ref('');
|
const debugCode = ref('');
|
||||||
const enableDebugMode = () => {
|
const enableDebugMode = () => {
|
||||||
@@ -132,11 +49,11 @@ const enableDebugMode = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
showDebugCodeModal.value = false;
|
showDebugCodeModal.value = false;
|
||||||
debugMode.value = true;
|
settingsStore.enableDebugMode();
|
||||||
};
|
};
|
||||||
const disableDebugMode = () => {
|
const disableDebugMode = () => {
|
||||||
showDebugCodeModal.value = false;
|
showDebugCodeModal.value = false;
|
||||||
debugMode.value = false;
|
settingsStore.disableDebugMode();
|
||||||
};
|
};
|
||||||
useEventListener('keydown', (event) => {
|
useEventListener('keydown', (event) => {
|
||||||
const { ctrlKey, altKey, code } = event;
|
const { ctrlKey, altKey, code } = event;
|
||||||
@@ -147,18 +64,28 @@ useEventListener('keydown', (event) => {
|
|||||||
|
|
||||||
const expectToShowDebugCodeInput = ref(false);
|
const expectToShowDebugCodeInput = ref(false);
|
||||||
const onModalAfterEnter = () => {
|
const onModalAfterEnter = () => {
|
||||||
expectToShowDebugCodeInput.value = !debugMode.value;
|
expectToShowDebugCodeInput.value = !debugModeEnabled.value;
|
||||||
};
|
};
|
||||||
const onModalAfterLeave = () => {
|
const onModalAfterLeave = () => {
|
||||||
expectToShowDebugCodeInput.value = false;
|
expectToShowDebugCodeInput.value = false;
|
||||||
debugCode.value = '';
|
debugCode.value = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pollingStore = usePollingStore();
|
||||||
|
const { pollingEnabled } = storeToRefs(pollingStore);
|
||||||
|
const onPollingEnabledUpdate = (enabled: boolean) => {
|
||||||
|
if (enabled) {
|
||||||
|
pollingStore.startPolling();
|
||||||
|
} else {
|
||||||
|
pollingStore.stopPolling();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
type IndexedDbStoreId = typeof NDM_STATION_STORE_ID | typeof NDM_DEVICE_STORE_ID | typeof NDM_ALARM_STORE_ID;
|
type IndexedDbStoreId = typeof NDM_STATION_STORE_ID | typeof NDM_DEVICE_STORE_ID | typeof NDM_ALARM_STORE_ID;
|
||||||
type IndexedDbStoreStates = {
|
type IndexedDbStoreStates = {
|
||||||
[NDM_STATION_STORE_ID]: { stations: Station[] };
|
[NDM_STATION_STORE_ID]: { stations: Station[] };
|
||||||
[NDM_DEVICE_STORE_ID]: { lineDevices: LineDevices };
|
[NDM_DEVICE_STORE_ID]: { lineDevices: LineDevices };
|
||||||
[NDM_ALARM_STORE_ID]: { lineAlarms: LineAlarms };
|
[NDM_ALARM_STORE_ID]: { lineAlarms: LineAlarms; unreadLineAlarms: LineAlarms };
|
||||||
};
|
};
|
||||||
const exportFromIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, options?: { errorMsg?: string }) => {
|
const exportFromIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, options?: { errorMsg?: string }) => {
|
||||||
const { errorMsg } = options ?? {};
|
const { errorMsg } = options ?? {};
|
||||||
@@ -171,9 +98,8 @@ const exportFromIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, optio
|
|||||||
};
|
};
|
||||||
const importToIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, options?: { successMsg?: string; errorMsg?: string }) => {
|
const importToIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, options?: { successMsg?: string; errorMsg?: string }) => {
|
||||||
const { successMsg, errorMsg } = options ?? {};
|
const { successMsg, errorMsg } = options ?? {};
|
||||||
pollingStations.value = false;
|
pollingStore.stopPolling();
|
||||||
activeRequests.value = false;
|
offlineDev.value = true;
|
||||||
subscribeMessages.value = false;
|
|
||||||
const fileInput = document.createElement('input');
|
const fileInput = document.createElement('input');
|
||||||
fileInput.type = 'file';
|
fileInput.type = 'file';
|
||||||
fileInput.accept = '.json';
|
fileInput.accept = '.json';
|
||||||
@@ -196,9 +122,8 @@ const importToIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, options
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
const deleteFromIndexedDB = async (storeId: IndexedDbStoreId) => {
|
const deleteFromIndexedDB = async (storeId: IndexedDbStoreId) => {
|
||||||
pollingStations.value = false;
|
pollingStore.stopPolling();
|
||||||
activeRequests.value = false;
|
offlineDev.value = true;
|
||||||
subscribeMessages.value = false;
|
|
||||||
await localforage.removeItem(storeId).catch((error) => {
|
await localforage.removeItem(storeId).catch((error) => {
|
||||||
window.$message.error(`${error}`);
|
window.$message.error(`${error}`);
|
||||||
return;
|
return;
|
||||||
@@ -267,27 +192,13 @@ const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
watch([activeRequests, show], ([active, entered]) => {
|
onMounted(() => {
|
||||||
if (!active) return;
|
|
||||||
if (entered) {
|
|
||||||
getRetentionDays();
|
|
||||||
getSnapStatus();
|
|
||||||
} else {
|
|
||||||
abortControllers.value.retentionDays.abort();
|
|
||||||
abortControllers.value.snapStatus.abort();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const onDrawerAfterEnter = () => {
|
|
||||||
getVersionInfo();
|
getVersionInfo();
|
||||||
};
|
});
|
||||||
const onDrawerAfterLeave = () => {
|
|
||||||
abortControllers.value.retentionDays.abort();
|
|
||||||
abortControllers.value.snapStatus.abort();
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NDrawer v-model:show="show" :width="560" :auto-focus="false" @after-enter="onDrawerAfterEnter" @after-leave="onDrawerAfterLeave">
|
<NDrawer v-model:show="show" :width="560" :auto-focus="false">
|
||||||
<NDrawerContent closable title="系统设置" :native-scrollbar="false">
|
<NDrawerContent closable title="系统设置" :native-scrollbar="false">
|
||||||
<NFlex vertical>
|
<NFlex vertical>
|
||||||
<NDivider>主题</NDivider>
|
<NDivider>主题</NDivider>
|
||||||
@@ -299,64 +210,26 @@ const onDrawerAfterLeave = () => {
|
|||||||
<NFormItem label="折叠菜单" label-placement="left">
|
<NFormItem label="折叠菜单" label-placement="left">
|
||||||
<NSwitch size="small" v-model:value="menuCollpased" />
|
<NSwitch size="small" v-model:value="menuCollpased" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem label="车站列数" label-placement="left">
|
<template v-if="route.path === '/station'">
|
||||||
<NInputNumber v-model:value="stationGridCols" :min="1" :max="10" />
|
<NFormItem label="车站列数" label-placement="left">
|
||||||
</NFormItem>
|
<NInputNumber v-model:value="stationGridCols" :min="1" :max="10" />
|
||||||
|
|
||||||
<template v-if="!!occStation && hasPermission(occStation.code, PERMISSION_TYPE_LITERALS.OPERATION)">
|
|
||||||
<NDivider>告警</NDivider>
|
|
||||||
<NFormItem label="告警画面截图保留天数" label-placement="left">
|
|
||||||
<NFlex justify="space-between" align="center" style="width: 100%">
|
|
||||||
<NInputNumber v-model:value="retentionDays" :min="1" :max="15" />
|
|
||||||
<NButtonGroup>
|
|
||||||
<NButton secondary size="small" :disabled="retentionDaysSaving" :loading="retentionDaysLoading" @click="() => getRetentionDays()">刷新</NButton>
|
|
||||||
<NButton secondary size="small" :disabled="retentionDaysLoading" :loading="retentionDaysSaving" @click="() => saveRetentionDays()">保存</NButton>
|
|
||||||
</NButtonGroup>
|
|
||||||
</NFlex>
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem label="自动获取告警画面截图" label-placement="left">
|
|
||||||
<NFlex justify="space-between" align="center" style="width: 100%">
|
|
||||||
<NSwitch size="small" v-model:value="snapStatus" />
|
|
||||||
<NButtonGroup>
|
|
||||||
<NButton secondary size="small" :disabled="snapStatusSaving" :loading="snapStatusLoading" @click="() => getSnapStatus()">刷新</NButton>
|
|
||||||
<NButton secondary size="small" :disabled="snapStatusLoading" :loading="snapStatusSaving" @click="() => saveSnapStatus()">保存</NButton>
|
|
||||||
</NButtonGroup>
|
|
||||||
</NFlex>
|
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="debugMode">
|
<template v-if="debugModeEnabled">
|
||||||
<NDivider title-placement="center">调试</NDivider>
|
<NDivider title-placement="center">调试</NDivider>
|
||||||
<NFormItem label="调试模式" label-placement="left">
|
<NFormItem label="启用轮询" label-placement="left">
|
||||||
<NSwitch size="small" v-model:value="debugMode" />
|
<NSwitch size="small" :value="pollingEnabled" @update:value="onPollingEnabledUpdate" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NDivider title-placement="left" dashed>数据设置</NDivider>
|
<NFormItem label="离线开发" label-placement="left">
|
||||||
<NFormItem label="显示设备原始数据" label-placement="left">
|
<NSwitch size="small" v-model:value="offlineDev" />
|
||||||
<NSwitch size="small" v-model:value="showDeviceRawData" />
|
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NDivider title-placement="left" dashed>网络设置</NDivider>
|
<NFormItem label="本地数据库" label-placement="left">
|
||||||
<NFormItem label="轮询车站" label-placement="left">
|
|
||||||
<NSwitch size="small" v-model:value="pollingStations" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem label="主动请求" label-placement="left">
|
|
||||||
<NSwitch size="small" v-model:value="activeRequests" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem label="订阅消息" label-placement="left">
|
|
||||||
<NSwitch size="small" v-model:value="subscribeMessages" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem label="模拟用户" label-placement="left">
|
|
||||||
<NSwitch size="small" v-model:value="mockUser" />
|
|
||||||
</NFormItem>
|
|
||||||
<NDivider title-placement="left" dashed>数据库设置</NDivider>
|
|
||||||
<NFormItem label="直接操作本地数据库" label-placement="left">
|
|
||||||
<NSwitch size="small" v-model:value="useLocalDB" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem label="数据操作" label-placement="left">
|
|
||||||
<NFlex>
|
<NFlex>
|
||||||
<NDropdown trigger="click" :options="exportDropdownOptions" @select="onSelectDropdownOption">
|
<NDropdown trigger="click" :options="exportDropdownOptions" @select="onSelectDropdownOption">
|
||||||
<NButton secondary size="small">
|
<NButton secondary size="small">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="DownloadIcon" />
|
<NIcon :component="ExportOutlined" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>导出</template>
|
<template #default>导出</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -364,7 +237,7 @@ const onDrawerAfterLeave = () => {
|
|||||||
<NDropdown trigger="click" :options="importDropdownOptions" @select="onSelectDropdownOption">
|
<NDropdown trigger="click" :options="importDropdownOptions" @select="onSelectDropdownOption">
|
||||||
<NButton secondary size="small">
|
<NButton secondary size="small">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="UploadIcon" />
|
<NIcon :component="ImportOutlined" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>导入</template>
|
<template #default>导入</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -372,7 +245,7 @@ const onDrawerAfterLeave = () => {
|
|||||||
<NDropdown trigger="click" :options="deleteDropdownOptions" @select="onSelectDropdownOption">
|
<NDropdown trigger="click" :options="deleteDropdownOptions" @select="onSelectDropdownOption">
|
||||||
<NButton secondary size="small">
|
<NButton secondary size="small">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="Trash2Icon" />
|
<NIcon :component="DeleteOutlined" />
|
||||||
</template>
|
</template>
|
||||||
<template #default>删除</template>
|
<template #default>删除</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -391,7 +264,7 @@ const onDrawerAfterLeave = () => {
|
|||||||
|
|
||||||
<NModal v-model:show="showDebugCodeModal" preset="dialog" type="info" @after-enter="onModalAfterEnter" @after-leave="onModalAfterLeave">
|
<NModal v-model:show="showDebugCodeModal" preset="dialog" type="info" @after-enter="onModalAfterEnter" @after-leave="onModalAfterLeave">
|
||||||
<template #header>
|
<template #header>
|
||||||
<NText v-if="!debugMode">请输入调试码</NText>
|
<NText v-if="!debugModeEnabled">请输入调试码</NText>
|
||||||
<NText v-else>确认关闭调试模式</NText>
|
<NText v-else>确认关闭调试模式</NText>
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
@@ -399,7 +272,7 @@ const onDrawerAfterLeave = () => {
|
|||||||
</template>
|
</template>
|
||||||
<template #action>
|
<template #action>
|
||||||
<NButton @click="showDebugCodeModal = false">取消</NButton>
|
<NButton @click="showDebugCodeModal = false">取消</NButton>
|
||||||
<NButton v-if="!debugMode" type="primary" @click="enableDebugMode">启用</NButton>
|
<NButton v-if="!debugModeEnabled" type="primary" @click="enableDebugMode">启用</NButton>
|
||||||
<NButton v-else type="primary" @click="disableDebugMode">确认</NButton>
|
<NButton v-else type="primary" @click="disableDebugMode">确认</NButton>
|
||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ import { storeToRefs } from 'pinia';
|
|||||||
import type { ComponentInstance } from 'vue';
|
import type { ComponentInstance } from 'vue';
|
||||||
|
|
||||||
const settingsStore = useSettingStore();
|
const settingsStore = useSettingStore();
|
||||||
const { darkMode } = storeToRefs(settingsStore);
|
const { darkThemeEnabled } = storeToRefs(settingsStore);
|
||||||
|
|
||||||
// 使外部能够获取NSwitch的类型提示
|
// 使外部能够获取NSwitch的类型提示
|
||||||
defineExpose({} as ComponentInstance<typeof NSwitch>);
|
defineExpose({} as ComponentInstance<typeof NSwitch>);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSwitch v-model:value="darkMode">
|
<NSwitch v-model:value="darkThemeEnabled">
|
||||||
<template #unchecked-icon>
|
<template #unchecked-icon>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export * from './device';
|
export * from './device';
|
||||||
export * from './global';
|
export * from './global';
|
||||||
export * from './permission';
|
|
||||||
export * from './station';
|
export * from './station';
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import type { ComponentInstance } from 'vue';
|
|
||||||
import PermissionConfigModal from './permission-config-modal.vue';
|
|
||||||
|
|
||||||
export type PermissionConfigModalProps = ComponentInstance<typeof PermissionConfigModal>['$props'];
|
|
||||||
|
|
||||||
export { PermissionConfigModal };
|
|
||||||
@@ -1,302 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { detailBaseEmployeeApi, modifyPermissionApi, pagePermissionApi, type BaseEmployeeResultVO, type NdmPermissionResultVO, type NdmPermissionSaveVO, type Station } from '@/apis';
|
|
||||||
import { PERMISSION_TYPE_LITERALS, PERMISSION_TYPE_NAMES, type PermissionType } from '@/enums';
|
|
||||||
import { useStationStore } from '@/stores';
|
|
||||||
import { parseErrorFeedback } from '@/utils';
|
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
|
||||||
import { objectEntries } from '@vueuse/core';
|
|
||||||
import { isCancel } from 'axios';
|
|
||||||
import { cloneDeep } from 'es-toolkit';
|
|
||||||
import { NButton, NCheckbox, NDataTable, NFlex, NModal, NText, type DataTableColumn, type DataTableColumns } from 'naive-ui';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { computed, h, ref, toRefs } from 'vue';
|
|
||||||
|
|
||||||
type NdmPermissionSaveOrResultVO = NdmPermissionSaveVO | NdmPermissionResultVO;
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
employeeId?: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const stationStore = useStationStore();
|
|
||||||
const { stations } = storeToRefs(stationStore);
|
|
||||||
|
|
||||||
const show = defineModel<boolean>('show', { default: false });
|
|
||||||
|
|
||||||
const { employeeId } = toRefs(props);
|
|
||||||
|
|
||||||
const abortController = ref<AbortController>(new AbortController());
|
|
||||||
|
|
||||||
const employee = ref<BaseEmployeeResultVO>();
|
|
||||||
const { mutateAsync: getEmployeeAsync } = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
abortController.value.abort();
|
|
||||||
abortController.value = new AbortController();
|
|
||||||
|
|
||||||
if (!employeeId.value) return;
|
|
||||||
|
|
||||||
const signal = abortController.value.signal;
|
|
||||||
|
|
||||||
const data = await detailBaseEmployeeApi(employeeId.value, { signal });
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
onSuccess: (data) => {
|
|
||||||
if (!data) return;
|
|
||||||
employee.value = data;
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (isCancel(error)) return;
|
|
||||||
console.error(error);
|
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
|
||||||
window.$message.error(errorFeedback);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 从后端获取的原始权限列表
|
|
||||||
const originalList = ref<NdmPermissionResultVO[]>([]);
|
|
||||||
// 当前用户配置的权限列表
|
|
||||||
const currentList = ref<NdmPermissionSaveOrResultVO[]>([]);
|
|
||||||
|
|
||||||
const { mutate: getPermissions, isPending: permissionsLoading } = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
if (!employeeId.value) throw new Error('员工ID不能为空');
|
|
||||||
|
|
||||||
abortController.value.abort();
|
|
||||||
abortController.value = new AbortController();
|
|
||||||
|
|
||||||
const signal = abortController.value.signal;
|
|
||||||
|
|
||||||
const data = await pagePermissionApi(
|
|
||||||
{
|
|
||||||
model: {
|
|
||||||
employeeId: employeeId.value,
|
|
||||||
},
|
|
||||||
current: 1,
|
|
||||||
size: Object.keys(PERMISSION_TYPE_LITERALS).length * stations.value.length,
|
|
||||||
},
|
|
||||||
{ signal },
|
|
||||||
);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
onSuccess: (data) => {
|
|
||||||
if (!data) return;
|
|
||||||
const { records } = data;
|
|
||||||
originalList.value = cloneDeep(records);
|
|
||||||
currentList.value = cloneDeep(records);
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (isCancel(error)) return;
|
|
||||||
console.error(error);
|
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
|
||||||
window.$message.error(errorFeedback);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const onUpdatePermissionChecked = (checked: boolean, stationCode: Station['code'], permissionType: PermissionType) => {
|
|
||||||
if (!employeeId.value) return;
|
|
||||||
if (checked) {
|
|
||||||
const existed = currentList.value.some((permission) => permission.stationCode === stationCode && permission.type === permissionType);
|
|
||||||
if (!existed) {
|
|
||||||
const saveVO: NdmPermissionSaveVO = {
|
|
||||||
employeeId: employeeId.value,
|
|
||||||
stationCode,
|
|
||||||
type: permissionType,
|
|
||||||
};
|
|
||||||
currentList.value.push(saveVO);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const index = currentList.value.findIndex((permission) => permission.stationCode === stationCode && permission.type === permissionType);
|
|
||||||
if (index !== -1) {
|
|
||||||
currentList.value.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const tableColumns = computed<DataTableColumns<Station>>(() => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: () => {
|
|
||||||
const permissionCount = currentList.value.length;
|
|
||||||
const permissionTypeCount = objectEntries(PERMISSION_TYPE_LITERALS).length;
|
|
||||||
const checked = permissionCount === stations.value.length * permissionTypeCount;
|
|
||||||
const indeterminate = permissionCount > 0 && permissionCount < stations.value.length * permissionTypeCount;
|
|
||||||
return h(NCheckbox, {
|
|
||||||
checked,
|
|
||||||
indeterminate,
|
|
||||||
onUpdateChecked: (checked) => {
|
|
||||||
objectEntries(PERMISSION_TYPE_LITERALS).forEach(([permissionType]) => {
|
|
||||||
stations.value.forEach((station) => {
|
|
||||||
onUpdatePermissionChecked(checked, station.code, permissionType);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
key: 'row-check',
|
|
||||||
align: 'center',
|
|
||||||
width: 60,
|
|
||||||
fixed: 'left',
|
|
||||||
render: (rowData) => {
|
|
||||||
const { code: stationCode } = rowData;
|
|
||||||
const permissionTypeCount = objectEntries(PERMISSION_TYPE_LITERALS).length;
|
|
||||||
const stationCheckedPermissions = currentList.value.filter((permission) => permission.stationCode === stationCode);
|
|
||||||
const checked = stationCheckedPermissions.length === permissionTypeCount;
|
|
||||||
const indeterminate = stationCheckedPermissions.length > 0 && stationCheckedPermissions.length < permissionTypeCount;
|
|
||||||
return h(NCheckbox, {
|
|
||||||
checked,
|
|
||||||
indeterminate,
|
|
||||||
onUpdateChecked: (checked) => {
|
|
||||||
objectEntries(PERMISSION_TYPE_LITERALS).forEach(([permissionType]) => {
|
|
||||||
onUpdatePermissionChecked(checked, stationCode, permissionType);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ title: '车站编号', key: 'code', align: 'center', width: 120 },
|
|
||||||
{ title: '车站名称', key: 'name', align: 'center', width: 360 },
|
|
||||||
// 「权限」列
|
|
||||||
...objectEntries(PERMISSION_TYPE_NAMES).map<DataTableColumn<Station>>(([permissionType, title]) => ({
|
|
||||||
title: () => {
|
|
||||||
const permissionCount = currentList.value.filter((permission) => permission.type === permissionType).length;
|
|
||||||
const checked = permissionCount === stations.value.length;
|
|
||||||
const indeterminate = permissionCount > 0 && permissionCount < stations.value.length;
|
|
||||||
return h(
|
|
||||||
NFlex,
|
|
||||||
{
|
|
||||||
justify: 'center',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
default: () => [
|
|
||||||
h(NCheckbox, {
|
|
||||||
checked,
|
|
||||||
indeterminate,
|
|
||||||
onUpdateChecked: (checked) => {
|
|
||||||
stations.value.forEach((station) => {
|
|
||||||
onUpdatePermissionChecked(checked, station.code, permissionType);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
h('span', title),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
key: permissionType,
|
|
||||||
align: 'center',
|
|
||||||
render: (rowData) => {
|
|
||||||
const { code: stationCode } = rowData;
|
|
||||||
return h(NCheckbox, {
|
|
||||||
checked: currentList.value.some((permission) => permission.stationCode === stationCode && permission.type === permissionType),
|
|
||||||
onUpdateChecked: (checked) => onUpdatePermissionChecked(checked, stationCode, permissionType),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
const { mutate: savePermissions, isPending: permissionsSaving } = useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
if (!employeeId.value) throw new Error('员工ID不能为空');
|
|
||||||
|
|
||||||
abortController.value.abort();
|
|
||||||
abortController.value = new AbortController();
|
|
||||||
|
|
||||||
const signal = abortController.value.signal;
|
|
||||||
|
|
||||||
// 执行diff计算,生成需要保存的权限列表和需要删除的权限ID列表
|
|
||||||
const saveList: NdmPermissionSaveVO[] = [];
|
|
||||||
const removeList: string[] = [];
|
|
||||||
// 遍历当前状态,如果权限不在原始权限列表中,说明是需要新增的权限
|
|
||||||
currentList.value.forEach((permission) => {
|
|
||||||
const { stationCode, type } = permission;
|
|
||||||
if (!stationCode || !type) return;
|
|
||||||
if (!originalList.value.some((permission) => permission.stationCode === stationCode && permission.type === type)) {
|
|
||||||
saveList.push({
|
|
||||||
employeeId: employeeId.value,
|
|
||||||
stationCode,
|
|
||||||
type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 遍历原始状态,如果权限不在当前状态中,说明是需要删除的权限
|
|
||||||
originalList.value.forEach((permission) => {
|
|
||||||
const { id, stationCode, type } = permission;
|
|
||||||
if (!id) return;
|
|
||||||
if (!currentList.value.some((permission) => permission.stationCode === stationCode && permission.type === type)) {
|
|
||||||
removeList.push(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await modifyPermissionApi(
|
|
||||||
{
|
|
||||||
employeeId: employeeId.value,
|
|
||||||
saveList,
|
|
||||||
removeList,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
signal,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onSuccess: () => {
|
|
||||||
window.$message.success('权限配置保存成功');
|
|
||||||
getPermissions();
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
if (isCancel(error)) return;
|
|
||||||
console.error(error);
|
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
|
||||||
window.$message.error(errorFeedback);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const onAfterEnter = () => {
|
|
||||||
getEmployeeAsync().then(() => getPermissions());
|
|
||||||
};
|
|
||||||
|
|
||||||
const onAfterLeave = () => {
|
|
||||||
employee.value = undefined;
|
|
||||||
originalList.value = [];
|
|
||||||
currentList.value = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClose = () => {
|
|
||||||
abortController.value.abort();
|
|
||||||
show.value = false;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<NModal
|
|
||||||
v-model:show="show"
|
|
||||||
preset="card"
|
|
||||||
style="width: 100vw; height: 100vh"
|
|
||||||
:content-style="{ height: '100%', overflow: 'hidden' }"
|
|
||||||
:close-on-esc="false"
|
|
||||||
:mask-closable="false"
|
|
||||||
:auto-focus="false"
|
|
||||||
@after-enter="onAfterEnter"
|
|
||||||
@after-leave="onAfterLeave"
|
|
||||||
@close="onClose"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<span>{{ `配置权限 - ${employee?.realName ?? ''}` }}</span>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<NDataTable flex-height style="height: 100%" :columns="tableColumns" :data="stations" :loading="permissionsLoading" :single-line="false" />
|
|
||||||
</template>
|
|
||||||
<template #footer>
|
|
||||||
<NText depth="3" style="font-size: smaller">*未勾选任何权限的用户将被认为拥有所有权限</NText>
|
|
||||||
</template>
|
|
||||||
<template #action>
|
|
||||||
<NFlex justify="end">
|
|
||||||
<NButton size="small" @click="onClose">取消</NButton>
|
|
||||||
<NButton type="primary" size="small" :loading="permissionsSaving" @click="() => savePermissions()">保存</NButton>
|
|
||||||
</NFlex>
|
|
||||||
</template>
|
|
||||||
</NModal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
@@ -59,7 +59,7 @@ const tableColumns = ref<DataTableBaseColumn<NdmDeviceAlarmLogResultVO>[]>([
|
|||||||
const stationDevices = lineDevices.value[stationCode];
|
const stationDevices = lineDevices.value[stationCode];
|
||||||
if (!stationDevices) return;
|
if (!stationDevices) return;
|
||||||
const classified = stationDevices[deviceType];
|
const classified = stationDevices[deviceType];
|
||||||
const device = classified.find((device) => !!device.deviceId && device.deviceId === rowData.deviceId);
|
const device = classified.find((device) => device.deviceId === rowData.deviceId);
|
||||||
if (!device) return;
|
if (!device) return;
|
||||||
const deviceDbId = device.id;
|
const deviceDbId = device.id;
|
||||||
router.push({
|
router.push({
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { batchExportRecordCheckApi, pageDefParameterApi, type Station } from '@/apis';
|
import { getRecordCheckApi, type NdmNvrResultVO, type Station } from '@/apis';
|
||||||
import { downloadByData, parseErrorFeedback } from '@/utils';
|
import { exportRecordDiagCsv, isNvrCluster, transformRecordChecks } from '@/helpers';
|
||||||
|
import { useDeviceStore } from '@/stores';
|
||||||
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
import { isCancel } from 'axios';
|
import { isCancel } from 'axios';
|
||||||
import dayjs from 'dayjs';
|
import { NButton, NGrid, NGridItem, NModal, NScrollbar, NSpin } from 'naive-ui';
|
||||||
import { NButton, NFlex, NGrid, NGridItem, NModal, NScrollbar, NSpin } from 'naive-ui';
|
import { storeToRefs } from 'pinia';
|
||||||
import { ref, toRefs } from 'vue';
|
import { computed, ref, toRefs } from 'vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
stations: Station[];
|
stations: Station[];
|
||||||
@@ -17,66 +19,50 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const show = defineModel<boolean>('show');
|
const show = defineModel<boolean>('show');
|
||||||
|
|
||||||
|
const deviceStore = useDeviceStore();
|
||||||
|
const { lineDevices } = storeToRefs(deviceStore);
|
||||||
|
|
||||||
const { stations } = toRefs(props);
|
const { stations } = toRefs(props);
|
||||||
|
|
||||||
|
const nvrClusterRecord = computed(() => {
|
||||||
|
const clusterMap: Record<Station['code'], { stationName: Station['name']; clusters: NdmNvrResultVO[] }> = {};
|
||||||
|
stations.value.forEach((station) => {
|
||||||
|
clusterMap[station.code] = {
|
||||||
|
stationName: station.name,
|
||||||
|
clusters: [],
|
||||||
|
};
|
||||||
|
const stationDevices = lineDevices.value[station.code];
|
||||||
|
const nvrs = stationDevices?.['ndmNvr'] ?? [];
|
||||||
|
nvrs.forEach((nvr) => {
|
||||||
|
if (isNvrCluster(nvr)) {
|
||||||
|
clusterMap[station.code]?.clusters?.push(nvr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return clusterMap;
|
||||||
|
});
|
||||||
|
|
||||||
const abortController = ref<AbortController>(new AbortController());
|
const abortController = ref<AbortController>(new AbortController());
|
||||||
|
|
||||||
const { mutate: batchExportRecordCheck, isPending: batchExporting } = useMutation({
|
const { mutate: exportRecordDiags, isPending: exporting } = useMutation({
|
||||||
mutationFn: async (params: { stations: Station[] }) => {
|
mutationFn: async (params: { clusters: NdmNvrResultVO[]; stationCode: Station['code'] }) => {
|
||||||
const timer = setTimeout(() => {
|
const { clusters, stationCode } = params;
|
||||||
if (!batchExporting.value) return;
|
if (clusters.length === 0) {
|
||||||
window.$message.info('导出耗时较长,请耐心等待...', { duration: 0 });
|
const stationName = nvrClusterRecord.value[stationCode]?.stationName ?? '';
|
||||||
}, 3000);
|
window.$message.info(`${stationName} 没有录像诊断数据`);
|
||||||
|
return;
|
||||||
try {
|
|
||||||
abortController.value.abort();
|
|
||||||
abortController.value = new AbortController();
|
|
||||||
const { records = [] } = await pageDefParameterApi(
|
|
||||||
{
|
|
||||||
model: {
|
|
||||||
key: 'NVR_GAP_SECONDS',
|
|
||||||
},
|
|
||||||
extra: {},
|
|
||||||
current: 1,
|
|
||||||
size: 1,
|
|
||||||
sort: 'id',
|
|
||||||
order: 'descending',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
signal: abortController.value.signal,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const gapSeconds = parseInt(records.at(0)?.value ?? '5');
|
|
||||||
|
|
||||||
abortController.value.abort();
|
|
||||||
abortController.value = new AbortController();
|
|
||||||
const data = await batchExportRecordCheckApi(
|
|
||||||
{
|
|
||||||
checkDuration: 90,
|
|
||||||
gapSeconds,
|
|
||||||
stationCode: params.stations.map((station) => station.code),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
signal: abortController.value.signal,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
} finally {
|
|
||||||
window.$message.destroyAll();
|
|
||||||
clearTimeout(timer);
|
|
||||||
}
|
}
|
||||||
|
const cluster = clusters.at(0);
|
||||||
|
if (!cluster) return;
|
||||||
|
abortController.value.abort();
|
||||||
|
abortController.value = new AbortController();
|
||||||
|
const checks = await getRecordCheckApi(cluster, 90, [], { stationCode: stationCode, signal: abortController.value.signal });
|
||||||
|
return checks;
|
||||||
},
|
},
|
||||||
onSuccess: (data, { stations }) => {
|
onSuccess: (checks, { stationCode }) => {
|
||||||
const time = dayjs().format('YYYY-MM-DD_HH-mm-ss');
|
if (!checks || checks.length === 0) return;
|
||||||
let stationName = '';
|
const recordDiags = transformRecordChecks(checks);
|
||||||
if (stations.length === 1) {
|
exportRecordDiagCsv(recordDiags, nvrClusterRecord.value[stationCode]?.stationName ?? '');
|
||||||
const name = stations.at(0)?.name;
|
|
||||||
if (!!name) {
|
|
||||||
stationName = `${name}_`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
downloadByData(data, `${stationName}录像缺失记录_${time}.xlsx`);
|
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (isCancel(error)) return;
|
if (isCancel(error)) return;
|
||||||
@@ -87,7 +73,6 @@ const { mutate: batchExportRecordCheck, isPending: batchExporting } = useMutatio
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onAfterLeave = () => {
|
const onAfterLeave = () => {
|
||||||
abortController.value.abort();
|
|
||||||
emit('afterLeave');
|
emit('afterLeave');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -96,22 +81,17 @@ const onAfterLeave = () => {
|
|||||||
<NModal v-model:show="show" preset="card" title="导出录像诊断" @after-leave="onAfterLeave" style="width: 800px">
|
<NModal v-model:show="show" preset="card" title="导出录像诊断" @after-leave="onAfterLeave" style="width: 800px">
|
||||||
<template #default>
|
<template #default>
|
||||||
<NScrollbar style="height: 300px">
|
<NScrollbar style="height: 300px">
|
||||||
<NSpin size="small" :show="batchExporting">
|
<NSpin size="small" :show="exporting">
|
||||||
<NGrid :cols="6">
|
<NGrid :cols="6">
|
||||||
<template v-for="station in stations" :key="station.code">
|
<template v-for="({ stationName, clusters }, code) in nvrClusterRecord" :key="code">
|
||||||
<NGridItem>
|
<NGridItem>
|
||||||
<NButton text type="info" style="height: 30px" @click="() => batchExportRecordCheck({ stations: [station] })">{{ station.name }}</NButton>
|
<NButton text type="info" style="height: 30px" @click="() => exportRecordDiags({ clusters, stationCode: code })">{{ stationName }}</NButton>
|
||||||
</NGridItem>
|
</NGridItem>
|
||||||
</template>
|
</template>
|
||||||
</NGrid>
|
</NGrid>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</NScrollbar>
|
</NScrollbar>
|
||||||
</template>
|
</template>
|
||||||
<template #action>
|
|
||||||
<NFlex justify="flex-end" align="center">
|
|
||||||
<NButton secondary :loading="batchExporting" @click="() => batchExportRecordCheck({ stations })">导出全部</NButton>
|
|
||||||
</NFlex>
|
|
||||||
</template>
|
|
||||||
</NModal>
|
</NModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Station, StationAlarms, StationDevices } from '@/apis';
|
import type { Station, StationAlarms, StationDevices } from '@/apis';
|
||||||
import { usePermission } from '@/composables';
|
import { DEVICE_TYPE_LITERALS } from '@/enums';
|
||||||
import { DEVICE_TYPE_LITERALS, PERMISSION_TYPE_LITERALS } from '@/enums';
|
import { EllipsisOutlined, MoreOutlined } from '@vicons/antd';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { isFunction } from 'es-toolkit';
|
import { isFunction } from 'es-toolkit';
|
||||||
import { MoreHorizontalIcon, MoreVerticalIcon } from 'lucide-vue-next';
|
|
||||||
import { NButton, NCard, NCheckbox, NDropdown, NFlex, NIcon, NTag, NTooltip, useThemeVars, type DropdownOption } from 'naive-ui';
|
import { NButton, NCard, NCheckbox, NDropdown, NFlex, NIcon, NTag, NTooltip, useThemeVars, type DropdownOption } from 'naive-ui';
|
||||||
import { computed, toRefs } from 'vue';
|
import { computed, toRefs } from 'vue';
|
||||||
|
|
||||||
@@ -25,8 +24,6 @@ const emit = defineEmits<{
|
|||||||
clickConfig: [station: Station];
|
clickConfig: [station: Station];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { station, devices, alarms, selectable } = toRefs(props);
|
const { station, devices, alarms, selectable } = toRefs(props);
|
||||||
|
|
||||||
const onlineDeviceCount = computed(() => {
|
const onlineDeviceCount = computed(() => {
|
||||||
@@ -74,7 +71,7 @@ const openDeviceConfigModal = () => {
|
|||||||
emit('clickConfig', station.value);
|
emit('clickConfig', station.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const dropdownOptions = computed<DropdownOption[]>(() => [
|
const dropdownOptions: DropdownOption[] = [
|
||||||
{
|
{
|
||||||
label: '视频平台',
|
label: '视频平台',
|
||||||
key: 'video-platform',
|
key: 'video-platform',
|
||||||
@@ -83,10 +80,9 @@ const dropdownOptions = computed<DropdownOption[]>(() => [
|
|||||||
{
|
{
|
||||||
label: '设备配置',
|
label: '设备配置',
|
||||||
key: 'device-config',
|
key: 'device-config',
|
||||||
show: hasPermission(station.value.code, PERMISSION_TYPE_LITERALS.OPERATION),
|
|
||||||
onSelect: openDeviceConfigModal,
|
onSelect: openDeviceConfigModal,
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
|
|
||||||
const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
||||||
const onSelect = option['onSelect'];
|
const onSelect = option['onSelect'];
|
||||||
@@ -120,7 +116,7 @@ const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
|||||||
<NDropdown trigger="click" :options="dropdownOptions" @select="onSelectDropdownOption">
|
<NDropdown trigger="click" :options="dropdownOptions" @select="onSelectDropdownOption">
|
||||||
<NButton quaternary size="tiny" :focusable="false">
|
<NButton quaternary size="tiny" :focusable="false">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="MoreVerticalIcon" />
|
<NIcon :component="MoreOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</NDropdown>
|
</NDropdown>
|
||||||
@@ -133,7 +129,7 @@ const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
|||||||
<span>{{ deviceCount }} 台设备</span>
|
<span>{{ deviceCount }} 台设备</span>
|
||||||
<NButton quaternary size="tiny" :focusable="false" @click="() => emit('clickDetail', 'device', station)">
|
<NButton quaternary size="tiny" :focusable="false" @click="() => emit('clickDetail', 'device', station)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="MoreHorizontalIcon" />
|
<NIcon :component="EllipsisOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
@@ -147,7 +143,7 @@ const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
|||||||
<!-- 占位按钮,对齐布局 -->
|
<!-- 占位按钮,对齐布局 -->
|
||||||
<NButton quaternary size="tiny" :focusable="false" style="visibility: hidden">
|
<NButton quaternary size="tiny" :focusable="false" style="visibility: hidden">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="MoreHorizontalIcon" />
|
<NIcon :component="EllipsisOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
@@ -157,7 +153,7 @@ const onSelectDropdownOption = (key: string, option: DropdownOption) => {
|
|||||||
<span :style="{ color: alarmCount > 0 ? themeVars.warningColor : '' }">今日 {{ alarmCount }} 条告警</span>
|
<span :style="{ color: alarmCount > 0 ? themeVars.warningColor : '' }">今日 {{ alarmCount }} 条告警</span>
|
||||||
<NButton quaternary size="tiny" :focusable="false" @click="() => emit('clickDetail', 'alarm', station)">
|
<NButton quaternary size="tiny" :focusable="false" @click="() => emit('clickDetail', 'alarm', station)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon :component="MoreHorizontalIcon" />
|
<NIcon :component="EllipsisOutlined" />
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Station, SyncCameraResult } from '@/apis';
|
|
||||||
import { usePermissionStore } from '@/stores';
|
|
||||||
import { watchDebounced } from '@vueuse/core';
|
import { watchDebounced } from '@vueuse/core';
|
||||||
import { EditIcon, PlusCircleIcon, Trash2Icon } from 'lucide-vue-next';
|
|
||||||
import { NFlex, NIcon, NList, NListItem, NModal, NScrollbar, NStatistic, NText, NThing } from 'naive-ui';
|
import { NFlex, NIcon, NList, NListItem, NModal, NScrollbar, NStatistic, NText, NThing } from 'naive-ui';
|
||||||
import { computed, ref, toRefs } from 'vue';
|
import { computed, ref, toRefs } from 'vue';
|
||||||
|
import { useStationStore } from '@/stores';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import type { Station, SyncCameraResult } from '@/apis';
|
||||||
|
import { DeleteFilled, EditFilled, PlusCircleFilled } from '@vicons/antd';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
syncCameraResult: Record<Station['code'], SyncCameraResult>;
|
syncCameraResult: Record<Station['code'], SyncCameraResult>;
|
||||||
@@ -14,8 +15,8 @@ const emit = defineEmits<{
|
|||||||
afterLeave: [];
|
afterLeave: [];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const permissionStore = usePermissionStore();
|
const stationStore = useStationStore();
|
||||||
const stations = computed(() => permissionStore.stations.VIEW ?? []);
|
const { stations } = storeToRefs(stationStore);
|
||||||
|
|
||||||
const { syncCameraResult } = toRefs(props);
|
const { syncCameraResult } = toRefs(props);
|
||||||
|
|
||||||
@@ -60,19 +61,19 @@ const syncList = computed(() => {
|
|||||||
<NFlex justify="space-around" :size="24" style="margin-top: 8px">
|
<NFlex justify="space-around" :size="24" style="margin-top: 8px">
|
||||||
<NStatistic label="新增">
|
<NStatistic label="新增">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<NIcon :component="PlusCircleIcon" />
|
<NIcon :component="PlusCircleFilled" />
|
||||||
</template>
|
</template>
|
||||||
{{ insertList.length }}
|
{{ insertList.length }}
|
||||||
</NStatistic>
|
</NStatistic>
|
||||||
<NStatistic label="更新">
|
<NStatistic label="更新">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<NIcon :component="EditIcon" />
|
<NIcon :component="EditFilled" />
|
||||||
</template>
|
</template>
|
||||||
{{ updateList.length }}
|
{{ updateList.length }}
|
||||||
</NStatistic>
|
</NStatistic>
|
||||||
<NStatistic label="删除">
|
<NStatistic label="删除">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<NIcon :component="Trash2Icon" />
|
<NIcon :component="DeleteFilled" />
|
||||||
</template>
|
</template>
|
||||||
{{ deleteList.length }}
|
{{ deleteList.length }}
|
||||||
</NStatistic>
|
</NStatistic>
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import { usePermission } from '../permission';
|
|
||||||
import { deleteCameraIgnoreApi, pageCameraIgnoreApi, saveCameraIgnoreApi, updateDeviceAlarmLogApi, type NdmDeviceAlarmLogResultVO } from '@/apis';
|
import { deleteCameraIgnoreApi, pageCameraIgnoreApi, saveCameraIgnoreApi, updateDeviceAlarmLogApi, type NdmDeviceAlarmLogResultVO } from '@/apis';
|
||||||
import { DEVICE_TYPE_LITERALS, PERMISSION_TYPE_LITERALS, tryGetDeviceType } from '@/enums';
|
import { DEVICE_TYPE_LITERALS, tryGetDeviceType } from '@/enums';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
import { NButton, NFlex, NPopconfirm, type DataTableColumn, type DataTableRowData } from 'naive-ui';
|
import { NButton, NFlex, NPopconfirm, type DataTableColumn, type DataTableRowData } from 'naive-ui';
|
||||||
import { h, type Ref } from 'vue';
|
import { h, type Ref } from 'vue';
|
||||||
|
|
||||||
export const useAlarmActionColumn = (tableData: Ref<DataTableRowData[]>) => {
|
export const useAlarmActionColumn = (tableData: Ref<DataTableRowData[]>) => {
|
||||||
const { hasPermission } = usePermission();
|
|
||||||
|
|
||||||
const { mutate: confirmAlarm } = useMutation({
|
const { mutate: confirmAlarm } = useMutation({
|
||||||
mutationFn: async (params: { id: string | null }) => {
|
mutationFn: async (params: { id: string | null }) => {
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
@@ -118,30 +115,28 @@ export const useAlarmActionColumn = (tableData: Ref<DataTableRowData[]>) => {
|
|||||||
default: () => '确认告警?',
|
default: () => '确认告警?',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
tryGetDeviceType(rowData.deviceType) === DEVICE_TYPE_LITERALS.ndmCamera &&
|
tryGetDeviceType(rowData.deviceType) === DEVICE_TYPE_LITERALS.ndmCamera && [
|
||||||
rowData.stationCode &&
|
h(
|
||||||
hasPermission(rowData.stationCode, PERMISSION_TYPE_LITERALS.OPERATION) && [
|
NPopconfirm,
|
||||||
h(
|
{
|
||||||
NPopconfirm,
|
onPositiveClick: () => ignoreCamera({ id }),
|
||||||
{
|
},
|
||||||
onPositiveClick: () => ignoreCamera({ id }),
|
{
|
||||||
},
|
trigger: () => h(NButton, { tertiary: true, type: 'info', size: 'tiny' }, { default: () => '忽略' }),
|
||||||
{
|
default: () => '忽略设备?',
|
||||||
trigger: () => h(NButton, { tertiary: true, type: 'info', size: 'tiny' }, { default: () => '忽略' }),
|
},
|
||||||
default: () => '忽略设备?',
|
),
|
||||||
},
|
// h(
|
||||||
),
|
// NPopconfirm,
|
||||||
// h(
|
// {
|
||||||
// NPopconfirm,
|
// onPositiveClick: () => noticeCamera({ id }),
|
||||||
// {
|
// },
|
||||||
// onPositiveClick: () => noticeCamera({ id }),
|
// {
|
||||||
// },
|
// trigger: () => h(NButton, { text: true, type: 'info', size: 'small' }, { icon: () => h(EyeOutlined) }),
|
||||||
// {
|
// default: () => '取消忽略设备?',
|
||||||
// trigger: () => h(NButton, { text: true, type: 'info', size: 'small' }, { icon: () => h(EyeOutlined) }),
|
// },
|
||||||
// default: () => '取消忽略设备?',
|
// ),
|
||||||
// },
|
],
|
||||||
// ),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { detailDeviceAlarmSnapLogApi, type NdmDeviceAlarmLogResultVO } from '@/apis';
|
import { getCameraSnapApi, type NdmDeviceAlarmLogResultVO } from '@/apis';
|
||||||
import { tryGetDeviceType, DEVICE_TYPE_LITERALS } from '@/enums';
|
import { tryGetDeviceType, DEVICE_TYPE_LITERALS } from '@/enums';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { useMutation } from '@tanstack/vue-query';
|
import { useMutation } from '@tanstack/vue-query';
|
||||||
@@ -7,9 +7,11 @@ import { h, ref, watch, type Ref } from 'vue';
|
|||||||
|
|
||||||
export const useCameraSnapColumn = (tableData: Ref<DataTableRowData[]>) => {
|
export const useCameraSnapColumn = (tableData: Ref<DataTableRowData[]>) => {
|
||||||
const { mutateAsync: getSnapByDeviceId } = useMutation({
|
const { mutateAsync: getSnapByDeviceId } = useMutation({
|
||||||
mutationFn: async (params: { id: string }) => {
|
mutationFn: async (params: { deviceAlarmLog: NdmDeviceAlarmLogResultVO }) => {
|
||||||
const { id } = params;
|
const { deviceAlarmLog } = params;
|
||||||
const snap = await detailDeviceAlarmSnapLogApi(id);
|
const { deviceId } = deviceAlarmLog;
|
||||||
|
if (!deviceId) throw new Error('设备ID不能为空');
|
||||||
|
const snap = await getCameraSnapApi(deviceId);
|
||||||
return snap;
|
return snap;
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
@@ -26,15 +28,15 @@ export const useCameraSnapColumn = (tableData: Ref<DataTableRowData[]>) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const cameraSnapColumn: DataTableColumn<NdmDeviceAlarmLogResultVO & { snapUrl?: string }> = {
|
const cameraSnapColumn: DataTableColumn<NdmDeviceAlarmLogResultVO & { snapUrl?: string }> = {
|
||||||
title: '告警画面截图',
|
title: '实时画面截图',
|
||||||
key: 'snapUrl',
|
key: 'snapUrl',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (rowData) => {
|
render: (rowData) => {
|
||||||
const { id, deviceType: deviceTypeCode, snapUrl } = rowData;
|
const { deviceType: deviceTypeCode, snapUrl } = rowData;
|
||||||
if (!id) return null;
|
|
||||||
const deviceType = tryGetDeviceType(deviceTypeCode);
|
const deviceType = tryGetDeviceType(deviceTypeCode);
|
||||||
if (deviceType !== DEVICE_TYPE_LITERALS.ndmCamera) return null;
|
if (deviceType !== DEVICE_TYPE_LITERALS.ndmCamera) return null;
|
||||||
if (!snapUrl) {
|
if (!snapUrl) {
|
||||||
|
const id = rowData.id ?? '';
|
||||||
return h(
|
return h(
|
||||||
NButton,
|
NButton,
|
||||||
{
|
{
|
||||||
@@ -44,9 +46,8 @@ export const useCameraSnapColumn = (tableData: Ref<DataTableRowData[]>) => {
|
|||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
loadingMap.value[id] = true;
|
loadingMap.value[id] = true;
|
||||||
try {
|
try {
|
||||||
const snap = await getSnapByDeviceId({ id });
|
const snap = await getSnapByDeviceId({ deviceAlarmLog: rowData });
|
||||||
if (!snap.url) return;
|
rowData.snapUrl = snap.data.url;
|
||||||
rowData.snapUrl = snap.url;
|
|
||||||
} finally {
|
} finally {
|
||||||
loadingMap.value[id] = false;
|
loadingMap.value[id] = false;
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,6 @@ export const useCameraSnapColumn = (tableData: Ref<DataTableRowData[]>) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cameraSnapColumn,
|
cameraSnapColumn,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,33 +1,39 @@
|
|||||||
import type { LineDevices, NdmDeviceResultVO, Station } from '@/apis';
|
import type { LineDevices, NdmDeviceResultVO, Station } from '@/apis';
|
||||||
import { tryGetDeviceType, type DeviceType } from '@/enums';
|
import { tryGetDeviceType, type DeviceType } from '@/enums';
|
||||||
import { ref } from 'vue';
|
import { useDeviceStore } from '@/stores';
|
||||||
|
import { watchDebounced } from '@vueuse/core';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { onMounted, ref, toValue, watch, type MaybeRefOrGetter } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
export const useDeviceSelection = () => {
|
export const useDeviceSelection = (options?: { syncRoute?: MaybeRefOrGetter<boolean> }) => {
|
||||||
|
const { syncRoute } = options ?? {};
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const deviceStore = useDeviceStore();
|
||||||
|
const { lineDevices } = storeToRefs(deviceStore);
|
||||||
|
|
||||||
const selectedStationCode = ref<Station['code']>();
|
const selectedStationCode = ref<Station['code']>();
|
||||||
const selectedDeviceType = ref<DeviceType>();
|
const selectedDeviceType = ref<DeviceType>();
|
||||||
const selectedDevice = ref<NdmDeviceResultVO>();
|
const selectedDevice = ref<NdmDeviceResultVO>();
|
||||||
|
|
||||||
// 从路由参数同步选中的车站、设备类型以及设备
|
const initFromRoute = (lineDevices: LineDevices) => {
|
||||||
const syncFromRoute = (lineDevices: LineDevices) => {
|
const { stationCode, deviceType, deviceDbId } = route.query;
|
||||||
// console.log('sync from route');
|
if (stationCode) {
|
||||||
const { stationCode: routeStationCode, deviceType: routeDeviceType, deviceDbId: routeDeviceDbId } = route.query;
|
selectedStationCode.value = stationCode as Station['code'];
|
||||||
if (routeStationCode) {
|
|
||||||
selectedStationCode.value = routeStationCode as Station['code'];
|
|
||||||
}
|
}
|
||||||
if (routeDeviceType) {
|
if (deviceType) {
|
||||||
selectedDeviceType.value = routeDeviceType as DeviceType;
|
selectedDeviceType.value = deviceType as DeviceType;
|
||||||
}
|
}
|
||||||
if (routeDeviceDbId && selectedStationCode.value && selectedDeviceType.value) {
|
if (deviceDbId && selectedStationCode.value && selectedDeviceType.value) {
|
||||||
const selectedDeviceDbId = routeDeviceDbId as string;
|
const selectedDeviceDbId = deviceDbId as string;
|
||||||
const stationDevices = lineDevices[selectedStationCode.value];
|
const stationDevices = lineDevices[selectedStationCode.value];
|
||||||
if (stationDevices) {
|
if (stationDevices) {
|
||||||
const classifiedDevices = stationDevices[selectedDeviceType.value];
|
const devices = stationDevices[selectedDeviceType.value];
|
||||||
if (classifiedDevices) {
|
if (devices) {
|
||||||
const device = classifiedDevices.find((device) => device.id === selectedDeviceDbId);
|
const device = devices.find((device) => device.id === selectedDeviceDbId);
|
||||||
if (device) {
|
if (device) {
|
||||||
selectedDevice.value = device;
|
selectedDevice.value = device;
|
||||||
}
|
}
|
||||||
@@ -45,9 +51,7 @@ export const useDeviceSelection = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 将选中的车站、设备类型以及设备ID同步到路由参数
|
|
||||||
const syncToRoute = () => {
|
const syncToRoute = () => {
|
||||||
// console.log('sync to route');
|
|
||||||
const query = { ...route.query };
|
const query = { ...route.query };
|
||||||
// 当选中的设备发生变化时,删除fromPage参数
|
// 当选中的设备发生变化时,删除fromPage参数
|
||||||
if (selectedDevice.value?.id && route.query.deviceDbId !== selectedDevice.value.id) {
|
if (selectedDevice.value?.id && route.query.deviceDbId !== selectedDevice.value.id) {
|
||||||
@@ -65,13 +69,39 @@ export const useDeviceSelection = () => {
|
|||||||
router.replace({ query });
|
router.replace({ query });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(selectedDevice, () => {
|
||||||
|
if (toValue(syncRoute)) {
|
||||||
|
syncToRoute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// lineDevices是shallowRef,因此需要深度侦听才能获取内部变化,
|
||||||
|
// 而单纯的深度侦听又可能会引发性能问题,因此尝试使用防抖侦听
|
||||||
|
watchDebounced(
|
||||||
|
lineDevices,
|
||||||
|
(newLineDevices) => {
|
||||||
|
if (toValue(syncRoute)) {
|
||||||
|
initFromRoute(newLineDevices);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
debounce: 500,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (toValue(syncRoute)) {
|
||||||
|
initFromRoute(lineDevices.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedStationCode,
|
selectedStationCode,
|
||||||
selectedDeviceType,
|
selectedDeviceType,
|
||||||
selectedDevice,
|
selectedDevice,
|
||||||
|
|
||||||
syncFromRoute,
|
initFromRoute,
|
||||||
syncToRoute,
|
|
||||||
selectDevice,
|
selectDevice,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
import type { MaybeRefOrGetter } from 'vue';
|
||||||
import { useDeviceManagement } from './use-device-management';
|
import { useDeviceManagement } from './use-device-management';
|
||||||
import { useDeviceSelection } from './use-device-selection';
|
import { useDeviceSelection } from './use-device-selection';
|
||||||
|
|
||||||
export const useDeviceTree = () => {
|
export const useDeviceTree = (options?: { syncRoute?: MaybeRefOrGetter<boolean> }) => {
|
||||||
const deviceSelection = useDeviceSelection();
|
const { syncRoute } = options ?? {};
|
||||||
|
|
||||||
|
const deviceSelection = useDeviceSelection({ syncRoute });
|
||||||
const deviceManagement = useDeviceManagement();
|
const deviceManagement = useDeviceManagement();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
export * from './alarm';
|
export * from './alarm';
|
||||||
export * from './device';
|
export * from './device';
|
||||||
export * from './permission';
|
|
||||||
export * from './query';
|
export * from './query';
|
||||||
export * from './station';
|
|
||||||
export * from './stomp';
|
export * from './stomp';
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from './use-permission';
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import type { PermissionType } from '@/enums';
|
|
||||||
import { usePermissionStore } from '@/stores';
|
|
||||||
|
|
||||||
export const usePermission = () => {
|
|
||||||
const permissionStore = usePermissionStore();
|
|
||||||
|
|
||||||
const hasPermission = (stationCode: string, permissionType: PermissionType) => {
|
|
||||||
return !!permissionStore.permissions[stationCode]?.includes(permissionType);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
hasPermission,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
export * from './use-line-alarms-query';
|
export * from './use-line-alarms-query';
|
||||||
export * from './use-line-devices-query';
|
export * from './use-line-devices-query';
|
||||||
export * from './use-line-stations-query';
|
export * from './use-line-stations-query';
|
||||||
export * from './use-user-permission-query';
|
|
||||||
export * from './use-verify-user-query';
|
export * from './use-verify-user-query';
|
||||||
export * from './use-version-check-query';
|
export * from './use-version-check-query';
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { initStationAlarms, pageDeviceAlarmLogApi, type Station } from '@/apis';
|
import { initStationAlarms, pageDeviceAlarmLogApi, type Station } from '@/apis';
|
||||||
import { LINE_ALARMS_QUERY_KEY, STATION_ALARMS_MUTATION_KEY } from '@/constants';
|
import { LINE_ALARMS_QUERY_KEY, STATION_ALARMS_MUTATION_KEY } from '@/constants';
|
||||||
import { tryGetDeviceType } from '@/enums';
|
import { tryGetDeviceType } from '@/enums';
|
||||||
import { useAlarmStore, usePermissionStore } from '@/stores';
|
import { useAlarmStore, useStationStore } from '@/stores';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { CancelledError, useMutation, useQuery } from '@tanstack/vue-query';
|
import { CancelledError, useMutation, useQuery } from '@tanstack/vue-query';
|
||||||
import { isCancel } from 'axios';
|
import { isCancel } from 'axios';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
export const useStationAlarmsMutation = () => {
|
export const useStationAlarmsMutation = () => {
|
||||||
@@ -55,8 +56,8 @@ export const useStationAlarmsMutation = () => {
|
|||||||
alarmStore.setStationAlarms(station.code, stationAlarms);
|
alarmStore.setStationAlarms(station.code, stationAlarms);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (isCancel(error) || error instanceof CancelledError) return;
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
if (isCancel(error) || error instanceof CancelledError) return;
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
const errorFeedback = parseErrorFeedback(error);
|
||||||
window.$message.error(errorFeedback);
|
window.$message.error(errorFeedback);
|
||||||
},
|
},
|
||||||
@@ -68,22 +69,19 @@ export const useStationAlarmsMutation = () => {
|
|||||||
* @see [use-line-stations-query.ts](./use-line-stations-query.ts)
|
* @see [use-line-stations-query.ts](./use-line-stations-query.ts)
|
||||||
*/
|
*/
|
||||||
export const useLineAlarmsQuery = () => {
|
export const useLineAlarmsQuery = () => {
|
||||||
const permissionStore = usePermissionStore();
|
const stationStore = useStationStore();
|
||||||
const stations = computed(() => permissionStore.stations.VIEW ?? []);
|
const { stations } = storeToRefs(stationStore);
|
||||||
|
|
||||||
const { mutateAsync: getStationAlarms } = useStationAlarmsMutation();
|
const { mutateAsync: getStationAlarms } = useStationAlarmsMutation();
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: computed(() => [LINE_ALARMS_QUERY_KEY]),
|
queryKey: computed(() => [LINE_ALARMS_QUERY_KEY]),
|
||||||
enabled: false,
|
enabled: false,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
const startTime = performance.now();
|
console.time(LINE_ALARMS_QUERY_KEY);
|
||||||
for (const station of stations.value) {
|
for (const station of stations.value) {
|
||||||
await getStationAlarms({ station, signal }).catch(() => {});
|
await getStationAlarms({ station, signal }).catch(() => {});
|
||||||
}
|
}
|
||||||
const endTime = performance.now();
|
console.timeEnd(LINE_ALARMS_QUERY_KEY);
|
||||||
console.log(`${LINE_ALARMS_QUERY_KEY}: ${endTime - startTime} ms`);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { getAllDevicesApi, initStationDevices, type Station } from '@/apis';
|
import { getAllDevicesApi, initStationDevices, type Station } from '@/apis';
|
||||||
import { LINE_DEVICES_QUERY_KEY, STATION_DEVICES_MUTATION_KEY } from '@/constants';
|
import { LINE_DEVICES_QUERY_KEY, STATION_DEVICES_MUTATION_KEY } from '@/constants';
|
||||||
import { useDeviceStore, usePermissionStore } from '@/stores';
|
import { useDeviceStore, useStationStore } from '@/stores';
|
||||||
import { parseErrorFeedback } from '@/utils';
|
import { parseErrorFeedback } from '@/utils';
|
||||||
import { CancelledError, useMutation, useQuery } from '@tanstack/vue-query';
|
import { CancelledError, useMutation, useQuery } from '@tanstack/vue-query';
|
||||||
import { isCancel } from 'axios';
|
import { isCancel } from 'axios';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
export const useStationDevicesMutation = () => {
|
export const useStationDevicesMutation = () => {
|
||||||
@@ -22,8 +23,8 @@ export const useStationDevicesMutation = () => {
|
|||||||
deviceStore.setStationDevices(station.code, devices);
|
deviceStore.setStationDevices(station.code, devices);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (isCancel(error) || error instanceof CancelledError) return;
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
if (isCancel(error) || error instanceof CancelledError) return;
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
const errorFeedback = parseErrorFeedback(error);
|
||||||
window.$message.error(errorFeedback);
|
window.$message.error(errorFeedback);
|
||||||
},
|
},
|
||||||
@@ -35,22 +36,19 @@ export const useStationDevicesMutation = () => {
|
|||||||
* @see [use-line-stations-query.ts](./use-line-stations-query.ts)
|
* @see [use-line-stations-query.ts](./use-line-stations-query.ts)
|
||||||
*/
|
*/
|
||||||
export const useLineDevicesQuery = () => {
|
export const useLineDevicesQuery = () => {
|
||||||
const permissionStore = usePermissionStore();
|
const stationStore = useStationStore();
|
||||||
const stations = computed(() => permissionStore.stations.VIEW ?? []);
|
const { stations } = storeToRefs(stationStore);
|
||||||
|
|
||||||
const { mutateAsync: getStationDevices } = useStationDevicesMutation();
|
const { mutateAsync: getStationDevices } = useStationDevicesMutation();
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: computed(() => [LINE_DEVICES_QUERY_KEY]),
|
queryKey: computed(() => [LINE_DEVICES_QUERY_KEY]),
|
||||||
enabled: false,
|
enabled: false,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
const startTime = performance.now();
|
console.time(LINE_DEVICES_QUERY_KEY);
|
||||||
for (const station of stations.value) {
|
for (const station of stations.value) {
|
||||||
await getStationDevices({ station, signal }).catch(() => {});
|
await getStationDevices({ station, signal }).catch(() => {});
|
||||||
}
|
}
|
||||||
const endTime = performance.now();
|
console.timeEnd(LINE_DEVICES_QUERY_KEY);
|
||||||
console.log(`${LINE_DEVICES_QUERY_KEY}: ${endTime - startTime} ms`);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { batchVerifyApi, type Station } from '@/apis';
|
import { batchVerifyApi, type Station } from '@/apis';
|
||||||
import { LINE_STATIONS_MUTATION_KEY, LINE_STATIONS_QUERY_KEY } from '@/constants';
|
import { LINE_STATIONS_MUTATION_KEY, LINE_STATIONS_QUERY_KEY } from '@/constants';
|
||||||
import { useSettingStore, useStationStore } from '@/stores';
|
import { usePollingStore, useStationStore } from '@/stores';
|
||||||
import { getAppEnvConfig, parseErrorFeedback } from '@/utils';
|
import { getAppEnvConfig, parseErrorFeedback } from '@/utils';
|
||||||
import { CancelledError, useMutation, useQuery } from '@tanstack/vue-query';
|
import { CancelledError, useMutation, useQuery } from '@tanstack/vue-query';
|
||||||
import axios, { isCancel } from 'axios';
|
import axios, { isCancel } from 'axios';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
import { useLineDevicesQuery } from './use-line-devices-query';
|
||||||
|
import { useLineAlarmsQuery } from './use-line-alarms-query';
|
||||||
|
|
||||||
export const useLineStationsMutation = () => {
|
export const useLineStationsMutation = () => {
|
||||||
const stationStore = useStationStore();
|
const stationStore = useStationStore();
|
||||||
@@ -15,13 +17,12 @@ export const useLineStationsMutation = () => {
|
|||||||
mutationKey: [LINE_STATIONS_MUTATION_KEY],
|
mutationKey: [LINE_STATIONS_MUTATION_KEY],
|
||||||
mutationFn: async (params: { signal?: AbortSignal }) => {
|
mutationFn: async (params: { signal?: AbortSignal }) => {
|
||||||
const { signal } = params;
|
const { signal } = params;
|
||||||
const { data: ndmStationList } = await axios.get<Omit<Station, 'online' | 'ip'>[]>(`/minio/ndm/ndm-stations.json?_t=${dayjs().unix()}`, { signal });
|
const { data: ndmStationList } = await axios.get<{ code: string; name: string }[]>(`/minio/ndm/ndm-stations.json?_t=${dayjs().unix()}`, { signal });
|
||||||
const stations = ndmStationList.map<Station>((station) => ({
|
const stations = ndmStationList.map<Station>((station) => ({
|
||||||
code: station.code ?? '',
|
code: station.code ?? '',
|
||||||
name: station.name ?? '',
|
name: station.name ?? '',
|
||||||
online: false,
|
online: false,
|
||||||
ip: '',
|
ip: '',
|
||||||
occ: station.occ,
|
|
||||||
}));
|
}));
|
||||||
const verifyList = await batchVerifyApi({ signal });
|
const verifyList = await batchVerifyApi({ signal });
|
||||||
return stations.map((station) => ({
|
return stations.map((station) => ({
|
||||||
@@ -34,8 +35,8 @@ export const useLineStationsMutation = () => {
|
|||||||
stationStore.setStations(stations);
|
stationStore.setStations(stations);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (isCancel(error) || error instanceof CancelledError) return;
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
if (isCancel(error) || error instanceof CancelledError) return;
|
||||||
const errorFeedback = parseErrorFeedback(error);
|
const errorFeedback = parseErrorFeedback(error);
|
||||||
window.$message.error(errorFeedback);
|
window.$message.error(errorFeedback);
|
||||||
},
|
},
|
||||||
@@ -43,21 +44,28 @@ export const useLineStationsMutation = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useLineStationsQuery = () => {
|
export const useLineStationsQuery = () => {
|
||||||
const settingStore = useSettingStore();
|
const pollingStore = usePollingStore();
|
||||||
const { pollingStations } = storeToRefs(settingStore);
|
const { pollingEnabled } = storeToRefs(pollingStore);
|
||||||
const { requestInterval } = getAppEnvConfig();
|
const { requestInterval } = getAppEnvConfig();
|
||||||
const { mutateAsync: getLineStations } = useLineStationsMutation();
|
const { mutateAsync: getLineStations } = useLineStationsMutation();
|
||||||
|
const { refetch: refetchLineDevicesQuery } = useLineDevicesQuery();
|
||||||
|
const { refetch: refetchLineAlarmsQuery } = useLineAlarmsQuery();
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: computed(() => [LINE_STATIONS_QUERY_KEY]),
|
queryKey: computed(() => [LINE_STATIONS_QUERY_KEY]),
|
||||||
enabled: computed(() => pollingStations.value),
|
enabled: computed(() => pollingEnabled.value),
|
||||||
refetchInterval: requestInterval * 1000,
|
refetchInterval: requestInterval * 1000,
|
||||||
staleTime: (requestInterval * 1000) / 2,
|
staleTime: (requestInterval * 1000) / 2,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
const startTime = performance.now();
|
console.time(LINE_STATIONS_QUERY_KEY);
|
||||||
await getLineStations({ signal }).catch(() => {});
|
await getLineStations({ signal }).catch(() => {});
|
||||||
const endTime = performance.now();
|
console.timeEnd(LINE_STATIONS_QUERY_KEY);
|
||||||
console.log(`${LINE_STATIONS_QUERY_KEY}: ${endTime - startTime} ms`);
|
|
||||||
|
if (!pollingEnabled.value) return null;
|
||||||
|
await refetchLineDevicesQuery();
|
||||||
|
|
||||||
|
if (!pollingEnabled.value) return null;
|
||||||
|
await refetchLineAlarmsQuery();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
import { useLineDevicesQuery } from './use-line-devices-query';
|
|
||||||
import { useLineAlarmsQuery } from './use-line-alarms-query';
|
|
||||||
import { pagePermissionApi } from '@/apis';
|
|
||||||
import { USER_PERMISSION_QUERY_KEY } from '@/constants';
|
|
||||||
import { PERMISSION_TYPE_LITERALS } from '@/enums';
|
|
||||||
import { usePermissionStore, useSettingStore, useStationStore, useUserStore } from '@/stores';
|
|
||||||
import { useQuery } from '@tanstack/vue-query';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { computed, watch } from 'vue';
|
|
||||||
import { useLineStationsQuery } from './use-line-stations-query';
|
|
||||||
|
|
||||||
export const useUserPermissionQuery = () => {
|
|
||||||
const settingStore = useSettingStore();
|
|
||||||
const { pollingStations, activeRequests } = storeToRefs(settingStore);
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const { userInfo } = storeToRefs(userStore);
|
|
||||||
|
|
||||||
const stationStore = useStationStore();
|
|
||||||
const { stations } = storeToRefs(stationStore);
|
|
||||||
|
|
||||||
const permissionStore = usePermissionStore();
|
|
||||||
const { permissions } = storeToRefs(permissionStore);
|
|
||||||
|
|
||||||
const { dataUpdatedAt: stationsUpdatedTime } = useLineStationsQuery();
|
|
||||||
const { refetch: refetchLineDevicesQuery } = useLineDevicesQuery();
|
|
||||||
const { refetch: refetchLineAlarmsQuery } = useLineAlarmsQuery();
|
|
||||||
|
|
||||||
watch([permissions, stationsUpdatedTime], async ([newPermissions, newUpdatedTime], [oldPermissions, oldUpdatedTime]) => {
|
|
||||||
const newPermissionsJson = JSON.stringify(newPermissions);
|
|
||||||
const oldPermissionsJson = JSON.stringify(oldPermissions);
|
|
||||||
if (newPermissionsJson === oldPermissionsJson && newUpdatedTime === oldUpdatedTime) return;
|
|
||||||
// 设备查询和告警查询依赖pollingEnabdled
|
|
||||||
// 当关闭轮询时,只会取消当前正在执行的查询,
|
|
||||||
// 所以如果在关闭轮询时refetch还未执行,那么这一次取消就是无效的,refetch依然会执行,
|
|
||||||
// 所以在每个refetch被调用前都需要检查pollingEnabled,否则就可能会取消失败
|
|
||||||
if (!pollingStations.value) return;
|
|
||||||
await refetchLineDevicesQuery();
|
|
||||||
if (!pollingStations.value) return;
|
|
||||||
await refetchLineAlarmsQuery();
|
|
||||||
});
|
|
||||||
|
|
||||||
return useQuery({
|
|
||||||
queryKey: computed(() => [USER_PERMISSION_QUERY_KEY]),
|
|
||||||
// 启用【车站轮询】或【主动请求】时,都认为查询被启用
|
|
||||||
enabled: computed(() => (pollingStations.value || activeRequests.value) && userInfo.value?.['employeeId'] && stations.value.length > 0),
|
|
||||||
// 当启用【车站轮询】时,刷新间隔为10秒,缓存时间为5秒
|
|
||||||
refetchInterval: computed(() => (pollingStations.value ? 10 * 1000 : undefined)),
|
|
||||||
staleTime: computed(() => (pollingStations.value ? 5 * 1000 : undefined)),
|
|
||||||
queryFn: async ({ signal }) => {
|
|
||||||
const { records } = await pagePermissionApi(
|
|
||||||
{
|
|
||||||
model: {
|
|
||||||
employeeId: userInfo.value['employeeId'],
|
|
||||||
},
|
|
||||||
current: 1,
|
|
||||||
size: Object.keys(PERMISSION_TYPE_LITERALS).length * stations.value.length,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
signal,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
permissionStore.setPermRecords(records);
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -8,17 +8,17 @@ import { computed, watch } from 'vue';
|
|||||||
export const useVerifyUserQuery = () => {
|
export const useVerifyUserQuery = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
const { activeRequests } = storeToRefs(settingStore);
|
const { offlineDev } = storeToRefs(settingStore);
|
||||||
|
|
||||||
watch(activeRequests, (active) => {
|
watch(offlineDev, (offline) => {
|
||||||
if (!active) {
|
if (offline) {
|
||||||
queryClient.cancelQueries({ queryKey: [VERIFY_USER_QUERY_KEY] });
|
queryClient.cancelQueries({ queryKey: [VERIFY_USER_QUERY_KEY] });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [VERIFY_USER_QUERY_KEY],
|
queryKey: [VERIFY_USER_QUERY_KEY],
|
||||||
enabled: computed(() => activeRequests.value),
|
enabled: computed(() => !offlineDev.value),
|
||||||
refetchInterval: 10 * 1000,
|
refetchInterval: 10 * 1000,
|
||||||
queryFn: async ({ signal }) => {
|
queryFn: async ({ signal }) => {
|
||||||
await verifyApi({ signal });
|
await verifyApi({ signal });
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from './use-batch-actions';
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user