initial commit

This commit is contained in:
yangsy
2025-08-13 01:36:30 +08:00
commit 202f83d157
78 changed files with 5896 additions and 0 deletions

8
.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
max_line_length = 100

16
.env Normal file
View File

@@ -0,0 +1,16 @@
# 设备页定时请求时间间隔
VITE_REQUEST_INTERVAL = 30
# 网管的appKey
VITE_NDM_APP_KEY = ndm
# clientId 和 clientSecret 用于生成 Authorization
VITE_LAMP_CLIENT_ID = cuedes_admin
VITE_LAMP_CLIENT_SECRET = cuedes_admin_secret
# 用于登录 LAMP 系统的用户名和密码
VITE_LAMP_USERNAME = lamp
VITE_LAMP_PASSWORD = fjoc(1KHP(Ls&Bje)C
# 如果 Authorization 已存在则会直接采用, 否则会根据 clientId 和 clientSecret 生成
VITE_LAMP_AUTHORIZATION = Y3VlZGVzX2FkbWluOmN1ZWRlc19hZG1pbl9zZWNyZXQ=

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

30
.gitignore vendored Normal file
View File

@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

6
.prettierrc.json Normal file
View File

@@ -0,0 +1,6 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"printWidth": 100
}

8
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"recommendations": [
"Vue.volar",
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode"
]
}

39
README.md Normal file
View File

@@ -0,0 +1,39 @@
# ndm-web-client-v
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
pnpm install
```
### Compile and Hot-Reload for Development
```sh
pnpm dev
```
### Type-Check, Compile and Minify for Production
```sh
pnpm build
```
### Lint with [ESLint](https://eslint.org/)
```sh
pnpm lint
```

1
env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

28
eslint.config.ts Normal file
View File

@@ -0,0 +1,28 @@
import { globalIgnores } from 'eslint/config'
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
import pluginVue from 'eslint-plugin-vue'
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
// import { configureVueProject } from '@vue/eslint-config-typescript'
// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
export default defineConfigWithVueTs(
{
name: 'app/files-to-lint',
files: ['**/*.{ts,mts,tsx,vue}'],
},
globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,
skipFormatting,
{
rules: {
'@typescript-eslint/no-explicit-any': 'off',
},
},
)

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>网络设备管理平台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

56
package.json Normal file
View File

@@ -0,0 +1,56 @@
{
"name": "ndm-web-client-v",
"version": "0.0.0",
"private": true,
"type": "module",
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build",
"lint": "eslint . --fix",
"format": "prettier --write src/"
},
"dependencies": {
"@stomp/stompjs": "^7.1.1",
"@vueuse/core": "^13.6.0",
"axios": "^1.11.0",
"compressing": "^2.0.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"destr": "^2.0.5",
"echarts": "^6.0.0",
"es-toolkit": "^1.39.9",
"naive-ui": "^2.42.0",
"nanoid": "^5.1.5",
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0",
"vue": "^3.5.18",
"vue-router": "^4.5.1",
"ws": "^8.18.3"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.2",
"@types/crypto-js": "^4.2.2",
"@types/node": "^22.16.5",
"@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.0.1",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.6.0",
"@vue/tsconfig": "^0.7.0",
"eslint": "^9.31.0",
"eslint-plugin-vue": "~10.3.0",
"jiti": "^2.4.2",
"npm-run-all2": "^8.0.4",
"prettier": "3.6.2",
"typescript": "~5.8.0",
"vite": "^7.0.6",
"vite-plugin-vue-devtools": "^8.0.0",
"vue-tsc": "^3.0.4"
},
"packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748"
}

4067
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,2 @@
onlyBuiltDependencies:
- esbuild

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

50
src/App.vue Normal file
View File

@@ -0,0 +1,50 @@
<script lang="ts">
const GlobalFeedback = defineComponent({
setup() {
window.$dialog = useDialog()
window.$loadingBar = useLoadingBar()
window.$message = useMessage()
window.$notification = useNotification()
return () => null
},
})
</script>
<script setup lang="ts">
import {
dateZhCN,
NConfigProvider,
NDialogProvider,
NLoadingBarProvider,
NMessageProvider,
NNotificationProvider,
useDialog,
useLoadingBar,
useMessage,
useNotification,
zhCN,
} from 'naive-ui'
import { defineComponent } from 'vue'
import { useThemeStore } from '@/stores/theme'
import { storeToRefs } from 'pinia'
const themeStore = useThemeStore()
const { themeMode } = storeToRefs(themeStore)
</script>
<template>
<NConfigProvider :date-locale="dateZhCN" :locale="zhCN" :theme="themeMode">
<NDialogProvider>
<NLoadingBarProvider>
<NMessageProvider>
<NNotificationProvider>
<GlobalFeedback />
<RouterView />
</NNotificationProvider>
</NMessageProvider>
</NLoadingBarProvider>
</NDialogProvider>
</NConfigProvider>
</template>
<style scoped></style>

28
src/apis/client.ts Normal file
View File

@@ -0,0 +1,28 @@
import type { AxiosError } from 'axios';
import { Request } from '@/utils/request';
export const ndmClient = new Request({
requestInterceptor: (config) => {
return config;
},
responseInterceptor: (response) => {
return response;
},
responseErrorInterceptor: (error) => {
return Promise.reject(error);
},
});
export const userClient = new Request({
responseErrorInterceptor: (error) => {
const err = error as AxiosError;
if (err.response?.status === 401) {
// TODO: 处理 401 错误,例如跳转到登录页
}
if (err.response?.status === 404) {
// TODO: 处理 404 错误
}
return Promise.reject(error);
},
});

View File

@@ -0,0 +1,6 @@
export * from './ndm-camera-diag-info';
export * from './ndm-decoder-diag-info';
export * from './ndm-nvr-diag-info';
export * from './ndm-security-box-diag-info';
export * from './ndm-server-diag-info';
export * from './ndm-switch-diag-info';

View File

@@ -0,0 +1,5 @@
export interface NdmCameraDiagInfo {
[key: string]: any;
logTime: string;
info: string;
}

View File

@@ -0,0 +1,14 @@
export interface NdmDecoderDiagInfo {
[key: string]: any;
logTime: string;
stCommonInfo: {
设备ID: string;
软件版本: string;
生产厂商: string;
设备别名: string;
设备型号: string;
硬件版本: string;
内存使用率: string;
CPU使用率: string;
};
}

View File

@@ -0,0 +1,23 @@
export interface NdmNvrDiagInfo {
[key: string]: any;
logTime: string;
info: {
diskHealth: number[];
groupInfoList: {
freeSize: number;
state: number;
stateValue: string;
totalSize: number;
}[];
};
stCommonInfo: {
设备ID: string;
软件版本: string;
生产厂商: string;
设备别名: string;
设备型号: string;
硬件版本: string;
内存使用率: string;
CPU使用率: string;
};
}

View File

@@ -0,0 +1,21 @@
export interface NdmSecurityBoxDiagInfo {
[key: string]: any;
info: [
{
addrCode: number;
circuits: {
current: number;
status: number;
voltage: number;
}[];
fanSpeeds: number[];
humidity: number;
switches: number[];
temperature: number;
},
];
stCommonInfo: {
内存使用率: string;
CPU使用率: string;
};
}

View File

@@ -0,0 +1,9 @@
export interface NdmServerDiagInfo {
[key: string]: any;
commInfo: {
CPU使用率: string;
内存使用率: string;
磁盘使用率: string;
系统运行时间: string;
};
}

View File

@@ -0,0 +1,22 @@
export interface NdmSwitchDiagInfo {
[key: string]: any;
cpuRatio?: string; // 因环境不同可能不存在
memoryRatio?: string; // 因环境不同可能不存在
logTime: string;
info: {
overFlowPorts: string[];
portInfoList: NdmSwitchPortInfo[];
};
}
export interface NdmSwitchPortInfo {
flow: number;
inBytes: number;
inFlow: number;
lastInBytes: number;
lastOutBytes: number;
outBytes: number;
outFlow: number;
portName: string;
upDown: number;
}

View File

@@ -0,0 +1,2 @@
export * from './diag-info';
export * from './station';

View File

@@ -0,0 +1,6 @@
export interface Station {
id: string;
code: string;
name: string;
online: boolean;
}

View File

@@ -0,0 +1,18 @@
export interface SuperModel {
id: string
createdBy: string
createdTime: string
echoMap?: any
}
export interface BaseModel extends SuperModel {
updatedBy: string
updatedTime: string
}
export interface TreeModel extends BaseModel {
parentId: string
sortValue: number
treeGrade: number
treePath: string
}

View File

@@ -0,0 +1,33 @@
export interface BasicPageParams {
page: number
pageSize: number
}
export interface BasicFetchResult<T> {
items: T[]
total: number
}
export interface RemoteData {
key: string | number
data?: any
}
export interface PageParams<T> {
model: T
size: number
current: number
sort?: string
order?: string
extra?: any
}
export interface PageResult<T> {
records: T[]
// offset: number
pages: string
current: string
total: string
size: string
orders: any[]
}

View File

@@ -0,0 +1,8 @@
export type ReduceForUpdateVO =
| 'createdTime'
| 'createdBy'
| 'updatedTime'
| 'updatedBy'
| 'echoMap'
export type ReduceForSaveVO = ReduceForUpdateVO | 'id'
export type ReduceForPageQuery = ReduceForUpdateVO

View File

@@ -0,0 +1,27 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmDeviceAlarmLogVO extends BaseModel {
alarmNo: string;
alarmDate: string;
faultLocation: string;
faultDescription: string;
faultLevel: string;
faultCode: string;
deviceId: string;
deviceName: string;
alarmCategory: string;
alarmConfirm: string;
alarmRepairSuggestion: string;
impactService: string;
alarmType: string;
deviceType: string;
}
export type NdmDeviceAlarmLogResultVO = Partial<NdmDeviceAlarmLogVO>;
export type NdmDeviceAlarmLogSaveVO = Partial<Omit<NdmDeviceAlarmLogVO, ReduceForSaveVO>>;
export type NdmDeviceAlarmLogUpdateVO = Partial<Omit<NdmDeviceAlarmLogVO, ReduceForUpdateVO>>;
export type NdmDeviceAlarmLogPageQuery = Partial<Omit<NdmDeviceAlarmLogVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,28 @@
import type { NdmSecurityBoxVO } from './other/ndm-security-box';
import type { NdmSwitchVO } from './other/ndm-switch';
import type { NdmNvrVO } from './storage/ndm-nvr';
import type { NdmCameraVO } from './video/ndm-camera';
import type { NdmDecoderVO } from './video/ndm-decoder';
import type { NdmKeyboardVO } from './video/ndm-keyboard';
import type { NdmMediaServerVO } from './video/ndm-media-server';
import type { NdmVideoServerVO } from './video/ndm-video-server';
export * from './alarm/ndm-device-alarm-log';
export * from './log/ndm-icmp-log';
export * from './log/ndm-snmp-log';
export * from './other/ndm-security-box';
export * from './other/ndm-switch';
export * from './storage/ndm-nvr';
export * from './video/ndm-camera';
export * from './video/ndm-decoder';
export * from './video/ndm-keyboard';
export * from './video/ndm-media-server';
export * from './video/ndm-video-server';
export type NdmDeviceVO = NdmSecurityBoxVO | NdmSwitchVO | NdmNvrVO | NdmCameraVO | NdmDecoderVO | NdmKeyboardVO | NdmMediaServerVO | NdmVideoServerVO;
export type NdmServerVO = NdmMediaServerVO | NdmVideoServerVO;

View File

@@ -0,0 +1,17 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmIcmpLogVO extends BaseModel {
deviceId: string;
name: string;
ipAddress: string;
deviceStatus: string;
}
export type NdmIcmpLogResultVO = Partial<NdmIcmpLogVO>;
export type NdmIcmpLogSaveVO = Partial<Omit<NdmIcmpLogVO, ReduceForSaveVO>>;
export type NdmIcmpLogUpdateVO = Partial<Omit<NdmIcmpLogVO, ReduceForUpdateVO>>;
export type NdmIcmpLogPageQuery = Partial<Omit<NdmIcmpLogVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,18 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmSnmpLogVO extends BaseModel {
deviceId: string;
name: string;
ipAddress: string;
diagInfo: string;
deviceType: string;
}
export type NdmSnmpLogResultVO = Partial<NdmSnmpLogVO>;
export type NdmSnmpLogSaveVO = Partial<Omit<NdmSnmpLogVO, ReduceForSaveVO>>;
export type NdmSnmpLogUpdateVO = Partial<Omit<NdmSnmpLogVO, ReduceForUpdateVO>>;
export type NdmSnmpLogPageQuery = Partial<Omit<NdmSnmpLogVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,35 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmSecurityBoxVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
}
export type NdmSecurityBoxResultVO = Partial<NdmSecurityBoxVO>;
export type NdmSecurityBoxSaveVO = Partial<Omit<NdmSecurityBoxVO, ReduceForSaveVO>>;
export type NdmSecurityBoxUpdateVO = Partial<Omit<NdmSecurityBoxVO, ReduceForUpdateVO>>;
export type NdmSecurityBoxPageQuery = Partial<Omit<NdmSecurityBoxVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,35 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmSwitchVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
}
export type NdmSwitchResultVO = Partial<NdmSwitchVO>;
export type NdmSwitchSaveVO = Partial<Omit<NdmSwitchVO, ReduceForSaveVO>>;
export type NdmSwitchUpdateVO = Partial<Omit<NdmSwitchVO, ReduceForUpdateVO>>;
export type NdmSwitchPageQuery = Partial<Omit<NdmSwitchVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,134 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmNvrVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
gbCode: string;
gbPort: number;
gbDomain: string;
gb28181Enabled: boolean;
onvifPort: number;
onvifUsername: string;
onvifPassword: string;
onvifMajorIndex: number;
onvifMinorIndex: number;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
recordCheckEnabled: boolean;
clusterList: string;
}
export type NdmNvrResultVO = Partial<NdmNvrVO>;
export type NdmNvrSaveVO = Partial<Omit<NdmNvrVO, ReduceForSaveVO>>;
export type NdmNvrUpdateVO = Partial<Omit<NdmNvrVO, ReduceForUpdateVO>>;
export type NdmNvrPageQuery = Partial<Omit<NdmNvrVO, ReduceForPageQuery>>;
export interface RecordSum {
code: string;
recordList: NdmRecordCheck[];
channel: ClientChannel;
availableRecordList: UnixRecordItem[];
unavailableRecordList: UnixRecordItem[];
}
export interface NdmRecordCheck extends BaseModel {
gbCode: string;
parentGbCode: string;
name: string;
ipAddress: string;
diagInfo: string | RecordInfo;
checkDate: string;
}
export interface ClientChannel {
code: string;
name: string;
manufacture: string;
model: string;
owner: string;
civilCode: string;
block: string;
address: string;
parental: number;
parentId: string;
status: number;
longitude: number;
latitude: number;
}
export interface RecordInfo {
deviceId: string;
channelId: string;
sn: string;
name: string;
sumNum: number;
count: number;
lastTime: number;
recordList: RecordItem[];
}
export interface RecordItem {
startTime: string;
endTime: string;
}
export interface UnixRecordItem {
startTime: number;
endTime: number;
}
export interface QueryGbRecordBody {
code: string;
start: string;
end: string;
}
export interface QueryGbDeviceBody {
code: string;
time: string;
}
export interface QueryRecordCheckBody {
parentId: string;
start: string;
end: string;
}
export interface QueryReloadCheckBody {
code: string;
name: string;
manufacture: string;
model: string;
owner: string;
civilCode: string;
block: string;
address: string;
parental: number;
parentId: string;
status: number;
longitude: number;
latitude: number;
dayOffset: number;
}

View File

@@ -0,0 +1,45 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmCameraVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
gbCode: string;
gbPort: number;
gbDomain: string;
gb28181Enabled: boolean;
onvifPort: number;
onvifUsername: string;
onvifPassword: string;
onvifMajorIndex: number;
onvifMinorIndex: number;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
cameraType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
}
export type NdmCameraResultVO = Partial<NdmCameraVO>;
export type NdmCameraSaveVO = Partial<Omit<NdmCameraVO, ReduceForSaveVO>>;
export type NdmCameraUpdateVO = Partial<Omit<NdmCameraVO, ReduceForUpdateVO>>;
export type NdmCameraPageQuery = Partial<Omit<NdmCameraVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,42 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmDecoderVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
gbCode: string;
gbPort: number;
gbDomain: string;
gb28181Enabled: boolean;
onvifPort: number;
onvifUsername: string;
onvifPassword: string;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
}
export type NdmDecoderResultVO = Partial<NdmDecoderVO>;
export type NdmDecoderSaveVO = Partial<Omit<NdmDecoderVO, ReduceForSaveVO>>;
export type NdmDecoderUpdateVO = Partial<Omit<NdmDecoderVO, ReduceForUpdateVO>>;
export type NdmDecoderPageQuery = Partial<Omit<NdmDecoderVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,35 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmKeyboardVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
}
export type NdmKeyboardResultVO = Partial<NdmKeyboardVO>;
export type NdmKeyboardSaveVO = Partial<Omit<NdmKeyboardVO, ReduceForSaveVO>>;
export type NdmKeyboardUpdateVO = Partial<Omit<NdmKeyboardVO, ReduceForUpdateVO>>;
export type NdmKeyboardPageQuery = Partial<Omit<NdmKeyboardVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,39 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmMediaServerVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
gbCode: string;
gbPort: number;
gbDomain: string;
gb28181Enabled: boolean;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
}
export type NdmMediaServerResultVO = Partial<NdmMediaServerVO>;
export type NdmMediaServerSaveVO = Partial<Omit<NdmMediaServerVO, ReduceForSaveVO>>;
export type NdmMediaServerUpdateVO = Partial<Omit<NdmMediaServerVO, ReduceForUpdateVO>>;
export type NdmMediaServerPageQuery = Partial<Omit<NdmMediaServerVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,39 @@
import type { BaseModel } from '../../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../../base/reduce';
export interface NdmVideoServerVO extends BaseModel {
deviceId: string;
name: string;
manufacturer: string;
state: boolean;
model: string;
ipAddress: string;
manageUrl: string;
manageUsername: string;
managePassword: string;
gbCode: string;
gbPort: number;
gbDomain: string;
gb28181Enabled: boolean;
diagFlag: string;
diagParam: string;
diagFormat: string;
lastDiagInfo: string;
lastDiagTime: string;
icmpEnabled: boolean;
description: string;
deviceStatus: string;
deviceType: string;
community: string;
frontendConfig: string;
linkDescription: string;
snmpEnabled: boolean;
}
export type NdmVideoServerResultVO = Partial<NdmVideoServerVO>;
export type NdmVideoServerSaveVO = Partial<Omit<NdmVideoServerVO, ReduceForSaveVO>>;
export type NdmVideoServerUpdateVO = Partial<Omit<NdmVideoServerVO, ReduceForUpdateVO>>;
export type NdmVideoServerPageQuery = Partial<Omit<NdmVideoServerVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1,18 @@
import type { BaseModel } from '../base/model';
import type { ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '../base/reduce';
export interface DefParameterVO extends BaseModel {
key: string;
value: string;
name: string;
remarks: string;
paramType: string;
}
export type DefParameterResultVO = Partial<DefParameterVO>;
export type DefParameterSaveVO = Partial<Omit<DefParameterVO, ReduceForSaveVO>>;
export type DefParameterUpdateVO = Partial<Omit<DefParameterVO, ReduceForUpdateVO>>;
export type DefParameterPageQuery = Partial<Omit<DefParameterVO, ReduceForPageQuery>>;

View File

@@ -0,0 +1 @@
export * from './def-parameter';

View File

@@ -0,0 +1,2 @@
export * from './login-params';
export * from './login-result';

View File

@@ -0,0 +1,8 @@
export interface LoginParams {
username: string;
password: string;
code: string;
key: string;
grantType: 'PASSWORD' | 'CAPTCHA' | 'REFRESH_TOKEN';
refreshToken?: string;
}

View File

@@ -0,0 +1,8 @@
export interface LoginResult {
tenantId: string;
uuid: string;
token: string;
refreshToken: string;
expire: string;
expiration: string;
}

View File

@@ -0,0 +1,8 @@
export * from './ndm-camera';
export * from './ndm-decoder';
export * from './ndm-keyboard';
export * from './ndm-media-server';
export * from './ndm-nvr';
export * from './ndm-security-box';
export * from './ndm-switch';
export * from './ndm-video-server';

View File

@@ -0,0 +1,24 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmCameraPageQuery, NdmCameraResultVO, NdmCameraUpdateVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmCameraPage = async (stationCode: string, pageQuery: PageParams<NdmCameraPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmCameraResultVO>>(`${prefix}/api/ndm/ndmCamera/page`, pageQuery);
const [err, ndmCameraData] = resp;
if (err || !ndmCameraData) {
throw err;
}
return ndmCameraData;
};
export const putNdmCamera = async (stationCode: string, updateVO: NdmCameraUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmCameraResultVO>(`${prefix}/api/ndm/ndmCamera`, updateVO);
const [err, ndmCamera] = resp;
if (err || !ndmCamera) {
throw err;
}
return ndmCamera;
};

View File

@@ -0,0 +1,24 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmDecoderPageQuery, NdmDecoderResultVO, NdmDecoderUpdateVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmDecoderPage = async (stationCode: string, pageQuery: PageParams<NdmDecoderPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmDecoderResultVO>>(`${prefix}/api/ndm/ndmDecoder/page`, pageQuery);
const [err, ndmDecoderData] = resp;
if (err || !ndmDecoderData) {
throw err;
}
return ndmDecoderData;
};
export const putNdmDecoder = async (stationCode: string, updateVO: NdmDecoderUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmDecoderResultVO>(`${prefix}/api/ndm/ndmDecoder`, updateVO);
const [err, ndmDecoder] = resp;
if (err || !ndmDecoder) {
throw err;
}
return ndmDecoder;
};

View File

@@ -0,0 +1,24 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmKeyboardPageQuery, NdmKeyboardResultVO, NdmKeyboardUpdateVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmKeyboardPage = async (stationCode: string, pageQuery: PageParams<NdmKeyboardPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmKeyboardResultVO>>(`${prefix}/api/ndm/ndmKeyboard/page`, pageQuery);
const [err, ndmKeyboardData] = resp;
if (err || !ndmKeyboardData) {
throw err;
}
return ndmKeyboardData;
};
export const putNdmKeyboard = async (stationCode: string, updateVO: NdmKeyboardUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmKeyboardResultVO>(`${prefix}/api/ndm/ndmKeyboard`, updateVO);
const [err, ndmKeyboard] = resp;
if (err || !ndmKeyboard) {
throw err;
}
return ndmKeyboard;
};

View File

@@ -0,0 +1,24 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmMediaServerPageQuery, NdmMediaServerResultVO, NdmMediaServerUpdateVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmMediaServerPage = async (stationCode: string, pageQuery: PageParams<NdmMediaServerPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmMediaServerResultVO>>(`${prefix}/api/ndm/ndmMediaServer/page`, pageQuery);
const [err, ndmMediaServerData] = resp;
if (err || !ndmMediaServerData) {
throw err;
}
return ndmMediaServerData;
};
export const putNdmMediaServer = async (stationCode: string, updateVO: NdmMediaServerUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmMediaServerResultVO>(`${prefix}/api/ndm/ndmMediaServer`, updateVO);
const [err, ndmMediaServer] = resp;
if (err || !ndmMediaServer) {
throw err;
}
return ndmMediaServer;
};

View File

@@ -0,0 +1,10 @@
import { ndmClient } from '@/apis/client';
export const resetMonitorSchedule = async (stationCode: string) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.get<void>(`${prefix}/api/ndm/ndmConstant/anyTenant/resetMonitorSchedule`);
const [err] = resp;
if (err) {
throw err;
}
};

View File

@@ -0,0 +1,69 @@
import dayjs from 'dayjs';
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { ClientChannel, NdmNvrPageQuery, NdmNvrResultVO, NdmNvrUpdateVO, NdmNvrVO, NdmRecordCheck } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmNvrPage = async (stationCode: string, pageQuery: PageParams<NdmNvrPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmNvrResultVO>>(`${prefix}/api/ndm/ndmNvr/page`, pageQuery);
const [err, ndmNvrData] = resp;
if (err || !ndmNvrData) {
throw err;
}
return ndmNvrData;
};
export const putNdmNvr = async (stationCode: string, updateVO: NdmNvrUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmNvrResultVO>(`${prefix}/api/ndm/ndmNvr`, updateVO);
const [err, ndmNvr] = resp;
if (err || !ndmNvr) {
throw err;
}
return ndmNvr;
};
export const getChannelList = async (stationCode: string, ndmNvr: NdmNvrVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<ClientChannel[]>(`${prefix}/api/ndm/ndmRecordCheck/getChannelList`, {
code: ndmNvr.gbCode,
time: '',
});
const [err, channelList] = resp;
if (err || !channelList) {
throw err;
}
return channelList;
};
export const getRecordCheckByParentId = async (stationCode: string, ndmNvr: NdmNvrVO, lastDays: number, gbCodeList: string[] = []) => {
const prefix = stationCode ? `/${stationCode}` : '';
const endDateTime = dayjs();
const startDateTime = endDateTime.subtract(lastDays, 'day');
const resp = await ndmClient.post<NdmRecordCheck[]>(`${prefix}/api/ndm/ndmRecordCheck/getRecordCheckByParentId`, {
start: startDateTime.format('YYYY-MM-DD'),
end: endDateTime.format('YYYY-MM-DD'),
parentId: ndmNvr.gbCode,
gbCodeList,
});
const [err, recordCheckList] = resp;
if (err || !recordCheckList) {
throw err;
}
return recordCheckList;
};
export const reloadRecordCheckByGbId = async (stationCode: string, channel: ClientChannel, dayOffset: number) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<boolean>(`${prefix}/api/ndm/ndmRecordCheck/reloadRecordCheckByGbId`, {
...channel,
dayOffset,
});
const [err, result] = resp;
if (err || !result) {
throw err;
}
return result;
};

View File

@@ -0,0 +1,39 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmSecurityBoxPageQuery, NdmSecurityBoxResultVO, NdmSecurityBoxUpdateVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmSecurityBoxPage = async (stationCode: string, pageQuery: PageParams<NdmSecurityBoxPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmSecurityBoxResultVO>>(`${prefix}/api/ndm/ndmSecurityBox/page`, pageQuery);
const [err, ndmSecurityBoxData] = resp;
if (err || !ndmSecurityBoxData) {
throw err;
}
return ndmSecurityBoxData;
};
export const putNdmSecurityBox = async (stationCode: string, updateVO: NdmSecurityBoxUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmSecurityBoxResultVO>(`${prefix}/api/ndm/ndmSecurityBox`, updateVO);
const [err, ndmSecurityBox] = resp;
if (err || !ndmSecurityBox) {
throw err;
}
return ndmSecurityBox;
};
export const turnStatus = async (stationCode: string, ipAddress: string, circuitIndex: number, status: number) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<boolean>(`${prefix}/api/ndm/ndmSecurityBox/turnStatus`, {
community: 'public',
ipAddress,
circuit: `${circuitIndex}`,
status,
});
const [err, result] = resp;
if (err || !result) {
throw err;
}
return result;
};

View File

@@ -0,0 +1,24 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmSwitchPageQuery, NdmSwitchResultVO, NdmSwitchUpdateVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmSwitchPage = async (stationCode: string, pageQuery: PageParams<NdmSwitchPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmSwitchResultVO>>(`${prefix}/api/ndm/ndmSwitch/page`, pageQuery);
const [err, ndmSwitchData] = resp;
if (err || !ndmSwitchData) {
throw err;
}
return ndmSwitchData;
};
export const putNdmSwitch = async (stationCode: string, updateVO: NdmSwitchUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmSwitchResultVO>(`${prefix}/api/ndm/ndmSwitch`, updateVO);
const [err, ndmSwitch] = resp;
if (err || !ndmSwitch) {
throw err;
}
return ndmSwitch;
};

View File

@@ -0,0 +1,24 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmVideoServerPageQuery, NdmVideoServerResultVO, NdmVideoServerUpdateVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postNdmVideoServerPage = async (stationCode: string, pageQuery: PageParams<NdmVideoServerPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmVideoServerResultVO>>(`${prefix}/api/ndm/ndmVideoServer/page`, pageQuery);
const [err, ndmVideoServerData] = resp;
if (err || !ndmVideoServerData) {
throw err;
}
return ndmVideoServerData;
};
export const putNdmVideoServer = async (stationCode: string, updateVO: NdmVideoServerUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<NdmVideoServerResultVO>(`${prefix}/api/ndm/ndmVideoServer`, updateVO);
const [err, ndmVideoServer] = resp;
if (err || !ndmVideoServer) {
throw err;
}
return ndmVideoServer;
};

View File

@@ -0,0 +1,17 @@
export * from './device/ndm-camera';
export * from './device/ndm-decoder';
export * from './device/ndm-keyboard';
export * from './device/ndm-media-server';
export * from './device/ndm-monitor';
export * from './device/ndm-nvr';
export * from './device/ndm-security-box';
export * from './device/ndm-switch';
export * from './device/ndm-video-server';
export * from './log/ndm-device-alarm-log';
export * from './log/ndm-icmp-log';
export * from './log/ndm-snmp-log';
export * from './station/ndm-verify';
export * from './system/def-parameter';

View File

@@ -0,0 +1,10 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmDeviceAlarmLogPageQuery, NdmDeviceAlarmLogResultVO } from '@/apis/models/device/alarm/ndm-device-alarm-log';
import { ndmClient } from '@/apis/client';
export const postNdmDeviceAlarmLogPage = async (stationCode: string, pageQuery: PageParams<NdmDeviceAlarmLogPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmDeviceAlarmLogResultVO>>(`${prefix}/api/ndm/ndmDeviceAlarmLog/page`, pageQuery);
return resp;
};

View File

@@ -0,0 +1,10 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmIcmpLogPageQuery, NdmIcmpLogResultVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postIcmpLogPage = async (stationCode: string, pageQuery: PageParams<NdmIcmpLogPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmIcmpLogResultVO>>(`${prefix}/api/ndm/ndmIcmpLog/page`, pageQuery);
return resp;
};

View File

@@ -0,0 +1,10 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { NdmSnmpLogPageQuery, NdmSnmpLogResultVO } from '@/apis/models/device';
import { ndmClient } from '@/apis/client';
export const postSnmpLogPage = async (stationCode: string, pageQuery: PageParams<NdmSnmpLogPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<NdmSnmpLogResultVO>>(`${prefix}/api/ndm/ndmSnmpLog/page`, pageQuery);
return resp;
};

View File

@@ -0,0 +1,10 @@
import { ndmClient } from '@/apis/client';
export const ndmVerify = async (stationCode: string) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<void>(`${prefix}/api/ndm/ndmKeepAlive/verify`, {}, { timeout: 5000 });
const [err] = resp;
if (err) {
throw err;
}
};

View File

@@ -0,0 +1,22 @@
import type { PageParams, PageResult } from '@/apis/models/base/page';
import type { Result } from '@/axios';
import type { DefParameterPageQuery, DefParameterResultVO, DefParameterUpdateVO } from '../../models/system';
import { ndmClient } from '../../client';
export const postDefParameterPage = async (stationCode: string, pageQuery: PageParams<DefParameterPageQuery>) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.post<PageResult<DefParameterResultVO>>(`${prefix}/api/system/defParameter/page`, pageQuery);
const [err, defParameterData] = resp;
if (err || !defParameterData) {
throw err;
}
return defParameterData;
};
export const putDefParameter = async (stationCode: string, updateVO: DefParameterUpdateVO) => {
const prefix = stationCode ? `/${stationCode}` : '';
const resp = await ndmClient.put<Result<DefParameterResultVO>>(`${prefix}/api/system/defParameter`, { ...updateVO });
return resp;
};

10
src/axios.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
export interface Result<T = unknown> {
code: number;
data: T;
errorMsg: string;
extra: unknown;
isSuccess: boolean;
msg: string;
path?: string;
timestamp: string;
}

4
src/constants/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export const JAVA_INTEGER_MAX_VALUE = 2147483647;
export const JAVA_UNSIGNED_INTEGER_MAX_VALUE = 4294967295;
export const NDM_SWITCH_PROBE_INTERVAL = 5;

15
src/main.ts Normal file
View File

@@ -0,0 +1,15 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'
import App from './App.vue'
import router from './router'
import '@/styles/reset.scss'
const app = createApp(App)
app.use(createPinia().use(persist))
app.use(router)
app.mount('#app')

8
src/router/index.ts Normal file
View File

@@ -0,0 +1,8 @@
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [],
})
export default router

11
src/stores/station.ts Normal file
View File

@@ -0,0 +1,11 @@
import type { Station } from '@/apis/domains'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
export const useStationStore = defineStore('ndmstation', () => {
const stationList = ref<Station[]>([])
const onlineStationList = computed(() => stationList.value.filter((station) => station.online))
return { stationList, onlineStationList }
})

12
src/stores/theme.ts Normal file
View File

@@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { darkTheme, lightTheme } from 'naive-ui'
export const useThemeStore = defineStore('ndm-theme', () => {
const darkThemeEnabled = ref(false)
const themeMode = computed(() => {
return darkThemeEnabled.value ? darkTheme : lightTheme
})
return { darkThemeEnabled, themeMode }
})

68
src/styles/reset.scss Normal file
View File

@@ -0,0 +1,68 @@
/*
Josh's Custom CSS Reset
https://www.joshwcomeau.com/css/custom-css-reset/
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
* {
margin: 0;
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords;
}
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
input,
button,
textarea,
select {
font: inherit;
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
p {
text-wrap: pretty;
}
h1,
h2,
h3,
h4,
h5,
h6 {
text-wrap: balance;
}
#root,
#__next {
isolation: isolate;
}

58
src/utils/cipher.ts Normal file
View File

@@ -0,0 +1,58 @@
import { decrypt, encrypt } from 'crypto-js/aes';
import Base64 from 'crypto-js/enc-base64';
import UTF8, { parse } from 'crypto-js/enc-utf8';
import md5 from 'crypto-js/md5';
import ECB from 'crypto-js/mode-ecb';
import pkcs7 from 'crypto-js/pad-pkcs7';
export interface EncryptionParams {
key: string;
iv: string;
}
export class AesEncryption {
private key;
private iv;
constructor(opt?: Partial<EncryptionParams>) {
const { key, iv } = opt ?? {};
if (key) {
this.key = parse(key);
} else {
this.key = parse('_11111000001111@');
}
if (iv) {
this.iv = parse(iv);
} else {
this.iv = parse('@11111000001111_');
}
}
get getOptions() {
return {
mode: ECB,
padding: pkcs7,
iv: this.iv,
};
}
encryptByAES(cipherText: string) {
return encrypt(cipherText, this.key, this.getOptions).toString();
}
decryptByAES(cipherText: string) {
return decrypt(cipherText, this.key, this.getOptions).toString(UTF8);
}
}
export function encryptByBase64(cipherText: string) {
return UTF8.parse(cipherText).toString(Base64);
}
export function decodeByBase64(cipherText: string) {
return Base64.parse(cipherText).toString(UTF8);
}
export function encryptByMd5(password: string) {
return md5(password).toString();
}

17
src/utils/download.ts Normal file
View File

@@ -0,0 +1,17 @@
export function downloadByData(data: BlobPart, filename: string, mime?: string, bom?: BlobPart) {
const blobData = typeof bom !== 'undefined' ? [bom, data] : [data];
const blob = new Blob(blobData, { type: mime || 'application/octet-stream' });
const blobURL = window.URL.createObjectURL(blob);
const tempLink = document.createElement('a');
tempLink.style.display = 'none';
tempLink.href = blobURL;
tempLink.setAttribute('download', filename);
if (typeof tempLink.download === 'undefined') {
tempLink.setAttribute('target', '_blank');
}
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
}

21
src/utils/env.ts Normal file
View File

@@ -0,0 +1,21 @@
export const getAppEnvConfig = () => {
const env = import.meta.env;
const {
VITE_REQUEST_INTERVAL,
VITE_NDM_APP_KEY,
VITE_LAMP_CLIENT_ID,
VITE_LAMP_CLIENT_SECRET,
VITE_LAMP_USERNAME,
VITE_LAMP_PASSWORD,
VITE_LAMP_AUTHORIZATION,
} = env;
return {
requestInterval: Number.parseInt(VITE_REQUEST_INTERVAL as string),
ndmAppKey: VITE_NDM_APP_KEY as string,
lampClientId: VITE_LAMP_CLIENT_ID as string,
lampClientSecret: VITE_LAMP_CLIENT_SECRET as string,
lampUsername: VITE_LAMP_USERNAME as string,
lampPassword: VITE_LAMP_PASSWORD as string,
lampAuthorization: VITE_LAMP_AUTHORIZATION as string,
};
};

15
src/utils/post-build.ts Normal file
View File

@@ -0,0 +1,15 @@
import { tgz } from 'compressing';
import dayjs from 'dayjs';
import packageJson from '../../package.json';
const now = dayjs();
const fileName = `${packageJson.name}-${now.format('YYMMDD-HHmm')}`;
try {
await tgz.compressDir('./dist', `${fileName}.tar`);
await tgz.compressDir('./dist', `${fileName}.tar.gz`);
} catch (error) {
console.error('压缩失败:', error);
}

155
src/utils/request.ts Normal file
View File

@@ -0,0 +1,155 @@
import type {
AxiosError,
AxiosInstance,
AxiosRequestConfig,
AxiosResponse,
CreateAxiosDefaults,
InternalAxiosRequestConfig,
} from 'axios';
import axios from 'axios';
import type { Result } from '@/axios';
import { getAppEnvConfig } from './env';
export type Response<T> = [err: AxiosError | null, data: T | null, resp: Result<T> | null];
export interface RequestOptions extends CreateAxiosDefaults {
requestInterceptor?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
responseInterceptor?: (resp: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>;
responseErrorInterceptor?: (error: any) => any;
}
export class Request {
private instance: AxiosInstance;
private abortController: AbortController;
private lastAbortController: AbortController | null;
private uniq: boolean;
constructor(config?: RequestOptions) {
this.instance = axios.create(config);
this.abortController = new AbortController();
this.lastAbortController = null;
this.uniq = false;
this.instance.interceptors.request.use((config) => {
// 取消上一次请求
if (this.uniq && this.lastAbortController?.signal) {
this.lastAbortController.abort();
}
this.lastAbortController = this.abortController;
this.abortController = new AbortController();
return config;
// 业务登录所需headers
// const { lampAuthorization, lampClientId, lampClientSecret } = getAppEnvConfig();
// const newAuthorization = window.btoa(`${lampClientId}:${lampClientSecret}`);
// const authorization = lampAuthorization.trim() !== '' ? lampAuthorization : newAuthorization;
// config.headers.set('accept-language', 'zh-CN,zh;q=0.9');
// config.headers.set('accept', 'application/json, text/plain, */*');
// config.headers.set('Applicationid', '')
// config.headers.set('Tenantid', '1');
// config.headers.set('Authorization', authorization);
// config.headers.set('token', this.extraInfo?.token ?? '')
// return config;
});
const requestInterceptor = config?.requestInterceptor ?? Request.defaultRequestInterceptor;
const responseInterceptor = config?.responseInterceptor ?? Request.defaultResponseInterceptor;
const responseErrorInterceptor = config?.responseErrorInterceptor ?? Request.defaultResponseErrorInterceptor;
this.instance.interceptors.request.use(requestInterceptor);
this.instance.interceptors.response.use(responseInterceptor, responseErrorInterceptor);
}
private static defaultRequestInterceptor(config: InternalAxiosRequestConfig) {
return config;
}
private static defaultResponseInterceptor(response: AxiosResponse) {
return response;
}
private static defaultResponseErrorInterceptor(error: any) {
const err = error as AxiosError;
if (err.status === 401) {
//
}
if (err.status === 404) {
//
}
return Promise.reject(error);
}
get<T>(url: string, option?: AxiosRequestConfig & { uniq?: boolean }): Promise<Response<T>> {
const { uniq, ...reqConfig } = option ?? {};
this.uniq = !!uniq;
return new Promise((resolve) => {
this.instance
.get<Result<T>>(url, {
...reqConfig,
signal: this.abortController.signal,
})
.then((res) => {
resolve([null, res.data.data, res.data]);
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
}
post<T>(url: string, data: AxiosRequestConfig['data'], option?: Partial<Omit<AxiosRequestConfig, 'data'>> & { retRaw?: boolean; uniq?: boolean; upload?: boolean }): Promise<Response<T>> {
const { retRaw, uniq, upload, ...reqConfig } = option ?? {};
this.uniq = !!uniq;
return new Promise((resolve) => {
this.instance
.post(url, data, { ...reqConfig, headers: { 'content-type': upload ? 'multipart/form-data' : 'application/json' }, signal: this.abortController.signal })
.then((res) => {
if (retRaw) {
const data = res as T;
resolve([null, data, null]);
} else {
const resp = res as AxiosResponse<Result<T>>;
resolve([null, resp.data.data, resp.data]);
}
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
}
put<T>(url: string, data: AxiosRequestConfig['data'], option?: Partial<Omit<AxiosRequestConfig, 'data'>> & { uniq?: boolean }): Promise<Response<T>> {
const { uniq, ...reqConfig } = option ?? {};
this.uniq = !!uniq;
return new Promise((resolve) => {
this.instance
.put<Result<T>>(url, data, { ...reqConfig, signal: this.abortController.signal })
.then((res) => {
resolve([null, res.data.data, res.data]);
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
}
delete<T>(url: string, idList: string[], option?: Partial<Omit<AxiosRequestConfig, 'data'>> & { uniq?: boolean }): Promise<Response<T>> {
const { uniq, ...reqConfig } = option ?? {};
this.uniq = !!uniq;
return new Promise((resolve) => {
this.instance
.delete<Result<T>>(url, { ...reqConfig, data: { ids: idList }, signal: this.abortController.signal })
.then((res) => {
resolve([null, res.data.data, res.data]);
})
.catch((err) => {
resolve([err as AxiosError, null, null]);
});
});
}
}

16
src/window.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
import { DialogApiInjection } from 'naive-ui/es/dialog/src/DialogProvider';
import { LoadingBarApiInjection } from 'naive-ui/es/loading-bar/src/LoadingBarProvider';
import { MessageApiInjection } from 'naive-ui/es/message/src/MessageProvider';
import { NotificationApiInjection } from 'naive-ui/es/notification/src/NotificationProvider';
import type { NdmLogger } from '@/utils/ndmLogger';
declare global {
interface Window {
$dialog: DialogApiInjection;
$loadingBar: LoadingBarApiInjection;
$message: MessageApiInjection;
$notification: NotificationApiInjection;
$ndmLogger: NdmLogger;
}
}

12
tsconfig.app.json Normal file
View File

@@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
tsconfig.json Normal file
View File

@@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

19
tsconfig.node.json Normal file
View File

@@ -0,0 +1,19 @@
{
"extends": "@tsconfig/node22/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*",
"eslint.config.*"
],
"compilerOptions": {
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

44
vite.config.ts Normal file
View File

@@ -0,0 +1,44 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, ProxyOptions } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import vueDevTools from 'vite-plugin-vue-devtools'
const apiProxyList: [string, string][] = [
// ['/api', 'http://172.16.6.248:18760/api'],
['/api', 'http://localhost:3000/api'],
['/10/api', 'http://localhost:3000/api'],
['/11/api', 'http://localhost:3000/api'],
]
// https://vite.dev/config/
export default defineConfig((/* { command, mode } */) => {
const viteProxy: Record<string, string | ProxyOptions> = {}
apiProxyList.forEach((apiProxy) => {
const [prefix, target] = apiProxy
viteProxy[prefix] = {
target,
changeOrigin: true,
rewrite: (path) => {
console.log(`请求路径: ${path}`)
const rewrittenPath = path.replace(new RegExp(`^${prefix}`), '')
console.log(`将代理到: ${target}${rewrittenPath}`)
return rewrittenPath
},
}
})
return {
plugins: [vue(), vueJsx(), vueDevTools()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
server: {
port: 9654,
proxy: viteProxy,
},
}
})