字段调整
This commit is contained in:
parent
a4ba10534c
commit
6c25f21f19
18
index.html
18
index.html
|
@ -1,13 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="zh_CN" id="htmlRoot">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" />
|
||||
|
||||
<title><%= title %></title>
|
||||
<link rel="icon" href="<%= basePublicPath %>/logo.png" />
|
||||
|
@ -170,13 +167,14 @@
|
|||
<!-- 百度统计 -->
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?0febd9e3cacb3f627ddac64d52caac39";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
(function () {
|
||||
var hm = document.createElement('script');
|
||||
hm.src = 'https://hm.baidu.com/hm.js?0febd9e3cacb3f627ddac64d52caac39';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- 腾讯地图 -->
|
||||
<script src="https://map.qq.com/api/gljs?v=1.exp&key=2E6BZ-ZC3E3-BMX3D-OWFUI-FLY2F-MLFFJ"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
27
package.json
27
package.json
|
@ -21,18 +21,19 @@
|
|||
"husky:install": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jeecg/online": "3.7.1-RC",
|
||||
"@iconify/iconify": "^3.1.1",
|
||||
"@ant-design/colors": "^7.2.0",
|
||||
"@ant-design/icons-vue": "^7.0.1",
|
||||
"@iconify/iconify": "^3.1.1",
|
||||
"@jeecg/online": "3.7.1-RC",
|
||||
"@tinymce/tinymce-vue": "4.0.7",
|
||||
"@traptitech/markdown-it-katex": "^3.6.0",
|
||||
"@vant/area-data": "^1.5.2",
|
||||
"@vue/shared": "^3.5.13",
|
||||
"@vueuse/core": "^10.11.1",
|
||||
"@tinymce/tinymce-vue": "4.0.7",
|
||||
"@zxcvbn-ts/core": "^3.0.4",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"axios": "^1.7.9",
|
||||
"china-area-data": "^5.0.1",
|
||||
"@vant/area-data": "^1.5.2",
|
||||
"clipboard": "^2.0.11",
|
||||
"codemirror": "^5.65.18",
|
||||
"cron-parser": "^4.9.0",
|
||||
|
@ -43,14 +44,13 @@
|
|||
"echarts": "^5.6.0",
|
||||
"emoji-mart-vue-fast": "^15.0.3",
|
||||
"enquire.js": "^2.1.6",
|
||||
"event-source-polyfill": "^1.0.31",
|
||||
"highlight.js": "^11.11.1",
|
||||
"intro.js": "^7.2.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lodash.get": "^4.4.2",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-link-attributes": "^4.0.1",
|
||||
"event-source-polyfill": "^1.0.31",
|
||||
"highlight.js": "^11.11.1",
|
||||
"@traptitech/markdown-it-katex": "^3.6.0",
|
||||
"md5": "^2.3.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
|
@ -69,6 +69,7 @@
|
|||
"vue-cropperjs": "^5.0.0",
|
||||
"vue-i18n": "^9.14.2",
|
||||
"vue-infinite-scroll": "^2.0.2",
|
||||
"vue-jsonp": "^2.1.0",
|
||||
"vue-print-nb-jeecg": "^1.0.12",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-types": "^5.1.3",
|
||||
|
@ -83,6 +84,7 @@
|
|||
"@commitlint/config-conventional": "^18.6.3",
|
||||
"@iconify/json": "^2.2.292",
|
||||
"@purge-icons/generated": "^0.10.0",
|
||||
"@rys-fe/vite-plugin-theme": "^0.8.6",
|
||||
"@types/codemirror": "^5.60.15",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
|
@ -104,11 +106,13 @@
|
|||
"@vue/compiler-sfc": "^3.5.13",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"big.js": "^6.2.2",
|
||||
"commitizen": "^4.3.1",
|
||||
"conventional-changelog-cli": "^4.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"cz-git": "^1.11.0",
|
||||
"czg": "^1.11.0",
|
||||
"dingtalk-jsapi": "^3.0.42",
|
||||
"dotenv": "^16.4.7",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
|
@ -144,6 +148,7 @@
|
|||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^4.9.5",
|
||||
"unocss": "^0.58.9",
|
||||
"vite": "^6.0.7",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
|
@ -152,15 +157,11 @@
|
|||
"vite-plugin-optimize-persist": "^0.1.2",
|
||||
"vite-plugin-package-config": "^0.1.1",
|
||||
"vite-plugin-purge-icons": "^0.10.0",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vite-plugin-qiankun": "^1.0.15",
|
||||
"@rys-fe/vite-plugin-theme": "^0.8.6",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vite-plugin-vue-setup-extend-plus": "^0.1.0",
|
||||
"unocss": "^0.58.9",
|
||||
"vue-eslint-parser": "^9.4.3",
|
||||
"vue-tsc": "^1.8.27",
|
||||
"dingtalk-jsapi": "^3.0.42",
|
||||
"big.js": "^6.2.2"
|
||||
"vue-tsc": "^1.8.27"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
<template>
|
||||
<div class="map-wrapper">
|
||||
<div id="map-container" ref="mapContainer" style="width: 100%; height: 300px;"></div>
|
||||
<button @click="resetMap" class="reset-button">复位视图</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
latitude: {
|
||||
type: Number,
|
||||
default: 43.8171 // 长春市纬度
|
||||
},
|
||||
longitude: {
|
||||
type: Number,
|
||||
default: 125.3235 // 长春市经度
|
||||
}
|
||||
});
|
||||
|
||||
const mapContainer = ref<HTMLElement | null>(null);
|
||||
let map: any = null;
|
||||
let marker: any = null;
|
||||
|
||||
// 初始化地图(确保交互正常)
|
||||
const initMap = () => {
|
||||
if (!mapContainer.value) return;
|
||||
|
||||
// 创建地图实例(关键配置)
|
||||
map = new TMap.Map(mapContainer.value, {
|
||||
center: new TMap.LatLng(props.latitude, props.longitude),
|
||||
zoom: 14,
|
||||
pitch: 40,
|
||||
rotation: 0,
|
||||
viewMode: '2D', // 必须设置为3D才能旋转
|
||||
dragEnable: true, // 启用拖动
|
||||
zoomEnable: true, // 启用缩放
|
||||
});
|
||||
|
||||
console.log("地图初始化完成");
|
||||
|
||||
// 添加标记
|
||||
addMarker(new TMap.LatLng(props.latitude, props.longitude));
|
||||
};
|
||||
|
||||
// 添加图钉标记
|
||||
const addMarker = (position: any) => {
|
||||
if (marker) {
|
||||
map.remove(marker);
|
||||
}
|
||||
|
||||
marker = new TMap.MultiMarker({
|
||||
map: map,
|
||||
styles: {
|
||||
marker: new TMap.MarkerStyle({
|
||||
width: 20,
|
||||
height: 30,
|
||||
anchor: { x: 10, y: 30 }
|
||||
})
|
||||
},
|
||||
geometries: [{
|
||||
id: 'location-marker',
|
||||
position: position,
|
||||
properties: {
|
||||
title: '目标位置'
|
||||
},
|
||||
styleId: 'marker'
|
||||
}]
|
||||
});
|
||||
};
|
||||
|
||||
// 复位功能
|
||||
const resetMap = () => {
|
||||
if (!map) {
|
||||
console.error("地图对象为空");
|
||||
return;
|
||||
}
|
||||
|
||||
map.setCenter(new TMap.LatLng(props.latitude, props.longitude));
|
||||
map.setZoom(14);
|
||||
map.setPitch(40);
|
||||
map.setRotation(0);
|
||||
};
|
||||
|
||||
// 监听坐标变化
|
||||
watch(() => [props.latitude, props.longitude], () => {
|
||||
if (!map) return;
|
||||
|
||||
const newCenter = new TMap.LatLng(props.latitude, props.longitude);
|
||||
map.setCenter(newCenter);
|
||||
addMarker(newCenter);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 确保TMap加载完成
|
||||
if (window.TMap) {
|
||||
initMap();
|
||||
} else {
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://map.qq.com/api/gljs?v=1.exp&key=YOUR_KEY';
|
||||
script.onload = initMap; // 加载完成后调用 initMap
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.map-wrapper {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
margin-left: 5%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.reset-button {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 25px;
|
||||
padding: 8px;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
width: 50px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.reset-button:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
</style>
|
|
@ -1,54 +1,43 @@
|
|||
<template>
|
||||
<div class="terminal-container">
|
||||
<div class="terminal-header">
|
||||
<span>SSH终端</span>
|
||||
<div>
|
||||
<a-button @click="connect" type="primary" size="small">连接</a-button>
|
||||
<a-button @click="disconnect" size="small" style="margin-left: 8px">断开</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="terminal-container">
|
||||
<div class="terminal-header">
|
||||
<span>SSH终端</span>
|
||||
<div>
|
||||
<a-button @click="connect" type="primary" size="small">连接</a-button>
|
||||
<a-button @click="disconnect" size="small" style="margin-left: 8px">断开</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="terminal-body" ref="terminalBody">
|
||||
<div v-for="(line, index) in outputLines" :key="index" class="terminal-line">
|
||||
<span v-if="line.type === 'input'" class="input-prompt">$ </span>
|
||||
<span :class="line.type">{{ line.text }}</span>
|
||||
</div>
|
||||
<div class="terminal-input-line">
|
||||
<span class="input-prompt">$ </span>
|
||||
<input
|
||||
v-model="currentCommand"
|
||||
@keyup.enter="executeCommand"
|
||||
@keyup.up="historyUp"
|
||||
@keyup.down="historyDown"
|
||||
ref="commandInput"
|
||||
class="terminal-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="terminal-body" ref="terminalBody">
|
||||
<div v-for="(line, index) in outputLines" :key="index" class="terminal-line">
|
||||
<span v-if="line.type === 'input'" class="input-prompt">$ </span>
|
||||
<span :class="line.type">{{ line.text }}</span>
|
||||
</div>
|
||||
<div class="terminal-input-line">
|
||||
<span class="input-prompt">$ </span>
|
||||
<input v-model="currentCommand" @keyup.enter="executeCommand" @keyup.up="historyUp"
|
||||
@keyup.down="historyDown" ref="commandInput" class="terminal-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-modal
|
||||
v-model:visible="connectionModalVisible"
|
||||
title="SSH连接配置"
|
||||
@ok="handleConnect"
|
||||
:ok-button-props="{ disabled: connecting }"
|
||||
:cancel-button-props="{ disabled: connecting }"
|
||||
>
|
||||
<a-form :model="connectionForm" :rules="formRules" layout="vertical">
|
||||
<a-form-item label="主机地址" name="host">
|
||||
<a-input v-model:value="connectionForm.host" />
|
||||
</a-form-item>
|
||||
<a-form-item label="端口" name="port">
|
||||
<a-input-number v-model:value="connectionForm.port" :min="1" :max="65535" />
|
||||
</a-form-item>
|
||||
<a-form-item label="用户名" name="username">
|
||||
<a-input v-model:value="connectionForm.username" />
|
||||
</a-form-item>
|
||||
<a-form-item label="密码" name="password">
|
||||
<a-input-password v-model:value="connectionForm.password" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</div>
|
||||
<a-modal v-model:visible="connectionModalVisible" title="SSH连接配置" @ok="handleConnect"
|
||||
:ok-button-props="{ disabled: connecting }" :cancel-button-props="{ disabled: connecting }">
|
||||
<a-form :model="connectionForm" :rules="formRules" layout="vertical">
|
||||
<a-form-item label="主机地址" name="host">
|
||||
<a-input v-model:value="connectionForm.host" />
|
||||
</a-form-item>
|
||||
<a-form-item label="端口" name="port">
|
||||
<a-input-number v-model:value="connectionForm.port" :min="1" :max="65535" />
|
||||
</a-form-item>
|
||||
<a-form-item label="用户名" name="username">
|
||||
<a-input v-model:value="connectionForm.username" />
|
||||
</a-form-item>
|
||||
<a-form-item label="密码" name="password">
|
||||
<a-input-password v-model:value="connectionForm.password" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -56,254 +45,301 @@ import { defineComponent, ref, nextTick, onMounted, onBeforeUnmount } from 'vue'
|
|||
import { message } from 'ant-design-vue'
|
||||
|
||||
interface TerminalLine {
|
||||
type: 'input' | 'output' | 'error' | 'system'
|
||||
text: string
|
||||
type: 'input' | 'output' | 'error' | 'system'
|
||||
text: string
|
||||
}
|
||||
|
||||
interface ConnectionForm {
|
||||
host: string
|
||||
port: number
|
||||
username: string
|
||||
password: string
|
||||
host: string
|
||||
port: number
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SshTerminal',
|
||||
setup() {
|
||||
const outputLines = ref<TerminalLine[]>([])
|
||||
const currentCommand = ref('')
|
||||
const commandHistory = ref<string[]>([])
|
||||
const historyIndex = ref(-1)
|
||||
const connectionModalVisible = ref(false)
|
||||
const connecting = ref(false)
|
||||
const connected = ref(false)
|
||||
const socket = ref<WebSocket | null>(null)
|
||||
const terminalBody = ref<HTMLElement | null>(null)
|
||||
const commandInput = ref<HTMLInputElement | null>(null)
|
||||
name: 'SshTerminal',
|
||||
setup() {
|
||||
const outputLines = ref<TerminalLine[]>([])
|
||||
const currentCommand = ref('')
|
||||
const commandHistory = ref<string[]>([])
|
||||
const historyIndex = ref(-1)
|
||||
const connectionModalVisible = ref(false)
|
||||
const connecting = ref(false)
|
||||
const connected = ref(false)
|
||||
const socket = ref<WebSocket | null>(null)
|
||||
const terminalBody = ref<HTMLElement | null>(null)
|
||||
const commandInput = ref<HTMLInputElement | null>(null)
|
||||
|
||||
const connectionForm = ref<ConnectionForm>({
|
||||
host: '',
|
||||
port: 22,
|
||||
username: '',
|
||||
password: ''
|
||||
})
|
||||
const connectionForm = ref<ConnectionForm>({
|
||||
host: '121.36.88.64',
|
||||
port: 22,
|
||||
username: '',
|
||||
password: ''
|
||||
})
|
||||
|
||||
const formRules = {
|
||||
host: [{ required: true, message: '请输入主机地址' }],
|
||||
port: [{ required: true, message: '请输入端口' }],
|
||||
username: [{ required: true, message: '请输入用户名' }],
|
||||
password: [{ required: true, message: '请输入密码' }]
|
||||
}
|
||||
|
||||
const clientId = Math.random().toString(36).substring(2, 10)
|
||||
|
||||
const addOutput = (type: TerminalLine['type'], text: string) => {
|
||||
outputLines.value.push({ type, text })
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
const scrollToBottom = () => {
|
||||
nextTick(() => {
|
||||
if (terminalBody.value) {
|
||||
terminalBody.value.scrollTop = terminalBody.value.scrollHeight
|
||||
const formRules = {
|
||||
host: [{ required: true, message: '请输入主机地址' }],
|
||||
port: [{ required: true, message: '请输入端口' }],
|
||||
username: [{ required: true, message: '请输入用户名' }],
|
||||
password: [{ required: true, message: '请输入密码' }]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const connect = () => {
|
||||
connectionModalVisible.value = true
|
||||
}
|
||||
const clientId = Math.random().toString(36).substring(2, 10)
|
||||
|
||||
const handleConnect = () => {
|
||||
connecting.value = true
|
||||
initWebSocket()
|
||||
}
|
||||
|
||||
const initWebSocket = () => {
|
||||
const wsUrl = `ws://${window.location.host}/jeecg-boot/ws/ssh/${clientId}`
|
||||
socket.value = new WebSocket(wsUrl)
|
||||
|
||||
socket.value.onopen = () => {
|
||||
const { host, port, username, password } = connectionForm.value
|
||||
const connectMsg = `connect:${host}:${port}:${username}:${password}`
|
||||
socket.value?.send(connectMsg)
|
||||
connected.value = true
|
||||
connecting.value = false
|
||||
connectionModalVisible.value = false
|
||||
addOutput('system', 'SSH连接已建立')
|
||||
}
|
||||
|
||||
socket.value.onmessage = (event) => {
|
||||
addOutput('output', event.data)
|
||||
}
|
||||
|
||||
socket.value.onerror = (error) => {
|
||||
addOutput('error', '连接错误: ' + error)
|
||||
connecting.value = false
|
||||
connected.value = false
|
||||
}
|
||||
|
||||
socket.value.onclose = () => {
|
||||
if (connected.value) {
|
||||
addOutput('system', 'SSH连接已断开')
|
||||
const addOutput = (type: TerminalLine['type'], text: string) => {
|
||||
outputLines.value.push({ type, text })
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
const scrollToBottom = () => {
|
||||
nextTick(() => {
|
||||
if (terminalBody.value) {
|
||||
terminalBody.value.scrollTop = terminalBody.value.scrollHeight
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const connect = () => {
|
||||
connectionModalVisible.value = true
|
||||
}
|
||||
|
||||
const handleConnect = () => {
|
||||
connecting.value = true
|
||||
initWebSocket()
|
||||
}
|
||||
|
||||
const initWebSocket = () => {
|
||||
const wsUrl = `ws://localhost:8080/nursing-unit/ws/ssh/${clientId}`
|
||||
socket.value = new WebSocket(wsUrl)
|
||||
|
||||
socket.value.onopen = () => {
|
||||
const { host, port, username, password } = connectionForm.value
|
||||
const connectMsg = `connect:${host}:${port}:${username}:${password}`
|
||||
socket.value?.send(connectMsg)
|
||||
connected.value = true
|
||||
connecting.value = false
|
||||
connectionModalVisible.value = false
|
||||
addOutput('system', 'SSH连接已建立')
|
||||
}
|
||||
|
||||
socket.value.onmessage = (event) => {
|
||||
addOutput('output', event.data)
|
||||
}
|
||||
|
||||
socket.value.onerror = (error) => {
|
||||
addOutput('error', '连接错误: ' + error)
|
||||
connecting.value = false
|
||||
connected.value = false
|
||||
}
|
||||
|
||||
socket.value.onclose = () => {
|
||||
if (connected.value) {
|
||||
addOutput('system', 'SSH连接已断开')
|
||||
}
|
||||
connected.value = false
|
||||
connecting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const disconnect = () => {
|
||||
if (connected.value && socket.value) {
|
||||
socket.value.send('disconnect')
|
||||
socket.value.close()
|
||||
}
|
||||
}
|
||||
|
||||
const executeCommand = () => {
|
||||
if (!currentCommand.value.trim()) return
|
||||
|
||||
if (!connected.value) {
|
||||
addOutput('system', '请先建立SSH连接')
|
||||
return
|
||||
}
|
||||
|
||||
// 添加到历史记录
|
||||
commandHistory.value.push(currentCommand.value)
|
||||
historyIndex.value = commandHistory.value.length
|
||||
|
||||
// 显示输入的命令
|
||||
addOutput('input', currentCommand.value)
|
||||
|
||||
// 发送命令
|
||||
socket.value?.send(currentCommand.value)
|
||||
|
||||
currentCommand.value = ''
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
const historyUp = () => {
|
||||
if (commandHistory.value.length === 0) return
|
||||
|
||||
if (historyIndex.value > 0) {
|
||||
historyIndex.value--
|
||||
currentCommand.value = commandHistory.value[historyIndex.value]
|
||||
}
|
||||
}
|
||||
|
||||
const historyDown = () => {
|
||||
if (historyIndex.value < commandHistory.value.length - 1) {
|
||||
historyIndex.value++
|
||||
currentCommand.value = commandHistory.value[historyIndex.value]
|
||||
} else if (historyIndex.value === commandHistory.value.length - 1) {
|
||||
historyIndex.value++
|
||||
currentCommand.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const focusInput = () => {
|
||||
nextTick(() => {
|
||||
commandInput.value?.focus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
// 检测 Ctrl+C 组合键
|
||||
if (event.ctrlKey && event.key === 'c') {
|
||||
event.preventDefault()
|
||||
if (connected.value && socket.value) {
|
||||
// 发送中断信号
|
||||
socket.value.send('\x03') // Ctrl+C 的 ASCII 码
|
||||
addOutput('system', '^C') // 显示中断符号
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
focusInput()
|
||||
// 添加键盘事件监听
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (socket.value) {
|
||||
socket.value.close()
|
||||
}
|
||||
// 移除键盘事件监听
|
||||
window.removeEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
|
||||
return {
|
||||
outputLines,
|
||||
currentCommand,
|
||||
connectionModalVisible,
|
||||
connecting,
|
||||
connectionForm,
|
||||
formRules,
|
||||
terminalBody,
|
||||
commandInput,
|
||||
connect,
|
||||
handleConnect,
|
||||
disconnect,
|
||||
executeCommand,
|
||||
historyUp,
|
||||
historyDown
|
||||
}
|
||||
connected.value = false
|
||||
connecting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const disconnect = () => {
|
||||
if (connected.value && socket.value) {
|
||||
socket.value.send('disconnect')
|
||||
socket.value.close()
|
||||
}
|
||||
}
|
||||
|
||||
const executeCommand = () => {
|
||||
if (!currentCommand.value.trim()) return
|
||||
|
||||
if (!connected.value) {
|
||||
addOutput('system', '请先建立SSH连接')
|
||||
return
|
||||
}
|
||||
|
||||
// 添加到历史记录
|
||||
commandHistory.value.push(currentCommand.value)
|
||||
historyIndex.value = commandHistory.value.length
|
||||
|
||||
// 显示输入的命令
|
||||
addOutput('input', currentCommand.value)
|
||||
|
||||
// 发送命令
|
||||
socket.value?.send(currentCommand.value)
|
||||
|
||||
currentCommand.value = ''
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
const historyUp = () => {
|
||||
if (commandHistory.value.length === 0) return
|
||||
|
||||
if (historyIndex.value > 0) {
|
||||
historyIndex.value--
|
||||
currentCommand.value = commandHistory.value[historyIndex.value]
|
||||
}
|
||||
}
|
||||
|
||||
const historyDown = () => {
|
||||
if (historyIndex.value < commandHistory.value.length - 1) {
|
||||
historyIndex.value++
|
||||
currentCommand.value = commandHistory.value[historyIndex.value]
|
||||
} else if (historyIndex.value === commandHistory.value.length - 1) {
|
||||
historyIndex.value++
|
||||
currentCommand.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const focusInput = () => {
|
||||
nextTick(() => {
|
||||
commandInput.value?.focus()
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
focusInput()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (socket.value) {
|
||||
socket.value.close()
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
outputLines,
|
||||
currentCommand,
|
||||
connectionModalVisible,
|
||||
connecting,
|
||||
connectionForm,
|
||||
formRules,
|
||||
terminalBody,
|
||||
commandInput,
|
||||
connect,
|
||||
handleConnect,
|
||||
disconnect,
|
||||
executeCommand,
|
||||
historyUp,
|
||||
historyDown
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.terminal-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #1e1e1e;
|
||||
color: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
height: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #121212;
|
||||
color: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.terminal-header {
|
||||
padding: 8px 16px;
|
||||
background-color: #333;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #444;
|
||||
padding: 8px 12px;
|
||||
background-color: #1a1a1a;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #2a2a2a;
|
||||
font-family: 'Lucida Console', 'Consolas', monospace;
|
||||
}
|
||||
|
||||
.terminal-body {
|
||||
flex: 1;
|
||||
padding: 8px;
|
||||
overflow-y: auto;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
font-family: 'Lucida Console', 'Consolas', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
background-color: #121212;
|
||||
}
|
||||
|
||||
.terminal-line {
|
||||
margin-bottom: 4px;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
margin-bottom: 4px;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.terminal-input-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
padding: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.input-prompt {
|
||||
color: #4caf50;
|
||||
margin-right: 8px;
|
||||
color: #00ff00;
|
||||
margin-right: 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.terminal-input {
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
flex: 1;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
font-family: 'Lucida Console', 'Consolas', monospace;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
padding: 4px 8px;
|
||||
border-radius: 2px;
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.terminal-input:focus {
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.output {
|
||||
color: #f0f0f0;
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #ff5252;
|
||||
color: #ff5555;
|
||||
}
|
||||
|
||||
.input {
|
||||
color: #bbdefb;
|
||||
color: #00ffff;
|
||||
}
|
||||
|
||||
.system {
|
||||
color: #ff9800;
|
||||
color: #ffff55;
|
||||
}
|
||||
|
||||
.terminal-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.terminal-body::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.terminal-body::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.terminal-body::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
</style>
|
|
@ -110,11 +110,11 @@ const labelCol = reactive({
|
|||
xs: 24,
|
||||
sm: 4,
|
||||
xl: 6,
|
||||
xxl: 4
|
||||
xxl: 5
|
||||
});
|
||||
const wrapperCol = reactive({
|
||||
xs: 24,
|
||||
sm: 20,
|
||||
sm: 19,
|
||||
});
|
||||
|
||||
// 高级查询配置
|
||||
|
|
|
@ -155,6 +155,12 @@
|
|||
<a-col :span="24">
|
||||
<SectionDivider :title="'机构信息'" />
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="机构所在地">
|
||||
<span>{{ formData.orgProvince_dictText + formData.orgCity_dictText + formData.orgDistrict_dictText
|
||||
}}</span>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="机构地址" v-bind="validateInfos.orgAddress" id="OrgApplyInfoForm-orgAddress"
|
||||
name="orgAddress">
|
||||
|
@ -195,6 +201,9 @@
|
|||
</a-form>
|
||||
</template>
|
||||
</JFormContainer>
|
||||
<!-- <a-col :span="24" v-if="!!formData.orgCoordinateLa && !!formData.orgCoordinateLo">
|
||||
<TencentMap :latitude="formData.orgCoordinateLa" :longitude="formData.orgCoordinateLo" />
|
||||
</a-col> -->
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
|
@ -207,6 +216,7 @@ import { getValueType } from '/@/utils';
|
|||
import { saveOrUpdate } from '../OrgApplyInfo.api';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||||
import TencentMap from '/@/components/TencentMap/TencentMap.vue';
|
||||
|
||||
const props = defineProps({
|
||||
formDisabled: { type: Boolean, default: false },
|
||||
|
@ -243,13 +253,21 @@ const formData = reactive<Record<string, any>>({
|
|||
comCreditCode: '',
|
||||
comLegalPerson: '',
|
||||
orgAddress: '',
|
||||
orgCoordinate: '',
|
||||
orgCoordinateLo: '',
|
||||
orgCoordinateLa: '',
|
||||
orgLeader: '',
|
||||
orgLeaderPhone: '',
|
||||
orgBuildingNumber: '',
|
||||
orgPropertyType: '',
|
||||
orgBuildingArea: undefined,
|
||||
orgProvince: '',
|
||||
orgCity: '',
|
||||
orgDistrict: '',
|
||||
orgProvince_dictText: '',
|
||||
orgCity_dictText: '',
|
||||
orgDistrict_dictText: '',
|
||||
});
|
||||
const tempNullVal = ref('')
|
||||
const { createMessage } = useMessage();
|
||||
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
|
||||
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
灵敏度
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-slider v-model:value="formData.digitalSensitivity" :disabled="!formData.enabled" :min="1" :max="100" @change="(value) => changeSensitivity(value)"/>
|
||||
<a-slider v-model:value="formData.digitalSensitivity" :disabled="!formData.enabled" :min="1" :max="100" @afterChange="(value) => changeSensitivity(value)"/>
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.digitalSensitivity" :disabled="!formData.enabled" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeSensitivity(value)"/>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<a-row>
|
||||
<a-col :span="2"></a-col>
|
||||
<a-col :span="20">
|
||||
<div id="video-container" class="video-container"></div>
|
||||
<div id="video-container" class="video-container"></div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row style="margin-top: 14px">
|
||||
|
@ -46,10 +46,12 @@
|
|||
亮度
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-slider v-model:value="formData.luma" :min="1" :max="100" @change="(value) => changeCommon('luma', value)"/>
|
||||
<a-slider v-model:value="formData.luma" :min="1" :max="100"
|
||||
@afterChange="(value) => changeCommon('luma', value)" />
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.luma" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeCommon('luma', value)"/>
|
||||
<a-input-number v-model:value="formData.luma" :min="1" :max="100" style="margin-left: 12px"
|
||||
@change="(value) => changeCommon('luma', value)" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -59,10 +61,12 @@
|
|||
对比度
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-slider v-model:value="formData.contrast" :min="1" :max="100" @change="(value) => changeCommon('contrast', value)"/>
|
||||
<a-slider v-model:value="formData.contrast" :min="1" :max="100"
|
||||
@afterChange="(value) => changeCommon('contrast', value)" />
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.contrast" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeCommon('contrast', value)"/>
|
||||
<a-input-number v-model:value="formData.contrast" :min="1" :max="100" style="margin-left: 12px"
|
||||
@change="(value) => changeCommon('contrast', value)" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -72,10 +76,12 @@
|
|||
饱和度
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-slider v-model:value="formData.saturation" :min="1" :max="100" @change="(value) => changeCommon('saturation', value)"/>
|
||||
<a-slider v-model:value="formData.saturation" :min="1" :max="100"
|
||||
@afterChange="(value) => changeCommon('saturation', value)" />
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.saturation" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeCommon('saturation', value)"/>
|
||||
<a-input-number v-model:value="formData.saturation" :min="1" :max="100" style="margin-left: 12px"
|
||||
@change="(value) => changeCommon('saturation', value)" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -85,10 +91,12 @@
|
|||
锐度
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-slider v-model:value="formData.sharpness" :min="1" :max="100" @change="(value) => changeCommon('sharpness', value)"/>
|
||||
<a-slider v-model:value="formData.sharpness" :min="1" :max="100"
|
||||
@afterChange="(value) => changeCommon('sharpness', value)" />
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.sharpness" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeCommon('sharpness', value)"/>
|
||||
<a-input-number v-model:value="formData.sharpness" :min="1" :max="100" style="margin-left: 12px"
|
||||
@change="(value) => changeCommon('sharpness', value)" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -98,21 +106,24 @@
|
|||
宽动态
|
||||
</a-col>
|
||||
<a-col :span="16">
|
||||
<a-select v-model:value="formData.wide_dynamic" @change="(value) => changeCommon('wide_dynamic', value)">
|
||||
<a-select-option value="off">关闭</a-select-option>
|
||||
<a-select-option value="on">开启</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model:value="formData.wide_dynamic"
|
||||
@change="(value) => changeCommon('wide_dynamic', value)">
|
||||
<a-select-option value="off">关闭</a-select-option>
|
||||
<a-select-option value="on">开启</a-select-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="20" v-show="formData.wide_dynamic=='on'">
|
||||
<a-col :span="20" v-show="formData.wide_dynamic == 'on'">
|
||||
<a-row style="margin-bottom: 14px">
|
||||
<a-col :span="6" class="labelText"></a-col>
|
||||
<a-col :span="12">
|
||||
<a-slider v-model:value="formData.wd_gain" :min="1" :max="100" @change="(value) => changeCommon('wd_gain', value)"/>
|
||||
<a-slider v-model:value="formData.wd_gain" :min="1" :max="100"
|
||||
@afterChange="(value) => changeCommon('wd_gain', value)" />
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.wd_gain" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeCommon('wd_gain', value)"/>
|
||||
<a-input-number v-model:value="formData.wd_gain" :min="1" :max="100" style="margin-left: 12px"
|
||||
@change="(value) => changeCommon('wd_gain', value)" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -127,7 +138,8 @@
|
|||
照明模式
|
||||
</a-col>
|
||||
<a-col :span="16">
|
||||
<a-select v-model:value="formData.night_vision_mode" @change="(value) => changeSwitch('night_vision_mode', value)">
|
||||
<a-select v-model:value="formData.night_vision_mode"
|
||||
@change="(value) => changeSwitch('night_vision_mode', value)">
|
||||
<a-select-option value="wtl_night_vision">白光照明</a-select-option>
|
||||
<a-select-option value="inf_night_vision">红外照明</a-select-option>
|
||||
<a-select-option value="md_night_vision">移动侦测全彩</a-select-option>
|
||||
|
@ -135,7 +147,7 @@
|
|||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="20" v-show="formData.night_vision_mode=='md_night_vision'">
|
||||
<a-col :span="20" v-show="formData.night_vision_mode == 'md_night_vision'">
|
||||
<a-row style="margin-bottom: 14px">
|
||||
<a-col :span="6" class="labelText">
|
||||
防红外过曝
|
||||
|
@ -149,16 +161,18 @@
|
|||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="20" v-show="formData.night_vision_mode=='md_night_vision'&&formData.smartir=='manual'">
|
||||
<a-col :span="20" v-show="formData.night_vision_mode == 'md_night_vision' && formData.smartir == 'manual'">
|
||||
<a-row style="margin-bottom: 14px">
|
||||
<a-col :span="6" class="labelText">
|
||||
防过曝等级
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-slider v-model:value="formData.smartir_level" :min="1" :max="100" @change="(value) => changeCommon('smartir_level', value)"/>
|
||||
<a-slider v-model:value="formData.smartir_level" :min="1" :max="100"
|
||||
@afterChange="(value) => changeCommon('smartir_level', value)" />
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.smartir_level" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeCommon('smartir_level', value)"/>
|
||||
<a-input-number v-model:value="formData.smartir_level" :min="1" :max="100" style="margin-left: 12px"
|
||||
@change="(value) => changeCommon('smartir_level', value)" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -176,16 +190,18 @@
|
|||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="20" v-show="formData.smartwtl=='manual'">
|
||||
<a-col :span="20" v-show="formData.smartwtl == 'manual'">
|
||||
<a-row style="margin-bottom: 14px">
|
||||
<a-col :span="6" class="labelText">
|
||||
白光等级
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-slider v-model:value="formData.smartwtl_digital_level" :min="1" :max="100" @change="(value) => changeCommon('smartwtl_digital_level', value)"/>
|
||||
<a-slider v-model:value="formData.smartwtl_digital_level" :min="1" :max="100"
|
||||
@afterChange="(value) => changeCommon('smartwtl_digital_level', value)" />
|
||||
</a-col>
|
||||
<a-col :span="4">
|
||||
<a-input-number v-model:value="formData.smartwtl_digital_level" :min="1" :max="100" style="margin-left: 12px" @change="(value) => changeCommon('smartwtl_digital_level', value)"/>
|
||||
<a-input-number v-model:value="formData.smartwtl_digital_level" :min="1" :max="100"
|
||||
style="margin-left: 12px" @change="(value) => changeCommon('smartwtl_digital_level', value)" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
|
@ -205,238 +221,237 @@ import {
|
|||
onMounted,
|
||||
watch,
|
||||
} from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
import { getValueType } from '/@/utils';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||||
import {
|
||||
getImageCommon,
|
||||
setImageCommon,
|
||||
configRecovery,
|
||||
getPreviewUrl,
|
||||
} from "../camera.api";
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
|
||||
import { getValueType } from '/@/utils';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||||
import {
|
||||
getImageCommon,
|
||||
setImageCommon,
|
||||
configRecovery,
|
||||
getPreviewUrl,
|
||||
} from "../camera.api";
|
||||
|
||||
const props = defineProps({
|
||||
data: { type: Object, default: () => ({}) },
|
||||
const props = defineProps({
|
||||
data: { type: Object, default: () => ({}) },
|
||||
});
|
||||
const formRef = ref();
|
||||
const useForm = Form.useForm;
|
||||
const formData = reactive<Record<string, any>>({
|
||||
deviceIndex: '',//设备索引
|
||||
streamType: 0,//码流类型 0 代表主码流,1 代码子码流
|
||||
//视频预览参数
|
||||
url: '',//预览通道对应的URL
|
||||
backupUrl: '',//备选URL,当流媒体服务器存在内外网IP配置时,该字段不为null
|
||||
wsUrl: '',//用于建立ws连接传输视频帧信息
|
||||
wssUrl: '',//用于建立wss接传输视频帧信息
|
||||
|
||||
chroma: "0", //色度
|
||||
luma: "0", //亮度
|
||||
sharpness: "0", //锐度
|
||||
saturation: "0", //饱和度
|
||||
contrast: "0", //对比度
|
||||
wd_gain: "0", //宽动态度
|
||||
smartir_level: "0",//防过曝等级
|
||||
wide_dynamic: "off", //宽动态 "off"//关闭 "on"//开启
|
||||
smartir: "auto_ir",//防红外过曝:"auto_ir_ae" //自动-增强模式 "auto_ir" //自动-标准模式 "manual"//手动——防过曝等级
|
||||
smartwtl: "auto_wtl",//白光强度:"auto_wtl_ae" //智能白光-柔和 ;"auto_wtl" //智能白光-标准 ; "manual" //手动——出现白光等级
|
||||
smartwtl_digital_level: "0",//白光等级
|
||||
|
||||
flip_type: "center",//画面镜像旋转: "off"//关闭 "left_and_right"//左右 "up_and_down"//上下 "center"//中心
|
||||
night_vision_mode: "md_night_vision",//照明模式:"wtl_night_vision"//白光照明 ;"inf_night_vision"//红外照明 ; "md_night_vision"//移动侦测全彩——出现白光强度
|
||||
|
||||
});
|
||||
const player = ref();
|
||||
const { createMessage } = useMessage();
|
||||
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 8 } });
|
||||
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
|
||||
const confirmLoading = ref<boolean>(false);
|
||||
|
||||
/**
|
||||
* 恢复默认
|
||||
*/
|
||||
function restoreDefault() {
|
||||
if (formData.deviceIndex == '') {
|
||||
return
|
||||
}
|
||||
confirmLoading.value = true;
|
||||
configRecovery({ "deviceIndex": formData.deviceIndex }).then(res => {
|
||||
confirmLoading.value = false;
|
||||
getCommon(formData.deviceIndex);
|
||||
getSwitch(formData.deviceIndex);
|
||||
});
|
||||
const formRef = ref();
|
||||
const useForm = Form.useForm;
|
||||
const formData = reactive<Record<string, any>>({
|
||||
deviceIndex: '',//设备索引
|
||||
streamType: 0,//码流类型 0 代表主码流,1 代码子码流
|
||||
//视频预览参数
|
||||
url: '',//预览通道对应的URL
|
||||
backupUrl: '',//备选URL,当流媒体服务器存在内外网IP配置时,该字段不为null
|
||||
wsUrl: '',//用于建立ws连接传输视频帧信息
|
||||
wssUrl: '',//用于建立wss接传输视频帧信息
|
||||
|
||||
chroma: "0", //色度
|
||||
luma: "0", //亮度
|
||||
sharpness: "0", //锐度
|
||||
saturation: "0", //饱和度
|
||||
contrast: "0", //对比度
|
||||
wd_gain: "0", //宽动态度
|
||||
smartir_level: "0",//防过曝等级
|
||||
wide_dynamic: "off", //宽动态 "off"//关闭 "on"//开启
|
||||
smartir: "auto_ir",//防红外过曝:"auto_ir_ae" //自动-增强模式 "auto_ir" //自动-标准模式 "manual"//手动——防过曝等级
|
||||
smartwtl: "auto_wtl",//白光强度:"auto_wtl_ae" //智能白光-柔和 ;"auto_wtl" //智能白光-标准 ; "manual" //手动——出现白光等级
|
||||
smartwtl_digital_level: "0",//白光等级
|
||||
|
||||
flip_type: "center",//画面镜像旋转: "off"//关闭 "left_and_right"//左右 "up_and_down"//上下 "center"//中心
|
||||
night_vision_mode: "md_night_vision",//照明模式:"wtl_night_vision"//白光照明 ;"inf_night_vision"//红外照明 ; "md_night_vision"//移动侦测全彩——出现白光强度
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放
|
||||
*/
|
||||
async function preview(deviceIndex, streamType, url) {
|
||||
if (deviceIndex == null) {
|
||||
return
|
||||
}
|
||||
if (url != '') {
|
||||
return
|
||||
}
|
||||
await getPreviewUrl({ "deviceIndex": deviceIndex, "streamType": streamType }).then(res => {
|
||||
formData.url = res.url;
|
||||
formData.backupUrl = res.backupUrl;
|
||||
formData.wsUrl = res.wsUrl;
|
||||
formData.wssUrl = res.wssUrl;
|
||||
confirmLoading.value = false;
|
||||
});
|
||||
const player = ref();
|
||||
const { createMessage } = useMessage();
|
||||
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 8 } });
|
||||
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
|
||||
const confirmLoading = ref<boolean>(false);
|
||||
|
||||
/**
|
||||
* 恢复默认
|
||||
*/
|
||||
function restoreDefault(){
|
||||
if(formData.deviceIndex==''){
|
||||
return
|
||||
const TumsPlayer = window['tums-player'].default;
|
||||
player.value = new TumsPlayer('video-container', {
|
||||
type: "rtsp", // 协议类型,rtsp
|
||||
url: formData.url, // 取流地址, getPreviewUrl接口获取
|
||||
// url: formData.backupUrl, // 取流地址, getPreviewUrl接口获取
|
||||
socket: formData.wssUrl, // websocket地址, getPreviewUrl接口获取
|
||||
pluginPath: '/static', // 当sdk资源不在根路径下时,需配置pluginPath
|
||||
});
|
||||
let isPlaying = player.value.isPlaying();
|
||||
if (!isPlaying) {
|
||||
if (player.value.isInit) {
|
||||
player.value.start();
|
||||
} else {
|
||||
player.value.play();
|
||||
}
|
||||
confirmLoading.value=true;
|
||||
configRecovery({"deviceIndex":formData.deviceIndex}).then(res=>{
|
||||
confirmLoading.value=false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁
|
||||
*/
|
||||
function destroy(player) {
|
||||
if (player) {
|
||||
player.value.destroy().then(() => {
|
||||
}); // 销毁
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取画面通用信息
|
||||
*/
|
||||
function getCommon(deviceIndex) {
|
||||
if (deviceIndex == null) {
|
||||
return
|
||||
}
|
||||
getImageCommon({
|
||||
"deviceIndex": deviceIndex,
|
||||
"type": "common"
|
||||
}).then(res => {
|
||||
formData.chroma = res.chroma; //色度
|
||||
formData.luma = res.luma; //亮度
|
||||
formData.sharpness = res.sharpness; //锐度
|
||||
formData.saturation = res.saturation; //饱和度
|
||||
formData.contrast = res.contrast; //对比度
|
||||
formData.wd_gain = res.wd_gain; //宽动态度
|
||||
formData.smartir_level = res.smartir_level; //防过曝等级
|
||||
formData.wide_dynamic = res.wide_dynamic; //宽动态 "off"//关闭 "on"//开启
|
||||
formData.smartir = res.smartir; //防红外过曝:"auto_ir_ae" //自动-增强模式 "auto_ir" //自动-标准模式 "manual"//手动——防过曝等级
|
||||
formData.smartwtl = res.smartwtl; //白光强度:"auto_wtl_ae" //智能白光-柔和 ;"auto_wtl" //智能白光-标准 ; "manual" //手动——出现白光等级
|
||||
formData.smartwtl_digital_level = res.smartwtl_digital_level; //白光等级
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取照明设置信息
|
||||
*/
|
||||
function getSwitch(deviceIndex) {
|
||||
if (deviceIndex == null) {
|
||||
return
|
||||
}
|
||||
getImageCommon({
|
||||
"deviceIndex": deviceIndex,
|
||||
"type": "switch"
|
||||
}).then(res => {
|
||||
formData.flip_type = res.flip_type; //画面镜像翻转
|
||||
formData.night_vision_mode = res.night_vision_mode; //照明模式
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置画面信息
|
||||
* @param paramKey
|
||||
* @param paramValue
|
||||
*/
|
||||
function setCommon(paramKey, paramValue) {
|
||||
setImageCommon({
|
||||
"deviceIndex": formData.deviceIndex,
|
||||
"type": formData.deviceIndex,
|
||||
paramKey: paramValue
|
||||
}).then(res => { });
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置照明设置信息
|
||||
* @param paramObj
|
||||
* @param type
|
||||
*/
|
||||
function setCommonSwitch(paramObj, type) {
|
||||
setImageCommon({
|
||||
"deviceIndex": formData.deviceIndex,
|
||||
"type": type,
|
||||
"param": paramObj
|
||||
}).then(res => { });
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改画面信息
|
||||
* @param attr
|
||||
* @param value
|
||||
*/
|
||||
function changeCommon(attr, value) {
|
||||
let param = {};
|
||||
param[attr] = value;
|
||||
setCommonSwitch(param, "common");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改照明设置信息
|
||||
* @param attr
|
||||
* @param value
|
||||
*/
|
||||
function changeSwitch(attr, value) {
|
||||
let param = {};
|
||||
param[attr] = value;
|
||||
setCommonSwitch(param, "switch");
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watch(
|
||||
() => props.data,
|
||||
async () => {
|
||||
formData.deviceIndex = props.data.deviceIndex;
|
||||
getCommon(formData.deviceIndex);
|
||||
getSwitch(formData.deviceIndex);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放
|
||||
*/
|
||||
async function preview(deviceIndex,streamType,url) {
|
||||
if(deviceIndex==null){
|
||||
return
|
||||
}
|
||||
if (url!=''){
|
||||
return
|
||||
}
|
||||
await getPreviewUrl({"deviceIndex":deviceIndex,"streamType":streamType}).then(res=>{
|
||||
formData.url = res.url;
|
||||
formData.backupUrl = res.backupUrl;
|
||||
formData.wsUrl = res.wsUrl;
|
||||
formData.wssUrl = res.wssUrl;
|
||||
confirmLoading.value=false;
|
||||
});
|
||||
const TumsPlayer = window['tums-player'].default;
|
||||
player.value = new TumsPlayer('video-container', {
|
||||
type: "rtsp", // 协议类型,rtsp
|
||||
url: formData.url, // 取流地址, getPreviewUrl接口获取
|
||||
// url: formData.backupUrl, // 取流地址, getPreviewUrl接口获取
|
||||
socket: formData.wssUrl, // websocket地址, getPreviewUrl接口获取
|
||||
pluginPath: '/static', // 当sdk资源不在根路径下时,需配置pluginPath
|
||||
});
|
||||
let isPlaying = player.value.isPlaying();
|
||||
if (!isPlaying) {
|
||||
if (player.value.isInit) {
|
||||
player.value.start();
|
||||
} else {
|
||||
player.value.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁
|
||||
*/
|
||||
function destroy(player){
|
||||
if (player){
|
||||
player.value.destroy().then(() => {
|
||||
}); // 销毁
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取画面通用信息
|
||||
*/
|
||||
function getCommon(deviceIndex){
|
||||
if(deviceIndex==null){
|
||||
return
|
||||
}
|
||||
getImageCommon({
|
||||
"deviceIndex": deviceIndex,
|
||||
"type": "common"
|
||||
}).then(res=>{
|
||||
formData.chroma = res.chroma; //色度
|
||||
formData.luma = res.luma; //亮度
|
||||
formData.sharpness = res.sharpness; //锐度
|
||||
formData.saturation = res.saturation; //饱和度
|
||||
formData.contrast = res.contrast; //对比度
|
||||
formData.wd_gain = res.wd_gain; //宽动态度
|
||||
formData.smartir_level = res.smartir_level; //防过曝等级
|
||||
formData.wide_dynamic = res.wide_dynamic; //宽动态 "off"//关闭 "on"//开启
|
||||
formData.smartir = res.smartir; //防红外过曝:"auto_ir_ae" //自动-增强模式 "auto_ir" //自动-标准模式 "manual"//手动——防过曝等级
|
||||
formData.smartwtl = res.smartwtl; //白光强度:"auto_wtl_ae" //智能白光-柔和 ;"auto_wtl" //智能白光-标准 ; "manual" //手动——出现白光等级
|
||||
formData.smartwtl_digital_level = res.smartwtl_digital_level; //白光等级
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取照明设置信息
|
||||
*/
|
||||
function getSwitch(deviceIndex){
|
||||
if(deviceIndex==null){
|
||||
return
|
||||
}
|
||||
getImageCommon({
|
||||
"deviceIndex": deviceIndex,
|
||||
"type": "switch"
|
||||
}).then(res=>{
|
||||
formData.flip_type = res.flip_type; //画面镜像翻转
|
||||
formData.night_vision_mode = res.night_vision_mode; //照明模式
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置画面信息
|
||||
* @param paramKey
|
||||
* @param paramValue
|
||||
*/
|
||||
function setCommon(paramKey, paramValue){
|
||||
setImageCommon({
|
||||
"deviceIndex": formData.deviceIndex,
|
||||
"type": formData.deviceIndex,
|
||||
paramKey: paramValue
|
||||
}).then(res=>{ });
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置照明设置信息
|
||||
* @param paramObj
|
||||
* @param type
|
||||
*/
|
||||
function setCommonSwitch(paramObj,type){
|
||||
setImageCommon({
|
||||
"deviceIndex": formData.deviceIndex,
|
||||
"type": type,
|
||||
"param": paramObj
|
||||
}).then(res=>{ });
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改画面信息
|
||||
* @param attr
|
||||
* @param value
|
||||
*/
|
||||
function changeCommon(attr,value){
|
||||
let param = {};
|
||||
param[attr] = value;
|
||||
setCommonSwitch(param,"common");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改照明设置信息
|
||||
* @param attr
|
||||
* @param value
|
||||
*/
|
||||
function changeSwitch(attr,value){
|
||||
let param = {};
|
||||
param[attr] = value;
|
||||
setCommonSwitch(param,"switch");
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watch(
|
||||
() => props.data,
|
||||
async () => {
|
||||
formData.deviceIndex = props.data.deviceIndex;
|
||||
getCommon(formData.deviceIndex);
|
||||
getSwitch(formData.deviceIndex);
|
||||
preview(formData.deviceIndex,formData.streamType,formData.url);
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
});
|
||||
preview(formData.deviceIndex, formData.streamType, formData.url);
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.antd-modal-form {
|
||||
padding: 14px;
|
||||
}
|
||||
.antd-modal-form {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.labelText {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-right: 8px;
|
||||
}
|
||||
.labelText {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
height: 500px;
|
||||
width: 500px;
|
||||
background-color: #010917;
|
||||
}
|
||||
.ant-select {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
height: 500px;
|
||||
width: 500px;
|
||||
background-color: #010917;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -168,7 +168,7 @@ const labelCol = reactive({
|
|||
xs: 24,
|
||||
sm: 4,
|
||||
xl: 6,
|
||||
xxl: 4
|
||||
xxl: 5
|
||||
});
|
||||
const wrapperCol = reactive({
|
||||
xs: 24,
|
||||
|
|
Loading…
Reference in New Issue