This commit is contained in:
yyy 2025-05-27 09:39:01 +08:00
parent ecfe1b6145
commit 771e4dd829
147 changed files with 51817 additions and 162 deletions

2
.env
View File

@ -1,5 +1,5 @@
# 标题
VITE_APP_TITLE=芋道管理系统
VITE_APP_TITLE=RCS智能设备调度系统
# 项目本地运行端口号
VITE_PORT=80

View File

@ -4,7 +4,9 @@ NODE_ENV=production
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://api-dashboard.yudao.iocoder.cn'
# VITE_BASE_URL='http://192.168.0.66:48080'
# VITE_BASE_URL='http://192.168.0.189:48080'
VITE_BASE_URL='http://10.10.5.5:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server
@ -31,7 +33,7 @@ VITE_OUT_DIR=dist
VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn'
# 验证码的开关
VITE_APP_CAPTCHA_ENABLE=true
VITE_APP_CAPTCHA_ENABLE=false
# GoView域名
VITE_GOVIEW_URL='http://127.0.0.1:3000'

View File

@ -4,7 +4,9 @@ NODE_ENV=development
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://localhost:48080'
# VITE_BASE_URL='http://192.168.77.50:48080'
# VITE_BASE_URL='http://10.10.100.32:48080'
VITE_BASE_URL='http://10.10.5.5:48080'
# 文件上传类型server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server

View File

@ -62,16 +62,16 @@
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
@ -141,5 +141,6 @@
"package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.eslintrc-auto-import.json,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
},
"terminal.integrated.scrollback": 10000,
"nuxt.isNuxtApp": false
"nuxt.isNuxtApp": false,
"liveServer.settings.port": 5502
}

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@ -136,7 +136,7 @@
<div class="app-loading">
<div class="app-loading-wrap">
<div class="app-loading-title">
<img src="/logo.gif" class="app-loading-logo" alt="Logo" />
<!-- <img src="/logo.gif" class="app-loading-logo" alt="Logo" /> -->
<div class="app-loading-title">%VITE_APP_TITLE%</div>
</div>
<div class="app-loading-item">

31850
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@
"@element-plus/icons-vue": "^2.1.0",
"@form-create/designer": "^3.2.6",
"@form-create/element-ui": "^3.2.11",
"@gausszhou/vue3-drag-resize-rotate": "^3.0.2",
"@iconify/iconify": "^3.1.1",
"@microsoft/fetch-event-source": "^2.0.1",
"@videojs-player/vue": "^1.0.0",
@ -51,6 +52,7 @@
"fast-xml-parser": "^4.3.2",
"highlight.js": "^11.9.0",
"jsencrypt": "^3.3.2",
"json-bigint": "^1.0.0",
"lodash-es": "^4.17.21",
"markdown-it": "^14.1.0",
"markmap-common": "^0.16.0",
@ -66,9 +68,11 @@
"qs": "^6.12.0",
"sortablejs": "^1.15.3",
"steady-xml": "^0.1.0",
"swiper": "^8.4.7",
"url": "^0.11.3",
"video.js": "^7.21.5",
"vue": "3.5.12",
"vue-awesome-swiper": "^5.0.1",
"vue-dompurify-html": "^4.1.4",
"vue-i18n": "9.10.2",
"vue-router": "4.4.5",

View File

@ -22,7 +22,7 @@ const setDefaultTheme = () => {
}
appStore.setIsDark(isDarkTheme)
}
setDefaultTheme()
// setDefaultTheme()
</script>
<template>
<ConfigGlobal :size="currentSize">
@ -54,4 +54,13 @@ body {
.#{$prefix-cls}-grey-mode {
filter: grayscale(100%);
}
.indexpage-custom-message-style {
// padding: 0 !important;
background: #c60606;
border: none;
padding: 9px 20px !important;
.el-message-icon--info {
color: #ffffff !important;
}
}
</style>

View File

@ -0,0 +1,8 @@
import request from '@/config/axios'
//获取整体看板信息
export const bulletinBoardGet = async (params) => {
return await request.get({ url: `/system/bulletinBoard/get`, params })
}

72
src/api/car/index.ts Normal file
View File

@ -0,0 +1,72 @@
import request from '@/config/axios'
//agv 下载
export const agvDownload = async (params) => {
return await request.download({ url: `/system/position-map/agvDownload`, params })
}
//点位地图列表
export const getPositionMapList = async (params) => {
return await request.get({ url: `/system/position-map/list`, params })
}
//删除车辆信息
export const deleteRobotInformation = async (id: number) => {
return await request.delete({ url: `/system/robot/information/delete?id=` + id })
}
//查询所有车辆
export const getAllRobot = async (data) => {
return await request.post({ url: `/system/robot/information/getAllRobot`, data })
}
//获得车辆信息 详情
export const getRobotInformation = async (params) => {
return await request.get({ url: `/system/robot/information/get`, params })
}
//分页查询车辆列表 看板信息车辆目前用的是这个
export const robotInformationPage = async (params) => {
return await request.get({ url: `/system/robot/information/page`, params })
}
//统计车辆待命-任务中-离线
export const robotInformationStatistics = async (data) => {
return await request.post({ url: `/system/robot/information/statistics`, data })
}
// 创建车辆信息
export const robotInformationCreate = async (data) => {
return await request.post({ url: `/system/robot/information/create`, data })
}
// 编辑车辆信息
export const robotInformationUpdate = async (data) => {
return await request.put({ url: `/system/robot/information/update`, data })
}
//分页查询车辆列表 看板信息车辆目前用的是这个
export const robotGetAllModel = async (params) => {
return await request.get({ url: `/system/robot/model/getAllModel`, params })
}
// 范围选择
export const robotPositionGetMap = async (params) => {
return await request.get({ url: `/system/position-map/getMap`, params })
}
// 完整范围选择
export const robotPositionGetMapAll = async (params) => {
return await request.get({ url: `/system/position-map/getAllMap`, params })
}
// 完整范围选择 修改成这个了 车辆那边
export const robotPositionGetMapAllNew = async (params) => {
return await request.get({ url: `/system/position-map/getMap`, params })
}
//获得车辆列表 新
export const getRobotInformationList = async (params) => {
return await request.get({ url: `/system/robot/information/list`, params })
}
// 清除交管
export const cleanTrafficManagement = async (data) => {
return await request.post({ url: `/system/robot/information/cleanTrafficManagement?robotNo=${data.robotNo}`, data })
}
// 恢复任务
export const doTaskContinue = async (data) => {
return await request.post({ url: `/system/robot/information/doTaskContinue?robotNo=${data.robotNo}`, data })
}

17
src/api/carError/index.ts Normal file
View File

@ -0,0 +1,17 @@
import request from '@/config/axios'
//获得机器人告警信息分页
export const getRobotWarnMsgPage = async (params) => {
return await request.get({ url: `/system/robot/warn-msg/page`, params })
}
//更新已读状态
export const robotWarnMsgUpdate= async (data) => {
return await request.put({ url: `/system/robot/warn-msg/update`, data })
}
//更新已读状态 全部已读
export const robotWarnMsgUpdateAll= async (data) => {
return await request.post({ url: `/system/robot/warn-msg/allRead`, data })
}

43
src/api/device/index.ts Normal file
View File

@ -0,0 +1,43 @@
import request from '@/config/axios'
//分页查询设备列表 看板信息设备目前用的是这个
export const deviceInformationPage = async (params) => {
return await request.get({ url: `/system/device/information/page`, params })
}
//统计车辆待命-任务中-离线
export const robotInformationStatistics = async (data) => {
return await request.post({ url: `/system/robot/information/statistics`, data })
}
// 创建设备信息
export const deviceInformationCreate = async (data) => {
return await request.post({ url: `/system/device/information/create`, data })
}
// 编辑设备信息
export const deviceInformationUpdate = async (data) => {
return await request.put({ url: `/system/device/information/update`, data })
}
// 地图绑定设备
export const deviceInformationGet = async (params) => {
return await request.get({ url: `/system/device/information/get`, params })
}
//删除设备信息
export const deleteDeviceInformation = async (id: number) => {
return await request.delete({ url: `/system/device/information/delete?id=` + id })
}
// 获取设备列表
export const deviceNumber = async (params) => {
return await request.get({ url: `/system/device/information/deviceNumber`, params })
}
// 获取设备列表 新不分页
export const deviceGetInformationList = async (params) => {
return await request.get({ url: `/system/device/information/getInformationList`, params })
}
// 获取设备列表
export const getMapDeviceImageUrl = async (params) => {
return await request.get({ url: `/system/device/information/getMapImageUrl`, params })
}

View File

@ -0,0 +1,16 @@
import request from '@/config/axios'
//获得获得库位
export const getHouseLocation = async (id: number) => {
return await request.get({ url: `/system/ware/house-location/get?id=` + id })
}
// 更新库位
export const updateHouseLocation = (data) => {
return request.put({ url: '/system/ware/house-location/update', data })
}
//获得库位分页
export const getHouseLocationPage = async (data) => {
return await request.post({ url: `/system/ware/house-location/page`, data })
}

16
src/api/map/logList.ts Normal file
View File

@ -0,0 +1,16 @@
import request from '@/config/axios'
//任务日志分页
export const getRobotTaskPage = async (data) => {
return await request.post({ url: `/system/robot/task/logPage`, data })
}
//获得车辆动作记录分页
export const getTaskDetailPage = async (params) => {
return await request.get({ url: `/system/robot/task-detail-action-log/page`, params })
}
//用户操作记录
export const getUserOperationLogPage = async (params) => {
return await request.get({ url: `/system/log/user-operation-log/page`, params })
}

250
src/api/map/map.ts Normal file
View File

@ -0,0 +1,250 @@
import request from '@/config/axios'
//agv 下载
export const agvDownload = async (params) => {
return await request.download({ url: `/system/position-map/agvDownload`, params })
}
//点位地图列表
export const getPositionMapList = async (params) => {
return await request.get({ url: `/system/position-map/list`, params })
}
//点位地图列表 map分好组
export const getPositionMapGetMap = async (params) => {
return await request.get({ url: `/system/position-map/getMap`, params })
}
//点位地图列表 详细数据
export const getPositionMapDownloadPng = async (params) => {
return await request.get({ url: `/system/position-map/downloadPng`, params })
}
//点位地图 base64
export const getPositionMapdDwnloadPngBase64 = async (params) => {
return await request.get({ url: `/system/position-map/downloadPngBase64`, params })
}
//删除仓库点位地图
export const deletePositionMap = async (id: number) => {
return await request.delete({ url: `/system/position-map/delete?id=` + id })
}
//下载文件
export const downloadPositionMap = async (params) => {
return await request.get({ url: `/system/position-map/download`, params })
}
//获得仓库点位地图
export const getPositionMap = async (id) => {
return await request.get({ url: `/system/position-map/get?id=` + id })
}
// 文件上传
export const uploadPositionMap = async (data) => {
return await request.post({ url: `/system/position-map/upload`, data })
}
//创建编辑仓库点位地图连线
export const createOrEditPositionMapLine = async (data) => {
return await request.post({ url: `/system/position-map-line/createOrEdit`, data })
}
//删除仓库点位地图连线
export const deletePositionMapLine = async (data) => {
return await request.delete({ url: `/system/position-map-line/delete`, data })
}
//获得仓库点位地图连线
export const getPositionMapLine = async (params) => {
return await request.get({ url: `/system/position-map-line/get`, params })
}
//通过地图id获取连线列表
export const getPositionMapLineList = async (params) => {
return await request.get({ url: `/system/position-map-line/list`, params })
}
//批量新增编辑删除节点
export const batchSaveOrEditOrDelMapItem = async (positionMapId, data) => {
return await request.post({
url: `/system/position-map-item/batchSaveOrEditOrDel?positionMapId=${positionMapId}`,
data
})
}
//导出仓库点位地图子表 Excel
export const exportPositionMapItemExcel = async (params) => {
return await request.get({ url: `/system/position-map-item/export-excel`, params })
}
//获得仓库点位地图子表
export const getPositionMapItem = async (params) => {
return await request.get({ url: `/system/position-map-item/get`, params })
}
//获取仓库点位地图节点列表
export const getPositionMapItemList = async (params) => {
return await request.get({ url: `/system/position-map-item/list`, params })
}
//获得设备信息列表
export const getDeviceInformationList = async (params) => {
return await request.get({ url: `/system/device/information/list`, params })
}
//地图绑定设备
export const mapBindDeviceInfo = async (data) => {
return await request.post({ url: `/system/device/information/mapBindDeviceInfo`, data })
}
//创建修改删除库区
export const createOrEditOrDelHouseArea = async (data) => {
return await request.post({ url: `/system/ware/house-area/createOrEditOrDel`, data })
}
//创建修改删除线库
export const createOrEditOrDelHouseLane = async (data) => {
return await request.post({ url: `/system/ware/house-lane/createOrEditOrDel`, data })
}
//根据点位获取库位信息列表
export const houseLocationGetByMapItemId = async (params) => {
return await request.get({ url: `/system/ware/house-location/getByMapItemId`, params })
}
// 更新库位
export const updateHouseLocation = async (data) => {
return await request.put({ url: `/system/ware/house-location/update`, data })
}
//创建编辑删除仓库点位地图连线
export const createOrEditOrDelPositionMapLine = async (positionMapId, data) => {
return await request.post({
url: `/system/position-map-line/createOrEditOrDel?positionMapId=${positionMapId}`,
data
})
}
// 获得仓库点位地图连线
export const getPositionMapLineById = async (id: number) => {
return await request.get({ url: `/system/position-map-line/get?id=` + id })
}
// 通过地图id获取连线列表
export const getPositionMapLineByPositionMapId = async (positionMapId: number) => {
return await request.get({ url: `/system/position-map-line/list?positionMapId=` + positionMapId })
}
//获取仓库点位地图节点列表
export const getWareHouseAreaPage = async (params) => {
return await request.get({ url: `/system/ware/house-area/page`, params })
}
//删除仓库点位地图
export const deleteWareHouseArea = async (id: number) => {
return await request.delete({ url: `/system/ware/house-area/delete?id=` + id })
}
//获得线库分页
export const getWareHouseLanePage = async (params) => {
return await request.get({ url: `/system/ware/house-lane/page`, params })
}
//删除仓库点位地图
export const deleteWareLaneArea = async (id: number) => {
return await request.delete({ url: `/system/ware/house-lane/delete?id=` + id })
}
// 获取仓库点位连线
export const mapLineGet = async (params) => {
return await request.get({ url: `/system/position-map-line/get`, params })
}
//通过地图id获取连线列表
export const mapLineListGet = async (params) => {
return await request.get({ url: `/system/position-map-line/list`, params })
}
// 获得车辆信息分页
export const getRobotInformationPage = async (params) => {
return await request.get({ url: `/system/robot/information/page`, params })
}
//获取AGV点位信息
export const getAGVPointInformation = async (macAddress) => {
return await request.get({
url: `/system/position-map-item/getAGVPointInformation?macAddress=` + macAddress
})
}
//根据地图id获取车辆列表
export const getListByMapId = async (mapId) => {
return await request.get({
url: `/system/robot/information/getListByMapId?mapId=` + mapId
})
}
//批量更新库位
export const updateBatchHouseLocation = async (data) => {
return await request.put({
url: `/system/ware/house-location/updateBatch`,
data
})
}
// 获取楼层区域对应的机器人编号
export const getRobotByFloorAndArea = async (params) => {
return await request.post({ url: `/system/robot/information/getRobotByFloorAndArea`, params })
}
//根据点位获取库位信息列表
export const getByMapItemId = async (mapId, mapItemId) => {
return await request.get({
url: `/system/ware/house-location/getByMapItemId?mapItemId=${mapItemId}&mapId=${mapId}`
})
}
//线上加点保存点位
export const lineAddItem = async (data) => {
return await request.post({
url: `/system/position-map-item/lineAddItem`,
data
})
}
//获取id
export const getNodeId = async () => {
return await request.get({
url: `/system/position-map-item/getUUid`
})
}
//一键急停or一键恢复地图上所有AGV
export const emergencyStopOrRecovery = async (params) => {
return await request.get({
url: `/system/position-map/emergencyStopOrRecovery`,
params
})
}
// 根据地图id获取暂停的地图
export const getMapIsStop = async (params) => {
return await request.get({
url: `/system/robot/map-stop/getByMapId`,
params
})
}
//创建区域变更点绑定
export const bindingPositionChangePoint = async (data) => {
return await request.post({
url: `/system/position-change-point-binding/create`,
data
})
}
//根据点位id查询此点位已经绑定的转换点信息
export const getPositionChangePoint = async (params) => {
return await request.get({
url: `/system/position-change-point-binding/get`,
params
})
}
//更新区域变更点绑定
export const updatePositionChangePoint = async (data) => {
return await request.put({
url: `/system/position-change-point-binding/update`,
data
})
}
//根据排序查询点位信息
export const getPositionChangePointBySortNum = async (params) => {
return await request.get({
url: `/system/position-change-point-binding/getItemBySortNum`,
params
})
}
//删除区域变更点绑定
export const deletePositionChangePoint = async (data) => {
return await request.delete({
url: `/system/position-change-point-binding/delete`,
data
})
}
export const checkHaveTask = async (data) => {
return await request.post({
url: `/system/robot/task/checkHaveTask`,
data
})
}

46
src/api/map/mapTask.ts Normal file
View File

@ -0,0 +1,46 @@
import request from '@/config/axios'
//获取取货位置
export const getLocationByName = (data) => {
return request.post({ url: '/system/ware/house-location/getLocationByName', data })
}
//获得任务号
export const getTaskNo = async (id: number) => {
return await request.get({ url: `/system/robot/task/getTaskNo?id=` + id })
}
// 查询能正常使用的车辆
export const getCanUseRobot = () => {
return request.post({ url: '/system/robot/information/getAllRobot' })
}
// 创建机器人任务主表
export const createTask = (data) => {
return request.post({ url: '/system/robot/task/create', data })
}
// 删除机器人任务主表
export const deleteTask = (id: number) => {
return request.delete({ url: '/system/robot/task/delete?id=' + id })
}
// 更新机器人任务主表
export const updateTask = (data) => {
return request.post({ url: '/system/robot/task-detail/manuallyCompleted?id=' + data.id })
}
// 更新机器人任务主表
export const closeTask = (data) => {
return request.put({ url: '/system/robot/task/close', data })
}
//更新优先级
export const updateRobotTask = (data) => {
return request.put({ url: '/system/robot/task/update', data })
}
//获得机器人任务主表分页
export const getTaskPageList = async (data) => {
return await request.post({ url: `/system/robot/task/page`, data })
}

21
src/api/map/statistics.ts Normal file
View File

@ -0,0 +1,21 @@
import request from '@/config/axios'
//统计车辆状态分类
export const robotStatusClassification = async (params) => {
return await request.get({ url: `/system/statistics/robotStatusClassification`, params })
}
//统计任务人工完成-自动完成
export const robotTaskAutomaticArtificial = async (params) => {
return await request.get({ url: `/system/statistics/robotTaskAutomaticArtificial`, params })
}
//统计故障根因分析
export const robotWarnMsgClassification = async (params) => {
return await request.get({ url: `/system/statistics/robotWarnMsgClassification`, params })
}
//车辆工作时长统计
export const robotWorkHourStatistics = async (params) => {
return await request.get({ url: `/system/statistics/robotWorkHourStatistics`, params })
}

View File

@ -0,0 +1,21 @@
import request from '@/config/axios'
//获得通用配置分页 固定参数 configType 1
export const getCommonConfig = async (params) => {
return await request.get({ url: `/system/common/config/get`, params })
}
//更新通用配置 固定参数 configType 1
export const updateCommonConfig = async (data) => {
return await request.put({ url: `/system/common/config/update`, data })
}
//创建通用配置 固定参数 configType 1
export const createCommonConfig = async (data) => {
return await request.post({ url: `/system/common/config/create`, data })
}

View File

@ -47,3 +47,9 @@ export const getUnreadNotifyMessageList = async () => {
export const getUnreadNotifyMessageCount = async () => {
return await request.get({ url: '/system/notify-message/get-unread-count' })
}
// 获得当前用户的未读站内信数量 车辆异常
export const warnMsgReadPage = async () => {
return await request.get({ url: '/system/robot/warn-msg/readPage ' })
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

BIN
src/assets/imgs/chache.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
src/assets/imgs/gaojing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
src/assets/imgs/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src/assets/login-bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

BIN
src/assets/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -11,7 +11,7 @@ const prefixCls = getPrefixCls('content-wrap')
defineProps({
title: propTypes.string.def(''),
message: propTypes.string.def(''),
bodyStyle: propTypes.object.def({ padding: '10px' })
bodyStyle: propTypes.object.def({ padding: '16px' })
})
</script>

View File

@ -18,7 +18,7 @@
</el-select>
</ElDialog>
<div v-else class="custom-hover" @click.stop="showTopSearch = !showTopSearch">
<Icon icon="ep:search" />
<Icon icon="ep:search" color="var(--top-header-text-color)" />
<el-select
@click.stop
filterable

View File

@ -1,5 +1,6 @@
import UploadImg from './src/UploadImg.vue'
import UploadImgs from './src/UploadImgs.vue'
import UploadFile from './src/UploadFile.vue'
import UploadFileNew from './src/UploadFileNew.vue'
export { UploadImg, UploadImgs, UploadFile }
export { UploadImg, UploadImgs, UploadFile ,UploadFileNew}

View File

@ -0,0 +1,271 @@
<template>
<div class="upload-box">
<el-upload
:id="uuid"
:accept="fileType.join(',')"
:action="uploadUrl"
:before-upload="beforeUpload"
:class="['upload', drag ? 'no-border' : '']"
:disabled="disabled"
:drag="drag"
:http-request="httpRequest"
:multiple="false"
:on-error="uploadError"
:on-success="uploadSuccess"
:show-file-list="false"
>
<template v-if="modelValue">
<img :src="modelValue" class="upload-image" />
<div class="upload-handle" @click.stop>
<div v-if="!disabled" class="handle-icon" @click="editImg">
<Icon icon="ep:edit" />
<span v-if="showBtnText">{{ t('action.edit') }}</span>
</div>
<div class="handle-icon" @click="imagePreview(modelValue)">
<Icon icon="ep:zoom-in" />
<span v-if="showBtnText">{{ t('action.detail') }}</span>
</div>
<div v-if="showDelete && !disabled" class="handle-icon" @click="deleteImg">
<Icon icon="ep:delete" />
<span v-if="showBtnText">{{ t('action.del') }}</span>
</div>
</div>
</template>
<template v-else>
<div class="upload-empty">
<slot name="empty">
<Icon icon="ep:plus" />
<!-- <span>请上传图片</span> -->
</slot>
</div>
</template>
</el-upload>
<div class="el-upload__tip">
<slot name="tip"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import type { UploadProps } from 'element-plus'
import { generateUUID } from '@/utils'
import { propTypes } from '@/utils/propTypes'
import { createImageViewer } from '@/components/ImageViewer'
import { useUpload } from '@/components/UploadFile/src/useUpload'
defineOptions({ name: 'UploadImg' })
type FileTypes =
| 'image/apng'
| 'image/bmp'
| 'image/gif'
| 'image/jpeg'
| 'image/pjpeg'
| 'image/png'
| 'image/svg+xml'
| 'image/tiff'
| 'image/webp'
| 'image/x-icon'
//
const props = defineProps({
modelValue: propTypes.string.def(''),
drag: propTypes.bool.def(true), // ==> true
disabled: propTypes.bool.def(false), // ==> false
fileSize: propTypes.number.def(5), // ==> 5M
fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // ==> ["image/jpeg", "image/png", "image/gif"]
height: propTypes.string.def('150px'), // ==> 150px
width: propTypes.string.def('150px'), // ==> 150px
borderradius: propTypes.string.def('8px'), // ==> 8px
showDelete: propTypes.bool.def(true), //
showBtnText: propTypes.bool.def(true) //
})
const { t } = useI18n() //
const message = useMessage() //
// id
const uuid = ref('id-' + generateUUID())
//
const imagePreview = (imgUrl: string) => {
createImageViewer({
zIndex: 9999999,
urlList: [imgUrl]
})
}
const emit = defineEmits(['update:modelValue'])
const deleteImg = () => {
emit('update:modelValue', '')
}
const { uploadUrl, httpRequest } = useUpload()
const editImg = () => {
const dom = document.querySelector(`#${uuid.value} .el-upload__input`)
dom && dom.dispatchEvent(new MouseEvent('click'))
}
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
const imgType = props.fileType
if (!imgType.includes(rawFile.type as FileTypes))
message.notifyWarning('上传图片不符合所需的格式!')
if (!imgSize) message.notifyWarning(`上传图片大小不能超过 ${props.fileSize}M`)
return imgType.includes(rawFile.type as FileTypes) && imgSize
}
//
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
message.success('上传成功')
emit('update:modelValue', res.data)
}
//
const uploadError = () => {
message.notifyError('图片上传失败,请您重新上传!')
}
</script>
<style lang="scss" scoped>
.is-error {
.upload {
:deep(.el-upload),
:deep(.el-upload-dragger) {
border: 1px dashed var(--el-color-danger) !important;
&:hover {
border-color: var(--el-color-primary) !important;
}
}
}
}
:deep(.disabled) {
.el-upload,
.el-upload-dragger {
cursor: not-allowed !important;
background: var(--el-disabled-bg-color);
border: 1px dashed var(--el-border-color-darker) !important;
&:hover {
border: 1px dashed var(--el-border-color-darker) !important;
}
}
}
.upload-box {
.no-border {
:deep(.el-upload) {
border: none !important;
}
}
:deep(.upload) {
.el-upload {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: v-bind(width);
height: v-bind(height);
overflow: hidden;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
transition: var(--el-transition-duration-fast);
&:hover {
border-color: var(--el-color-primary);
.upload-handle {
opacity: 1;
}
}
.el-upload-dragger {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
padding: 0;
overflow: hidden;
background-color: transparent;
border: 1px dashed var(--el-border-color-darker);
border-radius: v-bind(borderradius);
&:hover {
border: 1px dashed var(--el-color-primary);
}
}
.el-upload-dragger.is-dragover {
background-color: var(--el-color-primary-light-9);
border: 2px dashed var(--el-color-primary) !important;
}
.upload-image {
width: 100%;
height: 100%;
object-fit: contain;
}
.upload-empty {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 12px;
line-height: 30px;
color: var(--el-color-info);
.el-icon {
font-size: 28px;
color: var(--el-text-color-secondary);
}
}
.upload-handle {
position: absolute;
top: 0;
right: 0;
display: flex;
width: 100%;
height: 100%;
cursor: pointer;
background: rgb(0 0 0 / 60%);
opacity: 0;
box-sizing: border-box;
transition: var(--el-transition-duration-fast);
align-items: center;
justify-content: center;
.handle-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 6%;
color: aliceblue;
.el-icon {
margin-bottom: 40%;
font-size: 130%;
line-height: 130%;
}
span {
font-size: 85%;
line-height: 85%;
}
}
}
}
}
.el-upload__tip {
line-height: 18px;
text-align: center;
}
}
</style>

View File

@ -7,8 +7,10 @@ import axios from 'axios'
* URL
*/
export const getUploadUrl = (): string => {
// return import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/infra/file/upload'
return import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/infra/file/upload'
}
export const useUpload = () => {
// 后端上传地址

View File

@ -0,0 +1,76 @@
@charset "UTF-8";
/* 改变主题色变量 */
/* 改变 icon 字体路径变量,必需 */
@use '~element-ui/packages/theme-chalk/src/index';
.el-table td,
.el-table th {
color: #333;
}
.el-drawer__header {
padding: 16px 16px 8px 16px;
margin: 0;
line-height: 24px;
font-size: 18px;
color: #303133;
box-sizing: border-box;
border-bottom: 1px solid #e8e8e8;
}
div[class^='el-drawer']:focus,
span:focus {
outline: none;
}
.el-drawer__body {
box-sizing: border-box;
padding: 16px;
width: 100%;
overflow-y: auto;
}
.el-dialog {
margin-top: 50vh !important;
transform: translateY(-50%);
overflow: hidden;
}
.el-dialog__wrapper {
overflow: hidden;
max-height: 100vh;
}
.el-dialog__header {
padding: 16px 16px 8px 16px;
box-sizing: border-box;
border-bottom: 1px solid #e8e8e8;
}
.el-dialog__body {
padding: 16px;
max-height: 80vh;
box-sizing: border-box;
overflow-y: auto;
}
.el-dialog__footer {
padding: 16px;
box-sizing: border-box;
border-top: 1px solid #e8e8e8;
}
.el-dialog__close {
font-weight: 600;
}
.el-select {
width: 100%;
}
.el-divider:not(.el-divider--horizontal) {
margin: 0 8px;
}
.el-divider.el-divider--horizontal {
margin: 16px 0;
}

View File

@ -0,0 +1 @@
@use '~element-ui/packages/theme-chalk/src/index';.el-table td,.el-table th{color:#333}.el-drawer__header{padding:16px 16px 8px 16px;margin:0;line-height:24px;font-size:18px;color:#303133;box-sizing:border-box;border-bottom:1px solid #e8e8e8}div[class^='el-drawer']:focus,span:focus{outline:none}.el-drawer__body{box-sizing:border-box;padding:16px;width:100%;overflow-y:auto}.el-dialog{margin-top:50vh !important;transform:translateY(-50%);overflow:hidden}.el-dialog__wrapper{overflow:hidden;max-height:100vh}.el-dialog__header{padding:16px 16px 8px 16px;box-sizing:border-box;border-bottom:1px solid #e8e8e8}.el-dialog__body{padding:16px;max-height:80vh;box-sizing:border-box;overflow-y:auto}.el-dialog__footer{padding:16px;box-sizing:border-box;border-top:1px solid #e8e8e8}.el-dialog__close{font-weight:600}.el-select{width:100%}.el-divider:not(.el-divider--horizontal){margin:0 8px}.el-divider.el-divider--horizontal{margin:16px 0}

View File

@ -5,6 +5,7 @@ import qs from 'qs'
import { config } from '@/config/axios/config'
import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
import errorCode from './errorCode'
import JSONBigInt from 'json-bigint'
import { resetRouter } from '@/router'
import { deleteUserCache } from '@/hooks/web/useCache'
@ -36,6 +37,16 @@ const service: AxiosInstance = axios.create({
paramsSerializer: (params) => {
return qs.stringify(params, { allowDots: true })
}
// transformResponse: [
// (data) => {
// try {
// // 使用 json-bigint 解析,大数字会转为字符串
// return JSONBigInt.parse(data)
// } catch (e) {
// return data
// }
// }
// ]
})
// request拦截器
@ -220,4 +231,5 @@ const handleAuthorized = () => {
}
return Promise.reject(t('sys.api.timeoutMessage'))
}
export { service }

View File

@ -59,7 +59,7 @@ export default defineComponent({
<Backtop></Backtop>
<Setting></Setting>
{/* <Setting></Setting> */}
</section>
)
}

View File

@ -21,6 +21,8 @@ const getCaches = computed((): string[] => {
const tagsView = computed(() => appStore.getTagsView)
const { currentRoute } = useRouter() //
//region
const routerAlive = ref(true)
//
@ -35,6 +37,27 @@ provide('reload', reload)
<template>
<section
v-if="
currentRoute.name === 'editMapPageRealTimeMap' || currentRoute.name === 'MapPageRealTimeMap'
"
:class="[
'w-full bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]',
{
'!min-h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] pb-0':
footer
}
]"
>
<router-view v-if="routerAlive">
<template #default="{ Component, route }">
<keep-alive :include="getCaches">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</template>
</router-view>
</section>
<section
v-else
:class="[
'p-[var(--app-content-padding)] w-full bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]',
{

View File

@ -57,7 +57,7 @@ watch(
</script>
<template>
<div>
<div :style="{ 'background-color': appStore.getTheme.topHeaderBgColor }">
<router-link
:class="[
prefixCls,
@ -80,6 +80,7 @@ watch(
layout === 'topLeft' || layout === 'top' || layout === 'cutMenu'
}
]"
style="font-size: 13px"
>
{{ title }}
</div>

View File

@ -171,7 +171,8 @@ $prefix-cls: #{$namespace}-menu;
.#{$elNamespace}-menu {
.#{$elNamespace}-sub-menu__title,
.#{$elNamespace}-menu-item:not(.is-active) {
background-color: var(--left-menu-bg-light-color) !important;
// background-color: var(--left-menu-bg-light-color) !important;
background-color: #ffffff !important;
}
}
}

View File

@ -13,22 +13,30 @@ const list = ref<any[]>([]) // 消息列表
//
const getList = async () => {
list.value = await NotifyMessageApi.getUnreadNotifyMessageList()
// list.value = await NotifyMessageApi.getUnreadNotifyMessageList()
list.value = await NotifyMessageApi.warnMsgReadPage()
console.log(list.value)
// unreadCount 0
unreadCount.value = 0
}
//
const getUnreadCount = async () => {
NotifyMessageApi.getUnreadNotifyMessageCount().then((data) => {
unreadCount.value = data
// NotifyMessageApi.getUnreadNotifyMessageCount().then((data) => {
// unreadCount.value = data
// })
NotifyMessageApi.warnMsgReadPage().then((data) => {
// console.log(data)
unreadCount.value = data && data.length ? data.length : 0
})
}
//
const popoverRef = ref()
const goMyList = () => {
popoverRef.value.hide()
push({
name: 'MyNotifyMessage'
name: 'SystemCarError'
})
}
@ -45,16 +53,22 @@ onMounted(() => {
unreadCount.value = 0
}
},
1000 * 60 * 2
1000 * 60 * 1
)
})
</script>
<template>
<div class="message">
<ElPopover :width="400" placement="bottom" trigger="click">
<ElPopover ref="popoverRef" :width="400" placement="bottom" trigger="click">
<template #reference>
<ElBadge :is-dot="unreadCount > 0" class="item">
<Icon :size="18" class="cursor-pointer" icon="ep:bell" @click="getList" />
<Icon
:size="18"
class="cursor-pointer"
icon="ep:bell"
@click="getList"
color="var(--top-header-text-color)"
/>
</ElBadge>
</template>
<ElTabs v-model="activeName">
@ -62,10 +76,12 @@ onMounted(() => {
<el-scrollbar class="message-list">
<template v-for="item in list" :key="item.id">
<div class="message-item">
<img alt="" class="message-icon" src="@/assets/imgs/avatar.gif" />
<!-- <img alt="" class="message-icon" src="@/assets/imgs/avatar.gif" /> -->
<div class="message-content">
<!-- <div style="margin-bottom: 5px;">异常等级{{ item.warnLevel }}</div> -->
<span class="message-title">
{{ item.templateNickname }}{{ item.templateContent }}
{{ item.warnMsg }}
</span>
<span class="message-date">
{{ formatDate(item.createTime) }}

View File

@ -297,6 +297,6 @@ $prefix-cls: #{$namespace}-setting;
.#{$prefix-cls} {
border-radius: 6px 0 0 6px;
z-index: 1200;/*修正没有z-index会被表格层覆盖,值不要超过4000*/
z-index: 1200; /*修正没有z-index会被表格层覆盖,值不要超过4000*/
}
</style>

View File

@ -1,6 +1,6 @@
<script lang="tsx">
import { defineComponent, computed } from 'vue'
import { Message } from '@/layout/components//Message'
import { Message } from '@/layout/components/Message'
import { Collapse } from '@/layout/components/Collapse'
import { UserInfo } from '@/layout/components/UserInfo'
import { Screenfull } from '@/layout/components/Screenfull'
@ -52,6 +52,7 @@ export default defineComponent({
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between',
'dark:bg-[var(--el-bg-color)]'
]}
style="height:51px"
>
{layout.value !== 'top' ? (
<div class="h-full flex items-center">

View File

@ -68,10 +68,10 @@ const toDocument = () => {
<Icon icon="ep:tools" />
<div @click="toProfile">{{ t('common.profile') }}</div>
</ElDropdownItem>
<ElDropdownItem>
<!-- <ElDropdownItem>
<Icon icon="ep:menu" />
<div @click="toDocument">{{ t('common.document') }}</div>
</ElDropdownItem>
</ElDropdownItem> -->
<ElDropdownItem divided>
<Icon icon="ep:lock" />
<div @click="lockScreen">{{ t('lock.lockScreen') }}</div>

View File

@ -55,7 +55,8 @@ export const useRenderLayout = () => {
'w-[var(--left-menu-max-width)]': !appStore.getCollapse
}
]}
style="transition: all var(--transition-time-02);"
style="transition: all var(--transition-time-02);height:50px;display: flex;
align-items: center;"
></Logo>
) : undefined}
<Menu class={[{ '!h-[calc(100%-var(--logo-height))]': logo.value }]}></Menu>
@ -106,9 +107,9 @@ export const useRenderLayout = () => {
]}
></ToolHeader>
{tagsView.value ? (
{/* {tagsView.value ? (
<TagsView class="layout-border__top layout-border__bottom"></TagsView>
) : undefined}
) : undefined} */}
</div>
<AppView></AppView>

View File

@ -41,11 +41,16 @@ import '@/plugins/tongji' // 百度统计
import Logger from '@/utils/Logger'
import VueDOMPurifyHTML from 'vue-dompurify-html' // 解决v-html 的安全隐患
import VueDragResizeRotate from '@gausszhou/vue3-drag-resize-rotate'
import '@gausszhou/vue3-drag-resize-rotate/lib/bundle.esm.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { vDrag } from './utils/drag'
// 创建实例
const setupAll = async () => {
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
await setupI18n(app)
setupStore(app)
@ -63,9 +68,10 @@ const setupAll = async () => {
setupMountedFocus(app)
await router.isReady()
// 注册全局指令
app.directive('drag', vDrag)
app.use(VueDOMPurifyHTML)
app.use(VueDragResizeRotate)
app.mount('#app')
}

View File

@ -59,10 +59,10 @@ const remainingRouter: AppRouteRecordRaw[] = [
children: [
{
path: 'index',
component: () => import('@/views/Home/Index.vue'),
name: 'Index',
component: () => import('@/views/mapPage/realTimeMap/index.vue'),
name: 'MapPageRealTimeMap',
meta: {
title: t('router.home'),
title: '实时地图',
icon: 'ep:home-filled',
noCache: false,
affix: true
@ -70,6 +70,62 @@ const remainingRouter: AppRouteRecordRaw[] = [
}
]
},
// {
// path: '/',
// component: Layout,
// redirect: '/index',
// name: 'Home',
// meta: {},
// children: [
// {
// path: 'index',
// component: () => import('@/views/Home/Index.vue'),
// name: 'Index',
// meta: {
// title: t('router.home'),
// icon: 'ep:home-filled',
// noCache: false,
// affix: true
// }
// }
// ]
// },
//地图
{
path: '/warehouse/map',
component: Layout,
name: 'warehouseMap',
meta: {
hidden: true
},
children: [
{
path: 'edit',
component: () => import('@/views/mapPage/realTimeMap/editMap.vue'),
name: 'editMapPageRealTimeMap',
meta: {
noCache: true, // 需要缓存
hidden: true,
canTo: true,
icon: 'ep:edit',
title: '地图编辑'
}
},
{
path: 'test',
component: () => import('@/views/mapPage/realTimeMap/test.vue'),
name: 'testMapPageRealTimeMap',
meta: {
noCache: true, // 需要缓存
hidden: true,
canTo: true,
icon: 'ep:edit',
title: '测试'
}
}
]
},
{
path: '/user',
component: Layout,

View File

@ -47,7 +47,6 @@ export const useAppStore = defineStore('app', {
mobile: false, // 是否是移动端
title: import.meta.env.VITE_APP_TITLE, // 标题
pageLoading: false, // 路由跳转loading
breadcrumb: true, // 面包屑
breadcrumbIcon: true, // 面包屑图标
collapse: false, // 折叠菜单
@ -56,49 +55,49 @@ export const useAppStore = defineStore('app', {
screenfull: true, // 全屏图标
search: true, // 搜索图标
size: true, // 尺寸图标
locale: true, // 多语言图标
locale: false, // 多语言图标
message: true, // 消息图标
tagsView: true, // 标签页
tagsView: false, // 标签页
tagsViewImmerse: false, // 标签页沉浸
tagsViewIcon: true, // 是否显示标签图标
logo: true, // logo
fixedHeader: true, // 固定toolheader
footer: true, // 显示页脚
footer: false, // 显示页脚
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
fixedMenu: wsCache.get('fixedMenu') || false, // 是否固定菜单
layout: wsCache.get(CACHE_KEY.LAYOUT) || 'classic', // layout布局
isDark: wsCache.get(CACHE_KEY.IS_DARK) || false, // 是否是暗黑模式
// isDark: wsCache.get(CACHE_KEY.IS_DARK) || false, // 是否是暗黑模式
isDark: false, // 是否是暗黑模式
currentSize: wsCache.get('default') || 'default', // 组件尺寸
theme: wsCache.get(CACHE_KEY.THEME) || {
// 主题色
elColorPrimary: '#409eff',
elColorPrimary: '#00329F',
// 左侧菜单边框颜色
leftMenuBorderColor: 'inherit',
// 左侧菜单背景颜色
leftMenuBgColor: '#001529',
leftMenuBgColor: '#ffffff',
// 左侧菜单浅色背景颜色
leftMenuBgLightColor: '#0f2438',
// 左侧菜单选中背景颜色
leftMenuBgActiveColor: 'var(--el-color-primary)',
leftMenuBgActiveColor: '#EBF1FF',
// 左侧菜单收起选中背景颜色
leftMenuCollapseBgActiveColor: 'var(--el-color-primary)',
leftMenuCollapseBgActiveColor: '#EBF1FF',
// 左侧菜单字体颜色
leftMenuTextColor: '#bfcbd9',
leftMenuTextColor: '#98A4BF',
// 左侧菜单选中字体颜色
leftMenuTextActiveColor: '#fff',
leftMenuTextActiveColor: '#00329F',
// logo字体颜色
logoTitleTextColor: '#fff',
// logo边框颜色
logoBorderColor: 'inherit',
// 头部背景颜色
topHeaderBgColor: '#fff',
topHeaderBgColor: '#00329F',
// 头部字体颜色
topHeaderTextColor: 'inherit',
topHeaderTextColor: '#ffffff',
// 头部悬停颜色
topHeaderHoverColor: '#f6f6f6',
topHeaderHoverColor: '#215bd8',
// 头部边框颜色
topToolBorderColor: '#eee'
topToolBorderColor: '#E2E7F5'
}
}
},

View File

@ -0,0 +1,19 @@
@font-face {
font-family: "fc-icon";
src: url("@/styles/FormCreate/fonts/fontello.woff") format("woff");
}
.icon-doc-text:before {
content: "\f0f6";
}
.icon-server:before {
content: "\f233";
}
.icon-address-card-o:before {
content: "\f2bc";
}
.icon-user-o:before {
content: "\f2c0";
}/*# sourceMappingURL=index.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sources":["index.scss","index.css"],"names":[],"mappings":"AAEA;EACE,sBAAA;EACA,kEAAA;ACDF;ADIA;EACE,gBAAA;ACFF;;ADKA;EACE,gBAAA;ACFF;;ADKA;EACE,gBAAA;ACFF;;ADKA;EACE,gBAAA;ACFF","file":"index.css"}

View File

@ -1,13 +1,15 @@
:root {
--el-color-primary: #00329f;
--login-bg-color: #293146;
--left-menu-max-width: 200px;
--left-menu-min-width: 64px;
--left-menu-bg-color: #001529;
--left-menu-bg-color: #ffffff;
--left-menu-bg-light-color: #0f2438;
--left-menu-bg-light-color: #ffffff;
--left-menu-bg-active-color: var(--el-color-primary);
@ -19,7 +21,7 @@
/* left menu end */
/* logo start */
--logo-height: 50px;
--logo-height: 40px;
--logo-title-text-color: #fff;
/* logo end */
@ -29,13 +31,15 @@
--top-header-text-color: 'inherit';
--top-header-hover-color: #f6f6f6;
--top-header-hover-color: #215bd8;
--top-tool-height: var(--logo-height);
/* --top-tool-height: var(--logo-height); */
--top-tool-height: 50px;
--top-tool-p-x: 0;
--tags-view-height: 35px;
/* --tags-view-height: 35px; 开启面包屑时 */
--tags-view-height: 0px;
/* header start */
/* tab menu start */

View File

@ -239,5 +239,10 @@ export enum DICT_TYPE {
IOT_PRODUCT_FUNCTION_TYPE = 'iot_product_function_type', // IOT 产品功能类型
IOT_DATA_TYPE = 'iot_data_type', // IOT 数据类型
IOT_UNIT_TYPE = 'iot_unit_type', // IOT 单位类型
IOT_RW_TYPE = 'iot_rw_type' // IOT 读写类型
IOT_RW_TYPE = 'iot_rw_type', // IOT 读写类型
// ========== wcs 地图 ==========
ROBOT_TASK_STATUS = 'robot_task_status', //机器人的任务状态
ROBOT_QUEST_PHASES = 'robot_quest_phases', //机器人的任务阶段
DEVICE_TYPE = 'device_type'
}

81
src/utils/drag.ts Normal file
View File

@ -0,0 +1,81 @@
// directives.js
export const vDrag = {
mounted(el, binding) {
const enableDrag = binding.value; // 获取指令绑定的值
// if (!enableDrag) return; // 如果为 false则不执行后续拖拽逻辑
el.style.position = 'absolute';
// 记录元素的初始位置
const initialTop = el.offsetTop;
const initialLeft = el.offsetLeft;
let startX, startY, initialMouseX, initialMouseY;
const mousemove = (e) => {
const dx = e.clientX - initialMouseX;
const dy = e.clientY - initialMouseY;
el.style.top = `${startY + dy}px`;
el.style.left = `${startX + dx}px`;
};
const mouseup = () => {
document.removeEventListener('mousemove', mousemove);
document.removeEventListener('mouseup', mouseup);
};
const mousedown = (e) => {
startX = el.offsetLeft;
startY = el.offsetTop;
initialMouseX = e.clientX;
initialMouseY = e.clientY;
document.addEventListener('mousemove', mousemove);
document.addEventListener('mouseup', mouseup);
e.preventDefault();
};
el.addEventListener('mousedown', mousedown);
// 保存 mousedown 事件处理函数,以便在 updated 中使用
el.__vDragMousedown = mousedown;
// 保存初始位置,以便后续还原
el.__vDragInitialTop = initialTop;
el.__vDragInitialLeft = initialLeft;
if(!enableDrag){
// 如果之前启用,现在禁用,移除 mousedown 事件监听器
el.removeEventListener('mousedown', el.__vDragMousedown);
// 确保在禁用时停止正在进行的拖拽
document.removeEventListener('mousemove', el.__vDragMousemove);
document.removeEventListener('mouseup', el.__vDragMouseup);
}
},
updated(el, binding) {
// console.log('会走这边吗');
const enableDrag = binding.value;
const prevEnableDrag = binding.oldValue;
if (enableDrag && !prevEnableDrag) {
// 如果之前禁用,现在启用,添加 mousedown 事件监听器
el.addEventListener('mousedown', el.__vDragMousedown);
} else if (!enableDrag && prevEnableDrag) {
// 如果之前启用,现在禁用,移除 mousedown 事件监听器
el.removeEventListener('mousedown', el.__vDragMousedown);
// 确保在禁用时停止正在进行的拖拽
document.removeEventListener('mousemove', el.__vDragMousemove);
document.removeEventListener('mouseup', el.__vDragMouseup);
}
},
beforeUnmount(el) {
// 在元素卸载前移除 mousedown 事件监听器
if (el.__vDragMousedown) {
el.removeEventListener('mousedown', el.__vDragMousedown);
}
}
};
// 定义一个还原位置的函数
export const resetDragPosition = (el) => {
console.log(el);
if (el.__vDragInitialTop!== undefined && el.__vDragInitialLeft!== undefined) {
el.style.top = `${el.__vDragInitialTop}px`;
el.style.left = `${el.__vDragInitialLeft}px`;
}
};

View File

@ -1,19 +1,19 @@
<template>
<div
:class="prefixCls"
class="relative h-[100%] lt-md:px-10px lt-sm:px-10px lt-xl:px-10px lt-xl:px-10px"
class="relative h-[100%] lt-md:px-10px lt-sm:px-10px lt-xl:px-10px lt-xl:px-10px login-page"
>
<div class="relative mx-auto h-full flex">
<div
:class="`${prefixCls}__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px lt-xl:hidden overflow-x-hidden overflow-y-auto`"
:class="`${prefixCls}__left flex-1 bg-opacity-20 relative p-30px lt-xl:hidden overflow-x-hidden overflow-y-auto`"
>
<!-- 左上角的 logo + 系统标题 -->
<div class="relative flex items-center text-white">
<!-- <div class="relative flex items-center text-white">
<img alt="" class="mr-10px h-48px w-48px" src="@/assets/imgs/logo.png" />
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
</div>
</div> -->
<!-- 左边的背景图 + 欢迎语 -->
<div class="h-[calc(100%-60px)] flex items-center justify-center">
<!-- <div class="h-[calc(100%-60px)] flex items-center justify-center">
<TransitionGroup
appear
enter-active-class="animate__animated animate__bounceInLeft"
@ -25,7 +25,7 @@
{{ t('login.message') }}
</div>
</TransitionGroup>
</div>
</div> -->
</div>
<div
class="relative flex-1 p-30px dark:bg-[var(--login-bg-color)] lt-sm:p-10px overflow-x-hidden overflow-y-auto"
@ -33,15 +33,15 @@
<!-- 右上角的主题语言选择 -->
<div
class="flex items-center justify-between at-2xl:justify-end at-xl:justify-end"
style="color: var(--el-text-color-primary);"
style="color: var(--el-text-color-primary)"
>
<div class="flex items-center at-2xl:hidden at-xl:hidden">
<img alt="" class="mr-10px h-48px w-48px" src="@/assets/imgs/logo.png" />
<span class="text-20px font-bold" >{{ underlineToHump(appStore.getTitle) }}</span>
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
</div>
<div class="flex items-center justify-end space-x-10px h-48px">
<ThemeSwitch />
<LocaleDropdown />
<!-- <LocaleDropdown /> -->
</div>
</div>
<!-- 右边的登录界面 -->
@ -106,7 +106,7 @@ $prefix-cls: #{$namespace}-login;
}
</style>
<style lang="scss">
<style lang="scss" scoped>
.dark .login-form {
.el-divider__text {
background-color: var(--login-bg-color);
@ -116,4 +116,16 @@ $prefix-cls: #{$namespace}-login;
background-color: var(--login-bg-color);
}
}
</style>
.login-page {
background-image: url('@/assets/login-bg.png');
/* 让背景图片覆盖整个元素 */
background-size: cover;
/* 让背景图片居中显示 */
background-position: center;
/* 禁止背景图片重复 */
background-repeat: no-repeat;
/* 设置元素的宽度和高度为视口的宽度和高度 */
width: 100vw;
height: 100vh;
}
</style>

View File

@ -4,85 +4,88 @@
ref="formLogin"
:model="loginData.loginForm"
:rules="LoginRules"
class="login-form"
label-position="top"
label-width="120px"
size="large"
>
<el-row style="margin-right: -10px; margin-left: -10px">
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<el-row>
<el-col :span="24">
<el-form-item>
<LoginFormTitle style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantName">
<el-input
v-model="loginData.loginForm.tenantName"
:placeholder="t('login.tenantNamePlaceholder')"
:prefix-icon="iconHouse"
link
type="primary"
/>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<el-form-item prop="username">
<el-input
v-model="loginData.loginForm.username"
:placeholder="t('login.usernamePlaceholder')"
:prefix-icon="iconAvatar"
/>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<el-form-item prop="password">
<el-input
v-model="loginData.loginForm.password"
:placeholder="t('login.passwordPlaceholder')"
:prefix-icon="iconLock"
show-password
type="password"
@keyup.enter="getCode()"
/>
</el-form-item>
</el-col>
<el-col
:span="24"
style="padding-right: 10px; padding-left: 10px; margin-top: -20px; margin-bottom: -20px"
>
<el-form-item>
<el-row justify="space-between" style="width: 100%">
<el-col :span="6">
<el-checkbox v-model="loginData.loginForm.rememberMe">
{{ t('login.remember') }}
</el-checkbox>
</el-col>
<el-col :offset="6" :span="12">
<el-link style="float: right" type="primary">{{ t('login.forgetPassword') }}</el-link>
</el-col>
</el-row>
</el-form-item>
</el-col>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<el-form-item>
<XButton
:loading="loginLoading"
:title="t('login.login')"
class="w-[100%]"
type="primary"
@click="getCode()"
/>
</el-form-item>
</el-col>
<Verify
ref="verify"
:captchaType="captchaType"
:imgSize="{ width: '400px', height: '200px' }"
mode="pop"
@success="handleLogin"
/>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<div class="login-form">
<div class="login-tip">欢迎登录</div>
<el-col :span="24">
<el-form-item v-if="loginData.tenantEnable === 'true'">
<el-input
:disabled="true"
placeholder="中鼐智能"
:prefix-icon="iconHouse"
type="primary"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="username">
<el-input
v-model="loginData.loginForm.username"
:placeholder="t('login.usernamePlaceholder')"
:prefix-icon="iconAvatar"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="password">
<el-input
v-model="loginData.loginForm.password"
:placeholder="t('login.passwordPlaceholder')"
:prefix-icon="iconLock"
show-password
type="password"
@keyup.enter="getCode()"
/>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-top: -10px; margin-bottom: 20px">
<el-form-item>
<el-row justify="space-between" style="width: 100%">
<el-col :span="6">
<el-checkbox v-model="loginData.loginForm.rememberMe">
{{ t('login.remember') }}
</el-checkbox>
</el-col>
<!--
忘记密码
<el-col :offset="6" :span="12">
<el-link style="float: right" type="primary">{{
t('login.forgetPassword')
}}</el-link>
</el-col> -->
</el-row>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item>
<XButton
:loading="loginLoading"
:title="t('login.login')"
class="w-[100%]"
type="primary"
@click="getCode()"
/>
</el-form-item>
</el-col>
<Verify
ref="verify"
:captchaType="captchaType"
:imgSize="{ width: '400px', height: '200px' }"
mode="pop"
@success="handleLogin"
/>
</div>
<!--
<el-col :span="24" >
<el-form-item>
<el-row :gutter="5" justify="space-between" style="width: 100%">
<el-col :span="8">
@ -109,8 +112,8 @@
</el-row>
</el-form-item>
</el-col>
<el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider>
<el-col :span="24" >
<el-form-item>
<div class="w-[100%] flex justify-between">
<Icon
@ -126,7 +129,7 @@
</el-form-item>
</el-col>
<el-divider content-position="center">萌新必读</el-divider>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<el-col :span="24" >
<el-form-item>
<div class="w-[100%] flex justify-between">
<el-link href="https://doc.iocoder.cn/" target="_blank">📚开发指南</el-link>
@ -139,7 +142,7 @@
</el-link>
</div>
</el-form-item>
</el-col>
</el-col> -->
</el-row>
</el-form>
</template>
@ -352,4 +355,25 @@ onMounted(() => {
cursor: pointer;
}
}
.login-form {
box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px;
width: 100%;
background-color: #ffffff;
padding: 40px 42px 32px 42px;
margin-top: 20px;
.login-tip {
margin-bottom: 28px;
font-family:
PingFangSC,
PingFang SC;
font-weight: 600;
font-size: 18px;
color: #0d162a;
line-height: 22px;
text-align: left;
font-style: normal;
}
}
</style>

View File

@ -1,6 +1,7 @@
<template>
<h2 class="enter-x mb-3 text-center text-2xl font-bold xl:text-center xl:text-3xl">
{{ getFormTitle }}
<h2 class="form-title">
<!-- {{ getFormTitle }} -->
RCS智能设备调度系统
</h2>
</template>
<script lang="ts" setup>
@ -24,3 +25,11 @@ const getFormTitle = computed(() => {
return titleObj[unref(getLoginState)]
})
</script>
<style scoped lang="scss">
.form-title {
color: #34335b;
font-size: 44px;
line-height: 62px;
text-align: center;
}
</style>

View File

@ -133,7 +133,7 @@ const loginData = reactive({
},
loginForm: {
uuid: '',
tenantName: '芋道源码',
tenantName: '中鼐科技',
mobileNumber: '',
code: ''
}

View File

@ -22,9 +22,9 @@
<el-tab-pane :label="t('profile.info.resetPwd')" name="resetPwd">
<ResetPwd />
</el-tab-pane>
<el-tab-pane :label="t('profile.info.userSocial')" name="userSocial">
<!-- <el-tab-pane :label="t('profile.info.userSocial')" name="userSocial">
<UserSocial v-model:activeName="activeName" />
</el-tab-pane>
</el-tab-pane> -->
</el-tabs>
</div>
</el-card>

View File

@ -3,7 +3,7 @@
<div class="chat-empty">
<!-- title -->
<div class="center-container">
<div class="title">芋道 AI</div>
<div class="title">中鼐 AI</div>
<div class="role-list">
<div
class="role-item"

Some files were not shown because too many files have changed in this diff Show More