From e6ef6d656ee20318e94f44c36b31533e3fad9daa Mon Sep 17 00:00:00 2001 From: zyh Date: Thu, 10 Apr 2025 22:10:08 +0000 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=9C=B0=E5=9B=BE=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E4=BC=98=E5=8C=96=E6=A0=87=E8=AE=B0=E7=82=B9?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=A8=E5=B1=80=E9=85=8D=E7=BD=AE=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=96=B9=E5=BC=8F=EF=BC=8C=E6=8F=90=E5=8D=87=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=8F=AF=E7=BB=B4=E6=8A=A4=E6=80=A7=E5=92=8C=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=BD=93=E9=AA=8C=E3=80=82=E5=90=8C=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=9C=B0=E5=9B=BE=E6=A0=87=E8=AE=B0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89=EF=BC=8C=E7=A1=AE?= =?UTF-8?q?=E4=BF=9D=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=E4=B8=80=E8=87=B4?= =?UTF-8?q?=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/admin/components_amap.tsx | 11 +++-- client/admin/pages_map.tsx | 30 +++++++----- client/share/types.ts | 84 ++++++++++++++++++++------------ deno.lock | 6 +++ 4 files changed, 83 insertions(+), 48 deletions(-) diff --git a/client/admin/components_amap.tsx b/client/admin/components_amap.tsx index e52b91f..d3fa203 100644 --- a/client/admin/components_amap.tsx +++ b/client/admin/components_amap.tsx @@ -1,5 +1,7 @@ import React, { useEffect, useRef } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { getGlobalConfig } from './utils.ts'; +import type { GlobalConfig } from '../share/types.ts'; import { Spin } from 'antd'; import './style_amap.css'; import { MapMode, MarkerData } from '../share/types.ts'; @@ -7,9 +9,9 @@ import { MapMode, MarkerData } from '../share/types.ts'; // 在线地图配置 export const AMAP_ONLINE_CONFIG = { // 高德地图 Web API 密钥 - API_KEY: window.CONFIG?.MAP_CONFIG?.KEY, + API_KEY: getGlobalConfig('MAP_CONFIG')?.KEY || '', // 主JS文件路径 - MAIN_JS: 'https://webapi.amap.com/maps?v=2.0&key=' + window.CONFIG?.MAP_CONFIG?.KEY, + MAIN_JS: 'https://webapi.amap.com/maps?v=2.0&key=' + (getGlobalConfig('MAP_CONFIG')?.KEY || ''), // 插件列表 PLUGINS: ['AMap.MouseTool', 'AMap.RangingTool', 'AMap.Scale', 'AMap.ToolBar', 'AMap.MarkerCluster'], }; @@ -82,6 +84,7 @@ export interface AMapInstance { declare global { interface Window { AMap: any; + CONFIG?: GlobalConfig; } } @@ -338,7 +341,7 @@ const AMapComponent: React.FC = ({ height = '400px', center = TILE_CONFIG.DEFAULT_CENTER as [number, number], zoom = TILE_CONFIG.DEFAULT_ZOOM, - mode = window.CONFIG?.MAP_CONFIG?.MAP_MODE || MapMode.ONLINE, + mode = (getGlobalConfig('MAP_CONFIG')?.MAP_MODE as MapMode) || MapMode.ONLINE, onMarkerClick, onClick, markers = [], @@ -438,4 +441,4 @@ const AMapComponent: React.FC = ({ ); }; -export default AMapComponent; \ No newline at end of file +export default AMapComponent; diff --git a/client/admin/pages_map.tsx b/client/admin/pages_map.tsx index fde6c10..0a77af6 100644 --- a/client/admin/pages_map.tsx +++ b/client/admin/pages_map.tsx @@ -108,16 +108,18 @@ export const LoginMapPage = () => { // 渲染地图标记点 const renderMarkers = (locations: LoginLocation[]): MarkerData[] => { - return locations.map(location => ({ - id: location.id, - longitude: location.longitude, - latitude: location.latitude, - title: location.user.nickname || location.user.username, - description: `登录时间: ${dayjs(location.loginTime).format('YYYY-MM-DD HH:mm:ss')}\nIP地址: ${location.ipAddress}`, - status: 'online', - type: 'login', - extraData: location - })); + return locations + .filter(location => location.longitude !== null && location.latitude !== null) + .map(location => ({ + id: location.id?.toString() || '', + longitude: location.longitude as number, + latitude: location.latitude as number, + title: location.user?.nickname || location.user?.username || '未知用户', + description: `登录时间: ${dayjs(location.login_time).format('YYYY-MM-DD HH:mm:ss')}\nIP地址: ${location.ip_address}`, + status: 'online', + type: 'login', + extraData: location + })); }; return ( @@ -156,7 +158,9 @@ export const LoginMapPage = () => {
@@ -179,7 +183,7 @@ export const LoginMapPage = () => { ) : markerDetail ? ( 用户}> - {markerDetail.user.nickname || markerDetail.user.username} + {markerDetail.user?.nickname || markerDetail.user?.username || '未知用户'} 登录时间}> {dayjs(markerDetail.login_time).format('YYYY-MM-DD HH:mm:ss')} @@ -208,4 +212,4 @@ export const LoginMapPage = () => {
); -}; \ No newline at end of file +}; diff --git a/client/share/types.ts b/client/share/types.ts index d766a1f..014432e 100644 --- a/client/share/types.ts +++ b/client/share/types.ts @@ -161,6 +161,37 @@ export enum MapMode { OFFLINE = 'offline' } + +// 地图标记数据接口 - 基础定义 +export interface MarkerData { + /** 标记点经度 */ + longitude: number; + + /** 标记点纬度 */ + latitude: number; + + /** 标记点ID */ + id?: string | number; + + /** 标记点标题 */ + title?: string; + + /** 标记点描述 */ + description?: string; + + /** 标记点图标URL */ + iconUrl?: string; + + /** 标记点状态 */ + status?: string; + + /** 标记点类型 */ + type?: string; + + /** 标记点额外数据 */ + extraData?: Record; +} + // 审核状态枚举 export enum AuditStatus { PENDING = 0, // 待审核 @@ -424,44 +455,35 @@ export interface KnowInfo { updated_at: string; } -// 登录位置详细信息 -export interface LoginLocationDetail { - /** 记录ID */ +// 登录位置相关类型定义 +export interface LoginLocation { id: number; - /** 用户ID */ - user_id: number; - /** 登录时间 */ - login_time: string; - /** IP地址 */ - ip_address: string; - /** 用户代理 */ - user_agent: string; - /** 纬度 */ - latitude: number | null; - /** 经度 */ - longitude: number | null; - /** 位置名称 */ + loginTime: string; + ipAddress: string; + longitude: number; + latitude: number; location_name?: string; - /** 关联用户信息 */ - user?: { + user: { id: number; username: string; - nickname?: string; + nickname: string; }; } -// 登录位置信息 -export interface LoginLocation { - /** 纬度 */ - latitude: number | null; - /** 经度 */ - longitude: number | null; - /** IP地址 */ - ip_address?: string; - /** 用户代理 */ - user_agent?: string; - /** 登录时间 */ - login_time?: string; +export interface LoginLocationDetail { + id: number; + user_id: number; + login_time: string; + ip_address: string; + longitude: number; + latitude: number; + location_name: string; + user_agent: string; + user: { + id: number; + username: string; + nickname: string; + }; } // 消息类型枚举 diff --git a/deno.lock b/deno.lock index d1a82d2..d9c9b0f 100644 --- a/deno.lock +++ b/deno.lock @@ -643,6 +643,10 @@ "https://esm.d8d.fun/@deno/shim-deno-test@0.5.0?target=denonext": "503b73de1a14bd33782220e11fa2b33e9c87d574ac793e7addf1466c5436e66a", "https://esm.d8d.fun/@deno/shim-deno@0.18.2/denonext/shim-deno.mjs": "819d8ac34fdaf60658cf03d137f14adaff3f13a279ffd79cd8797d84a6ac46ab", "https://esm.d8d.fun/@deno/shim-deno@0.18.2?target=denonext": "ffa3ca347bb6b6530720158f307a2e31b16728fbb52e6432254a07d52fcbc404", + "https://esm.d8d.fun/@heroicons/react@2.1.1/24/outline?deps=react@19.0.0,react-dom@19.0.0": "5e99f4d40ce60c55b5cf421c3cf3f13df1707cf53152e447b2332570412cd77a", + "https://esm.d8d.fun/@heroicons/react@2.1.1/24/solid?deps=react@19.0.0,react-dom@19.0.0": "e3940182b574da537337b1e90a1b7f380e17050457423e13d5ac8c7bc88a3cc0", + "https://esm.d8d.fun/@heroicons/react@2.1.1/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/24/outline.mjs": "640f934a0c987f682032049e5d4a455567db676de47bca0d44e76b72023661f7", + "https://esm.d8d.fun/@heroicons/react@2.1.1/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/24/solid.mjs": "dcbd0c377d92857b6eb23c7dbb2ee6e650b12aa6ae1ef7fcc10dc1964df8ba47", "https://esm.d8d.fun/@socket.io/component-emitter@3.1.2/denonext/component-emitter.mjs": "3c6c5f2d64d4933b577a7117df1d8855c51ff01ab3dea8f42af1adcb1a5989e7", "https://esm.d8d.fun/@socket.io/component-emitter@3.1.2?target=denonext": "f6ff0f94ae3c9850a2c3a925cc2b236ec03a80fc2298d0ca48c2a90b10487db3", "https://esm.d8d.fun/@tanstack/query-core@5.67.1/denonext/query-core.mjs": "3001acc66d3efeab4900278cf630cb56ba23ac70cd77f7e0c413abb8a1f223f3", @@ -886,6 +890,8 @@ "https://esm.d8d.fun/react-dom@19.0.0/client": "c972c16184c695fc5828dfa61d7f341edbc463d20d8108765c93a98027c24227", "https://esm.d8d.fun/react-dom@19.0.0/denonext/client.mjs": "af662fd134eea98f37fdcea6142accd0f8a7d2e13c1c3c9e98dc37a8c7aad46b", "https://esm.d8d.fun/react-dom@19.0.0/denonext/react-dom.mjs": "a2f7bc344e1d5b7ca47e68665291e206ae4db17ee84f234f3d3e2533b9119f63", + "https://esm.d8d.fun/react-hook-form@7.55.0/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/react-hook-form.mjs": "788ec1a54e10051f539ba435aa513802c823bad03e11e2534b1b17df99189a87", + "https://esm.d8d.fun/react-hook-form@7.55.0?deps=react@19.0.0,react-dom@19.0.0": "8ed376b3af6e11be43538b15e654692d5995232523a6dc16ce7f81263b1a3614", "https://esm.d8d.fun/react-router@7.3.0/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/dist/development/chunk-K6CSEXPM.mjs": "441898046ad7c4fd9a6b53e13a398c9c74c4412c519e942f82b8a77f7af9f9d6", "https://esm.d8d.fun/react-router@7.3.0/X-ZHJlYWN0LWRvbUAxOS4wLjAscmVhY3RAMTkuMC4w/denonext/react-router.mjs": "b0b05fcfc3a03c5f679cd0bc69ca19aa10abaa977395df00e86b3fb114e5e346", "https://esm.d8d.fun/react-router@7.3.0?deps=react@19.0.0,react-dom@19.0.0": "ad747718e32a45020d67eb4ff98f9734cb06a10ceb393baac0a965043e96cdf0",