进入检测页面,增加了设备是否就绪的检测。
This commit is contained in:
parent
def6304bd9
commit
75c3380ff3
@ -30,7 +30,7 @@ backend = directshow
|
||||
|
||||
[CAMERA2]
|
||||
enable = True
|
||||
device_index = 1
|
||||
device_index = 2
|
||||
width = 1280
|
||||
height = 720
|
||||
fps = 30
|
||||
@ -60,7 +60,7 @@ pressure_port = COM3
|
||||
pressure_baudrate = 115200
|
||||
|
||||
[REMOTE]
|
||||
enable = True
|
||||
enable = False
|
||||
port = COM6
|
||||
baudrate = 115200
|
||||
timeout = 0.1
|
||||
|
||||
@ -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 并覆盖配置段
|
||||
|
||||
@ -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:
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -778,6 +778,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">
|
||||
@ -970,6 +1001,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()
|
||||
@ -2217,10 +2326,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',
|
||||
@ -2231,10 +2343,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) {
|
||||
@ -2247,7 +2370,9 @@ async function startDetection() {
|
||||
|
||||
} catch (error) {
|
||||
console.error('💥 开始检测失败:', error)
|
||||
ElMessage.error(`开始检测失败: ${error.message}`)
|
||||
if (!(options && options.silent)) {
|
||||
ElMessage.error(`开始检测失败: ${error.message}`)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@ -2467,7 +2592,7 @@ const getDevicesInit = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
for(let i = 0; i < 20; i++){
|
||||
let port = "COM" + (i + 1)
|
||||
remotePortData.value.push(port)
|
||||
@ -2478,12 +2603,35 @@ onMounted(() => {
|
||||
}
|
||||
patientId.value = props.selectedPatient.id
|
||||
//patientId.value = '202511150005'
|
||||
// 加载患者信息
|
||||
loadPatientInfo()
|
||||
// 启动检测
|
||||
startDetection()
|
||||
// 页面加载时自动连接WebSocket
|
||||
connectWebSocket()
|
||||
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)
|
||||
@ -3368,6 +3516,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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user