From 97dc93f3aa660842a60045d582917acc48ccbdca Mon Sep 17 00:00:00 2001 From: mocheng <3057647414@qq.com> Date: Sat, 16 Aug 2025 17:58:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=89=E9=98=B2=E5=A4=A7=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/package.json | 3 + apps/web-antd/src/api/cockpit/cockpit.ts | 48 + apps/web-antd/src/bootstrap.ts | 4 + apps/web-antd/src/layouts/basic.vue | 2 +- apps/web-antd/src/main.ts | 1 + apps/web-antd/src/router/routes/core.ts | 32 +- apps/web-antd/src/store/notify.ts | 49 +- .../src/views/cockpit/security/index.vue | 895 +++++++++++++++++- .../src/views/screen/security/index.vue | 32 +- apps/web-antd/vite.config.mts | 3 +- package.json | 3 +- .../widgets/user-dropdown/user-dropdown.vue | 5 +- packages/stores/src/modules/user.ts | 4 + playground/src/store/auth.ts | 2 +- 14 files changed, 1027 insertions(+), 56 deletions(-) diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json index 0007c442..499e5d14 100644 --- a/apps/web-antd/package.json +++ b/apps/web-antd/package.json @@ -27,6 +27,9 @@ }, "dependencies": { "@ant-design/icons-vue": "^7.0.1", + "@dataview/datav-vue3": "0.0.0-test.1672506674342", + "@jiaminghi/charts": "^0.2.18", + "@jiaminghi/data-view": "^2.10.0", "@tinymce/tinymce-vue": "^6.0.1", "@vben/access": "workspace:*", "@vben/common-ui": "workspace:*", diff --git a/apps/web-antd/src/api/cockpit/cockpit.ts b/apps/web-antd/src/api/cockpit/cockpit.ts index e69de29b..bad54c5a 100644 --- a/apps/web-antd/src/api/cockpit/cockpit.ts +++ b/apps/web-antd/src/api/cockpit/cockpit.ts @@ -0,0 +1,48 @@ + +import { requestClient } from '#/api/request'; + +/** + * 大屏接口 + */ + +/** + * 访客 + */ +export function visitir() { + return requestClient.get('/property/cockpit/visitor'); +} + +/** + *费用 + */ +export function expenses() { + return requestClient.get('/property/cockpit/expenses'); +} + +/** + * 物业人员配置 + */ +export function propertyPerson() { + return requestClient.get('/property/cockpit/propertyperson'); +} + +/** + * sos报警 + */ +export function sos() { + return requestClient.get('/property/cockpit/sos'); +} + +/** + * sos报警记录 + */ +export function soslist() { + return requestClient.get('/property/cockpit/soslist'); +} + +/** + * 工单 + */ +export function workcount() { + return requestClient.get('/property/cockpit/workcount'); +} diff --git a/apps/web-antd/src/bootstrap.ts b/apps/web-antd/src/bootstrap.ts index a6d65a40..45d2df24 100644 --- a/apps/web-antd/src/bootstrap.ts +++ b/apps/web-antd/src/bootstrap.ts @@ -17,6 +17,8 @@ import { initSetupVbenForm } from './adapter/form'; import App from './app.vue'; import { router } from './router'; + + async function bootstrap(namespace: string) { // 初始化组件适配器 await initComponentAdapter(); @@ -43,6 +45,7 @@ async function bootstrap(namespace: string) { spinning: 'spinning', }); + // 国际化 i18n 配置 await setupI18n(app); @@ -59,6 +62,7 @@ async function bootstrap(namespace: string) { // 配置路由及路由守卫 app.use(router); + // 配置Motion插件 const { MotionPlugin } = await import('@vben/plugins/motion'); app.use(MotionPlugin); diff --git a/apps/web-antd/src/layouts/basic.vue b/apps/web-antd/src/layouts/basic.vue index fffb92c6..f87a5fbd 100644 --- a/apps/web-antd/src/layouts/basic.vue +++ b/apps/web-antd/src/layouts/basic.vue @@ -146,7 +146,7 @@ watch( :avatar :menus :text="userStore.userInfo?.realName" - description="ann.vben@gmail.com" + :description="userStore.userInfo?.roles[0]" tag-text="Pro" @logout="handleLogout" /> diff --git a/apps/web-antd/src/main.ts b/apps/web-antd/src/main.ts index f58a0b98..f3228461 100644 --- a/apps/web-antd/src/main.ts +++ b/apps/web-antd/src/main.ts @@ -1,6 +1,7 @@ import { initPreferences } from '@vben/preferences'; import { unmountGlobalLoading } from '@vben/utils'; import { overridesPreferences } from './preferences'; + /** * 应用初始化完成之后再进行页面加载渲染 */ diff --git a/apps/web-antd/src/router/routes/core.ts b/apps/web-antd/src/router/routes/core.ts index a966a897..4a15fc27 100644 --- a/apps/web-antd/src/router/routes/core.ts +++ b/apps/web-antd/src/router/routes/core.ts @@ -125,8 +125,18 @@ const coreRoutes: RouteRecordRaw[] = [ title: '物业大屏', requiresAuth: true, // 如果需要登录验证 }, - }, { - component: () => import('#/views/screen/security/index.vue'), + }, + // { + // component: () => import('#/views/screen/security/index.vue'), + // name: 'security', + // path: '/security', + // meta: { + // title: '安防大屏', + // requiresAuth: true, // 如果需要登录验证 + // }, + // }, + { + component: () => import('#/views/cockpit/security/index.vue'), name: 'security', path: '/security', meta: { @@ -143,15 +153,15 @@ const coreRoutes: RouteRecordRaw[] = [ requiresAuth: true, // 如果需要登录验证 }, }, - { - component: () => import('#/views/screen/security/index.vue'), - name: 'security', - path: '/security', - meta: { - title: '安防大屏', - requiresAuth: true, // 如果需要登录验证 - }, - }, + // { + // component: () => import('#/views/screen/security/index.vue'), + // name: 'security', + // path: '/security', + // meta: { + // title: '安防大屏', + // requiresAuth: true, // 如果需要登录验证 + // }, + // }, { component: () => import('#/views/screen/digitalIntelligence/index.vue'), name: 'digitalIntelligence', diff --git a/apps/web-antd/src/store/notify.ts b/apps/web-antd/src/store/notify.ts index 4fd0a951..a183ba15 100644 --- a/apps/web-antd/src/store/notify.ts +++ b/apps/web-antd/src/store/notify.ts @@ -24,7 +24,7 @@ export const useNotifyStore = defineStore( * return才会被持久化 存储全部消息 */ const notificationList = ref([]); - + const sseList = ref(["111"]); const userStore = useUserStore(); const userId = computed(() => { return userStore.userInfo?.userId || '0'; @@ -65,24 +65,33 @@ export const useNotifyStore = defineStore( if (!message) return; console.log(`接收到消息: ${message}`); - notification.success({ - description: message, - duration: 3, - message: $t('component.notice.received'), - }); + try { + // 尝试解析JSON + const obj = JSON.parse(message); + // 检查解析结果是否为对象且不为null + if (obj.getType() ==="yvjin"){ + sseList.value.join(message) + } + } catch (e) { + notification.success({ + description: message, + duration: 3, + message: $t('component.notice.received'), + }); - notificationList.value.unshift({ - // avatar: `https://api.multiavatar.com/${random(0, 10_000)}.png`, 随机头像 - avatar: SvgMessageUrl, - date: dayjs().format('YYYY-MM-DD HH:mm:ss'), - isRead: false, - message, - title: $t('component.notice.title'), - userId: userId.value, - }); + notificationList.value.unshift({ + // avatar: `https://api.multiavatar.com/${random(0, 10_000)}.png`, 随机头像 + avatar: SvgMessageUrl, + date: dayjs().format('YYYY-MM-DD HH:mm:ss'), + isRead: false, + message, + title: $t('component.notice.title'), + userId: userId.value, + }); - // 需要手动置空 vue3在值相同时不会触发watch - data.value = null; + // 需要手动置空 vue3在值相同时不会触发watch + data.value = null; + } }); } @@ -96,6 +105,10 @@ export const useNotifyStore = defineStore( item.isRead = true; }); } + function getsseList(){ + console.log(sseList.value) + return sseList.value + } /** * 设置单条消息已读 @@ -134,6 +147,8 @@ export const useNotifyStore = defineStore( $reset, clearAllMessage, notificationList, + sseList, + getsseList, notifications, setAllRead, setRead, diff --git a/apps/web-antd/src/views/cockpit/security/index.vue b/apps/web-antd/src/views/cockpit/security/index.vue index 63cf316b..d6b2d8a5 100644 --- a/apps/web-antd/src/views/cockpit/security/index.vue +++ b/apps/web-antd/src/views/cockpit/security/index.vue @@ -1,11 +1,894 @@ - - - +const list=useNotifyStore().sseList; +list.map(item=>{ + +}) +// 模拟预警数据 +const events = ref([ + { + id: 1, + title: "设备故障报警", + type: "设备故障", + status: "emergency", + time: "2023-10-15T08:23:45", + updateTime: "2023-10-15T08:45:12", + location: "一号厂房A区", + description: "流水线三号设备突然停机,显示电机故障代码E109,需要紧急处理以避免生产线中断。", + position: { x: 35, y: 40 }, + processingRecords: [ + { id: 1, action: "接收到报警信息", user: "系统自动", time: "2023-10-15T08:23:45" }, + { id: 2, action: "指派给维修组", user: "张经理", time: "2023-10-15T08:25:10" } + ] + }, + { + id: 2, + title: "安全门异常开启", + type: "安全预警", + status: "important", + time: "2023-10-15T07:15:30", + updateTime: "2023-10-15T07:30:22", + location: "二号仓库入口", + description: "非工作时间安全门被异常开启,系统已自动记录并触发警报,需检查是否有异常进入。", + position: { x: 65, y: 30 }, + processingRecords: [ + { id: 1, action: "接收到报警信息", user: "系统自动", time: "2023-10-15T07:15:30" }, + { id: 2, action: "安保人员已前往查看", user: "李主管", time: "2023-10-15T07:17:05" }, + { id: 3, action: "初步检查未发现异常", user: "王保安", time: "2023-10-15T07:30:22" } + ] + }, + { + id: 3, + title: "温湿度超标", + type: "环境异常", + status: "normal", + time: "2023-10-15T09:40:12", + updateTime: "2023-10-15T09:40:12", + location: "实验室B区", + description: "实验室B区温湿度超出正常范围,当前温度26℃,湿度65%,需调整空调系统。", + position: { x: 45, y: 60 }, + processingRecords: [ + { id: 1, action: "接收到报警信息", user: "系统自动", time: "2023-10-15T09:40:12" } + ] + }, + { + id: 4, + title: "物料短缺预警", + type: "物料管理", + status: "normal", + time: "2023-10-15T10:15:22", + updateTime: "2023-10-15T10:15:22", + location: "原料仓库", + description: "A类原材料库存低于警戒线,剩余数量约可维持2天生产,请及时采购补充。", + position: { x: 25, y: 70 }, + processingRecords: [ + { id: 1, action: "系统自动发出预警", user: "系统自动", time: "2023-10-15T10:15:22" } + ] + }, + { + id: 5, + title: "网络中断恢复", + type: "网络问题", + status: "resolved", + time: "2023-10-15T06:30:15", + updateTime: "2023-10-15T07:05:33", + location: "三号车间", + description: "三号车间网络中断,影响设备数据上传,技术人员已修复,网络恢复正常。", + position: { x: 75, y: 55 }, + processingRecords: [ + { id: 1, action: "检测到网络中断", user: "系统自动", time: "2023-10-15T06:30:15" }, + { id: 2, action: "技术人员前往处理", user: "赵主管", time: "2023-10-15T06:35:40" }, + { id: 3, action: "网络已恢复正常", user: "孙工", time: "2023-10-15T07:05:33" } + ] + } +]); + +// 选中的预警 +const selectedEvent = ref(null); + +// 统计数据 +const stats = ref({ + emergency: 1, + important: 1, + normal: 2, + resolved: 1 +}); + +// 当前时间和最后更新时间 +const currentTime = ref(""); +const lastUpdateTime = ref("2023-10-15 10:30:45"); + +// 图表引用 +const eventTypePieChart = ref(null); +const processingTimeChart = ref(null); +const dailyEventsChart = ref(null); + +// 处理进度(根据预警状态计算) +const processingProgress = computed(() => { + if (!selectedEvent.value) return 0; + + switch(selectedEvent.value.status) { + case 'emergency': return 30; + case 'important': return 50; + case 'normal': return 20; + case 'resolved': return 100; + default: return 0; + } +}); + +// 选择预警 +const selectEvent = (event) => { + selectedEvent.value = event; +}; + +// 标记为已处理 +const markAsResolved = () => { + if (selectedEvent.value) { + // 更新预警状态 + selectedEvent.value.status = 'resolved'; + selectedEvent.value.updateTime = new Date().toISOString(); + + // 添加处理记录 + if (processingNote.value.trim()) { + selectedEvent.value.processingRecords.push({ + id: selectedEvent.value.processingRecords.length + 1, + action: `标记为已处理: ${processingNote.value.trim()}`, + user: "当前操作员", + time: new Date().toISOString() + }); + processingNote.value = ''; + } else { + selectedEvent.value.processingRecords.push({ + id: selectedEvent.value.processingRecords.length + 1, + action: "标记为已处理", + user: "当前操作员", + time: new Date().toISOString() + }); + } + + // 更新统计数据 + stats.value.resolved++; + if (stats.value.emergency > 0) stats.value.emergency--; + else if (stats.value.important > 0) stats.value.important--; + else if (stats.value.normal > 0) stats.value.normal--; + + // 重新绘制图表 + drawAllCharts(); + } +}; + +// 格式化时间 +const formatTime = (timeString) => { + const date = new Date(timeString); + return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); +}; + +// 格式化日期时间 +const formatDateTime = (timeString) => { + const date = new Date(timeString); + return date.toLocaleString(); +}; + +// 预警状态文本 +const eventStatusText = (status) => { + const statusMap = { + 'emergency': '紧急', + 'important': '重要', + 'normal': '一般', + 'resolved': '已处理' + }; + return statusMap[status] || '未知'; +}; + +// 预警状态颜色 +const eventStatusColor = (status) => { + const colorMap = { + 'emergency': 'bg-red-500', + 'important': 'bg-orange-500', + 'normal': 'bg-yellow-500', + 'resolved': 'bg-green-500' + }; + return colorMap[status] || 'bg-slate-500'; +}; + +// 预警状态标记颜色(脉冲效果) +const eventStatusPingClass = (status) => { + const colorMap = { + 'emergency': 'bg-red-500/30', + 'important': 'bg-orange-500/30', + 'normal': 'bg-yellow-500/30', + 'resolved': 'bg-green-500/30' + }; + return colorMap[status] || 'bg-slate-500/30'; +}; + +// 预警状态徽章样式 +const eventStatusBadgeClass = (status) => { + const classMap = { + 'emergency': 'bg-red-500/20 text-red-400 border border-red-500/30', + 'important': 'bg-orange-500/20 text-orange-400 border border-orange-500/30', + 'normal': 'bg-yellow-500/20 text-yellow-400 border border-yellow-500/30', + 'resolved': 'bg-green-500/20 text-green-400 border border-green-500/30' + }; + return classMap[status] || 'bg-slate-500/20 text-slate-400 border border-slate-500/30'; +}; + +// 更新当前时间 +const updateCurrentTime = () => { + const now = new Date(); + currentTime.value = now.toLocaleString(); +}; + +// 绘制饼图 - 使用原生Canvas API +const drawPieChart = (canvas, data) => { + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + const width = canvas.width; + const height = canvas.height; + + // 清除画布 + ctx.clearRect(0, 0, width, height); + + const centerX = width / 2; + const centerY = height / 2; + const radius = Math.min(width, height) / 3; + + const total = data.values.reduce((sum, value) => sum + value, 0); + let startAngle = 0; + + data.values.forEach((value, index) => { + const sliceAngle = 2 * Math.PI * (value / total); + const color = data.colors[index]; + + // 绘制扇形 + ctx.beginPath(); + ctx.moveTo(centerX, centerY); + ctx.arc(centerX, centerY, radius, startAngle, startAngle + sliceAngle); + ctx.closePath(); + ctx.fillStyle = color; + ctx.fill(); + + // 添加边框 + ctx.strokeStyle = 'rgba(30, 41, 59, 0.8)'; + ctx.lineWidth = 1; + ctx.stroke(); + + // 计算标签位置 + const labelAngle = startAngle + sliceAngle / 2; + const labelRadius = radius + 15; + const labelX = centerX + Math.cos(labelAngle) * labelRadius; + const labelY = centerY + Math.sin(labelAngle) * labelRadius; + + // 绘制标签 + ctx.fillStyle = '#e2e8f0'; + ctx.font = '10px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(`${data.labels[index]}: ${value}`, labelX, labelY); + + startAngle += sliceAngle; + }); +}; + +// 绘制折线图 - 使用原生Canvas API +const drawLineChart = (canvas, data) => { + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + const width = canvas.width; + const height = canvas.height; + + // 清除画布 + ctx.clearRect(0, 0, width, height); + + // 边距 + const margin = { top: 10, right: 10, bottom: 20, left: 30 }; + const chartWidth = width - margin.left - margin.right; + const chartHeight = height - margin.top - margin.bottom; + + // 找到数据范围 + const maxValue = Math.max(...data.values); + const minValue = 0; + const valueRange = maxValue - minValue; + + // 计算X轴和Y轴的比例 + const xScale = chartWidth / (data.values.length - 1); + const yScale = chartHeight / valueRange; + + // 绘制坐标轴 + ctx.beginPath(); + ctx.strokeStyle = 'rgba(148, 163, 184, 0.5)'; + ctx.lineWidth = 1; + + // X轴 + ctx.moveTo(margin.left, margin.top + chartHeight); + ctx.lineTo(margin.left + chartWidth, margin.top + chartHeight); + ctx.stroke(); + + // Y轴 + ctx.moveTo(margin.left, margin.top); + ctx.lineTo(margin.left, margin.top + chartHeight); + ctx.stroke(); + + // 绘制网格线 + ctx.strokeStyle = 'rgba(148, 163, 184, 0.1)'; + + // 水平网格线 + const yGridCount = 5; + for (let i = 0; i <= yGridCount; i++) { + const y = margin.top + chartHeight - (i * chartHeight / yGridCount); + ctx.beginPath(); + ctx.moveTo(margin.left, y); + ctx.lineTo(margin.left + chartWidth, y); + ctx.stroke(); + + // Y轴刻度 + ctx.fillStyle = 'rgba(148, 163, 184, 0.7)'; + ctx.font = '8px sans-serif'; + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillText(Math.round(i * valueRange / yGridCount), margin.left - 5, y); + } + + // 绘制数据线 + ctx.beginPath(); + data.values.forEach((value, index) => { + const x = margin.left + index * xScale; + const y = margin.top + chartHeight - (value - minValue) * yScale; + + if (index === 0) { + ctx.moveTo(x, y); + } else { + ctx.lineTo(x, y); + } + + // 绘制数据点 + ctx.fillStyle = data.lineColor; + ctx.beginPath(); + ctx.arc(x, y, 3, 0, 2 * Math.PI); + ctx.fill(); + + // 绘制白色边框 + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 1; + ctx.stroke(); + }); + + // 绘制线条 + ctx.strokeStyle = data.lineColor; + ctx.lineWidth = 2; + ctx.stroke(); + + // 填充区域 + ctx.lineTo(margin.left + (data.values.length - 1) * xScale, margin.top + chartHeight); + ctx.lineTo(margin.left, margin.top + chartHeight); + ctx.closePath(); + ctx.fillStyle = data.areaColor; + ctx.fill(); + + // 绘制X轴标签 + data.labels.forEach((label, index) => { + const x = margin.left + index * xScale; + ctx.fillStyle = 'rgba(148, 163, 184, 0.7)'; + ctx.font = '8px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + ctx.fillText(label, x, margin.top + chartHeight + 5); + }); +}; + +// 绘制柱状图 - 使用原生Canvas API +const drawBarChart = (canvas, data) => { + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + const width = canvas.width; + const height = canvas.height; + + // 清除画布 + ctx.clearRect(0, 0, width, height); + + // 边距 + const margin = { top: 10, right: 10, bottom: 20, left: 30 }; + const chartWidth = width - margin.left - margin.right; + const chartHeight = height - margin.top - margin.bottom; + + // 找到数据范围 + const maxValue = Math.max(...data.values) * 1.1; // 留10%的余量 + const minValue = 0; + const valueRange = maxValue - minValue; + + // 计算X轴和Y轴的比例 + const barWidth = chartWidth / (data.values.length * 2); + const xScale = chartWidth / (data.values.length); + const yScale = chartHeight / valueRange; + + // 绘制坐标轴 + ctx.beginPath(); + ctx.strokeStyle = 'rgba(148, 163, 184, 0.5)'; + ctx.lineWidth = 1; + + // X轴 + ctx.moveTo(margin.left, margin.top + chartHeight); + ctx.lineTo(margin.left + chartWidth, margin.top + chartHeight); + ctx.stroke(); + + // Y轴 + ctx.moveTo(margin.left, margin.top); + ctx.lineTo(margin.left, margin.top + chartHeight); + ctx.stroke(); + + // 绘制网格线 + ctx.strokeStyle = 'rgba(148, 163, 184, 0.1)'; + + // 水平网格线 + const yGridCount = 5; + for (let i = 0; i <= yGridCount; i++) { + const y = margin.top + chartHeight - (i * chartHeight / yGridCount); + ctx.beginPath(); + ctx.moveTo(margin.left, y); + ctx.lineTo(margin.left + chartWidth, y); + ctx.stroke(); + + // Y轴刻度 + ctx.fillStyle = 'rgba(148, 163, 184, 0.7)'; + ctx.font = '8px sans-serif'; + ctx.textAlign = 'right'; + ctx.textBaseline = 'middle'; + ctx.fillText(Math.round(i * valueRange / yGridCount), margin.left - 5, y); + } + + // 绘制柱子 + data.values.forEach((value, index) => { + const x = margin.left + index * xScale + (xScale - barWidth) / 2; + const barHeight = (value - minValue) * yScale; + const y = margin.top + chartHeight - barHeight; + + // 绘制柱子 + ctx.fillStyle = data.barColor; + ctx.fillRect(x, y, barWidth, barHeight); + + // 绘制柱子顶部的值 + ctx.fillStyle = 'rgba(226, 232, 240, 0.9)'; + ctx.font = '8px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + ctx.fillText(value, x + barWidth / 2, y - 3); + }); + + // 绘制X轴标签 + data.labels.forEach((label, index) => { + const x = margin.left + index * xScale + xScale / 2; + ctx.fillStyle = 'rgba(148, 163, 184, 0.7)'; + ctx.font = '8px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'top'; + ctx.fillText(label, x, margin.top + chartHeight + 5); + }); +}; + +// 绘制所有图表 +const drawAllCharts = () => { + // 设置Canvas尺寸(考虑高DPI屏幕) + const setupCanvas = (canvas) => { + if (!canvas) return; + const dpr = window.devicePixelRatio || 1; + const rect = canvas.getBoundingClientRect(); + canvas.width = rect.width * dpr; + canvas.height = rect.height * dpr; + const ctx = canvas.getContext('2d'); + ctx.scale(dpr, dpr); + canvas.style.width = `${rect.width}px`; + canvas.style.height = `${rect.height}px`; + }; + + // 预警类型饼图数据 + const pieData = { + labels: ['设备故障', '安全预警', '环境异常', '物料管理', '网络问题'], + values: [1, 1, 1, 1, 1], + colors: [ + '#3b82f6', // 蓝色 + '#f97316', // 橙色 + '#eab308', // 黄色 + '#10b981', // 绿色 + '#8b5cf6' // 紫色 + ] + }; + + // 处理时间折线图数据 + const lineData = { + labels: ['1日', '2日', '3日', '4日', '5日', '6日', '7日'], + values: [25, 32, 28, 45, 36, 22, 30], + lineColor: '#3b82f6', + areaColor: 'rgba(59, 130, 246, 0.1)' + }; + + // 每日预警数量柱状图数据 + const barData = { + labels: ['1日', '2日', '3日', '4日', '5日', '6日', '7日'], + values: [8, 12, 5, 15, 7, 10, 5], + barColor: '#06b6d4' + }; + + // 设置并绘制图表 + // setupCanvas(eventTypePieChart.value); + setupCanvas(processingTimeChart.value); + setupCanvas(dailyEventsChart.value); + + // drawPieChart(eventTypePieChart.value, pieData); + drawLineChart(processingTimeChart.value, lineData); + drawBarChart(dailyEventsChart.value, barData); +}; + +// 页面加载时初始化 +onMounted(() => { + // 默认选择第一个预警 + if (events.value.length > 0) { + selectedEvent.value = events.value[0]; + } + + // 初始化时间 + updateCurrentTime(); + setInterval(updateCurrentTime, 1000); + + // 初始化图表 + drawAllCharts(); + + // 监听窗口大小变化,重新绘制图表 + window.addEventListener('resize', drawAllCharts); +}); + diff --git a/apps/web-antd/src/views/screen/security/index.vue b/apps/web-antd/src/views/screen/security/index.vue index 94cb47ec..2e44f114 100644 --- a/apps/web-antd/src/views/screen/security/index.vue +++ b/apps/web-antd/src/views/screen/security/index.vue @@ -750,23 +750,23 @@ onBeforeUnmount(() => { align-items: center; display: flex; justify-content: space-between; - .left { - display: flex; - width: 18.3125rem; - .left-first { - padding-left: 2.3125rem; - font-size: 1.875rem; - width: 10.5rem; - color: #ffffff; + .left{ + display: flex; + width: 14.3125rem; + .left-first{ + padding-left: 2.3125rem; + padding-right: 3.5rem; + font-size: 1.875rem; + color: #FFFFFF; + } + .left-second{ + width: 6.5rem; + font-family: ShiShangZhongHeiJianTi; + font-weight: 400; + font-size: 1.25rem; + color: #FFFFFF; + } } - .left-second { - width: 6.5rem; - font-family: ShiShangZhongHeiJianTi; - font-weight: 400; - font-size: 1.25rem; - color: #ffffff; - } - } .center{ font-size: 1.9rem; color: #fff; diff --git a/apps/web-antd/vite.config.mts b/apps/web-antd/vite.config.mts index b55e2848..6aa8b8e1 100644 --- a/apps/web-antd/vite.config.mts +++ b/apps/web-antd/vite.config.mts @@ -27,7 +27,8 @@ export default defineConfig(async () => { changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), // mock代理目标地址 - target: 'http://127.0.0.1:8080', + // target: 'http://127.0.0.1:8080', + target: 'http://183.230.235.66:11010/api', ws: true, }, }, diff --git a/package.json b/package.json index 777662d1..f64af8dd 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,3 @@ - { "name": "vben-admin-monorepo", "version": "5.5.6", @@ -59,6 +58,7 @@ "catalog": "pnpx codemod pnpm/catalog" }, "devDependencies": { + "@dataview/datav-vue3": "0.0.0-test.1672506674342", "@changesets/changelog-github": "catalog:", "@changesets/cli": "catalog:", "@playwright/test": "catalog:", @@ -118,6 +118,7 @@ }, "dependencies": { "@ant-design/icons-vue": "^7.0.1", + "@dataview/datav-vue3": "0.0.0-test.1672506674342", "ant-design-vue": "^4.2.6", "postcss-antd-fixes": "^0.2.0" } diff --git a/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue b/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue index 8b5f499f..4d8d93d5 100644 --- a/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue +++ b/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue @@ -68,12 +68,12 @@ defineOptions({ const props = withDefaults(defineProps(), { avatar: '', - description: '', enableShortcutKey: true, menus: () => [], showShortcutKey: true, tagText: '', text: '', + description: '', trigger: 'click', hoverDelay: 500, }); @@ -168,6 +168,7 @@ if (enableShortcutKey.value) { v-if="preferences.widget.lockScreen" :avatar="avatar" :text="text" + :description="description" @submit="handleSubmitLock" /> @@ -214,7 +215,7 @@ if (enableShortcutKey.value) { -
+
{{ description }}
diff --git a/packages/stores/src/modules/user.ts b/packages/stores/src/modules/user.ts index afc974a2..56810b4f 100644 --- a/packages/stores/src/modules/user.ts +++ b/packages/stores/src/modules/user.ts @@ -26,6 +26,10 @@ interface BasicUserInfo { * 用户名 */ username: string; + /** + * 邮箱 + */ + email: string; } interface AccessState { diff --git a/playground/src/store/auth.ts b/playground/src/store/auth.ts index 4adeb76e..8e840aff 100644 --- a/playground/src/store/auth.ts +++ b/playground/src/store/auth.ts @@ -47,8 +47,8 @@ export const useAuthStore = defineStore('auth', () => { ]); userInfo = fetchUserInfoResult; - userStore.setUserInfo(userInfo); + accessStore.setAccessCodes(accessCodes); if (accessStore.loginExpired) {