| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- <template>
- <el-dialog
- v-model="visible"
- :title="title"
- :close-on-click-modal="false"
- :close-on-press-escape="false"
- :show-close="false"
- width="680px"
- class="hardware-check-dialog"
- >
- <div class="hardware-check-container">
- <el-timeline>
- <el-timeline-item type="primary" :hollow="true">
- <template #dot>
- <div class="step-dot">1</div>
- </template>
- <div class="step-content">
- <div class="step-title">
- <template v-if="checkLoading">正在初始化检测硬件......</template>
- <template v-else-if="checkSuccess">硬件检测完成</template>
- <template v-else>初始化检测硬件失败</template>
- </div>
- <el-progress
- v-if="checkLoading"
- :percentage="checkInfoStore.getProgress"
- :colors="['#2FB0FF', '#B863FB']"
- :stroke-width="8"
- />
- <div class="check-error-result" v-else-if="!checkSuccess">
- 失败的原因,{{ checkInfoStore.getErrorMsg }}
- </div>
- </div>
- </el-timeline-item>
- <el-timeline-item type="primary" :hollow="true">
- <template #dot>
- <div class="step-dot">2</div>
- </template>
- <div class="step-content">
- <div class="step-title">自我检查</div>
- <div class="check-result">
- <p>补光灯电源和连接器是否正常连上。</p>
- <p>请检查红外线器是否正常显示。</p>
- </div>
- </div>
- </el-timeline-item>
- </el-timeline>
- <div class="device-summary">
- <div class="device-row">
- <span class="device-label">MCU设备</span>
- <span class="device-value" :class="mcuConnected ? 'is-ok' : 'is-bad'">
- {{ mcuConnected ? '已连接MCU' : '未连接MCU' }}
- </span>
- <span class="device-serial" v-if="serialSummary">{{ serialSummary }}</span>
- </div>
- <div class="device-row">
- <span class="device-label">相机设备</span>
- <span class="device-value" :class="cameraConnected ? 'is-ok' : 'is-bad'">
- {{ cameraConnected ? '已连接相机' : '未连接相机' }}
- </span>
- </div>
- <div class="motor-grid">
- <div class="motor-item" v-for="item in motorItems" :key="item.key">
- <div class="motor-name">{{ item.label }}</div>
- <div class="motor-status" :class="getStatusClass(deviceStatusStore.runStatus[item.key])">
- {{ getStatusText(deviceStatusStore.runStatus[item.key]) }}
- </div>
- </div>
- </div>
- <div class="device-log-box">
- <div v-if="recentLogs.length === 0" class="log-empty">暂无设备上报信息</div>
- <div v-else class="log-list">
- <div v-for="(log, index) in recentLogs" :key="index" class="log-item">
- <span class="log-time">{{ log.current_time }}</span>
- <span class="log-message">{{ log.message }}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
- <template #footer v-if="!checkLoading">
- <div class="flex" v-if="!checkSuccess">
- <div class="check-btn cu-p" style="width: 160px; margin-right: 10px;" @click="reCheck">重新监测一次</div>
- <div class="check-btn check-btn-secondary cu-p" style="width: 160px;" @click="openStatusDialog">查看设备状态</div>
- </div>
- <div class="flex" v-else>
- <div class="check-btn cu-p" style="width: 180px" @click="confirm()">检测成功,继续操作!</div>
- </div>
- </template>
- </el-dialog>
- </template>
- <script setup>
- import { ref, watch, watchEffect, computed, onUnmounted } from 'vue';
- import useUserInfo from "@/stores/modules/user";
- import checkInfo from "@/stores/modules/check";
- import client from "@/stores/modules/client";
- import useDeviceStatusStore from '@/stores/modules/deviceStatus';
- const useUserInfoStore = useUserInfo()
- const checkInfoStore = checkInfo()
- const clientStore = client()
- const deviceStatusStore = useDeviceStatusStore()
- const checkSuccess = ref(false);
- const checkLoading = ref(true);
- const props = defineProps({
- isInitCheck: {
- type: Boolean,
- default: false
- },
- title: {
- type: String,
- default: '检测硬件'
- }
- });
- const emit = defineEmits(['confirm']);
- const checkCount = ref(props.isInitCheck ? 0 : 1);
- const visible = ref(false);
- const motorItems = [
- { key: 'state_camera_motor', label: '相机升降' },
- { key: 'state_camera_steering', label: '相机角度' },
- { key: 'state_move_turntable_steering', label: '前后移动' },
- { key: 'state_turntable_steering', label: '转盘电机' },
- { key: 'state_overturn_steering', label: '翻板' },
- ]
- const stateTextMap = {
- 0: '未初始化',
- 1: '运动中',
- 2: '已停止',
- 3: '未在线',
- 4: '堵转'
- }
- const mcuConnected = computed(() => checkInfoStore.mcuConnected)
- const serialSummary = computed(() => checkInfoStore.serialSummary)
- const cameraConnected = computed(() => checkInfoStore.devices.cam_control.status === 2)
- const recentLogs = computed(() =>
- (deviceStatusStore.logs || []).filter((log) => log.message)
- )
- function getStatusText(status) {
- return stateTextMap[status] || '未知状态'
- }
- function getStatusClass(status) {
- const classMap = {
- 0: 'status-uninit',
- 1: 'status-moving',
- 2: 'status-stopped',
- 3: 'status-offline',
- 4: 'status-blocked'
- }
- return classMap[status] || 'status-unknown'
- }
- function syncMotorListen() {
- if (visible.value && checkInfoStore.mcuConnected) {
- deviceStatusStore.startRunStatusListen()
- } else {
- deviceStatusStore.stopRunStatusListen()
- if (!checkInfoStore.mcuConnected) {
- deviceStatusStore.resetRunStatus()
- }
- }
- }
- function startProgress() {
- checkInfoStore.set_isCheckStatus(true);
- checkLoading.value = true;
- checkSuccess.value = false;
- deviceStatusStore.resetRunStatus()
- checkInfoStore.reCheckAction()
- deviceStatusStore.fetchLogs()
- }
- function reCheck() {
- startProgress()
- }
- watchEffect(async ()=>{
- if( useUserInfoStore.userInfo.id && checkCount.value === 0 && checkInfoStore.isCheckStatus){
- if(clientStore.isClient){
- visible.value = true
- //python 启动有延时,延迟2秒执行
- setTimeout(()=>{
- startProgress()
- },5000)
- }
- checkCount.value++;
- }
- })
- watchEffect(async ()=>{
- if( checkCount.value >= 1 && checkInfoStore.getProgress !== 100 && !checkInfoStore.isCheckStatus){
- localStorage.setItem('check',false)
- visible.value = true
- checkLoading.value = false;
- checkSuccess.value = false;
- }
- })
- watchEffect(async ()=>{
- if(checkInfoStore.getProgress === 100 ){
- checkLoading.value = false;
- checkSuccess.value = true;
- }
- })
- watchEffect(async ()=>{
- if( checkInfoStore.getErrorMsg){
- checkLoading.value = false;
- checkSuccess.value = false;
- }
- })
- watchEffect(async ()=>{
- if( checkInfoStore.getProgress === 100){
- checkLoading.value = false;
- checkSuccess.value = true;
- }
- })
- watch(visible, (val) => {
- if (val) {
- deviceStatusStore.fetchLogs()
- checkInfoStore.requestHardwareCheckInfo()
- }
- syncMotorListen()
- })
- watch(() => checkInfoStore.mcuConnected, (connected) => {
- if (visible.value && connected) {
- checkInfoStore.requestHardwareCheckInfo()
- }
- syncMotorListen()
- })
- function confirm(){
- visible.value = false;
- checkInfoStore.set_isCheckStatus(false);
- localStorage.setItem('check',true)
- emit('confirm')
- }
- function openStatusDialog() {
- deviceStatusStore.openDialog();
- }
- onUnmounted(() => {
- deviceStatusStore.stopRunStatusListen()
- })
- </script>
- <style lang="scss" scoped>
- .hardware-check-container {
- padding: 8px 8px 0;
- text-align: left;
- }
- .step-content {
- flex: 1;
- }
- .step-title {
- font-weight: 600;
- font-size: 14px;
- color: #000000;
- margin-bottom: 12px;
- padding-top: 4px;
- text-align: left;
- }
- .check-result {
- color: rgba(0,0,0,0.45);
- text-align: left;
- p {
- margin: 8px 0;
- }
- }
- :deep(.el-progress-bar__inner) {
- background-image: linear-gradient(to right, #409EFF, #7e57c2);
- }
- :deep(.el-timeline) {
- padding-left: 4px;
- }
- :deep(.el-timeline-item__tail) {
- left: 7px;
- }
- .step-dot {
- width: 22px;
- height: 22px;
- border-radius: 50%;
- background: #2F6BFF;
- color: #fff;
- font-size: 13px;
- font-weight: 600;
- display: flex;
- align-items: center;
- justify-content: center;
- position: relative;
- left: -5px;
- }
- .check-btn{
- width: 100px;
- height: 40px;
- background: linear-gradient( 135deg, #2FB0FF 0%, #B863FB 100%);
- border-radius: 4px;
- font-weight: 400;
- font-size: 16px;
- color: #FFFFFF;
- text-align: center;
- line-height: 40px;
- }
- .check-error-result{
- font-size: 14px;
- text-align: left;
- color: #FF4C00;
- }
- .check-btn-secondary {
- background: linear-gradient(135deg, #909399 0%, #C0C4CC 100%);
- }
- .device-summary {
- margin-top: 4px;
- padding-left: 36px;
- }
- .device-row {
- display: flex;
- align-items: center;
- margin-bottom: 10px;
- font-size: 14px;
- line-height: 22px;
- }
- .device-label {
- color: #333;
- min-width: 72px;
- margin-right: 12px;
- }
- .device-value {
- font-weight: 600;
- &.is-ok {
- color: #67C23A;
- }
- &.is-bad {
- color: #F56C6C;
- }
- }
- .device-serial {
- margin-left: auto;
- color: #F56C6C;
- font-size: 13px;
- text-align: right;
- max-width: 280px;
- }
- .motor-grid {
- display: grid;
- grid-template-columns: repeat(5, 1fr);
- gap: 8px;
- margin: 8px 0 14px;
- }
- .motor-item {
- text-align: left;
- }
- .motor-name {
- font-size: 13px;
- color: #333;
- margin-bottom: 4px;
- }
- .motor-status {
- font-size: 13px;
- font-weight: 500;
- &.status-uninit,
- &.status-unknown {
- color: #909399;
- }
- &.status-moving {
- color: #E6A23C;
- }
- &.status-stopped {
- color: #67C23A;
- }
- &.status-offline,
- &.status-blocked {
- color: #F56C6C;
- }
- }
- .device-log-box {
- background: #F5F6F7;
- border-radius: 8px;
- padding: 8px 12px;
- min-height: 108px;
- max-height: 180px;
- overflow-y: auto;
- width: 100%;
- box-sizing: border-box;
- text-align: left !important;
- }
- .log-empty {
- color: #999;
- font-size: 13px;
- line-height: 22px;
- text-align: left !important;
- }
- .log-list {
- width: 100%;
- text-align: left !important;
- }
- .log-item {
- display: flex;
- justify-content: flex-start;
- align-items: flex-start;
- width: 100%;
- box-sizing: border-box;
- padding: 8px 0;
- border-bottom: 1px solid #f0f0f0;
- font-size: 13px;
- text-align: left !important;
- &:last-child {
- border-bottom: none;
- }
- }
- .log-time {
- flex-shrink: 0;
- color: #999;
- margin-right: 12px;
- min-width: 150px;
- line-height: 20px;
- text-align: left !important;
- }
- .log-message {
- flex: 1;
- color: #333;
- word-break: break-all;
- line-height: 20px;
- text-align: left !important;
- }
- </style>
- <style lang="scss">
- .hardware-check-dialog {
- .el-dialog__title {
- display: block;
- width: 100%;
- text-align: center;
- font-size: 16px;
- font-weight: 400;
- color: #333;
- }
- .el-dialog__body {
- padding-top: 10px;
- text-align: left !important;
- }
- .device-log-box,
- .log-list,
- .log-item,
- .log-time,
- .log-message,
- .log-empty {
- text-align: left !important;
- }
- }
- </style>
|