feat: 请求方法初始化,视频流写入demo完成

main
donghao 2 months ago
parent 8704bd645c
commit a58eba6644

@ -0,0 +1,4 @@
# .env.development
NODE_ENV = development
VITE_APP_ENV = development
VITE_APP_BASE_API = http://192.168.10.14:8888

@ -0,0 +1,4 @@
# .env.production
NODE_ENV = production
VITE_APP_ENV = production
VITE_APP_BASE_API = https://api.production.com

@ -3,11 +3,14 @@
"Component": true, "Component": true,
"ComponentPublicInstance": true, "ComponentPublicInstance": true,
"ComputedRef": true, "ComputedRef": true,
"DirectiveBinding": true,
"EffectScope": true, "EffectScope": true,
"ExtractDefaultPropTypes": true, "ExtractDefaultPropTypes": true,
"ExtractPropTypes": true, "ExtractPropTypes": true,
"ExtractPublicPropTypes": true, "ExtractPublicPropTypes": true,
"InjectionKey": true, "InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true, "PropType": true,
"Ref": true, "Ref": true,
"VNode": true, "VNode": true,
@ -41,6 +44,7 @@
"onServerPrefetch": true, "onServerPrefetch": true,
"onUnmounted": true, "onUnmounted": true,
"onUpdated": true, "onUpdated": true,
"onWatcherCleanup": true,
"provide": true, "provide": true,
"reactive": true, "reactive": true,
"readonly": true, "readonly": true,
@ -58,17 +62,13 @@
"useAttrs": true, "useAttrs": true,
"useCssModule": true, "useCssModule": true,
"useCssVars": true, "useCssVars": true,
"useId": true,
"useModel": true,
"useSlots": true, "useSlots": true,
"useTemplateRef": true,
"watch": true, "watch": true,
"watchEffect": true, "watchEffect": true,
"watchPostEffect": true, "watchPostEffect": true,
"watchSyncEffect": true, "watchSyncEffect": true
"DirectiveBinding": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"onWatcherCleanup": true,
"useId": true,
"useModel": true,
"useTemplateRef": true
} }
} }

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 17:57:05 * @Date: 2025-03-06 17:57:05
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-07 16:43:21 * @LastEditTime: 2025-03-12 19:16:05
* @FilePath: \5G-Loading-Bay-Web\index.html * @FilePath: \5G-Loading-Bay-Web\index.html
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
--> -->
@ -13,6 +13,9 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>监控平台</title> <title>监控平台</title>
<script src="/public/adapter.min.js"></script>
<script src="/public/webrtcstreamer.js"></script>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

@ -5,11 +5,15 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "cross-env NODE_ENV=development vite", "dev": "cross-env NODE_ENV=development vite",
"test": "cross-env NODE_ENV=test vite build", "prod": "vite --mode production",
"build": "cross-env NODE_ENV=production vite build", "build": "cross-env NODE_ENV=production vite build",
"preview": "vite preview --port 5050" "build:dev": "vite build --mode development",
"build:prod": "vite build --mode production",
"preview": "vite preview --port 5050",
"preview:prod": "vite preview --port 6060 --mode production"
}, },
"dependencies": { "dependencies": {
"axios": "^1.8.3",
"echarts": "^5.6.0", "echarts": "^5.6.0",
"postcss-scss": "^4.0.9", "postcss-scss": "^4.0.9",
"sass": "^1.85.1", "sass": "^1.85.1",

@ -8,6 +8,9 @@ importers:
.: .:
dependencies: dependencies:
axios:
specifier: ^1.8.3
version: 1.8.3
echarts: echarts:
specifier: ^5.6.0 specifier: ^5.6.0
version: 5.6.0 version: 5.6.0
@ -886,6 +889,9 @@ packages:
async-validator@4.2.5: async-validator@4.2.5:
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
autoprefixer@10.4.20: autoprefixer@10.4.20:
resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@ -893,6 +899,9 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.1.0 postcss: ^8.1.0
axios@1.8.3:
resolution: {integrity: sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==}
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@ -921,6 +930,10 @@ packages:
peerDependencies: peerDependencies:
esbuild: '>=0.17' esbuild: '>=0.17'
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
camelcase-css@2.0.1: camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -943,6 +956,10 @@ packages:
color-name@1.1.4: color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@13.1.0: commander@13.1.0:
resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -1008,6 +1025,10 @@ packages:
supports-color: supports-color:
optional: true optional: true
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
detect-libc@1.0.3: detect-libc@1.0.3:
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
@ -1026,6 +1047,10 @@ packages:
dom-walk@0.1.2: dom-walk@0.1.2:
resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
eastasianwidth@0.2.0: eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@ -1061,6 +1086,22 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
esbuild@0.25.0: esbuild@0.25.0:
resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -1109,10 +1150,23 @@ packages:
resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
foreground-child@3.3.1: foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'} engines: {node: '>=14'}
form-data@4.0.2:
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
engines: {node: '>= 6'}
fraction.js@4.3.7: fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
@ -1128,6 +1182,14 @@ packages:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
glob-parent@5.1.2: glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -1147,9 +1209,21 @@ packages:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'} engines: {node: '>=4'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
graceful-fs@4.2.11: graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2: hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -1333,6 +1407,10 @@ packages:
magic-string@0.30.17: magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
memoize-one@6.0.0: memoize-one@6.0.0:
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
@ -1344,6 +1422,14 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
min-document@2.19.0: min-document@2.19.0:
resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==}
@ -1543,6 +1629,9 @@ packages:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'} engines: {node: '>= 0.6.0'}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
quansync@0.2.8: quansync@0.2.8:
resolution: {integrity: sha512-4+saucphJMazjt7iOM27mbFCk+D9dd/zmgMDCzRZ8MEoBfYp7lAvoN38et/phRQF6wOPMy/OROBGgoWeSKyluA==} resolution: {integrity: sha512-4+saucphJMazjt7iOM27mbFCk+D9dd/zmgMDCzRZ8MEoBfYp7lAvoN38et/phRQF6wOPMy/OROBGgoWeSKyluA==}
@ -2600,6 +2689,8 @@ snapshots:
async-validator@4.2.5: {} async-validator@4.2.5: {}
asynckit@0.4.0: {}
autoprefixer@10.4.20(postcss@8.5.3): autoprefixer@10.4.20(postcss@8.5.3):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
@ -2610,6 +2701,14 @@ snapshots:
postcss: 8.5.3 postcss: 8.5.3
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
axios@1.8.3:
dependencies:
follow-redirects: 1.15.9
form-data: 4.0.2
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
binary-extensions@2.3.0: {} binary-extensions@2.3.0: {}
@ -2636,6 +2735,11 @@ snapshots:
esbuild: 0.25.0 esbuild: 0.25.0
load-tsconfig: 0.2.5 load-tsconfig: 0.2.5
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
camelcase-css@2.0.1: {} camelcase-css@2.0.1: {}
caniuse-lite@1.0.30001702: {} caniuse-lite@1.0.30001702: {}
@ -2662,6 +2766,10 @@ snapshots:
color-name@1.1.4: {} color-name@1.1.4: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
commander@13.1.0: {} commander@13.1.0: {}
commander@4.1.1: {} commander@4.1.1: {}
@ -2711,6 +2819,8 @@ snapshots:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
delayed-stream@1.0.0: {}
detect-libc@1.0.3: detect-libc@1.0.3:
optional: true optional: true
@ -2722,6 +2832,12 @@ snapshots:
dom-walk@0.1.2: {} dom-walk@0.1.2: {}
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
eastasianwidth@0.2.0: {} eastasianwidth@0.2.0: {}
echarts@5.6.0: echarts@5.6.0:
@ -2767,6 +2883,21 @@ snapshots:
entities@4.5.0: {} entities@4.5.0: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
esbuild@0.25.0: esbuild@0.25.0:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.25.0 '@esbuild/aix-ppc64': 0.25.0
@ -2841,11 +2972,20 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
follow-redirects@1.15.9: {}
foreground-child@3.3.1: foreground-child@3.3.1:
dependencies: dependencies:
cross-spawn: 7.0.6 cross-spawn: 7.0.6
signal-exit: 4.1.0 signal-exit: 4.1.0
form-data@4.0.2:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
mime-types: 2.1.35
fraction.js@4.3.7: {} fraction.js@4.3.7: {}
fsevents@2.3.3: fsevents@2.3.3:
@ -2855,6 +2995,24 @@ snapshots:
gensync@1.0.0-beta.2: {} gensync@1.0.0-beta.2: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
glob-parent@5.1.2: glob-parent@5.1.2:
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
@ -2879,8 +3037,16 @@ snapshots:
globals@11.12.0: {} globals@11.12.0: {}
gopd@1.2.0: {}
graceful-fs@4.2.11: {} graceful-fs@4.2.11: {}
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2: hasown@2.0.2:
dependencies: dependencies:
function-bind: 1.1.2 function-bind: 1.1.2
@ -3016,6 +3182,8 @@ snapshots:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0
math-intrinsics@1.1.0: {}
memoize-one@6.0.0: {} memoize-one@6.0.0: {}
merge2@1.4.1: {} merge2@1.4.1: {}
@ -3025,6 +3193,12 @@ snapshots:
braces: 3.0.3 braces: 3.0.3
picomatch: 2.3.1 picomatch: 2.3.1
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
min-document@2.19.0: min-document@2.19.0:
dependencies: dependencies:
dom-walk: 0.1.2 dom-walk: 0.1.2
@ -3192,6 +3366,8 @@ snapshots:
process@0.11.10: {} process@0.11.10: {}
proxy-from-env@1.1.0: {}
quansync@0.2.8: {} quansync@0.2.8: {}
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}

3514
public/adapter.min.js vendored

File diff suppressed because it is too large Load Diff

@ -0,0 +1,381 @@
var WebRtcStreamer = (function () {
/**
* Interface with WebRTC-streamer API
* @constructor
* @param {string} videoElement - id of the video element tag
* @param {string} srvurl - url of webrtc-streamer (default is current location)
*/
var WebRtcStreamer = function WebRtcStreamer(videoElement, srvurl) {
if (typeof videoElement === "string") {
this.videoElement = document.getElementById(videoElement);
} else {
this.videoElement = videoElement;
}
this.srvurl = srvurl || location.protocol + "//" + window.location.hostname + ":" + window.location.port;
this.pc = null;
this.mediaConstraints = {
offerToReceiveAudio: true,
offerToReceiveVideo: true
};
this.iceServers = null;
this.earlyCandidates = [];
}
WebRtcStreamer.prototype._handleHttpErrors = function (response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
/**
* Connect a WebRTC Stream to videoElement
* @param {string} videourl - id of WebRTC video stream
* @param {string} audiourl - id of WebRTC audio stream
* @param {string} options - options of WebRTC call
* @param {string} stream - local stream to send
* @param {string} prefmime - prefered mime
*/
WebRtcStreamer.prototype.connect = function (videourl, audiourl, options, localstream, prefmime) {
this.disconnect();
// getIceServers is not already received
if (!this.iceServers) {
console.log("Get IceServers");
fetch(this.srvurl + "/api/getIceServers")
.then(this._handleHttpErrors)
.then((response) => (response.json()))
.then((response) => this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream, prefmime))
.catch((error) => this.onError("getIceServers " + error))
} else {
this.onReceiveGetIceServers(this.iceServers, videourl, audiourl, options, localstream, prefmime);
}
}
/**
* Disconnect a WebRTC Stream and clear videoElement source
*/
WebRtcStreamer.prototype.disconnect = function () {
if (this.videoElement?.srcObject) {
this.videoElement.srcObject.getTracks().forEach(track => {
track.stop()
this.videoElement.srcObject.removeTrack(track);
});
}
if (this.pc) {
fetch(this.srvurl + "/api/hangup?peerid=" + this.pc.peerid)
.then(this._handleHttpErrors)
.catch((error) => this.onError("hangup " + error))
try {
this.pc.close();
} catch (e) {
console.log("Failure close peer connection:" + e);
}
this.pc = null;
}
}
WebRtcStreamer.prototype.filterPreferredCodec = function (sdp, prefmime) {
const lines = sdp.split('\n');
const [prefkind, prefcodec] = prefmime.toLowerCase().split('/');
let currentMediaType = null;
let sdpSections = [];
let currentSection = [];
// Group lines into sections
lines.forEach(line => {
if (line.startsWith('m=')) {
if (currentSection.length) {
sdpSections.push(currentSection);
}
currentSection = [line];
} else {
currentSection.push(line);
}
});
sdpSections.push(currentSection);
// Process each section
const processedSections = sdpSections.map(section => {
const firstLine = section[0];
if (!firstLine.startsWith('m=' + prefkind)) {
return section.join('\n');
}
// Get payload types for preferred codec
const rtpLines = section.filter(line => line.startsWith('a=rtpmap:'));
const preferredPayloads = rtpLines
.filter(line => line.toLowerCase().includes(prefcodec))
.map(line => line.split(':')[1].split(' ')[0]);
if (preferredPayloads.length === 0) {
return section.join('\n');
}
// Modify m= line to only include preferred payloads
const mLine = firstLine.split(' ');
const newMLine = [...mLine.slice(0, 3), ...preferredPayloads].join(' ');
// Filter related attributes
const filteredLines = section.filter(line => {
if (line === firstLine) return false;
if (line.startsWith('a=rtpmap:')) {
return preferredPayloads.some(payload => line.startsWith(`a=rtpmap:${payload}`));
}
if (line.startsWith('a=fmtp:') || line.startsWith('a=rtcp-fb:')) {
return preferredPayloads.some(payload => line.startsWith(`a=${line.split(':')[0].split('a=')[1]}:${payload}`));
}
return true;
});
return [newMLine, ...filteredLines].join('\n');
});
return processedSections.join('\n');
}
/*
* GetIceServers callback
*/
WebRtcStreamer.prototype.onReceiveGetIceServers = function (iceServers, videourl, audiourl, options, stream, prefmime) {
this.iceServers = iceServers;
this.pcConfig = iceServers || {
"iceServers": []
};
try {
this.createPeerConnection();
let callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl);
if (audiourl) {
callurl += "&audiourl=" + encodeURIComponent(audiourl);
}
if (options) {
callurl += "&options=" + encodeURIComponent(options);
}
if (stream) {
this.pc.addStream(stream);
}
// clear early candidates
this.earlyCandidates.length = 0;
// create Offer
this.pc.createOffer(this.mediaConstraints).then((sessionDescription) => {
console.log("Create offer:" + JSON.stringify(sessionDescription));
console.log(`video codecs:${Array.from(new Set(RTCRtpReceiver.getCapabilities("video")?.codecs?.map(codec => codec.mimeType)))}`)
console.log(`audio codecs:${Array.from(new Set(RTCRtpReceiver.getCapabilities("audio")?.codecs?.map(codec => codec.mimeType)))}`)
if (prefmime != undefined) {
//set prefered codec
let [prefkind] = prefmime.split('/');
if (prefkind != "video" && prefkind != "audio") {
prefkind = "video";
prefmime = prefkind + "/" + prefmime;
}
console.log("sdp:" + sessionDescription.sdp);
sessionDescription.sdp = this.filterPreferredCodec(sessionDescription.sdp, prefmime);
console.log("sdp:" + sessionDescription.sdp);
}
this.pc.setLocalDescription(sessionDescription)
.then(() => {
fetch(callurl, {
method: "POST",
body: JSON.stringify(sessionDescription)
})
.then(this._handleHttpErrors)
.then((response) => (response.json()))
.catch((error) => this.onError("call " + error))
.then((response) => this.onReceiveCall(response))
.catch((error) => this.onError("call " + error))
}, (error) => {
console.log("setLocalDescription error:" + JSON.stringify(error));
});
}, (error) => {
alert("Create offer error:" + JSON.stringify(error));
});
} catch (e) {
this.disconnect();
alert("connect error: " + e);
}
}
WebRtcStreamer.prototype.getIceCandidate = function () {
fetch(this.srvurl + "/api/getIceCandidate?peerid=" + this.pc.peerid)
.then(this._handleHttpErrors)
.then((response) => (response.json()))
.then((response) => this.onReceiveCandidate(response))
.catch((error) => this.onError("getIceCandidate " + error))
}
/*
* create RTCPeerConnection
*/
WebRtcStreamer.prototype.createPeerConnection = function () {
console.log("createPeerConnection config: " + JSON.stringify(this.pcConfig));
this.pc = new RTCPeerConnection(this.pcConfig);
let pc = this.pc;
pc.peerid = Math.random();
pc.onicecandidate = (evt) => this.onIceCandidate(evt);
pc.onaddstream = (evt) => this.onAddStream(evt);
pc.oniceconnectionstatechange = (evt) => {
console.log("oniceconnectionstatechange state: " + pc.iceConnectionState);
if (this.videoElement) {
if (pc.iceConnectionState === "connected") {
this.videoElement.style.opacity = "1.0";
} else if (pc.iceConnectionState === "disconnected") {
this.videoElement.style.opacity = "0.25";
} else if ((pc.iceConnectionState === "failed") || (pc.iceConnectionState === "closed")) {
this.videoElement.style.opacity = "0.5";
} else if (pc.iceConnectionState === "new") {
this.getIceCandidate();
}
}
}
pc.ondatachannel = function (evt) {
console.log("remote datachannel created:" + JSON.stringify(evt));
evt.channel.onopen = function () {
console.log("remote datachannel open");
this.send("remote channel openned");
}
evt.channel.onmessage = function (event) {
console.log("remote datachannel recv:" + JSON.stringify(event.data));
}
}
try {
let dataChannel = pc.createDataChannel("ClientDataChannel");
dataChannel.onopen = function () {
console.log("local datachannel open");
this.send("local channel openned");
}
dataChannel.onmessage = function (evt) {
console.log("local datachannel recv:" + JSON.stringify(evt.data));
}
} catch (e) {
console.log("Cannor create datachannel error: " + e);
}
console.log("Created RTCPeerConnnection with config: " + JSON.stringify(this.pcConfig));
return pc;
}
/*
* RTCPeerConnection IceCandidate callback
*/
WebRtcStreamer.prototype.onIceCandidate = function (event) {
if (event.candidate) {
if (this.pc.currentRemoteDescription) {
this.addIceCandidate(this.pc.peerid, event.candidate);
} else {
this.earlyCandidates.push(event.candidate);
}
} else {
console.log("End of candidates.");
}
}
WebRtcStreamer.prototype.addIceCandidate = function (peerid, candidate) {
fetch(this.srvurl + "/api/addIceCandidate?peerid=" + peerid, {
method: "POST",
body: JSON.stringify(candidate)
})
.then(this._handleHttpErrors)
.then((response) => (response.json()))
.then((response) => {
console.log("addIceCandidate ok:" + response)
})
.catch((error) => this.onError("addIceCandidate " + error))
}
/*
* RTCPeerConnection AddTrack callback
*/
WebRtcStreamer.prototype.onAddStream = function (event) {
console.log("Remote track added:" + JSON.stringify(event));
this.videoElement.srcObject = event.stream;
let promise = this.videoElement.play();
if (promise !== undefined) {
promise.catch((error) => {
console.warn("error:" + error);
this.videoElement.setAttribute("controls", true);
});
}
}
/*
* AJAX /call callback
*/
WebRtcStreamer.prototype.onReceiveCall = function (dataJson) {
console.log("offer: " + JSON.stringify(dataJson));
let descr = new RTCSessionDescription(dataJson);
this.pc.setRemoteDescription(descr).then(() => {
console.log("setRemoteDescription ok");
while (this.earlyCandidates.length) {
let candidate = this.earlyCandidates.shift();
this.addIceCandidate(this.pc.peerid, candidate);
}
this.getIceCandidate()
}, (error) => {
console.log("setRemoteDescription error:" + JSON.stringify(error));
});
}
/*
* AJAX /getIceCandidate callback
*/
WebRtcStreamer.prototype.onReceiveCandidate = function (dataJson) {
console.log("candidate: " + JSON.stringify(dataJson));
if (dataJson) {
for (let i = 0; i < dataJson.length; i++) {
let candidate = new RTCIceCandidate(dataJson[i]);
console.log("Adding ICE candidate :" + JSON.stringify(candidate));
this.pc.addIceCandidate(candidate).then(() => {
console.log("addIceCandidate OK");
}, (error) => {
console.log("addIceCandidate error:" + JSON.stringify(error));
});
}
this.pc.addIceCandidate();
}
}
/*
* AJAX callback for Error
*/
WebRtcStreamer.prototype.onError = function (status) {
console.log("onError:" + status);
}
return WebRtcStreamer;
})();
if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {
window.WebRtcStreamer = WebRtcStreamer;
}
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = WebRtcStreamer;
}

@ -0,0 +1,29 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-12 15:13:38
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-12 19:20:43
* @FilePath: \5G-Loading-Bay-Web\src\api\user.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from '@/utils/request/instance'
import { config } from '@/config'
// 定义响应类型
interface LoginRes {
token: string
userInfo: {
id: number
username: string
}
}
export const loginApi = (data: { username: string; password: string }) => {
return request.post<LoginRes>(`${config.baseURL}/api/v1/user/login`, data, {
showLoading: false // 单独关闭loading
})
}
// export const getUserInfo = (userId: number) => {
// return request.get(`/user/info/${userId}`)
// }

@ -74,6 +74,7 @@
padding: 4px 0; padding: 4px 0;
} }
.baseTable_box { .baseTable_box {
cursor: default;
.el-table__body { .el-table__body {
background: linear-gradient(90deg, #082050 0%, #02102a 100%); background: linear-gradient(90deg, #082050 0%, #02102a 100%);
tr { tr {

@ -1,4 +1,46 @@
<template> <template>
<!-- 实时视频播放器 --> <div class="video-player">
</template> <video ref="refPlayer" autoplay controls muted width="100%" height="100%" style="object-fit: fill;"></video>
<!-- <iframe src="http://192.168.10.113:8889/cam/" frameborder="0"></iframe> -->
</div>
<!-- http://192.168.10.113:8889/cam/ -->
</template>
<script setup lang="ts">
import { nextTick } from 'vue';
const webRtcServer = ref(null);
const refPlayer = ref(null);
const videoSrc = 'rtsp://192.168.10.63:8554/mystream';
function initData() {
webRtcServer.value.connect(videoSrc || '', '', "rtptransport=tcp&timeout=60&width=320&height=0");
}
onMounted(() => {
//
// let srvUrl = 'http://127.0.0.1:8000';
nextTick(() => {
console.log(location.protocol, "refPlayer");
// TODO
webRtcServer.value = new WebRtcStreamer(refPlayer.value, `http://192.168.10.26:9988`);
nextTick(() => {
videoSrc && initData();
})
})
})
onUnmounted(() => {
webRtcServer.disconnect();
webRtcServer.value = null;
})
</script>
<style lang="scss">
.video-player {
position: fixed;
width: 50%;
z-index: 999999999;
}
</style>

@ -0,0 +1,13 @@
const env = import.meta.env
export const config = {
env: env.VITE_APP_ENV,
baseURL: env.VITE_APP_BASE_API,
timeout: 10000,
url: '',
showLoading: false,
loadingInstance: null,
// uploadURL: env.VITE_APP_UPLOAD_URL,
// appName: env.VITE_APP_NAME,
// version: env.VITE_APP_VERSION
}

12
src/env.d.ts vendored

@ -0,0 +1,12 @@
interface ImportMetaEnv {
readonly VITE_APP_ENV: 'development' | 'staging' | 'production'
readonly VITE_APP_BASE_API: string
readonly VITE_APP_UPLOAD_URL: string
readonly VITE_APP_NAME: string
readonly VITE_APP_VERSION: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 13:56:12 * @Date: 2025-03-06 13:56:12
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-07 10:40:22 * @LastEditTime: 2025-03-12 16:46:39
* @FilePath: \vite-ai\data-dashboard\src\views\dashboard\home.vue * @FilePath: \vite-ai\data-dashboard\src\views\dashboard\home.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
--> -->

@ -2,18 +2,10 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 17:57:05 * @Date: 2025-03-06 17:57:05
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-10 13:51:54 * @LastEditTime: 2025-03-12 15:20:34
* @FilePath: \5G-Loading-Bay-Web\src\stores\user.ts * @FilePath: \5G-Loading-Bay-Web\src\stores\user.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 13:51:46
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-10 13:40:39
* @FilePath: \vite-ai\data-dashboard\src\stores\user.ts
* @Description:
*/
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import router, { resetRouter } from "@/router"; import router, { resetRouter } from "@/router";
import { getLocal, setLocal, removeLocal} from "@/utils/local"; import { getLocal, setLocal, removeLocal} from "@/utils/local";
@ -39,8 +31,8 @@ export const useUserStore = defineStore("user", {
logout() { logout() {
this.token = null; this.token = null;
removeLocal("token"); removeLocal("token");
resetRouter(); // resetRouter();
router.replace("/login"); // router.replace("/login");
}, },
}, },
}); });

@ -0,0 +1,10 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-12 18:59:29
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-12 18:59:36
* @FilePath: \5G-Loading-Bay-Web\src\utils\request.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
// src/utils/request.ts
const baseURL = import.meta.env.VITE_APP_BASE_API

@ -0,0 +1,107 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-12 15:11:56
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-12 15:12:06
* @FilePath: \5G-Loading-Bay-Web\src\utils\request\index.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { RequestConfig, RequestInterceptors } from './type'
import { useUserStore } from '@/stores/user'
class Request {
instance: AxiosInstance
interceptors?: RequestInterceptors
constructor(config: RequestConfig) {
this.instance = axios.create(config)
this.interceptors = config.interceptors
// 全局请求拦截器
this.instance.interceptors.request.use(
(config: RequestConfig) => {
// 处理 token
const userStore = useUserStore()
if (userStore.token) {
config.headers!.Authorization = `Bearer ${userStore.token}`
}
return config
},
(error: any) => Promise.reject(error)
)
// 实例拦截器
this.instance.interceptors.request.use(
this.interceptors?.requestInterceptor,
this.interceptors?.requestInterceptorCatch
)
this.instance.interceptors.response.use(
this.interceptors?.responseInterceptor,
this.interceptors?.responseInterceptorCatch
)
// 全局响应拦截器
this.instance.interceptors.response.use(
(res: AxiosResponse) => {
const { code, message } = res.data
if (code !== 200) {
ElMessage.error(message || '请求失败')
return Promise.reject(message)
}
return res.data
},
(error: any) => {
// 处理 HTTP 状态码
if (error.response?.status === 401) {
ElMessageBox.confirm('登录已过期,请重新登录', '提示', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const userStore = useUserStore()
userStore.logout()
location.reload()
})
}
ElMessage.error(error.message || '请求错误')
return Promise.reject(error)
}
)
}
request<T = any>(config: RequestConfig<T>): Promise<T> {
return new Promise((resolve, reject) => {
// 单个请求的拦截器
if (config.interceptors?.requestInterceptor) {
config = config.interceptors.requestInterceptor(config)
}
this.instance
.request<any, T>(config)
.then(res => {
if (config.interceptors?.responseInterceptor) {
res = config.interceptors.responseInterceptor(res)
}
resolve(res)
})
.catch(err => {
reject(err)
})
})
}
get<T = any>(url: string, config?: RequestConfig<T>): Promise<T> {
return this.request<T>({ ...config, method: 'GET', url })
}
post<T = any>(url: string, data?: any, config?: RequestConfig<T>): Promise<T> {
return this.request<T>({ ...config, method: 'POST', url, data })
}
// 其他方法类似...
}
export default Request

@ -0,0 +1,50 @@
import Request from './index'
import { config } from '@/config'
import { ElLoading } from "element-plus";
// 根据环境显示不同提示
const envTagMap = {
development: '【开发环境】',
// staging: '【测试环境】',
production: '【生产环境】'
}
const request = new Request({
baseURL: config.baseURL,
timeout: config.timeout,
interceptors: {
requestInterceptor: config => {
// 开发环境显示环境标识
if (import.meta.env.DEV) {
console.log(`${envTagMap[config.env]} 请求路径: ${config.url}`)
}
// 全局 loading 配置
if (config.showLoading !== false) {
const loading = ElLoading.service({
lock: true,
text: '加载中...',
background: 'rgba(0, 0, 0, 0.7)'
})
config.loadingInstance = loading
}
return config
},
responseInterceptor: res => {
// 关闭 loading
res.config.loadingInstance?.close()
// 测试环境记录详细日志
// if (config.env === 'staging') {
// console.groupCollapsed(`[${res.config.method}] ${res.config.url}`)
// console.log('请求参数:', res.config.data)
// console.log('响应数据:', res.data)
// console.groupEnd()
// }
return res
}
}
})
export default request

@ -0,0 +1,13 @@
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
export interface RequestInterceptors<T = AxiosResponse> {
requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
requestInterceptorCatch?: (error: any) => any
responseInterceptor?: (res: T) => T
responseInterceptorCatch?: (error: any) => any
}
export interface RequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
interceptors?: RequestInterceptors<T>
showLoading?: boolean
}

@ -9,8 +9,9 @@
</ContentHeader> </ContentHeader>
</div> </div>
<div class="px-[16px] device-status-content-box"> <div class="px-[16px] device-status-content-box">
<div class="mt-[16px] bg-transparent baseTable_wrap full_table" v-loading="dataLoading" :element-loading-svg="svg" <HistoryVideoModal />
element-loading-svg-view-box="-10, -10, 50, 50"> <div class="mt-[16px] bg-transparent baseTable_wrap full_table" v-loading="dataLoading"
:element-loading-svg="svg" element-loading-svg-view-box="-10, -10, 50, 50">
<template v-if="pagination.total > 0"> <template v-if="pagination.total > 0">
<BaseTable class="bg-transparent baseTable_box" :total="pagination.total" <BaseTable class="bg-transparent baseTable_box" :total="pagination.total"
:pageSize="pagination.pageSize" :dataSource="listData" :isFixedPagination="true" :pageSize="pagination.pageSize" :dataSource="listData" :isFixedPagination="true"
@ -52,10 +53,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { BaseTable } from "@/components/CustomTable"; import { BaseTable } from "@/components/CustomTable";
import ContentHeader from '@/components/ContentHeader.vue'; import ContentHeader from '@/components/ContentHeader.vue';
import HistoryVideoModal from './components/HistoryVideoModal.vue';
import onLineIcon from '@/assets/common/online_icon.png'; import onLineIcon from '@/assets/common/online_icon.png';
import outLineIcon from '@/assets/common/outline_icon.png'; import outLineIcon from '@/assets/common/outline_icon.png';
import errorIcon from '@/assets/common/error_icon.png'; import errorIcon from '@/assets/common/error_icon.png';
import Demo from '../../components/videoPlayer/Demo.vue';
defineOptions({ defineOptions({
name: "DeviceStatusIndex" name: "DeviceStatusIndex"
}); });

@ -0,0 +1,93 @@
.pole-monitor-wrap {
background-image: url("@/assets/common/bg_banner_1.png");
background-size: cover;
background-position: bottom;
background-repeat: no-repeat;
height: 823px;
.search-section {
padding: 16px 0;
}
.pole-main-content {
width: 100%;
}
.pole-monitor-search-box {
display: flex;
align-items: center;
gap: 12px;
margin: 16px 0;
}
.right-panel {
.el-scrollbar__view {
background: transparent !important;
height: 600px;
}
}
.pole-monitor-main {
.left-panel {
.main-image {
box-sizing: border-box;
min-height: 511px;
position: relative;
background-color: #090F48;
border-radius: 4px;
img {
width: 100%;
max-height: 460px;
}
.image-info{
position: absolute;
height: 52px;
line-height: 52px;
bottom: 0;
font-size: 14px;
padding: 0 16px;
&> span {
margin-right: 10px;
}
}
}
.thumbnail-container {
width: 100%;
overflow: visible;
.swiper {
width: 100%;
height: 100%;
.swiper-slide {
width: 20%;
border-radius: 4px;
img {
width: 100%;
height: 144px;
border-radius: 4px;
}
}
.active-slide img {
border-radius: 4px;
border: 2px solid #2ecce0;
}
.swiper-button-prev,
.swiper-button-next {
background-color: rgba(0, 0, 0, 0.5);
color: white;
width: 32px;
height: 32px;
border-radius: 50%;
}
.swiper-button-prev::after,
.swiper-button-next::after {
font-size: 12px;
color: #fff;
}
/* 修改按钮悬停样式 */
.swiper-button-prev:hover,
.swiper-button-next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
}
}
}
}
}

@ -1,19 +1,9 @@
.pole-monitor-wrap { .pole-monitor-wrap {
background-image: url("@/assets/common/bg_banner.png"); background-image: url("@/assets/common/bg_banner_1.png");
// background-color: red; background-size: cover;
background-size: contain; background-position: bottom;
background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
.bg_footer_desp{ height: 823px;
width: 100%;
height: 20px;
background-image: url("@/assets/common/bg_banner_footer.png");
// background-color: red;
background-size: contain;
background-position: bottom center;
background-repeat: no-repeat;
}
.search-section { .search-section {
padding: 16px 0; padding: 16px 0;
} }
@ -37,10 +27,24 @@
.left-panel { .left-panel {
.main-image { .main-image {
box-sizing: border-box; box-sizing: border-box;
min-height: 512px; min-height: 511px;
position: relative;
background-color: #090F48;
border-radius: 4px;
img { img {
width: 100%; width: 100%;
height: 512px; max-height: 460px;
}
.image-info{
position: absolute;
height: 52px;
line-height: 52px;
bottom: 0;
font-size: 14px;
padding: 0 16px;
&> span {
margin-right: 10px;
}
} }
} }
.thumbnail-container { .thumbnail-container {

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 15:15:01 * @Date: 2025-03-06 15:15:01
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-12 14:31:43 * @LastEditTime: 2025-03-12 15:01:18
* @FilePath: \vite-ai\data-dashboard\src\views\dashboard\PoleMonitor.vue * @FilePath: \vite-ai\data-dashboard\src\views\dashboard\PoleMonitor.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
--> -->
@ -47,15 +47,19 @@
<div class="left-panel w-[870px]"> <div class="left-panel w-[870px]">
<!-- 主图显示 --> <!-- 主图显示 -->
<div class="main-image"> <div class="main-image">
<img src="https://picsum.photos/300/200?random=1" alt="监控画面"> <img src="https://picsum.photos/300/200?random=1" alt="监控画面">
<!-- <div class="image-info"> <div class="image-info">
: 35cm : 52cm : 28cm 体积: 50960cm 重量: 58kg <span>: 35cm</span>
</div> --> <span>: 35cm</span>
<span>: 28cm</span>
<span>体积: 50960</span>
<span>重量: 58kg</span>
</div>
</div> </div>
<!-- 缩略图区域 --> <!-- 缩略图区域 -->
<div class="thumbnail-container"> <div class="thumbnail-container mt-[16px]">
<swiper ref="swiperRef" :modules="modules" :slides-per-view="4" :space-between="10" navigation <swiper ref="swiperRef" :modules="modules" :slides-per-view="3" :space-between="10" navigation
:scrollbar="{ draggable: false }" :centered-slides="false" :observer="true" :scrollbar="{ draggable: false }" :centered-slides="false" :observer="true"
:observeParents="true" @swiper="onSwiper" @slideChange="onSlideChange"> :observeParents="true" @swiper="onSwiper" @slideChange="onSlideChange">
<swiper-slide v-for="(image, index) in images" :key="index" @click="handleSlideClick(index)" <swiper-slide v-for="(image, index) in images" :key="index" @click="handleSlideClick(index)"
@ -78,8 +82,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="bg_footer_desp"> <!-- <div class="bg_footer_desp">
</div> </div> -->
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

@ -0,0 +1,47 @@
<template>
<div class="video-player">
<video ref="refPlayer" autoplay controls muted width="100%" height="100%" style="object-fit: fill;"></video>
<!-- <iframe src="http://192.168.10.113:8889/cam/" frameborder="0"></iframe> -->
</div>
<!-- http://192.168.10.113:8889/cam/ -->
</template>
<script setup lang="ts">
import { nextTick } from 'vue';
const webRtcServer = ref(null);
const refPlayer = ref(null);
const videoSrc = 'rtsp://192.168.10.63:8554/mystream';
function initData() {
webRtcServer.value.connect(videoSrc || '', '', "rtptransport=tcp&timeout=60&width=320&height=0");
}
onMounted(() => {
//
// let srvUrl = 'http://127.0.0.1:8000';
nextTick(() => {
console.log(location.protocol, "refPlayer");
// TODO
webRtcServer.value = new WebRtcStreamer(refPlayer.value, `http://192.168.10.26:9988`);
nextTick(() => {
videoSrc && initData();
})
})
})
onUnmounted(() => {
webRtcServer.disconnect();
webRtcServer.value = null;
})
</script>
<style lang="scss">
.video-player {
position: fixed;
width: 50%;
z-index: 999999999;
}
</style>

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 17:57:05 * @Date: 2025-03-06 17:57:05
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-11 15:40:59 * @LastEditTime: 2025-03-12 19:39:47
* @FilePath: \5G-Loading-Bay-Web\src\views\login\Login.vue * @FilePath: \5G-Loading-Bay-Web\src\views\login\Login.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE? * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE?
--> -->
@ -50,6 +50,7 @@ import { useRouter } from 'vue-router'
import accountIconUrl from '@/assets/login/account_icon.png'; import accountIconUrl from '@/assets/login/account_icon.png';
import passwordIconUrl from '@/assets/login/password_icon.png'; import passwordIconUrl from '@/assets/login/password_icon.png';
import { getLocal} from "@/utils/local"; import { getLocal} from "@/utils/local";
import { loginApi } from '@/api/user'
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
@ -59,6 +60,18 @@ const form = reactive({
password: '', password: '',
remember: false remember: false
}) })
// TODO
// const handleLogin = async () => {
// try {
// const res = await loginApi({
// username: 'admin',
// password: 'admin123'
// })
// ElMessage.success(`${res.userInfo.username}`)
// } catch (error) {
// console.error(':', error)
// }
// }
const handleLogin = async () => { const handleLogin = async () => {
if (form.username !== 'admin' || form.password !== 'admin123') { if (form.username !== 'admin' || form.password !== 'admin123') {

1
src/vite-env.d.ts vendored

@ -1 +0,0 @@
/// <reference types="vite/client" />

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 11:27:03 * @Date: 2025-03-06 11:27:03
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-07 14:35:23 * @LastEditTime: 2025-03-12 19:38:36
* @FilePath: \vite-ai\data-dashboard\vite.config.ts * @FilePath: \vite-ai\data-dashboard\vite.config.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
@ -42,8 +42,21 @@ export default defineConfig(({ mode }) => {
} }
}) })
], ],
server: { // 开发服务器配置
port: parseInt(env.VITE_PORT) || 5050 server: {
port: 5050,
proxy: {
'/api': {
target: env.VITE_APP_BASE_API,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
// 生产构建配置
build: {
outDir: mode === 'staging' ? 'dist-staging' : 'dist',
sourcemap: mode !== 'production' // 生产环境关闭 sourcemap
}, },
define: { define: {
'process.env': env 'process.env': env

Loading…
Cancel
Save