Compare commits
53 Commits
cc6ea1acc6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a6a6198eaa | |||
| 9fbfe54f92 | |||
| fb9c5b9255 | |||
| 73247053dd | |||
| 695755546f | |||
| 43ce3433ce | |||
| 3e60e699ce | |||
| 5cbfb36fbf | |||
| 87ec4dff70 | |||
| 46559fe955 | |||
| c550369a4b | |||
| a9c2a499ce | |||
| 24dd0c17da | |||
| 913e9e63ad | |||
| 3abdc187fb | |||
| 809dc883f5 | |||
| 7c505f8169 | |||
| 3654ccb9db | |||
| 195aa7ccff | |||
| 7353c4eede | |||
| dbda9f76fb | |||
| c2c5afa82d | |||
| f5c7ebc59c | |||
| 98e1baf1bb | |||
| 51f938fbfc | |||
| e43ada5c7f | |||
| f2f4390ac2 | |||
| 52a0346c4c | |||
| 4b9a87638c | |||
| b4dba77229 | |||
| 7e61f330dc | |||
| 8c1772c784 | |||
| c9da54829d | |||
| db767de8bb | |||
| 9cbacf5998 | |||
| 947fa2f9b9 | |||
| e5df404aaa | |||
| 8a6ec3ef96 | |||
| 922f7dfc4b | |||
| ee101984f0 | |||
| 3f4d50b395 | |||
| 58365870ef | |||
| aa6db97457 | |||
| f5d0bae89b | |||
| 7a20329594 | |||
| 83b713890b | |||
| c3f38f5e2a | |||
| c6d0df6fd2 | |||
| 93e8f3349f | |||
| fc5d653433 | |||
| fafdb0d830 | |||
| 99a5f8bd16 | |||
| 9f1c3eb660 |
@@ -8,16 +8,17 @@ VITE_APP_TITLE=标准管理系统
|
||||
VITE_APP_DESCRIPTION="default standard template"
|
||||
VITE_USE_MOCK=false
|
||||
|
||||
# API 基础URL
|
||||
# VITE_API_BASE_URL=https://ops-api.apinb.com
|
||||
# 开发环境走 Vite 同源代理,避免依赖本机 80/443 nginx
|
||||
VITE_API_BASE_URL=
|
||||
# 开发环境通过 Vite 同源代理访问 API,避免浏览器跨域
|
||||
VITE_API_BASE_URL=/api
|
||||
VITE_API_PROXY_TARGET=https://ops-api.apinb.com
|
||||
|
||||
# 海康 WebSDK 开发代理(按实际摄像头/NVR 地址填写,不要提交账号密码)
|
||||
VITE_HIKVISION_PROXY_TARGET=http://192.168.1.101:80
|
||||
VITE_HIKVISION_WS_PROXY_TARGET=
|
||||
|
||||
# Logs 本地调试地址(仅 logs 模块使用)
|
||||
VITE_LOGS_API_BASE_URL=http://127.0.0.1:12440
|
||||
|
||||
|
||||
|
||||
# 应用版本
|
||||
VITE_APP_VERSION=1.0.0
|
||||
|
||||
|
||||
1123
3D机房前后端接口文档.md
Normal file
203
PAGES_README.md
@@ -1,203 +0,0 @@
|
||||
# 官网首页和帮助中心页面说明
|
||||
|
||||
## 新增页面
|
||||
|
||||
本次为系统添加了两个全新的对外页面,无需登录即可访问:
|
||||
|
||||
### 1. 官网首页 (`/home`)
|
||||
|
||||
**功能特点:**
|
||||
|
||||
- 🎨 现代化的渐变背景设计
|
||||
- 📱 响应式布局,适配各种设备
|
||||
- 🎯 清晰的功能特性展示区域
|
||||
- 📊 数据中心关键指标展示
|
||||
- 🔗 快速导航到登录系统和帮助中心
|
||||
- 💬 完整的页脚信息
|
||||
|
||||
**主要板块:**
|
||||
|
||||
1. **顶部导航栏** - 包含 Logo、导航链接和登录按钮
|
||||
2. **Banner 区域** - 醒目的标题和行动号召按钮
|
||||
3. **功能特性** - 6 个核心功能卡片展示
|
||||
4. **数据中心** - 关键运行指标统计
|
||||
5. **行动号召** - 引导用户登录或查看帮助
|
||||
6. **页脚** - 版权信息和快速链接
|
||||
|
||||
**访问方式:**
|
||||
|
||||
- 直接访问:`http://your-domain/#/home`
|
||||
- 根路径自动重定向到首页
|
||||
|
||||
### 2. 帮助中心页面 (`/help`)
|
||||
|
||||
**功能特点:**
|
||||
|
||||
- 🔍 文档搜索功能
|
||||
- 📑 左侧分类导航菜单
|
||||
- ❓ 常见问题 FAQ(折叠面板)
|
||||
- 📖 使用指南卡片
|
||||
- 📥 操作手册下载
|
||||
- 📞 联系方式展示
|
||||
|
||||
**主要内容:**
|
||||
|
||||
1. **常见问题** - 8 个典型问题的问答
|
||||
2. **使用指南** - 6 个分类的详细教程
|
||||
- 快速入门
|
||||
- 仪表盘
|
||||
- 告警管理
|
||||
- 数据中心
|
||||
- 报表分析
|
||||
- 系统设置
|
||||
3. **操作手册** - 可下载的文档资料
|
||||
4. **联系我们** - 电话、邮件、在线客服
|
||||
|
||||
**访问方式:**
|
||||
|
||||
- 直接访问:`http://your-domain/#/help`
|
||||
- 从首页导航点击"帮助中心"
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 文件结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── views/
|
||||
│ ├── home/ # 官网首页
|
||||
│ │ └── index.vue
|
||||
│ └── help/ # 帮助中心
|
||||
│ └── index.vue
|
||||
├── layout/
|
||||
│ └── standalone-layout.vue # 独立布局(无侧边栏)
|
||||
└── router/
|
||||
├── index.ts # 路由配置
|
||||
└── constants.ts # 路由常量(白名单)
|
||||
```
|
||||
|
||||
### 路由配置
|
||||
|
||||
```typescript
|
||||
// 根路径配置
|
||||
{
|
||||
path: '/',
|
||||
name: 'root',
|
||||
component: () => import('@/layout/standalone-layout.vue'),
|
||||
redirect: '/home',
|
||||
children: [
|
||||
{
|
||||
path: '/home',
|
||||
name: 'Home',
|
||||
component: () => import('@/views/home/index.vue'),
|
||||
meta: { requiresAuth: false }
|
||||
},
|
||||
{
|
||||
path: '/help',
|
||||
name: 'Help',
|
||||
component: () => import('@/views/help/index.vue'),
|
||||
meta: { requiresAuth: false }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 权限控制
|
||||
|
||||
- 两个页面都设置了 `requiresAuth: false`,无需登录即可访问
|
||||
- 已添加到路由白名单 `WHITE_LIST` 中
|
||||
- 使用独立的 `standalone-layout`,不显示系统的导航栏和侧边栏
|
||||
|
||||
## 自定义内容
|
||||
|
||||
### 修改公司信息
|
||||
|
||||
在两个页面的页脚部分,可以修改:
|
||||
|
||||
- 版权信息
|
||||
- 联系方式(电话、邮箱)
|
||||
- 公司地址
|
||||
|
||||
### 添加更多帮助文档
|
||||
|
||||
编辑 `help/index.vue` 中的数据:
|
||||
|
||||
```typescript
|
||||
// 添加 FAQ
|
||||
const faqs = ref([
|
||||
{
|
||||
question: '您的问题',
|
||||
answer: '您的答案',
|
||||
category: '分类',
|
||||
},
|
||||
])
|
||||
|
||||
// 添加使用指南
|
||||
const guides = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '指南标题',
|
||||
description: '描述',
|
||||
icon: '图标',
|
||||
category: '分类',
|
||||
categoryName: '分类名称',
|
||||
updatedAt: '更新日期',
|
||||
},
|
||||
])
|
||||
```
|
||||
|
||||
### 修改配色方案
|
||||
|
||||
页面使用了 Arco Design 的设计令牌(Design Tokens),可以通过修改主题变量来调整配色:
|
||||
|
||||
```less
|
||||
// 主要颜色
|
||||
rgb(var(--primary-6)) // 主色调
|
||||
rgb(var(--success-6)) // 成功色
|
||||
rgb(var(--warning-6)) // 警告色
|
||||
```
|
||||
|
||||
## 登录页面优化
|
||||
|
||||
在登录页面右上角添加了"访问官网首页"按钮,方便用户在登录前了解系统功能。
|
||||
|
||||
## 下一步建议
|
||||
|
||||
1. **添加真实数据** - 将演示数据替换为实际的帮助文档
|
||||
2. **集成客服系统** - 接入第三方在线客服工具
|
||||
3. **添加视频教学** - 在帮助中心增加视频教程
|
||||
4. **SEO 优化** - 添加 meta 标签、title 等 SEO 元素
|
||||
5. **多语言支持** - 如果需要,可以添加国际化支持
|
||||
6. **访问统计** - 集成网站分析工具(如百度统计、Google Analytics)
|
||||
|
||||
## 运行项目
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 启动开发服务器
|
||||
pnpm dev
|
||||
|
||||
# 构建生产版本
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## 浏览器兼容性
|
||||
|
||||
- ✅ Chrome (推荐)
|
||||
- ✅ Firefox
|
||||
- ✅ Edge
|
||||
- ✅ Safari
|
||||
- ⚠️ IE11(需要额外 polyfill)
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 确保 logo 文件路径正确(`@/assets/logo.svg`)
|
||||
2. 如果部署在子目录,需要调整路由的 base 配置
|
||||
3. 如需启用 SSR 或 SEO,建议使用 Vue Router 的 history 模式
|
||||
4. 生产环境部署时,确保服务器正确处理 hash 路由
|
||||
|
||||
---
|
||||
|
||||
如有任何问题或需要进一步的技术支持,请联系开发团队。
|
||||
@@ -1,89 +0,0 @@
|
||||
# 快速启动指南
|
||||
|
||||
## 🎉 新增功能
|
||||
|
||||
已成功为您的智能运维管理系统添加了两个全新的对外页面:
|
||||
|
||||
### ✅ 已完成的工作
|
||||
|
||||
1. **官网首页** (`/#/home`)
|
||||
- 现代化的 UI 设计
|
||||
- 功能特性展示(6 个核心功能)
|
||||
- 数据中心关键指标
|
||||
- 响应式布局
|
||||
2. **帮助中心** (`/#/help`)
|
||||
- 常见问题 FAQ
|
||||
- 使用指南分类
|
||||
- 操作手册下载
|
||||
- 联系方式展示
|
||||
|
||||
3. **登录页面优化**
|
||||
- 添加"访问官网首页"按钮
|
||||
|
||||
4. **路由配置**
|
||||
- 无需登录即可访问
|
||||
- 独立布局(无侧边栏)
|
||||
- 根路径自动重定向到首页
|
||||
|
||||
## 🚀 立即查看效果
|
||||
|
||||
### 方式一:直接访问 URL
|
||||
|
||||
在浏览器中访问:
|
||||
|
||||
```
|
||||
http://localhost:5173/#/home
|
||||
http://localhost:5173/#/help
|
||||
```
|
||||
|
||||
### 方式二:从登录页跳转
|
||||
|
||||
访问登录页面,点击右上角的"首页"图标即可跳转到官网首页。
|
||||
|
||||
## 📝 下一步自定义建议
|
||||
|
||||
### 1. 修改 Logo
|
||||
|
||||
替换 `src/assets/logo.svg` 文件为您公司的 logo
|
||||
|
||||
### 2. 更新联系信息
|
||||
|
||||
编辑以下文件中的联系方式:
|
||||
|
||||
- `src/views/home/index.vue` - 页脚联系方式
|
||||
- `src/views/help/index.vue` - 联系我们板块
|
||||
|
||||
### 3. 添加真实的帮助文档
|
||||
|
||||
编辑 `src/views/help/index.vue` 中的:
|
||||
|
||||
```typescript
|
||||
const faqs = ref([...]) // 常见问题
|
||||
const guides = ref([...]) // 使用指南
|
||||
const manuals = ref([...]) // 操作手册
|
||||
```
|
||||
|
||||
### 4. 调整配色方案
|
||||
|
||||
页面使用了 Arco Design 主题色,可以通过 CSS 变量调整:
|
||||
|
||||
```less
|
||||
rgb(var(--primary-6)) // 主色调
|
||||
```
|
||||
|
||||
## 💡 提示
|
||||
|
||||
- 所有页面都已经适配移动端,可以在手机上查看效果
|
||||
- 页面使用了 Vue Router 的 hash 模式,部署简单
|
||||
- 无需后端支持,纯静态页面,可直接部署
|
||||
|
||||
## 📦 技术栈
|
||||
|
||||
- Vue 3 + TypeScript
|
||||
- Arco Design 组件库
|
||||
- Vite 构建工具
|
||||
- Vue Router 路由管理
|
||||
|
||||
---
|
||||
|
||||
享受您的新页面!🎊
|
||||
376
asset-source-address-frontend-integration.md
Normal file
@@ -0,0 +1,376 @@
|
||||
# 资产设备源地址前端对接文档
|
||||
|
||||
## 1. 变更说明
|
||||
|
||||
设备资产新增可选字段 `source_address`,界面名称为“源地址”。该字段适用于所有设备分类,可用于保存 RTSP、HTTP、HTTPS、HLS 等形式的播放源地址。
|
||||
|
||||
| 属性 | 内容 |
|
||||
| --- | --- |
|
||||
| JSON 字段 | `source_address` |
|
||||
| TypeScript 类型 | `string` |
|
||||
| 是否必填 | 否 |
|
||||
| 最大长度 | 1000 个字符 |
|
||||
| 协议限制 | 无 |
|
||||
| 数据库字段 | `assets_assets.source_address` |
|
||||
| 数据库类型 | `varchar(1000)` |
|
||||
|
||||
前端不需要根据设备分类判断是否展示该字段。
|
||||
|
||||
## 2. 接口公共约定
|
||||
|
||||
资产接口基础路径:
|
||||
|
||||
```text
|
||||
/Assets/v1/asset
|
||||
```
|
||||
|
||||
请求头:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
统一响应结构:
|
||||
|
||||
```ts
|
||||
interface ApiResponse<T> {
|
||||
code: number
|
||||
message: string
|
||||
details: T
|
||||
timeseq: number
|
||||
}
|
||||
```
|
||||
|
||||
`code === 0` 表示请求成功,业务数据位于 `details`。
|
||||
|
||||
## 3. 前端类型
|
||||
|
||||
在资产表单类型中增加 `source_address`:
|
||||
|
||||
```ts
|
||||
export interface AssetForm {
|
||||
id?: number
|
||||
asset_name: string
|
||||
asset_code: string
|
||||
source_address?: string
|
||||
}
|
||||
```
|
||||
|
||||
当前项目已经在 `src/api/ops/asset.ts` 的 `AssetForm` 中加入该字段。其他以资产对象为基础的详情、列表和批量导入数据可以直接复用该字段。
|
||||
|
||||
## 4. 创建设备资产
|
||||
|
||||
### 4.1 接口
|
||||
|
||||
```http
|
||||
POST /Assets/v1/asset/create
|
||||
```
|
||||
|
||||
### 4.2 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"asset_name": "东门监控摄像头",
|
||||
"asset_code": "CAMERA-001",
|
||||
"category_id": 12,
|
||||
"model": "DS-2CD3T",
|
||||
"manufacturer": "海康威视",
|
||||
"serial_number": "SN20260817001",
|
||||
"source_address": "rtsp://192.168.1.100:554/Streaming/Channels/101",
|
||||
"status": "in_use"
|
||||
}
|
||||
```
|
||||
|
||||
未填写源地址时可以省略 `source_address`,也可以传空字符串:
|
||||
|
||||
```json
|
||||
{
|
||||
"asset_name": "普通设备",
|
||||
"asset_code": "DEVICE-001",
|
||||
"source_address": ""
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 成功响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "",
|
||||
"details": {
|
||||
"id": 101,
|
||||
"asset_name": "东门监控摄像头",
|
||||
"asset_code": "CAMERA-001",
|
||||
"source_address": "rtsp://192.168.1.100:554/Streaming/Channels/101",
|
||||
"status": "in_use"
|
||||
},
|
||||
"timeseq": 1786932000000
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 调用方式
|
||||
|
||||
```ts
|
||||
import { createAsset, type AssetForm } from '@/api/ops/asset'
|
||||
|
||||
const data: AssetForm = {
|
||||
asset_name: '东门监控摄像头',
|
||||
asset_code: 'CAMERA-001',
|
||||
source_address: 'rtsp://192.168.1.100:554/Streaming/Channels/101',
|
||||
status: 'in_use',
|
||||
}
|
||||
|
||||
const response = await createAsset(data)
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || '创建设备失败')
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 更新设备资产
|
||||
|
||||
### 5.1 接口
|
||||
|
||||
```http
|
||||
PUT /Assets/v1/asset/update
|
||||
```
|
||||
|
||||
### 5.2 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 101,
|
||||
"asset_name": "东门监控摄像头",
|
||||
"asset_code": "CAMERA-001",
|
||||
"source_address": "https://video.example.com/live/camera-001.m3u8",
|
||||
"status": "in_use"
|
||||
}
|
||||
```
|
||||
|
||||
更新接口需要同时传入:
|
||||
|
||||
- `id`
|
||||
- `asset_name`
|
||||
- `asset_code`
|
||||
|
||||
`source_address` 仍为选填字段。传入非空值时更新源地址;不传时保留原值。
|
||||
|
||||
当前后端使用 GORM 结构体更新,空字符串属于零值,因此传入 `source_address: ""` 不会清空已有源地址。前端暂时不要把“传空字符串”作为清空操作。
|
||||
|
||||
### 5.3 调用方式
|
||||
|
||||
```ts
|
||||
import { updateAsset, type AssetForm } from '@/api/ops/asset'
|
||||
|
||||
const data: AssetForm = {
|
||||
id: 101,
|
||||
asset_name: '东门监控摄像头',
|
||||
asset_code: 'CAMERA-001',
|
||||
source_address: 'https://video.example.com/live/camera-001.m3u8',
|
||||
status: 'in_use',
|
||||
}
|
||||
|
||||
const response = await updateAsset(data)
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || '更新设备失败')
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 查询设备详情
|
||||
|
||||
### 6.1 接口
|
||||
|
||||
```http
|
||||
GET /Assets/v1/asset/detail/{id}
|
||||
```
|
||||
|
||||
### 6.2 成功响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "",
|
||||
"details": {
|
||||
"id": 101,
|
||||
"asset_name": "东门监控摄像头",
|
||||
"asset_code": "CAMERA-001",
|
||||
"source_address": "rtsp://192.168.1.100:554/Streaming/Channels/101",
|
||||
"status": "in_use"
|
||||
},
|
||||
"timeseq": 1786932000000
|
||||
}
|
||||
```
|
||||
|
||||
未填写源地址时,`source_address` 返回空字符串。
|
||||
|
||||
### 6.3 表单回填
|
||||
|
||||
当前编辑页面使用详情对象整体回填:
|
||||
|
||||
```ts
|
||||
const response = await fetchAssetDetail(deviceId)
|
||||
if (response.code === 0) {
|
||||
form.value = { ...response.details } as AssetForm
|
||||
}
|
||||
```
|
||||
|
||||
`source_address` 会随其他资产字段自动回填,不需要单独请求。
|
||||
|
||||
## 7. 分页查询设备资产
|
||||
|
||||
### 7.1 接口
|
||||
|
||||
```http
|
||||
POST /Assets/v1/asset/list
|
||||
```
|
||||
|
||||
### 7.2 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"keyword": "",
|
||||
"status": "in_use"
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "",
|
||||
"details": {
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"data": [
|
||||
{
|
||||
"id": 101,
|
||||
"asset_name": "东门监控摄像头",
|
||||
"asset_code": "CAMERA-001",
|
||||
"source_address": "rtsp://192.168.1.100:554/Streaming/Channels/101"
|
||||
}
|
||||
]
|
||||
},
|
||||
"timeseq": 1786932000000
|
||||
}
|
||||
```
|
||||
|
||||
以下接口返回的资产对象同样包含 `source_address`:
|
||||
|
||||
```http
|
||||
GET /Assets/v1/asset/page
|
||||
GET /Assets/v1/asset/all
|
||||
GET /Assets/v1/asset/export
|
||||
```
|
||||
|
||||
## 8. 批量导入
|
||||
|
||||
### 8.1 接口
|
||||
|
||||
```http
|
||||
POST /Assets/v1/asset/bulk_import
|
||||
```
|
||||
|
||||
### 8.2 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"dry_run": false,
|
||||
"items": [
|
||||
{
|
||||
"asset_name": "西门监控摄像头",
|
||||
"asset_code": "CAMERA-002",
|
||||
"source_address": "rtsp://192.168.1.101:554/live",
|
||||
"status": "in_use"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
每个 `items` 元素都可以单独填写或省略 `source_address`。
|
||||
|
||||
## 9. 表单接入
|
||||
|
||||
### 9.1 默认值
|
||||
|
||||
```ts
|
||||
const form = ref<AssetForm>({
|
||||
asset_name: '',
|
||||
asset_code: '',
|
||||
source_address: '',
|
||||
})
|
||||
```
|
||||
|
||||
### 9.2 表单组件
|
||||
|
||||
```vue
|
||||
<a-form-item label="源地址" field="source_address">
|
||||
<a-input
|
||||
v-model="form.source_address"
|
||||
placeholder="请输入源地址"
|
||||
:max-length="1000"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
```
|
||||
|
||||
该字段不设置 `required` 规则,也不校验具体协议格式。
|
||||
|
||||
### 9.3 提交
|
||||
|
||||
新增和编辑直接复用现有资产提交逻辑:
|
||||
|
||||
```ts
|
||||
const data = { ...form.value }
|
||||
|
||||
if (isEdit.value && deviceId.value) {
|
||||
await updateAsset({ ...data, id: deviceId.value })
|
||||
} else {
|
||||
await createAsset(data)
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 详情展示
|
||||
|
||||
```vue
|
||||
<a-descriptions-item label="源地址" :span="2">
|
||||
<span class="source-address">{{ device?.source_address || '-' }}</span>
|
||||
</a-descriptions-item>
|
||||
```
|
||||
|
||||
长地址需要允许换行:
|
||||
|
||||
```css
|
||||
.source-address {
|
||||
word-break: break-all;
|
||||
}
|
||||
```
|
||||
|
||||
## 11. 播放功能使用建议
|
||||
|
||||
获取播放地址时直接读取资产对象的 `source_address`:
|
||||
|
||||
```ts
|
||||
const sourceAddress = record.source_address?.trim()
|
||||
|
||||
if (!sourceAddress) {
|
||||
Message.warning('该设备未配置源地址')
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
前端不要自动补全协议、转换大小写或修改地址内容。具体播放器需要支持对应的流媒体协议,例如浏览器不能直接原生播放 RTSP 地址。
|
||||
|
||||
## 12. 对接检查项
|
||||
|
||||
- 新增设备时可以不填写源地址。
|
||||
- 新增设备时填写源地址后可以正常保存。
|
||||
- 编辑设备时能够正确回填源地址。
|
||||
- 编辑设备时修改源地址后可以正常保存。
|
||||
- 详情接口和详情弹窗能够显示源地址。
|
||||
- 列表接口返回的每条资产数据包含 `source_address`。
|
||||
- 超长地址能够在详情区域正常换行。
|
||||
- 接口失败时优先显示响应中的 `message`。
|
||||
@@ -1,54 +1,132 @@
|
||||
import { mergeConfig } from 'vite'
|
||||
import type { IncomingMessage } from 'node:http'
|
||||
import { loadEnv, mergeConfig, type ConfigEnv, type ProxyOptions } from 'vite'
|
||||
// import eslint from 'vite-plugin-eslint'
|
||||
import baseConfig from './vite.config.base'
|
||||
|
||||
const HIKVISION_PROXY_TIMEOUT = 8000
|
||||
|
||||
const proxyTarget = (port: number) => ({
|
||||
target: `http://127.0.0.1:${port}`,
|
||||
changeOrigin: true,
|
||||
})
|
||||
|
||||
export default mergeConfig(
|
||||
{
|
||||
mode: 'development',
|
||||
server: {
|
||||
open: true,
|
||||
host: '0.0.0.0',
|
||||
fs: {
|
||||
strict: true,
|
||||
},
|
||||
proxy: {
|
||||
'/rbac2': proxyTarget(10001),
|
||||
'/Alert': proxyTarget(12427),
|
||||
'/alert': proxyTarget(12427),
|
||||
'/DC-Control': proxyTarget(3031),
|
||||
'/dc-control': proxyTarget(3031),
|
||||
'/dc-network': proxyTarget(12429),
|
||||
'/DC-Hardware': proxyTarget(12450),
|
||||
'/dc-hardware': proxyTarget(12450),
|
||||
'/dc-host': proxyTarget(9030),
|
||||
'/dc-middleware': proxyTarget(12428),
|
||||
'/dc-database': proxyTarget(12580),
|
||||
'/Feedback': proxyTarget(12432),
|
||||
'/feedback': proxyTarget(12432),
|
||||
'/Assets': proxyTarget(12430),
|
||||
'/assets': proxyTarget(12430),
|
||||
'/Logs': proxyTarget(12440),
|
||||
'/logs': proxyTarget(12440),
|
||||
'/Kb': proxyTarget(12434),
|
||||
'/kb': proxyTarget(12434),
|
||||
'/Mgt': proxyTarget(12436),
|
||||
'/mgt': proxyTarget(12436),
|
||||
'/Visual': proxyTarget(12438),
|
||||
'/visual': proxyTarget(12438),
|
||||
},
|
||||
/** 读取海康 WebSDK 写入的代理目标 Cookie。 */
|
||||
function getProxyCookie(request: IncomingMessage, name: string): string {
|
||||
const cookie = request.headers.cookie || ''
|
||||
const matched = cookie.match(new RegExp(`(?:^|;\\s*)${name}=([^;]+)`))
|
||||
if (!matched) return ''
|
||||
try {
|
||||
return decodeURIComponent(matched[1])
|
||||
} catch (_error) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
/** 从 SDK Cookie 解析 WebSocket 端口,并限制只能代理到已配置的录像机。 */
|
||||
function resolveHikvisionWebSocketTarget(request: IncomingMessage, allowedHost: string, fallbackTarget: string): string {
|
||||
const secureAddress = getProxyCookie(request, 'webVideoCtrlProxyWss')
|
||||
const address = secureAddress || getProxyCookie(request, 'webVideoCtrlProxyWs')
|
||||
if (!address) return fallbackTarget
|
||||
try {
|
||||
const target = new URL(`${secureAddress ? 'wss' : 'ws'}://${address}`)
|
||||
return target.hostname.toLowerCase() === allowedHost.toLowerCase() ? target.toString() : fallbackTarget
|
||||
} catch (_error) {
|
||||
return fallbackTarget
|
||||
}
|
||||
}
|
||||
|
||||
/** 创建开发环境 Vite 配置。 */
|
||||
export default ({ mode }: ConfigEnv) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
const apiProxyTarget = env.VITE_API_PROXY_TARGET || 'https://ops-api.apinb.com'
|
||||
const proxy: Record<string, ProxyOptions> = {
|
||||
'/api': {
|
||||
target: apiProxyTarget,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
},
|
||||
plugins: [
|
||||
// eslint({
|
||||
// cache: false,
|
||||
// include: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.vue'],
|
||||
// exclude: ['node_modules'],
|
||||
// }),
|
||||
],
|
||||
},
|
||||
baseConfig
|
||||
)
|
||||
'/rbac2': proxyTarget(10001),
|
||||
'/Alert': proxyTarget(12427),
|
||||
'/alert': proxyTarget(12427),
|
||||
'/DC-Control': proxyTarget(3031),
|
||||
'/dc-control': proxyTarget(3031),
|
||||
'/dc-network': proxyTarget(12429),
|
||||
'/DC-Hardware': proxyTarget(12450),
|
||||
'/dc-hardware': proxyTarget(12450),
|
||||
'/dc-host': proxyTarget(9030),
|
||||
'/dc-middleware': proxyTarget(12428),
|
||||
'/dc-database': proxyTarget(12580),
|
||||
'/Feedback': proxyTarget(12432),
|
||||
'/feedback': proxyTarget(12432),
|
||||
'/Assets': proxyTarget(12430),
|
||||
'/assets': proxyTarget(12430),
|
||||
'/Logs': proxyTarget(12440),
|
||||
'/logs': proxyTarget(12440),
|
||||
'/Kb': proxyTarget(12434),
|
||||
'/kb': proxyTarget(12434),
|
||||
'/Mgt': proxyTarget(12436),
|
||||
'/mgt': proxyTarget(12436),
|
||||
'/Visual': proxyTarget(12438),
|
||||
'/visual': proxyTarget(12438),
|
||||
}
|
||||
|
||||
if (env.VITE_HIKVISION_PROXY_TARGET) {
|
||||
const hikvisionHttpTarget = new URL(env.VITE_HIKVISION_PROXY_TARGET)
|
||||
const hikvisionWebSocketTarget =
|
||||
env.VITE_HIKVISION_WS_PROXY_TARGET || `${hikvisionHttpTarget.protocol === 'https:' ? 'wss' : 'ws'}://${hikvisionHttpTarget.host}`
|
||||
proxy['/ISAPI'] = {
|
||||
target: env.VITE_HIKVISION_PROXY_TARGET,
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
timeout: HIKVISION_PROXY_TIMEOUT,
|
||||
proxyTimeout: HIKVISION_PROXY_TIMEOUT,
|
||||
}
|
||||
proxy['/SDK'] = {
|
||||
target: env.VITE_HIKVISION_PROXY_TARGET,
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
timeout: HIKVISION_PROXY_TIMEOUT,
|
||||
proxyTimeout: HIKVISION_PROXY_TIMEOUT,
|
||||
}
|
||||
proxy['/webSocketVideoCtrlProxy'] = {
|
||||
target: hikvisionWebSocketTarget,
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
ws: true,
|
||||
timeout: HIKVISION_PROXY_TIMEOUT,
|
||||
proxyTimeout: HIKVISION_PROXY_TIMEOUT,
|
||||
router: env.VITE_HIKVISION_WS_PROXY_TARGET
|
||||
? undefined
|
||||
: (request) => resolveHikvisionWebSocketTarget(request, hikvisionHttpTarget.hostname, hikvisionWebSocketTarget),
|
||||
rewrite: (path) => path.replace(/^\/webSocketVideoCtrlProxy/, '/'),
|
||||
}
|
||||
}
|
||||
|
||||
return mergeConfig(
|
||||
{
|
||||
mode: 'development',
|
||||
server: {
|
||||
open: true,
|
||||
host: '0.0.0.0',
|
||||
headers: {
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
'Cross-Origin-Resource-Policy': 'cross-origin',
|
||||
},
|
||||
fs: {
|
||||
strict: true,
|
||||
},
|
||||
proxy,
|
||||
},
|
||||
plugins: [
|
||||
// eslint({
|
||||
// cache: false,
|
||||
// include: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.vue'],
|
||||
// exclude: ['node_modules'],
|
||||
// }),
|
||||
],
|
||||
},
|
||||
baseConfig
|
||||
)
|
||||
}
|
||||
|
||||
24
dev/components.d.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// biome-ignore lint: disable
|
||||
// oxlint-disable
|
||||
// ------
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import { GlobalComponents } from 'vue'
|
||||
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
}
|
||||
|
||||
// For TSX support
|
||||
declare global {
|
||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||
const RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="https://unpkg.byted-static.com/latest/byted/arco-config/assets/favicon.ico" />
|
||||
<link rel="icon" type="image/svg+xml" href="%BASE_URL%favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>智能运维管理系统</title>
|
||||
</head>
|
||||
|
||||
15673
package-lock.json
generated
Normal file
@@ -19,6 +19,7 @@
|
||||
"dependencies": {
|
||||
"@arco-design/web-vue": "^2.57.0",
|
||||
"@tabler/icons-vue": "^3.40.0",
|
||||
"@tweenjs/tween.js": "18.6.0",
|
||||
"@vue-flow/background": "^1.3.2",
|
||||
"@vue-flow/controls": "^1.1.3",
|
||||
"@vue-flow/core": "^1.48.2",
|
||||
@@ -33,6 +34,7 @@
|
||||
"pinia": "^3.0.4",
|
||||
"query-string": "^9.3.1",
|
||||
"sortablejs": "^1.15.7",
|
||||
"three": "0.115.0",
|
||||
"uuid": "^13.0.0",
|
||||
"vue": "^3.5.29",
|
||||
"vue-echarts": "^8.0.1",
|
||||
@@ -72,7 +74,6 @@
|
||||
"rollup": "^4.59.0",
|
||||
"rollup-plugin-visualizer": "^7.0.1",
|
||||
"stylelint": "^17.4.0",
|
||||
"stylelint-config-prettier": "^9.0.5",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-config-recommended-vue": "^1.6.1",
|
||||
"stylelint-config-standard": "^40.0.0",
|
||||
|
||||
30
pnpm-lock.yaml
generated
@@ -13,6 +13,9 @@ importers:
|
||||
'@tabler/icons-vue':
|
||||
specifier: ^3.40.0
|
||||
version: 3.40.0(vue@3.5.29(typescript@5.9.3))
|
||||
'@tweenjs/tween.js':
|
||||
specifier: 18.6.0
|
||||
version: 18.6.0
|
||||
'@vue-flow/background':
|
||||
specifier: ^1.3.2
|
||||
version: 1.3.2(@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))
|
||||
@@ -55,6 +58,9 @@ importers:
|
||||
sortablejs:
|
||||
specifier: ^1.15.7
|
||||
version: 1.15.7
|
||||
three:
|
||||
specifier: 0.115.0
|
||||
version: 0.115.0
|
||||
uuid:
|
||||
specifier: ^13.0.0
|
||||
version: 13.0.0
|
||||
@@ -167,9 +173,6 @@ importers:
|
||||
stylelint:
|
||||
specifier: ^17.4.0
|
||||
version: 17.4.0(typescript@5.9.3)
|
||||
stylelint-config-prettier:
|
||||
specifier: ^9.0.5
|
||||
version: 9.0.5(stylelint@17.4.0(typescript@5.9.3))
|
||||
stylelint-config-rational-order:
|
||||
specifier: ^0.1.2
|
||||
version: 0.1.2
|
||||
@@ -205,6 +208,9 @@ importers:
|
||||
version: 3.2.5(typescript@5.9.3)
|
||||
|
||||
packages:
|
||||
'@tweenjs/tween.js@18.6.0':
|
||||
resolution: { integrity: sha512-z45HU0G0e/SenbvGdAlTpUR5Hur5zwZXQcqfI+f7EnVHdeb2oMI2rQghEePu7uXuvBC0nuKWG5YtZ1nWbuvqzQ== }
|
||||
|
||||
'@arco-design/color@0.4.0':
|
||||
resolution: { integrity: sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g== }
|
||||
|
||||
@@ -3968,13 +3974,6 @@ packages:
|
||||
postcss-html: ^1.0.0
|
||||
stylelint: '>=14.0.0'
|
||||
|
||||
stylelint-config-prettier@9.0.5:
|
||||
resolution: { integrity: sha512-U44lELgLZhbAD/xy/vncZ2Pq8sh2TnpiPvo38Ifg9+zeioR+LAkHu0i6YORIOxFafZoVg0xqQwex6e6F25S5XA== }
|
||||
engines: { node: '>= 12' }
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
stylelint: '>= 11.x < 15'
|
||||
|
||||
stylelint-config-rational-order@0.1.2:
|
||||
resolution: { integrity: sha512-Qo7ZQaihCwTqijfZg4sbdQQHtugOX/B1/fYh018EiDZHW+lkqH9uHOnsDwDPGZrYJuB6CoyI7MZh2ecw2dOkew== }
|
||||
|
||||
@@ -4110,6 +4109,9 @@ packages:
|
||||
trough@1.0.5:
|
||||
resolution: { integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== }
|
||||
|
||||
three@0.115.0:
|
||||
resolution: { integrity: sha512-mAV2Ky3RdcbdSbR9capI+tKLvRldWYxd4151PZTT/o7+U2jh9Is3a4KmnYwzyUAhB2ZA3pXSgCd2DOY4Tj5kow== }
|
||||
|
||||
ts-api-utils@2.4.0:
|
||||
resolution: { integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== }
|
||||
engines: { node: '>=18.12' }
|
||||
@@ -4502,6 +4504,8 @@ packages:
|
||||
resolution: { integrity: sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg== }
|
||||
|
||||
snapshots:
|
||||
'@tweenjs/tween.js@18.6.0': {}
|
||||
|
||||
'@arco-design/color@0.4.0':
|
||||
dependencies:
|
||||
color: 3.2.1
|
||||
@@ -8473,10 +8477,6 @@ snapshots:
|
||||
postcss-html: 1.8.1
|
||||
stylelint: 17.4.0(typescript@5.9.3)
|
||||
|
||||
stylelint-config-prettier@9.0.5(stylelint@17.4.0(typescript@5.9.3)):
|
||||
dependencies:
|
||||
stylelint: 17.4.0(typescript@5.9.3)
|
||||
|
||||
stylelint-config-rational-order@0.1.2:
|
||||
dependencies:
|
||||
stylelint: 9.10.1
|
||||
@@ -8667,6 +8667,8 @@ snapshots:
|
||||
|
||||
text-table@0.2.0: {}
|
||||
|
||||
three@0.115.0: {}
|
||||
|
||||
tiny-emitter@2.1.0: {}
|
||||
|
||||
tinyexec@1.0.2: {}
|
||||
|
||||
4
public/favicon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33">
|
||||
<path d="M0 240.941176a240.941176 240.941176 0 0 1 240.941176-240.941176h542.117648a240.941176 240.941176 0 0 1 240.941176 240.941176v542.117648a240.941176 240.941176 0 0 1-240.941176 240.941176H240.941176a240.941176 240.941176 0 0 1-240.941176-240.941176V240.941176z" fill="#287BF7"></path>
|
||||
<path d="M340.931765 388.969412a120.621176 120.621176 0 1 0 115.260235 209.799529l70.776471 97.490824a241.091765 241.091765 0 1 1 82.522353-283.587765c15.751529 39.936 14.516706 83.546353 13.763764 110.290824-0.150588 4.879059-0.271059 9.216-0.271059 12.860235 0 22.648471 5.812706 48.519529 18.221177 66.831059 10.24 15.058824 26.654118 28.310588 61.108706 28.310588 31.804235 0 49.152-10.721882 59.331764-22.40753 11.264-12.950588 18.974118-33.370353 18.974118-59.452235 0-18.642824-9.396706-39.574588-27.166118-53.067294-16.022588-12.137412-43.550118-21.594353-86.768941-8.734118l-34.42447-115.440941c75.926588-22.618353 144.112941-9.637647 193.987764 28.190118 48.128 36.502588 74.842353 93.093647 74.842353 149.082353 0 48.489412-14.245647 99.087059-48.609882 138.541176-35.418353 40.719059-87.341176 63.728941-150.166588 63.728941-75.294118 0-128.662588-33.792-160.768-81.106823-29.936941-44.062118-39.032471-95.864471-39.032471-134.475294 0-9.396706 0.150588-17.588706 0.240941-24.847059 0.421647-25.057882 0.632471-38.972235-5.330823-54.091294a120.621176 120.621176 0 0 0-156.491294-67.915294z" fill="#FFFFFF"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/three-machine-room/images/server1.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
public/three-machine-room/images/server2.jpg
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
public/three-machine-room/rack/homebg.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 469 KiB |
|
After Width: | Height: | Size: 276 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 285 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 586 KiB |
|
After Width: | Height: | Size: 612 KiB |
BIN
public/three-machine-room/rack/qd/maps/Map__106_Noise.tga
Normal file
BIN
public/three-machine-room/rack/qd/maps/Map__107_Noise.tga
Normal file
BIN
public/three-machine-room/rack/qd/maps/Map__19_Falloff.tga
Normal file
BIN
public/three-machine-room/rack/qd/maps/Map__1_颜色校正.tga
Normal file
BIN
public/three-machine-room/rack/qd/maps/Map__614327418_VR-贴图.tga
Normal file
BIN
public/three-machine-room/rack/qd/maps/t1.jpg
Normal file
|
After Width: | Height: | Size: 766 KiB |
BIN
public/three-machine-room/rack/qd/maps/t2.jpg
Normal file
|
After Width: | Height: | Size: 603 KiB |
BIN
public/three-machine-room/rack/qd/maps/t3.jpg
Normal file
|
After Width: | Height: | Size: 840 KiB |
BIN
public/three-machine-room/rack/qd/maps/t5.jpg
Normal file
|
After Width: | Height: | Size: 451 KiB |
BIN
public/three-machine-room/rack/qd/maps/t7.jpg
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/three-machine-room/rack/qd/maps/贴图__123_Noise.tga
Normal file
962
public/three-machine-room/rack/qd/quding.mtl
Normal file
@@ -0,0 +1,962 @@
|
||||
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
|
||||
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>:04.08.2026 13:21:15
|
||||
|
||||
newmtl Mat3d66_10994759_12_33214
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.3686 0.3686 0.3686
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_10994759_11_76789
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 1.0000 1.0000 1.0000
|
||||
Kd 1.0000 1.0000 1.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\Map__107_Noise.tga
|
||||
map_Kd maps\Map__107_Noise.tga
|
||||
map_bump -bm 0.2000 maps\Map__106_Noise.tga
|
||||
|
||||
newmtl Mat3d66_10994759_30_54055
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.6667 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66_17938251_color_VR-<2D><>ɫ.tga
|
||||
map_Kd maps\3d66_17938251_color_VR-<2D><>ɫ.tga
|
||||
map_bump -bm 0.0500 maps\3d66_17938251_color_VR-<2D><>ɫ.tga
|
||||
|
||||
newmtl Mat3d66_11807706_26_30152
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0196 0.0196 0.0196
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_bump maps\3d66Model-11807706-files-51.png
|
||||
bump maps\3d66Model-11807706-files-51.png
|
||||
|
||||
newmtl Mat3d66_10994759_29_37910
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.6078 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_10994759_22_2dad4012
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.1373 0.1373 0.1373
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_10994759_34_15870
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.6392 0.6392 0.6392
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Model-10994759-files-1.jpg
|
||||
map_Kd maps\3d66Model-10994759-files-1.jpg
|
||||
|
||||
newmtl Mat3d66_10994759_22_24012
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0039 0.0039 0.0039
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_10994759_37_59834
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl wire_198225087
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.7765 0.8824 0.3412
|
||||
Kd 0.7765 0.8824 0.3412
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
|
||||
newmtl Mat3d66_10994759_35_21635
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0588 0.0588 0.0588
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl wire_115115115
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.4510 0.4510 0.4510
|
||||
Kd 0.4510 0.4510 0.4510
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
|
||||
newmtl Mat3d66_10994759_25_25429
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.8549 0.9098 0.9412
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Model-10994759-files-13.jpg
|
||||
map_Kd maps\3d66Model-10994759-files-13.jpg
|
||||
map_bump maps\3d66Model-10994759-files-13.jpg
|
||||
bump maps\3d66Model-10994759-files-13.jpg
|
||||
|
||||
newmtl wire_000000000
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.0000 0.0000 0.0000
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
|
||||
newmtl 3d66_VRayMtl_23563919_021
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.7529 0.7647 0.7294
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_23563919_022
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5961 0.6039 0.5765
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_23563919_018
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.6314 0.0392 0.0392
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_23563919_019
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_23563919_020
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0275 0.0275 0.0275
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl <20><>ҵ<EFBFBD><D2B5><EFBFBD>Ұ<EFBFBD>ɫ<EFBFBD>߹<EFBFBD><DFB9>⻬<EFBFBD><E2BBAC>ƺ<EFBFBD><C6BA>_Ϳ<5F><CDBF>_VR
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.3922 0.3922 0.3922
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Mat-14871359-maps-3.jpg
|
||||
map_Kd maps\3d66Mat-14871359-maps-3.jpg
|
||||
map_bump -bm 0.0150 maps\<5C><>ͼ__123_Noise.tga
|
||||
|
||||
newmtl <20>ִ<EFBFBD><D6B4><EFBFBD>ɫ<EFBFBD>ƹ<EFBFBD><C6B9>⻬<EFBFBD><E2BBAC><EFBFBD><EFBFBD>_<EFBFBD><5F>_VR
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0196 0.0196 0.0196
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_11807706_4_39763
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0196 0.0196 0.0196
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_11807706_5_89594
|
||||
Ns 41.0000
|
||||
Ni 1.5000
|
||||
d 0.8000
|
||||
Tr 0.2000
|
||||
Tf 0.8000 0.8000 0.8000
|
||||
illum 2
|
||||
Ka 0.9725 0.0000 0.0000
|
||||
Kd 0.9725 0.0000 0.0000
|
||||
Ks 0.3960 0.3960 0.3960
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl wire_225198087
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.8824 0.7765 0.3412
|
||||
Kd 0.8824 0.7765 0.3412
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
|
||||
newmtl Mat3d66_11807706_7_95731
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5333 0.5294 0.5255
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_11807706_8_21117
|
||||
Ns 76.0000
|
||||
Ni 1.5000
|
||||
d 0.4000
|
||||
Tr 0.6000
|
||||
Tf 0.4000 0.4000 0.4000
|
||||
illum 2
|
||||
Ka 0.1608 0.1569 0.1843
|
||||
Kd 0.1608 0.1569 0.1843
|
||||
Ks 0.7920 0.7920 0.7920
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_refl maps\Map__614327418_VR-<2D><>ͼ.tga
|
||||
|
||||
newmtl Mat3d66_11807706_9_83349
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0863 0.0745 0.0667
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_11807706_10_61673
|
||||
Ns 76.0000
|
||||
Ni 1.5000
|
||||
d 0.0500
|
||||
Tr 0.9500
|
||||
Tf 0.0500 0.0500 0.0500
|
||||
illum 2
|
||||
Ka 0.1608 0.1569 0.1843
|
||||
Kd 0.1608 0.1569 0.1843
|
||||
Ks 0.7920 0.7920 0.7920
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_refl maps\Map__614327418_VR-<2D><>ͼ.tga
|
||||
|
||||
newmtl Mat3d66_11807706_11_67368
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0863 0.0745 0.0667
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Model-11807706-files-3.jpg
|
||||
map_Kd maps\3d66Model-11807706-files-3.jpg
|
||||
|
||||
newmtl 22___Default
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0039 0.0039 0.0039
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_11807706_29_27585
|
||||
Ns 38.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5882 0.5882 0.5882
|
||||
Kd 0.5882 0.5882 0.5882
|
||||
Ks 0.1800 0.1800 0.1800
|
||||
Ke 0.0706 0.0706 0.0706
|
||||
map_Ka maps\3d66Model-11807706-files-60.jpg
|
||||
map_Kd maps\3d66Model-11807706-files-60.jpg
|
||||
map_bump maps\3d66Model-11807706-files-60.jpg
|
||||
bump maps\3d66Model-11807706-files-60.jpg
|
||||
|
||||
newmtl Mat3d66_11807706_120_47020
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\Map__1_<31><5F>ɫУ<C9AB><D0A3>.tga
|
||||
map_Kd maps\Map__1_<31><5F>ɫУ<C9AB><D0A3>.tga
|
||||
map_bump maps\Map__1_<31><5F>ɫУ<C9AB><D0A3>.tga
|
||||
|
||||
newmtl wire_010140195
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.0392 0.5490 0.7647
|
||||
Kd 0.0392 0.5490 0.7647
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
|
||||
newmtl Mat3d66_11807706_28_26251
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.8941 0.8941 0.8941
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_15185da96_31_5088
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0275 0.0275 0.0235
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_10994759_49_69999
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.1373 0.1373 0.1373
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_10994759_31_26985
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0392 0.0392 0.0392
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_bump maps\3d66Model-10994759-files-15.JPG
|
||||
bump maps\3d66Model-10994759-files-15.JPG
|
||||
|
||||
newmtl 24___Default
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\t7.jpg
|
||||
map_Kd maps\t7.jpg
|
||||
|
||||
newmtl 3d66_VRayMtl_20092954_028
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.9216 0.9216 0.9216
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_20092954_034
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.1176 0.1176 0.1176
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_7566050_1_94391
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.9020 0.9020 0.9020
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_1518596_31_5088
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.6471 0.6235 0.6000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_23605226_030
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5882 0.5882 0.5882
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_23605226_031
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Model-23605226-files-005.png
|
||||
map_Kd maps\3d66Model-23605226-files-005.png
|
||||
map_bump maps\3d66_VRayNormalMap_23605226_023_VR-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ.tga
|
||||
|
||||
newmtl Mat3d66_7859414_4_42689
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.3529 0.3529 0.3529
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_7859414_3_41489
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.8627 0.8549 0.8471
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_7859414_7_21754
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.1765 0.1765 0.1765
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_7859414_5_93165
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.8235 0.8196 0.8157
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl wire_135006006
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.5294 0.0235 0.0235
|
||||
Kd 0.5294 0.0235 0.0235
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_046
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_047
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0275 0.0275 0.0275
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_045
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.6314 0.0392 0.0392
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_048
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.7529 0.7647 0.7294
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_049
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5961 0.6039 0.5765
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_052
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0510 0.0510 0.0510
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_069
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 1.0000 1.0000 1.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_070
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.7176 0.7882 0.8510
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_071
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_074
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66_Bricks_22568095_021_Tiles.tga
|
||||
map_Kd maps\3d66_Bricks_22568095_021_Tiles.tga
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_025
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0902 0.0902 0.0902
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_Standardmaterial_22568095_004
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5882 0.5882 0.5882
|
||||
Kd 0.5882 0.5882 0.5882
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 3d66_VRayMtl_22568095_066
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0392 0.0392 0.0392
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl 17___Default
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\t3.jpg
|
||||
map_Kd maps\t3.jpg
|
||||
|
||||
newmtl 18___Default
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\t5.jpg
|
||||
map_Kd maps\t5.jpg
|
||||
|
||||
newmtl 16___Default
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\t2.jpg
|
||||
map_Kd maps\t2.jpg
|
||||
|
||||
newmtl 15___Default
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.5000 0.5000 0.5000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\t1.jpg
|
||||
map_Kd maps\t1.jpg
|
||||
|
||||
newmtl Mat3d66_14662737_11_91260
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 1.0000 1.0000 1.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Model-14662737-files-5.jpg
|
||||
map_Kd maps\3d66Model-14662737-files-5.jpg
|
||||
|
||||
newmtl Mat3d66_14662737_12_48868
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 1.0000 1.0000 1.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Model-14662737-files-5.jpg
|
||||
map_Kd maps\3d66Model-14662737-files-5.jpg
|
||||
|
||||
newmtl wire_154185229
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.6039 0.7255 0.8980
|
||||
Kd 0.6039 0.7255 0.8980
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
|
||||
newmtl Glass
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Mat3d66_8099876_13_28564
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.4667 0.4510 0.4353
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Material__53
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl Material__52
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.1451 0.1451 0.1451
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_Ka maps\3d66Model-8099876-files-4.jpg
|
||||
map_Kd maps\3d66Model-8099876-files-4.jpg
|
||||
|
||||
newmtl Material__109
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.0000 0.0000 0.0000
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl <20><><EFBFBD>ݧ<EFBFBD><DDA7>ާڧߧڧ<DFA7>_<EFBFBD><5F><EFBFBD><EFBFBD><EFBFBD>ݧڧ<DDA7><DAA7><EFBFBD><EFBFBD>ӧѧߧߧ<DFA7><DFA7><EFBFBD>
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.1872 0.1872 0.1872
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
|
||||
newmtl <20><><EFBFBD><EFBFBD><EFBFBD>ݧ<EFBFBD>
|
||||
Ns 10.0000
|
||||
Ni 1.5000
|
||||
d 1.0000
|
||||
Tr 0.0000
|
||||
Tf 1.0000 1.0000 1.0000
|
||||
illum 2
|
||||
Ka 0.5880 0.5880 0.5880
|
||||
Kd 0.7529 0.7529 0.7529
|
||||
Ks 0.0000 0.0000 0.0000
|
||||
Ke 0.0000 0.0000 0.0000
|
||||
map_d maps\Map__19_Falloff.tga
|
||||
|
||||
newmtl wire_154215229
|
||||
Ns 32
|
||||
d 1
|
||||
Tr 0
|
||||
Tf 1 1 1
|
||||
illum 2
|
||||
Ka 0.6039 0.8431 0.8980
|
||||
Kd 0.6039 0.8431 0.8980
|
||||
Ks 0.3500 0.3500 0.3500
|
||||
2938085
public/three-machine-room/rack/qd/quding.obj
Normal file
621
public/vendor/hikvision/encryption/AES.js
vendored
Normal file
@@ -0,0 +1,621 @@
|
||||
(function() {
|
||||
var Nr = 10;
|
||||
// convert two-dimensional indicies to one-dim array indices
|
||||
var I00 = 0;
|
||||
var I01 = 1;
|
||||
var I02 = 2;
|
||||
var I03 = 3;
|
||||
var I10 = 4;
|
||||
var I11 = 5;
|
||||
var I12 = 6;
|
||||
var I13 = 7;
|
||||
var I20 = 8;
|
||||
var I21 = 9;
|
||||
var I22 = 10;
|
||||
var I23 = 11;
|
||||
var I30 = 12;
|
||||
var I31 = 13;
|
||||
var I32 = 14;
|
||||
var I33 = 15;
|
||||
|
||||
// S-Box substitution table
|
||||
var S_enc = new Array(
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
|
||||
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
||||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
|
||||
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
||||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
|
||||
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
||||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
|
||||
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
||||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
|
||||
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
|
||||
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
|
||||
|
||||
// inverse S-Box for decryptions
|
||||
var S_dec = new Array(
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
|
||||
0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
|
||||
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
|
||||
0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
|
||||
0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
||||
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
|
||||
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
|
||||
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
|
||||
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
|
||||
0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
|
||||
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
|
||||
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
|
||||
0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
|
||||
0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
|
||||
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
|
||||
0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
|
||||
0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
|
||||
|
||||
function cvt_hex8 (val) {
|
||||
var vh = (val>>>4)&0x0f;
|
||||
return vh.toString(16) + (val&0x0f).toString(16);
|
||||
}
|
||||
function cvt_byte (str) {
|
||||
// get the first hex digit
|
||||
var val1 = str.charCodeAt(0);
|
||||
// do some error checking
|
||||
if (val1 >= 48 && val1 <= 57) {
|
||||
// have a valid digit 0-9
|
||||
val1 -= 48;
|
||||
} else if (val1 >= 65 && val1 <= 70) {
|
||||
// have a valid digit A-F
|
||||
val1 -= 55;
|
||||
} else if (val1 >= 97 && val1 <= 102) {
|
||||
// have a valid digit A-F
|
||||
val1 -= 87;
|
||||
} else {
|
||||
// not 0-9 or A-F, complain
|
||||
console.log( str.charAt(1)+" is not a valid hex digit" );
|
||||
return -1;
|
||||
}
|
||||
// get the second hex digit
|
||||
var val2 = str.charCodeAt(1);
|
||||
// do some error checking
|
||||
if ( val2 >= 48 && val2 <= 57 ) {
|
||||
// have a valid digit 0-9
|
||||
val2 -= 48;
|
||||
} else if ( val2 >= 65 && val2 <= 70 ) {
|
||||
// have a valid digit A-F
|
||||
val2 -= 55;
|
||||
} else if ( val2 >= 97 && val2 <= 102 ) {
|
||||
// have a valid digit A-F
|
||||
val2 -= 87;
|
||||
} else {
|
||||
// not 0-9 or A-F, complain
|
||||
console.log( str.charAt(2)+" is not a valid hex digit" );
|
||||
return -1;
|
||||
}
|
||||
// all is ok, return the value
|
||||
return val1*16 + val2;
|
||||
}
|
||||
|
||||
// conversion function for non-constant subscripts
|
||||
// assume subscript range 0..3
|
||||
function I(x,y) {
|
||||
return (x*4) + y;
|
||||
}
|
||||
|
||||
// remove spaces from input
|
||||
function remove_spaces(instr) {
|
||||
var i;
|
||||
var outstr = "";
|
||||
for(i=0; i<instr.length; i++) {
|
||||
if ( instr.charAt(i) != " " )
|
||||
// not a space, include it
|
||||
outstr += instr.charAt(i);
|
||||
}
|
||||
return outstr;
|
||||
}
|
||||
|
||||
// get the message to encrypt/decrypt or the key
|
||||
// return as a 16-byte array
|
||||
function get_value(str, isASCII) {
|
||||
var dbyte = new Array(16);
|
||||
var i;
|
||||
var val; // one hex digit
|
||||
if (isASCII) {
|
||||
// check length of data
|
||||
if (str.length > 16) {
|
||||
console.log("is too long, using the first 16 ASCII characters" );
|
||||
}
|
||||
// have ASCII data
|
||||
// 16 characters?
|
||||
if (str.length >= 16) {
|
||||
// 16 or more characters
|
||||
for(i=0; i<16; i++) {
|
||||
dbyte[i] = str.charCodeAt(i);
|
||||
}
|
||||
} else {
|
||||
// less than 16 characters - fill with NULLs
|
||||
for(i=0; i<str.length; i++) {
|
||||
dbyte[i] = str.charCodeAt(i);
|
||||
}
|
||||
for( i=str.length; i<16; i++) {
|
||||
dbyte[i] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// have hex data - remove any spaces they used, then convert
|
||||
//str = remove_spaces(str);
|
||||
// check length of data
|
||||
if ( str.length != 32 ) {
|
||||
//console.log("\tget_value:\tstr = " + str + "\tisASCII = " + isASCII); //isASCII = false
|
||||
console.log("length wrong: Is " + str.length + " hex digits, but must be 128 bits (32 hex digits)");
|
||||
dbyte[0] = -1;
|
||||
return dbyte;
|
||||
}
|
||||
for( i=0; i<16; i++ ) {
|
||||
// isolate and convert this substring
|
||||
dbyte[i] = cvt_byte( str.substr(i*2,2) );
|
||||
if( dbyte[i] < 0 ) {
|
||||
// have an error
|
||||
dbyte[0] = -1;
|
||||
return dbyte;
|
||||
}
|
||||
}
|
||||
}
|
||||
// return successful conversion
|
||||
return dbyte;
|
||||
}
|
||||
//do the AES GF(2**8) multiplication
|
||||
// do this by the shift-and-"add" approach
|
||||
function aes_mul(a, b) {
|
||||
var res = 0;
|
||||
while(a > 0) {
|
||||
if((a&1) != 0)
|
||||
res = res ^ b; // "add" to the result
|
||||
a >>>= 1; // shift a to get next higher-order bit
|
||||
b <<= 1; // shift multiplier also
|
||||
}
|
||||
// now reduce it modulo x**8 + x**4 + x**3 + x + 1
|
||||
var hbit = 0x10000; // bit to test if we need to take action
|
||||
var modulus = 0x11b00; // modulus - XOR by this to change value
|
||||
while(hbit >= 0x100) {
|
||||
if ((res & hbit) != 0) {
|
||||
res ^= modulus; // XOR with the modulus
|
||||
}
|
||||
// prepare for the next loop
|
||||
hbit >>= 1;
|
||||
modulus >>= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// apply the S-box substitution to the key expansion
|
||||
function SubWord(word_ary) {
|
||||
var i;
|
||||
for(i=0; i<16; i++) {
|
||||
word_ary[i] = S_enc[word_ary[i]];
|
||||
}
|
||||
return word_ary;
|
||||
}
|
||||
|
||||
// rotate the bytes in a word
|
||||
function RotWord(word_ary) {
|
||||
return new Array(word_ary[1], word_ary[2], word_ary[3], word_ary[0]);
|
||||
}
|
||||
|
||||
// calculate the first item Rcon[i] = { x^(i-1), 0, 0, 0 }
|
||||
// note we only return the first item
|
||||
function Rcon(exp) {
|
||||
var val = 2;
|
||||
var result = 1;
|
||||
|
||||
// remember to calculate x^(exp-1)
|
||||
exp--;
|
||||
|
||||
// process the exponent using normal shift and multiply
|
||||
while ( exp > 0 )
|
||||
{
|
||||
if ( (exp & 1) != 0 )
|
||||
result = aes_mul( result, val );
|
||||
|
||||
// square the value
|
||||
val = aes_mul( val, val );
|
||||
|
||||
// move to the next bit
|
||||
exp >>= 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
// round key generation
|
||||
// return a byte array with the expanded key information
|
||||
function key_expand( key )
|
||||
{
|
||||
var temp = new Array(4);
|
||||
var i, j;
|
||||
var w = new Array(4*(Nr+1));
|
||||
|
||||
// copy initial key stuff
|
||||
for( i=0; i<16; i++ )
|
||||
{
|
||||
w[i] = key[i];
|
||||
}
|
||||
|
||||
// generate rest of key schedule using 32-bit words
|
||||
i = 4;
|
||||
while ( i < 4*(Nr+1)) // blocksize * ( rounds + 1 )
|
||||
{
|
||||
// copy word W[i-1] to temp
|
||||
for( j=0; j<4; j++ )
|
||||
temp[j] = w[(i-1)*4+j];
|
||||
|
||||
if ( i % 4 == 0)
|
||||
{
|
||||
// temp = SubWord(RotWord(temp)) ^ Rcon[i/4];
|
||||
temp = RotWord( temp );
|
||||
temp = SubWord( temp );
|
||||
temp[0] ^= Rcon( i>>>2 );
|
||||
}
|
||||
|
||||
// word = word ^ temp
|
||||
for( j=0; j<4; j++ )
|
||||
w[i*4+j] = w[(i-4)*4+j] ^ temp[j];
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
// do S-Box substitution
|
||||
function SubBytes(state, Sbox)
|
||||
{
|
||||
var i;
|
||||
|
||||
for( i=0; i<16; i++ )
|
||||
state[i] = Sbox[ state[i] ];
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// shift each row as appropriate
|
||||
function ShiftRows(state)
|
||||
{
|
||||
var t0, t1, t2, t3;
|
||||
|
||||
// top row (row 0) isn't shifted
|
||||
|
||||
// next row (row 1) rotated left 1 place
|
||||
t0 = state[I10];
|
||||
t1 = state[I11];
|
||||
t2 = state[I12];
|
||||
t3 = state[I13];
|
||||
state[I10] = t1;
|
||||
state[I11] = t2;
|
||||
state[I12] = t3;
|
||||
state[I13] = t0;
|
||||
|
||||
// next row (row 2) rotated left 2 places
|
||||
t0 = state[I20];
|
||||
t1 = state[I21];
|
||||
t2 = state[I22];
|
||||
t3 = state[I23];
|
||||
state[I20] = t2;
|
||||
state[I21] = t3;
|
||||
state[I22] = t0;
|
||||
state[I23] = t1;
|
||||
|
||||
// bottom row (row 3) rotated left 3 places
|
||||
t0 = state[I30];
|
||||
t1 = state[I31];
|
||||
t2 = state[I32];
|
||||
t3 = state[I33];
|
||||
state[I30] = t3;
|
||||
state[I31] = t0;
|
||||
state[I32] = t1;
|
||||
state[I33] = t2;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// inverset shift each row as appropriate
|
||||
function InvShiftRows(state)
|
||||
{
|
||||
var t0, t1, t2, t3;
|
||||
|
||||
// top row (row 0) isn't shifted
|
||||
|
||||
// next row (row 1) rotated left 1 place
|
||||
t0 = state[I10];
|
||||
t1 = state[I11];
|
||||
t2 = state[I12];
|
||||
t3 = state[I13];
|
||||
state[I10] = t3;
|
||||
state[I11] = t0;
|
||||
state[I12] = t1;
|
||||
state[I13] = t2;
|
||||
|
||||
// next row (row 2) rotated left 2 places
|
||||
t0 = state[I20];
|
||||
t1 = state[I21];
|
||||
t2 = state[I22];
|
||||
t3 = state[I23];
|
||||
state[I20] = t2;
|
||||
state[I21] = t3;
|
||||
state[I22] = t0;
|
||||
state[I23] = t1;
|
||||
|
||||
// bottom row (row 3) rotated left 3 places
|
||||
t0 = state[I30];
|
||||
t1 = state[I31];
|
||||
t2 = state[I32];
|
||||
t3 = state[I33];
|
||||
state[I30] = t1;
|
||||
state[I31] = t2;
|
||||
state[I32] = t3;
|
||||
state[I33] = t0;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// process column info
|
||||
function MixColumns(state)
|
||||
{
|
||||
var col;
|
||||
var c0, c1, c2, c3;
|
||||
|
||||
for( col=0; col<4; col++ )
|
||||
{
|
||||
c0 = state[I(0,col)];
|
||||
c1 = state[I(1,col)];
|
||||
c2 = state[I(2,col)];
|
||||
c3 = state[I(3,col)];
|
||||
|
||||
// do mixing, and put back into array
|
||||
state[I(0,col)] = aes_mul(2,c0) ^ aes_mul(3,c1) ^ c2 ^ c3;
|
||||
state[I(1,col)] = c0 ^ aes_mul(2,c1) ^ aes_mul(3,c2) ^ c3;
|
||||
state[I(2,col)] = c0 ^ c1 ^ aes_mul(2,c2) ^ aes_mul(3,c3);
|
||||
state[I(3,col)] = aes_mul(3,c0) ^ c1 ^ c2 ^ aes_mul(2,c3);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// inverse process column info
|
||||
function InvMixColumns(state)
|
||||
{
|
||||
var col;
|
||||
var c0, c1, c2, c3;
|
||||
|
||||
for( col=0; col<4; col++ )
|
||||
{
|
||||
c0 = state[I(0,col)];
|
||||
c1 = state[I(1,col)];
|
||||
c2 = state[I(2,col)];
|
||||
c3 = state[I(3,col)];
|
||||
|
||||
// do inverse mixing, and put back into array
|
||||
state[I(0,col)] = aes_mul(0x0e,c0) ^ aes_mul(0x0b,c1)
|
||||
^ aes_mul(0x0d,c2) ^ aes_mul(0x09,c3);
|
||||
state[I(1,col)] = aes_mul(0x09,c0) ^ aes_mul(0x0e,c1)
|
||||
^ aes_mul(0x0b,c2) ^ aes_mul(0x0d,c3);
|
||||
state[I(2,col)] = aes_mul(0x0d,c0) ^ aes_mul(0x09,c1)
|
||||
^ aes_mul(0x0e,c2) ^ aes_mul(0x0b,c3);
|
||||
state[I(3,col)] = aes_mul(0x0b,c0) ^ aes_mul(0x0d,c1)
|
||||
^ aes_mul(0x09,c2) ^ aes_mul(0x0e,c3);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// insert subkey information
|
||||
function AddRoundKey( state, w, base )
|
||||
{
|
||||
var col;
|
||||
|
||||
for( col=0; col<4; col++ )
|
||||
{
|
||||
state[I(0,col)] ^= w[base+col*4];
|
||||
state[I(1,col)] ^= w[base+col*4+1];
|
||||
state[I(2,col)] ^= w[base+col*4+2];
|
||||
state[I(3,col)] ^= w[base+col*4+3];
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// return a transposed array
|
||||
function transpose( msg )
|
||||
{
|
||||
var row, col;
|
||||
var state = new Array( 16 );
|
||||
|
||||
for( row=0; row<4; row++ )
|
||||
for( col=0; col<4; col++ )
|
||||
state[I(row,col)] = msg[I(col,row)];
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// final AES state
|
||||
var AES_output = new Array(16);
|
||||
|
||||
// format AES output
|
||||
// -- uses the global array DES_output
|
||||
function format_AES_output(bASCII)
|
||||
{
|
||||
var i;
|
||||
var bits;
|
||||
var str="";
|
||||
|
||||
// what type of data do we have to work with?
|
||||
if (bASCII)
|
||||
{
|
||||
// convert each set of bits back to ASCII
|
||||
for( i=0; i<16; i++ )
|
||||
str += String.fromCharCode( AES_output[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
// output hexdecimal data (insert spaces)
|
||||
str = cvt_hex8( AES_output[0] );
|
||||
for( i=1; i<16; i++ )
|
||||
{
|
||||
str += "" + cvt_hex8( AES_output[i] );
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// do encrytion
|
||||
function aes_encrypt(str, key, bASCII)
|
||||
{
|
||||
//console.log(" aes_encrypt:\tstr = " + str + "\tkey = " + key + "\t bASCII = " + bASCII);
|
||||
var w = new Array( 4*(Nr+1) ); // subkey information
|
||||
var state = new Array( 16 ); // working state
|
||||
var round;
|
||||
|
||||
//accumulated_output_info = "";
|
||||
|
||||
// get the message from the user
|
||||
// also check if it is ASCII or hex
|
||||
var msg = get_value(str, bASCII);
|
||||
|
||||
// problems??
|
||||
if ( msg[0] < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the key from the user
|
||||
var key = get_value(key, false);
|
||||
// problems??
|
||||
if ( key[0] < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// expand the key
|
||||
w = key_expand( key );
|
||||
|
||||
// initial state = message in columns (transposed from what we input)
|
||||
state = transpose( msg );
|
||||
|
||||
// display the round key - Transpose due to the way it is stored/used
|
||||
state = AddRoundKey(state, w, 0);
|
||||
|
||||
for( round=1; round<Nr; round++ )
|
||||
{
|
||||
state = SubBytes(state, S_enc);
|
||||
state = ShiftRows(state);
|
||||
state = MixColumns(state);
|
||||
// display the round key - Transpose due to the way it is stored/used
|
||||
// note here the spec uses 32-bit words, we are using bytes, so an extra *4
|
||||
state = AddRoundKey(state, w, round*4*4);
|
||||
}
|
||||
|
||||
SubBytes(state, S_enc);
|
||||
ShiftRows(state);
|
||||
AddRoundKey(state, w, Nr*4*4);
|
||||
|
||||
// process output
|
||||
AES_output = transpose( state );
|
||||
var szOutput = format_AES_output(!bASCII);
|
||||
return szOutput;
|
||||
}
|
||||
|
||||
// do decryption
|
||||
function aes_decrypt(str, key, bASCII)
|
||||
{
|
||||
//console.log(" aes_decrypt:\tstr = " + str + "\tkey = " + key + "\tbASCII = " + bASCII);
|
||||
var w = new Array( 4*(Nr+1) ); // subkey information
|
||||
var state = new Array( 16 ); // working state
|
||||
var round;
|
||||
|
||||
//accumulated_output_info = "";
|
||||
|
||||
// get the message from the user
|
||||
// also check if it is ASCII or hex
|
||||
var msg = get_value(str, bASCII);
|
||||
|
||||
// problems??
|
||||
if ( msg[0] < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the key from the user
|
||||
var key = get_value(key, false);
|
||||
// problems??
|
||||
if ( key[0] < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// expand the key
|
||||
w = key_expand( key );
|
||||
|
||||
// initial state = message
|
||||
state = transpose( msg );
|
||||
// display the round key - Transpose due to the way it is stored/used
|
||||
state = AddRoundKey(state, w, Nr*4*4);
|
||||
|
||||
for( round=Nr-1; round>=1; round-- )
|
||||
{
|
||||
state = InvShiftRows(state);
|
||||
state = SubBytes(state, S_dec);
|
||||
// display the round key - Transpose due to the way it is stored/used
|
||||
// note here the spec uses 32-bit words, we are using bytes, so an extra *4
|
||||
state = AddRoundKey(state, w, round*4*4);
|
||||
state = InvMixColumns(state);
|
||||
}
|
||||
|
||||
InvShiftRows(state);
|
||||
SubBytes(state, S_dec);
|
||||
AddRoundKey(state, w, 0);
|
||||
|
||||
// process output
|
||||
AES_output = transpose( state );
|
||||
var szOutput = format_AES_output(!bASCII);
|
||||
return szOutput;
|
||||
}
|
||||
window.aes_encrypt = aes_encrypt;
|
||||
window.aes_decrypt = aes_decrypt;
|
||||
window.console = window.console || {
|
||||
log: function() {}
|
||||
};
|
||||
}());
|
||||
106
public/vendor/hikvision/encryption/cryptico.min.js
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
var dbits,canary=244837814094590,j_lm=(canary&16777215)==15715070;function BigInteger(a,b,c){a!=null&&("number"==typeof a?this.fromNumber(a,b,c):b==null&&"string"!=typeof a?this.fromString(a,256):this.fromString(a,b))}function nbi(){return new BigInteger(null)}function am1(a,b,c,d,e,g){for(;--g>=0;){var h=b*this[a++]+c[d]+e,e=Math.floor(h/67108864);c[d++]=h&67108863}return e}
|
||||
function am2(a,b,c,d,e,g){var h=b&32767;for(b>>=15;--g>=0;){var f=this[a]&32767,o=this[a++]>>15,p=b*f+o*h,f=h*f+((p&32767)<<15)+c[d]+(e&1073741823),e=(f>>>30)+(p>>>15)+b*o+(e>>>30);c[d++]=f&1073741823}return e}function am3(a,b,c,d,e,g){var h=b&16383;for(b>>=14;--g>=0;){var f=this[a]&16383,o=this[a++]>>14,p=b*f+o*h,f=h*f+((p&16383)<<14)+c[d]+e,e=(f>>28)+(p>>14)+b*o;c[d++]=f&268435455}return e}
|
||||
j_lm&&navigator.appName=="Microsoft Internet Explorer"?(BigInteger.prototype.am=am2,dbits=30):j_lm&&navigator.appName!="Netscape"?(BigInteger.prototype.am=am1,dbits=26):(BigInteger.prototype.am=am3,dbits=28);BigInteger.prototype.DB=dbits;BigInteger.prototype.DM=(1<<dbits)-1;BigInteger.prototype.DV=1<<dbits;var BI_FP=52;BigInteger.prototype.FV=Math.pow(2,BI_FP);BigInteger.prototype.F1=BI_FP-dbits;BigInteger.prototype.F2=2*dbits-BI_FP;var BI_RM="0123456789abcdefghijklmnopqrstuvwxyz",BI_RC=[],rr,vv;
|
||||
rr="0".charCodeAt(0);for(vv=0;vv<=9;++vv)BI_RC[rr++]=vv;rr="a".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;rr="A".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;function int2char(a){return BI_RM.charAt(a)}function intAt(a,b){var c=BI_RC[a.charCodeAt(b)];return c==null?-1:c}function bnpCopyTo(a){for(var b=this.t-1;b>=0;--b)a[b]=this[b];a.t=this.t;a.s=this.s}function bnpFromInt(a){this.t=1;this.s=a<0?-1:0;a>0?this[0]=a:a<-1?this[0]=a+DV:this.t=0}
|
||||
function nbv(a){var b=nbi();b.fromInt(a);return b}
|
||||
function bnpFromString(a,b){var c;if(b==16)c=4;else if(b==8)c=3;else if(b==256)c=8;else if(b==2)c=1;else if(b==32)c=5;else if(b==4)c=2;else{this.fromRadix(a,b);return}this.s=this.t=0;for(var d=a.length,e=!1,g=0;--d>=0;){var h=c==8?a[d]&255:intAt(a,d);h<0?a.charAt(d)=="-"&&(e=!0):(e=!1,g==0?this[this.t++]=h:g+c>this.DB?(this[this.t-1]|=(h&(1<<this.DB-g)-1)<<g,this[this.t++]=h>>this.DB-g):this[this.t-1]|=h<<g,g+=c,g>=this.DB&&(g-=this.DB))}if(c==8&&(a[0]&128)!=0)this.s=-1,g>0&&(this[this.t-1]|=(1<<
|
||||
this.DB-g)-1<<g);this.clamp();e&&BigInteger.ZERO.subTo(this,this)}function bnpClamp(){for(var a=this.s&this.DM;this.t>0&&this[this.t-1]==a;)--this.t}
|
||||
function bnToString(a){if(this.s<0)return"-"+this.negate().toString(a);if(a==16)a=4;else if(a==8)a=3;else if(a==2)a=1;else if(a==32)a=5;else if(a==64)a=6;else if(a==4)a=2;else return this.toRadix(a);var b=(1<<a)-1,c,d=!1,e="",g=this.t,h=this.DB-g*this.DB%a;if(g-- >0){if(h<this.DB&&(c=this[g]>>h)>0)d=!0,e=int2char(c);for(;g>=0;)h<a?(c=(this[g]&(1<<h)-1)<<a-h,c|=this[--g]>>(h+=this.DB-a)):(c=this[g]>>(h-=a)&b,h<=0&&(h+=this.DB,--g)),c>0&&(d=!0),d&&(e+=int2char(c))}return d?e:"0"}
|
||||
function bnNegate(){var a=nbi();BigInteger.ZERO.subTo(this,a);return a}function bnAbs(){return this.s<0?this.negate():this}function bnCompareTo(a){var b=this.s-a.s;if(b!=0)return b;var c=this.t,b=c-a.t;if(b!=0)return b;for(;--c>=0;)if((b=this[c]-a[c])!=0)return b;return 0}function nbits(a){var b=1,c;if((c=a>>>16)!=0)a=c,b+=16;if((c=a>>8)!=0)a=c,b+=8;if((c=a>>4)!=0)a=c,b+=4;if((c=a>>2)!=0)a=c,b+=2;a>>1!=0&&(b+=1);return b}
|
||||
function bnBitLength(){return this.t<=0?0:this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(a,b){var c;for(c=this.t-1;c>=0;--c)b[c+a]=this[c];for(c=a-1;c>=0;--c)b[c]=0;b.t=this.t+a;b.s=this.s}function bnpDRShiftTo(a,b){for(var c=a;c<this.t;++c)b[c-a]=this[c];b.t=Math.max(this.t-a,0);b.s=this.s}
|
||||
function bnpLShiftTo(a,b){var c=a%this.DB,d=this.DB-c,e=(1<<d)-1,g=Math.floor(a/this.DB),h=this.s<<c&this.DM,f;for(f=this.t-1;f>=0;--f)b[f+g+1]=this[f]>>d|h,h=(this[f]&e)<<c;for(f=g-1;f>=0;--f)b[f]=0;b[g]=h;b.t=this.t+g+1;b.s=this.s;b.clamp()}
|
||||
function bnpRShiftTo(a,b){b.s=this.s;var c=Math.floor(a/this.DB);if(c>=this.t)b.t=0;else{var d=a%this.DB,e=this.DB-d,g=(1<<d)-1;b[0]=this[c]>>d;for(var h=c+1;h<this.t;++h)b[h-c-1]|=(this[h]&g)<<e,b[h-c]=this[h]>>d;d>0&&(b[this.t-c-1]|=(this.s&g)<<e);b.t=this.t-c;b.clamp()}}
|
||||
function bnpSubTo(a,b){for(var c=0,d=0,e=Math.min(a.t,this.t);c<e;)d+=this[c]-a[c],b[c++]=d&this.DM,d>>=this.DB;if(a.t<this.t){for(d-=a.s;c<this.t;)d+=this[c],b[c++]=d&this.DM,d>>=this.DB;d+=this.s}else{for(d+=this.s;c<a.t;)d-=a[c],b[c++]=d&this.DM,d>>=this.DB;d-=a.s}b.s=d<0?-1:0;d<-1?b[c++]=this.DV+d:d>0&&(b[c++]=d);b.t=c;b.clamp()}
|
||||
function bnpMultiplyTo(a,b){var c=this.abs(),d=a.abs(),e=c.t;for(b.t=e+d.t;--e>=0;)b[e]=0;for(e=0;e<d.t;++e)b[e+c.t]=c.am(0,d[e],b,e,0,c.t);b.s=0;b.clamp();this.s!=a.s&&BigInteger.ZERO.subTo(b,b)}function bnpSquareTo(a){for(var b=this.abs(),c=a.t=2*b.t;--c>=0;)a[c]=0;for(c=0;c<b.t-1;++c){var d=b.am(c,b[c],a,2*c,0,1);if((a[c+b.t]+=b.am(c+1,2*b[c],a,2*c+1,d,b.t-c-1))>=b.DV)a[c+b.t]-=b.DV,a[c+b.t+1]=1}a.t>0&&(a[a.t-1]+=b.am(c,b[c],a,2*c,0,1));a.s=0;a.clamp()}
|
||||
function bnpDivRemTo(a,b,c){var d=a.abs();if(!(d.t<=0)){var e=this.abs();if(e.t<d.t)b!=null&&b.fromInt(0),c!=null&&this.copyTo(c);else{c==null&&(c=nbi());var g=nbi(),h=this.s,a=a.s,f=this.DB-nbits(d[d.t-1]);f>0?(d.lShiftTo(f,g),e.lShiftTo(f,c)):(d.copyTo(g),e.copyTo(c));d=g.t;e=g[d-1];if(e!=0){var o=e*(1<<this.F1)+(d>1?g[d-2]>>this.F2:0),p=this.FV/o,o=(1<<this.F1)/o,q=1<<this.F2,n=c.t,k=n-d,j=b==null?nbi():b;g.dlShiftTo(k,j);c.compareTo(j)>=0&&(c[c.t++]=1,c.subTo(j,c));BigInteger.ONE.dlShiftTo(d,
|
||||
j);for(j.subTo(g,g);g.t<d;)g[g.t++]=0;for(;--k>=0;){var l=c[--n]==e?this.DM:Math.floor(c[n]*p+(c[n-1]+q)*o);if((c[n]+=g.am(0,l,c,k,0,d))<l){g.dlShiftTo(k,j);for(c.subTo(j,c);c[n]<--l;)c.subTo(j,c)}}b!=null&&(c.drShiftTo(d,b),h!=a&&BigInteger.ZERO.subTo(b,b));c.t=d;c.clamp();f>0&&c.rShiftTo(f,c);h<0&&BigInteger.ZERO.subTo(c,c)}}}}function bnMod(a){var b=nbi();this.abs().divRemTo(a,null,b);this.s<0&&b.compareTo(BigInteger.ZERO)>0&&a.subTo(b,b);return b}function Classic(a){this.m=a}
|
||||
function cConvert(a){return a.s<0||a.compareTo(this.m)>=0?a.mod(this.m):a}function cRevert(a){return a}function cReduce(a){a.divRemTo(this.m,null,a)}function cMulTo(a,b,c){a.multiplyTo(b,c);this.reduce(c)}function cSqrTo(a,b){a.squareTo(b);this.reduce(b)}Classic.prototype.convert=cConvert;Classic.prototype.revert=cRevert;Classic.prototype.reduce=cReduce;Classic.prototype.mulTo=cMulTo;Classic.prototype.sqrTo=cSqrTo;
|
||||
function bnpInvDigit(){if(this.t<1)return 0;var a=this[0];if((a&1)==0)return 0;var b=a&3,b=b*(2-(a&15)*b)&15,b=b*(2-(a&255)*b)&255,b=b*(2-((a&65535)*b&65535))&65535,b=b*(2-a*b%this.DV)%this.DV;return b>0?this.DV-b:-b}function Montgomery(a){this.m=a;this.mp=a.invDigit();this.mpl=this.mp&32767;this.mph=this.mp>>15;this.um=(1<<a.DB-15)-1;this.mt2=2*a.t}
|
||||
function montConvert(a){var b=nbi();a.abs().dlShiftTo(this.m.t,b);b.divRemTo(this.m,null,b);a.s<0&&b.compareTo(BigInteger.ZERO)>0&&this.m.subTo(b,b);return b}function montRevert(a){var b=nbi();a.copyTo(b);this.reduce(b);return b}
|
||||
function montReduce(a){for(;a.t<=this.mt2;)a[a.t++]=0;for(var b=0;b<this.m.t;++b){var c=a[b]&32767,d=c*this.mpl+((c*this.mph+(a[b]>>15)*this.mpl&this.um)<<15)&a.DM,c=b+this.m.t;for(a[c]+=this.m.am(0,d,a,b,0,this.m.t);a[c]>=a.DV;)a[c]-=a.DV,a[++c]++}a.clamp();a.drShiftTo(this.m.t,a);a.compareTo(this.m)>=0&&a.subTo(this.m,a)}function montSqrTo(a,b){a.squareTo(b);this.reduce(b)}function montMulTo(a,b,c){a.multiplyTo(b,c);this.reduce(c)}Montgomery.prototype.convert=montConvert;
|
||||
Montgomery.prototype.revert=montRevert;Montgomery.prototype.reduce=montReduce;Montgomery.prototype.mulTo=montMulTo;Montgomery.prototype.sqrTo=montSqrTo;function bnpIsEven(){return(this.t>0?this[0]&1:this.s)==0}function bnpExp(a,b){if(a>4294967295||a<1)return BigInteger.ONE;var c=nbi(),d=nbi(),e=b.convert(this),g=nbits(a)-1;for(e.copyTo(c);--g>=0;)if(b.sqrTo(c,d),(a&1<<g)>0)b.mulTo(d,e,c);else var h=c,c=d,d=h;return b.revert(c)}
|
||||
function bnModPowInt(a,b){var c;c=a<256||b.isEven()?new Classic(b):new Montgomery(b);return this.exp(a,c)}BigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo;BigInteger.prototype.subTo=bnpSubTo;
|
||||
BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpIsEven;BigInteger.prototype.exp=bnpExp;BigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt;
|
||||
BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);function bnClone(){var a=nbi();this.copyTo(a);return a}function bnIntValue(){if(this.s<0)if(this.t==1)return this[0]-this.DV;else{if(this.t==0)return-1}else if(this.t==1)return this[0];else if(this.t==0)return 0;return(this[1]&(1<<32-this.DB)-1)<<this.DB|this[0]}function bnByteValue(){return this.t==0?this.s:this[0]<<24>>24}function bnShortValue(){return this.t==0?this.s:this[0]<<16>>16}
|
||||
function bnpChunkSize(a){return Math.floor(Math.LN2*this.DB/Math.log(a))}function bnSigNum(){return this.s<0?-1:this.t<=0||this.t==1&&this[0]<=0?0:1}function bnpToRadix(a){a==null&&(a=10);if(this.signum()==0||a<2||a>36)return"0";var b=this.chunkSize(a),b=Math.pow(a,b),c=nbv(b),d=nbi(),e=nbi(),g="";for(this.divRemTo(c,d,e);d.signum()>0;)g=(b+e.intValue()).toString(a).substr(1)+g,d.divRemTo(c,d,e);return e.intValue().toString(a)+g}
|
||||
function bnpFromRadix(a,b){this.fromInt(0);b==null&&(b=10);for(var c=this.chunkSize(b),d=Math.pow(b,c),e=!1,g=0,h=0,f=0;f<a.length;++f){var o=intAt(a,f);o<0?a.charAt(f)=="-"&&this.signum()==0&&(e=!0):(h=b*h+o,++g>=c&&(this.dMultiply(d),this.dAddOffset(h,0),h=g=0))}g>0&&(this.dMultiply(Math.pow(b,g)),this.dAddOffset(h,0));e&&BigInteger.ZERO.subTo(this,this)}
|
||||
function bnpFromNumber(a,b,c){if("number"==typeof b)if(a<2)this.fromInt(1);else{this.fromNumber(a,c);this.testBit(a-1)||this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);for(this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(b);)this.dAddOffset(2,0),this.bitLength()>a&&this.subTo(BigInteger.ONE.shiftLeft(a-1),this)}else{var c=[],d=a&7;c.length=(a>>3)+1;b.nextBytes(c);d>0?c[0]&=(1<<d)-1:c[0]=0;this.fromString(c,256)}}
|
||||
function bnToByteArray(){var a=this.t,b=[];b[0]=this.s;var c=this.DB-a*this.DB%8,d,e=0;if(a-- >0){if(c<this.DB&&(d=this[a]>>c)!=(this.s&this.DM)>>c)b[e++]=d|this.s<<this.DB-c;for(;a>=0;)if(c<8?(d=(this[a]&(1<<c)-1)<<8-c,d|=this[--a]>>(c+=this.DB-8)):(d=this[a]>>(c-=8)&255,c<=0&&(c+=this.DB,--a)),(d&128)!=0&&(d|=-256),e==0&&(this.s&128)!=(d&128)&&++e,e>0||d!=this.s)b[e++]=d}return b}function bnEquals(a){return this.compareTo(a)==0}function bnMin(a){return this.compareTo(a)<0?this:a}
|
||||
function bnMax(a){return this.compareTo(a)>0?this:a}function bnpBitwiseTo(a,b,c){var d,e,g=Math.min(a.t,this.t);for(d=0;d<g;++d)c[d]=b(this[d],a[d]);if(a.t<this.t){e=a.s&this.DM;for(d=g;d<this.t;++d)c[d]=b(this[d],e);c.t=this.t}else{e=this.s&this.DM;for(d=g;d<a.t;++d)c[d]=b(e,a[d]);c.t=a.t}c.s=b(this.s,a.s);c.clamp()}function op_and(a,b){return a&b}function bnAnd(a){var b=nbi();this.bitwiseTo(a,op_and,b);return b}function op_or(a,b){return a|b}
|
||||
function bnOr(a){var b=nbi();this.bitwiseTo(a,op_or,b);return b}function op_xor(a,b){return a^b}function bnXor(a){var b=nbi();this.bitwiseTo(a,op_xor,b);return b}function op_andnot(a,b){return a&~b}function bnAndNot(a){var b=nbi();this.bitwiseTo(a,op_andnot,b);return b}function bnNot(){for(var a=nbi(),b=0;b<this.t;++b)a[b]=this.DM&~this[b];a.t=this.t;a.s=~this.s;return a}function bnShiftLeft(a){var b=nbi();a<0?this.rShiftTo(-a,b):this.lShiftTo(a,b);return b}
|
||||
function bnShiftRight(a){var b=nbi();a<0?this.lShiftTo(-a,b):this.rShiftTo(a,b);return b}function lbit(a){if(a==0)return-1;var b=0;(a&65535)==0&&(a>>=16,b+=16);(a&255)==0&&(a>>=8,b+=8);(a&15)==0&&(a>>=4,b+=4);(a&3)==0&&(a>>=2,b+=2);(a&1)==0&&++b;return b}function bnGetLowestSetBit(){for(var a=0;a<this.t;++a)if(this[a]!=0)return a*this.DB+lbit(this[a]);return this.s<0?this.t*this.DB:-1}function cbit(a){for(var b=0;a!=0;)a&=a-1,++b;return b}
|
||||
function bnBitCount(){for(var a=0,b=this.s&this.DM,c=0;c<this.t;++c)a+=cbit(this[c]^b);return a}function bnTestBit(a){var b=Math.floor(a/this.DB);return b>=this.t?this.s!=0:(this[b]&1<<a%this.DB)!=0}function bnpChangeBit(a,b){var c=BigInteger.ONE.shiftLeft(a);this.bitwiseTo(c,b,c);return c}function bnSetBit(a){return this.changeBit(a,op_or)}function bnClearBit(a){return this.changeBit(a,op_andnot)}function bnFlipBit(a){return this.changeBit(a,op_xor)}
|
||||
function bnpAddTo(a,b){for(var c=0,d=0,e=Math.min(a.t,this.t);c<e;)d+=this[c]+a[c],b[c++]=d&this.DM,d>>=this.DB;if(a.t<this.t){for(d+=a.s;c<this.t;)d+=this[c],b[c++]=d&this.DM,d>>=this.DB;d+=this.s}else{for(d+=this.s;c<a.t;)d+=a[c],b[c++]=d&this.DM,d>>=this.DB;d+=a.s}b.s=d<0?-1:0;d>0?b[c++]=d:d<-1&&(b[c++]=this.DV+d);b.t=c;b.clamp()}function bnAdd(a){var b=nbi();this.addTo(a,b);return b}function bnSubtract(a){var b=nbi();this.subTo(a,b);return b}
|
||||
function bnMultiply(a){var b=nbi();this.multiplyTo(a,b);return b}function bnSquare(){var a=nbi();this.squareTo(a);return a}function bnDivide(a){var b=nbi();this.divRemTo(a,b,null);return b}function bnRemainder(a){var b=nbi();this.divRemTo(a,null,b);return b}function bnDivideAndRemainder(a){var b=nbi(),c=nbi();this.divRemTo(a,b,c);return[b,c]}function bnpDMultiply(a){this[this.t]=this.am(0,a-1,this,0,0,this.t);++this.t;this.clamp()}
|
||||
function bnpDAddOffset(a,b){if(a!=0){for(;this.t<=b;)this[this.t++]=0;for(this[b]+=a;this[b]>=this.DV;)this[b]-=this.DV,++b>=this.t&&(this[this.t++]=0),++this[b]}}function NullExp(){}function nNop(a){return a}function nMulTo(a,b,c){a.multiplyTo(b,c)}function nSqrTo(a,b){a.squareTo(b)}NullExp.prototype.convert=nNop;NullExp.prototype.revert=nNop;NullExp.prototype.mulTo=nMulTo;NullExp.prototype.sqrTo=nSqrTo;function bnPow(a){return this.exp(a,new NullExp)}
|
||||
function bnpMultiplyLowerTo(a,b,c){var d=Math.min(this.t+a.t,b);c.s=0;for(c.t=d;d>0;)c[--d]=0;var e;for(e=c.t-this.t;d<e;++d)c[d+this.t]=this.am(0,a[d],c,d,0,this.t);for(e=Math.min(a.t,b);d<e;++d)this.am(0,a[d],c,d,0,b-d);c.clamp()}function bnpMultiplyUpperTo(a,b,c){--b;var d=c.t=this.t+a.t-b;for(c.s=0;--d>=0;)c[d]=0;for(d=Math.max(b-this.t,0);d<a.t;++d)c[this.t+d-b]=this.am(b-d,a[d],c,0,0,this.t+d-b);c.clamp();c.drShiftTo(1,c)}
|
||||
function Barrett(a){this.r2=nbi();this.q3=nbi();BigInteger.ONE.dlShiftTo(2*a.t,this.r2);this.mu=this.r2.divide(a);this.m=a}function barrettConvert(a){if(a.s<0||a.t>2*this.m.t)return a.mod(this.m);else if(a.compareTo(this.m)<0)return a;else{var b=nbi();a.copyTo(b);this.reduce(b);return b}}function barrettRevert(a){return a}
|
||||
function barrettReduce(a){a.drShiftTo(this.m.t-1,this.r2);if(a.t>this.m.t+1)a.t=this.m.t+1,a.clamp();this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);for(this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);a.compareTo(this.r2)<0;)a.dAddOffset(1,this.m.t+1);for(a.subTo(this.r2,a);a.compareTo(this.m)>=0;)a.subTo(this.m,a)}function barrettSqrTo(a,b){a.squareTo(b);this.reduce(b)}function barrettMulTo(a,b,c){a.multiplyTo(b,c);this.reduce(c)}Barrett.prototype.convert=barrettConvert;
|
||||
Barrett.prototype.revert=barrettRevert;Barrett.prototype.reduce=barrettReduce;Barrett.prototype.mulTo=barrettMulTo;Barrett.prototype.sqrTo=barrettSqrTo;
|
||||
function bnModPow(a,b){var c=a.bitLength(),d,e=nbv(1),g;if(c<=0)return e;else d=c<18?1:c<48?3:c<144?4:c<768?5:6;g=c<8?new Classic(b):b.isEven()?new Barrett(b):new Montgomery(b);var h=[],f=3,o=d-1,p=(1<<d)-1;h[1]=g.convert(this);if(d>1){c=nbi();for(g.sqrTo(h[1],c);f<=p;)h[f]=nbi(),g.mulTo(c,h[f-2],h[f]),f+=2}for(var q=a.t-1,n,k=!0,j=nbi(),c=nbits(a[q])-1;q>=0;){c>=o?n=a[q]>>c-o&p:(n=(a[q]&(1<<c+1)-1)<<o-c,q>0&&(n|=a[q-1]>>this.DB+c-o));for(f=d;(n&1)==0;)n>>=1,--f;if((c-=f)<0)c+=this.DB,--q;if(k)h[n].copyTo(e),
|
||||
k=!1;else{for(;f>1;)g.sqrTo(e,j),g.sqrTo(j,e),f-=2;f>0?g.sqrTo(e,j):(f=e,e=j,j=f);g.mulTo(j,h[n],e)}for(;q>=0&&(a[q]&1<<c)==0;)g.sqrTo(e,j),f=e,e=j,j=f,--c<0&&(c=this.DB-1,--q)}return g.revert(e)}
|
||||
function bnGCD(a){var b=this.s<0?this.negate():this.clone(),a=a.s<0?a.negate():a.clone();if(b.compareTo(a)<0)var c=b,b=a,a=c;var c=b.getLowestSetBit(),d=a.getLowestSetBit();if(d<0)return b;c<d&&(d=c);d>0&&(b.rShiftTo(d,b),a.rShiftTo(d,a));for(;b.signum()>0;)(c=b.getLowestSetBit())>0&&b.rShiftTo(c,b),(c=a.getLowestSetBit())>0&&a.rShiftTo(c,a),b.compareTo(a)>=0?(b.subTo(a,b),b.rShiftTo(1,b)):(a.subTo(b,a),a.rShiftTo(1,a));d>0&&a.lShiftTo(d,a);return a}
|
||||
function bnpModInt(a){if(a<=0)return 0;var b=this.DV%a,c=this.s<0?a-1:0;if(this.t>0)if(b==0)c=this[0]%a;else for(var d=this.t-1;d>=0;--d)c=(b*c+this[d])%a;return c}
|
||||
function bnModInverse(a){var b=a.isEven();if(this.isEven()&&b||a.signum()==0)return BigInteger.ZERO;for(var c=a.clone(),d=this.clone(),e=nbv(1),g=nbv(0),h=nbv(0),f=nbv(1);c.signum()!=0;){for(;c.isEven();){c.rShiftTo(1,c);if(b){if(!e.isEven()||!g.isEven())e.addTo(this,e),g.subTo(a,g);e.rShiftTo(1,e)}else g.isEven()||g.subTo(a,g);g.rShiftTo(1,g)}for(;d.isEven();){d.rShiftTo(1,d);if(b){if(!h.isEven()||!f.isEven())h.addTo(this,h),f.subTo(a,f);h.rShiftTo(1,h)}else f.isEven()||f.subTo(a,f);f.rShiftTo(1,
|
||||
f)}c.compareTo(d)>=0?(c.subTo(d,c),b&&e.subTo(h,e),g.subTo(f,g)):(d.subTo(c,d),b&&h.subTo(e,h),f.subTo(g,f))}if(d.compareTo(BigInteger.ONE)!=0)return BigInteger.ZERO;if(f.compareTo(a)>=0)return f.subtract(a);if(f.signum()<0)f.addTo(a,f);else return f;return f.signum()<0?f.add(a):f}
|
||||
var lowprimes=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,
|
||||
733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],lplim=67108864/lowprimes[lowprimes.length-1];
|
||||
function bnIsProbablePrime(a){var b,c=this.abs();if(c.t==1&&c[0]<=lowprimes[lowprimes.length-1]){for(b=0;b<lowprimes.length;++b)if(c[0]==lowprimes[b])return!0;return!1}if(c.isEven())return!1;for(b=1;b<lowprimes.length;){for(var d=lowprimes[b],e=b+1;e<lowprimes.length&&d<lplim;)d*=lowprimes[e++];for(d=c.modInt(d);b<e;)if(d%lowprimes[b++]==0)return!1}return c.millerRabin(a)}
|
||||
function bnpMillerRabin(a){var b=this.subtract(BigInteger.ONE),c=b.getLowestSetBit();if(c<=0)return!1;var d=b.shiftRight(c),a=a+1>>1;if(a>lowprimes.length)a=lowprimes.length;for(var e=nbi(),g=0;g<a;++g){e.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);var h=e.modPow(d,this);if(h.compareTo(BigInteger.ONE)!=0&&h.compareTo(b)!=0){for(var f=1;f++<c&&h.compareTo(b)!=0;)if(h=h.modPowInt(2,this),h.compareTo(BigInteger.ONE)==0)return!1;if(h.compareTo(b)!=0)return!1}}return!0}
|
||||
BigInteger.prototype.chunkSize=bnpChunkSize;BigInteger.prototype.toRadix=bnpToRadix;BigInteger.prototype.fromRadix=bnpFromRadix;BigInteger.prototype.fromNumber=bnpFromNumber;BigInteger.prototype.bitwiseTo=bnpBitwiseTo;BigInteger.prototype.changeBit=bnpChangeBit;BigInteger.prototype.addTo=bnpAddTo;BigInteger.prototype.dMultiply=bnpDMultiply;BigInteger.prototype.dAddOffset=bnpDAddOffset;BigInteger.prototype.multiplyLowerTo=bnpMultiplyLowerTo;BigInteger.prototype.multiplyUpperTo=bnpMultiplyUpperTo;
|
||||
BigInteger.prototype.modInt=bnpModInt;BigInteger.prototype.millerRabin=bnpMillerRabin;BigInteger.prototype.clone=bnClone;BigInteger.prototype.intValue=bnIntValue;BigInteger.prototype.byteValue=bnByteValue;BigInteger.prototype.shortValue=bnShortValue;BigInteger.prototype.signum=bnSigNum;BigInteger.prototype.toByteArray=bnToByteArray;BigInteger.prototype.equals=bnEquals;BigInteger.prototype.min=bnMin;BigInteger.prototype.max=bnMax;BigInteger.prototype.and=bnAnd;BigInteger.prototype.or=bnOr;
|
||||
BigInteger.prototype.xor=bnXor;BigInteger.prototype.andNot=bnAndNot;BigInteger.prototype.not=bnNot;BigInteger.prototype.shiftLeft=bnShiftLeft;BigInteger.prototype.shiftRight=bnShiftRight;BigInteger.prototype.getLowestSetBit=bnGetLowestSetBit;BigInteger.prototype.bitCount=bnBitCount;BigInteger.prototype.testBit=bnTestBit;BigInteger.prototype.setBit=bnSetBit;BigInteger.prototype.clearBit=bnClearBit;BigInteger.prototype.flipBit=bnFlipBit;BigInteger.prototype.add=bnAdd;BigInteger.prototype.subtract=bnSubtract;
|
||||
BigInteger.prototype.multiply=bnMultiply;BigInteger.prototype.divide=bnDivide;BigInteger.prototype.remainder=bnRemainder;BigInteger.prototype.divideAndRemainder=bnDivideAndRemainder;BigInteger.prototype.modPow=bnModPow;BigInteger.prototype.modInverse=bnModInverse;BigInteger.prototype.pow=bnPow;BigInteger.prototype.gcd=bnGCD;BigInteger.prototype.isProbablePrime=bnIsProbablePrime;BigInteger.prototype.square=bnSquare;
|
||||
(function(a,b,c,d,e,g,h){function f(a){var b,d,e=this,g=a.length,f=0,h=e.i=e.j=e.m=0;e.S=[];e.c=[];for(g||(a=[g++]);f<c;)e.S[f]=f++;for(f=0;f<c;f++)b=e.S[f],h=h+b+a[f%g]&c-1,d=e.S[h],e.S[f]=d,e.S[h]=b;e.g=function(a){var b=e.S,d=e.i+1&c-1,g=b[d],f=e.j+g&c-1,h=b[f];b[d]=h;b[f]=g;for(var k=b[g+h&c-1];--a;)d=d+1&c-1,g=b[d],f=f+g&c-1,h=b[f],b[d]=h,b[f]=g,k=k*c+b[g+h&c-1];e.i=d;e.j=f;return k};e.g(c)}function o(a,b,c,d,e){c=[];e=typeof a;if(b&&e=="object")for(d in a)if(d.indexOf("S")<5)try{c.push(o(a[d],
|
||||
b-1))}catch(g){}return c.length?c:a+(e!="string"?"\x00":"")}function p(a,b,d,e){a+="";for(e=d=0;e<a.length;e++){var g=b,f=e&c-1,h=(d^=b[e&c-1]*19)+a.charCodeAt(e);g[f]=h&c-1}a="";for(e in b)a+=String.fromCharCode(b[e]);return a}b.seedrandom=function(q,n){var k=[],j,q=p(o(n?[q,a]:arguments.length?q:[(new Date).getTime(),a,window],3),k);j=new f(k);p(j.S,a);b.random=function(){for(var a=j.g(d),b=h,f=0;a<e;)a=(a+f)*c,b*=c,f=j.g(1);for(;a>=g;)a/=2,b/=2,f>>>=1;return(a+f)/b};return q};h=b.pow(c,d);e=b.pow(2,
|
||||
e);g=e*2;p(b.random(),a)})([],Math,256,6,52);function SeededRandom(){}function SRnextBytes(a){var b;for(b=0;b<a.length;b++)a[b]=Math.floor(Math.random()*256)}SeededRandom.prototype.nextBytes=SRnextBytes;function Arcfour(){this.j=this.i=0;this.S=[]}function ARC4init(a){var b,c,d;for(b=0;b<256;++b)this.S[b]=b;for(b=c=0;b<256;++b)c=c+this.S[b]+a[b%a.length]&255,d=this.S[b],this.S[b]=this.S[c],this.S[c]=d;this.j=this.i=0}
|
||||
function ARC4next(){var a;this.i=this.i+1&255;this.j=this.j+this.S[this.i]&255;a=this.S[this.i];this.S[this.i]=this.S[this.j];this.S[this.j]=a;return this.S[a+this.S[this.i]&255]}Arcfour.prototype.init=ARC4init;Arcfour.prototype.next=ARC4next;function prng_newstate(){return new Arcfour}var rng_psize=256,rng_state,rng_pool,rng_pptr;
|
||||
function rng_seed_int(a){rng_pool[rng_pptr++]^=a&255;rng_pool[rng_pptr++]^=a>>8&255;rng_pool[rng_pptr++]^=a>>16&255;rng_pool[rng_pptr++]^=a>>24&255;rng_pptr>=rng_psize&&(rng_pptr-=rng_psize)}function rng_seed_time(){rng_seed_int((new Date).getTime())}
|
||||
if(rng_pool==null){rng_pool=[];rng_pptr=0;var t;if(navigator.appName=="Netscape"&&navigator.appVersion<"5"&&window.crypto){var z=window.crypto.random(32);for(t=0;t<z.length;++t)rng_pool[rng_pptr++]=z.charCodeAt(t)&255}for(;rng_pptr<rng_psize;)t=Math.floor(65536*Math.random()),rng_pool[rng_pptr++]=t>>>8,rng_pool[rng_pptr++]=t&255;rng_pptr=0;rng_seed_time()}
|
||||
function rng_get_byte(){if(rng_state==null){rng_seed_time();rng_state=prng_newstate();rng_state.init(rng_pool);for(rng_pptr=0;rng_pptr<rng_pool.length;++rng_pptr)rng_pool[rng_pptr]=0;rng_pptr=0}return rng_state.next()}function rng_get_bytes(a){var b;for(b=0;b<a.length;++b)a[b]=rng_get_byte()}function SecureRandom(){}SecureRandom.prototype.nextBytes=rng_get_bytes;
|
||||
function SHA256(a){function b(a,b){var c=(a&65535)+(b&65535);return(a>>16)+(b>>16)+(c>>16)<<16|c&65535}function c(a,b){return a>>>b|a<<32-b}a=function(a){for(var a=a.replace(/\r\n/g,"\n"),b="",c=0;c<a.length;c++){var h=a.charCodeAt(c);h<128?b+=String.fromCharCode(h):(h>127&&h<2048?b+=String.fromCharCode(h>>6|192):(b+=String.fromCharCode(h>>12|224),b+=String.fromCharCode(h>>6&63|128)),b+=String.fromCharCode(h&63|128))}return b}(a);return function(a){for(var b="",c=0;c<a.length*4;c++)b+="0123456789abcdef".charAt(a[c>>
|
||||
2]>>(3-c%4)*8+4&15)+"0123456789abcdef".charAt(a[c>>2]>>(3-c%4)*8&15);return b}(function(a,e){var g=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,
|
||||
2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],h=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],f=Array(64),o,p,q,n,k,j,l,m,s,r,u,w;a[e>>5]|=128<<24-e%32;a[(e+64>>9<<4)+15]=e;for(s=0;s<a.length;s+=16){o=h[0];p=h[1];q=h[2];n=h[3];
|
||||
k=h[4];j=h[5];l=h[6];m=h[7];for(r=0;r<64;r++)f[r]=r<16?a[r+s]:b(b(b(c(f[r-2],17)^c(f[r-2],19)^f[r-2]>>>10,f[r-7]),c(f[r-15],7)^c(f[r-15],18)^f[r-15]>>>3),f[r-16]),u=b(b(b(b(m,c(k,6)^c(k,11)^c(k,25)),k&j^~k&l),g[r]),f[r]),w=b(c(o,2)^c(o,13)^c(o,22),o&p^o&q^p&q),m=l,l=j,j=k,k=b(n,u),n=q,q=p,p=o,o=b(u,w);h[0]=b(o,h[0]);h[1]=b(p,h[1]);h[2]=b(q,h[2]);h[3]=b(n,h[3]);h[4]=b(k,h[4]);h[5]=b(j,h[5]);h[6]=b(l,h[6]);h[7]=b(m,h[7])}return h}(function(a){for(var b=[],c=0;c<a.length*8;c+=8)b[c>>5]|=(a.charCodeAt(c/
|
||||
8)&255)<<24-c%32;return b}(a),a.length*8))}var sha256={hex:function(a){return SHA256(a)}};
|
||||
function SHA1(a){function b(a,b){return a<<b|a>>>32-b}function c(a){var b="",c,d;for(c=7;c>=0;c--)d=a>>>c*4&15,b+=d.toString(16);return b}var d,e,g=Array(80),h=1732584193,f=4023233417,o=2562383102,p=271733878,q=3285377520,n,k,j,l,m,a=function(a){for(var a=a.replace(/\r\n/g,"\n"),b="",c=0;c<a.length;c++){var d=a.charCodeAt(c);d<128?b+=String.fromCharCode(d):(d>127&&d<2048?b+=String.fromCharCode(d>>6|192):(b+=String.fromCharCode(d>>12|224),b+=String.fromCharCode(d>>6&63|128)),b+=String.fromCharCode(d&
|
||||
63|128))}return b}(a);n=a.length;var s=[];for(d=0;d<n-3;d+=4)e=a.charCodeAt(d)<<24|a.charCodeAt(d+1)<<16|a.charCodeAt(d+2)<<8|a.charCodeAt(d+3),s.push(e);switch(n%4){case 0:d=2147483648;break;case 1:d=a.charCodeAt(n-1)<<24|8388608;break;case 2:d=a.charCodeAt(n-2)<<24|a.charCodeAt(n-1)<<16|32768;break;case 3:d=a.charCodeAt(n-3)<<24|a.charCodeAt(n-2)<<16|a.charCodeAt(n-1)<<8|128}for(s.push(d);s.length%16!=14;)s.push(0);s.push(n>>>29);s.push(n<<3&4294967295);for(a=0;a<s.length;a+=16){for(d=0;d<16;d++)g[d]=
|
||||
s[a+d];for(d=16;d<=79;d++)g[d]=b(g[d-3]^g[d-8]^g[d-14]^g[d-16],1);e=h;n=f;k=o;j=p;l=q;for(d=0;d<=19;d++)m=b(e,5)+(n&k|~n&j)+l+g[d]+1518500249&4294967295,l=j,j=k,k=b(n,30),n=e,e=m;for(d=20;d<=39;d++)m=b(e,5)+(n^k^j)+l+g[d]+1859775393&4294967295,l=j,j=k,k=b(n,30),n=e,e=m;for(d=40;d<=59;d++)m=b(e,5)+(n&k|n&j|k&j)+l+g[d]+2400959708&4294967295,l=j,j=k,k=b(n,30),n=e,e=m;for(d=60;d<=79;d++)m=b(e,5)+(n^k^j)+l+g[d]+3395469782&4294967295,l=j,j=k,k=b(n,30),n=e,e=m;h=h+e&4294967295;f=f+n&4294967295;o=o+k&4294967295;
|
||||
p=p+j&4294967295;q=q+l&4294967295}m=c(h)+c(f)+c(o)+c(p)+c(q);return m.toLowerCase()}
|
||||
var sha1={hex:function(a){return SHA1(a)}},MD5=function(a){function b(a,b){var c,d,e,f,g;e=a&2147483648;f=b&2147483648;c=a&1073741824;d=b&1073741824;g=(a&1073741823)+(b&1073741823);return c&d?g^2147483648^e^f:c|d?g&1073741824?g^3221225472^e^f:g^1073741824^e^f:g^e^f}function c(a,c,d,e,f,g,h){a=b(a,b(b(c&d|~c&e,f),h));return b(a<<g|a>>>32-g,c)}function d(a,c,d,e,f,g,h){a=b(a,b(b(c&e|d&~e,f),h));return b(a<<g|a>>>32-g,c)}function e(a,c,d,e,f,g,h){a=b(a,b(b(c^d^e,f),h));return b(a<<g|a>>>32-g,c)}function g(a,
|
||||
c,d,e,f,g,h){a=b(a,b(b(d^(c|~e),f),h));return b(a<<g|a>>>32-g,c)}function h(a){var b="",c="",d;for(d=0;d<=3;d++)c=a>>>d*8&255,c="0"+c.toString(16),b+=c.substr(c.length-2,2);return b}var f=[],o,p,q,n,k,j,l,m,a=function(a){for(var a=a.replace(/\r\n/g,"\n"),b="",c=0;c<a.length;c++){var d=a.charCodeAt(c);d<128?b+=String.fromCharCode(d):(d>127&&d<2048?b+=String.fromCharCode(d>>6|192):(b+=String.fromCharCode(d>>12|224),b+=String.fromCharCode(d>>6&63|128)),b+=String.fromCharCode(d&63|128))}return b}(a),
|
||||
f=function(a){var b,c=a.length;b=c+8;for(var d=((b-b%64)/64+1)*16,e=Array(d-1),f=0,g=0;g<c;)b=(g-g%4)/4,f=g%4*8,e[b]|=a.charCodeAt(g)<<f,g++;e[(g-g%4)/4]|=128<<g%4*8;e[d-2]=c<<3;e[d-1]=c>>>29;return e}(a);k=1732584193;j=4023233417;l=2562383102;m=271733878;for(a=0;a<f.length;a+=16)o=k,p=j,q=l,n=m,k=c(k,j,l,m,f[a+0],7,3614090360),m=c(m,k,j,l,f[a+1],12,3905402710),l=c(l,m,k,j,f[a+2],17,606105819),j=c(j,l,m,k,f[a+3],22,3250441966),k=c(k,j,l,m,f[a+4],7,4118548399),m=c(m,k,j,l,f[a+5],12,1200080426),l=c(l,
|
||||
m,k,j,f[a+6],17,2821735955),j=c(j,l,m,k,f[a+7],22,4249261313),k=c(k,j,l,m,f[a+8],7,1770035416),m=c(m,k,j,l,f[a+9],12,2336552879),l=c(l,m,k,j,f[a+10],17,4294925233),j=c(j,l,m,k,f[a+11],22,2304563134),k=c(k,j,l,m,f[a+12],7,1804603682),m=c(m,k,j,l,f[a+13],12,4254626195),l=c(l,m,k,j,f[a+14],17,2792965006),j=c(j,l,m,k,f[a+15],22,1236535329),k=d(k,j,l,m,f[a+1],5,4129170786),m=d(m,k,j,l,f[a+6],9,3225465664),l=d(l,m,k,j,f[a+11],14,643717713),j=d(j,l,m,k,f[a+0],20,3921069994),k=d(k,j,l,m,f[a+5],5,3593408605),
|
||||
m=d(m,k,j,l,f[a+10],9,38016083),l=d(l,m,k,j,f[a+15],14,3634488961),j=d(j,l,m,k,f[a+4],20,3889429448),k=d(k,j,l,m,f[a+9],5,568446438),m=d(m,k,j,l,f[a+14],9,3275163606),l=d(l,m,k,j,f[a+3],14,4107603335),j=d(j,l,m,k,f[a+8],20,1163531501),k=d(k,j,l,m,f[a+13],5,2850285829),m=d(m,k,j,l,f[a+2],9,4243563512),l=d(l,m,k,j,f[a+7],14,1735328473),j=d(j,l,m,k,f[a+12],20,2368359562),k=e(k,j,l,m,f[a+5],4,4294588738),m=e(m,k,j,l,f[a+8],11,2272392833),l=e(l,m,k,j,f[a+11],16,1839030562),j=e(j,l,m,k,f[a+14],23,4259657740),
|
||||
k=e(k,j,l,m,f[a+1],4,2763975236),m=e(m,k,j,l,f[a+4],11,1272893353),l=e(l,m,k,j,f[a+7],16,4139469664),j=e(j,l,m,k,f[a+10],23,3200236656),k=e(k,j,l,m,f[a+13],4,681279174),m=e(m,k,j,l,f[a+0],11,3936430074),l=e(l,m,k,j,f[a+3],16,3572445317),j=e(j,l,m,k,f[a+6],23,76029189),k=e(k,j,l,m,f[a+9],4,3654602809),m=e(m,k,j,l,f[a+12],11,3873151461),l=e(l,m,k,j,f[a+15],16,530742520),j=e(j,l,m,k,f[a+2],23,3299628645),k=g(k,j,l,m,f[a+0],6,4096336452),m=g(m,k,j,l,f[a+7],10,1126891415),l=g(l,m,k,j,f[a+14],15,2878612391),
|
||||
j=g(j,l,m,k,f[a+5],21,4237533241),k=g(k,j,l,m,f[a+12],6,1700485571),m=g(m,k,j,l,f[a+3],10,2399980690),l=g(l,m,k,j,f[a+10],15,4293915773),j=g(j,l,m,k,f[a+1],21,2240044497),k=g(k,j,l,m,f[a+8],6,1873313359),m=g(m,k,j,l,f[a+15],10,4264355552),l=g(l,m,k,j,f[a+6],15,2734768916),j=g(j,l,m,k,f[a+13],21,1309151649),k=g(k,j,l,m,f[a+4],6,4149444226),m=g(m,k,j,l,f[a+11],10,3174756917),l=g(l,m,k,j,f[a+2],15,718787259),j=g(j,l,m,k,f[a+9],21,3951481745),k=b(k,o),j=b(j,p),l=b(l,q),m=b(m,n);return(h(k)+h(j)+h(l)+
|
||||
h(m)).toLowerCase()};function parseBigInt(a,b){return new BigInteger(a,b)}function linebrk(a,b){for(var c="",d=0;d+b<a.length;)c+=a.substring(d,d+b)+"\n",d+=b;return c+a.substring(d,a.length)}function byte2Hex(a){return a<16?"0"+a.toString(16):a.toString(16)}
|
||||
function pkcs1pad2(a,b){if(b<a.length+11)throw"Message too long for RSA (n="+b+", l="+a.length+")";for(var c=[],d=a.length-1;d>=0&&b>0;){var e=a.charCodeAt(d--);e<128?c[--b]=e:e>127&&e<2048?(c[--b]=e&63|128,c[--b]=e>>6|192):(c[--b]=e&63|128,c[--b]=e>>6&63|128,c[--b]=e>>12|224)}c[--b]=0;d=new SecureRandom;for(e=[];b>2;){for(e[0]=0;e[0]==0;)d.nextBytes(e);c[--b]=e[0]}c[--b]=2;c[--b]=0;return new BigInteger(c)}
|
||||
function RSAKey(){this.n=null;this.e=0;this.coeff=this.dmq1=this.dmp1=this.q=this.p=this.d=null}function RSASetPublic(a,b){a!=null&&b!=null&&a.length>0&&b.length>0?(this.n=parseBigInt(a,16),this.e=parseInt(b,16)):alert("Invalid RSA public key")}function RSADoPublic(a){return a.modPowInt(this.e,this.n)}function RSAEncrypt(a){a=pkcs1pad2(a,this.n.bitLength()+7>>3);if(a==null)return null;a=this.doPublic(a);if(a==null)return null;a=a.toString(16);return(a.length&1)==0?a:"0"+a}
|
||||
RSAKey.prototype.doPublic=RSADoPublic;RSAKey.prototype.setPublic=RSASetPublic;RSAKey.prototype.encrypt=RSAEncrypt;function pkcs1unpad2(a,b){for(var c=a.toByteArray(),d=0;d<c.length&&c[d]==0;)++d;if(c.length-d!=b-1||c[d]!=2)return null;for(++d;c[d]!=0;)if(++d>=c.length)return null;for(var e="";++d<c.length;){var g=c[d]&255;g<128?e+=String.fromCharCode(g):g>191&&g<224?(e+=String.fromCharCode((g&31)<<6|c[d+1]&63),++d):(e+=String.fromCharCode((g&15)<<12|(c[d+1]&63)<<6|c[d+2]&63),d+=2)}return e}
|
||||
function RSASetPrivate(a,b,c){a!=null&&b!=null&&a.length>0&&b.length>0?(this.n=parseBigInt(a,16),this.e=parseInt(b,16),this.d=parseBigInt(c,16)):alert("Invalid RSA private key")}
|
||||
function RSASetPrivateEx(a,b,c,d,e,g,h,f){a!=null&&b!=null&&a.length>0&&b.length>0?(this.n=parseBigInt(a,16),this.e=parseInt(b,16),this.d=parseBigInt(c,16),this.p=parseBigInt(d,16),this.q=parseBigInt(e,16),this.dmp1=parseBigInt(g,16),this.dmq1=parseBigInt(h,16),this.coeff=parseBigInt(f,16)):alert("Invalid RSA private key")}
|
||||
function RSAGenerate(a,b){var c=new SeededRandom,d=a>>1;this.e=parseInt(b,16);for(var e=new BigInteger(b,16);;){for(;;)if(this.p=new BigInteger(a-d,1,c),this.p.subtract(BigInteger.ONE).gcd(e).compareTo(BigInteger.ONE)==0&&this.p.isProbablePrime(10))break;for(;;)if(this.q=new BigInteger(d,1,c),this.q.subtract(BigInteger.ONE).gcd(e).compareTo(BigInteger.ONE)==0&&this.q.isProbablePrime(10))break;if(this.p.compareTo(this.q)<=0){var g=this.p;this.p=this.q;this.q=g}var g=this.p.subtract(BigInteger.ONE),
|
||||
h=this.q.subtract(BigInteger.ONE),f=g.multiply(h);if(f.gcd(e).compareTo(BigInteger.ONE)==0){this.n=this.p.multiply(this.q);this.d=e.modInverse(f);this.dmp1=this.d.mod(g);this.dmq1=this.d.mod(h);this.coeff=this.q.modInverse(this.p);break}}}
|
||||
function RSADoPrivate(a){if(this.p==null||this.q==null)return a.modPow(this.d,this.n);for(var b=a.mod(this.p).modPow(this.dmp1,this.p),a=a.mod(this.q).modPow(this.dmq1,this.q);b.compareTo(a)<0;)b=b.add(this.p);return b.subtract(a).multiply(this.coeff).mod(this.p).multiply(this.q).add(a)}function RSADecrypt(a){a=this.doPrivate(parseBigInt(a,16));return a==null?null:pkcs1unpad2(a,this.n.bitLength()+7>>3)}RSAKey.prototype.doPrivate=RSADoPrivate;RSAKey.prototype.setPrivate=RSASetPrivate;
|
||||
RSAKey.prototype.setPrivateEx=RSASetPrivateEx;RSAKey.prototype.generate=RSAGenerate;RSAKey.prototype.decrypt=RSADecrypt;var _RSASIGN_DIHEAD=[];_RSASIGN_DIHEAD.sha1="3021300906052b0e03021a05000414";_RSASIGN_DIHEAD.sha256="3031300d060960864801650304020105000420";var _RSASIGN_HASHHEXFUNC=[];_RSASIGN_HASHHEXFUNC.sha1=sha1.hex;_RSASIGN_HASHHEXFUNC.sha256=sha256.hex;
|
||||
function _rsasign_getHexPaddedDigestInfoForString(a,b,c){b/=4;for(var a=(0,_RSASIGN_HASHHEXFUNC[c])(a),c="00"+_RSASIGN_DIHEAD[c]+a,a="",b=b-4-c.length,d=0;d<b;d+=2)a+="ff";return sPaddedMessageHex="0001"+a+c}function _rsasign_signString(a,b){var c=_rsasign_getHexPaddedDigestInfoForString(a,this.n.bitLength(),b);return this.doPrivate(parseBigInt(c,16)).toString(16)}
|
||||
function _rsasign_signStringWithSHA1(a){a=_rsasign_getHexPaddedDigestInfoForString(a,this.n.bitLength(),"sha1");return this.doPrivate(parseBigInt(a,16)).toString(16)}function _rsasign_signStringWithSHA256(a){a=_rsasign_getHexPaddedDigestInfoForString(a,this.n.bitLength(),"sha256");return this.doPrivate(parseBigInt(a,16)).toString(16)}function _rsasign_getDecryptSignatureBI(a,b,c){var d=new RSAKey;d.setPublic(b,c);return d.doPublic(a)}
|
||||
function _rsasign_getHexDigestInfoFromSig(a,b,c){return _rsasign_getDecryptSignatureBI(a,b,c).toString(16).replace(/^1f+00/,"")}function _rsasign_getAlgNameAndHashFromHexDisgestInfo(a){for(var b in _RSASIGN_DIHEAD){var c=_RSASIGN_DIHEAD[b],d=c.length;if(a.substring(0,d)==c)return[b,a.substring(d)]}return[]}
|
||||
function _rsasign_verifySignatureWithArgs(a,b,c,d){b=_rsasign_getHexDigestInfoFromSig(b,c,d);c=_rsasign_getAlgNameAndHashFromHexDisgestInfo(b);if(c.length==0)return!1;b=c[1];a=(0,_RSASIGN_HASHHEXFUNC[c[0]])(a);return b==a}function _rsasign_verifyHexSignatureForMessage(a,b){var c=parseBigInt(a,16);return _rsasign_verifySignatureWithArgs(b,c,this.n.toString(16),this.e.toString(16))}
|
||||
function _rsasign_verifyString(a,b){var b=b.replace(/[ \n]+/g,""),c=this.doPublic(parseBigInt(b,16)).toString(16).replace(/^1f+00/,""),d=_rsasign_getAlgNameAndHashFromHexDisgestInfo(c);if(d.length==0)return!1;c=d[1];d=(0,_RSASIGN_HASHHEXFUNC[d[0]])(a);return c==d}RSAKey.prototype.signString=_rsasign_signString;RSAKey.prototype.signStringWithSHA1=_rsasign_signStringWithSHA1;RSAKey.prototype.signStringWithSHA256=_rsasign_signStringWithSHA256;RSAKey.prototype.verifyString=_rsasign_verifyString;
|
||||
RSAKey.prototype.verifyHexSignatureForMessage=_rsasign_verifyHexSignatureForMessage;
|
||||
var aes=function(){var a={Sbox:[99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,205,12,19,236,
|
||||
95,151,68,23,196,167,126,61,100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22],ShiftRowTab:[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11]};a.Init=
|
||||
function(){a.Sbox_Inv=Array(256);for(var b=0;b<256;b++)a.Sbox_Inv[a.Sbox[b]]=b;a.ShiftRowTab_Inv=Array(16);for(b=0;b<16;b++)a.ShiftRowTab_Inv[a.ShiftRowTab[b]]=b;a.xtime=Array(256);for(b=0;b<128;b++)a.xtime[b]=b<<1,a.xtime[128+b]=b<<1^27};a.Done=function(){delete a.Sbox_Inv;delete a.ShiftRowTab_Inv;delete a.xtime};a.ExpandKey=function(b){var c=b.length,d,e=1;switch(c){case 16:d=176;break;case 24:d=208;break;case 32:d=240;break;default:alert("my.ExpandKey: Only key lengths of 16, 24 or 32 bytes allowed!")}for(var g=
|
||||
c;g<d;g+=4){var h=b.slice(g-4,g);if(g%c==0){if(h=[a.Sbox[h[1]]^e,a.Sbox[h[2]],a.Sbox[h[3]],a.Sbox[h[0]]],(e<<=1)>=256)e^=283}else c>24&&g%c==16&&(h=[a.Sbox[h[0]],a.Sbox[h[1]],a.Sbox[h[2]],a.Sbox[h[3]]]);for(var f=0;f<4;f++)b[g+f]=b[g+f-c]^h[f]}};a.Encrypt=function(b,c){var d=c.length;a.AddRoundKey(b,c.slice(0,16));for(var e=16;e<d-16;e+=16)a.SubBytes(b,a.Sbox),a.ShiftRows(b,a.ShiftRowTab),a.MixColumns(b),a.AddRoundKey(b,c.slice(e,e+16));a.SubBytes(b,a.Sbox);a.ShiftRows(b,a.ShiftRowTab);a.AddRoundKey(b,
|
||||
c.slice(e,d))};a.Decrypt=function(b,c){var d=c.length;a.AddRoundKey(b,c.slice(d-16,d));a.ShiftRows(b,a.ShiftRowTab_Inv);a.SubBytes(b,a.Sbox_Inv);for(d-=32;d>=16;d-=16)a.AddRoundKey(b,c.slice(d,d+16)),a.MixColumns_Inv(b),a.ShiftRows(b,a.ShiftRowTab_Inv),a.SubBytes(b,a.Sbox_Inv);a.AddRoundKey(b,c.slice(0,16))};a.SubBytes=function(a,c){for(var d=0;d<16;d++)a[d]=c[a[d]]};a.AddRoundKey=function(a,c){for(var d=0;d<16;d++)a[d]^=c[d]};a.ShiftRows=function(a,c){for(var d=[].concat(a),e=0;e<16;e++)a[e]=d[c[e]]};
|
||||
a.MixColumns=function(b){for(var c=0;c<16;c+=4){var d=b[c+0],e=b[c+1],g=b[c+2],h=b[c+3],f=d^e^g^h;b[c+0]^=f^a.xtime[d^e];b[c+1]^=f^a.xtime[e^g];b[c+2]^=f^a.xtime[g^h];b[c+3]^=f^a.xtime[h^d]}};a.MixColumns_Inv=function(b){for(var c=0;c<16;c+=4){var d=b[c+0],e=b[c+1],g=b[c+2],h=b[c+3],f=d^e^g^h,o=a.xtime[f],p=a.xtime[a.xtime[o^d^g]]^f;f^=a.xtime[a.xtime[o^e^h]];b[c+0]^=p^a.xtime[d^e];b[c+1]^=f^a.xtime[e^g];b[c+2]^=p^a.xtime[g^h];b[c+3]^=f^a.xtime[h^d]}};return a}(),cryptico=function(){var a={};aes.Init();
|
||||
a.b256to64=function(a){var c,d,e,g="",h=0,f=0,o=a.length;for(e=0;e<o;e++)d=a.charCodeAt(e),f==0?(g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>2&63),c=(d&3)<<4):f==1?(g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(c|d>>4&15),c=(d&15)<<2):f==2&&(g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(c|d>>6&3),h+=1,g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d&63)),h+=1,f+=1,f==3&&
|
||||
(f=0);f>0&&(g+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(c),g+="=");f==1&&(g+="=");return g};a.b64to256=function(a){var c,d,e="",g=0,h=0,f=a.length;for(d=0;d<f;d++)c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(a.charAt(d)),c>=0&&(g&&(e+=String.fromCharCode(h|c>>6-g&255)),g=g+2&7,h=c<<g&255);return e};a.b16to64=function(a){var c,d,e="";a.length%2==1&&(a="0"+a);for(c=0;c+3<=a.length;c+=3)d=parseInt(a.substring(c,c+3),16),e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>
|
||||
6)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d&63);c+1==a.length?(d=parseInt(a.substring(c,c+1),16),e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d<<2)):c+2==a.length&&(d=parseInt(a.substring(c,c+2),16),e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(d>>2)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt((d&3)<<4));for(;(e.length&3)>0;)e+="=";return e};a.b64to16=function(a){var c="",
|
||||
d,e=0,g;for(d=0;d<a.length;++d){if(a.charAt(d)=="=")break;v="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(a.charAt(d));v<0||(e==0?(c+=int2char(v>>2),g=v&3,e=1):e==1?(c+=int2char(g<<2|v>>4),g=v&15,e=2):e==2?(c+=int2char(g),c+=int2char(v>>2),g=v&3,e=3):(c+=int2char(g<<2|v>>4),c+=int2char(v&15),e=0))}e==1&&(c+=int2char(g<<2));return c};a.string2bytes=function(a){for(var c=[],d=0;d<a.length;d++)c.push(a.charCodeAt(d));return c};a.bytes2string=function(a){for(var c="",d=0;d<
|
||||
a.length;d++)c+=String.fromCharCode(a[d]);return c};a.blockXOR=function(a,c){for(var d=Array(16),e=0;e<16;e++)d[e]=a[e]^c[e];return d};a.blockIV=function(){var a=new SecureRandom,c=Array(16);a.nextBytes(c);return c};a.pad16=function(a){var c=a.slice(0),d=(16-a.length%16)%16;for(i=a.length;i<a.length+d;i++)c.push(0);return c};a.depad=function(a){for(a=a.slice(0);a[a.length-1]==0;)a=a.slice(0,a.length-1);return a};a.encryptAESCBC=function(b,c){var d=c.slice(0);aes.ExpandKey(d);for(var e=a.string2bytes(b),
|
||||
e=a.pad16(e),g=a.blockIV(),h=0;h<e.length/16;h++){var f=e.slice(h*16,h*16+16),o=g.slice(h*16,h*16+16),f=a.blockXOR(o,f);aes.Encrypt(f,d);g=g.concat(f)}d=a.bytes2string(g);return a.b256to64(d)};a.decryptAESCBC=function(b,c){var d=c.slice(0);aes.ExpandKey(d);for(var b=a.b64to256(b),e=a.string2bytes(b),g=[],h=1;h<e.length/16;h++){var f=e.slice(h*16,h*16+16),o=e.slice((h-1)*16,(h-1)*16+16);aes.Decrypt(f,d);f=a.blockXOR(o,f);g=g.concat(f)}g=a.depad(g);return a.bytes2string(g)};a.wrap60=function(a){for(var c=
|
||||
"",d=0;d<a.length;d++)d%60==0&&d!=0&&(c+="\n"),c+=a[d];return c};a.generateAESKey=function(){var a=Array(16);(new SecureRandom).nextBytes(a);return a};a.generateRSAKey=function(a,c){Math.seedrandom(sha256.hex(a));var d=new RSAKey;d.generate(c,"10001");return d};a.publicKeyString=function(b){return pubkey=b.n.toString(16)};a.publicKeyID=function(a){return MD5(a)};a.publicKeyFromString=function(b){var b=b.split("|")[0],c=new RSAKey;c.setPublic(b,"10001");return c};a.encrypt=function(b,
|
||||
c,d){var e="";try{var h=a.publicKeyFromString(c);e+=h.encrypt(b)+"?"}catch(f){return{status:"Invalid public key"}};return{status:"success",cipher:e}};a.decrypt=function(b,c){var d=b.split("?"),e=c.decrypt(d[0]);return{status:"success",plaintext:e,signature:"unsigned"}};return a}();
|
||||
35
public/vendor/hikvision/encryption/crypto-3.1.2.min.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
CryptoJS v3.1.2
|
||||
code.google.com/p/crypto-js
|
||||
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||
code.google.com/p/crypto-js/wiki/License
|
||||
*/
|
||||
var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
|
||||
r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
|
||||
32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,
|
||||
2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},
|
||||
q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this._doProcessBlock(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);
|
||||
a._data=this._data.clone();return a},_minBufferSize:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},_createHmacHelper:function(a){return function(b,e){return(new n.HMAC.init(a,
|
||||
e)).finalize(b)}}});var n=d.algo={};return d}(Math);
|
||||
(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this._map;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<
|
||||
l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();
|
||||
(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])},
|
||||
_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),
|
||||
f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,
|
||||
m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,
|
||||
E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/
|
||||
4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math);
|
||||
(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,
|
||||
l)}})();
|
||||
CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this._ENC_XFORM_MODE,e,a)},createDecryptor:function(e,a){return this.create(this._DEC_XFORM_MODE,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this._xformMode=e;this._key=a;this.reset()},reset:function(){t.reset.call(this);this._doReset()},process:function(e){this._append(e);return this._process()},
|
||||
finalize:function(e){e&&this._append(e);return this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this._iv;c?this._iv=u:c=this._prevBlock;for(var d=0;d<b;d++)e[a+d]^=
|
||||
c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this._cipher=e;this._iv=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this._prevBlock=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this._cipher,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,
|
||||
e,a,c);this._prevBlock=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a,
|
||||
this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,
|
||||
1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},
|
||||
decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,
|
||||
b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();
|
||||
(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,
|
||||
16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>
|
||||
8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=
|
||||
d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})();
|
||||
2
public/vendor/hikvision/jsPlugin/jquery.min.js
vendored
Normal file
301
public/vendor/hikvision/jsPlugin/jsPlugin-3.0.0.min.js
vendored
Normal file
174
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV1/Decoder.js
vendored
Normal file
21
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3/Decoder.js
vendored
Normal file
BIN
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3/Decoder.wasm
vendored
Normal file
1
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3/Decoder.worker.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason??e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}JSPlayerModule(Module)}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
|
||||
21
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3_NoSIMD/Decoder.js
vendored
Normal file
BIN
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3_NoSIMD/Decoder.wasm
vendored
Normal file
1
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3_NoSIMD/Decoder.worker.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"use strict";var Module={};var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason??e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}JSPlayerModule(Module)}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
|
||||
21
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3_NoWorker/Decoder.js
vendored
Normal file
BIN
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/playctrlV3_NoWorker/Decoder.wasm
vendored
Normal file
1
public/vendor/hikvision/jsPlugin/playctrl/PlayCtrlWasm/wasmplayer.min.js
vendored
Normal file
6630
public/vendor/hikvision/jsPlugin/transform/libSystemTransform.js
vendored
Normal file
BIN
public/vendor/hikvision/jsPlugin/transform/libSystemTransform.wasm
vendored
Normal file
240
public/vendor/hikvision/jsPlugin/transform/systemTransform-worker.js
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
importScripts('libSystemTransform.js');
|
||||
const RECORDRTP = 0; //录制一份未经过转封装的码流原始数据,用于定位问题
|
||||
let dataType = 1;
|
||||
|
||||
// 字母字符串转byte数组
|
||||
function stringToBytes (str) {
|
||||
var ch;
|
||||
var st;
|
||||
var re = [];
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i); // get char
|
||||
st = []; // set up "stack"
|
||||
do {
|
||||
st.push(ch & 0xFF); // push byte to stack
|
||||
ch = ch >> 8; // shift value down by 1 byte
|
||||
}
|
||||
while (ch);
|
||||
// add stack contents to result
|
||||
// done because chars have "wrong" endianness
|
||||
re = re.concat(st.reverse());
|
||||
}
|
||||
// return an array of bytes
|
||||
return re;
|
||||
}
|
||||
|
||||
// 转封装库回调函数
|
||||
self.STCallBack = function (fileIndex, indexLen, data, dataLen) {
|
||||
//stFrameInfo的类型见DETAIL_FRAME_INFO
|
||||
let stFrameInfo = Module._GetDetialFrameInfo();
|
||||
let nIsMp4Index = stFrameInfo.nIsMp4Index;
|
||||
|
||||
//console.log("FrameType is " , stFrameInfo);
|
||||
//console.log("nIsMp4Index is " + nIsMp4Index);
|
||||
//debugger
|
||||
var pData = null;
|
||||
pData = new Uint8Array(dataLen);
|
||||
pData.set(Module.HEAPU8.subarray(data, data + dataLen));
|
||||
if (dataType === 1) {
|
||||
postMessage({ type: "outputData",
|
||||
buf: pData.buffer,
|
||||
dType: 1,
|
||||
frameInfo: stFrameInfo }, [pData.buffer]);
|
||||
dataType = 2;
|
||||
} else {
|
||||
if (nIsMp4Index) {
|
||||
postMessage({ type: "outputData",
|
||||
buf: pData.buffer,
|
||||
dType: 6,
|
||||
frameInfo: stFrameInfo }, [pData.buffer]); //6:索引类型
|
||||
} else {
|
||||
postMessage({ type: "outputData",
|
||||
buf: pData.buffer,
|
||||
dType: 2,
|
||||
frameInfo: stFrameInfo }, [pData.buffer]); //2:码流
|
||||
}
|
||||
}
|
||||
|
||||
//stFrameInfo的类型见DETAIL_FRAME_INFO
|
||||
//let stFrameInfo = Module._GetDetialFrameInfo();
|
||||
//let stFrameType = stFrameInfo.nFrameType;
|
||||
//let nFrameNum = stFrameInfo.nFrameNum;
|
||||
//let nTimeStamp = stFrameInfo.nTimeStamp;
|
||||
//let nIsMp4Index = stFrameInfo.nIsMp4Index;
|
||||
|
||||
//console.log("FrameType is " + stFrameType);
|
||||
//console.log("nIsMp4Index is " + nIsMp4Index);
|
||||
};
|
||||
|
||||
// self.Module = { memoryInitializerRequest: loadMemInitFile(), TOTAL_MEMORY: 128*1024*1024 };
|
||||
// importScripts('SystemTransform.js');
|
||||
|
||||
self.Module['onRuntimeInitialized'] = function () {
|
||||
postMessage({type: "loaded"});
|
||||
};
|
||||
onmessage = function (e) {
|
||||
var data = e.data;
|
||||
if ("create" === data.type) {
|
||||
if (RECORDRTP) {
|
||||
postMessage({ type: "created" });
|
||||
postMessage({ type: "outputData",
|
||||
buf: data.buf,
|
||||
dType: 1 }, [data.buf]);
|
||||
} else {
|
||||
var iHeadLen = data.len;
|
||||
var pHead = Module._malloc(iHeadLen);
|
||||
if (pHead === null) {
|
||||
console.log("inputdata malloc failed!!!");
|
||||
return -1;
|
||||
}
|
||||
var iTransType = data.packType;//目标格式
|
||||
var iRet = 0;
|
||||
var buf = new Uint8Array(data.buf);
|
||||
//PS流(只有ps支持探测),并且编码格式异常(正常是265和264,11位和10位 不可能全是0,全0 并且是ps就探测策略)的情况下,使用探测策略
|
||||
if (buf[9] === 0 && buf[8] === 2 && buf[11] === 0 && buf[10] === 0) {
|
||||
iRet = Module._CreatHandle(0, iTransType, iHeadLen); //用探测的策略
|
||||
} else {
|
||||
self.writeArrayToMemory(buf, pHead);
|
||||
iRet = Module._CreatHandle(pHead, iTransType, iHeadLen);
|
||||
//-2147483645代表的是参数错误,此种情况,大概率发生在头信息错误,例如大华设备的情况,此时用 无头探测的策略
|
||||
//其他情况 按海康标准处理流程,不要做任何特殊处理
|
||||
if (iRet == -2147483645) {
|
||||
iRet = Module._CreatHandle(0, iTransType, iHeadLen); //失败了,用探测的策略再试一次
|
||||
}
|
||||
}
|
||||
if (iRet != 0) {
|
||||
if (iRet == -2147483647) {
|
||||
postMessage({ type: "outputData",
|
||||
dType: 1501 }); //标记为格式不支持
|
||||
} else {
|
||||
postMessage({ type: "outputData",
|
||||
dType: 1501 }); //转封装创建失败,也同样提示码流格式不支持,如果后续要细化再区分
|
||||
}
|
||||
console.log("_CreatHandle failed!" + iRet);
|
||||
} else {
|
||||
if (data.options && typeof data.options.pKeyData !== "undefined" && data.options.pKeyData !== null) {
|
||||
if ((2 === iTransType && "" === data.options.pKeyData)) {
|
||||
//转ps的时候,如果密码是空是允许的,即使码流加密了,导出加密后的码流就行
|
||||
//此时不要设置密码否则反而会提示密码错误
|
||||
} else {
|
||||
var secretInfo = data.options;
|
||||
var keyLen = secretInfo.nKeyLen;
|
||||
var pKeyData = Module._malloc(keyLen);
|
||||
if (pKeyData === null) {
|
||||
console.log("setEncryptKey malloc failed!!!");
|
||||
return -1;
|
||||
}
|
||||
var nKeySize = secretInfo.pKeyData.length;
|
||||
var bufData = stringToBytes(secretInfo.pKeyData);
|
||||
|
||||
let inputData = new Uint8Array(bufData);
|
||||
Module.writeArrayToMemory(inputData, pKeyData);
|
||||
inputData = null;
|
||||
|
||||
iRet = Module._SysTransSetEncryptKey(secretInfo.nKeyType, pKeyData, keyLen, nKeySize);
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransSetEncryptKey failed!");
|
||||
}
|
||||
if (pKeyData != null) {
|
||||
Module._free(pKeyData);
|
||||
pKeyData = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
//带samplingParam参数,代表需要 用到 音频替换功能
|
||||
if (data.options && typeof data.options.samplingParam !== "undefined") {
|
||||
var oParam = data.options.samplingParam;
|
||||
var nCapacityType = 1; //写死1 代表 剔除音频
|
||||
var nType = 3; //写死3 代表 修改输出目标的海康头配置,内部包含视频参数、音频参数
|
||||
var nAudioEnable = 1; //音频参数修改使能开关,0=不启用,1=启用
|
||||
var nAudioFormat = oParam.iAudioType; //音频编码类型 对应关系参考海康媒体头规范,PCM 0x7001 G711_U 0x7110 G711_A 0x7111 AAC 0x2001
|
||||
var nAudioChannels = oParam.iChannel; //音频通道数直接设置为
|
||||
var nAudioBitsPerSample = oParam.iAudioBitWidth; //音频位样率
|
||||
var nAudioSamplesrate = oParam.iAudioSamplingRate; //音频采样率
|
||||
var nAudioBitrate = oParam.iAudioBitRate; //音频比特率
|
||||
iRet = Module._SysTransConfig(nCapacityType, nType, nAudioEnable, nAudioFormat,
|
||||
nAudioChannels, nAudioBitsPerSample, nAudioSamplesrate, nAudioBitrate);
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransConfig Failed:" + iRet);
|
||||
}
|
||||
} else {
|
||||
iRet = Module._SysTransConfig(128, 0, 0, 0, 0, 0, 0, 0); //nCapacityType = 0x00000080 代表开启私有信息回调 解决转mp4后,私有信息丢失问题
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransConfig Failed:" + iRet);
|
||||
}
|
||||
}
|
||||
iRet = Module._SysTransRegisterDataCallBack();
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransRegisterDataCallBack Failed:" + iRet);
|
||||
}
|
||||
|
||||
iRet = Module._SysTransStart(null, null);
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransStart Failed:" + iRet);
|
||||
}
|
||||
postMessage({type: "created"});
|
||||
}
|
||||
if (pHead != null) {
|
||||
Module._free(pHead);
|
||||
pHead = null;
|
||||
}
|
||||
}
|
||||
} else if ("inputData" === data.type) {
|
||||
if (RECORDRTP) {
|
||||
var aFileData = new Uint8Array(data.buf); // 拷贝一份
|
||||
var iBufferLen = aFileData.length;
|
||||
var szBufferLen = iBufferLen.toString(16);
|
||||
if (szBufferLen.length === 1) {
|
||||
szBufferLen = "000" + szBufferLen;
|
||||
} else if (szBufferLen.length === 2) {
|
||||
szBufferLen = "00" + szBufferLen;
|
||||
} else if (szBufferLen.length === 3) {
|
||||
szBufferLen = "0" + szBufferLen;
|
||||
}
|
||||
var aData = [0, 0, parseInt(szBufferLen.substring(0, 2), 16), parseInt(szBufferLen.substring(2, 4), 16)];
|
||||
for (var iIndex = 0, iDataLength = aFileData.length; iIndex < iDataLength; iIndex++) {
|
||||
aData[iIndex + 4] = aFileData[iIndex];
|
||||
}
|
||||
var dataUint8 = new Uint8Array(aData);
|
||||
postMessage({type: "outputData",
|
||||
buf: dataUint8.buffer,
|
||||
dType: 2});
|
||||
} else {
|
||||
let inputMode = 0; //代表输入原始数据
|
||||
if (data.samplingParam) {
|
||||
iRet = Module._SysTransInputAudioPara(5, data.samplingParam.iChannel, data.samplingParam.iAudioBitWidth,
|
||||
data.samplingParam.iAudioSamplingRate, data.samplingParam.iTimeStamp, data.samplingParam.iAudioBitRate); //参数含义和_SysTransConfig类似
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransInputAudioPara Failed:" + iRet);
|
||||
}
|
||||
inputMode = 2; //输入替换的音频
|
||||
}
|
||||
var pInputDataBuf = Module._malloc(data.len);
|
||||
var idataLen = data.len;
|
||||
self.writeArrayToMemory(new Uint8Array(data.buf), pInputDataBuf);
|
||||
// 输入数据,每次最多2m
|
||||
let pp = Module._SysTransInputData(inputMode, pInputDataBuf, idataLen);
|
||||
if (pp == -2147483627) {
|
||||
//-2147483627 对应十六进制的80000015
|
||||
postMessage({ type: "outputData",
|
||||
dType: 1500 }); //标记为密码错误
|
||||
} else if (pp == -2147483647) {
|
||||
postMessage({ type: "outputData",
|
||||
dType: 1501 }); //标记为格式不支持
|
||||
} else if (pp != 0) {
|
||||
console.log("InputData Failed:" + pp);
|
||||
}
|
||||
Module._free(pInputDataBuf);
|
||||
}
|
||||
} else if ("release" === data.type) {
|
||||
var iRet = Module._SysTransStop();
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransStop failed!");
|
||||
}
|
||||
Module._SysTransRelease();
|
||||
if (iRet != 0) {
|
||||
console.log("_SysTransRelease failed!");
|
||||
}
|
||||
close();
|
||||
}
|
||||
};
|
||||
1
public/vendor/hikvision/webVideoCtrl.js
vendored
Normal file
@@ -1,24 +0,0 @@
|
||||
import { AxiosProgressEvent } from 'axios'
|
||||
import { request } from '@/api/request'
|
||||
|
||||
/** 上传文件 */
|
||||
const FtsUpload = (data: FormData, onUploadProgress?: (progress: number) => void) => {
|
||||
data.append('provider', 'local')
|
||||
data.append('bucket', 'visual')
|
||||
|
||||
return request.post(`/Assets/v1/fts/uploader`, data, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
onUploadProgress: onUploadProgress
|
||||
? (progressEvent: AxiosProgressEvent) => {
|
||||
if (progressEvent.total) {
|
||||
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
|
||||
onUploadProgress(percentCompleted)
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
|
||||
export default FtsUpload
|
||||
@@ -1,93 +1,86 @@
|
||||
import { request } from '@/api/request'
|
||||
import type { KbReply } from './types'
|
||||
|
||||
/** 分类类型 */
|
||||
/** 公共分类状态。 */
|
||||
export type CategoryStatus = 'active' | 'inactive'
|
||||
|
||||
/** 公共分类。 */
|
||||
export interface Category {
|
||||
id: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
name: string
|
||||
description: string
|
||||
type: string
|
||||
type: 'general'
|
||||
icon: string
|
||||
color: string
|
||||
parent_id: number
|
||||
level: number
|
||||
level: 1 | 2 | 3
|
||||
path: string
|
||||
sort_order: number
|
||||
status: string
|
||||
status: CategoryStatus
|
||||
creator_id: number
|
||||
creator_name: string
|
||||
doc_count: number
|
||||
faq_count: number
|
||||
metadata: string | null
|
||||
metadata: string
|
||||
remarks: string
|
||||
}
|
||||
|
||||
/** API响应包装类型 */
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
/** 公共分类树节点;详情字段需通过详情接口获取。 */
|
||||
export interface CategoryTreeNode {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
type: 'general'
|
||||
icon: string
|
||||
color: string
|
||||
parent_id: number
|
||||
level: 1 | 2 | 3
|
||||
path: string
|
||||
sort_order: number
|
||||
status: CategoryStatus
|
||||
doc_count: number
|
||||
faq_count: number
|
||||
children: CategoryTreeNode[]
|
||||
}
|
||||
|
||||
/** 创建分类请求参数 */
|
||||
/** 创建分类参数。 */
|
||||
export interface CreateCategoryParams {
|
||||
name: string
|
||||
description?: string
|
||||
type?: string
|
||||
icon?: string
|
||||
color?: string
|
||||
parent_id?: number
|
||||
sort_order?: number
|
||||
remarks?: string
|
||||
description: string
|
||||
icon: string
|
||||
color: string
|
||||
parent_id: number
|
||||
sort_order: number
|
||||
status: CategoryStatus
|
||||
remarks: string
|
||||
}
|
||||
|
||||
/** 更新分类请求参数 */
|
||||
export interface UpdateCategoryParams {
|
||||
/** 更新分类参数。 */
|
||||
export interface UpdateCategoryParams extends CreateCategoryParams {
|
||||
id: number
|
||||
name?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
color?: string
|
||||
sort_order?: number
|
||||
status?: string
|
||||
remarks?: string
|
||||
}
|
||||
|
||||
/** 获取分类列表参数 */
|
||||
/** 分类列表参数。 */
|
||||
export interface FetchCategoryListParams {
|
||||
type?: string
|
||||
parent_id?: number
|
||||
}
|
||||
|
||||
/** 创建分类 */
|
||||
export const createCategory = (data: CreateCategoryParams) => {
|
||||
return request.post<ApiResponse<Category>>('/Kb/v1/category/create', data)
|
||||
}
|
||||
/** 创建公共分类。 */
|
||||
export const createCategory = (data: CreateCategoryParams) => request.post<KbReply<Category>>('/Kb/v1/category/create', data)
|
||||
|
||||
/** 更新分类 */
|
||||
export const updateCategory = (data: UpdateCategoryParams) => {
|
||||
return request.post<ApiResponse<Category>>('/Kb/v1/category/update', data)
|
||||
}
|
||||
/** 更新公共分类。 */
|
||||
export const updateCategory = (data: UpdateCategoryParams) => request.post<KbReply<Category>>('/Kb/v1/category/update', data)
|
||||
|
||||
/** 删除分类 */
|
||||
export const deleteCategory = (id: number) => {
|
||||
return request.delete<ApiResponse<string>>(`/Kb/v1/category/${id}`)
|
||||
}
|
||||
/** 删除公共分类。 */
|
||||
export const deleteCategory = (id: number) => request.delete<KbReply<string>>(`/Kb/v1/category/${id}`)
|
||||
|
||||
/** 获取分类详情 */
|
||||
export const fetchCategoryDetail = (id: number) => {
|
||||
return request.get<ApiResponse<Category>>(`/Kb/v1/category/${id}`)
|
||||
}
|
||||
/** 获取公共分类详情。 */
|
||||
export const fetchCategoryDetail = (id: number) => request.get<KbReply<Category>>(`/Kb/v1/category/${id}`)
|
||||
|
||||
/** 获取分类列表 */
|
||||
export const fetchCategoryList = (params?: FetchCategoryListParams) => {
|
||||
return request.get<ApiResponse<Category[]>>('/Kb/v1/category/list', { params })
|
||||
}
|
||||
/** 获取公共分类列表。 */
|
||||
export const fetchCategoryList = (params?: FetchCategoryListParams) => request.get<KbReply<Category[]>>('/Kb/v1/category/list', { params })
|
||||
|
||||
/** 获取分类树 */
|
||||
export const fetchCategoryTree = (type?: string) => {
|
||||
return request.get<ApiResponse<Category[]>>('/Kb/v1/category/tree', {
|
||||
params: type ? { type } : undefined,
|
||||
})
|
||||
}
|
||||
/** 获取完整公共分类树,包含停用节点。 */
|
||||
export const fetchCategoryTree = () => request.get<KbReply<CategoryTreeNode[]>>('/Kb/v1/category/tree')
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { request } from '@/api/request'
|
||||
import type { KbReply } from './types'
|
||||
|
||||
/** 文档状态 */
|
||||
/** 文档状态。 */
|
||||
export type DocumentStatus = 'draft' | 'published' | 'reviewed' | 'rejected'
|
||||
|
||||
/** 文档类型 */
|
||||
/** 文档类型。 */
|
||||
export type DocumentType = 'common' | 'guide' | 'solution' | 'troubleshoot' | 'process' | 'technical'
|
||||
/** 文档列表范围。 */
|
||||
export type DocumentScope = 'my' | 'all'
|
||||
|
||||
/** 文档接口类型 */
|
||||
/** 文档资源。 */
|
||||
export interface Document {
|
||||
id: number
|
||||
created_at: string
|
||||
@@ -33,71 +35,54 @@ export interface Document {
|
||||
version: string
|
||||
version_notes: string
|
||||
tags: string
|
||||
attachments: string | null
|
||||
related_docs: string | null
|
||||
detection_point_ids: string | null
|
||||
metadata: string | null
|
||||
attachments: string
|
||||
related_docs: string
|
||||
detection_point_ids: string
|
||||
metadata: string
|
||||
keywords: string
|
||||
remarks: string
|
||||
is_favorited?: boolean
|
||||
is_favorited: boolean
|
||||
}
|
||||
|
||||
/** API响应包装类型 */
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
|
||||
/** 分页响应类型 */
|
||||
export interface PaginatedResponse<T> {
|
||||
/** 文档分页结果。 */
|
||||
export interface DocumentPage {
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
data: T[]
|
||||
data: Document[]
|
||||
}
|
||||
|
||||
/** 创建文档请求参数 */
|
||||
/** 文档创建字段。 */
|
||||
export interface CreateDocumentParams {
|
||||
title: string
|
||||
description?: string
|
||||
description: string
|
||||
content: string
|
||||
type?: DocumentType
|
||||
category_id?: number
|
||||
sub_category?: string
|
||||
keywords?: string
|
||||
tags?: string
|
||||
detection_point_ids?: string
|
||||
remarks?: string
|
||||
type: DocumentType
|
||||
category_id: number
|
||||
sub_category: string
|
||||
keywords: string
|
||||
tags: string
|
||||
detection_point_ids: string
|
||||
remarks: string
|
||||
}
|
||||
|
||||
/** 更新文档请求参数 */
|
||||
export interface UpdateDocumentParams {
|
||||
/** 文档编辑字段。 */
|
||||
export interface UpdateDocumentParams extends CreateDocumentParams {
|
||||
id: number
|
||||
title?: string
|
||||
description?: string
|
||||
content?: string
|
||||
type?: DocumentType
|
||||
category_id?: number
|
||||
sub_category?: string
|
||||
keywords?: string
|
||||
tags?: string
|
||||
detection_point_ids?: string
|
||||
remarks?: string
|
||||
}
|
||||
|
||||
/** 获取文档列表参数 */
|
||||
/** 文档列表参数。 */
|
||||
export interface FetchDocumentListParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
scope?: DocumentScope
|
||||
keyword?: string
|
||||
type?: DocumentType
|
||||
status?: DocumentStatus
|
||||
category_id?: number
|
||||
}
|
||||
|
||||
/** 文档类型选项 */
|
||||
export const documentTypeOptions = [
|
||||
export const documentTypeOptions: Array<{ label: string; value: DocumentType }> = [
|
||||
{ label: '通用文档', value: 'common' },
|
||||
{ label: '操作指南', value: 'guide' },
|
||||
{ label: '解决方案', value: 'solution' },
|
||||
@@ -106,115 +91,28 @@ export const documentTypeOptions = [
|
||||
{ label: '技术文档', value: 'technical' },
|
||||
]
|
||||
|
||||
/** 文档状态选项 */
|
||||
export const documentStatusOptions = [
|
||||
{ label: '草稿', value: 'draft' },
|
||||
{ label: '已发布', value: 'published' },
|
||||
{ label: '已审核', value: 'reviewed' },
|
||||
{ label: '未通过审核', value: 'rejected' },
|
||||
]
|
||||
/** 创建文档草稿。 */
|
||||
export const createDocument = (data: CreateDocumentParams) => request.post<KbReply<Document>>('/Kb/v1/document/create', data)
|
||||
|
||||
/** 获取文档状态文本 */
|
||||
export const getDocumentStatusText = (status: DocumentStatus): string => {
|
||||
const statusMap: Record<DocumentStatus, string> = {
|
||||
draft: '草稿',
|
||||
published: '已发布',
|
||||
reviewed: '已审核',
|
||||
rejected: '未通过审核',
|
||||
}
|
||||
return statusMap[status] || status
|
||||
}
|
||||
/** 更新文档。 */
|
||||
export const updateDocument = (data: UpdateDocumentParams) => request.post<KbReply<Document>>('/Kb/v1/document/update', data)
|
||||
|
||||
/** 获取文档状态颜色 */
|
||||
export const getDocumentStatusColor = (status: DocumentStatus): string => {
|
||||
const colorMap: Record<DocumentStatus, string> = {
|
||||
draft: 'gray',
|
||||
published: 'blue',
|
||||
reviewed: 'green',
|
||||
rejected: 'red',
|
||||
}
|
||||
return colorMap[status] || 'gray'
|
||||
}
|
||||
/** 删除文档并移入回收站。 */
|
||||
export const deleteDocument = (id: number) => request.delete<KbReply<string>>(`/Kb/v1/document/${id}`)
|
||||
|
||||
/** 获取文档类型文本 */
|
||||
export const getDocumentTypeText = (type: DocumentType): string => {
|
||||
const typeMap: Record<DocumentType, string> = {
|
||||
common: '通用文档',
|
||||
guide: '操作指南',
|
||||
solution: '解决方案',
|
||||
troubleshoot: '故障排查',
|
||||
process: '流程规范',
|
||||
technical: '技术文档',
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
/** 获取文档详情。 */
|
||||
export const fetchDocumentDetail = (id: number) => request.get<KbReply<Document>>(`/Kb/v1/document/${id}`)
|
||||
|
||||
/** 创建文档 */
|
||||
export const createDocument = (data: CreateDocumentParams) => {
|
||||
return request.post<ApiResponse<Document>>('/Kb/v1/document/create', data)
|
||||
}
|
||||
/** 获取指定可见范围的文档列表。 */
|
||||
export const fetchDocumentList = (params: FetchDocumentListParams) => request.get<KbReply<DocumentPage>>('/Kb/v1/document/list', { params })
|
||||
|
||||
/** 更新文档 */
|
||||
export const updateDocument = (data: UpdateDocumentParams) => {
|
||||
return request.post<ApiResponse<Document>>('/Kb/v1/document/update', data)
|
||||
}
|
||||
/** 提交文档审核。 */
|
||||
export const publishDocument = (id: number) => request.post<KbReply<string>>('/Kb/v1/document/publish', { id })
|
||||
|
||||
/** 删除文档(移入回收站) */
|
||||
export const deleteDocument = (id: number) => {
|
||||
return request.delete<ApiResponse<string>>(`/Kb/v1/document/${id}`)
|
||||
}
|
||||
/** 收藏文档。 */
|
||||
export const favoriteDocument = (id: number) =>
|
||||
request.post<KbReply<unknown>>('/Kb/v1/favorite/collect', { resource_type: 'document', resource_id: id })
|
||||
|
||||
/** 获取文档详情 */
|
||||
export const fetchDocumentDetail = (id: number) => {
|
||||
return request.get<ApiResponse<Document>>(`/Kb/v1/document/${id}`)
|
||||
}
|
||||
|
||||
/** 获取文档列表 */
|
||||
export const fetchDocumentList = (params?: FetchDocumentListParams) => {
|
||||
return request.get<ApiResponse<PaginatedResponse<Document>>>('/Kb/v1/document/list', { params })
|
||||
}
|
||||
|
||||
/** 发布文档 */
|
||||
export const publishDocument = (id: number) => {
|
||||
return request.post<ApiResponse<string>>('/Kb/v1/document/publish', { id })
|
||||
}
|
||||
|
||||
/** 移入回收站 */
|
||||
export const moveToTrash = (resourceId: number, resourceType: string) => {
|
||||
return request.post<ApiResponse<string>>('/Kb/v1/trash/move', {
|
||||
resource_id: resourceId,
|
||||
resource_type: resourceType,
|
||||
})
|
||||
}
|
||||
|
||||
/** 获取我的文档列表(由我创建的所有文档) */
|
||||
export const fetchMyDocumentList = (params?: FetchDocumentListParams) => {
|
||||
return request.get<ApiResponse<PaginatedResponse<Document>>>('/Kb/v1/review/publish/list', { params })
|
||||
}
|
||||
|
||||
/** 获取已审核通过的文档列表 */
|
||||
export const fetchApprovedDocumentList = (params?: FetchDocumentListParams) => {
|
||||
return request.get<ApiResponse<PaginatedResponse<Document>>>('/Kb/v1/review/approved/list', { params })
|
||||
}
|
||||
|
||||
/** 收藏文档 */
|
||||
export const favoriteDocument = (id: number, remarks?: string) => {
|
||||
return request.post<ApiResponse<string>>('/Kb/v1/favorite/collect', {
|
||||
resource_type: 'document',
|
||||
resource_id: id,
|
||||
remarks,
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消收藏文档 */
|
||||
export const unfavoriteDocument = (id: number) => {
|
||||
return request.post<ApiResponse<string>>('/Kb/v1/favorite/uncollect', {
|
||||
resource_type: 'document',
|
||||
resource_id: id,
|
||||
})
|
||||
}
|
||||
|
||||
/** 下载文档 */
|
||||
export const downloadDocument = (id: number) => {
|
||||
return request.get<Blob>(`/Kb/v1/document/${id}/download`, { responseType: 'blob' })
|
||||
}
|
||||
/** 取消收藏文档。 */
|
||||
export const unfavoriteDocument = (id: number) =>
|
||||
request.post<KbReply<string>>('/Kb/v1/favorite/uncollect', { resource_type: 'document', resource_id: id })
|
||||
|
||||
177
src/api/kb/faq.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import { request } from '@/api/request'
|
||||
import type { KbReply } from './types'
|
||||
|
||||
export { fetchCategoryTree as fetchGeneralCategoryTree } from './category'
|
||||
export type { CategoryTreeNode } from './category'
|
||||
export type { KbReply } from './types'
|
||||
|
||||
/** FAQ 审核状态。 */
|
||||
export type FaqStatus = 'draft' | 'published' | 'reviewed' | 'rejected'
|
||||
/** FAQ 优先级。 */
|
||||
export type FaqPriority = 'low' | 'medium' | 'high'
|
||||
/** FAQ 列表可见范围。 */
|
||||
export type FaqScope = 'my' | 'all'
|
||||
|
||||
/** FAQ 资源。 */
|
||||
export interface Faq {
|
||||
id: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
faq_no: string
|
||||
question: string
|
||||
answer: string
|
||||
status: FaqStatus
|
||||
priority: FaqPriority
|
||||
category_id: number
|
||||
sub_category: string
|
||||
problem_type: string
|
||||
solution: string
|
||||
process_steps: string
|
||||
prerequisites: string
|
||||
author_id: number
|
||||
author_name: string
|
||||
reviewer_id: number
|
||||
reviewer_name: string
|
||||
reviewed_at: string | null
|
||||
published_at: string | null
|
||||
view_count: number
|
||||
use_count: number
|
||||
helpful_count: number
|
||||
useless_count: number
|
||||
tags: string
|
||||
related_faqs: string
|
||||
related_docs: string
|
||||
related_links: string
|
||||
detection_point_ids: string
|
||||
attachments: string
|
||||
keywords: string
|
||||
applicable_scope: string
|
||||
remarks: string
|
||||
is_favorited: boolean
|
||||
}
|
||||
|
||||
/** FAQ 分页结果。 */
|
||||
export interface FaqPage {
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
data: Faq[]
|
||||
}
|
||||
|
||||
/** FAQ 列表查询参数。 */
|
||||
export interface FaqListParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
scope?: FaqScope
|
||||
keyword?: string
|
||||
category_id?: number
|
||||
status?: FaqStatus
|
||||
priority?: FaqPriority
|
||||
problem_type?: string
|
||||
}
|
||||
|
||||
/** FAQ 创建和编辑字段。 */
|
||||
export interface FaqFormData {
|
||||
question: string
|
||||
answer: string
|
||||
priority: FaqPriority
|
||||
category_id: number
|
||||
sub_category: string
|
||||
problem_type: string
|
||||
solution: string
|
||||
process_steps: string
|
||||
prerequisites: string
|
||||
keywords: string
|
||||
tags: string
|
||||
detection_point_ids: string
|
||||
applicable_scope: string
|
||||
remarks: string
|
||||
}
|
||||
|
||||
/** FAQ 编辑请求。 */
|
||||
export interface UpdateFaqData extends FaqFormData {
|
||||
id: number
|
||||
}
|
||||
|
||||
/** FAQ 状态筛选项。 */
|
||||
export const faqStatusOptions: Array<{ label: string; value: FaqStatus }> = [
|
||||
{ label: '草稿', value: 'draft' },
|
||||
{ label: '待审核', value: 'published' },
|
||||
{ label: '已审核', value: 'reviewed' },
|
||||
{ label: '已拒绝', value: 'rejected' },
|
||||
]
|
||||
|
||||
/** FAQ 优先级筛选项。 */
|
||||
export const faqPriorityOptions: Array<{ label: string; value: FaqPriority }> = [
|
||||
{ label: '低', value: 'low' },
|
||||
{ label: '中', value: 'medium' },
|
||||
{ label: '高', value: 'high' },
|
||||
]
|
||||
|
||||
/** 常用问题类型;接口仍允许自由字符串。 */
|
||||
export const faqProblemTypeOptions = [
|
||||
{ label: '故障', value: '故障' },
|
||||
{ label: '咨询', value: '咨询' },
|
||||
{ label: '请求', value: '请求' },
|
||||
{ label: '其他', value: '其他' },
|
||||
]
|
||||
|
||||
const faqStatusMeta: Record<FaqStatus, { text: string; color: string }> = {
|
||||
draft: { text: '草稿', color: 'gray' },
|
||||
published: { text: '待审核', color: 'orange' },
|
||||
reviewed: { text: '已审核', color: 'green' },
|
||||
rejected: { text: '已拒绝', color: 'red' },
|
||||
}
|
||||
|
||||
const faqPriorityMeta: Record<FaqPriority, { text: string; color: string }> = {
|
||||
low: { text: '低', color: 'gray' },
|
||||
medium: { text: '中', color: 'blue' },
|
||||
high: { text: '高', color: 'orange' },
|
||||
}
|
||||
|
||||
/** 获取 FAQ 状态文案。 */
|
||||
export const getFaqStatusText = (status: FaqStatus | string) => faqStatusMeta[status as FaqStatus]?.text || status || '-'
|
||||
|
||||
/** 获取 FAQ 状态标签颜色。 */
|
||||
export const getFaqStatusColor = (status: FaqStatus | string) => faqStatusMeta[status as FaqStatus]?.color || 'gray'
|
||||
|
||||
/** 获取 FAQ 优先级文案。 */
|
||||
export const getFaqPriorityText = (priority: FaqPriority | string) => faqPriorityMeta[priority as FaqPriority]?.text || priority || '-'
|
||||
|
||||
/** 获取 FAQ 优先级标签颜色。 */
|
||||
export const getFaqPriorityColor = (priority: FaqPriority | string) => faqPriorityMeta[priority as FaqPriority]?.color || 'gray'
|
||||
|
||||
/** 获取 FAQ 列表。 */
|
||||
export const fetchFaqList = (params: FaqListParams) =>
|
||||
request.get<KbReply<FaqPage>>('/Kb/v1/faq/list', {
|
||||
params,
|
||||
})
|
||||
|
||||
/** 获取 FAQ 详情。 */
|
||||
export const fetchFaqDetail = (id: number) => request.get<KbReply<Faq>>(`/Kb/v1/faq/${id}`)
|
||||
|
||||
/** 创建 FAQ 草稿。 */
|
||||
export const createFaq = (data: FaqFormData) => request.post<KbReply<Faq>>('/Kb/v1/faq/create', data)
|
||||
|
||||
/** 更新 FAQ。 */
|
||||
export const updateFaq = (data: UpdateFaqData) => request.post<KbReply<Faq>>('/Kb/v1/faq/update', data)
|
||||
|
||||
/** 提交 FAQ 审核。 */
|
||||
export const publishFaq = (id: number) => request.post<KbReply<string>>('/Kb/v1/faq/publish', { id })
|
||||
|
||||
/** 删除 FAQ 并移入回收站。 */
|
||||
export const deleteFaq = (id: number) => request.delete<KbReply<string>>(`/Kb/v1/faq/${id}`)
|
||||
|
||||
/** 收藏 FAQ。 */
|
||||
export const favoriteFaq = (id: number) =>
|
||||
request.post<KbReply<unknown>>('/Kb/v1/favorite/collect', {
|
||||
resource_type: 'faq',
|
||||
resource_id: id,
|
||||
})
|
||||
|
||||
/** 取消收藏 FAQ。 */
|
||||
export const unfavoriteFaq = (id: number) =>
|
||||
request.post<KbReply<string>>('/Kb/v1/favorite/uncollect', {
|
||||
resource_type: 'faq',
|
||||
resource_id: id,
|
||||
})
|
||||
@@ -1,9 +1,11 @@
|
||||
import { request } from '@/api/request'
|
||||
import type { Document } from './document'
|
||||
import type { Faq } from './faq'
|
||||
import type { KbReply } from './types'
|
||||
|
||||
/** 资源类型 */
|
||||
export type ResourceType = 'document' | 'faq'
|
||||
|
||||
/** 收藏记录接口 */
|
||||
/** 收藏记录。 */
|
||||
export interface Favorite {
|
||||
id: number
|
||||
created_at: string
|
||||
@@ -12,69 +14,36 @@ export interface Favorite {
|
||||
resource_name: string
|
||||
remarks: string
|
||||
is_deleted: boolean
|
||||
resource_data?: any
|
||||
resource_data?: Document | Faq
|
||||
}
|
||||
|
||||
/** 收藏列表响应 */
|
||||
export interface FavoriteListResponse {
|
||||
export interface FavoritePage {
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
data: Favorite[]
|
||||
}
|
||||
|
||||
/** 获取收藏列表参数 */
|
||||
export interface FetchFavoriteListParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
resource_type?: ResourceType
|
||||
}
|
||||
|
||||
/** 收藏请求参数 */
|
||||
export interface CollectParams {
|
||||
resource_type: ResourceType
|
||||
resource_id: number
|
||||
remarks?: string
|
||||
}
|
||||
|
||||
/** 取消收藏参数 */
|
||||
export interface UncollectParams {
|
||||
resource_type: ResourceType
|
||||
resource_id: number
|
||||
}
|
||||
export type UncollectParams = Omit<CollectParams, 'remarks'>
|
||||
|
||||
/** API响应包装类型 */
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
/** 获取收藏列表。 */
|
||||
export const fetchFavoriteList = (params: FetchFavoriteListParams = {}) =>
|
||||
request.get<KbReply<FavoritePage>>('/Kb/v1/favorite/list', { params })
|
||||
|
||||
/**
|
||||
* 获取收藏列表
|
||||
*/
|
||||
export async function fetchFavoriteList(params: FetchFavoriteListParams = {}): Promise<ApiResponse<FavoriteListResponse>> {
|
||||
return request.get<ApiResponse<FavoriteListResponse>>('/Kb/v1/favorite/list', {
|
||||
params,
|
||||
})
|
||||
}
|
||||
/** 收藏资源。 */
|
||||
export const collectResource = (data: CollectParams) => request.post<KbReply<Favorite>>('/Kb/v1/favorite/collect', data)
|
||||
|
||||
/**
|
||||
* 收藏资源
|
||||
*/
|
||||
export async function collectResource(data: CollectParams): Promise<ApiResponse<Favorite>> {
|
||||
return request.post<ApiResponse<Favorite>>('/Kb/v1/favorite/collect', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消收藏
|
||||
*/
|
||||
export async function uncollectResource(data: UncollectParams): Promise<ApiResponse<string>> {
|
||||
return request.post<ApiResponse<string>>('/Kb/v1/favorite/uncollect', data)
|
||||
}
|
||||
|
||||
/** 资源类型选项 */
|
||||
export const resourceTypeOptions = [
|
||||
{ label: '文档', value: 'document' },
|
||||
{ label: 'FAQ', value: 'faq' },
|
||||
]
|
||||
/** 取消收藏。 */
|
||||
export const uncollectResource = (data: UncollectParams) => request.post<KbReply<string>>('/Kb/v1/favorite/uncollect', data)
|
||||
|
||||
@@ -1,169 +1,71 @@
|
||||
import { request } from '@/api/request'
|
||||
import type { Document } from './document'
|
||||
import type { Faq } from './faq'
|
||||
import type { KbReply } from './types'
|
||||
|
||||
export type ReviewStatsResourceType = 'all' | 'document' | 'faq'
|
||||
export type ReviewResourceType = 'all' | 'document' | 'faq'
|
||||
|
||||
/** 审核统计接口返回的 data 字段 */
|
||||
export interface ReviewStatsPayload {
|
||||
need_my_review_document?: number
|
||||
need_my_review_faq?: number
|
||||
need_my_review_total?: number
|
||||
need_my_review_unreviewed_document?: number
|
||||
need_my_review_unreviewed_faq?: number
|
||||
need_my_review_unreviewed_total?: number
|
||||
}
|
||||
|
||||
/** 文档资源类型 */
|
||||
export interface DocumentResource {
|
||||
id: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
doc_no: string
|
||||
title: string
|
||||
description: string
|
||||
content: string
|
||||
type: string
|
||||
status: string
|
||||
category_id: number
|
||||
sub_category: string
|
||||
author_id: number
|
||||
author_name: string
|
||||
reviewer_id: number
|
||||
reviewer_name: string
|
||||
reviewed_at: string | null
|
||||
published_at: string | null
|
||||
publisher_id: number
|
||||
view_count: number
|
||||
like_count: number
|
||||
comment_count: number
|
||||
download_count: number
|
||||
version: string
|
||||
version_notes: string
|
||||
tags: string
|
||||
attachments: string | null
|
||||
related_docs: string | null
|
||||
metadata: string | null
|
||||
keywords: string
|
||||
remarks: string
|
||||
}
|
||||
|
||||
/** FAQ资源类型 */
|
||||
export interface FaqResource {
|
||||
id: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
faq_no: string
|
||||
question: string
|
||||
answer: string
|
||||
status: string
|
||||
priority: string
|
||||
category_id: number
|
||||
sub_category: string
|
||||
problem_type: string
|
||||
solution: string
|
||||
process_steps: string
|
||||
prerequisites: string
|
||||
author_id: number
|
||||
author_name: string
|
||||
reviewer_id: number
|
||||
reviewer_name: string
|
||||
reviewed_at: string | null
|
||||
published_at: string | null
|
||||
view_count: number
|
||||
use_count: number
|
||||
helpful_count: number
|
||||
useless_count: number
|
||||
tags: string
|
||||
related_faqs: string | null
|
||||
related_docs: string | null
|
||||
related_links: string | null
|
||||
attachments: string | null
|
||||
keywords: string
|
||||
applicable_scope: string
|
||||
remarks: string
|
||||
}
|
||||
|
||||
/** 审核列表项(resource_type 为 all 时) */
|
||||
/** 统一审核列表项。 */
|
||||
export interface ReviewListItem {
|
||||
type: 'document' | 'faq'
|
||||
resource: DocumentResource | FaqResource
|
||||
resource: Document | Faq
|
||||
}
|
||||
|
||||
/** 分页响应类型 */
|
||||
export interface PaginatedResponse<T> {
|
||||
/** 审核分页结果。 */
|
||||
export interface ReviewPage {
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
data: T[]
|
||||
data: ReviewListItem[]
|
||||
}
|
||||
|
||||
/** API响应包装类型 */
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
/** 当前审核人的待审数量。 */
|
||||
export interface ReviewStats {
|
||||
need_my_review_document: number
|
||||
need_my_review_faq: number
|
||||
need_my_review_total: number
|
||||
need_my_review_unreviewed_document: number
|
||||
need_my_review_unreviewed_faq: number
|
||||
need_my_review_unreviewed_total: number
|
||||
}
|
||||
|
||||
/** 获取审核列表参数 */
|
||||
/** 审核列表参数。 */
|
||||
export interface FetchReviewListParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
resource_type?: ReviewStatsResourceType
|
||||
resource_type?: ReviewResourceType
|
||||
}
|
||||
|
||||
/** 审核通过参数 */
|
||||
export interface ApproveParams {
|
||||
resource_type: 'document' | 'faq'
|
||||
id: number
|
||||
}
|
||||
|
||||
/** 审核拒绝参数 */
|
||||
export interface RejectParams {
|
||||
resource_type: 'document' | 'faq'
|
||||
id: number
|
||||
reason?: string
|
||||
export interface RejectParams extends ApproveParams {
|
||||
reason: string
|
||||
}
|
||||
|
||||
/** 按当前登录用户统计需要本人审核的数量(不含本人为作者的稿件) */
|
||||
export const fetchReviewStats = (params?: { resource_type?: ReviewStatsResourceType }) =>
|
||||
request.get('/Kb/v1/review/stats', params ? { params } : undefined)
|
||||
/** 获取当前用户可审核的待审资源。 */
|
||||
export const fetchReviewList = (params: FetchReviewListParams) => request.get<KbReply<ReviewPage>>('/Kb/v1/review/list', { params })
|
||||
|
||||
/** 获取待审核列表 */
|
||||
export const fetchReviewList = (params?: FetchReviewListParams) =>
|
||||
request.get<ApiResponse<PaginatedResponse<ReviewListItem | DocumentResource | FaqResource>>>('/Kb/v1/review/list', { params })
|
||||
/** 获取当前审核人的待审统计。 */
|
||||
export const fetchReviewStats = (params: { resource_type?: ReviewResourceType } = {}) =>
|
||||
request.get<KbReply<ReviewStats>>('/Kb/v1/review/stats', { params })
|
||||
|
||||
/** 审核通过 */
|
||||
export const approveReview = (data: ApproveParams) => request.post<ApiResponse<string>>('/Kb/v1/review/approve', data)
|
||||
/** 审核通过。 */
|
||||
export const approveReview = (data: ApproveParams) => request.post<KbReply<string>>('/Kb/v1/review/approve', data)
|
||||
|
||||
/** 审核拒绝 */
|
||||
export const rejectReview = (data: RejectParams) => request.post<ApiResponse<string>>('/Kb/v1/review/reject', data)
|
||||
/** 审核拒绝。 */
|
||||
export const rejectReview = (data: RejectParams) => request.post<KbReply<string>>('/Kb/v1/review/reject', data)
|
||||
|
||||
/** 获取文档详情 */
|
||||
export const fetchDocumentDetail = (id: number) => request.get<ApiResponse<DocumentResource>>(`/Kb/v1/document/${id}`)
|
||||
|
||||
/** 获取FAQ详情 */
|
||||
export const fetchFaqDetail = (id: number) => request.get<ApiResponse<FaqResource>>(`/Kb/v1/faq/${id}`)
|
||||
|
||||
/** 资源类型选项 */
|
||||
export const resourceTypeOptions = [
|
||||
export const resourceTypeOptions: Array<{ label: string; value: ReviewResourceType }> = [
|
||||
{ label: '全部', value: 'all' },
|
||||
{ label: '文档', value: 'document' },
|
||||
{ label: 'FAQ', value: 'faq' },
|
||||
]
|
||||
|
||||
/** 获取资源类型文本 */
|
||||
export const getResourceTypeText = (type: string): string => {
|
||||
const typeMap: Record<string, string> = {
|
||||
document: '文档',
|
||||
faq: 'FAQ',
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
/** 获取审核资源类型文案。 */
|
||||
export const getResourceTypeText = (type: string) => ({ document: '文档', faq: 'FAQ' })[type] || type
|
||||
|
||||
/** 获取资源类型颜色 */
|
||||
export const getResourceTypeColor = (type: string): string => {
|
||||
const colorMap: Record<string, string> = {
|
||||
document: 'arcoblue',
|
||||
faq: 'green',
|
||||
}
|
||||
return colorMap[type] || 'gray'
|
||||
}
|
||||
/** 获取审核资源类型颜色。 */
|
||||
export const getResourceTypeColor = (type: string) => ({ document: 'arcoblue', faq: 'green' })[type] || 'gray'
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
import { request } from '@/api/request'
|
||||
import type { KbReply } from './types'
|
||||
|
||||
/** API响应包装类型 */
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
}
|
||||
export type TrashResourceType = 'document' | 'faq'
|
||||
|
||||
/** 分页响应类型 */
|
||||
export interface PaginatedResponse<T> {
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
data: T[]
|
||||
}
|
||||
|
||||
/** 回收站记录 */
|
||||
/** 回收站记录。 */
|
||||
export interface TrashRecord {
|
||||
id: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
resource_type: 'document' | 'faq'
|
||||
resource_type: TrashResourceType
|
||||
resource_id: number
|
||||
resource_name: string
|
||||
deleted_by: number
|
||||
@@ -31,58 +19,35 @@ export interface TrashRecord {
|
||||
remarks: string
|
||||
}
|
||||
|
||||
/** 获取回收站列表参数 */
|
||||
export interface TrashPage {
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
data: TrashRecord[]
|
||||
}
|
||||
|
||||
export interface FetchTrashListParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
resource_type?: 'document' | 'faq'
|
||||
resource_type?: TrashResourceType
|
||||
}
|
||||
|
||||
/** 恢复资源请求参数 */
|
||||
export interface RestoreTrashParams {
|
||||
id: number
|
||||
}
|
||||
|
||||
/** 彻底删除请求参数 */
|
||||
export interface DeleteTrashParams {
|
||||
id: number
|
||||
}
|
||||
|
||||
/** 资源类型选项 */
|
||||
export const resourceTypeOptions = [
|
||||
export const resourceTypeOptions: Array<{ label: string; value: TrashResourceType }> = [
|
||||
{ label: '文档', value: 'document' },
|
||||
{ label: '常见问题', value: 'faq' },
|
||||
{ label: 'FAQ', value: 'faq' },
|
||||
]
|
||||
|
||||
/** 获取资源类型文本 */
|
||||
export const getResourceTypeText = (type: string): string => {
|
||||
const typeMap: Record<string, string> = {
|
||||
document: '文档',
|
||||
faq: '常见问题',
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
/** 获取回收站资源类型文案。 */
|
||||
export const getResourceTypeText = (type: string) => ({ document: '文档', faq: 'FAQ' })[type] || type
|
||||
|
||||
/** 获取资源类型颜色 */
|
||||
export const getResourceTypeColor = (type: string): string => {
|
||||
const colorMap: Record<string, string> = {
|
||||
document: 'blue',
|
||||
faq: 'green',
|
||||
}
|
||||
return colorMap[type] || 'gray'
|
||||
}
|
||||
/** 获取回收站资源类型颜色。 */
|
||||
export const getResourceTypeColor = (type: string) => ({ document: 'blue', faq: 'green' })[type] || 'gray'
|
||||
|
||||
/** 获取回收站列表 */
|
||||
export const fetchTrashList = (params?: FetchTrashListParams) => {
|
||||
return request.get<ApiResponse<PaginatedResponse<TrashRecord>>>('/Kb/v1/trash/list', { params })
|
||||
}
|
||||
/** 获取回收站列表。 */
|
||||
export const fetchTrashList = (params: FetchTrashListParams) => request.get<KbReply<TrashPage>>('/Kb/v1/trash/list', { params })
|
||||
|
||||
/** 恢复资源 */
|
||||
export const restoreTrash = (data: RestoreTrashParams) => {
|
||||
return request.post<ApiResponse<string>>('/Kb/v1/trash/restore', data)
|
||||
}
|
||||
/** 恢复资源。 */
|
||||
export const restoreTrash = (id: number) => request.post<KbReply<string>>('/Kb/v1/trash/restore', { id })
|
||||
|
||||
/** 彻底删除 */
|
||||
export const deleteTrash = (data: DeleteTrashParams) => {
|
||||
return request.post<ApiResponse<string>>('/Kb/v1/trash/delete', data)
|
||||
}
|
||||
/** 彻底删除资源。 */
|
||||
export const deleteTrash = (id: number) => request.post<KbReply<string>>('/Kb/v1/trash/delete', { id })
|
||||
|
||||
7
src/api/kb/types.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/** 知识库服务统一响应。 */
|
||||
export interface KbReply<T> {
|
||||
code: number
|
||||
message: string
|
||||
details: T
|
||||
timeseq: number
|
||||
}
|
||||
@@ -18,6 +18,10 @@ export interface MessageRecord {
|
||||
incidentId?: number
|
||||
alertRecordId?: number
|
||||
nextRetryAt?: string
|
||||
occurrenceCount?: number
|
||||
firstOccurredAt?: string
|
||||
lastOccurredAt?: string
|
||||
lastDeliveryId?: number
|
||||
}
|
||||
export type MessageListType = MessageRecord[]
|
||||
|
||||
|
||||
@@ -68,10 +68,11 @@ export const createRule = (data: {
|
||||
severity_id: number
|
||||
enabled?: boolean
|
||||
metric_name?: string
|
||||
query_expr?: string
|
||||
data_source?: string
|
||||
threshold?: number
|
||||
compare_op?: string
|
||||
duration?: number
|
||||
eval_interval?: number
|
||||
baseline_config?: string
|
||||
labels?: string
|
||||
annotations?: string
|
||||
@@ -86,10 +87,11 @@ export const updateRule = (data: {
|
||||
severity_id?: number
|
||||
enabled?: boolean
|
||||
metric_name?: string
|
||||
query_expr?: string
|
||||
data_source?: string
|
||||
threshold?: number
|
||||
compare_op?: string
|
||||
duration?: number
|
||||
eval_interval?: number
|
||||
baseline_config?: string
|
||||
labels?: string
|
||||
annotations?: string
|
||||
|
||||
@@ -28,8 +28,6 @@ export const fetchAlertRecordDetail = (id: number) => request.get(`/Alert/v1/rec
|
||||
export const createAlertProcess = (data: {
|
||||
alert_record_id: number
|
||||
action: string // ack / resolve / silence / comment / assign / escalate / close
|
||||
operator: string
|
||||
operator_id?: string
|
||||
comment?: string
|
||||
assign_to?: string
|
||||
assign_to_id?: string
|
||||
|
||||
@@ -20,12 +20,13 @@ export interface AlertRule {
|
||||
name: string
|
||||
data_source: string
|
||||
metric_name: string
|
||||
rule_type: 'static' | 'dynamic' | 'promql'
|
||||
rule_type: 'static' | 'dynamic'
|
||||
compare_op: '>' | '>=' | '<' | '<=' | '==' | '!='
|
||||
threshold: string | number
|
||||
duration: number
|
||||
eval_interval: number
|
||||
severity_code: string
|
||||
baseline_config?: string
|
||||
labels?: Record<string, string>
|
||||
annotations?: Record<string, string>
|
||||
}
|
||||
@@ -105,12 +106,11 @@ export const TEMPLATE_CATEGORIES = [
|
||||
// 数据源选项
|
||||
export const DATA_SOURCES = [
|
||||
{ value: 'dc-host', label: '主机/操作系统指标' },
|
||||
{ value: 'dc-hardware', label: '服务器硬件指标' },
|
||||
{ value: 'dc-network', label: '网络设备指标' },
|
||||
{ value: 'dc-database', label: '数据库指标' },
|
||||
{ value: 'dc-middleware', label: '中间件指标' },
|
||||
{ value: 'dc-virtualization', label: '虚拟化指标' },
|
||||
{ value: 'dc-env', label: '动力/环境/安防指标' },
|
||||
{ value: 'dc-security', label: '安全设备指标' },
|
||||
{ value: 'dc-storage', label: '存储设备指标' },
|
||||
{ value: 'dc-room-device', label: '机房设备指标' },
|
||||
]
|
||||
|
||||
// 比较运算符选项
|
||||
@@ -127,7 +127,6 @@ export const COMPARE_OPERATORS = [
|
||||
export const RULE_TYPES = [
|
||||
{ value: 'static', label: '静态阈值' },
|
||||
{ value: 'dynamic', label: '动态阈值' },
|
||||
{ value: 'promql', label: 'PromQL 表达式' },
|
||||
]
|
||||
|
||||
// ==================== 告警模板接口 ====================
|
||||
|
||||
@@ -42,13 +42,6 @@ export interface AssetListParams {
|
||||
page_size?: number
|
||||
keyword?: string
|
||||
status?: string
|
||||
category_id?: number
|
||||
supplier_id?: number
|
||||
datacenter_id?: number
|
||||
floor_id?: number
|
||||
room_id?: number
|
||||
rack_id?: number
|
||||
department?: string
|
||||
sort?: string
|
||||
order?: string
|
||||
}
|
||||
@@ -62,10 +55,11 @@ export interface AssetForm {
|
||||
model?: string
|
||||
manufacturer?: string
|
||||
serial_number?: string
|
||||
source_address?: string
|
||||
purchase_date?: string
|
||||
original_value?: number
|
||||
supplier_id?: number
|
||||
warranty_period?: string
|
||||
warranty_period?: number
|
||||
warranty_expiry?: string
|
||||
department?: string
|
||||
user?: string
|
||||
@@ -74,9 +68,6 @@ export interface AssetForm {
|
||||
datacenter_id?: number
|
||||
floor_id?: number
|
||||
room_id?: number
|
||||
rack_id?: number
|
||||
unit_start?: number
|
||||
unit_end?: number
|
||||
qr_code?: string
|
||||
rfid_tag?: string
|
||||
asset_tag?: string
|
||||
@@ -137,21 +128,6 @@ export const fetchSupplierOptions = () => {
|
||||
return request.get('/Assets/v1/supplier/all')
|
||||
}
|
||||
|
||||
/** 获取数据中心列表(下拉) */
|
||||
export const fetchDatacenterOptions = () => {
|
||||
return request.get('/Assets/v1/datacenter/list')
|
||||
}
|
||||
|
||||
/** 根据数据中心获取楼层列表 */
|
||||
export const fetchFloorOptions = (datacenterId: number) => {
|
||||
return request.get(`/Assets/v1/datacenter/${datacenterId}`)
|
||||
}
|
||||
|
||||
/** 获取机柜列表(下拉) */
|
||||
export const fetchRackOptions = (params?: { datacenter_id?: number; floor_id?: number }) => {
|
||||
return request.post('/Assets/v1/rack/list', params || {})
|
||||
}
|
||||
|
||||
/** 绑定资产和监控资源 */
|
||||
export const linkAssetResource = (data: {
|
||||
asset_id: number
|
||||
|
||||
@@ -61,8 +61,3 @@ export const fetchDatacenterByCity = (cityId: number) => {
|
||||
export const fetchDatacenterTree = () => {
|
||||
return request.get('/Assets/v1/datacenter/tree')
|
||||
}
|
||||
|
||||
/** 获取3D机房后端导出契约数据 */
|
||||
export const fetchDatacenterThreeDExport = (params?: { datacenter_ids?: string; room_ids?: string }) => {
|
||||
return request.get('/Assets/v1/three-d/export', { params })
|
||||
}
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
import { request } from '@/api/request'
|
||||
|
||||
/** 许可证配置(与 DC-Control `LicenceConfig` / 接口 `data` 一致;字段按实际响应可能部分缺失) */
|
||||
export interface LicenceConfig {
|
||||
title?: string
|
||||
version?: string
|
||||
company_name?: string
|
||||
create_time?: string
|
||||
expire_time?: string
|
||||
machine_code?: string
|
||||
max_database?: number
|
||||
max_middleware?: number
|
||||
max_pc?: number
|
||||
max_server?: number
|
||||
max_client?: number
|
||||
max_user?: number
|
||||
max_role?: number
|
||||
max_permission?: number
|
||||
max_menu?: number
|
||||
export interface LicenceQuotas {
|
||||
max_database: number
|
||||
max_middleware: number
|
||||
max_network_device: number
|
||||
max_security: number
|
||||
max_storage: number
|
||||
max_pc: number
|
||||
max_server: number
|
||||
max_user: number
|
||||
max_role: number
|
||||
max_permission: number
|
||||
max_menu: number
|
||||
}
|
||||
|
||||
export interface LicenceInfo {
|
||||
id: string
|
||||
platform_name: string
|
||||
workspace: string
|
||||
issued_on: string
|
||||
valid_from: string
|
||||
expires_on: string
|
||||
quotas: LicenceQuotas
|
||||
}
|
||||
|
||||
/** 获取 采集器 */
|
||||
@@ -39,7 +44,8 @@ export const updateCollector = (data: any) => request.put(`/DC-Control/v1/collec
|
||||
export const fetchCollectorStatistics = () => request.get('/DC-Control/v1/statistics')
|
||||
|
||||
/** 获取 许可证信息 */
|
||||
export const fetchLicenseInfo = () => request.get<{ code?: number; data?: LicenceConfig; message?: string }>('/DC-Control/v1/license')
|
||||
export const fetchLicenseInfo = () =>
|
||||
request.get<{ code: number; details: LicenceInfo; message: string; timeseq: number }>('/DC-Control/v1/license')
|
||||
|
||||
export interface PageResult<T> {
|
||||
total: number
|
||||
@@ -182,7 +188,9 @@ export const fetchControlResources = (params?: ResourceListParams) =>
|
||||
request.get<{ code?: number; details?: PageResult<ControlResource>; message?: string }>('/DC-Control/v1/resources', { params })
|
||||
|
||||
export const fetchControlResourceOptions = (params?: { resource_category?: string }) =>
|
||||
request.get<{ code?: number; details?: { list: OptionItem[]; count: number }; message?: string }>('/DC-Control/v1/resources/options', { params })
|
||||
request.get<{ code?: number; details?: { list: OptionItem[]; count: number }; message?: string }>('/DC-Control/v1/resources/options', {
|
||||
params,
|
||||
})
|
||||
|
||||
export const createControlResource = (data: ControlResourcePayload) =>
|
||||
request.post<{ code?: number; details?: ControlResource; message?: string }>('/DC-Control/v1/resources', data)
|
||||
@@ -203,10 +211,9 @@ export const fetchControlResourceTypeOptions = () =>
|
||||
request.get<{ code?: number; details?: { list: OptionItem[]; count: number }; message?: string }>('/DC-Control/v1/resource-types/options')
|
||||
|
||||
export const fetchControlMetricDefinitions = (params?: { page?: number; size?: number; keyword?: string; resource_category?: string }) =>
|
||||
request.get<{ code?: number; details?: PageResult<ControlMetricDefinition>; message?: string }>(
|
||||
'/DC-Control/v1/metric-definitions',
|
||||
{ params }
|
||||
)
|
||||
request.get<{ code?: number; details?: PageResult<ControlMetricDefinition>; message?: string }>('/DC-Control/v1/metric-definitions', {
|
||||
params,
|
||||
})
|
||||
|
||||
export const fetchControlMetricDefinitionOptions = (params?: { resource_category?: string }) =>
|
||||
request.get<{ code?: number; details?: { list: OptionItem[]; count: number }; message?: string }>(
|
||||
@@ -218,10 +225,14 @@ export const fetchControlMetricSeries = (params?: MetricSeriesListParams) =>
|
||||
request.get<{ code?: number; details?: PageResult<ControlMetricSeries>; message?: string }>('/DC-Control/v1/metric-series', { params })
|
||||
|
||||
export const fetchControlBusinessSystems = (params?: { page?: number; size?: number; keyword?: string; status?: string }) =>
|
||||
request.get<{ code?: number; details?: PageResult<ControlBusinessSystem>; message?: string }>('/DC-Control/v1/business-systems', { params })
|
||||
request.get<{ code?: number; details?: PageResult<ControlBusinessSystem>; message?: string }>('/DC-Control/v1/business-systems', {
|
||||
params,
|
||||
})
|
||||
|
||||
export const fetchControlBusinessSystemOptions = () =>
|
||||
request.get<{ code?: number; details?: { list: OptionItem[]; count: number }; message?: string }>('/DC-Control/v1/business-systems/options')
|
||||
request.get<{ code?: number; details?: { list: OptionItem[]; count: number }; message?: string }>(
|
||||
'/DC-Control/v1/business-systems/options'
|
||||
)
|
||||
|
||||
export const fetchCollectionStatus = (params?: {
|
||||
page?: number
|
||||
@@ -231,7 +242,6 @@ export const fetchCollectionStatus = (params?: {
|
||||
resource_uid?: string
|
||||
status?: string
|
||||
}) =>
|
||||
request.get<{ code?: number; details?: PageResult<ControlCollectionStatus>; message?: string }>(
|
||||
'/DC-Control/v1/collection/status',
|
||||
{ params }
|
||||
)
|
||||
request.get<{ code?: number; details?: PageResult<ControlCollectionStatus>; message?: string }>('/DC-Control/v1/collection/status', {
|
||||
params,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
import { request } from '@/api/request'
|
||||
|
||||
export interface Floor {
|
||||
id?: number
|
||||
name?: string
|
||||
code?: string
|
||||
datacenter_id?: number
|
||||
floor_number?: number
|
||||
status?: string
|
||||
area?: number
|
||||
height?: number
|
||||
load_bearing?: number
|
||||
enabled?: boolean
|
||||
layout_plan?: string
|
||||
layout_plan_file_id?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type SaveFloorPayload = Omit<Floor, 'layout_plan'>
|
||||
|
||||
interface ApiResponse<T> {
|
||||
code: number
|
||||
message: string
|
||||
details: T
|
||||
}
|
||||
|
||||
/** 获取楼层列表(分页) */
|
||||
export const fetchFloorList = (data?: { page?: number; page_size?: number; keyword?: string; datacenter_id?: number; status?: string }) => {
|
||||
return request.post('/Assets/v1/floor/list', data || {})
|
||||
@@ -16,13 +40,13 @@ export const fetchFloorListByDatacenter = (datacenterId: number, params?: { name
|
||||
}
|
||||
|
||||
/** 创建楼层 */
|
||||
export const createFloor = (data: any) => {
|
||||
return request.post('/Assets/v1/floor/create', data)
|
||||
export const createFloor = (data: SaveFloorPayload) => {
|
||||
return request.post<ApiResponse<Floor>>('/Assets/v1/floor/create', data)
|
||||
}
|
||||
|
||||
/** 更新楼层 */
|
||||
export const updateFloor = (data: any) => {
|
||||
return request.put('/Assets/v1/floor/update', data)
|
||||
export const updateFloor = (data: SaveFloorPayload) => {
|
||||
return request.put<ApiResponse<Floor>>('/Assets/v1/floor/update', data)
|
||||
}
|
||||
|
||||
/** 删除楼层 */
|
||||
@@ -31,7 +55,6 @@ export const deleteFloor = (id: number) => {
|
||||
}
|
||||
|
||||
/** 获取数据中心列表(用于下拉选择) */
|
||||
export const fetchDatacenterList = (params?: { keyword?: string; name?: string }) => {
|
||||
const normalizedParams = params?.keyword ? { ...params, name: params.name ?? params.keyword } : params
|
||||
return request.get('/Assets/v1/datacenter/all', { params: normalizedParams })
|
||||
export const fetchDatacenterList = (params?: { keyword?: string }) => {
|
||||
return request.get('/Assets/v1/datacenter/all', { params })
|
||||
}
|
||||
|
||||
48
src/api/ops/floorFile.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { request } from '@/api/request'
|
||||
|
||||
export interface PendingUpload {
|
||||
file_id: string
|
||||
object_key: string
|
||||
upload: {
|
||||
method: string
|
||||
url: string
|
||||
headers: Record<string, string>
|
||||
expires_at: string
|
||||
}
|
||||
}
|
||||
|
||||
interface ApiResponse<T> {
|
||||
code: number
|
||||
message: string
|
||||
details: T
|
||||
}
|
||||
|
||||
/** 初始化楼层布局文件并直传 OSS。 */
|
||||
export async function uploadFloorLayout(file: File): Promise<PendingUpload> {
|
||||
const response = await request.post<ApiResponse<PendingUpload>>('/Assets/v1/floor/layout/init', {
|
||||
filename: file.name,
|
||||
size: file.size,
|
||||
content_type: file.type || 'application/octet-stream',
|
||||
})
|
||||
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || '初始化楼层布局文件上传失败')
|
||||
}
|
||||
|
||||
const pendingUpload = response.details
|
||||
if (!pendingUpload?.file_id || !pendingUpload.upload?.method || !pendingUpload.upload?.url) {
|
||||
throw new Error('楼层布局文件上传参数不完整')
|
||||
}
|
||||
|
||||
const uploadResponse = await fetch(pendingUpload.upload.url, {
|
||||
method: pendingUpload.upload.method,
|
||||
headers: pendingUpload.upload.headers,
|
||||
body: file,
|
||||
credentials: 'omit',
|
||||
})
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error(`上传楼层布局文件失败: HTTP ${uploadResponse.status}`)
|
||||
}
|
||||
|
||||
return pendingUpload
|
||||
}
|
||||
@@ -23,17 +23,6 @@ export interface GoViewProjectData {
|
||||
createUserId: string
|
||||
}
|
||||
|
||||
export interface GoViewFile {
|
||||
id: string
|
||||
fileName: string
|
||||
fileSize: number
|
||||
fileSuffix: string
|
||||
virtualKey: string
|
||||
relativePath: string
|
||||
absolutePath: string
|
||||
createTime: string
|
||||
}
|
||||
|
||||
export interface OssInfo {
|
||||
BucketName: string
|
||||
bucketURL: string
|
||||
@@ -106,15 +95,6 @@ export const publishProject = (data: { identity: string; state: -1 | 1 }) => {
|
||||
return request.put<GoViewResponse<{ identity: string; state: number }>>('/Visual/v1/project/publish', data)
|
||||
}
|
||||
|
||||
/** 上传文件 */
|
||||
export const uploadFile = (file: File) => {
|
||||
const formData = new FormData()
|
||||
formData.append('object', file)
|
||||
return request.post<GoViewResponse<GoViewFile>>('/Visual/v1/project/upload', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
}
|
||||
|
||||
/** 保存项目数据 */
|
||||
export const saveProjectData = (projectId: string, content: string) => {
|
||||
const formData = new URLSearchParams()
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface HostHardwareDevice {
|
||||
snmp_port?: number
|
||||
community?: string
|
||||
snmp_version?: string
|
||||
snmp_oids?: string
|
||||
redfish_base_url?: string
|
||||
redfish_tls_skip_verify?: boolean
|
||||
ipmi_timeout_seconds?: number
|
||||
@@ -65,6 +66,7 @@ export interface HostHardwareDeviceUpsert {
|
||||
snmp_port?: number
|
||||
community?: string
|
||||
snmp_version?: string
|
||||
snmp_oids?: string
|
||||
redfish_base_url?: string
|
||||
redfish_tls_skip_verify?: boolean
|
||||
location?: string
|
||||
|
||||
@@ -48,5 +48,5 @@ export const fetchIncidentAlerts = (id: number) => request.get(`/Alert/v1/incide
|
||||
|
||||
export const fetchIncidentTimeline = (id: number) => request.get(`/Alert/v1/incidents/${id}/timeline`)
|
||||
|
||||
export const transitionIncident = (id: number, data: { status: string; comment?: string; operator?: string }) =>
|
||||
export const transitionIncident = (id: number, data: { status: string; comment?: string }) =>
|
||||
request.post(`/Alert/v1/incidents/${id}/transition`, data)
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { request } from '@/api/request'
|
||||
|
||||
/** IPAM服务统一响应 */
|
||||
export interface IPAMResponse<T> {
|
||||
code: number
|
||||
details: T
|
||||
message?: string
|
||||
timeseq?: number
|
||||
}
|
||||
|
||||
/** IP地址运行状态 */
|
||||
export type IPStatus = 'online' | 'offline' | 'unknown'
|
||||
|
||||
@@ -118,7 +126,8 @@ export interface IPGroupListParams {
|
||||
|
||||
/** IP分组列表响应 */
|
||||
export interface IPGroupListResponse {
|
||||
data: IPGroupItem[]
|
||||
list: IPGroupItem[]
|
||||
count: number
|
||||
}
|
||||
|
||||
/** IP分组表单数据 */
|
||||
@@ -359,92 +368,96 @@ export interface IPAnomalyFormData {
|
||||
/** ========== 概览 API ========== */
|
||||
|
||||
/** 获取IPAM概览统计 */
|
||||
export const fetchIPAMOverview = () => request.get<IPAMOverview>('/DC-Control/v1/ipam/overview')
|
||||
export const fetchIPAMOverview = () => request.get<IPAMResponse<IPAMOverview>>('/DC-Control/v1/ipam/overview')
|
||||
|
||||
/** ========== IP地址 API ========== */
|
||||
|
||||
/** 获取IP地址列表 */
|
||||
export const fetchIPAddressList = (params?: IPAddressListParams) =>
|
||||
request.get<IPAddressListResponse>('/DC-Control/v1/ipaddresses', { params })
|
||||
request.get<IPAMResponse<IPAddressListResponse>>('/DC-Control/v1/ipaddresses', { params })
|
||||
|
||||
/** 获取IP地址详情 */
|
||||
export const fetchIPAddressDetail = (id: number) => request.get<IPAddressItem>(`/DC-Control/v1/ipaddresses/${id}`)
|
||||
export const fetchIPAddressDetail = (id: number) => request.get<IPAMResponse<IPAddressItem>>(`/DC-Control/v1/ipaddresses/${id}`)
|
||||
|
||||
/** 创建IP地址 */
|
||||
export const createIPAddress = (data: IPAddressFormData) => request.post<IPAddressItem>('/DC-Control/v1/ipaddresses', data)
|
||||
export const createIPAddress = (data: IPAddressFormData) => request.post<IPAMResponse<IPAddressItem>>('/DC-Control/v1/ipaddresses', data)
|
||||
|
||||
/** 更新IP地址 */
|
||||
export const updateIPAddress = (id: number, data: Partial<IPAddressFormData>) =>
|
||||
request.put<{ message: string }>(`/DC-Control/v1/ipaddresses/${id}`, data)
|
||||
request.put<IPAMResponse<{ message: string }>>(`/DC-Control/v1/ipaddresses/${id}`, data)
|
||||
|
||||
/** 删除IP地址 */
|
||||
export const deleteIPAddress = (id: number) => request.delete<{ message: string }>(`/DC-Control/v1/ipaddresses/${id}`)
|
||||
export const deleteIPAddress = (id: number) => request.delete<IPAMResponse<{ message: string }>>(`/DC-Control/v1/ipaddresses/${id}`)
|
||||
|
||||
/** ========== IP分组 API ========== */
|
||||
|
||||
/** 获取IP分组列表(树形) */
|
||||
export const fetchIPGroupList = (params?: IPGroupListParams) => request.get<IPGroupListResponse>('/DC-Control/v1/ip-groups', { params })
|
||||
export const fetchIPGroupList = (params?: IPGroupListParams) =>
|
||||
request.get<IPAMResponse<IPGroupListResponse>>('/DC-Control/v1/ip-groups', { params })
|
||||
|
||||
/** 创建IP分组 */
|
||||
export const createIPGroup = (data: IPGroupFormData) => request.post<IPGroupItem>('/DC-Control/v1/ip-groups', data)
|
||||
export const createIPGroup = (data: IPGroupFormData) => request.post<IPAMResponse<IPGroupItem>>('/DC-Control/v1/ip-groups', data)
|
||||
|
||||
/** 更新IP分组 */
|
||||
export const updateIPGroup = (id: number, data: Partial<IPGroupFormData>) =>
|
||||
request.put<{ message: string }>(`/DC-Control/v1/ip-groups/${id}`, data)
|
||||
request.put<IPAMResponse<{ message: string }>>(`/DC-Control/v1/ip-groups/${id}`, data)
|
||||
|
||||
/** 删除IP分组 */
|
||||
export const deleteIPGroup = (id: number) => request.delete<{ message: string }>(`/DC-Control/v1/ip-groups/${id}`)
|
||||
export const deleteIPGroup = (id: number) => request.delete<IPAMResponse<{ message: string }>>(`/DC-Control/v1/ip-groups/${id}`)
|
||||
|
||||
/** ========== IP子网 API ========== */
|
||||
|
||||
/** 获取IP子网列表 */
|
||||
export const fetchIPSubnetList = (params?: IPSubnetListParams) => request.get<IPSubnetListResponse>('/DC-Control/v1/ip-subnets', { params })
|
||||
export const fetchIPSubnetList = (params?: IPSubnetListParams) =>
|
||||
request.get<IPAMResponse<IPSubnetListResponse>>('/DC-Control/v1/ip-subnets', { params })
|
||||
|
||||
/** 获取IP子网详情 */
|
||||
export const fetchIPSubnetDetail = (id: number) => request.get<IPSubnetItem>(`/DC-Control/v1/ip-subnets/${id}`)
|
||||
export const fetchIPSubnetDetail = (id: number) => request.get<IPAMResponse<IPSubnetItem>>(`/DC-Control/v1/ip-subnets/${id}`)
|
||||
|
||||
/** 创建IP子网 */
|
||||
export const createIPSubnet = (data: IPSubnetFormData) => request.post<IPSubnetItem>('/DC-Control/v1/ip-subnets', data)
|
||||
export const createIPSubnet = (data: IPSubnetFormData) => request.post<IPAMResponse<IPSubnetItem>>('/DC-Control/v1/ip-subnets', data)
|
||||
|
||||
/** 更新IP子网 */
|
||||
export const updateIPSubnet = (id: number, data: Partial<IPSubnetFormData>) =>
|
||||
request.put<{ message: string }>(`/DC-Control/v1/ip-subnets/${id}`, data)
|
||||
request.put<IPAMResponse<{ message: string }>>(`/DC-Control/v1/ip-subnets/${id}`, data)
|
||||
|
||||
/** 删除IP子网 */
|
||||
export const deleteIPSubnet = (id: number) => request.delete<{ message: string }>(`/DC-Control/v1/ip-subnets/${id}`)
|
||||
export const deleteIPSubnet = (id: number) => request.delete<IPAMResponse<{ message: string }>>(`/DC-Control/v1/ip-subnets/${id}`)
|
||||
|
||||
/** ========== DHCP租约 API ========== */
|
||||
|
||||
/** 获取DHCP租约列表 */
|
||||
export const fetchDHCPLeaseList = (params?: DHCPLeaseListParams) =>
|
||||
request.get<DHCPLeaseListResponse>('/DC-Control/v1/ipam/dhcp-leases', { params })
|
||||
request.get<IPAMResponse<DHCPLeaseListResponse>>('/DC-Control/v1/ipam/dhcp-leases', { params })
|
||||
|
||||
/** 创建DHCP租约 */
|
||||
export const createDHCPLease = (data: DHCPLeaseFormData) => request.post<DHCPLeaseItem>('/DC-Control/v1/ipam/dhcp-leases', data)
|
||||
export const createDHCPLease = (data: DHCPLeaseFormData) =>
|
||||
request.post<IPAMResponse<DHCPLeaseItem>>('/DC-Control/v1/ipam/dhcp-leases', data)
|
||||
|
||||
/** ========== IP冲突 API ========== */
|
||||
|
||||
/** 获取IP冲突列表 */
|
||||
export const fetchIPConflictList = (params?: IPConflictListParams) =>
|
||||
request.get<IPConflictListResponse>('/DC-Control/v1/ipam/conflicts', { params })
|
||||
request.get<IPAMResponse<IPConflictListResponse>>('/DC-Control/v1/ipam/conflicts', { params })
|
||||
|
||||
/** 创建IP冲突记录 */
|
||||
export const createIPConflict = (data: IPConflictFormData) => request.post<IPConflictItem>('/DC-Control/v1/ipam/conflicts', data)
|
||||
export const createIPConflict = (data: IPConflictFormData) =>
|
||||
request.post<IPAMResponse<IPConflictItem>>('/DC-Control/v1/ipam/conflicts', data)
|
||||
|
||||
/** ========== IP变更 API ========== */
|
||||
|
||||
/** 获取IP变更列表 */
|
||||
export const fetchIPChangeList = (params?: IPChangeListParams) =>
|
||||
request.get<IPChangeListResponse>('/DC-Control/v1/ipam/changes', { params })
|
||||
request.get<IPAMResponse<IPChangeListResponse>>('/DC-Control/v1/ipam/changes', { params })
|
||||
|
||||
/** 创建IP变更记录 */
|
||||
export const createIPChange = (data: IPChangeFormData) => request.post<IPChangeItem>('/DC-Control/v1/ipam/changes', data)
|
||||
export const createIPChange = (data: IPChangeFormData) => request.post<IPAMResponse<IPChangeItem>>('/DC-Control/v1/ipam/changes', data)
|
||||
|
||||
/** ========== IP异常 API ========== */
|
||||
|
||||
/** 获取IP异常列表 */
|
||||
export const fetchIPAnomalyList = (params?: IPAnomalyListParams) =>
|
||||
request.get<IPAnomalyListResponse>('/DC-Control/v1/ipam/anomalies', { params })
|
||||
request.get<IPAMResponse<IPAnomalyListResponse>>('/DC-Control/v1/ipam/anomalies', { params })
|
||||
|
||||
/** 创建IP异常记录 */
|
||||
export const createIPAnomaly = (data: IPAnomalyFormData) => request.post<IPAnomalyItem>('/DC-Control/v1/ipam/anomalies', data)
|
||||
export const createIPAnomaly = (data: IPAnomalyFormData) => request.post<IPAMResponse<IPAnomalyItem>>('/DC-Control/v1/ipam/anomalies', data)
|
||||
|
||||
@@ -76,6 +76,8 @@ export interface SyslogRule {
|
||||
keyword_regex: string
|
||||
source_match: string
|
||||
message_regex: string
|
||||
recovery_match_regex: string
|
||||
lifecycle_key: string
|
||||
alert_name: string
|
||||
severity_code: string
|
||||
severity_mapping_json: string
|
||||
@@ -92,6 +94,8 @@ export interface TrapRule {
|
||||
priority: number
|
||||
oid_prefix: string
|
||||
varbind_match_regex: string
|
||||
recovery_match_regex: string
|
||||
lifecycle_key: string
|
||||
alert_name: string
|
||||
severity_code: string
|
||||
policy_id: number
|
||||
|
||||
@@ -32,7 +32,7 @@ export const createNoticeChannel = (data: {
|
||||
email_to?: string[]
|
||||
email_cc?: string[]
|
||||
email_bcc?: string[]
|
||||
email_use_tls?: boolean
|
||||
email_security_mode?: 'none' | 'starttls' | 'tls'
|
||||
sms_provider?: string
|
||||
sms_access_key_id?: string
|
||||
sms_access_key_secret?: string
|
||||
@@ -40,6 +40,7 @@ export const createNoticeChannel = (data: {
|
||||
sms_template_code?: string
|
||||
sms_phones?: string[]
|
||||
in_app_targets?: string[]
|
||||
in_app_aggregation_window?: number
|
||||
}) => {
|
||||
return request.post('/Alert/v1/channel/create', data)
|
||||
}
|
||||
@@ -67,7 +68,7 @@ export const updateNoticeChannel = (data: {
|
||||
email_to?: string[]
|
||||
email_cc?: string[]
|
||||
email_bcc?: string[]
|
||||
email_use_tls?: boolean
|
||||
email_security_mode?: 'none' | 'starttls' | 'tls'
|
||||
sms_provider?: string
|
||||
sms_access_key_id?: string
|
||||
sms_access_key_secret?: string
|
||||
@@ -75,6 +76,7 @@ export const updateNoticeChannel = (data: {
|
||||
sms_template_code?: string
|
||||
sms_phones?: string[]
|
||||
in_app_targets?: string[]
|
||||
in_app_aggregation_window?: number
|
||||
}) => {
|
||||
return request.post('/Alert/v1/channel/update', data)
|
||||
}
|
||||
|
||||
@@ -21,9 +21,14 @@ export const fetchRackListByDatacenter = (datacenterId: number, params?: { name?
|
||||
return request.get(`/Assets/v1/rack/datacenter/${datacenterId}`, { params })
|
||||
}
|
||||
|
||||
/** 根据楼层获取机柜列表(下拉,不分页)- 已废弃,请使用 fetchRackListByRoom */
|
||||
export const fetchRackListByFloor = (floorId: number, params?: { name?: string }) => {
|
||||
return request.get(`/Assets/v1/rack/floor/${floorId}`, { params })
|
||||
/** 根据楼层获取机柜列表 */
|
||||
export const fetchRackListByFloor = (floorId: number, params?: { keyword?: string }) => {
|
||||
return fetchRackList({
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
floor_id: floorId,
|
||||
keyword: params?.keyword,
|
||||
})
|
||||
}
|
||||
|
||||
/** 根据机房获取机柜列表(下拉,不分页) */
|
||||
@@ -62,13 +67,6 @@ export const fetchSupplierList = () => {
|
||||
}
|
||||
|
||||
/** 获取数据中心列表(用于下拉选择) */
|
||||
export const fetchDatacenterList = (params?: { keyword?: string; name?: string }) => {
|
||||
const normalizedParams = params?.keyword ? { ...params, name: params.name ?? params.keyword } : params
|
||||
return request.get('/Assets/v1/datacenter/all', { params: normalizedParams })
|
||||
}
|
||||
|
||||
/** 获取楼层列表(用于下拉选择) */
|
||||
export const fetchFloorListForSelect = (params?: { datacenter_id?: number; keyword?: string; name?: string }) => {
|
||||
const normalizedParams = params?.keyword ? { ...params, name: params.name ?? params.keyword } : params
|
||||
return request.get('/Assets/v1/floor/all', { params: normalizedParams })
|
||||
export const fetchDatacenterList = (params?: { keyword?: string }) => {
|
||||
return request.get('/Assets/v1/datacenter/all', { params })
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { request } from "@/api/request"
|
||||
import SafeStorage, { AppStorageKey } from "@/utils/safeStorage"
|
||||
import { request } from '@/api/request'
|
||||
import SafeStorage, { AppStorageKey } from '@/utils/safeStorage'
|
||||
|
||||
// ============ 通用响应类型 ============
|
||||
|
||||
@@ -18,6 +18,7 @@ export enum ReportType {
|
||||
FAULT = 'fault',
|
||||
SERVER = 'server',
|
||||
NETWORK_DEVICE = 'network_device',
|
||||
OPERATIONS = 'operations',
|
||||
EVIDENCE = 'evidence',
|
||||
}
|
||||
|
||||
@@ -32,7 +33,7 @@ export enum ReportStatus {
|
||||
|
||||
export interface ReportRecord {
|
||||
id: number
|
||||
/** 列表接口可能含已下线类型字符串,仅六类可再次生成 */
|
||||
/** 列表接口可能包含已下线或自动生成的报表类型 */
|
||||
report_type: ReportType | string
|
||||
title: string
|
||||
description?: string
|
||||
@@ -43,6 +44,8 @@ export interface ReportRecord {
|
||||
file_path?: string
|
||||
file_size?: number
|
||||
file_mime?: string
|
||||
started_at?: string
|
||||
finished_at?: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
@@ -64,6 +67,13 @@ export interface PageResult<T> {
|
||||
data: T[]
|
||||
}
|
||||
|
||||
export type ReportExportFormat = 'csv' | 'xlsx' | 'pdf'
|
||||
|
||||
export interface DownloadedReport {
|
||||
blob: Blob
|
||||
fileName: string
|
||||
}
|
||||
|
||||
// ============ 报表生成参数接口 ============
|
||||
|
||||
export interface TrafficReportParams {
|
||||
@@ -127,9 +137,7 @@ export interface NetworkDeviceReportParams {
|
||||
|
||||
export interface StatisticsReportParams {
|
||||
data_source: 'dc-host' | 'dc-network' | 'dc-database' | 'dc-middleware'
|
||||
/** 与 metric_name 二选一;网络等指标优先用 metric_id */
|
||||
metric_id?: string
|
||||
metric_name?: string
|
||||
metric_id: string
|
||||
target_identities: string[]
|
||||
start_time: string
|
||||
end_time: string
|
||||
@@ -152,16 +160,13 @@ export interface HistoryReportParams {
|
||||
|
||||
export interface TopNReportParams {
|
||||
data_source: 'dc-host' | 'dc-network' | 'dc-database' | 'dc-middleware' | 'alert'
|
||||
metric_id?: string
|
||||
metric_name?: string
|
||||
metric_id: string
|
||||
target_identities: string[]
|
||||
start_time: string
|
||||
end_time: string
|
||||
n?: number
|
||||
rank_aggregate?: 'avg' | 'max' | 'min' | 'last'
|
||||
order?: 'desc' | 'asc'
|
||||
metric_type?: 'cpu' | 'disk' | 'io' | 'memory' | 'network'
|
||||
collector_identity?: string
|
||||
}
|
||||
|
||||
/** 证据导出事件行 */
|
||||
@@ -230,7 +235,8 @@ export const fetchReportMetricsAvailable = (params: {
|
||||
identities?: string
|
||||
keyword?: string
|
||||
limit?: number
|
||||
}) => request.get<ApiResponse<{ data_source: string; items: any[]; registry: any[] }>>('/DC-Control/v1/reports/metrics/available', { params })
|
||||
}) =>
|
||||
request.get<ApiResponse<{ data_source: string; items: any[]; registry: any[] }>>('/DC-Control/v1/reports/metrics/available', { params })
|
||||
|
||||
/** 逻辑指标目录(Registry) */
|
||||
export const fetchReportMetricsRegistry = (params: { data_source: string }) =>
|
||||
@@ -239,8 +245,8 @@ export const fetchReportMetricsRegistry = (params: { data_source: string }) =>
|
||||
/** 查看报表内容 */
|
||||
export const fetchReportContent = (id: number) => request.get<ApiResponse<Record<string, any>>>(`/DC-Control/v1/reports/${id}/content`)
|
||||
|
||||
/** 原始 ArrayBuffer → 下载用 Blob;xlsx 校验 ZIP 魔数 PK */
|
||||
function exportBufferToBlob(ab: ArrayBuffer, format: 'csv' | 'xlsx', contentType: string | null): Blob {
|
||||
/** 原始 ArrayBuffer → 下载用 Blob;xlsx 校验 ZIP 魔数 PK,PDF 校验 %PDF- */
|
||||
function exportBufferToBlob(ab: ArrayBuffer, format: ReportExportFormat, contentType: string | null): Blob {
|
||||
const u8 = new Uint8Array(ab)
|
||||
if (format === 'xlsx') {
|
||||
const okZip = u8.length >= 4 && u8[0] === 0x50 && u8[1] === 0x4b
|
||||
@@ -265,16 +271,62 @@ function exportBufferToBlob(ab: ArrayBuffer, format: 'csv' | 'xlsx', contentType
|
||||
: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
return new Blob([ab], { type: mime })
|
||||
}
|
||||
const mime =
|
||||
contentType && /csv|text|plain/i.test(contentType) ? contentType : 'text/csv;charset=utf-8'
|
||||
if (format === 'pdf') {
|
||||
const okPdf = u8.length >= 5 && u8[0] === 0x25 && u8[1] === 0x50 && u8[2] === 0x44 && u8[3] === 0x46 && u8[4] === 0x2d
|
||||
if (!okPdf) {
|
||||
throw new Error('导出失败:服务器返回的不是有效的 PDF。')
|
||||
}
|
||||
const mime = contentType && /pdf/i.test(contentType) ? contentType : 'application/pdf'
|
||||
return new Blob([ab], { type: mime })
|
||||
}
|
||||
const mime = contentType && /csv|text|plain/i.test(contentType) ? contentType : 'text/csv;charset=utf-8'
|
||||
return new Blob([ab], { type: mime })
|
||||
}
|
||||
|
||||
function parseContentDispositionFileName(value: string | null): string | undefined {
|
||||
if (!value) return undefined
|
||||
|
||||
const utf8FileName = value.match(/filename\*=UTF-8''([^;]+)/i)
|
||||
if (utf8FileName) {
|
||||
try {
|
||||
return decodeURIComponent(utf8FileName[1])
|
||||
} catch {
|
||||
// 编码异常时继续读取普通文件名
|
||||
}
|
||||
}
|
||||
|
||||
return value.match(/filename="([^"]+)"/i)?.[1]
|
||||
}
|
||||
|
||||
function normalizeReportFileName(fileName: string | undefined, id: number, format: ReportExportFormat): string {
|
||||
const defaultName = `report_${id}.${format}`
|
||||
if (!fileName) return defaultName
|
||||
|
||||
let name = fileName.split(/[\\/]/).pop() || ''
|
||||
name = name
|
||||
.replace(/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, '')
|
||||
.replace(/[<>:"/\\|?*]/g, '_')
|
||||
.replace(/[ .]+$/, '')
|
||||
|
||||
const extensionIndex = name.lastIndexOf('.')
|
||||
if (extensionIndex > 0) {
|
||||
name = name.slice(0, extensionIndex).replace(/[ .]+$/, '')
|
||||
}
|
||||
if (!name) return defaultName
|
||||
|
||||
const reservedName = /^(con|prn|aux|nul|com[1-9¹²³]|lpt[1-9¹²³])$/i
|
||||
if (reservedName.test(name.split('.')[0])) {
|
||||
name = `_${name}`
|
||||
}
|
||||
|
||||
return `${name}.${format}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 报表文件导出:使用 fetch + arrayBuffer,绕过 axios 拦截器与 Blob 中间态,
|
||||
* 避免网络面板里已是合法 xlsx(PK…)但落盘文件损坏的情况。
|
||||
*/
|
||||
export const exportReport = async (id: number, format: 'csv' | 'xlsx' = 'csv'): Promise<Blob> => {
|
||||
export const exportReport = async (id: number, format: ReportExportFormat = 'csv'): Promise<DownloadedReport> => {
|
||||
const base = String(import.meta.env.VITE_API_BASE_URL || '').replace(/\/$/, '')
|
||||
const url = `${base}/DC-Control/v1/reports/${id}/export?format=${encodeURIComponent(format)}`
|
||||
const token = SafeStorage.get(AppStorageKey.TOKEN)
|
||||
@@ -296,7 +348,10 @@ export const exportReport = async (id: number, format: 'csv' | 'xlsx' = 'csv'):
|
||||
}
|
||||
throw new Error(msg)
|
||||
}
|
||||
return exportBufferToBlob(ab, format, r.headers.get('content-type'))
|
||||
return {
|
||||
blob: exportBufferToBlob(ab, format, r.headers.get('content-type')),
|
||||
fileName: normalizeReportFileName(parseContentDispositionFileName(r.headers.get('content-disposition')), id, format),
|
||||
}
|
||||
}
|
||||
|
||||
// ============ 监测指标类接口(旧版兼容) ============
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface RoomDeviceItem {
|
||||
service_identity: string
|
||||
name: string
|
||||
description: string
|
||||
room_id: string
|
||||
room_id: number
|
||||
device_code?: string
|
||||
device_category: string
|
||||
type?: string
|
||||
@@ -69,7 +69,7 @@ export interface RoomDeviceCreateData {
|
||||
service_identity?: string
|
||||
name: string
|
||||
description?: string
|
||||
room_id: string
|
||||
room_id: number
|
||||
device_category: string
|
||||
agent_config?: string
|
||||
collect_method?: 'api' | 'snmp'
|
||||
@@ -97,7 +97,7 @@ export interface RoomDeviceCreateData {
|
||||
export interface RoomDeviceUpdateData {
|
||||
name?: string
|
||||
description?: string
|
||||
room_id?: string
|
||||
room_id?: number
|
||||
device_category?: string
|
||||
agent_config?: string
|
||||
collect_method?: 'api' | 'snmp'
|
||||
|
||||
@@ -11,7 +11,9 @@ export interface RoomItem {
|
||||
description?: string
|
||||
floor_id: number
|
||||
datacenter_id: number
|
||||
status?: string
|
||||
layout_version: number
|
||||
status: string
|
||||
has3D: boolean
|
||||
floor?: { id: number; name: string }
|
||||
datacenter?: { id: number; name: string }
|
||||
}
|
||||
@@ -25,6 +27,13 @@ export interface RoomListResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/** 机房详情响应 */
|
||||
export interface RoomDetailResponse {
|
||||
code: number
|
||||
message?: string
|
||||
details: RoomItem
|
||||
}
|
||||
|
||||
/** 机房列表查询参数 */
|
||||
export interface RoomListParams {
|
||||
page?: number
|
||||
@@ -53,6 +62,12 @@ export interface RoomOptionItem {
|
||||
sort: number
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
code: number
|
||||
message?: string
|
||||
details: T
|
||||
}
|
||||
|
||||
/** 机房创建数据 */
|
||||
export interface RoomCreateData {
|
||||
name: string
|
||||
@@ -60,7 +75,7 @@ export interface RoomCreateData {
|
||||
description?: string
|
||||
floor_id: number
|
||||
datacenter_id: number
|
||||
status?: string
|
||||
status: string
|
||||
}
|
||||
|
||||
/** 机房更新数据 */
|
||||
@@ -81,17 +96,17 @@ export const fetchRoomList = (data?: RoomListParams) => {
|
||||
|
||||
/** 获取机房详情 */
|
||||
export const fetchRoomDetail = (id: number) => {
|
||||
return request.get<RoomItem>(`/Assets/v1/room/detail/${id}`)
|
||||
return request.get<RoomDetailResponse>(`/Assets/v1/room/detail/${id}`)
|
||||
}
|
||||
|
||||
/** 获取机房列表(下拉,不分页) */
|
||||
export const fetchRoomOptions = (params?: RoomOptionsParams) => {
|
||||
return request.get<RoomOptionItem[]>('/Assets/v1/room/all', { params })
|
||||
return request.get<ApiResponse<RoomOptionItem[]>>('/Assets/v1/room/all', { params })
|
||||
}
|
||||
|
||||
/** 根据楼层获取机房列表(下拉,不分页) */
|
||||
export const fetchRoomListByFloor = (floorId: number, params?: { name?: string }) => {
|
||||
return request.get<RoomItem[]>(`/Assets/v1/room/floor/${floorId}`, { params })
|
||||
return request.get<ApiResponse<RoomItem[]>>(`/Assets/v1/room/floor/${floorId}`, { params })
|
||||
}
|
||||
|
||||
/** 创建机房 */
|
||||
|
||||
@@ -67,7 +67,7 @@ export interface StorageListParams {
|
||||
|
||||
/** 创建存储设备请求参数 */
|
||||
export interface StorageCreateData {
|
||||
service_identity: string
|
||||
service_identity?: string
|
||||
name: string
|
||||
category?: string
|
||||
type: string
|
||||
|
||||
370
src/api/ops/three-machine-room.ts
Normal file
@@ -0,0 +1,370 @@
|
||||
import { request } from '@/api/request'
|
||||
|
||||
/** 3D 机房接口标准响应。 */
|
||||
interface ThreeMachineRoomResponse<T> {
|
||||
code: number
|
||||
message?: string
|
||||
details: T
|
||||
}
|
||||
|
||||
/** 告警级别。 */
|
||||
export interface ThreeMachineRoomSeverity {
|
||||
id?: number
|
||||
name?: string
|
||||
code?: string
|
||||
color?: string
|
||||
priority?: number
|
||||
}
|
||||
|
||||
/** 三维坐标和旋转。 */
|
||||
export interface ThreeMachineRoomTransform {
|
||||
position_x: number
|
||||
position_y: number
|
||||
position_z: number
|
||||
rotation_x?: number
|
||||
rotation_y?: number
|
||||
rotation_z?: number
|
||||
}
|
||||
|
||||
/** 独立设备三维尺寸。 */
|
||||
export interface ThreeMachineRoomSize {
|
||||
width: number
|
||||
height: number
|
||||
depth: number
|
||||
}
|
||||
|
||||
/** 设备绑定的监控资源。 */
|
||||
export interface ThreeMachineRoomBinding {
|
||||
resource_uid: string
|
||||
resource_category?: string
|
||||
service_identity?: string
|
||||
display_name?: string
|
||||
business_system_id?: number | null
|
||||
}
|
||||
|
||||
/** 监控指标。 */
|
||||
export interface ThreeMachineRoomMetric {
|
||||
name: string
|
||||
value?: string | number | null
|
||||
unit?: string
|
||||
type?: string
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
/** 设备资源运行数据。 */
|
||||
export interface ThreeMachineRoomResource extends ThreeMachineRoomBinding {
|
||||
status?: string
|
||||
metrics_at?: string
|
||||
metrics?: ThreeMachineRoomMetric[]
|
||||
}
|
||||
|
||||
/** 活动告警。 */
|
||||
export interface ThreeMachineRoomAlert {
|
||||
id?: number
|
||||
alert_name?: string
|
||||
summary?: string
|
||||
severity?: ThreeMachineRoomSeverity
|
||||
status?: string
|
||||
starts_at?: string
|
||||
last_seen_at?: string
|
||||
updated_at?: string
|
||||
}
|
||||
|
||||
/** 按监控资源分组的活动告警。 */
|
||||
export interface ThreeMachineRoomAlertGroup {
|
||||
resource_uid: string
|
||||
active_count?: number
|
||||
highest_severity?: ThreeMachineRoomSeverity
|
||||
alerts?: ThreeMachineRoomAlert[]
|
||||
}
|
||||
|
||||
/** 机柜 U 位。 */
|
||||
export interface ThreeMachineRoomUnit {
|
||||
id?: number
|
||||
unit_number: number
|
||||
status: 'available' | 'occupied' | 'reserved' | 'disabled'
|
||||
asset_id?: number | null
|
||||
}
|
||||
|
||||
/** 机柜中的资产设备。 */
|
||||
export interface ThreeMachineRoomDevice {
|
||||
asset_id: number
|
||||
asset_code?: string
|
||||
asset_name?: string
|
||||
category_id?: number | null
|
||||
category_code?: string
|
||||
category_name?: string
|
||||
placement_type?: 'rack' | 'room' | 'unplaced'
|
||||
rack_id?: number | null
|
||||
unit_start?: number | null
|
||||
unit_end?: number | null
|
||||
occupied_units?: number
|
||||
power_consumption?: number
|
||||
transform?: ThreeMachineRoomTransform
|
||||
size?: ThreeMachineRoomSize
|
||||
bindings?: ThreeMachineRoomBinding[]
|
||||
}
|
||||
|
||||
/** 3D 场景机柜。 */
|
||||
export interface ThreeMachineRoomRack {
|
||||
id: number
|
||||
code?: string
|
||||
name?: string
|
||||
row?: number
|
||||
column?: number
|
||||
height?: number
|
||||
width_mm?: number
|
||||
depth_mm?: number
|
||||
status?: string
|
||||
transform?: ThreeMachineRoomTransform
|
||||
utilization_rate?: number
|
||||
units?: ThreeMachineRoomUnit[]
|
||||
devices?: ThreeMachineRoomDevice[]
|
||||
}
|
||||
|
||||
/** 3D 机房场景数据。 */
|
||||
export interface ThreeMachineRoomScene {
|
||||
room: {
|
||||
id: number
|
||||
datacenter_id?: number
|
||||
floor_id?: number
|
||||
name?: string
|
||||
code?: string
|
||||
scene_length?: number
|
||||
scene_width?: number
|
||||
scene_height?: number
|
||||
layout_version?: number
|
||||
[key: string]: unknown
|
||||
}
|
||||
racks: ThreeMachineRoomRack[]
|
||||
room_devices?: ThreeMachineRoomDevice[]
|
||||
summary?: {
|
||||
rack_count?: number
|
||||
unit_count?: number
|
||||
rack_device_count?: number
|
||||
room_device_count?: number
|
||||
device_count?: number
|
||||
}
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/** 设备状态信号。 */
|
||||
export interface ThreeMachineRoomSignal {
|
||||
asset_id: number
|
||||
status?: 'normal' | 'warning' | 'abnormal' | string
|
||||
active_alert_count?: number
|
||||
highest_alert_severity?: ThreeMachineRoomSeverity
|
||||
resources?: ThreeMachineRoomResource[]
|
||||
alerts?: ThreeMachineRoomAlertGroup[]
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/** 机房状态信号集合。 */
|
||||
export interface ThreeMachineRoomSignals {
|
||||
signals: ThreeMachineRoomSignal[]
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/** 设备可观测数据。 */
|
||||
export interface ThreeMachineRoomObservability {
|
||||
device?: ThreeMachineRoomDevice
|
||||
resources?: ThreeMachineRoomResource[]
|
||||
alerts?: ThreeMachineRoomAlertGroup[]
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/** 3D 场景全量导出数据。 */
|
||||
export interface ThreeMachineRoomExport {
|
||||
datacenters: Array<{
|
||||
id: number
|
||||
name?: string
|
||||
code?: string
|
||||
status?: string
|
||||
latitude?: string
|
||||
longitude?: string
|
||||
rooms?: ThreeMachineRoomScene[]
|
||||
}>
|
||||
summary?: {
|
||||
datacenter_count?: number
|
||||
room_count?: number
|
||||
rack_count?: number
|
||||
unit_count?: number
|
||||
device_count?: number
|
||||
}
|
||||
}
|
||||
|
||||
/** 机柜布局保存项。 */
|
||||
export interface ThreeMachineRoomRackLayout {
|
||||
rack_id: number
|
||||
row?: number
|
||||
column?: number
|
||||
position_x: number
|
||||
position_y: number
|
||||
position_z: number
|
||||
rotation_y: number
|
||||
}
|
||||
|
||||
/** 机房 3D 初始化配置。 */
|
||||
export interface ThreeMachineRoomConfigData {
|
||||
expectedVersion: number
|
||||
sceneLength: number
|
||||
sceneWidth: number
|
||||
sceneHeight: number
|
||||
racks: ThreeMachineRoomRackLayout[]
|
||||
}
|
||||
|
||||
/** 独立设备放置参数。 */
|
||||
export interface RoomDevicePlacement {
|
||||
expectedVersion: number
|
||||
positionX: number
|
||||
positionY: number
|
||||
positionZ: number
|
||||
rotationX: number
|
||||
rotationY: number
|
||||
rotationZ: number
|
||||
sceneWidth: number
|
||||
sceneHeight: number
|
||||
sceneDepth: number
|
||||
}
|
||||
|
||||
/** 设备机柜上架参数。 */
|
||||
export interface RackDevicePlacement {
|
||||
expectedVersion: number
|
||||
rackId: number
|
||||
startUnit: number
|
||||
occupiedUnits: number
|
||||
powerConsumption?: number
|
||||
}
|
||||
|
||||
/** 校验响应并返回 3D 机房业务数据。 */
|
||||
function getResponseDetails<T>(response: ThreeMachineRoomResponse<T>): T {
|
||||
if (!response || typeof response !== 'object') {
|
||||
throw new Error('接口返回格式错误')
|
||||
}
|
||||
if (response.code !== 0) {
|
||||
throw new Error(response.message || '接口调用失败')
|
||||
}
|
||||
return response.details
|
||||
}
|
||||
|
||||
/** 获取指定机房的 3D 场景。 */
|
||||
export async function fetchThreeMachineRoomScene(roomId: number): Promise<ThreeMachineRoomScene> {
|
||||
const response = await request.get<ThreeMachineRoomResponse<ThreeMachineRoomScene>>(
|
||||
`/Assets/v1/three-d/rooms/${encodeURIComponent(roomId)}/scene`
|
||||
)
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 获取权限范围内的全部 3D 场景。 */
|
||||
export async function exportThreeMachineRoomScenes(): Promise<ThreeMachineRoomExport> {
|
||||
const response = await request.get<ThreeMachineRoomResponse<ThreeMachineRoomExport>>('/Assets/v1/three-d/export')
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 保存机房尺寸和初始机柜布局。 */
|
||||
export async function saveThreeMachineRoomConfig(
|
||||
roomId: number,
|
||||
config: ThreeMachineRoomConfigData
|
||||
): Promise<{ room_id: number; layout_version: number }> {
|
||||
const response = await request.put<ThreeMachineRoomResponse<{ room_id: number; layout_version: number }>>(
|
||||
`/Assets/v1/three-d/rooms/${encodeURIComponent(roomId)}/config`,
|
||||
{
|
||||
expected_version: config.expectedVersion,
|
||||
scene_length: config.sceneLength,
|
||||
scene_width: config.sceneWidth,
|
||||
scene_height: config.sceneHeight,
|
||||
racks: config.racks,
|
||||
}
|
||||
)
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 批量保存机柜布局。 */
|
||||
export async function saveThreeMachineRoomRackLayout(
|
||||
roomId: number,
|
||||
expectedVersion: number,
|
||||
racks: ThreeMachineRoomRackLayout[]
|
||||
): Promise<{ room_id: number; layout_version: number }> {
|
||||
const response = await request.put<ThreeMachineRoomResponse<{ room_id: number; layout_version: number }>>(
|
||||
`/Assets/v1/three-d/rooms/${encodeURIComponent(roomId)}/layout`,
|
||||
{
|
||||
expected_version: expectedVersion,
|
||||
racks,
|
||||
}
|
||||
)
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 获取指定机房的设备状态与告警。 */
|
||||
export async function fetchThreeMachineRoomSignals(roomId: number): Promise<ThreeMachineRoomSignals> {
|
||||
const response = await request.get<ThreeMachineRoomResponse<ThreeMachineRoomSignals>>(
|
||||
`/Assets/v1/three-d/rooms/${encodeURIComponent(roomId)}/signals`
|
||||
)
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 获取设备可观测指标与告警详情。 */
|
||||
export async function fetchThreeMachineRoomDeviceObservability(assetId: number): Promise<ThreeMachineRoomObservability> {
|
||||
const response = await request.get<ThreeMachineRoomResponse<ThreeMachineRoomObservability>>(
|
||||
`/Assets/v1/three-d/devices/${encodeURIComponent(assetId)}/observability`
|
||||
)
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 保存设备机柜及 U 位。 */
|
||||
export async function saveThreeMachineRoomRackPlacement(
|
||||
roomId: number,
|
||||
assetId: number,
|
||||
placement: RackDevicePlacement
|
||||
): Promise<{ layout_version: number }> {
|
||||
const response = await request.put<ThreeMachineRoomResponse<{ layout_version: number }>>(
|
||||
`/Assets/v1/three-d/rooms/${encodeURIComponent(roomId)}/devices/${encodeURIComponent(assetId)}/placement`,
|
||||
{
|
||||
expected_version: placement.expectedVersion,
|
||||
placement_type: 'rack',
|
||||
rack_id: placement.rackId,
|
||||
start_unit: placement.startUnit,
|
||||
occupied_units: placement.occupiedUnits,
|
||||
power_consumption: placement.powerConsumption || 0,
|
||||
}
|
||||
)
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 将设备放置在机房场景中。 */
|
||||
export async function saveThreeMachineRoomDevicePlacement(
|
||||
roomId: number,
|
||||
assetId: number,
|
||||
placement: RoomDevicePlacement
|
||||
): Promise<{ room_id: number; asset_id: number; placement_type: 'room'; layout_version: number }> {
|
||||
const response = await request.put<
|
||||
ThreeMachineRoomResponse<{ room_id: number; asset_id: number; placement_type: 'room'; layout_version: number }>
|
||||
>(`/Assets/v1/three-d/rooms/${encodeURIComponent(roomId)}/devices/${encodeURIComponent(assetId)}/placement`, {
|
||||
expected_version: placement.expectedVersion,
|
||||
placement_type: 'room',
|
||||
position_x: placement.positionX,
|
||||
position_y: placement.positionY,
|
||||
position_z: placement.positionZ,
|
||||
rotation_x: placement.rotationX,
|
||||
rotation_y: placement.rotationY,
|
||||
rotation_z: placement.rotationZ,
|
||||
scene_width: placement.sceneWidth,
|
||||
scene_height: placement.sceneHeight,
|
||||
scene_depth: placement.sceneDepth,
|
||||
})
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
|
||||
/** 解除设备在机柜或机房中的位置。 */
|
||||
export async function removeThreeMachineRoomDevicePlacement(
|
||||
roomId: number,
|
||||
assetId: number,
|
||||
expectedVersion: number
|
||||
): Promise<{ room_id: number; asset_id: number; placement_type: 'unplaced'; layout_version: number }> {
|
||||
const response = await request.delete<
|
||||
ThreeMachineRoomResponse<{ room_id: number; asset_id: number; placement_type: 'unplaced'; layout_version: number }>
|
||||
>(`/Assets/v1/three-d/rooms/${encodeURIComponent(roomId)}/devices/${encodeURIComponent(assetId)}/placement`, {
|
||||
data: { expected_version: expectedVersion },
|
||||
})
|
||||
return getResponseDetails(response)
|
||||
}
|
||||
@@ -1,31 +1,100 @@
|
||||
import { request } from '@/api/request'
|
||||
|
||||
/** U 位状态 */
|
||||
export type RackUnitStatus = 'available' | 'occupied' | 'reserved' | 'disabled'
|
||||
|
||||
/** U 位关联资产摘要 */
|
||||
export interface RackUnitAssetSummary {
|
||||
unit_start: number
|
||||
}
|
||||
|
||||
/** U 位公共字段 */
|
||||
export interface RackUnitBase {
|
||||
unit_number: number
|
||||
occupied_units: number
|
||||
description?: string
|
||||
}
|
||||
|
||||
/** 可用 U 位 */
|
||||
export interface AvailableRackUnit extends RackUnitBase {
|
||||
status: 'available'
|
||||
}
|
||||
|
||||
/** 已占用 U 位 */
|
||||
export interface OccupiedRackUnit extends RackUnitBase {
|
||||
status: 'occupied'
|
||||
asset_id: number
|
||||
asset_name: string
|
||||
asset_code: string
|
||||
asset_type: string
|
||||
power_consumption: number
|
||||
asset: RackUnitAssetSummary
|
||||
}
|
||||
|
||||
/** 已预留 U 位 */
|
||||
export interface ReservedRackUnit extends RackUnitBase {
|
||||
status: 'reserved'
|
||||
reserved_for: string
|
||||
reserved_until: string
|
||||
}
|
||||
|
||||
/** 已禁用 U 位 */
|
||||
export interface DisabledRackUnit extends RackUnitBase {
|
||||
status: 'disabled'
|
||||
}
|
||||
|
||||
/** 单个 U 位数据 */
|
||||
export type RackUnitItem = AvailableRackUnit | OccupiedRackUnit | ReservedRackUnit | DisabledRackUnit
|
||||
|
||||
/** U 位页面使用的机柜摘要 */
|
||||
export interface RackUnitRackInfo {
|
||||
id?: number
|
||||
room_id: number
|
||||
height: number
|
||||
status?: string
|
||||
used_power?: number
|
||||
}
|
||||
|
||||
/** 获取机柜 U 位状态响应 */
|
||||
export interface RackUnitListResponse {
|
||||
code: number
|
||||
message?: string
|
||||
details: {
|
||||
rack: RackUnitRackInfo
|
||||
units: RackUnitItem[]
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取机柜U位状态 */
|
||||
export const fetchRackUnits = (rackId: number) => {
|
||||
return request.get(`/Assets/v1/unit/rack/${rackId}`)
|
||||
return request.get<RackUnitListResponse>(`/Assets/v1/unit/rack/${rackId}`)
|
||||
}
|
||||
|
||||
/** 获取U位列表(别名) */
|
||||
export const fetchUnitList = fetchRackUnits
|
||||
|
||||
/** 分配U位 */
|
||||
export const allocateUnit = (data: {
|
||||
/** 机柜设备上架数据 */
|
||||
export interface RackPlacementData {
|
||||
expected_version: number
|
||||
rack_id: number
|
||||
start_unit: number
|
||||
occupied_units: number
|
||||
asset_id?: number
|
||||
asset_code?: string
|
||||
asset_name: string
|
||||
asset_type: string
|
||||
power_consumption?: number
|
||||
description?: string
|
||||
}) => {
|
||||
return request.post('/Assets/v1/unit/allocate', data)
|
||||
power_consumption: number
|
||||
}
|
||||
|
||||
/** 释放U位 */
|
||||
export const releaseUnit = (data: { rack_id: number; start_unit: number; end_unit: number }) => {
|
||||
return request.post('/Assets/v1/unit/release', data)
|
||||
/** 将资产上架到机柜U位 */
|
||||
export const placeAssetInRack = (roomId: number, assetId: number, data: RackPlacementData) => {
|
||||
return request.put(`/Assets/v1/three-d/rooms/${roomId}/devices/${assetId}/placement`, {
|
||||
...data,
|
||||
placement_type: 'rack',
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消资产在机房中的放置 */
|
||||
export const unplaceAsset = (roomId: number, assetId: number, expectedVersion: number) => {
|
||||
return request.delete(`/Assets/v1/three-d/rooms/${roomId}/devices/${assetId}/placement`, {
|
||||
data: { expected_version: expectedVersion },
|
||||
})
|
||||
}
|
||||
|
||||
/** 预留U位 */
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface LoginData {
|
||||
/** 用户信息 */
|
||||
export interface UserItem {
|
||||
id?: number
|
||||
user_id?: number
|
||||
account?: string
|
||||
password?: string
|
||||
confirmPassword?: string
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
@@ -1,12 +1,4 @@
|
||||
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.37754 16.9795L12.7498 9.43027C14.7163 7.41663 17.9428 7.37837 19.9564 9.34482C19.9852 9.37297 20.0137 9.40145 20.0418 9.43027L20.1221 9.51243C22.1049 11.5429 22.1049 14.7847 20.1221 16.8152L12.7498 24.3644C10.7834 26.378 7.55686 26.4163 5.54322 24.4498C5.5144 24.4217 5.48592 24.3932 5.45777 24.3644L5.37754 24.2822C3.39468 22.2518 3.39468 19.0099 5.37754 16.9795Z" fill="#12D2AC"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.0479 9.43034L27.3399 16.8974C29.3674 18.9735 29.3674 22.2883 27.3399 24.3644C25.3735 26.3781 22.147 26.4163 20.1333 24.4499C20.1045 24.4217 20.076 24.3933 20.0479 24.3644L12.7558 16.8974C10.7284 14.8213 10.7284 11.5065 12.7558 9.43034C14.7223 7.4167 17.9488 7.37844 19.9624 9.34489C19.9912 9.37304 20.0197 9.40152 20.0479 9.43034Z" fill="#307AF2"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.1321 9.52163L23.6851 13.1599L16.3931 20.627L9.10103 13.1599L12.6541 9.52163C14.6707 7.45664 17.9794 7.4174 20.0444 9.434C20.074 9.46286 20.1032 9.49207 20.1321 9.52163Z" fill="#0057FE"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="26" height="19" fill="white" transform="translate(3.5 7)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="33" height="33">
|
||||
<path d="M0 240.941176a240.941176 240.941176 0 0 1 240.941176-240.941176h542.117648a240.941176 240.941176 0 0 1 240.941176 240.941176v542.117648a240.941176 240.941176 0 0 1-240.941176 240.941176H240.941176a240.941176 240.941176 0 0 1-240.941176-240.941176V240.941176z" fill="#287BF7"></path>
|
||||
<path d="M340.931765 388.969412a120.621176 120.621176 0 1 0 115.260235 209.799529l70.776471 97.490824a241.091765 241.091765 0 1 1 82.522353-283.587765c15.751529 39.936 14.516706 83.546353 13.763764 110.290824-0.150588 4.879059-0.271059 9.216-0.271059 12.860235 0 22.648471 5.812706 48.519529 18.221177 66.831059 10.24 15.058824 26.654118 28.310588 61.108706 28.310588 31.804235 0 49.152-10.721882 59.331764-22.40753 11.264-12.950588 18.974118-33.370353 18.974118-59.452235 0-18.642824-9.396706-39.574588-27.166118-53.067294-16.022588-12.137412-43.550118-21.594353-86.768941-8.734118l-34.42447-115.440941c75.926588-22.618353 144.112941-9.637647 193.987764 28.190118 48.128 36.502588 74.842353 93.093647 74.842353 149.082353 0 48.489412-14.245647 99.087059-48.609882 138.541176-35.418353 40.719059-87.341176 63.728941-150.166588 63.728941-75.294118 0-128.662588-33.792-160.768-81.106823-29.936941-44.062118-39.032471-95.864471-39.032471-134.475294 0-9.396706 0.150588-17.588706 0.240941-24.847059 0.421647-25.057882 0.632471-38.972235-5.330823-54.091294a120.621176 120.621176 0 0 0-156.491294-67.915294z" fill="#FFFFFF"></path>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<a-spin style="display: block" :loading="loading">
|
||||
<a-spin class="message-box" :class="{ 'is-empty': !renderList.length }" style="display: block" :loading="loading">
|
||||
<a-tabs v-model:activeKey="messageType" type="rounded" destroy-on-hide>
|
||||
<a-tab-pane v-for="item in tabList" :key="item.key">
|
||||
<template #title>
|
||||
<span>{{ item.title }}{{ formatUnreadLength(item.key) }}</span>
|
||||
</template>
|
||||
<a-result v-if="!renderList.length" status="404">
|
||||
<a-result v-if="!renderList.length" class="message-empty" status="404">
|
||||
<template #subtitle>{{ $t('messageBox.noContent') }}</template>
|
||||
</a-result>
|
||||
<List
|
||||
@@ -16,11 +16,6 @@
|
||||
@view-history="openHistory"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<template #extra>
|
||||
<a-button type="text" @click="emptyList">
|
||||
{{ $t('messageBox.tab.button') }}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-tabs>
|
||||
<a-drawer v-model:visible="historyVisible" width="760px" title="通知投递历史" :footer="false" unmount-on-close @open="fetchHistory">
|
||||
<a-table :columns="historyColumns" :data="historyList" :loading="historyLoading" :pagination="historyPagination" row-key="id" @page-change="onHistoryPageChange">
|
||||
@@ -50,7 +45,7 @@ import {
|
||||
import useLoading from '@/hooks/loading'
|
||||
import useNotificationSocket from '@/hooks/useNotificationSocket'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { computed, reactive, ref, toRefs } from 'vue'
|
||||
import { computed, reactive, ref, toRefs, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import List from './list.vue'
|
||||
|
||||
@@ -59,9 +54,13 @@ interface TabItem {
|
||||
title: string
|
||||
avatar?: string
|
||||
}
|
||||
const visibleMessageTypes = ['message']
|
||||
const { loading, setLoading } = useLoading(true)
|
||||
const messageType = ref('message')
|
||||
const { t } = useI18n()
|
||||
const emit = defineEmits<{
|
||||
(event: 'unread-count-change', count: number): void
|
||||
}>()
|
||||
const messageData = reactive<{
|
||||
renderList: MessageRecord[]
|
||||
messageList: MessageRecord[]
|
||||
@@ -92,14 +91,6 @@ const tabList: TabItem[] = [
|
||||
key: 'message',
|
||||
title: t('messageBox.tab.title.message'),
|
||||
},
|
||||
{
|
||||
key: 'notice',
|
||||
title: t('messageBox.tab.title.notice'),
|
||||
},
|
||||
{
|
||||
key: 'todo',
|
||||
title: t('messageBox.tab.title.todo'),
|
||||
},
|
||||
]
|
||||
async function fetchSourceData() {
|
||||
setLoading(true)
|
||||
@@ -176,6 +167,9 @@ const getDeliveryColor = (status: string) => {
|
||||
const renderList = computed(() => {
|
||||
return messageData.messageList.filter((item) => messageType.value === item.type)
|
||||
})
|
||||
const totalUnreadCount = computed(() => {
|
||||
return messageData.messageList.filter((item) => visibleMessageTypes.includes(item.type) && !item.status).length
|
||||
})
|
||||
const unreadCount = computed(() => {
|
||||
return renderList.value.filter((item) => !item.status).length
|
||||
})
|
||||
@@ -190,9 +184,7 @@ const formatUnreadLength = (type: string) => {
|
||||
const handleItemClick = (items: MessageListType) => {
|
||||
if (renderList.value.length) readMessage([...items])
|
||||
}
|
||||
const emptyList = () => {
|
||||
messageData.messageList = []
|
||||
}
|
||||
watch(totalUnreadCount, (count) => emit('unread-count-change', count), { immediate: true })
|
||||
fetchSourceData()
|
||||
useNotificationSocket<MessageRecord>({
|
||||
onNotification: upsertMessageToTop,
|
||||
@@ -201,6 +193,32 @@ useNotificationSocket<MessageRecord>({
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.message-box {
|
||||
width: 400px;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.arco-spin-children) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.arco-tabs-content) {
|
||||
max-height: 360px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&.is-empty {
|
||||
:deep(.arco-tabs-content) {
|
||||
max-height: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.message-empty) {
|
||||
padding: 34px 0 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-popover-popup-content) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
<a-tag v-if="item.deliveryStatus" :color="getDeliveryColor(item.deliveryStatus)">
|
||||
{{ getDeliveryLabel(item.deliveryStatus) }}
|
||||
</a-tag>
|
||||
<a-tag v-else-if="item.messageType === 0" color="gray">未开始</a-tag>
|
||||
<a-tag v-if="(item.occurrenceCount || 1) > 1" color="arcoblue">发生 {{ item.occurrenceCount }} 次</a-tag>
|
||||
<a-tag v-if="item.messageType === 0" color="gray">未开始</a-tag>
|
||||
<a-tag v-else-if="item.messageType === 1" color="green">已开通</a-tag>
|
||||
<a-tag v-else-if="item.messageType === 2" color="blue">进行中</a-tag>
|
||||
<a-tag v-else-if="item.messageType === 3" color="red">即将到期</a-tag>
|
||||
@@ -54,7 +55,7 @@
|
||||
</div>
|
||||
</a-list-item>
|
||||
<template #footer>
|
||||
<a-space fill :size="0" :class="{ 'add-border-top': renderList.length < showMax }">
|
||||
<a-space fill :size="0" class="message-footer-actions" :class="{ 'add-border-top': renderList.length < showMax }">
|
||||
<div class="footer-wrap">
|
||||
<a-link @click="allRead">{{ $t('messageBox.allRead') }}</a-link>
|
||||
</div>
|
||||
@@ -147,10 +148,20 @@ const showMax = 3
|
||||
.arco-list-footer {
|
||||
padding: 0;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
line-height: normal;
|
||||
border-top: none;
|
||||
.arco-space-item {
|
||||
|
||||
.message-footer-actions {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.arco-space-item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
width: 50%;
|
||||
height: 50px;
|
||||
border-right: 1px solid rgb(var(--gray-3));
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
@@ -161,7 +172,20 @@ const showMax = 3
|
||||
}
|
||||
}
|
||||
.footer-wrap {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
|
||||
:deep(.arco-link) {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
:deep(.arco-link:focus-visible) {
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.arco-typography {
|
||||
margin-bottom: 0;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
export default {
|
||||
'messageBox.tab.title.message': 'Message',
|
||||
'messageBox.tab.title.notice': 'Notice',
|
||||
'messageBox.tab.title.todo': 'Todo',
|
||||
'messageBox.tab.button': 'empty',
|
||||
'messageBox.allRead': 'All Read',
|
||||
'messageBox.viewMore': 'View More',
|
||||
'messageBox.noContent': 'No Content',
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
export default {
|
||||
'messageBox.tab.title.message': '消息',
|
||||
'messageBox.tab.title.notice': '通知',
|
||||
'messageBox.tab.title.todo': '待办',
|
||||
'messageBox.tab.button': '清空',
|
||||
'messageBox.allRead': '全部已读',
|
||||
'messageBox.viewMore': '查看更多',
|
||||
'messageBox.noContent': '暂无内容',
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<li>
|
||||
<a-tooltip :content="$t('settings.navbar.alerts')">
|
||||
<div class="message-box-trigger">
|
||||
<a-badge dot>
|
||||
<a-badge dot :count="notificationUnreadCount">
|
||||
<a-button class="nav-btn" type="outline" :shape="'circle'" @click="setPopoverVisible">
|
||||
<icon-notification />
|
||||
</a-button>
|
||||
@@ -62,12 +62,12 @@
|
||||
<a-popover
|
||||
trigger="click"
|
||||
:arrow-style="{ display: 'none' }"
|
||||
:content-style="{ padding: 0, minWidth: '400px' }"
|
||||
:content-style="{ padding: 0, minWidth: '400px', overflow: 'hidden' }"
|
||||
content-class="message-popover"
|
||||
>
|
||||
<div ref="refBtn" class="ref-btn"></div>
|
||||
<template #content>
|
||||
<message-box />
|
||||
<message-box @unread-count-change="handleMessageBoxUnreadCountChange" />
|
||||
</template>
|
||||
</a-popover>
|
||||
</li>
|
||||
@@ -93,7 +93,8 @@
|
||||
<li>
|
||||
<a-dropdown trigger="click">
|
||||
<a-avatar :size="32" :style="{ marginRight: '8px' }">
|
||||
<img alt="avatar" :src="avatar" />
|
||||
<img v-if="avatar" alt="avatar" :src="avatar" />
|
||||
<icon-user v-else />
|
||||
</a-avatar>
|
||||
<template #content>
|
||||
<a-doption>
|
||||
@@ -126,8 +127,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { MessageRecord, queryMessageList } from '@/api/message'
|
||||
import useLocale from '@/hooks/locale'
|
||||
import useUser from '@/hooks/user'
|
||||
import useNotificationSocket from '@/hooks/useNotificationSocket'
|
||||
import { LOCALE_OPTIONS } from '@/locale'
|
||||
import { useAppStore, useUserStore } from '@/store'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
@@ -147,7 +150,7 @@ const { changeLocale, currentLocale }: any = useLocale()
|
||||
const { isFullscreen, toggle: toggleFullScreen } = useFullscreen()
|
||||
const locales = [...LOCALE_OPTIONS]
|
||||
const avatar = computed(() => {
|
||||
return userStore.avatar || '//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/dfdba5317c0c20ce20e64fac803d52bc.svg~tplv-49unhts6dw-image.image'
|
||||
return userStore.avatar
|
||||
})
|
||||
const theme = computed(() => {
|
||||
return appStore.theme
|
||||
@@ -173,8 +176,24 @@ const setVisible = () => {
|
||||
}
|
||||
const refBtn = ref()
|
||||
const triggerBtn = ref()
|
||||
const notificationUnreadCount = ref(0)
|
||||
const visibleMessageTypes = ['message']
|
||||
const passwordChangeVisible = ref(false)
|
||||
const profileChangeVisible = ref(false)
|
||||
const updateNotificationUnreadCount = (list: MessageRecord[] = []) => {
|
||||
notificationUnreadCount.value = list.filter((item) => visibleMessageTypes.includes(item.type) && !item.status).length
|
||||
}
|
||||
const fetchNotificationUnreadCount = async () => {
|
||||
try {
|
||||
const { data } = await queryMessageList()
|
||||
updateNotificationUnreadCount(data)
|
||||
} catch (err) {
|
||||
updateNotificationUnreadCount()
|
||||
}
|
||||
}
|
||||
const handleMessageBoxUnreadCountChange = (count: number) => {
|
||||
notificationUnreadCount.value = count
|
||||
}
|
||||
const setPopoverVisible = () => {
|
||||
const event = new MouseEvent('click', {
|
||||
view: window,
|
||||
@@ -201,6 +220,12 @@ const setDropDownVisible = () => {
|
||||
triggerBtn.value.dispatchEvent(event)
|
||||
}
|
||||
const toggleDrawerMenu = inject('toggleDrawerMenu') as () => void
|
||||
|
||||
fetchNotificationUnreadCount()
|
||||
useNotificationSocket<MessageRecord>({
|
||||
onNotification: fetchNotificationUnreadCount,
|
||||
onReconnectAfter: fetchNotificationUnreadCount,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
import { ref, watch } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { resetUserPassword } from '@/api/module/user'
|
||||
import type { UserItem } from '@/api/types'
|
||||
import SafeStorage, { AppStorageKey } from '@/utils/safeStorage'
|
||||
|
||||
interface Props {
|
||||
@@ -79,12 +80,12 @@ const handleSavePassword = async () => {
|
||||
|
||||
try {
|
||||
// 从 SafeStorage 获取登录用户信息
|
||||
const userInfo = SafeStorage.get(AppStorageKey.USER_INFO) || {}
|
||||
const userInfo = SafeStorage.get<UserItem>(AppStorageKey.USER_INFO)
|
||||
const res = await resetUserPassword({
|
||||
account: userInfo.account || '',
|
||||
account: userInfo?.account || '',
|
||||
code: '123456', // 暂时没校验,随便传
|
||||
password: form.value.newPassword,
|
||||
phone: userInfo.phone || '13800138000', // 暂时没校验,随便传
|
||||
phone: userInfo?.phone || '13800138000', // 暂时没校验,随便传
|
||||
})
|
||||
|
||||
if (res.code === 0) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
import { ref, watch } from 'vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { modifyUser } from '@/api/module/user'
|
||||
import type { UserItem } from '@/api/types'
|
||||
import SafeStorage, { AppStorageKey } from '@/utils/safeStorage'
|
||||
|
||||
interface Props {
|
||||
@@ -56,11 +57,11 @@ watch(
|
||||
visible.value = val
|
||||
if (val) {
|
||||
// 打开时从存储中获取用户信息
|
||||
const userInfo = SafeStorage.get(AppStorageKey.USER_INFO) || {}
|
||||
const userInfo = SafeStorage.get<UserItem>(AppStorageKey.USER_INFO)
|
||||
form.value = {
|
||||
account: userInfo.account || '',
|
||||
name: userInfo.name || '',
|
||||
email: userInfo.email || '',
|
||||
account: userInfo?.account || '',
|
||||
name: userInfo?.name || '',
|
||||
email: userInfo?.email || '',
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,11 +77,11 @@ const handleSaveProfile = async () => {
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const userInfo = SafeStorage.get(AppStorageKey.USER_INFO) || {}
|
||||
const userInfo = SafeStorage.get<UserItem>(AppStorageKey.USER_INFO)
|
||||
const updatedUserInfo = {
|
||||
...userInfo,
|
||||
...form.value,
|
||||
id: userInfo.user_id,
|
||||
id: userInfo?.user_id ?? userInfo?.id,
|
||||
}
|
||||
|
||||
const res = await modifyUser(updatedUserInfo)
|
||||
|
||||