合并代码

This commit is contained in:
limengnan 2026-02-09 09:34:20 +08:00
commit 6e4ec82e17
6 changed files with 504 additions and 74 deletions

View File

@ -30,7 +30,7 @@ backend = directshow
[CAMERA2]
enable = True
device_index = 1
device_index = 2
width = 1280
height = 720
fps = 30
@ -39,7 +39,7 @@ fourcc = MJPG
backend = directshow
[FEMTOBOLT]
enable = False
enable = True
algorithm_type = plt
color_resolution = 1080P
depth_mode = NFOV_2X2BINNED
@ -54,13 +54,13 @@ imu_enable = True
imu_use_mock = False
imu_ble_name = WT901BLE67
imu_mac_address = FA:E8:88:06:FE:F3
pressure_enable = False
pressure_use_mock = False
pressure_port = COM5
pressure_enable = True
pressure_use_mock = True
pressure_port = COM3
pressure_baudrate = 115200
[REMOTE]
enable = True
enable = False
port = COM6
baudrate = 115200
timeout = 0.1

View File

@ -57,6 +57,10 @@ class DeviceCoordinator:
self.is_initialized = False
self.is_running = False
self.coordinator_lock = threading.RLock()
self._init_summary = {
'initialized_at': None,
'device_results': {},
}
# 监控线程
self.monitor_thread = None
@ -116,8 +120,12 @@ class DeviceCoordinator:
self._register_namespaces()
# 初始化设备(失败则降级继续)
if not self._initialize_devices():
self.logger.warning("设备初始化失败,将以降级模式继续运行")
init_ok = bool(self._initialize_devices())
self._init_summary['initialized_at'] = time.time()
if not init_ok:
self.logger.warning("设备初始化失败(没有任何设备初始化成功)")
self.is_initialized = False
return False
self.is_initialized = True
self.stats['start_time'] = time.time()
@ -195,12 +203,14 @@ class DeviceCoordinator:
try:
timeout_s = 45 if device_name == 'imu' else 30
result = future.result(timeout=timeout_s)
self._init_summary['device_results'][device_name] = bool(result)
if result:
success_count += 1
self.logger.info(f"{device_name}设备初始化成功")
else:
self.logger.error(f"{device_name}设备初始化失败")
except Exception as e:
self._init_summary['device_results'][device_name] = False
self.logger.error(f"{device_name}设备初始化异常: {e}")
# 至少需要一个设备初始化成功
@ -215,6 +225,97 @@ class DeviceCoordinator:
self.logger.error(f"设备初始化失败: {e}")
return False
def get_enabled_devices(self) -> List[str]:
enabled = []
try:
for name, cfg in (self.device_configs or {}).items():
if isinstance(cfg, dict) and cfg.get('enable', False):
enabled.append(name)
except Exception:
pass
return enabled
def get_required_devices_for_detection(self) -> List[str]:
enabled = self.get_enabled_devices()
required = [d for d in enabled if d not in ('remote',)]
return required
def get_device_readiness(self, device_name: str) -> Dict[str, Any]:
enabled = bool(self.device_configs.get(device_name, {}).get('enable', False))
device = self.devices.get(device_name)
readiness = {
'device_name': device_name,
'enabled': enabled,
'exists': device is not None,
'initializing': False,
'is_connected': False,
'is_streaming': False,
'ready': False,
}
if not device:
return readiness
status = None
try:
if hasattr(device, 'get_status'):
status = device.get_status()
except Exception:
status = None
try:
readiness['initializing'] = bool(getattr(device, '_initializing', False))
except Exception:
readiness['initializing'] = False
try:
if isinstance(status, dict) and 'is_connected' in status:
readiness['is_connected'] = bool(status.get('is_connected'))
else:
readiness['is_connected'] = bool(getattr(device, 'is_connected', False))
except Exception:
readiness['is_connected'] = False
try:
if isinstance(status, dict) and 'is_streaming' in status:
readiness['is_streaming'] = bool(status.get('is_streaming'))
else:
readiness['is_streaming'] = bool(getattr(device, 'is_streaming', False))
except Exception:
readiness['is_streaming'] = False
ok = readiness['is_connected'] and (not readiness['initializing'])
readiness['ready'] = bool(ok)
return readiness
def get_readiness_snapshot(self, required_devices: Optional[List[str]] = None) -> Dict[str, Any]:
required = required_devices if required_devices is not None else self.get_required_devices_for_detection()
devices = {}
for name in required:
devices[name] = self.get_device_readiness(name)
all_ready = bool(self.is_initialized) and all(devices[name].get('ready', False) for name in devices)
return {
'coordinator': {
'is_initialized': bool(self.is_initialized),
'is_running': bool(self.is_running),
'enabled_devices': self.get_enabled_devices(),
'required_devices': required,
'init_summary': self._init_summary,
},
'devices': devices,
'all_ready': all_ready,
}
def wait_until_ready_for_detection(self, timeout_s: float = 10.0, poll_interval_s: float = 0.2) -> Dict[str, Any]:
deadline = time.time() + max(0.0, float(timeout_s))
last_snapshot = self.get_readiness_snapshot()
while time.time() < deadline:
last_snapshot = self.get_readiness_snapshot()
if last_snapshot.get('all_ready', False):
return last_snapshot
time.sleep(max(0.05, float(poll_interval_s)))
last_snapshot['timeout'] = True
last_snapshot['timeout_s'] = float(timeout_s)
return last_snapshot
def _init_camera_by_name(self, device_name: str, section: str = 'CAMERA1') -> bool:
"""
按名称初始化相机支持 camera1/camera2 并覆盖配置段

View File

@ -704,6 +704,7 @@ class PressureManager(BaseDevice):
Returns:
bool: 初始化是否成功
"""
self._initializing = True
try:
self.logger.info(f"正在初始化压力板设备...")
@ -716,13 +717,28 @@ class PressureManager(BaseDevice):
else:
self.device = MockPressureDevice()
connected = False
try:
if self.use_mock:
connected = True
elif hasattr(self.device, 'is_connected'):
connected = bool(self.device.is_connected)
else:
connected = bool(self.check_hardware_connection())
except Exception:
connected = False
# 使用set_connected方法启动连接监控线程
self.set_connected(True)
self.set_connected(bool(connected))
self._device_info.update({
'device_type': 'mock' if self.use_mock else 'real',
'matrix_size': '4x4' if hasattr(self.device, 'rows') else 'unknown'
})
if not connected:
self.logger.warning("压力板初始化完成但硬件未连接")
return False
self.logger.info(f"压力板初始化成功 - use_mock: {self.use_mock}")
return True
@ -732,6 +748,8 @@ class PressureManager(BaseDevice):
self.set_connected(False)
self.device = None
return False
finally:
self._initializing = False
def start_streaming(self) -> bool:

View File

@ -265,7 +265,7 @@ class AppServer:
def _initialize_devices(self):
"""
初始化设备在用户登录成功后调用
"""
try:
self.logger.info('开始初始化设备...')
@ -1294,21 +1294,37 @@ class AppServer:
if not self.db_manager or not self.device_coordinator:
return jsonify({'success': False, 'error': '数据库管理器或设备管理器未初始化'}), 500
# 检查设备是否已初始化
if self.device_coordinator and not self.device_coordinator.is_initialized:
self.logger.info('设备尚未初始化,等待初始化完成...')
# 最多等待10秒
start_wait = time.time()
while not self.device_coordinator.is_initialized:
if time.time() - start_wait > 10:
return jsonify({'success': False, 'error': '设备初始化超时,请稍后重试'}), 503
time.sleep(0.5)
self.logger.info('设备初始化完成,继续开始检测')
data = flask_request.get_json()
data = flask_request.get_json() or {}
patient_id = data.get('patient_id')
creator_id = data.get('creator_id')
force_start = bool(data.get('force_start', False))
if self.device_coordinator:
if not getattr(self.device_coordinator, 'is_initialized', False):
try:
threading.Thread(target=self._initialize_devices, daemon=True).start()
except Exception:
pass
readiness = {}
if not force_start:
try:
readiness = self.device_coordinator.wait_until_ready_for_detection(timeout_s=10.0, poll_interval_s=0.2)
except Exception as e:
self.logger.error(f'等待设备就绪失败: {e}')
readiness = {}
if not readiness or not readiness.get('all_ready', False):
return jsonify({
'success': False,
'error': '设备未就绪,请稍后重试',
'readiness': readiness
}), 503
else:
try:
readiness = self.device_coordinator.get_readiness_snapshot()
except Exception:
readiness = {}
if not patient_id or not creator_id:
return jsonify({'success': False, 'error': '缺少患者ID或创建人ID'}), 400
@ -1324,7 +1340,7 @@ class AppServer:
except Exception as monitor_error:
self.logger.error(f'启动设备连接监控失败: {monitor_error}')
return jsonify({'success': True, 'session_id': session_id})
return jsonify({'success': True, 'session_id': session_id, 'forced': bool(force_start), 'readiness': readiness})
except Exception as e:
self.logger.error(f'开始检测失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@ -1368,8 +1384,6 @@ class AppServer:
item_copy['type'] = 'video'
result_data.append(item_copy)
# 按时间戳排序
result_data.sort(key=lambda x: x.get('timestamp', ''), reverse=False)
return jsonify({
'success': True,

View File

@ -39,7 +39,7 @@
</div>
<div class="displayleft" style="width: 550px;
justify-content: flex-end;padding-right: 5px;">
<div class="icon-box" title="相机参数设置" @click="cameraUpdate">
<div class="icon-box" title="设备参数设置" @click="cameraUpdate">
<img src="@/assets/detection/settings.png" alt="" >
</div>
<div class="icon-box" title="查看档案" @click="routerClick">
@ -239,16 +239,17 @@
<div style="width:100%;height: 50px;"></div>
<div class="body-footbottom-leftbottom">
<div class="body-footbottom-leftbox">
<span class="currencytext1">右前足</span>
<span class="currencytext2">
{{ footPressure.right_front }}%
</span>
<span class="currencytext1">右前足</span>
</div>
<div class="body-footbottom-leftbox">
<span class="currencytext1">右后足</span>
<span class="currencytext2">
{{ footPressure.right_rear }}%
</span>
<span class="currencytext1">右后足</span>
</div>
<!-- <div class="body-footbottom-leftbox">
<span class="currencytext1">右足总压力</span>
@ -780,6 +781,37 @@
</el-row>
</div>
<!-- 无操作退出提示 -->
<div class="pop-up-mask init-mask" v-if="isSystemInitializing">
<div class="init-loading-container">
<div v-if="!initFailed" class="init-loading-content">
<div class="init-spinner"></div>
<div class="init-loading-text">{{ initLoadingText }}</div>
</div>
<div v-else class="init-failed-content">
<div class="init-failed-title">设备未就绪</div>
<div class="init-failed-subtitle">{{ initErrorText || '请检查设备连接与配置后重试' }}</div>
<div class="init-failed-list" v-if="notReadyDevices.length">
<div class="init-failed-item" v-for="item in notReadyDevices" :key="item.device_name">
<div class="init-failed-item-left">
<div class="init-failed-item-name">{{ getDeviceDisplayName(item.device_name) }}</div>
<div class="init-failed-item-reason">{{ getNotReadyReason(item) }}</div>
</div>
<div class="init-failed-item-right">
<div class="init-failed-item-kv">是否启用: {{ item.enabled === false ? 'N' : 'Y' }}</div>
<div class="init-failed-item-kv">是否创建实例: {{ item.exists ? 'Y' : 'N' }}</div>
<div class="init-failed-item-kv">是否初始化中: {{ item.initializing ? 'Y' : 'N' }}</div>
<div class="init-failed-item-kv">是否已连接: {{ item.is_connected ? 'Y' : 'N' }}</div>
</div>
</div>
</div>
<div class="init-failed-actions">
<el-button @click="handleInitBack">返回</el-button>
<el-button type="primary" @click="handleInitProceed">进入检测</el-button>
</div>
</div>
</div>
</div>
<div class="pop-up-mask" v-if="isTip">
<div class="pop-up-tip-container">
<div class="pop-up-tip-header">
@ -808,7 +840,7 @@
<div class="pop-up-mask" v-if="cameraDialogVisible">
<div class="pop-up-camera-container">
<div class="pop-up-camera-header">
<div>相机参数设置</div>
<div>设备参数设置</div>
<img src="@/assets/close.png" alt="" style="cursor: pointer;" @click="handleCameraCancel">
</div>
<div class="pop-up-camera-body">
@ -826,7 +858,7 @@
<el-checkbox v-model="cameraForm.femtobolt.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
</div>
<div class="pop-up-camera-display" style="padding-top: 30px;padding-bottom: 10px;">
<div class="pop-up-camera-display" style="padding-top: 20px;padding-bottom: 10px;">
<div class="pop-up-camera-line"></div>
<div class="pop-up-camera-title">足部相机</div>
</div>
@ -856,20 +888,9 @@
</el-radio-group>
<el-checkbox v-model="cameraForm.camera2.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
</div>
<div class="pop-up-camera-display" style="padding-top: 30px;padding-bottom: 00px;">
<div class="pop-up-camera-line"></div>
<div class="pop-up-camera-title">遥控器</div>
</div>
<div class="pop-up-camera-display" style="padding-top: 10px;">
<div class="pop-up-camera-name">串口号</div>
<el-select v-model="cameraForm.remote.port" placeholder="请选择" style="width: 434px;">
<el-option v-for="item in remotePortData" :label="item" :value="item" />
</el-select>
<el-checkbox v-model="cameraForm.remote.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
</div>
<div class="pop-up-camera-display" style="padding-top: 30px;padding-bottom: 00px;">
<div class="pop-up-camera-display" style="padding-top: 20px;padding-bottom: 00px;">
<div class="pop-up-camera-line"></div>
<div class="pop-up-camera-title">IMU设备</div>
</div>
@ -884,6 +905,29 @@
</div>
<div class="pop-up-camera-display" style="padding-top: 20px;padding-bottom: 0px;">
<div class="pop-up-camera-line"></div>
<div class="pop-up-camera-title">足底压力板</div>
</div>
<div class="pop-up-camera-display" style="padding-top: 10px;">
<div class="pop-up-camera-name">串口号</div>
<el-select v-model="cameraForm.pressure.port" placeholder="请选择" style="width: 434px;">
<el-option v-for="item in remotePortData" :label="item" :value="item" />
</el-select>
<el-checkbox v-model="cameraForm.pressure.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
</div>
<div class="pop-up-camera-display" style="padding-top: 20px;padding-bottom: 00px;">
<div class="pop-up-camera-line"></div>
<div class="pop-up-camera-title">遥控器</div>
</div>
<div class="pop-up-camera-display" style="padding-top: 10px;">
<div class="pop-up-camera-name">串口号</div>
<el-select v-model="cameraForm.remote.port" placeholder="请选择" style="width: 434px;">
<el-option v-for="item in remotePortData" :label="item" :value="item" />
</el-select>
<el-checkbox v-model="cameraForm.remote.enable" label="有效" size="large" style="width: 60px;margin-left:10px ;" />
</div>
<div class="form-actions-display">
<el-button @click="handleCameraCancel" class="formreturnCancel">退出</el-button>
<el-button type="primary" class="formsaveCancel"
@ -960,6 +1004,84 @@ const isCloseCreat =ref(false) // 是否打开患者信息编辑框
const isoperation = ref(false) //
const isVideoOperation = ref(false) //
const isTip =ref(false)
const isSystemInitializing = ref(false)
const initLoadingText = ref('系统设备正在初始化,请等待...')
const initFailed = ref(false)
const initErrorText = ref('')
const initReadiness = ref(null)
const notReadyDevices = computed(() => {
const r = initReadiness.value
const devices = r && r.devices ? r.devices : null
if (!devices) return []
const list = []
Object.keys(devices).forEach((k) => {
const v = devices[k]
if (v && v.enabled !== false && v.ready === false) {
list.push(v)
}
})
return list
})
function getNotReadyReason(item) {
if (!item) return '未知'
if (item.enabled === false) return '未启用'
if (!item.exists) return '设备实例未创建'
if (item.initializing) return '初始化中'
if (!item.is_connected) return '未连接'
return '未就绪'
}
function getDeviceDisplayName(deviceName) {
const name = String(deviceName || '').trim()
const map = {
camera1: '足部相机上',
camera2: '足部相机下',
femtobolt: '深度相机',
imu: '头部姿态IMU',
pressure: '足底压力板',
remote: '遥控器',
}
return map[name] || name
}
function handleInitBack() {
try {
isSystemInitializing.value = false
initFailed.value = false
initErrorText.value = ''
initReadiness.value = null
} catch (e) {
}
try {
emit('endChange', false)
} catch (e2) {
}
try {
routeTo('/')
} catch (e3) {
}
}
async function handleInitProceed() {
try {
initLoadingText.value = '正在进入检测...'
initFailed.value = false
initErrorText.value = ''
initReadiness.value = null
isSystemInitializing.value = true
await startDetection({ forceStart: true, silent: true })
connectWebSocket()
isSystemInitializing.value = false
} catch (e) {
const msg = String((e && e.message) ? e.message : (e || ''))
const readiness = (e && e.readiness) ? e.readiness : null
if (readiness) {
initReadiness.value = readiness
}
initFailed.value = true
initErrorText.value = msg || '进入检测失败'
initLoadingText.value = '系统设备正在初始化,请等待...'
isSystemInitializing.value = true
ElMessage.error(`进入检测失败: ${initErrorText.value}`)
}
}
const isStartVideo = ref(false)
function startVideoClick() {
startRecord()
@ -1117,6 +1239,10 @@ const cameraForm = ref({ // 相机参数
port: '', //
enable: false
},
pressure:{
port: '',
enable: false
},
})
const calculatedAge = ref(null)
@ -1359,7 +1485,12 @@ function cameraUpdate() { // 相机设置数据更新弹框
enable: false
},
remote:{
port: '', // IMU
port: '',
enable: false
},
pressure:{
port: '',
enable: false
}
}
//
@ -2198,10 +2329,13 @@ async function sendDetectionData(data) {
// }
// }
//
async function startDetection() {
async function startDetection(options = {}) {
try {
console.log('🚀 正在开始检测...')
const forceStart = !!(options && options.forceStart)
const silent = !!(options && options.silent)
// API
const response = await fetch(`${BACKEND_URL}/api/detection/start`, {
method: 'POST',
@ -2212,10 +2346,21 @@ async function startDetection() {
patient_id: patientId.value,
//
creator_id: creatorId.value,
force_start: forceStart,
})
})
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
let errorMsg = `HTTP ${response.status}: ${response.statusText}`
let readiness = null
try {
const err = await response.json()
readiness = (err && err.readiness) ? err.readiness : null
errorMsg = (err && (err.error || err.message)) ? (err.error || err.message) : errorMsg
} catch (e) {
}
const ex = new Error(errorMsg)
ex.readiness = readiness
throw ex
}
const result = await response.json()
if (result.success) {
@ -2228,7 +2373,9 @@ async function startDetection() {
} catch (error) {
console.error('💥 开始检测失败:', error)
if (!(options && options.silent)) {
ElMessage.error(`开始检测失败: ${error.message}`)
}
throw error
}
}
@ -2432,7 +2579,7 @@ const getDevicesInit = async () => {
if (response.ok) {
const result = await response.json()
if (result.success) {
console.log('相机参数加载成功:', result.data)
console.log('设备参数加载成功:', result.data)
cameraForm.value = result.data
cameraDialogVisible.value = true
// console.log(':', patientInfo.value)
@ -2443,12 +2590,12 @@ const getDevicesInit = async () => {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
} catch (error) {
console.error('加载相机参数失败:', error)
ElMessage.warning('加载相机参数失败,请检查网络连接')
console.error('加载设备参数失败:', error)
ElMessage.warning('加载设备参数失败,请检查网络连接')
}
}
onMounted(() => {
onMounted(async () => {
for(let i = 0; i < 20; i++){
let port = "COM" + (i + 1)
remotePortData.value.push(port)
@ -2459,12 +2606,35 @@ onMounted(() => {
}
patientId.value = props.selectedPatient.id
//patientId.value = '202511150005'
//
loadPatientInfo()
//
startDetection()
// WebSocket
try {
isSystemInitializing.value = true
initFailed.value = false
initErrorText.value = ''
initReadiness.value = null
await loadPatientInfo()
await startDetection()
connectWebSocket()
isSystemInitializing.value = false
} catch (e) {
const msg = String((e && e.message) ? e.message : (e || ''))
const readiness = (e && e.readiness) ? e.readiness : null
if (readiness) {
initReadiness.value = readiness
initFailed.value = true
initErrorText.value = msg || '设备未就绪,请稍后重试'
initLoadingText.value = '系统设备正在初始化,请等待...'
isSystemInitializing.value = true
ElMessage.error('设备初始化失败,请检查未就绪设备')
return
}
isSystemInitializing.value = false
if (msg) {
ElMessage.error(msg)
} else {
ElMessage.error('进入检测失败')
}
handleInitBack()
}
//
window.addEventListener('beforeunload', handleBeforeUnload)
@ -3349,6 +3519,129 @@ function viewClick(e){
height: 100vh;
background: rgba(0, 0, 0, 0.7);
}
.init-mask{
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
}
.init-loading-container{
width: 520px;
max-width: calc(100vw - 40px);
max-height: calc(100vh - 140px);
border-radius: 12px;
background: linear-gradient(135deg, rgba(53, 67, 90, 1) 0%, rgba(53, 67, 90, 1) 0%, rgba(62, 79, 105, 1) 99%, rgba(62, 79, 105, 1) 100%);
display: flex;
align-items: center;
justify-content: center;
box-shadow: rgb(17, 24, 33) 0px 0px 10px;
padding: 18px 20px;
box-sizing: border-box;
}
.init-loading-content{
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.init-spinner{
width: 34px;
height: 34px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: rgba(59, 242, 198, 1);
border-radius: 50%;
animation: initSpin 0.9s linear infinite;
}
.init-loading-text{
margin-top: 16px;
font-family:'Noto Sans SC Bold', 'Noto Sans SC Regular', 'Noto Sans SC';
font-weight:700;
font-style:normal;
font-size:16px;
color:#FFFFFF;
text-align: center;
}
@keyframes initSpin {
to { transform: rotate(360deg); }
}
.init-failed-content{
width: 100%;
}
.init-failed-title{
font-family:'Noto Sans SC Bold', 'Noto Sans SC Regular', 'Noto Sans SC';
font-weight:700;
font-style:normal;
font-size:18px;
color:#FFFFFF;
text-align: left;
}
.init-failed-subtitle{
margin-top: 8px;
font-family:'Noto Sans SC', 'Noto Sans SC Regular', 'Noto Sans SC';
font-weight:400;
font-style:normal;
font-size:14px;
color: rgba(255, 255, 255, 0.75);
text-align: left;
}
.init-failed-list{
margin-top: 14px;
max-height: 320px;
overflow: auto;
border-radius: 8px;
background: rgba(0, 0, 0, 0.18);
padding: 10px;
box-sizing: border-box;
}
.init-failed-item{
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.init-failed-item:last-child{
border-bottom: none;
}
.init-failed-item-left{
display: flex;
flex-direction: column;
}
.init-failed-item-name{
font-family:'Noto Sans SC Bold', 'Noto Sans SC Regular', 'Noto Sans SC';
font-weight:700;
font-style:normal;
font-size:14px;
color:#FFFFFF;
}
.init-failed-item-reason{
margin-top: 4px;
font-family:'Noto Sans SC', 'Noto Sans SC Regular', 'Noto Sans SC';
font-weight:400;
font-style:normal;
font-size:12px;
color: rgba(59, 242, 198, 0.95);
}
.init-failed-item-right{
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
font-family: 'Noto Sans SC';
font-weight:400;
font-style:normal;
font-size:12px;
color: rgba(255, 255, 255, 0.75);
}
.init-failed-item-kv{
white-space: nowrap;
}
.init-failed-actions{
margin-top: 14px;
display: flex;
justify-content: flex-end;
}
.pop-up-tip-container {
width: 400px;
@ -3364,7 +3657,7 @@ function viewClick(e){
}
.pop-up-camera-container{
width: 668px;
height:630px;
height:700px;
position: absolute;
top: 0;
right: 0;

View File

@ -426,7 +426,6 @@ const handleRegisterSubmit = async () => {
//
const handleLogin = async () => {
isLoading.value = true
//
if (!form.value.account) {
showError('请输入登录账号!')
@ -439,7 +438,9 @@ const handleLogin = async () => {
return
}
// 访32
isLoading.value = true
// 访3退200/400/800ms 1.4s
let healthOk = false
for (let attempt = 1; attempt <= 3; attempt++) {
try {
@ -451,9 +452,11 @@ const handleLogin = async () => {
// healthy
if (attempt === 3) {
showError('后台服务异常,请稍后重试!')
isLoading.value = false
return
}
await new Promise(resolve => setTimeout(resolve, 2000))
const delay = 200 * Math.pow(2, attempt - 1)
await new Promise(resolve => setTimeout(resolve, delay))
}
} catch (error) {
//
@ -462,7 +465,8 @@ const handleLogin = async () => {
isLoading.value = false
return
}
await new Promise(resolve => setTimeout(resolve, 2000))
const delay = 200 * Math.pow(2, attempt - 1)
await new Promise(resolve => setTimeout(resolve, delay))
}
}