字段调整

This commit is contained in:
1378012178@qq.com 2025-06-12 14:15:00 +08:00
parent a4ba10534c
commit 6c25f21f19
9 changed files with 724 additions and 522 deletions

View File

@ -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>

View File

@ -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",

View File

@ -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>

View File

@ -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>

View File

@ -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,
});
//

View File

@ -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 } });

View File

@ -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)"/>

View File

@ -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: '',//URLIPnull
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: '',//URLIPnull
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', // sdkpluginPath
});
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', // sdkpluginPath
});
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>

View File

@ -168,7 +168,7 @@ const labelCol = reactive({
xs: 24,
sm: 4,
xl: 6,
xxl: 4
xxl: 5
});
const wrapperCol = reactive({
xs: 24,