| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- <template>
- <div class="camera-config-container">
- <div class="selectBox multi-camera-config" v-id>
- <div class="point-tabs" v-if="isMultiCameraMode">
- <div
- v-for="point in displayPointList"
- :key="point.key"
- class="point-tab"
- :class="{ active: activePoint === point.key }"
- @click="switchPoint(point.key)"
- >
- <span class="tab-name">{{ $t('cameraConfig.pointLabel', { point: point.key }) }}</span>
- <el-tag :type="getPointTagInfo(point.key).type" size="small">
- {{ getPointTagInfo(point.key).text }}
- </el-tag>
- </div>
- <el-button
- type="primary"
- link
- class="refresh-btn"
- :loading="refreshing"
- @click="handleRefresh"
- >
- <el-icon><Refresh /></el-icon>
- {{ $t('cameraConfig.refresh') }}
- </el-button>
- </div>
- <div class="current-point-config">
- <div class="config-body">
- <div v-if="isMultiCameraMode" class="form-item">
- <label class="iso-label">{{ $t('cameraConfig.bindCamera') }}</label>
- <div class="camera-select-wrapper">
- <el-select
- v-model="multiConfig[activePoint].CameraKey"
- :placeholder="$t('cameraConfig.selectCamera')"
- filterable
- clearable
- @change="onCameraChange(activePoint)"
- @focus="ensureCurrentCameraInList"
- >
- <el-option
- v-for="camera in availableCameras"
- :key="camera.CameraKey"
- :label="camera.CameraName"
- :value="camera.CameraKey"
- :disabled="!camera.CameraStatus"
- >
- <span>{{ camera.CameraName }}</span>
- <el-tag v-if="!camera.CameraStatus" type="danger" size="small" style="margin-left: 8px">{{ $t('cameraConfig.notConnected') }}</el-tag>
- </el-option>
- </el-select>
- </div>
- </div>
- <div class="iso-section">
- <div class="iso-group">
- <span class="iso-label">{{ $t('cameraConfig.photoISO') }}</span>
- <div class="select-wrapper">
- <el-select
- v-model="multiConfig[activePoint].iso.low"
- filterable
- default-first-option
- :placeholder="$t('cameraConfig.select')"
- class="iso-select"
- >
- <el-option
- v-for="item in iso_options"
- :key="item"
- :label="item"
- :value="item"
- />
- </el-select>
- </div>
- </div>
- <div class="iso-group">
- <span class="iso-label">{{ $t('cameraConfig.previewISO') }}</span>
- <div class="select-wrapper">
- <el-select
- v-model="multiConfig[activePoint].iso.high"
- filterable
- default-first-option
- :placeholder="$t('cameraConfig.select')"
- class="iso-select"
- >
- <el-option
- v-for="item in iso_options"
- :key="item"
- :label="item"
- :value="item"
- />
- </el-select>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { reactive, onMounted, ref, watch, computed } from 'vue'
- import { ElMessage } from 'element-plus'
- import client from "@/stores/modules/client";
- import icpList from '@/utils/ipc';
- import socket from "@/stores/modules/socket.js";
- import useUserInfo from '@/stores/modules/user';
- import i18n from '@/locales';
- const clientStore = client();
- const socketStore = socket();
- const userInfoStore = useUserInfo();
- const props = defineProps({
- camera_configs: {
- type: Object,
- default: () => ({})
- }
- })
- const emit = defineEmits(['update:camera_configs'])
- const isMultiCameraMode = computed(() => userInfoStore.isMultiCameraMode)
- const activePoint = ref('A')
- const cameraList = ref([])
- const refreshing = ref(false)
- const pointList = reactive([
- { key: 'A', cameraName: '' },
- { key: 'B', cameraName: '' },
- { key: 'C', cameraName: '' },
- ])
- const getPointStatus = (pointKey) => {
- const config = multiConfig[pointKey]
- if (!config || !config.CameraKey) return 'unset'
- const camera = cameraList.value.find(c => c.CameraKey === config.CameraKey)
- if (!camera) return 'disconnected'
- return camera.CameraStatus ? 'connected' : 'disconnected'
- }
- const getPointTagInfo = (pointKey) => {
- const status = getPointStatus(pointKey)
- if (status === 'connected') return { text: i18n.global.t('cameraConfig.connected'), type: 'success' }
- if (status === 'disconnected') return { text: i18n.global.t('cameraConfig.notConnected'), type: 'danger' }
- return { text: i18n.global.t('cameraConfig.notSet'), type: 'info' }
- }
- const multiConfig = reactive({
- A: {
- iso: { low: '100', high: '6400' },
- CameraKey: '',
- CameraName: '',
- iso_options: ['auto', 100, 200, 400, 800, 1600, 3200, 6400, 12800]
- },
- B: {
- iso: { low: '100', high: '6400' },
- CameraKey: '',
- CameraName: '',
- iso_options: ['auto', 100, 200, 400, 800, 1600, 3200, 6400, 12800]
- },
- C: {
- iso: { low: '100', high: '6400' },
- CameraKey: '',
- CameraName: '',
- iso_options: ['auto', 100, 200, 400, 800, 1600, 3200, 6400, 12800]
- }
- })
- const iso_options = computed(() => {
- return multiConfig[activePoint.value]?.iso_options || ['auto', 100, 200, 400, 800, 1600, 3200, 6400, 12800]
- })
- const displayPointList = computed(() => {
- if (isMultiCameraMode.value) {
- return pointList
- } else {
- return pointList.filter(p => p.key === 'A')
- }
- })
- const availableCameras = computed(() => {
- const cameras = cameraList.value || []
- if (!isMultiCameraMode.value) {
- return cameras
- }
- const currentBoundCameraKey = multiConfig[activePoint.value].CameraKey
- return cameras.filter(cam => {
- if (cam.CameraKey === currentBoundCameraKey) {
- return true
- }
- const isBoundByOtherPoint = Object.entries(multiConfig).some(([key, config]) => {
- return key !== activePoint.value && config.CameraKey === cam.CameraKey
- })
- return !isBoundByOtherPoint
- })
- })
- const switchPoint = (pointKey) => {
- activePoint.value = pointKey
- const cameraKey = multiConfig[pointKey].CameraKey
- if (cameraKey) {
- const camera = cameraList.value.find(c => c.CameraKey === cameraKey)
- if (camera && camera.CameraISO && Array.isArray(camera.CameraISO)) {
- multiConfig[pointKey].iso_options = camera.CameraISO
- const currentLow = multiConfig[pointKey].iso.low
- const currentHigh = multiConfig[pointKey].iso.high
- if (!camera.CameraISO.includes(currentLow)) {
- multiConfig[pointKey].iso.low = camera.CameraISO[0]
- }
- if (!camera.CameraISO.includes(currentHigh)) {
- multiConfig[pointKey].iso.high = camera.CameraISO[0]
- }
- }
- }
- }
- const fetchCameraList = () => {
- return clientStore.ipc.invoke(icpList.camera.getCameraList).then(result => {
- if (result && result.CameraLists && Array.isArray(result.CameraLists)) {
- cameraList.value = result.CameraLists
- return true
- }
- return false
- }).catch(err => {
- throw err
- })
- }
- const handleRefresh = async () => {
- if (refreshing.value) return
- refreshing.value = true
- try {
- const ok = await fetchCameraList()
- if (ok) {
- ElMessage.success(i18n.global.t('cameraConfig.cameraConnected'))
- } else {
- ElMessage.warning(i18n.global.t('cameraConfig.noCameraList'))
- }
- } catch {
- ElMessage.error(i18n.global.t('cameraConfig.refreshFailed'))
- } finally {
- refreshing.value = false
- }
- }
- const fetchIsoConfig = () => {
- clientStore.ipc.removeAllListeners(icpList.socket.message + '_smart_shooter_getinfo');
- socketStore.sendMessage({ type: 'smart_shooter_getinfo' });
- clientStore.ipc.on(icpList.socket.message + '_smart_shooter_getinfo', async (event, result) => {
- if (result.code == 0 && result.data) {
- if (result.data.CameraISO && Array.isArray(result.data.CameraISO)) {
- iso_options.value = result.data.CameraISO
- }
- }
- clientStore.ipc.removeAllListeners(icpList.socket.message + '_smart_shooter_getinfo');
- })
- }
- const onCameraChange = (pointKey) => {
- const cameraKey = multiConfig[pointKey].CameraKey
- if (cameraKey) {
- const camera = cameraList.value.find(c => c.CameraKey === cameraKey)
- if (camera) {
- multiConfig[pointKey].CameraName = camera.CameraName
- if (camera.CameraISO && Array.isArray(camera.CameraISO)) {
- multiConfig[pointKey].iso_options = camera.CameraISO
- const currentLow = multiConfig[pointKey].iso.low
- const currentHigh = multiConfig[pointKey].iso.high
- if (!camera.CameraISO.includes(currentLow)) {
- multiConfig[pointKey].iso.low = camera.CameraISO[0]
- }
- if (!camera.CameraISO.includes(currentHigh)) {
- multiConfig[pointKey].iso.high = camera.CameraISO[0]
- }
- }
- }
- } else {
- multiConfig[pointKey].CameraName = ''
- multiConfig[pointKey].iso_options = ['auto', 100, 200, 400, 800, 1600, 3200, 6400, 12800]
- }
- }
- const ensureCurrentCameraInList = () => {
- const currentCameraKey = multiConfig[activePoint.value].CameraKey
- if (!currentCameraKey) return
- const exists = cameraList.value.some(c => c.CameraKey === currentCameraKey)
- if (!exists) {
- cameraList.value.push({
- CameraKey: currentCameraKey,
- CameraName: multiConfig[activePoint.value].CameraName || currentCameraKey,
- CameraStatus: false
- })
- }
- }
- watch(
- () => cameraList.value,
- () => {
- Object.keys(multiConfig).forEach(pointKey => {
- const config = multiConfig[pointKey]
- if (config.CameraKey) {
- const camera = cameraList.value.find(c => c.CameraKey === config.CameraKey)
- if (camera) {
- config.CameraName = camera.CameraName || config.CameraKey
- if (camera.CameraISO && Array.isArray(camera.CameraISO)) {
- config.iso_options = camera.CameraISO
- if (!camera.CameraISO.includes(config.iso.low)) {
- config.iso.low = camera.CameraISO[0]
- }
- if (!camera.CameraISO.includes(config.iso.high)) {
- config.iso.high = camera.CameraISO[0]
- }
- }
- }
- }
- })
- },
- { deep: true }
- )
- watch(multiConfig, (newVal) => {
- const isoConfig = {}
- Object.keys(newVal).forEach(key => {
- isoConfig[key] = {
- iso: newVal[key].iso,
- CameraKey: newVal[key].CameraKey,
- CameraName: newVal[key].CameraName
- }
- })
- emit('update:camera_configs', {
- iso_config: isoConfig,
- })
- }, { deep: true })
- onMounted(() => {
- if (props.camera_configs.iso_config) {
- const config = props.camera_configs.iso_config
- if (config.low !== undefined || config.high !== undefined) {
- multiConfig.A.iso.low = String(config.low || '100')
- multiConfig.A.iso.high = String(config.high || '6400')
- } else {
- Object.keys(config).forEach(key => {
- if (multiConfig[key] !== undefined) {
- if (config[key].iso) {
- multiConfig[key].iso.low = config[key].iso.low || '100'
- multiConfig[key].iso.high = config[key].iso.high || '6400'
- }
- if (config[key].CameraKey) {
- multiConfig[key].CameraKey = config[key].CameraKey
- multiConfig[key].CameraName = config[key].CameraName || ''
- }
- }
- })
- }
- }
- activePoint.value = 'A'
- fetchCameraList()
- })
- const save = () => {
- const current = multiConfig[activePoint.value]
- const isEmpty = (v) => v === undefined || v === null || v === ''
- if (isEmpty(current.iso.low)) {
- ElMessage.error('请选择拍照ISO')
- return false
- }
- if (isEmpty(current.iso.high)) {
- ElMessage.error('请选择预览ISO')
- return false
- }
- const lowNum = Number(current.iso.low)
- const highNum = Number(current.iso.high)
- if (!Number.isNaN(lowNum) && lowNum <= 0) {
- ElMessage.error('拍照ISO必须大于0')
- return false
- }
- if (!Number.isNaN(highNum) && highNum <= 0) {
- ElMessage.error('预览ISO必须大于0')
- return false
- }
- return true
- }
- defineExpose({ save })
- </script>
- <style lang="scss" scoped>
- .selectBox {
- padding-top: 10px;
- padding-bottom: 50px;
- }
- .multi-camera-config {
- padding-top: 20px;
- padding-left: 100px;
- }
- .point-tabs {
- display: flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 20px;
- }
- .point-tab {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 10px 20px;
- background: #F5F7FA;
- border: 2px solid #E4E7ED;
- border-radius: 8px;
- cursor: pointer;
- transition: all 0.3s;
- &:hover {
- border-color: #C0C4CC;
- }
- &.active {
- background: #ECF5FF;
- border-color: #409EFF;
- }
- .tab-name {
- font-weight: bold;
- color: #303133;
- }
- }
- .refresh-btn {
- margin-left: auto;
- }
- .current-point-config {
- overflow: hidden;
- max-width: 500px;
- .config-body {
- padding: 24px 20px;
- .form-item {
- margin-bottom: 20px;
- label {
- display: block;
- margin-bottom: 8px;
- font-size: 14px;
- }
- .camera-select-wrapper {
- max-width: 200px;
- }
- }
- .iso-section {
- display: flex;
- gap: 20px;
- flex-wrap: wrap;
- }
- .iso-group {
- display: flex;
- align-items: center;
- gap: 15px;
- .iso-label {
- min-width: 125px;
- font-size: 14px;
- text-align: right;
- color: #1A1A1A;
- }
- }
- }
- }
- .select-wrapper {
- :deep(.el-input__inner) {
- border-radius: 6px;
- }
- }
- :deep(.el-select) {
- width: 100%;
- }
- :deep(.camera-select-wrapper .el-select) {
- width: 300px;
- }
- </style>
|