From f0e5de9a0f113c253e474c53cdd11a9134ba3d08 Mon Sep 17 00:00:00 2001 From: hx <190679152@qq.com> Date: Tue, 28 Apr 2026 17:47:15 +0800 Subject: [PATCH] =?UTF-8?q?b=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/brand.js | 9 + src/api/device/device.js | 17 +- .../device/PendingActivateDialog.vue | 255 +++++++++ src/lang/fence-messages.js | 8 +- src/lang/profile-messages.js | 12 + src/layout/components/Navbar.vue | 21 +- src/layout/components/Sidebar/Logo.vue | 54 +- src/main.js | 91 ++- src/permission.js | 26 +- src/router/index.js | 58 +- src/store/getters.js | 4 +- src/store/index.js | 4 +- src/store/modules/brand.js | 64 +++ src/utils/brand.js | 125 ++++ src/utils/dynamicTitle.js | 20 +- src/utils/request.js | 72 +-- src/utils/validate.js | 73 +-- src/views/device/device/index.vue | 29 +- src/views/fence/device/index.vue | 327 ++++++++++- src/views/login.vue | 541 +++++++++--------- .../user/components/ProfileSettingsCard.vue | 25 +- 21 files changed, 1250 insertions(+), 585 deletions(-) create mode 100644 src/api/brand.js create mode 100644 src/components/device/PendingActivateDialog.vue create mode 100644 src/store/modules/brand.js create mode 100644 src/utils/brand.js diff --git a/src/api/brand.js b/src/api/brand.js new file mode 100644 index 0000000..10933f5 --- /dev/null +++ b/src/api/brand.js @@ -0,0 +1,9 @@ +import request from "@/utils/request"; + +export function getBrandConfig(businessNo) { + return request({ + url: "/system/info/brand", + method: "get", + params: businessNo ? { businessNo } : {} + }); +} diff --git a/src/api/device/device.js b/src/api/device/device.js index bf9aed6..f3462ed 100644 --- a/src/api/device/device.js +++ b/src/api/device/device.js @@ -8,6 +8,14 @@ export function listDevice(query) { }) } +export function listPendingActivateDevice(query) { + return request({ + url: '/device/device/pending-activate/list', + method: 'get', + params: query + }) +} + export function getDevice(id) { return request({ url: '/device/device/' + id, @@ -124,13 +132,14 @@ export function getBatchNo() { }) } -export function batchActivateDevice(ids) { +export function batchActivateDevice(payload) { + const requestPayload = Array.isArray(payload) + ? { ids: payload } + : (payload || { ids: [] }) return request({ url: '/device/device/activate/batch', method: 'put', - data: { - ids: ids - } + data: requestPayload }) } diff --git a/src/components/device/PendingActivateDialog.vue b/src/components/device/PendingActivateDialog.vue new file mode 100644 index 0000000..e1562f5 --- /dev/null +++ b/src/components/device/PendingActivateDialog.vue @@ -0,0 +1,255 @@ + + + + + diff --git a/src/lang/fence-messages.js b/src/lang/fence-messages.js index 211ec83..cac839a 100644 --- a/src/lang/fence-messages.js +++ b/src/lang/fence-messages.js @@ -136,7 +136,7 @@ const fenceZh = { overview: { online: '监控设备', normalDevice: '正常设备', alertDevice: '告警设备', activeFence: '启用围栏', openAlarm: '未处理告警', todayAlarm: '今日告警' }, query: { keyword: '关键字', fenceName: '围栏名称', status: '状态', shapeType: '图形类型', alarmType: '告警类型', handleStatus: '处理状态', alarmLevel: '告警级别', alarmTime: '告警时间' }, placeholder: { keyword: '请输入围栏名称或备注', fenceName: '请输入围栏名称', monitorKeyword: '请输入设备 SN / 名称 / 地址', alarmKeyword: '请输入告警内容', alarmSn: '请输入设备 SN', alarmFenceName: '请输入围栏名称', alarmDeviceName: '请输入设备名称', alarmTimeStart: '开始时间', alarmTimeEnd: '结束时间' }, - button: { add: '新增围栏', edit: '编辑', remove: '删除', scan: '执行扫描', refresh: '刷新', refreshAll: '刷新全局', save: '保存', handle: '处理告警', locate: '定位', more: '更多', preview: '预览', resetEditor: '重置编辑器', selectDevice: '选择设备', markNormal: '设为正常', expandMap: '放大地图', restoreMap: '还原地图' }, + button: { add: '新增围栏', addLocateTip: '新增围栏前点击可定位', edit: '编辑', remove: '删除', scan: '执行扫描', refresh: '刷新', refreshAll: '刷新全局', save: '保存', handle: '处理告警', locate: '定位', more: '更多', preview: '预览', resetEditor: '重置编辑器', selectDevice: '选择设备', markNormal: '设为正常', expandMap: '放大地图', restoreMap: '还原地图' }, status: { enabled: '启用', disabled: '停用' }, shape: { circle: '圆形', rect: '矩形', polygon: '多边形' }, alarmRule: { enter: '进入', exit: '离开', inside: '范围内', outside: '范围外', boundary: '边界', exitRecommended: '离开告警(防丢推荐)', enterExit: '进入+离开', enterOnly: '仅进入' }, @@ -150,7 +150,7 @@ const fenceZh = { form: { addTitle: '新增围栏', editTitle: '编辑围栏', name: '围栏名称', shapeType: '几何类型', alarmRules: '告警策略', scheduleType: '生效时间', scheduleStart: '开始时间', scheduleEnd: '结束时间', alarmCountdownMinutes: '告警倒计时(小时)', remark: '围栏备注', centerLat: '中心纬度', centerLng: '中心经度', radiusMeter: '半径(米)', geomWkt: '几何 WKT', shapeDataJson: '图形 JSON', deviceIds: '绑定设备', devicePlaceholder: '请选择需要监控的设备', deviceSearchPlaceholder: '搜索 SN / 设备名称 / 地址', timePlaceholder: 'HH:mm:ss' }, dialog: { deviceTitle: '选择绑定设备', deviceHint: '仅显示当前企业下已启用的设备,双击行可快速选择。', selectedCount: '已选择 {count} 台设备', alarmLocateTitle: '设备位置定位' }, table: { name: '围栏名称', shape: '图形', rules: '告警策略', status: '状态', actions: '操作', sn: '设备 SN', alias: '设备名称', lat: '纬度', lng: '经度', coordinates: '经纬度', address: '位置地址', locationTime: '更新时间', fenceStatus: '围栏状态', lastAlarm: '最近告警', alarmMessage: '告警内容', alarmTime: '告警时间', alarmType: '告警类型', alarmLevel: '告警级别' }, - message: { loadFailed: '围栏工作台加载失败', mapConfigLoadFailed: '地图配置加载失败', nameRequired: '请先填写围栏名称', ruleRequired: '请至少选择一项告警规则', circleRequired: '圆形围栏需要中心点和半径', shapeRequired: '请先在地图上绘制围栏图形', shapeSynced: '图形已同步到表单', saveSuccess: '保存成功', removeSuccess: '删除成功', confirmRemove: '确认删除选中的围栏吗?', selectFence: '请先选择围栏', handleSuccess: '告警处理成功', markNormalSuccess: '设备状态已设为正常', markNormalFailed: '当前状态无法设为正常', noMonitorDevice: '当前没有可监控设备', noFenceData: '当前没有围栏数据', noAlarmData: '当前没有告警数据', scanSuccessDetail: '扫描完成,设备 {deviceCount} 个,判定 {evaluatedCount} 条,新增告警 {alarmCount} 条。', alarmLocationMissing: '当前告警缺少经纬度,无法定位。', devicePointLoadFailed: '设备坐标加载失败,已先展示围栏' } + message: { loadFailed: '围栏工作台加载失败', mapConfigLoadFailed: '地图配置加载失败', nameRequired: '请先填写围栏名称', ruleRequired: '请至少选择一项告警规则', deviceRequired: '请至少选择一台绑定设备', circleRequired: '圆形围栏需要中心点和半径', shapeRequired: '请先在地图上绘制围栏图形', shapeSynced: '图形已同步到表单', saveSuccess: '保存成功', removeSuccess: '删除成功', confirmRemove: '确认删除选中的围栏吗?', selectFence: '请先选择围栏', handleSuccess: '告警处理成功', markNormalSuccess: '设备状态已设为正常', markNormalFailed: '当前状态无法设为正常', noMonitorDevice: '当前没有可监控设备', noFenceData: '当前没有围栏数据', noAlarmData: '当前没有告警数据', scanSuccessDetail: '扫描完成,设备 {deviceCount} 个,判定 {evaluatedCount} 条,新增告警 {alarmCount} 条。', alarmLocationMissing: '当前告警缺少经纬度,无法定位。', devicePointLoadFailed: '设备坐标加载失败,已先展示围栏' } } const fenceEn = { @@ -172,7 +172,7 @@ const fenceEn = { overview: { online: 'Monitored Devices', normalDevice: 'Normal Devices', alertDevice: 'Alert Devices', activeFence: 'Active Fences', openAlarm: 'Open Alarms', todayAlarm: 'Today Alarms' }, query: { keyword: 'Keyword', fenceName: 'Fence Name', status: 'Status', shapeType: 'Shape', alarmType: 'Alarm Type', handleStatus: 'Handle Status', alarmLevel: 'Alarm Level', alarmTime: 'Alarm Time' }, placeholder: { keyword: 'Enter fence name or remark', fenceName: 'Enter fence name', monitorKeyword: 'Enter device SN / name / address', alarmKeyword: 'Enter alarm content', alarmSn: 'Enter device SN', alarmFenceName: 'Enter fence name', alarmDeviceName: 'Enter device name', alarmTimeStart: 'Start time', alarmTimeEnd: 'End time' }, - button: { add: 'Add Fence', edit: 'Edit', remove: 'Delete', scan: 'Run Scan', refresh: 'Refresh', refreshAll: 'Refresh All', save: 'Save', handle: 'Handle', locate: 'Locate', more: 'More', preview: 'Preview', resetEditor: 'Reset Editor', selectDevice: 'Select Devices', markNormal: 'Set Normal', expandMap: 'Expand Map', restoreMap: 'Restore Map' }, + button: { add: 'Add Fence', addLocateTip: 'Click to locate before adding a fence', edit: 'Edit', remove: 'Delete', scan: 'Run Scan', refresh: 'Refresh', refreshAll: 'Refresh All', save: 'Save', handle: 'Handle', locate: 'Locate', more: 'More', preview: 'Preview', resetEditor: 'Reset Editor', selectDevice: 'Select Devices', markNormal: 'Set Normal', expandMap: 'Expand Map', restoreMap: 'Restore Map' }, status: { enabled: 'Enabled', disabled: 'Disabled' }, shape: { circle: 'Circle', rect: 'Rectangle', polygon: 'Polygon' }, alarmRule: { enter: 'Enter', exit: 'Exit', inside: 'Inside', outside: 'Outside', boundary: 'Boundary', exitRecommended: 'Exit Alert (Recommended)', enterExit: 'Enter + Exit', enterOnly: 'Enter Only' }, @@ -186,7 +186,7 @@ const fenceEn = { form: { addTitle: 'Add Fence', editTitle: 'Edit Fence', name: 'Fence Name', shapeType: 'Geometry Type', alarmRules: 'Alarm Rules', scheduleType: 'Schedule', scheduleStart: 'Start Time', scheduleEnd: 'End Time', alarmCountdownMinutes: 'Alarm Countdown (hour)', remark: 'Fence Remark', centerLat: 'Center Lat', centerLng: 'Center Lng', radiusMeter: 'Radius (m)', geomWkt: 'Geometry WKT', shapeDataJson: 'Shape JSON', deviceIds: 'Bind Devices', devicePlaceholder: 'Select devices', deviceSearchPlaceholder: 'Search SN / device name / address', timePlaceholder: 'HH:mm:ss' }, dialog: { deviceTitle: 'Select Devices', deviceHint: 'Only active devices in the current business are shown. Double-click a row to select it quickly.', selectedCount: '{count} devices selected', alarmLocateTitle: 'Device Location' }, table: { name: 'Fence Name', shape: 'Shape', rules: 'Rules', status: 'Status', actions: 'Actions', sn: 'Device SN', alias: 'Device Name', lat: 'Latitude', lng: 'Longitude', coordinates: 'Coordinates', address: 'Address', locationTime: 'Update Time', fenceStatus: 'Fence Status', lastAlarm: 'Last Alarm', alarmMessage: 'Alarm Message', alarmTime: 'Alarm Time', alarmType: 'Alarm Type', alarmLevel: 'Alarm Level' }, - message: { loadFailed: 'Failed to load fence workspace', mapConfigLoadFailed: 'Failed to load map config', nameRequired: 'Fence name is required', ruleRequired: 'Select at least one alarm rule', circleRequired: 'Circle fence needs center and radius', shapeRequired: 'Draw the fence shape on the map first', shapeSynced: 'The shape has been synced to the form', saveSuccess: 'Saved successfully', removeSuccess: 'Deleted successfully', confirmRemove: 'Delete the selected fences?', selectFence: 'Select fences first', handleSuccess: 'Alarm handled successfully', markNormalSuccess: 'State has been set to normal', markNormalFailed: 'Unable to set current state to normal', noMonitorDevice: 'No device available', noFenceData: 'No fence data', noAlarmData: 'No alarm data', scanSuccessDetail: 'Scan finished: {deviceCount} devices, {evaluatedCount} evaluations, {alarmCount} new alarms.', alarmLocationMissing: 'This alarm has no coordinates and cannot be located.', devicePointLoadFailed: 'Failed to load device coordinates, fence is shown first.' } + message: { loadFailed: 'Failed to load fence workspace', mapConfigLoadFailed: 'Failed to load map config', nameRequired: 'Fence name is required', ruleRequired: 'Select at least one alarm rule', deviceRequired: 'Select at least one bound device', circleRequired: 'Circle fence needs center and radius', shapeRequired: 'Draw the fence shape on the map first', shapeSynced: 'The shape has been synced to the form', saveSuccess: 'Saved successfully', removeSuccess: 'Deleted successfully', confirmRemove: 'Delete the selected fences?', selectFence: 'Select fences first', handleSuccess: 'Alarm handled successfully', markNormalSuccess: 'State has been set to normal', markNormalFailed: 'Unable to set current state to normal', noMonitorDevice: 'No device available', noFenceData: 'No fence data', noAlarmData: 'No alarm data', scanSuccessDetail: 'Scan finished: {deviceCount} devices, {evaluatedCount} evaluations, {alarmCount} new alarms.', alarmLocationMissing: 'This alarm has no coordinates and cannot be located.', devicePointLoadFailed: 'Failed to load device coordinates, fence is shown first.' } } diff --git a/src/lang/profile-messages.js b/src/lang/profile-messages.js index a891b74..b205ec7 100644 --- a/src/lang/profile-messages.js +++ b/src/lang/profile-messages.js @@ -12,6 +12,7 @@ const profileMessages = { nickName: "昵称", googleKey: "谷歌地图 Key", gaodeKey: "高德地图 Key", + maptilerKey: "MapTiler Key", gaodeSecurityKey: "高德安全密钥", oldPassword: "旧密码", newPassword: "新密码", @@ -20,6 +21,7 @@ const profileMessages = { placeholder: { googleKey: "请输入谷歌地图 Key", gaodeKey: "请输入高德地图 Key", + maptilerKey: "Enter MapTiler Key", gaodeSecurityKey: "请输入高德安全密钥", oldPassword: "请输入旧密码", newPassword: "请输入新密码", @@ -60,6 +62,7 @@ const profileMessages = { nickName: "Nickname", googleKey: "Google Maps Key", gaodeKey: "Amap Key", + maptilerKey: "MapTiler Key", gaodeSecurityKey: "Amap Security Key", oldPassword: "Old Password", newPassword: "New Password", @@ -68,6 +71,7 @@ const profileMessages = { placeholder: { googleKey: "Enter Google Maps Key", gaodeKey: "Enter Amap Key", + maptilerKey: "Enter MapTiler Key", gaodeSecurityKey: "Enter Amap Security Key", oldPassword: "Enter old password", newPassword: "Enter new password", @@ -108,6 +112,7 @@ const profileMessages = { nickName: "Псевдоним", googleKey: "Ключ Google Maps", gaodeKey: "Ключ Amap", + maptilerKey: "MapTiler Key", gaodeSecurityKey: "Ключ безопасности Amap", oldPassword: "Старый пароль", newPassword: "Новый пароль", @@ -116,6 +121,7 @@ const profileMessages = { placeholder: { googleKey: "Введите ключ Google Maps", gaodeKey: "Введите ключ Amap", + maptilerKey: "Enter MapTiler Key", gaodeSecurityKey: "Введите ключ безопасности Amap", oldPassword: "Введите старый пароль", newPassword: "Введите новый пароль", @@ -156,6 +162,7 @@ const profileMessages = { nickName: "Surnom", googleKey: "Cle Google Maps", gaodeKey: "Cle Amap", + maptilerKey: "MapTiler Key", gaodeSecurityKey: "Cle de securite Amap", oldPassword: "Ancien mot de passe", newPassword: "Nouveau mot de passe", @@ -164,6 +171,7 @@ const profileMessages = { placeholder: { googleKey: "Saisissez la cle Google Maps", gaodeKey: "Saisissez la cle Amap", + maptilerKey: "Enter MapTiler Key", gaodeSecurityKey: "Saisissez la cle de securite Amap", oldPassword: "Saisissez l'ancien mot de passe", newPassword: "Saisissez le nouveau mot de passe", @@ -204,6 +212,7 @@ const profileMessages = { nickName: "Apodo", googleKey: "Clave de Google Maps", gaodeKey: "Clave de Amap", + maptilerKey: "MapTiler Key", gaodeSecurityKey: "Clave de seguridad de Amap", oldPassword: "Contrasena anterior", newPassword: "Nueva contrasena", @@ -212,6 +221,7 @@ const profileMessages = { placeholder: { googleKey: "Ingrese la clave de Google Maps", gaodeKey: "Ingrese la clave de Amap", + maptilerKey: "Enter MapTiler Key", gaodeSecurityKey: "Ingrese la clave de seguridad de Amap", oldPassword: "Ingrese la contrasena anterior", newPassword: "Ingrese la nueva contrasena", @@ -252,6 +262,7 @@ const profileMessages = { nickName: "Apelido", googleKey: "Chave do Google Maps", gaodeKey: "Chave da Amap", + maptilerKey: "MapTiler Key", gaodeSecurityKey: "Chave de seguranca da Amap", oldPassword: "Senha antiga", newPassword: "Nova senha", @@ -260,6 +271,7 @@ const profileMessages = { placeholder: { googleKey: "Digite a chave do Google Maps", gaodeKey: "Digite a chave da Amap", + maptilerKey: "Enter MapTiler Key", gaodeSecurityKey: "Digite a chave de seguranca da Amap", oldPassword: "Digite a senha antiga", newPassword: "Digite a nova senha", diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 3447e90..1b6dcae 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -1,4 +1,4 @@ -