diff --git a/.env b/.env
index 41bc483..fad912c 100644
--- a/.env
+++ b/.env
@@ -1,3 +1,4 @@
VITE_BASE_API = '/remoteServer/admin-api/'
+VITE_BASE_API_SYSTEM = '/remote/admin-api/system/'
VITE_SHOW_ONLINE_DEVICE = true
-VITE_BASE_URL = 'http://43.140.245.32:48081'
+VITE_BASE_URL = 'http://43.140.245.32:48089'
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2b9b15a..08a84d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,4 +28,5 @@ yarn-error.log*
/node_modules/
/*.tar
-.idea
\ No newline at end of file
+.idea
+test.js
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 284d99b..baaf73b 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,7 +4,7 @@
-
+
@@ -18,6 +18,9 @@
+
+
+
- {
+ "keyToString": {
+ "ASKED_MARK_IGNORED_FILES_AS_EXCLUDED": "true",
+ "ModuleVcsDetector.initialDetectionPerformed": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
+ "RunOnceActivity.git.unshallow": "true",
+ "code.cleanup.on.save": "true",
+ "com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultAutoModeForALLUsers.v1": "true",
+ "com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
+ "git-widget-placeholder": "main",
+ "junie.onboarding.icon.badge.shown": "true",
+ "last_opened_file_path": "/Users/taqibe/worker/EDFS-EPM/public",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "rearrange.code.on.save": "true",
+ "settings.editor.selected.configurable": "preferences.general",
+ "to.speed.mode.migration.done": "true",
+ "ts.external.directory.path": "/Users/taqibe/worker/EDFS-EPM/node_modules/typescript/lib",
+ "vue.rearranger.settings.migration": "true"
},
- "keyToStringList": {
- "vue.recent.templates": [
- "Vue Composition API Component"
+ "keyToStringList": {
+ "vue.recent.templates": [
+ "Vue Composition API Component"
]
}
-}]]>
+}
+
@@ -110,7 +119,7 @@
-
+
@@ -167,6 +176,15 @@
+
+
+
+
+
+
+
+
+
@@ -416,7 +434,39 @@
1763358207970
-
+
+
+ 1764142225202
+
+
+
+ 1764142225202
+
+
+
+ 1764142233905
+
+
+
+ 1764142233905
+
+
+
+ 1765187239302
+
+
+
+ 1765187239302
+
+
+
+ 1765264099923
+
+
+
+ 1765264099923
+
+
@@ -428,8 +478,18 @@
+
-
-
-
@@ -464,7 +521,10 @@
-
+
+
+
+
diff --git a/global.types/components.d.ts b/global.types/components.d.ts
index e7d0f23..137173c 100644
--- a/global.types/components.d.ts
+++ b/global.types/components.d.ts
@@ -21,26 +21,24 @@ declare module 'vue' {
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDialog: typeof import('element-plus/es')['ElDialog']
+ ElDropdown: typeof import('element-plus/es')['ElDropdown']
+ ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
+ ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
- ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
- ElProgress: typeof import('element-plus/es')['ElProgress']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps']
- ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
- ElTable: typeof import('element-plus/es')['ElTable']
- ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
@@ -52,7 +50,6 @@ declare module 'vue' {
RouterView: typeof import('vue-router')['RouterView']
}
export interface GlobalDirectives {
- vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll']
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}
diff --git a/package.json b/package.json
index 26ef7e5..ce97000 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,8 @@
"uuid": "^11.1.0",
"vue": "^3.5.13",
"vue-echarts": "^7.0.3",
- "vue-router": "^4.5.0"
+ "vue-router": "^4.5.0",
+ "web-storage-cache": "^1.1.1"
},
"devDependencies": {
"@iconify/json": "^2.2.310",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f131fa7..e1bff6b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -71,6 +71,9 @@ importers:
vue-router:
specifier: ^4.5.0
version: 4.6.3(vue@3.5.25(typescript@5.7.3))
+ web-storage-cache:
+ specifier: ^1.1.1
+ version: 1.1.1
devDependencies:
'@iconify/json':
specifier: ^2.2.310
@@ -2469,6 +2472,9 @@ packages:
resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==}
engines: {node: '>=10.13.0'}
+ web-storage-cache@1.1.1:
+ resolution: {integrity: sha512-D0MieGooOs8RpsrK+vnejXnvh4OOv/+lTFB35JRkJJQt+uOjPE08XpaE0QBLMTRu47B1KGT/Nq3Gbag3Orinzw==}
+
webpack-sources@3.3.3:
resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==}
engines: {node: '>=10.13.0'}
@@ -5036,6 +5042,8 @@ snapshots:
glob-to-regexp: 0.4.1
graceful-fs: 4.2.11
+ web-storage-cache@1.1.1: {}
+
webpack-sources@3.3.3: {}
webpack-virtual-modules@0.6.2: {}
diff --git a/public/commun_config_modbustcp/commun_channel_moebustcp.json b/public/commun_config_modbustcp/commun_channel_moebustcp.json
deleted file mode 100644
index 43ea954..0000000
--- a/public/commun_config_modbustcp/commun_channel_moebustcp.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "channel": [
- {
- "name": "名称,唯一标识不可重复,不能为中文或特殊符号,长度32字节",
- "ip": "设备IP地址,字符串",
- "port": "端口号,整形数字,0~65535,一般为502"
- },
- {
- "name": "modbustcp_ch1",
- "ip": "192.168.10.123",
- "port": 502
- },
- {
- "name": "xxxx",
- "ip": "192.168.10.133",
- "port": 1502
- },
- {
- "name": "xxxxxx",
- "ip": "192.168.10.143",
- "port": 2502
- }
- ]
-}
\ No newline at end of file
diff --git a/public/commun_config_modbustcp/commun_dev_modbustcp.json b/public/commun_config_modbustcp/commun_dev_modbustcp.json
deleted file mode 100644
index 644adb7..0000000
--- a/public/commun_config_modbustcp/commun_dev_modbustcp.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "dev": [
- {
- "name": "名称,唯一标识不可重复,不能为中文或特殊符号,长度32字节",
- "ch": "所在通道名称,特指ModbusRtu通道的名称,字符串",
- "point": "使用点表名称,特指Modbus点表的名称,字符串",
- "addr": "站地址,字符串,0 ~ 255"
- },
- {
- "name": "xxxx1",
- "ch": "modbustcp_ch1",
- "point": "pcs",
- "addr": "1"
- },
- {
- "name": "xxxx2",
- "ch": "modbustcp_ch1",
- "point": "pcs",
- "addr": "2"
- },
- {
- "name": "xxxx3",
- "ch": "xxxx",
- "point": "bms",
- "addr": "1"
- },
- {
- "name": "xxxx4",
- "ch": "xxxxxx",
- "point": "tms",
- "addr": "1"
- }
- ]
-}
\ No newline at end of file
diff --git a/public/commun_config_modbustcp/index.json b/public/commun_config_modbustcp/index.json
deleted file mode 100644
index d16e67d..0000000
--- a/public/commun_config_modbustcp/index.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "工程名xxxx",
- "commun_channel": {
- "通讯通道类型,固定如下": "通讯通道配置文件路径",
- "modbustcp": "commun_channel_moebustcp.json"
- },
- "commun_dev": {
- "通讯设备类型,固定如下": "通讯设备配置文件路径",
- "modbustcp": "commun_dev_moebustcp.json"
- },
- "point_table": {
- "通讯点表类型,固定如下": {
- "名称": "路径"
- },
- "modbus": {
- "modbus点表名称,自定义,非中文、非特殊字符,32字节": "modbus点表文件路径",
- "pcs2": "point_table_modbus_01.json",
- "bms": "point_table_modbus_02.json",
- "tms": "point_table_modbus_03.json"
- }
- }
-}
\ No newline at end of file
diff --git a/public/commun_config_modbustcp/point_table_modbus_01.json b/public/commun_config_modbustcp/point_table_modbus_01.json
deleted file mode 100644
index 550aa8c..0000000
--- a/public/commun_config_modbustcp/point_table_modbus_01.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "name": "p12312cs",
- "point": [
- [
- "点起始地址,进制字符串, 范围 0x0000~0xFFFF 或 0~65535",
- "点数量,字符串, 范围 0x0001~0x10000 或 1~65536",
- "功能码,字符串,可选项: '0x01' '0x02' '0x03' '0x04' 或 '1' '2' '3' '4'",
- "数据类型,字符串,可选 'U16' 'S16' 'U32' 'S32'",
- "点读取周期ms,整形数字,-1时标志该点位未启用",
- "点位段名称,字符串,可设为空字符串"
- ],
- [
- "0x0001",
- "0x0010",
- "0x03",
- "U16",
- 1000,
- "点位段名称1"
- ],
- [
- "0x0100",
- "0x0020",
- "0x03",
- "U16",
- 1000,
- "点位段名称2"
- ],
- [
- "0x0120",
- "0x0020",
- "0x03",
- "U32",
- 1000,
- ""
- ],
- [
- "0x0000",
- "0x0020",
- "0x04",
- "U16",
- 1000,
- "点位段名称"
- ],
- [
- "0x0020",
- "0x0010",
- "0x04",
- "U32",
- 1000,
- "-"
- ],
- [
- "0x0040",
- "0x0020",
- "0x04",
- "U16",
- 1000,
- "点位段名称"
- ]
- ]
-}
\ No newline at end of file
diff --git a/public/commun_config_modbustcp/point_table_modbus_02.json b/public/commun_config_modbustcp/point_table_modbus_02.json
deleted file mode 100644
index f694b7b..0000000
--- a/public/commun_config_modbustcp/point_table_modbus_02.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "name": "xxxx",
- "point": [
- [
- "点起始地址,进制字符串, 范围 0x0000~0xFFFF 或 0~65535",
- "点数量,字符串, 范围 0x0001~0x10000 或 1~65536",
- "功能码,字符串,可选项: '0x01' '0x02' '0x03' '0x04' 或 '1' '2' '3' '4'",
- "数据类型,字符串,可选 'U16' 'S16' 'U32' 'S32'",
- "点读取周期ms,整形数字,-1时标志该点位未启用",
- "点位段名称,字符串,可设为空字符串"
- ],
- [
- "0x0001",
- "0x0010",
- "0x03",
- "U16",
- 1000,
- "点位段名称1"
- ],
- [
- "0x0100",
- "0x0020",
- "0x03",
- "U16",
- 1000,
- "点位段名称2"
- ],
- [
- "0x0120",
- "0x0020",
- "0x03",
- "U32",
- 1000,
- ""
- ],
- [
- "0x0000",
- "0x0020",
- "0x04",
- "U16",
- 1000,
- "点位段名称"
- ],
- [
- "0x0020",
- "0x0010",
- "0x04",
- "U32",
- 1000,
- "-"
- ],
- [
- "0x0040",
- "0x0020",
- "0x04",
- "U16",
- 1000,
- "点位段名称"
- ]
- ]
-}
\ No newline at end of file
diff --git a/public/commun_config_modbustcp/point_table_modbus_03.json b/public/commun_config_modbustcp/point_table_modbus_03.json
deleted file mode 100644
index f694b7b..0000000
--- a/public/commun_config_modbustcp/point_table_modbus_03.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "name": "xxxx",
- "point": [
- [
- "点起始地址,进制字符串, 范围 0x0000~0xFFFF 或 0~65535",
- "点数量,字符串, 范围 0x0001~0x10000 或 1~65536",
- "功能码,字符串,可选项: '0x01' '0x02' '0x03' '0x04' 或 '1' '2' '3' '4'",
- "数据类型,字符串,可选 'U16' 'S16' 'U32' 'S32'",
- "点读取周期ms,整形数字,-1时标志该点位未启用",
- "点位段名称,字符串,可设为空字符串"
- ],
- [
- "0x0001",
- "0x0010",
- "0x03",
- "U16",
- 1000,
- "点位段名称1"
- ],
- [
- "0x0100",
- "0x0020",
- "0x03",
- "U16",
- 1000,
- "点位段名称2"
- ],
- [
- "0x0120",
- "0x0020",
- "0x03",
- "U32",
- 1000,
- ""
- ],
- [
- "0x0000",
- "0x0020",
- "0x04",
- "U16",
- 1000,
- "点位段名称"
- ],
- [
- "0x0020",
- "0x0010",
- "0x04",
- "U32",
- 1000,
- "-"
- ],
- [
- "0x0040",
- "0x0020",
- "0x04",
- "U16",
- 1000,
- "点位段名称"
- ]
- ]
-}
\ No newline at end of file
diff --git a/public/commun_config_modbustcp/工程说明.md b/public/commun_config_modbustcp/工程说明.md
deleted file mode 100644
index 9e253dd..0000000
--- a/public/commun_config_modbustcp/工程说明.md
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-## 创建工程
-
-填写工程名,用户自定义输入
-
-
-
-## 通讯点表
-
-1. 展示目前工程中已有的通讯点表
-
-2. 导入新的通讯点表
-
- ```
- 自定义名称:设置点表自定义名字,用户自定义输入,需检查唯一性,禁止中文、特殊字符
- 通讯点表类型:通过下拉菜单选择,目前只支持ModbusTcp(预留支持其他类型,不同类型的点表需要分类保存)
- ```
-
-
-
-## 通讯通道
-
-1. 展示目前工程中已有的通讯通道
-
-2. 创建新的通讯通道
-
- ```
- 自定义名称:设置通讯通道自定义名字,用户自定义输入,需检查唯一性,禁止中文、特殊字符
- 通讯通道类型:通过下拉菜单选择,目前只支持ModbusTcp(预留支持其他类型,不同类型的通讯通道分类保存)
- 设备IP地址:用户自定义输入,须符合IP地址的格式,如192.168.10.123
- 设备端口:用户自定义输入,范围0~65535,一般为502
- ```
-
-
-
-## 通讯设备
-
-1. 展示目前工程中已有的通讯设备
-
-2. 创建新的通讯设备
-
- ```
- 自定义名称:设置通讯设备自定义名字,用户自定义输入,需检查唯一性,禁止中文、特殊字符
- 通讯设备类型:通过下拉菜单选择,目前只支持ModbusTcp(预留支持其他类型,不同类型的通讯设备分类保存)
- 通讯通道选择:通过下拉菜单选择,选项为已选择的类型(目前只有ModbusTcp)的所有通讯通道(是否支持在此处新建通道)
- 通讯点表选择:通过下拉菜单选择,选项为已选择的类型(目前只有ModbusTcp)的所有通讯点表(是否支持在此处新建点表)
- 通讯地址:用户自定义输入通讯站地址,范围0~255,一般为1
- ```
-
-
-
-
\ No newline at end of file
diff --git a/src/api/module/engineering/index.ts b/src/api/module/engineering/index.ts
index 0e92bcc..8cd8a6e 100644
--- a/src/api/module/engineering/index.ts
+++ b/src/api/module/engineering/index.ts
@@ -13,10 +13,8 @@ export const createEngineering = (params: IEngineeringOV) => {
export const getEngineeringList = (
params?: Pick,
) => {
- return globalServer<{
- list: IEngineeringOV[]
- }>({
- url: '/project/page',
+ return globalServer({
+ url: '/project/list',
method: 'get',
params,
})
diff --git a/src/api/module/index.ts b/src/api/module/index.ts
index ca6b36c..43c5ddc 100644
--- a/src/api/module/index.ts
+++ b/src/api/module/index.ts
@@ -2,5 +2,6 @@ import axiosInstance from '@/api/server/axiosInstance'
import { API_Config } from '@/api/server/config'
const globalServer = axiosInstance('global', API_Config.global)
+const systemServer = axiosInstance('system', API_Config.system)
-export { globalServer }
+export { globalServer, systemServer }
diff --git a/src/api/module/system/dept/index.ts b/src/api/module/system/dept/index.ts
new file mode 100644
index 0000000..c344de7
--- /dev/null
+++ b/src/api/module/system/dept/index.ts
@@ -0,0 +1,57 @@
+import { systemServer } from '../../index'
+export interface DeptVO {
+ id?: number
+ name: string
+ parentId: number
+ status: number
+ sort: number
+ leaderUserId: number
+ phone: string
+ email: string
+ createTime: Date
+}
+
+// 查询部门(精简)列表
+export const getSimpleDeptList = async () =>
+ systemServer({
+ url: '/dept/simple-list',
+ method: 'get',
+ })
+
+// 查询部门列表
+export const getDeptPage = async (params: PageParam) =>
+ systemServer({
+ url: '/dept/page',
+ method: 'get',
+ params,
+ })
+
+// 查询部门详情
+export const getDept = async (id: number) =>
+ systemServer({
+ url: '/dept/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增部门
+export const createDept = async (data: DeptVO) =>
+ systemServer({
+ url: '/dept/create',
+ method: 'post',
+ data,
+ })
+
+// 修改部门
+export const updateDept = async (params: DeptVO) =>
+ systemServer({
+ url: '/dept/update',
+ method: 'put',
+ data: params,
+ })
+
+// 删除部门
+export const deleteDept = async (id: number) =>
+ systemServer({
+ url: '/dept/delete?id=' + id,
+ method: 'delete',
+ })
diff --git a/src/api/module/system/dict/dict.data.ts b/src/api/module/system/dict/dict.data.ts
new file mode 100644
index 0000000..ada29de
--- /dev/null
+++ b/src/api/module/system/dict/dict.data.ts
@@ -0,0 +1,68 @@
+
+import { systemServer } from '../../index'
+
+export type DictDataVO = {
+ id: number | undefined
+ sort: number | undefined
+ label: string
+ value: string
+ dictType: string
+ status: number
+ colorType: string
+ cssClass: string
+ remark: string
+ createTime: Date
+}
+
+// 查询字典数据(精简)列表
+export const getSimpleDictDataList = () =>
+ systemServer({
+ url: '/dict-data/simple-list',
+ method: 'get',
+ })
+
+// 查询字典数据列表
+export const getDictDataPage = (params: PageParam) =>
+ systemServer({
+ url: '/dict-data/page',
+ method: 'get',
+ params,
+ })
+// 查询字典数据详情
+export const getDictData = (id: number) =>
+ systemServer({
+ url: '/dict-data/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增字典数据
+export const createDictData = (data: DictDataVO) =>
+ systemServer({
+ url: '/dict-data/create',
+ method: 'post',
+ data,
+ })
+
+// 修改字典数据
+export const updateDictData = (data: DictDataVO) =>
+ systemServer({
+ url: '/dict-data/update',
+ method: 'put',
+ data,
+ })
+
+// 删除字典数据
+export const deleteDictData = (id: number) =>
+ systemServer({
+ url: '/dict-data/delete?id=' + id,
+ method: 'delete',
+ })
+
+// 导出字典类型数据
+export const exportDictData = (params:any) =>
+ systemServer({
+ url: '/dict-data/export',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ })
\ No newline at end of file
diff --git a/src/api/module/system/dict/dict.type.ts b/src/api/module/system/dict/dict.type.ts
new file mode 100644
index 0000000..b7da000
--- /dev/null
+++ b/src/api/module/system/dict/dict.type.ts
@@ -0,0 +1,65 @@
+
+import { systemServer } from '../../index'
+
+export type DictTypeVO = {
+ id: number | undefined
+ name: string
+ type: string
+ status: number
+ remark: string
+ createTime: Date
+}
+
+// 查询字典(精简)列表
+export const getSimpleDictTypeList = () =>
+ systemServer({
+ url: '/dict-type/list-all-simple',
+ method: 'get',
+ })
+
+// 查询字典列表
+export const getDictTypePage = (params: PageParam) =>
+ systemServer({
+ url: '/dict-type/page',
+ method: 'get',
+ params,
+ })
+
+// 查询字典详情
+export const getDictType = (id: number) =>
+ systemServer({
+ url: '/dict-type/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增字典
+export const createDictType = (data: DictTypeVO) =>
+ systemServer({
+ url: '/dict-type/create',
+ method: 'post',
+ data,
+ })
+
+// 修改字典
+export const updateDictType = (data: DictTypeVO) =>
+ systemServer({
+ url: '/dict-type/update',
+ method: 'put',
+ data,
+ })
+
+// 删除字典
+export const deleteDictType = (id: number) =>
+ systemServer({
+ url: '/dict-type/delete?id=' + id,
+ method: 'delete',
+ })
+
+// 导出字典类型
+export const exportDictType = (params: any) =>
+ systemServer({
+ url: '/dict-type/export',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ })
diff --git a/src/api/module/system/file/index.ts b/src/api/module/system/file/index.ts
new file mode 100644
index 0000000..77c9210
--- /dev/null
+++ b/src/api/module/system/file/index.ts
@@ -0,0 +1,50 @@
+import { systemServer } from '../../index'
+export interface FilePageReqVO extends PageParam {
+ path?: string
+ type?: string
+ createTime?: Date[]
+}
+
+// 文件预签名地址 Response VO
+export interface FilePresignedUrlRespVO {
+ // 文件配置编号
+ configId: number
+ // 文件上传 URL
+ uploadUrl: string
+ // 文件 URL
+ url: string
+}
+
+// 查询文件列表
+export const getFilePage = (params: FilePageReqVO) => {
+ return systemServer({ url: '/infra/file/page', params, method: 'get' })
+}
+
+// 删除文件
+export const deleteFile = (id: number) => {
+ return systemServer({ url: '/infra/file/delete?id=' + id, method: 'delete' })
+}
+
+// 获取文件预签名地址
+export const getFilePresignedUrl = (path: string) => {
+ return systemServer({
+ url: '/infra/file/presigned-url',
+ params: { path },
+ method: 'get',
+ })
+}
+
+// 创建文件
+export const createFile = (data: any) => {
+ return systemServer({ url: '/infra/file/create', data, method: 'post' })
+}
+
+// 上传文件
+export const updateFile = (data: any) => {
+ return systemServer({
+ url: '/infra/file/upload',
+ data,
+ method: 'post',
+ headers: { 'Content-Type': 'multipart/form-data' },
+ })
+}
diff --git a/src/api/module/system/login/index.ts b/src/api/module/system/login/index.ts
new file mode 100644
index 0000000..658e462
--- /dev/null
+++ b/src/api/module/system/login/index.ts
@@ -0,0 +1,106 @@
+import { getRefreshToken } from '@/utils/auth'
+import { systemServer } from '../../index'
+
+type UserLoginVO = {
+ username: string
+ password: string
+ captchaVerification: string
+ socialType?: string
+ socialCode?: string
+ socialState?: string
+}
+
+export interface LoginRequestData {
+ username: string
+ password: string
+ // tenantName: string
+ // captchaVerification: string
+ // rememberMe: boolean
+}
+export interface SmsCodeVO {
+ mobile: string
+ scene: number
+}
+
+export interface SmsLoginVO {
+ mobile: string
+ code: string
+}
+interface LoginResponse {
+ accessToken: string
+ expiresTime: number
+ refreshToken: string
+ userId: number
+}
+
+export const getTenantId = (name: string) =>
+ systemServer({
+ url: '/tenant/get-id-by-name',
+ method: 'get',
+ params: {
+ name,
+ },
+ })
+
+export const login = (data: any) =>
+ systemServer({
+ method: 'post',
+ url: '/auth/login',
+ data,
+ })
+
+// 刷新访问令牌
+export const refreshToken = () =>
+ systemServer({
+ url: '/auth/refresh-token?refreshToken=' + getRefreshToken(),
+ method: 'post',
+ })
+
+// // 使用租户域名,获得租户信息
+// export const getTenantByWebsite = (website: string) => {
+// return request.get({ url: '/tenant/get-by-website?website=' + website })
+// }
+
+// // 登出
+export const loginOut = () => systemServer({ url: '/auth/logout', method: 'post' })
+
+export const getInfo = () =>
+ systemServer({ url: '/auth/get-permission-info', method: 'get' })
+
+// //获取登录验证码
+export const sendSmsCode = (data: SmsCodeVO) => {
+ return systemServer({ url: '/auth/send-sms-code', method: 'post', data })
+}
+
+// // 短信验证码登录
+export const smsLogin = (data: SmsLoginVO) => {
+ return systemServer({ url: '/auth/sms-login', method: 'post', data })
+}
+
+// // 社交快捷登录,使用 code 授权码
+// export function socialLogin(type: string, code: string, state: string) {
+// return request.post({
+// url: '/auth/social-login',
+// data: {
+// type,
+// code,
+// state
+// }
+// })
+// }
+
+// // 社交授权的跳转
+// export const socialAuthRedirect = (type: number, redirectUri: string) => {
+// return request.get({
+// url: '/auth/social-auth-redirect?type=' + type + '&redirectUri=' + redirectUri
+// })
+// }
+// // 获取验证图片以及 token
+// export const getCode = (data) => {
+// return request.postOriginal({ url: 'system/captcha/get', data })
+// }
+
+// // 滑动或者点选验证
+// export const reqCheck = (data) => {
+// return request.postOriginal({ url: 'system/captcha/check', data })
+// }
diff --git a/src/api/module/system/loginLog/index.ts b/src/api/module/system/loginLog/index.ts
new file mode 100644
index 0000000..29299e2
--- /dev/null
+++ b/src/api/module/system/loginLog/index.ts
@@ -0,0 +1,33 @@
+import { systemServer } from '../../index'
+export interface LoginLogVO {
+ id: number
+ logType: number
+ traceId: number
+ userId: number
+ userType: number
+ username: string
+ result: number
+ status: number
+ userIp: string
+ userAgent: string
+ createTime: Date
+}
+
+// 查询登录日志列表
+export const getLoginLogPage = (params: PageParam) => {
+ return systemServer({
+ url: '/login-log/page',
+ method: 'get',
+ params,
+ })
+}
+
+// 导出登录日志
+export const exportLoginLog = (params: any) => {
+ return systemServer({
+ url: '/login-log/export',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ })
+}
diff --git a/src/api/module/system/menu/index.ts b/src/api/module/system/menu/index.ts
new file mode 100644
index 0000000..7942111
--- /dev/null
+++ b/src/api/module/system/menu/index.ts
@@ -0,0 +1,63 @@
+import { systemServer } from '../../index'
+export interface MenuVO {
+ id: number
+ name: string
+ permission: string
+ type: number
+ sort: number
+ parentId: number
+ path: string
+ icon: string
+ component: string
+ componentName?: string
+ status: number
+ visible: boolean
+ keepAlive: boolean
+ alwaysShow?: boolean
+ createTime: Date
+}
+
+// 查询菜单(精简)列表
+export const getSimpleMenusList = () =>
+ systemServer({
+ url: '/menu/simple-list',
+ method: 'get',
+ })
+
+// 查询菜单列表
+export const getMenuList = (params: any) =>
+ systemServer({
+ url: '/menu/list',
+ method: 'get',
+ params,
+ })
+
+// 获取菜单详情
+export const getMenu = (id: number) =>
+ systemServer({
+ url: '/menu/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增菜单
+export const createMenu = (data: MenuVO) =>
+ systemServer({
+ url: '/menu/create',
+ method: 'post',
+ data,
+ })
+
+// 修改菜单
+export const updateMenu = (data: MenuVO) =>
+ systemServer({
+ url: '/menu/update',
+ method: 'put',
+ data,
+ })
+
+// 删除菜单
+export const deleteMenu = (id: number) =>
+ systemServer({
+ url: '/menu/delete?id=' + id,
+ method: 'delete',
+ })
diff --git a/src/api/module/system/operatelog/index.ts b/src/api/module/system/operatelog/index.ts
new file mode 100644
index 0000000..e4c2d6e
--- /dev/null
+++ b/src/api/module/system/operatelog/index.ts
@@ -0,0 +1,51 @@
+
+import { systemServer } from '../../index'
+
+export enum Action {
+ //用户个人操作
+ USER_LOGIN = '登录',
+ USER_LOGOUT = '登出',
+ //用户管理
+ USERMGR_ADD = '添加用户',
+ USERMGR_DEL = '删除用户',
+ USERMGR_MODIFY = '更改用户',
+ //zmq命令
+ ZMQ_CMD_PUBLISH = '设备命令下发',
+ //ssh
+ SSH_LOGIN = 'SSH连接',
+ SSH_LOGOUT = 'SSH中断连接'
+}
+
+export type OperateLogVO = {
+ id: number
+ traceId: string
+ userType: number
+ userId: number
+ userName: string
+ type: string
+ subType: string
+ bizId: number
+ action: string
+ extra: string
+ requestMethod: string
+ requestUrl: string
+ userIp: string
+ userAgent: string
+ creator: string
+ creatorName: string
+ createTime: Date
+}
+
+// 查询操作日志列表
+export const getOperateLogPage = (params: PageParam) => {
+ return systemServer({ url: '/operate-log/page', method: 'get', params })
+}
+// 导出操作日志
+export const exportOperateLog = (params: any) => {
+ return systemServer({
+ url: '/operate-log/export',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ })
+}
diff --git a/src/api/module/system/permission/index.ts b/src/api/module/system/permission/index.ts
new file mode 100644
index 0000000..eb4e6db
--- /dev/null
+++ b/src/api/module/system/permission/index.ts
@@ -0,0 +1,54 @@
+import { systemServer } from '../../index'
+export interface PermissionAssignUserRoleReqVO {
+ userId: number
+ roleIds: number[]
+}
+
+export interface PermissionAssignRoleMenuReqVO {
+ roleId: number
+ menuIds: number[]
+}
+
+export interface PermissionAssignRoleDataScopeReqVO {
+ roleId: number
+ dataScope: number
+ dataScopeDeptIds: number[]
+}
+
+// 查询角色拥有的菜单权限
+export const getRoleMenuList = async (roleId: number) =>
+ systemServer({
+ url: '/permission/list-role-menus?roleId=' + roleId,
+ method: 'get',
+ })
+
+// 赋予角色菜单权限
+export const assignRoleMenu = async (data: PermissionAssignRoleMenuReqVO) =>
+ systemServer({
+ url: '/permission/assign-role-menu',
+ method: 'post',
+ data,
+ })
+
+// 赋予角色数据权限
+export const assignRoleDataScope = async (data: PermissionAssignRoleDataScopeReqVO) =>
+ systemServer({
+ url: '/permission/assign-role-data-scope',
+ method: 'post',
+ data,
+ })
+
+// 查询用户拥有的角色数组
+export const getUserRoleList = async (userId: number) =>
+ systemServer({
+ url: '/permission/list-user-roles?userId=' + userId,
+ method: 'get',
+ })
+
+// 赋予用户角色
+export const assignUserRole = async (data: PermissionAssignUserRoleReqVO) =>
+ systemServer({
+ url: '/permission/assign-user-role',
+ method: 'post',
+ data,
+ })
diff --git a/src/api/module/system/post/index.ts b/src/api/module/system/post/index.ts
new file mode 100644
index 0000000..f577d12
--- /dev/null
+++ b/src/api/module/system/post/index.ts
@@ -0,0 +1,64 @@
+import { systemServer } from '../../index'
+export interface PostVO {
+ id?: number
+ name: string
+ code: string
+ sort: number
+ status: number
+ remark: string
+ createTime?: Date
+}
+
+// 查询岗位列表
+export const getPostPage = async (params: PageParam) =>
+ systemServer({
+ url: '/post/page',
+ method: 'get',
+ params,
+ })
+
+// 获取岗位精简信息列表
+export const getSimplePostList = async () =>
+ systemServer({
+ url: '/post/simple-list',
+ method: 'get',
+ })
+
+// 查询岗位详情
+export const getPost = async (id: number) =>
+ systemServer({
+ url: '/post/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增岗位
+export const createPost = async (data: PostVO) =>
+ systemServer({
+ url: '/post/create',
+ method: 'post',
+ data,
+ })
+
+// 修改岗位
+export const updatePost = async (data: PostVO) =>
+ systemServer({
+ url: '/post/update',
+ method: 'put',
+ data,
+ })
+
+// 删除岗位
+export const deletePost = async (id: number) =>
+ systemServer({
+ url: '/post/delete?id=' + id,
+ method: 'delete',
+ })
+
+// 导出岗位
+export const exportPost = async (params: any) =>
+ systemServer({
+ url: '/post/export',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ })
diff --git a/src/api/module/system/role/index.ts b/src/api/module/system/role/index.ts
new file mode 100644
index 0000000..d92def9
--- /dev/null
+++ b/src/api/module/system/role/index.ts
@@ -0,0 +1,79 @@
+import { systemServer } from '../../index'
+export interface RoleVO {
+ id: number
+ name: string
+ code: string
+ sort: number
+ status: number
+ type: number
+ dataScope: number
+ dataScopeDeptIds: number[]
+ createTime: Date
+}
+
+export interface UpdateStatusReqVO {
+ id: number
+ status: number
+}
+
+// 查询角色列表
+export const getRolePage = async (params: PageParam) =>
+ systemServer({
+ url: '/role/page',
+ method: 'get',
+ params,
+ })
+
+// 查询角色(精简)列表
+export const getSimpleRoleList = async () =>
+ systemServer({
+ url: '/role/simple-list',
+ method: 'get',
+ })
+
+// 查询角色详情
+export const getRole = async (id: number) =>
+ systemServer({
+ url: '/role/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增角色
+export const createRole = async (data: RoleVO) =>
+ systemServer({
+ url: '/role/create',
+ method: 'post',
+ data,
+ })
+
+// 修改角色
+export const updateRole = async (data: RoleVO) =>
+ systemServer({
+ url: '/role/update',
+ method: 'put',
+ data,
+ })
+
+// 修改角色状态
+export const updateRoleStatus = async (data: UpdateStatusReqVO) =>
+ systemServer({
+ url: '/role/update-status',
+ method: 'put',
+ data,
+ })
+
+// 删除角色
+export const deleteRole = async (id: number) =>
+ systemServer({
+ url: '/role/delete?id=' + id,
+ method: 'delete',
+ })
+
+// 导出角色
+export const exportRole = (params: any) =>
+ systemServer({
+ url: '/role/export-excel',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ })
diff --git a/src/api/module/system/tenant/index.ts b/src/api/module/system/tenant/index.ts
new file mode 100644
index 0000000..6d1444b
--- /dev/null
+++ b/src/api/module/system/tenant/index.ts
@@ -0,0 +1,80 @@
+import { systemServer } from '../../index'
+
+
+export interface TenantVO {
+ id: number
+ name: string
+ contactName: string
+ contactMobile: string
+ status: number
+ domain: string
+ packageId: number
+ username: string
+ password: string
+ expireTime: Date
+ accountCount: number
+ createTime: Date
+}
+
+export interface TenantPageReqVO extends PageParam {
+ name?: string
+ contactName?: string
+ contactMobile?: string
+ status?: number
+ createTime?: Date[]
+}
+
+export interface TenantExportReqVO {
+ name?: string
+ contactName?: string
+ contactMobile?: string
+ status?: number
+ createTime?: Date[]
+}
+
+// 查询租户列表
+export const getTenantPage = (params: TenantPageReqVO) =>
+ systemServer({
+ url: '/tenant/page',
+ method: 'get',
+ params,
+ })
+
+// 查询租户详情
+export const getTenant = (id: number) =>
+ systemServer({
+ url: '/tenant/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增租户
+export const createTenant = (data: TenantVO) =>
+ systemServer({
+ url: '/tenant/create',
+ method: 'post',
+ data,
+ })
+
+// 修改租户
+export const updateTenant = (data: TenantVO) =>
+ systemServer({
+ url: '/tenant/update',
+ method: 'put',
+ data,
+ })
+
+// 删除租户
+export const deleteTenant = (id: number) =>
+ systemServer({
+ url: '/tenant/delete?id=' + id,
+ method: 'delete',
+ })
+
+// 导出租户
+export const exportTenant = (params: TenantExportReqVO) =>
+ systemServer({
+ url: '/tenant/export-excel',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ })
diff --git a/src/api/module/system/tenantPackage/index.ts b/src/api/module/system/tenantPackage/index.ts
new file mode 100644
index 0000000..34847d6
--- /dev/null
+++ b/src/api/module/system/tenantPackage/index.ts
@@ -0,0 +1,58 @@
+import { systemServer } from '../../index'
+
+export interface TenantPackageVO {
+ id: number
+ name: string
+ status: number
+ remark: string
+ creator: string
+ updater: string
+ updateTime: string
+ menuIds: number[]
+ createTime: Date
+}
+
+// 查询租户套餐列表
+export const getTenantPackagePage = (params: PageParam) =>
+ systemServer({
+ url: '/tenant-package/page',
+ method: 'get',
+ params,
+ })
+
+// 获得租户
+export const getTenantPackage = (id: number) =>
+ systemServer({
+ url: '/tenant-package/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增租户套餐
+export const createTenantPackage = (data: TenantPackageVO) =>
+ systemServer({
+ url: '/tenant-package/create',
+ method: 'post',
+ data,
+ })
+
+// 修改租户套餐
+export const updateTenantPackage = (data: TenantPackageVO) =>
+ systemServer({
+ url: '/tenant-package/update',
+ method: 'put',
+ data,
+ })
+
+// 删除租户套餐
+export const deleteTenantPackage = (id: number) =>
+ systemServer({
+ url: '/tenant-package/delete?id=' + id,
+ method: 'delete',
+ })
+
+// 获取租户套餐精简信息列表
+export const getTenantPackageList = () =>
+ systemServer({
+ url: '/tenant-package/simple-list',
+ method: 'get',
+ })
diff --git a/src/api/module/system/user/index.ts b/src/api/module/system/user/index.ts
new file mode 100644
index 0000000..c226d5c
--- /dev/null
+++ b/src/api/module/system/user/index.ts
@@ -0,0 +1,121 @@
+import { systemServer } from '../../index'
+
+export interface UserVO {
+ id: number
+ username: string
+ nickname: string
+ deptId: number
+ postIds: string[]
+ email: string
+ mobile: string
+ sex: number
+ avatar: string
+ loginIp: string
+ status: number
+ remark: string
+ loginDate: Date
+ createTime: Date
+}
+
+export interface UserSimple {
+ id: number;
+ nickname: string;
+ deptId: number;
+ deptName: string;
+}
+
+// 查询用户管理列表
+export const getUserPage = (params: PageParam) =>
+ systemServer({
+ url: '/user/page',
+ method: 'get',
+ params,
+ })
+
+// 查询所有用户列表
+export const getAllUser = () =>
+ systemServer({
+ url: '/user/all',
+ method: 'get',
+ })
+
+// 查询用户详情
+export const getUser = (id: number) =>
+ systemServer({
+ url: '/user/get?id=' + id,
+ method: 'get',
+ })
+
+// 新增用户
+export const createUser = (data: UserVO) =>
+ systemServer({
+ url: '/user/create',
+ method: 'post',
+ data,
+ })
+
+// 修改用户
+export const updateUser = (data: UserVO) =>
+ systemServer({
+ url: '/user/update',
+ method: 'put',
+ data,
+ })
+
+// 删除用户
+export const deleteUser = (id: number) =>
+ systemServer({
+ url: '/user/delete?id=' + id,
+ method: 'delete',
+ })
+
+// 导出用户
+export const exportUser = (params: any) =>
+ systemServer({
+ url: '/user/export',
+ method: 'get',
+ responseType: 'blob',
+ params,
+ })
+
+// 下载用户导入模板
+export const importUserTemplate = () =>
+ systemServer({
+ url: '/user/get-import-template',
+ method: 'get',
+ responseType: 'blob',
+ })
+
+// 用户密码重置
+export const resetUserPwd = (id: number, password: string) => {
+ const data = {
+ id,
+ password,
+ }
+ return systemServer({
+ url: '/user/reset-password',
+ method: 'put',
+ data,
+ })
+}
+
+// 用户状态修改
+export const updateUserStatus = (id: number, status: number) => {
+ const data = {
+ id,
+ status,
+ }
+ return systemServer({
+ url: '/user/update-status',
+ method: 'put',
+ data,
+ })
+}
+
+// 获取用户精简信息列表
+export const getSimpleUserList = () => {
+ return systemServer({
+ url: '/user/simple-list',
+ method: 'get',
+ })
+}
diff --git a/src/api/module/system/user/profile.ts b/src/api/module/system/user/profile.ts
new file mode 100644
index 0000000..59e70bd
--- /dev/null
+++ b/src/api/module/system/user/profile.ts
@@ -0,0 +1,75 @@
+import { systemServer } from '../../index'
+export interface ProfileVO {
+ id: number
+ username: string
+ nickname: string
+ dept: {
+ id: number
+ name: string
+ }
+ roles: {
+ id: number
+ name: string
+ }[]
+ posts: {
+ id: number
+ name: string
+ }[]
+ socialUsers: {
+ type: number
+ openid: string
+ }[]
+ email: string
+ mobile: string
+ sex: number
+ avatar: string
+ status: number
+ remark: string
+ loginIp: string
+ loginDate: Date
+ createTime: Date
+}
+
+export interface UserProfileUpdateReqVO {
+ nickname: string
+ email: string
+ mobile: string
+ sex: number
+}
+
+// 查询用户个人信息
+export const getUserProfile = () =>
+ systemServer({
+ url: '/user/profile/get',
+ method: 'get',
+ })
+
+// 修改用户个人信息
+export const updateUserProfile = (data: UserProfileUpdateReqVO) =>
+ systemServer({
+ url: '/user/profile/update',
+ method: 'put',
+ data,
+ })
+
+// 用户密码重置
+export const updateUserPassword = (oldPassword: string, newPassword: string) =>
+ systemServer({
+ url: '/user/profile/update-password',
+ method: 'put',
+ data: {
+ oldPassword,
+ newPassword,
+ },
+ })
+
+// 用户头像上传
+export const uploadAvatar = (data: any) =>
+ systemServer({
+ url: '/user/profile/update-avatar',
+ data,
+ method: 'post',
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ },
+ })
diff --git a/src/api/module/system/user/socialUser.ts b/src/api/module/system/user/socialUser.ts
new file mode 100644
index 0000000..398f0a0
--- /dev/null
+++ b/src/api/module/system/user/socialUser.ts
@@ -0,0 +1,30 @@
+import { systemServer } from '../../index'
+// 社交绑定,使用 code 授权码
+export const socialBind = (type: any, code: any, state: any) =>
+ systemServer({
+ url: '/social-user/bind',
+ method: 'post',
+ data: {
+ type,
+ code,
+ state,
+ },
+ })
+
+// 取消社交绑定
+export const socialUnbind = (type: any, openid: any) =>
+ systemServer({
+ url: '/social-user/unbind',
+ method: 'delete',
+ data: {
+ type,
+ openid,
+ },
+ })
+
+// 社交授权的跳转
+export const socialAuthRedirect = (type: any, redirectUri: any) =>
+ systemServer({
+ url: '/auth/social-auth-redirect?type=' + type + '&redirectUri=' + redirectUri,
+ method: 'get',
+ })
diff --git a/src/api/server/axiosInstance.ts b/src/api/server/axiosInstance.ts
index 8fb273d..040c83e 100644
--- a/src/api/server/axiosInstance.ts
+++ b/src/api/server/axiosInstance.ts
@@ -67,6 +67,10 @@ const createAxiosInstance = (module: APIConfigKeys, config: Config) => {
(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
// config.headers.Authorization = basicHeader.token()
// config.headers['tenant-id'] = basicHeader.tenant()
+ if (config.url?.includes('/login')) {
+ config.headers['tenant-id'] = '1'
+ }
+
const params = config.params || {}
const data = config.data || false
diff --git a/src/api/server/config.ts b/src/api/server/config.ts
index cee8eca..d36f6d4 100644
--- a/src/api/server/config.ts
+++ b/src/api/server/config.ts
@@ -1,5 +1,6 @@
export interface APIConfig {
global: Config
+ system: Config
}
interface Config {
@@ -11,6 +12,9 @@ const API_Config: APIConfig = {
global: {
baseAPI: import.meta.env.VITE_BASE_API,
},
+ system: {
+ baseAPI: import.meta.env.VITE_BASE_API_SYSTEM,
+ },
}
diff --git a/src/assets/images/login/avatar.png b/src/assets/images/login/avatar.png
new file mode 100644
index 0000000..720f7d2
Binary files /dev/null and b/src/assets/images/login/avatar.png differ
diff --git a/src/assets/images/login/bg.png b/src/assets/images/login/bg.png
new file mode 100644
index 0000000..b9ef171
Binary files /dev/null and b/src/assets/images/login/bg.png differ
diff --git a/src/assets/images/login/logo.png b/src/assets/images/login/logo.png
new file mode 100644
index 0000000..0439741
Binary files /dev/null and b/src/assets/images/login/logo.png differ
diff --git a/src/hooks/useCache.ts b/src/hooks/useCache.ts
new file mode 100644
index 0000000..1902b8d
--- /dev/null
+++ b/src/hooks/useCache.ts
@@ -0,0 +1,38 @@
+/**
+ * 配置浏览器本地存储的方式,可直接存储对象数组。
+ */
+
+import Keys from '@/api/Keys'
+import WebStorageCache from 'web-storage-cache'
+
+type CacheType = 'localStorage' | 'sessionStorage'
+
+export const useCache = (type: CacheType = 'localStorage') => {
+ const wsCache: WebStorageCache = new WebStorageCache({
+ storage: type,
+ })
+
+ return {
+ wsCache,
+ }
+}
+
+export const deleteUserCache = () => {
+ const { wsCache } = useCache()
+ wsCache.delete(Keys.STORAGE_USER_INFO)
+ wsCache.delete(Keys.STORAGE_ROLE_ROUTERS)
+ wsCache.delete(Keys.STORAGE_STATIONID)
+}
+
+export function getCacheStationId(
+ stationId: number | string,
+ type: 'get' | 'set' = 'get'
+) {
+ const { wsCache } = useCache()
+ const id = wsCache.get(Keys.STORAGE_STATIONID)
+ if (!id || type === 'set') {
+ wsCache.set(Keys.STORAGE_STATIONID, stationId)
+ return Number(stationId)
+ }
+ return Number(id)
+}
diff --git a/src/hooks/useMessage.ts b/src/hooks/useMessage.ts
new file mode 100644
index 0000000..51ce7c3
--- /dev/null
+++ b/src/hooks/useMessage.ts
@@ -0,0 +1,148 @@
+import Keys from '@/api/Keys'
+import type { Result } from '@/api/basic/httpTypes'
+import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
+export const useMessage = () => {
+ return {
+ // 消息提示
+ info(content: string) {
+ ElMessage.info(content)
+ },
+ // 错误消息
+ error(content: string) {
+ ElMessage.error(content)
+ },
+ // 成功消息
+ success(content: string) {
+ ElMessage.success(content)
+ },
+ // 警告消息
+ warning(content: string) {
+ ElMessage.warning(content)
+ },
+ // 弹出提示
+ alert(content: string) {
+ ElMessageBox.alert(content, '系统提示')
+ },
+ // 错误提示
+ alertError(content: string) {
+ ElMessageBox.alert(content, '系统提示', { type: 'error' })
+ },
+ // 成功提示
+ alertSuccess(content: string) {
+ ElMessageBox.alert(content, '系统提示', { type: 'success' })
+ },
+ // 警告提示
+ alertWarning(content: string) {
+ ElMessageBox.alert(content, '系统提示', { type: 'warning' })
+ },
+ // 通知提示
+ notify(content: string) {
+ ElNotification.info(content)
+ },
+ // 错误通知
+ notifyError(content: string, tip?: string) {
+ ElNotification.error({
+ title: tip ? tip : '系统提示',
+ message: content,
+ })
+ },
+ // 成功通知
+ notifySuccess(content: string) {
+ ElNotification.success(content)
+ },
+ // 警告通知
+ notifyWarning(content: string) {
+ ElNotification.warning(content)
+ },
+ // 确认窗体
+ confirm(content: string, tip?: string) {
+ return ElMessageBox.confirm(content, tip ? tip : '系统提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ confirmButtonClass: 'el-button--success',
+ cancelButtonClass: 'el-button--default',
+ type: 'warning',
+ })
+ },
+ forceConfirm(content: string, tip?: string, buttonText?: string) {
+ return ElMessageBox.confirm(content, tip ? tip : '系统提示', {
+ confirmButtonText: buttonText ?? '确定',
+ showCancelButton: false,
+ closeOnClickModal: false,
+ closeOnPressEscape: false,
+ confirmButtonClass: 'el-button--success',
+ cancelButtonClass: 'el-button--default',
+ showClose: false,
+ type: 'warning',
+ })
+ },
+ // 删除窗体
+ delConfirm(content?: string, tip?: string) {
+ return new Promise((resolve, reject) => {
+ ElMessageBox.confirm(
+ content ? content : '是否确认删除数据项?',
+ tip ? tip : '系统提示',
+ {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning',
+ confirmButtonClass: 'el-button--success',
+ cancelButtonClass: 'el-button--default',
+ }
+ )
+ .then(() => {
+ resolve('')
+ })
+ .catch(() => {
+ reject('')
+ })
+ })
+ },
+ // 导出窗体
+ exportConfirm(content?: string, tip?: string) {
+ return ElMessageBox.confirm(
+ content ? content : '是否确认导出数据项?',
+ tip ? tip : '系统提示',
+ {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ confirmButtonClass: 'el-button--success',
+ cancelButtonClass: 'el-button--default',
+ type: 'warning',
+ }
+ )
+ },
+ // 提交内容
+ prompt(content: string, tip: string) {
+ return ElMessageBox.prompt(content, tip, {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ confirmButtonClass: 'el-button--success',
+ cancelButtonClass: 'el-button--default',
+ type: 'warning',
+ })
+ },
+
+ promptVerify(content: string, tip: string, pattern: string, inputErrorMessage = '') {
+ const PatternRegExp = new RegExp(
+ `^${pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')}$`
+ )
+ return ElMessageBox.prompt(content, tip, {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ confirmButtonClass: 'el-button--success',
+ cancelButtonClass: 'el-button--default',
+ inputPattern: PatternRegExp,
+ inputErrorMessage: inputErrorMessage,
+ type: 'warning',
+ })
+ },
+ }
+}
+
+export function isResError(res: Result, msg?: string) {
+ if (res.code === Keys.CODE_SUCCEED || res.status === 200 || res.code === 200)
+ return false
+ ElMessage.error(res?.msg ?? msg)
+ return true
+}
diff --git a/src/router/index.ts b/src/router/index.ts
index 9b5a9c6..48452f2 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -1,6 +1,17 @@
+import { getToken } from '@/utils/auth';
import { createRouter, createWebHistory } from 'vue-router'
export const defaultRouter = [
+ {
+ path: '/login',
+ component: () => import('@/views/login/index.vue'),
+ name: 'Login',
+ meta: {
+ hidden: true,
+ title: '登录',
+ noTagsView: true,
+ },
+ },
{
path: '/',
name: 'dashboard',
@@ -58,4 +69,24 @@ const router = createRouter({
routes: defaultRouter,
})
+
+const whiteList = ['/login']
+
+router.beforeEach(async (to, from, next) => {
+ if (!getToken()) {
+ if (whiteList.indexOf(to.path) !== -1) {
+ next()
+ } else {
+ next('/login')
+ }
+ return
+ }
+
+ if (to.path === '/login' || to.path === '/') {
+ next('/engineering')
+ return
+ }
+ next()
+})
+
export default router
diff --git a/src/stores/engineering.ts b/src/stores/engineering.ts
index f8cde81..cdec045 100644
--- a/src/stores/engineering.ts
+++ b/src/stores/engineering.ts
@@ -13,7 +13,7 @@ export const useEngineeringStore = defineStore('engineering', () => {
loading.value = true
try {
const res = await getEngineeringList()
- engineeringList.value = Array.isArray(res.data?.list) ? res.data.list : []
+ engineeringList.value = Array.isArray(res.data) ? res.data : []
} catch (error) {
console.error(error)
engineeringList.value = []
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
new file mode 100644
index 0000000..01fb0a3
--- /dev/null
+++ b/src/utils/auth.ts
@@ -0,0 +1,38 @@
+import Keys from "@/api/Keys";
+// @ts-ignore
+import { useCache } from "@/hooks/useCache";
+const { wsCache } = useCache();
+
+export const getToken = () => wsCache.get(Keys.STORAGE_TOKEN);
+
+export const setToken = (token: string) => {
+ wsCache.set(Keys.STORAGE_TOKEN, token);
+};
+
+export const setRefreshToken = (refreshToken: any) => {
+ wsCache.set(Keys.STORAGE_REFRESH_TOKEN, refreshToken);
+};
+
+export const getRefreshToken = () => wsCache.get(Keys.STORAGE_REFRESH_TOKEN);
+
+export const removeToken = () => {
+ wsCache.delete(Keys.STORAGE_TOKEN);
+ wsCache.delete(Keys.STORAGE_REFRESH_TOKEN);
+};
+
+export const getLocalUserInfo = () => wsCache.get(Keys.STORAGE_USER_INFO);
+
+export const setUserInfo = (userInfo: any) =>
+ wsCache.set(Keys.STORAGE_USER_INFO, userInfo);
+
+// ========== 权限路由相关 ==========
+export const getRoleRouters = () => wsCache.get(Keys.STORAGE_ROLE_ROUTERS);
+
+export const setRoleRouters = (roleRouters: any) =>
+ wsCache.set(Keys.STORAGE_ROLE_ROUTERS, roleRouters);
+
+// ========== 租户相关 ==========
+export const getTenantId = () => wsCache.get(Keys.STORAGE_TENANT_ID);
+
+export const setTenantId = (tenantId: number) =>
+ wsCache.set(Keys.STORAGE_TENANT_ID, tenantId);
diff --git a/src/utils/hooks.ts b/src/utils/hooks.ts
new file mode 100644
index 0000000..6b68afc
--- /dev/null
+++ b/src/utils/hooks.ts
@@ -0,0 +1,124 @@
+import { debounce } from 'lodash-es'
+import { onScopeDispose } from 'vue'
+
+export function useWindowKeyEnter(fn: Function) {
+ let isComposing = false
+
+ window.addEventListener('compositionstart', () => {
+ isComposing = true
+ })
+ window.addEventListener('compositionend', () => {
+ isComposing = false
+ })
+ window.addEventListener('keydown', handleKeyDown)
+
+ function handleKeyDown(e: KeyboardEvent) {
+ if (!isComposing && e.key === 'Enter') {
+ fn()
+ }
+ }
+
+ onScopeDispose(() => {
+ window.removeEventListener('compositionstart', () => {
+ isComposing = true
+ })
+ window.removeEventListener('compositionend', () => {
+ isComposing = false
+ })
+ window.removeEventListener('keydown', handleKeyDown)
+ })
+}
+
+export function useWindowResize(fn: (...args: any[]) => any, delay: number = 300) {
+ const handleResize = debounce(fn, delay)
+
+ window.addEventListener('resize', handleResize)
+
+ return () => {
+ window.removeEventListener('resize', handleResize)
+ }
+}
+
+export function useFlatArray(data: Array, flatKey: string = 'children') {
+ const result: any[] = []
+
+ function flat(items: any[]) {
+ for (const item of items) {
+ result.push(item)
+ if (item[flatKey] && item[flatKey].length > 0) {
+ flat(item[flatKey])
+ }
+ }
+ }
+
+ flat(data)
+ return result
+}
+
+export const ipPattern =
+ /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+
+export function getColor(percentageStr: string) {
+ let percentage
+ if (!percentageStr.includes('%')) {
+ percentage = parseFloat(percentageStr.replace('%', ''))
+ } else {
+ percentage = parseFloat(percentageStr)
+ }
+
+ if (percentage >= 0 && percentage <= 33.33) {
+ return '#D51B60'
+ } else if (percentage > 33.33 && percentage <= 66.66) {
+ return '#FC861B'
+ } else if (percentage > 66.66 && percentage <= 100) {
+ return '#00CD35'
+ } else {
+ return null // 超出范围
+ }
+}
+
+export function useParseHexToJson(hexString: string): object {
+ // 如果十六进制字符串长度是奇数,则在前面加零
+ if (hexString.length % 2 !== 0) {
+ hexString = '0' + hexString
+ }
+
+ // 将十六进制字符串转换为 ASCII 字符串
+ function hexToAscii(hex: string) {
+ let asciiStr = ''
+ for (let i = 0; i < hex.length; i += 2) {
+ asciiStr += String.fromCharCode(parseInt(hex.substring(i, i + 2), 16))
+ }
+ return asciiStr
+ }
+
+ // 解析十六进制字符串并转换为 JSON 对象
+ const asciiString = hexToAscii(hexString)
+ return JSON.parse(asciiString)
+}
+
+interface ItemWithChildren {
+ children?: ItemWithChildren[]
+}
+
+export function useFilterArray(
+ data: T[],
+ idToFilter: T[K],
+ idKey: K
+): T[] {
+ return data
+ .map(item => {
+ if (item[idKey] === idToFilter) {
+ return null
+ }
+
+ // 递归处理子节点
+ const filteredChildren = Array.isArray(item.children)
+ ? useFilterArray(item.children as T[], idToFilter, idKey)
+ : null
+
+ // 返回一个新的对象,包含过滤后的子节点
+ return { ...item, children: filteredChildren }
+ })
+ .filter(Boolean) as T[]
+}
diff --git a/src/views/engineering/config/index.vue b/src/views/engineering/config/index.vue
index ffec9f1..7e4a77c 100644
--- a/src/views/engineering/config/index.vue
+++ b/src/views/engineering/config/index.vue
@@ -112,7 +112,7 @@ const router = useRouter()
const route = useRoute()
const projectName = computed(() => route.query.name as string)
-const isCreate = computed(() => route.query.isCreate as string)
+const isCreate = computed(() => route.query.type === 'create')
type Step = 'channel' | 'category' | 'device'
const steps: Step[] = ['channel', 'category', 'device']
diff --git a/src/views/layout/index.vue b/src/views/layout/index.vue
index c992a1b..0bc9618 100644
--- a/src/views/layout/index.vue
+++ b/src/views/layout/index.vue
@@ -78,6 +78,23 @@
{{ currentTime }}
+
+
handleCommand(command)"
+ >
+
+
![]()
+
+
+
+
+
+ 退出登录
+
+
+
+
@@ -93,6 +110,10 @@ import { defaultRouter } from '@/router'
import dayjs from 'dayjs'
import { useEngineeringStore } from '@/stores/engineering'
import { storeToRefs } from 'pinia'
+import Avatar from '@/assets/images/login/avatar.png'
+import { loginOut } from '@/api/module/system/login'
+import { removeToken } from '@/utils/auth'
+import { deleteUserCache } from '@/hooks/useCache'
const unfold = 'i-icon-park-outline:menu-unfold'
const fold = 'i-icon-park-outline:menu-fold'
@@ -103,7 +124,7 @@ const engineeringStore = useEngineeringStore()
const { engineeringList } = storeToRefs(engineeringStore)
const menuList = computed(() => {
- const routes = JSON.parse(JSON.stringify(defaultRouter[0].children))
+ const routes = defaultRouter.find(r => r.name === 'dashboard')!.children as any[]
const engRoute = routes.find((r: any) => r.path === '/engineering')
if (engRoute) {
// Initialize children array
@@ -147,15 +168,8 @@ const engineeringTreeData = computed(() => [
},
])
-const circleUrl = ref(
- 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
-)
const isCollapse = ref(false)
-const getIconClass = (icon: string) => {
- return icon
-}
-
const { push, currentRoute } = useRouter()
const activeMenu = computed(() => {
const { meta, path, query } = unref(currentRoute)
@@ -183,6 +197,24 @@ const updateTime = () => {
requestAnimationFrame(updateTime)
}
+function handleCommand(command: string) {
+ if (command === 'logout') {
+ logOut()
+ }
+}
+async function logOut() {
+ try {
+ await ElMessageBox.confirm('是否退出本系统?', '温馨提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning',
+ })
+ await loginOut()
+ removeToken()
+ deleteUserCache()
+ push('/login')
+ } catch {}
+}
onMounted(() => {
updateTime()
engineeringStore.fetchEngineeringList()
@@ -279,8 +311,16 @@ onMounted(() => {
}
}
- .avatar {
- @apply w-24 h-24;
+ .right {
+ @apply h-full flex items-center;
+
+ .user-avatar {
+ @apply flex items-center cursor-pointer outline-none;
+
+ img {
+ @apply w-32px h-32px rounded-full;
+ }
+ }
}
.menu-icon {
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
new file mode 100644
index 0000000..f924e17
--- /dev/null
+++ b/src/views/login/index.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
![]()
+
+
+
+
+
+
+
+