This commit is contained in:
root 2025-08-07 16:22:42 +08:00
commit 6536a59c3c
16 changed files with 1244 additions and 870 deletions

View File

@ -106,14 +106,8 @@ def init_app():
# 初始化设备管理器
device_manager = DeviceManager(db_manager)
device_manager.set_socketio(socketio) # 设置WebSocket连接
# 自动启动推流以填充帧缓存
if device_manager.device_status['camera']:
streaming_result = device_manager.start_streaming()
logger.info(f'自动启动推流结果: {streaming_result}')
# 初始化视频流管理器
video_stream_manager = VideoStreamManager(socketio)
video_stream_manager = VideoStreamManager(socketio, device_manager)
logger.info('应用初始化完成')
@ -142,31 +136,6 @@ def api_health_check():
'version': '1.0.0'
})
@app.route('/api/frame-cache/status', methods=['GET'])
def get_frame_cache_status():
"""获取帧缓存状态"""
try:
if device_manager:
cache_info = device_manager.get_frame_cache_info()
return jsonify({
'success': True,
'data': cache_info,
'timestamp': datetime.now().isoformat()
})
else:
return jsonify({
'success': False,
'error': '设备管理器未初始化',
'timestamp': datetime.now().isoformat()
}), 500
except Exception as e:
logger.error(f'获取帧缓存状态失败: {e}')
return jsonify({
'success': False,
'error': str(e),
'timestamp': datetime.now().isoformat()
}), 500
# ==================== 认证API ====================
@app.route('/api/auth/login', methods=['POST'])
@ -720,7 +689,7 @@ def stop_detection(session_id):
}), 400
data = flask_request.get_json()
logger.debug(f'接收到停止检测请求session_id: {session_id}, 请求数据: {data}')
# logger.debug(f'接收到停止检测请求session_id: {session_id}, 请求数据: {data}')
# video_data = data.get('videoData') if data else None
video_data = data['videoData']
mime_type = data.get('mimeType', 'video/webm;codecs=vp9') # 默认webm格式
@ -743,11 +712,11 @@ def stop_detection(session_id):
}), 400
# 停止同步录制,传递视频数据
try:
logger.debug(f'调用device_manager.stop_recordingsession_id: {session_id}, video_data长度: {len(video_data) if video_data else 0}')
if video_data is None:
logger.warning(f'视频数据为空session_id: {session_id}')
else:
logger.debug(f'视频数据长度: {len(video_data)} 字符,约 {len(video_data)*3/4/1024:.2f} KB, session_id: {session_id}')
# logger.debug(f'调用device_manager.stop_recordingsession_id: {session_id}, video_data长度: {len(video_data) if video_data else 0}')
# if video_data is None:
# logger.warning(f'视频数据为空session_id: {session_id}')
# else:
# logger.debug(f'视频数据长度: {len(video_data)} 字符,约 {len(video_data)*3/4/1024:.2f} KB, session_id: {session_id}')
restrt=device_manager.stop_recording(session_id, video_data_base64=video_bytes)
logger.error(restrt)
except Exception as rec_e:

View File

@ -79,7 +79,7 @@ def init_app():
logger.info("设备管理器初始化成功")
# 初始化视频流管理器
video_stream_manager = VideoStreamManager()
video_stream_manager = VideoStreamManager(device_manager=device_manager)
logger.info("视频流管理器初始化成功")
logger.info("应用初始化完成")

View File

@ -658,8 +658,12 @@ class DatabaseManager:
logger.error(f'创建检测会话失败: {e}')
raise
def update_session_status(self, session_id: str, status: str):
"""更新会话状态"""
def update_session_status(self, session_id: str, status: str) -> bool:
"""更新会话状态
Returns:
bool: 更新成功返回True失败返回False
"""
conn = self.get_connection()
cursor = conn.cursor()
@ -681,11 +685,12 @@ class DatabaseManager:
conn.commit()
logger.info(f'更新会话状态: {session_id} -> {status}')
return True
except Exception as e:
conn.rollback()
logger.error(f'更新会话状态失败: {e}')
raise
return False
def update_session_duration(self, session_id: str, duration: int):
"""更新会话持续时间"""

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="15px" height="16px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -471 -604 )">
<path d="M 2.50414235937501 0 C 3.87625279687495 0 4.98789009375002 1.11158993749996 4.98789009375002 2.48291045312499 C 4.98789009375002 3.854964359375 3.87625432812501 4.96656957812502 2.50414235937501 4.96656957812502 C 1.13276376562499 4.96656957812502 0.0210974531249803 3.85494909374995 0.0210974531249803 2.48291045312499 C 0.0210974531249803 1.11158992187495 1.13276378124999 0 2.50414235937501 0 Z M 7.098429984375 0 C 7.78448520312497 0 8.34031149999998 0.555801843750032 8.34031149999998 1.24182956250002 C 8.34031149999998 1.92782671875 7.78448521874998 2.48364384374997 7.098429984375 2.48364384374997 C 6.41237475000003 2.48364384374997 5.85656374999996 1.92784200000006 5.85656374999996 1.24182956250002 C 5.85656374999996 0.555801843750032 6.41237476562503 0 7.098429984375 0 Z M 10.69892884375 0.309903156250016 C 11.38498559375 0.309889406250022 11.940795078125 0.865706515624993 11.940795078125 1.55173271875003 C 11.940795078125 2.23776043750001 11.3849840625001 2.79356228125005 10.69892884375 2.79356228125005 C 10.012873625 2.79356228125005 9.45704732812499 2.23776043750001 9.45704732812499 1.55173271875003 C 9.45704732812499 0.865705000000048 10.012873609375 0.309903156250016 10.69892884375 0.309903156250016 Z M 13.617007296875 1.92420717187497 C 14.30304725 1.92420717187497 14.8588888125 2.48001054687495 14.8588888125 3.16603673437498 C 14.8588888125 3.85206445312497 14.30306253125 4.407866296875 13.617007296875 4.407866296875 C 12.930952078125 4.407866296875 12.3751410625 3.85206445312497 12.3751410625 3.16603673437498 C 12.3751410625 2.480009015625 12.930952078125 1.92420717187497 13.617007296875 1.92420717187497 Z M 6.72520839062497 10.3674653125 C 6.11991084374995 9.57594962500002 3.09343687499995 9.34315098437503 3.88497240624997 6.36335835937496 C 3.88497240624997 6.36335835937496 4.676507953125 4.17506765625001 7.70299567187499 3.80259320312496 C 7.70299567187499 3.80259320312496 12.3751410625 3.47667328124999 13.1797766562499 8.0831213125 C 13.572634578125 10.333981796875 13.4089511562499 15.2096134375 9.79825217187499 15.95164409375 C 8.92667706249995 16.13062159375 6.399274703125 15.90800628125 6.72520839062497 13.626609578125 C 6.84015393749996 12.819808984375 7.59678350000002 11.506691546875 6.72520839062497 10.3674653125 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 471 604 )" />
</g>
</svg>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="20px" height="15px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -20 -68 )">
<path d="M 10 14.0353894412879 L 0.120591027462126 7.17959141216856 L 10 0.166593720407192 L 10 14.0353894412879 Z M 10 0.166647165009465 L 10 14.0814642814867 L 10.2509636008523 14.0585337653883 L 0.0753713896780255 7.17985866477272 L 10.2940986328125 0.119930900804931 L 10 0.166647165009465 Z M 10 0.21325651041667 L 0.165810635653429 7.17932415956439 L 10 13.9892611268939 L 10 0.21325651041667 Z M 18.5711613103693 7.92667737926136 C 19.9572551491477 9.55351497395833 19.9710989879262 12.3384774502841 19.9710989879262 12.3384774798769 C 19.9710989879262 12.3384774798769 19.7536599195076 11.1792300840436 19.0377893880208 10.4719651692708 C 18.4886862571023 9.92948999763257 18.1469199514678 9.62353589607008 17.3409308712122 9.45382868726325 C 15.2434029356061 9.01226917613636 5.67015113044505 9.45532531368372 5.67015113044505 9.45532531368372 L 5.67015113044505 5.42532640861742 C 5.67015113044505 5.42532640861742 12.0294419093277 5.32542631392046 14.1168676017992 5.76319078480114 C 14.736312352036 5.89307694128787 15.8322736446496 6.06043232125947 16.5773285097064 6.44191281960227 C 17.3805915897254 6.8532724609375 18.1643450224905 7.44925218986742 18.5711613103693 7.92667737926136 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 20 68 )" />
</g>
</svg>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="11px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -1271 -606 )">
<path d="M 11.3045078196872 1.90077626379218 L 11.3045078196872 3.21209917087594 C 11.3045078196872 3.26234142785233 11.251753449862 3.35026537756096 11.1462447102117 3.47587102000193 C 11.0407359705612 3.60147666244291 10.9276908923644 3.74969132052331 10.807109475621 3.92051499424303 C 10.6865280588777 4.09133866796276 10.5734829806809 4.2772350187754 10.4679742410303 4.47820404668096 C 10.36246550138 4.67917307458652 10.3097111315546 4.8851663281896 10.3097111315546 5.09618380749043 C 10.3097111315546 5.30720128679127 10.36246550138 5.5106824275457 10.4679742410303 5.70662722975362 C 10.5734829806809 5.90257203196154 10.6865280588777 6.08093204422767 10.807109475621 6.24170726655211 C 10.9276908923644 6.40248248887656 11.0407359705612 6.53562446986405 11.1462447102117 6.64113320951435 C 11.251753449862 6.74664194916477 11.3045078196872 6.81446899608295 11.3045078196872 6.84461435026878 L 11.3045078196872 8.42724544502494 C 11.3045078196872 8.59806911874466 11.2417049984667 8.79150180810382 11.1160993560259 9.00754351310229 C 10.9904937135848 9.22358521810077 10.8347427169581 9.42706635885509 10.6488463661453 9.61798693536537 C 10.4629500153328 9.80890751187565 10.2569567617295 9.96717062135133 10.0308666053359 10.0927762637922 C 9.80477644894199 10.2183819062332 9.5912468567924 10.2811847274537 9.39027782888684 10.2811847274537 L 1.89915731370752 10.2811847274537 C 1.62784912603502 10.2811847274537 1.37914995400183 10.2334545833261 1.15305979760819 10.1379942950709 C 0.926969641214328 10.0425340068159 0.728512726157533 9.90939202582842 0.557689052437809 9.7385683521087 C 0.386865378718085 9.56774467838898 0.25372339773071 9.36677565048342 0.158263109475683 9.13566126839203 C 0.0628028212204299 8.90454688630064 0.0150726770928031 8.65333560141869 0.0150726770928031 8.38202741374619 L 0.0150726770928031 1.88570358669926 C 0.0150726770928031 1.68473455879371 0.0602907083716673 1.47622919234175 0.150726770929168 1.26018748734327 C 0.241162833486669 1.0441457823448 0.369280588776519 0.845688867288118 0.53508003679849 0.664816742173116 C 0.700879484820689 0.483944617058114 0.896824287028494 0.333217846128946 1.12291444342236 0.212636429385611 C 1.349004599816 0.0920550126422768 1.59770377184918 0.0317643042706095 1.86901195952169 0.0317643042706095 L 9.360132474701 0.0317643042706095 C 9.63144066237351 0.0317643042706095 9.88516406010422 0.0794944483981226 10.1213026678934 0.174954736653262 C 10.3574412756823 0.270415024908402 10.5634345292856 0.401044893047015 10.7392824287028 0.5668443410691 C 10.9151303281203 0.732643789091185 11.0532965348052 0.93110070414798 11.153781048758 1.16221508623937 C 11.2542655627108 1.39332946833065 11.3045078196872 1.63951652751496 11.3045078196872 1.90077626379218 Z M 15.9921103955842 1.76512216995593 L 15.9921103955842 1.79526752414176 L 15.9921103955842 8.68348095560452 C 15.9921103955842 8.90454688630064 15.9343318000613 9.10049168850855 15.8187746090157 9.27131536222828 C 15.7032174179699 9.442139035948 15.5298816314014 9.52755087280786 15.29876724931 9.52755087280786 C 15.2183796381478 9.52755087280786 15.1153830113462 9.49740551862203 14.9897773689052 9.43711481025036 C 14.8641717264643 9.3768241018787 14.7385660840232 9.30648494211175 14.6129604415823 9.22609733094953 C 14.4873547991413 9.14570971978731 14.3692854952469 9.06532210862508 14.2587525298989 8.98493449746286 C 14.1482195645508 8.90454688630064 14.0678319533886 8.83923195223133 14.0175896964122 8.78898969525494 C 13.8869598282736 8.67845672990688 13.6885029132168 8.4875361533966 13.422218951242 8.21622796572422 C 13.1559349892671 7.94491977805171 12.8871389144433 7.63844201049574 12.615830726771 7.29679466305629 C 12.3445225390985 6.95514731561684 12.1058718184606 6.60345151678211 11.8998785648573 6.24170726655211 C 11.6938853112542 5.87996301632211 11.5908886844527 5.54836412027794 11.5908886844527 5.2469105784196 C 11.5908886844527 4.94545703656127 11.7014216498007 4.60129757627305 11.9224875804969 4.21443219755486 C 12.143553511193 3.82756681883666 12.4098374731677 3.44823777866497 12.7213394664213 3.07644507703969 C 13.032841459675 2.70465237541441 13.3594161300214 2.3604929151262 13.7010634774608 2.04396669617495 C 14.0427108249003 1.72744047722369 14.3290916896658 1.48878975658579 14.5602060717572 1.32801453426146 C 14.6506421343147 1.26772382588979 14.7737356639068 1.19487255327397 14.9294866605335 1.10946071641411 C 15.0852376571604 1.02404887955424 15.2234038638455 0.981342961124369 15.3439852805889 0.981342961124369 C 15.6152934682614 0.981342961124369 15.7911413676786 1.05670634658895 15.8715289788408 1.20743311751812 C 15.9519165900031 1.35815988844718 15.9921103955842 1.54405623925982 15.9921103955842 1.76512216995593 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 1271 606 )" />
</g>
</svg>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="15px" height="16px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -1271 -113 )">
<path d="M 0 2.30431893168605 C 0.0531561409884489 1.04717607194766 1.14285714026164 0.026578070494196 2.48903653706407 0.026578070494196 L 12.2352159520349 0.026578070494196 C 13.5800664425872 0.026578070494196 14.6710963481105 1.04717607194766 14.6710963481105 2.30431893168605 L 14.6710963481105 13.6956810683139 C 14.6710963481105 14.9528239280523 13.5813953488373 15.9734219295058 12.2352159520349 15.9734219295058 L 2.48903653706407 15.9734219295058 C 1.14418604651155 15.9734219295058 0.0531561409884489 14.9528239280523 0 13.6956810683139 L 0 2.30431893168605 Z M 12.2352159520349 1.16544851017443 L 2.48903653706407 1.16544851017443 C 1.81661128270343 1.16544851017443 1.2717607921511 1.67574751090118 1.2717607921511 2.30431893168605 L 1.2717607921511 13.6956810683139 C 1.2717607921511 14.3242524890989 1.81661128270343 14.8345515079942 2.48903653706407 14.8345514898256 L 12.2352159520349 14.8345514898256 C 12.9076412063955 14.8345514898256 13.4524916969476 14.3242524890989 13.4524916969476 13.6956810683139 L 13.4524916969476 2.30431893168605 C 13.4524916969476 1.67574751090118 12.9076412063955 1.16544849200582 12.2352159520349 1.16544851017443 Z M 2.71107331816233 5.34485049963664 C 2.71107331816233 5.71177420762504 3.00849157682455 6.00924165127614 3.37541527979647 6.00930232558139 C 3.74249176867511 6.0093023346657 4.03997698822059 5.71181711512028 4.03997698822059 5.34485049963664 C 4.03997698822059 4.97788388415299 3.74249176867511 4.68039866460757 3.37552515319135 4.68039866460757 C 3.00849157682455 4.68045934799713 2.71107331816233 4.9779267916482 2.71107331816233 5.34485049963664 Z M 2.71107331816233 8.0026578034157 C 2.71107331816233 8.36958151140411 3.00849157682455 8.66704895505521 3.37541527979647 8.66710962936045 C 3.74249176867511 8.66710963844477 4.03997698822059 8.36962441889935 4.03997698822059 8.0026578034157 C 4.03997698822059 7.63569118793205 3.74249176867511 7.33820596838663 3.37552515319135 7.33820596838663 C 3.00849157682455 7.33826665177619 2.71107331816233 7.63573409542727 2.71107331816233 8.0026578034157 Z M 3.37541527979647 11.3249169513082 C 3.74238189528023 11.3249169513082 4.03986711482571 11.0274317317627 4.03986711482571 10.6604651162791 C 4.03986711482571 10.2934985007954 3.74238189528023 9.99601328125001 3.37541527979647 9.99601328125001 C 3.00844866431294 9.99601328125001 2.71096344476746 10.2934985007954 2.71096344476746 10.6604651162791 C 2.71096344476746 11.0274317317627 3.00844866431294 11.3249169513082 3.37541527979647 11.3249169513082 Z M 4.70431893168598 5.34219269622093 C 4.70431893168598 5.70897011264535 4.95415281613373 6.00664453125 5.2624584665698 6.0066445130814 L 11.1229235828489 6.0066445130814 C 11.431229233285 6.0066445130814 11.6810631177325 5.70897009447674 11.6810631177325 5.34219269622093 C 11.6810631177325 4.97541529796513 11.431229233285 4.67774086119186 11.1229235828489 4.67774086119186 L 5.2624584665698 4.67774086119186 C 4.95415281613373 4.67774086119186 4.70431893168598 4.97541527979652 4.70431893168598 5.34219269622093 Z M 4.70431893168598 8 C 4.70431893168598 8.36677741642441 4.95415281613373 8.66445183502907 5.2624584665698 8.66445183502907 L 11.1229235828489 8.66445183502907 C 11.431229233285 8.66445183502907 11.6810631177325 8.36677741642441 11.6810631177325 8 C 11.6810631177325 7.63322258357559 11.431229233285 7.33554816497093 11.1229235828489 7.33554816497093 L 5.2624584665698 7.33554816497093 C 4.95415281613373 7.33554816497093 4.70431893168598 7.63322258357559 4.70431893168598 8 Z M 4.70431893168598 10.6578073037791 C 4.70431893168598 11.0245847020349 4.95415281613373 11.3222591388081 5.2624584665698 11.3222591388081 L 11.1229235828489 11.3222591388081 C 11.431229233285 11.3222591388081 11.6810631177325 11.0245847202035 11.6810631177325 10.6578073037791 C 11.6810631177325 10.2910298873547 11.431229233285 9.99335546875 11.1229235828489 9.9933554869186 L 5.2624584665698 9.9933554869186 C 4.95415281613373 9.9933554869186 4.70431893168598 10.2910299055233 4.70431893168598 10.6578073037791 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 1271 113 )" />
</g>
</svg>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="16px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -20 -113 )">
<path d="M 6.89803435773482 0.0122503798342564 C 5.95585189917128 0.0122503798342564 5.19135079419891 0.776771805939234 5.19135077693369 1.71893396063535 C 5.19135077693369 2.66121799033149 5.95577063190609 3.42561752417127 6.89803435773482 3.42561752417127 C 7.84031838743095 3.42561752417127 8.60471792127072 2.66121799033149 8.60471792127072 1.71893396063535 C 8.60471792127072 0.77667023480663 7.84023712016574 0.0122503970994501 6.89803435773482 0.0122503798342564 Z M 13.7246264157459 4.8531223756906 C 13.7246467368784 4.38204129834254 13.3423656940608 4.00158869129834 12.8713659012431 4 L 0.924682493093911 4 C 0.453601415745851 4.00158869129834 0.0714016574585514 4.38386971685082 0.0714016574585514 4.8548695269337 C 0.0714016574585514 5.32607249654697 0.453601415745851 5.70827225483426 0.924682493093911 5.70827225483426 L 4.42512284185082 5.70827225483426 C 4.62425759668508 5.74384509668508 4.89447707182322 5.84515961671271 5.03674810082873 6.21496679903315 C 5.20203686118785 6.64342548342542 5.12026605662984 7.40965341850828 5.01714342196132 8.05496217196132 L 4.88381130870167 8.81588770718233 C 4.88381130870167 8.81938200966852 4.88198289019337 8.8229372582873 4.88198289019337 8.82649252417127 L 3.80289274861877 14.9508714951657 C 3.72112194406077 15.4149436464088 4.03048983080112 15.857542058011 4.49456198204419 15.9393941298343 C 4.95845127762431 16.0210836671271 5.39586919889504 15.7117970476519 5.47753843232044 15.2478264675414 L 6.22424295580112 10.9829866022099 L 6.22424295580112 10.9882686809392 C 6.22424295580112 10.9882686809392 6.44645637085637 9.8327101519337 6.88021745511048 9.8327101519337 L 6.9193658667127 9.8327101519337 C 7.36198459944751 9.8327101519337 7.5753606871547 10.9882686809392 7.5753606871547 10.9882686809392 L 7.5753606871547 10.9847134323204 L 8.32196363950277 15.247806163674 C 8.40383601519338 15.7117767265193 8.8428994993094 16.0210633459945 9.3068700621547 15.9393738087017 C 9.77084062500001 15.8575014330111 10.0802085117403 15.4149030041436 9.99671087707182 14.9508511740331 L 8.91579233425415 8.82472505179558 L 8.91579233425415 8.82289663328729 C 8.91579233425415 8.8193413846685 8.91396391574585 8.81578613604972 8.91396391574585 8.81221056629835 L 8.77890495511051 8.05128501381215 C 8.67576201657459 7.40780467886741 8.59401153314917 6.64157674378453 8.75938154350828 6.21309775552486 C 8.90155100138122 5.84341248273481 9.17353794889502 5.74209794544198 9.37090523135359 5.70652510359116 L 12.8713455801105 5.70652510359116 C 13.3424266574586 5.70652510359116 13.7246264157459 5.32422375690608 13.7246264157459 4.8531223756906 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 20 113 )" />
</g>
</svg>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@ -34,21 +34,21 @@
</div>
<el-table ref="tableRef" :data="filteredPatients" style="width: 100%" border @cell-click="selectPatient"
highlight-current-row>
<el-table-column prop="name" label="姓名" min-width="60" />
<el-table-column prop="id" label="测试者ID" min-width="60" />
<el-table-column prop="updated_at" label="最后一次检查时间" min-width="60" />
<el-table-column prop="gender" label="性别" min-width="60" />
<el-table-column prop="num" label="测试次数" min-width="60" />
<el-table-column prop="status" label="测试状态" min-width="60">
<el-table-column prop="name" label="姓名" width="150" align="center" />
<el-table-column prop="id" label="测试者ID" min-width="120" align="center" />
<el-table-column prop="updated_at" label="最后一次检查时间" min-width="100" align="center" />
<el-table-column prop="gender" label="性别" width="120" align="center" />
<el-table-column prop="num" label="测试次数" width="120" align="center" />
<el-table-column prop="status" label="测试状态" align="center">
<template #default="scope">
<span v-if="!scope.row.status" style="font-size: 14px;color:#F59A23;">未处理</span>
<span v-else style="font-size: 14px;color:#ffffff;">已处理</span>
<span v-if="!scope.row.status" style="font-size: 18px;color:#F59A23;">未处理</span>
<span v-else style="font-size: 18px;color:#ffffff;">已处理</span>
</template>
</el-table-column>
<el-table-column prop="doctor" label="测试医生" min-width="60" />
<el-table-column fixed="right" label="操作" width="80">
<el-table-column prop="doctor" label="测试医生" min-width="80" align="center" />
<el-table-column fixed="right" label="操作" width="100">
<template #default="scope">
<el-button link type="primary" size="small" @click="delClick(scope.row.id)">删除</el-button>
<el-button link type="primary" style="font-size: 18px;" size="small" @click="delClick(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
@ -981,14 +981,14 @@ function delClick(id) {
display: flex;
justify-content: center;
box-sizing: border-box;
padding-top: 10px;
padding-top: 13px;
width: 100%;
}
.basic-info-text {
width: 33%;
text-align: center;
font-size: 14px;
font-size: 20px;
}
.basic-info-textcolor {
@ -1088,11 +1088,14 @@ function delClick(id) {
:deep(.el-table th .cell){
color: #30F3FF ;
font-weight: 400;
font-size: 14px;
font-size: 18px;
}
:deep(.el-table--border .el-table__inner-wrapper){
border-right: 1px solid #434343;
}
:deep(.el-table .cell){
font-size: 18px;
}
</style>
<style>
.dashboard-container.dashboard-container-home .el-table {

View File

@ -7,18 +7,19 @@
<header class="top-bar">
<div style="display: flex;align-items: center;">
<div v-if="!isRecording" class="top-bar-left" @click="routeTo('/')">
<img src="@/assets/svg/goback.svg" alt="">
<img src="@/assets/svg/u14.svg" alt="">
<!-- <el-icon class="back-icon" @click="handleBack"><ArrowLeft /></el-icon> -->
<span class="page-title">实时检测</span>
</div>
<!-- 录制时间 -->
<div v-if="isRecording" class="icon-container">
<img src="@/assets/record.png" class="blink-icon" :class="{ blinking: isRunning }" alt="">
<div>{{ formattedTime }}</div>
<div style="font-size: 18px;">{{ formattedTime }}</div>
</div>
<el-button v-if="!isRecording" @click="handleStartStop" :disabled="!isConnected" type="primary"
class="start-btn" style="background-image: linear-gradient(to right, rgb(236, 50, 166), rgb(160, 5, 216));
--el-button-border-color: #409EFF;
--el-button-border-color: transparent;">
--el-button-border-color: transparent;width: 120px;height: 30px;font-size: 20px;">
{{ isConnected ? '开始' : '连接中...' }}
</el-button>
<!-- handleStartStop -->
@ -49,53 +50,59 @@
<!-- 核心内容区网格布局 -->
<div id="detectare" class="content-grid">
<!-- 身体姿态模块 -->
<div class="module-card body-posture" style="width: 25%; ">
<div class="module-header" style="justify-content: flex-start;">
<div class="module-card body-posture" style="width: 25%;margin-right: 1px; ">
<div class="module-header">
<div class="module-title">
<div class="module-title-bg">
<img src="@/assets/st.png" alt="" srcset="" style="margin-right: 5px;">
<img src="@/assets/svg/u58.svg" alt="" srcset="" style="margin-right: 5px;">
身体姿态
</div>
</div>
<div style="margin-left: 10px;font-size: 14px;">{{ videoStatus }}</div>
<div :style="{ color: videoStatus == '已连接' ? '#00CC33' : '#ffffff' }" style="font-size: 14px;">
{{ videoStatus }}</div>
</div>
<div style="display: flex;justify-content: center;height: 100%;padding-top: 10px;">
<div style="display: flex;justify-content: center;height: 100%;padding-top: 0px;">
<!-- 使用深度相机视频流替换静态图片 -->
<img :src="depthCameraImgSrc || '@/assets/posture.png'" alt="深度相机视频流"
style="width: 100%;height: calc(100% - 10px);object-fit:contain;background:#2C2C2C;">
style="width: 100%;height: calc(100% - 10px);object-fit:contain;background:#323232;">
</div>
</div>
<div class="body-posture" style="width: 44%;display: flex;
<div class="body-posture" style="width: 45%;display: flex;margin-right: 1px;
flex-wrap: wrap;
align-content: space-between;
">
<div class="module-card" style=" height:50%;min-height: 425px;margin-bottom: 5px;">
<div class="module-card" style=" height:50%;min-height: 425px;margin-bottom: 1px;">
<!-- 头部姿态模块 -->
<div style="display: flex;">
<div class="module-header">
<div style="display: flex;align-items: center;">
<div class="module-title">
<div class="module-title-bg">
<img src="@/assets/tb.png" alt="" srcset="" style="margin-right: 5px;">
<img src="@/assets/svg/u67.svg" alt="" srcset="" style="margin-right: 5px;">
头部姿态
</div>
</div>
<div style="margin-left: 10px;font-size: 14px;">{{ imuStatus }}</div>
</div>
<div style="display: flex; gap: 10px;">
<div style="display: flex;align-items: center;">
<div :style="{ color: imuStatus == '已连接' ? '#00CC33' : '#ffffff' }" style="font-size: 14px;">{{
imuStatus
}}</div>
<el-button type="primary" class="start-btn" @click="clearAndStartTracking" :disabled="isRecording"
style="background-image: linear-gradient(to right, rgb(236, 50, 166), rgb(160, 5, 216));
--el-button-border-color: transparent !important;border-radius: 20px;border:none;width: 150px;">
style="background-color: #0099ff;font-size: 14px;margin-left: 15px;
--el-button-border-color: transparent !important;border-radius: 20px;height:26px;border:none;width: 100px;">
清零并保存
</el-button>
</div>
</div>
</div>
<!-- 仪表盘区域 -->
<div style="display: flex;justify-content: space-between;padding: 0px 10px;padding-top: 10px;">
<div style="width: 33%;">
<div style="width: 33%;position: relative;">
<div class="chart-title">旋转角</div>
<div id="rotationChartId" style="width: 100%;height: 140px;"></div>
<div class="gauge-group-box">
<div class="gauge-group-box-text1"><span class="gauge-group-box-text2">{{
@ -104,7 +111,8 @@
headPoseMaxValues.rotationRightMax.toFixed(1) }}°</span></div>
</div>
</div>
<div style="width: 33%;">
<div style="width: 33%;position: relative;">
<div class="chart-title">倾斜角</div>
<div id="pitchChartId" style="width: 100%;height: 140px;"></div>
<div class="gauge-group-box">
<div class="gauge-group-box-text1"><span class="gauge-group-box-text2">{{
@ -113,20 +121,25 @@
headPoseMaxValues.tiltRightMax.toFixed(1) }}°</span></div>
</div>
</div>
<div style="width: 33%;">
<div style="width: 33%;position: relative;">
<div class="chart-title">俯仰角</div>
<div id="tiltChartId" style="width: 100%;height: 140px;"></div>
<div class="gauge-group-box">
<div class="gauge-group-box-text1"><span class="gauge-group-box-text2">{{
<div class="gauge-group-box-text1"><span class="gauge-group-box-text2">{{
headPoseMaxValues.pitchDownMax.toFixed(1) }}°</span></div>
<div class="gauge-group-box-text1" style="margin-left: 20px;"><span class="gauge-group-box-text2">{{
<div class="gauge-group-box-text1" style="margin-left: 20px;"><span class="gauge-group-box-text2">{{
headPoseMaxValues.pitchUpMax.toFixed(1) }}°</span></div>
</div>
</div>
</div>
<div class="icon-box">
<div class="icon-box-mark"></div>
<div class="icon-box-text">历史数据</div>
</div>
<!-- 历史数据表格 -->
<div style="display: flex;justify-content: center;padding: 0px 25px;margin-top: 20px;">
<el-table :data="historyData" border style="width: 96%;overflow: auto;" :height="160">
<el-table-column prop="id" label="ID" width="60" />
<div style="display: flex;justify-content: center;padding: 0px 10px;margin-top: 5px;height: 100%;">
<el-table :data="historyData" border style="width: 100%;overflow: auto;height: calc(100% - 280px);" >
<el-table-column prop="id" label="ID" align="center" width="60" />
<el-table-column label="最大旋转角" align="center">
<el-table-column prop="rotLeft" label="左" min-width="60" align="center" />
<el-table-column prop="rotRight" label="右" min-width="60" align="center" />
@ -144,32 +157,32 @@
</div>
<!-- 足部压力模块 -->
<div class="module-card" style=" height:50%;">
<div style="display: flex;">
<div class="module-header" style="justify-content: flex-start;">
<div class="module-header">
<div class="module-title">
<div class="module-title-bg">
<img src="@/assets/zb.png" alt="" srcset="" style="margin-right: 5px;">
<img src="@/assets/svg/u125.svg" alt="" srcset="" style="margin-right: 5px;">
足部压力
</div>
</div>
<div style="margin-left: 10px;font-size: 14px;">{{ pressureStatus }}</div>
<div :style="{ color: pressureStatus == '已连接' ? '#00CC33' : '#ffffff' }" style="font-size: 14px;">{{
pressureStatus }}</div>
</div>
</div>
<div class="foot-container">
<div class="foot-container-left" style="font-size: 14px;">
<div>
<div class="foot-container-left" style="font-size: 18px;">
<div style="width: 160px;">
<span>左前足</span>
<span style="font-size: 24px;" class="foot-container-paddingcolor">{{ footPressure.left_front
}}</span>
<span class="foot-container-paddingcolor">{{ footPressure.left_front
}}%</span>
</div>
<div class="foot-container-margintop">
<div class="foot-container-margintop" style="width: 160px;">
<span>左后足</span>
<span style="font-size: 24px;" class="foot-container-paddingcolor">{{ footPressure.left_rear }}</span>
<span class="foot-container-paddingcolor">{{ footPressure.left_rear }}%</span>
</div>
</div>
<div class="foot-container-content">
<div style="display: flex;justify-content: center;margin-bottom: 8px;font-size: 16px;font-weight: 700;">
<div style="display: flex;justify-content: center;margin-bottom: 8px;font-size: 20px;">
<div>
<span>左足</span>
</div>
@ -177,30 +190,35 @@
<span>右足</span>
</div>
</div>
<img :src="footImgSrc" style="width: 300px;height: 300px;" alt="">
<div style="display: flex;justify-content: center;margin-top: 8px;font-size: 14px;">
<div style="position: relative;width: 300px;height: 300px;">
<img :src="footImgSrc" style="width: 300px;height: 300px;" alt="">
<div class="xline"></div>
<div class="yline"></div>
</div>
<div
style="display: flex;justify-content: center;margin-top: 8px;font-size: 18px;width: 430px;margin-left: -65px;">
<div>
<span>左足总压力</span>
<span style="font-size: 24px;" class="foot-container-paddingcolor">{{ footPressure.left_total
}}</span>
<span class="foot-container-paddingcolor">{{ footPressure.left_total
}}%</span>
</div>
<div class="foot-container-marginleft">
<span>右足总压力</span>
<span style="font-size: 24px;" class="foot-container-paddingcolor">{{ footPressure.right_total
}}</span>
<span class="foot-container-paddingcolor">{{ footPressure.right_total
}}%</span>
</div>
</div>
</div>
<div class="foot-container-right" style="font-size: 14px;">
<div>
<div class="foot-container-right" style="font-size: 18px;">
<div style="width: 160px;">
<span>右前足</span>
<span style="font-size: 24px;" class="foot-container-paddingcolor">{{ footPressure.right_front
}}</span>
<span class="foot-container-paddingcolor">{{ footPressure.right_front
}}%</span>
</div>
<div class="foot-container-margintop">
<div class="foot-container-margintop" style="width: 160px;">
<span>右后足</span>
<span style="font-size: 24px;" class="foot-container-paddingcolor">{{ footPressure.right_rear
}}</span>
<span class="foot-container-paddingcolor">{{ footPressure.right_rear
}}%</span>
</div>
</div>
</div>
@ -212,97 +230,103 @@
align-content: space-between;
">
<!-- 基础信息模块 -->
<div class="module-card" style="padding-bottom: 40px; height: 50%;min-height: 425px;margin-bottom: 5px;">
<div class="module-card" style="padding-bottom: 40px; height: 50%;min-height: 425px;margin-bottom: 1px;">
<div style="display: flex;">
<div class="module-header">
<div class="module-title">
<div class="module-title-bg">
<img src="@/assets/jc.png" alt="" srcset="" style="margin-right: 5px;">
<img src="@/assets/svg/u164.svg" alt="" srcset="" style="margin-right: 5px;">
基础信息
</div>
</div>
<el-icon class="edit-icon">
<el-icon class="edit-icon" style="width: 24px;height: 24px;font-size: 24px;">
<Edit />
</el-icon>
</div>
</div>
<div class="basic-info-box">
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">测试者ID</div>
<div>{{ patientInfo.id || '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">姓名</div>
<div class="basic-info-text2" style="color: #ffc907;">{{ patientInfo.name ||
'-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">姓名</div>
<div>{{ patientInfo.name || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">性别</div>
<div>{{ patientInfo.gender || '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">测试者ID</div>
<div class="basic-info-text2">{{ patientInfo.id || '-' }}</div>
</div>
</div>
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">出生日期</div>
<div>{{ patientInfo.birth_date ? formatDate(patientInfo.birth_date) : '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">性别</div>
<div class="basic-info-text2">{{ patientInfo.gender || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">年龄</div>
<div>{{ patientInfo.age || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">民族</div>
<div>{{ patientInfo.nationality || '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">出生日期</div>
<div class="basic-info-text2">{{ patientInfo.birth_date ? formatDate(patientInfo.birth_date) : '-' }}
</div>
</div>
</div>
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">身高cm</div>
<div>{{ patientInfo.height || '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">年龄</div>
<div class="basic-info-text2">{{ calculateAge(patientInfo.birth_date) }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">体重kg</div>
<div>{{ patientInfo.weight || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">鞋码</div>
<div>{{ patientInfo.shoe_size || '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">民族</div>
<div class="basic-info-text2">{{ patientInfo.nationality || '-' }}</div>
</div>
</div>
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">电话号码</div>
<div>{{ patientInfo.phone || '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">身高cm</div>
<div class="basic-info-text2">{{ patientInfo.height || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">建档时间</div>
<div>{{ patientInfo.created_at ? formatDate(patientInfo.created_at) : '-' }}</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">体重kg</div>
<div class="basic-info-text2">{{ patientInfo.weight || '-' }}</div>
</div>
<div class="basic-info-text">
</div>
<div class="basic-info-content">
<div class="basic-info-content-item">
<div class="basic-info-text1">鞋码</div>
<div class="basic-info-text2">{{ patientInfo.shoe_size || '-' }}</div>
</div>
<div class="basic-info-content-item">
<div class="basic-info-text1">电话号码</div>
<div class="basic-info-text2">{{ patientInfo.phone || '-' }}</div>
</div>
</div>
<div class="basic-info-content">
<div class="basic-info-content-item">
<div class="basic-info-text1">建档时间</div>
<div class="basic-info-text2">{{ patientInfo.created_at ? formatDate(patientInfo.created_at) : '-' }}
</div>
</div>
<div class="basic-info-content-item">
</div>
</div>
</div>
</div>
<!-- 视频模块 -->
<div class="module-card" style="height: 50%;">
<div style="display: flex;margin-bottom: 20px;">
<div class="module-header" style="justify-content: flex-start;">
<div style="display: flex;margin-bottom: 15px;">
<div class="module-header">
<div class="module-title">
<div class="module-title-bg">
<img src="@/assets/sp.png" alt="" srcset="" style="margin-right: 5px; ">
<img src="@/assets/svg/u155.svg" alt="" srcset="" style="margin-right: 5px; ">
视频
</div>
</div>
<div style="margin-left: 10px;font-size: 14px;">{{ videoStatus }}</div>
<div :style="{ color: videoStatus == '已连接' ? '#00CC33' : '#ffffff' }" style="font-size: 14px;">{{
videoStatus }}</div>
</div>
</div>
<!-- 使用img元素显示视频流优化的Data URL方案 -->
<img :src="rtspImgSrc" alt=""
style="width: 100%;height: calc(100% - 60px);object-fit:contain;background:#2C2C2C;" />
style="width: 100%;height: calc(100% - 80px);object-fit:contain;background:#323232;" />
</div>
</div>
</div>
@ -399,9 +423,9 @@ const handleClose = () => {
dialogVisible.value = false
}
const diagnosticForm = ref({
diagnosis_info:'',
treatment_info:'',
suggestion_info:''
diagnosis_info: '',
treatment_info: '',
suggestion_info: ''
})
//
const historyData = ref([
@ -412,6 +436,7 @@ const historyData = ref([
const chartoption = ref({
backgroundColor: '#000000',
grid: { top: 0, right: 0, bottom: 0, left: 0 },
animation: false,
series: [
{
type: 'gauge',
@ -538,7 +563,17 @@ const resetTimer = () => {
function routeTo(path) {
router.push(`/`)
}
const calculateAge = (birthDate) => {
if (!birthDate) return '-'
const today = new Date()
const birth = new Date(birthDate)
let age = today.getFullYear() - birth.getFullYear()
const monthDiff = today.getMonth() - birth.getMonth()
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--
}
return age
}
//
const handleBack = () => {
console.log('返回上一页')
@ -946,7 +981,7 @@ function updateHistoryTable() {
if (historyData.value) {
historyData.value.push(newHistoryItem)
}
historyData.value.sort((a, b) => b.id - a.id);
console.log('📋 历史数据表格已更新')
}
} catch (error) {
@ -1068,7 +1103,7 @@ function stopPressureStreaming() {
}
}
async function handleDiagnosticInfo(status){
async function handleDiagnosticInfo(status) {
try {
// ID
if (!patientInfo.value.sessionId) {
@ -1081,11 +1116,11 @@ async function handleDiagnosticInfo(status){
'Content-Type': 'application/json'
},
body: JSON.stringify({
diagnosis_info:diagnosticForm.diagnosis_info,
treatment_info:diagnosticForm.treatment_info,
suggestion_info:diagnosticForm.suggestion_info,
status:status,
session_id:patientInfo.value.sessionId,
diagnosis_info: diagnosticForm.diagnosis_info,
treatment_info: diagnosticForm.treatment_info,
suggestion_info: diagnosticForm.suggestion_info,
status: status,
session_id: patientInfo.value.sessionId,
})
})
if (!response.ok) {
@ -1565,9 +1600,9 @@ async function saveRecording() {
// patientInfo.value.sessionId = null
console.log('✅ 会话正式结束会话ID已清空')
diagnosticForm.value = {
diagnosis_info:'',
treatment_info:'',
suggestion_info:''
diagnosis_info: '',
treatment_info: '',
suggestion_info: ''
}
dialogVisible.value = true
} else {
@ -1910,7 +1945,8 @@ onUnmounted(() => {
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background-color: #000000;
background-color: #292929;
/* margin-bottom: 1px; */
}
.top-bar-left {
@ -1927,7 +1963,7 @@ onUnmounted(() => {
.page-title {
font-size: 18px;
font-weight: bold;
margin-left: 20px;
margin-left: 10px;
}
.start-btn {
@ -1956,9 +1992,9 @@ onUnmounted(() => {
/* 核心内容网格布局 */
.content-grid {
display: flex;
padding: 0px 10px;
padding: 0px 0px;
justify-content: space-between;
height: calc(100vh - 120px);
height: calc(100vh - 100px);
/* flex: 1;
display: grid;
@ -1970,18 +2006,24 @@ onUnmounted(() => {
/* 通用模块样式 */
.module-card {
width: 100%;
background-color: #2C2C2C !important;
background-color: #323232 !important;
border: none !important;
}
.module-header {
width: 100%;
display: flex;
height: 40px;
align-items: center;
justify-content: space-between;
margin-top: 10px;
margin-left: 10px;
margin-right: 10px;
padding: 0px 15px;
background-color: rgba(41, 41, 41, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(27, 27, 27, 1);
border-right: none;
border-left: none;
}
.module-title {
@ -1992,7 +2034,7 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
/* border: 2px solid #ffffff; */
background: linear-gradient(to right, rgb(245, 173, 7), rgb(160, 5, 216));
/* background: linear-gradient(to right, rgb(245, 173, 7), rgb(160, 5, 216)); */
border-radius: 20px;
@ -2006,9 +2048,11 @@ onUnmounted(() => {
display: flex;
align-items: center;
width: 116px;
background: #2C2C2C;
border-radius: 20px;
padding: 0px 15px;
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-style: normal;
font-size: 18px;
color: #FFFFFF;
}
.header-icon {
@ -2218,22 +2262,26 @@ onUnmounted(() => {
}
.gauge-group-box {
height: 50px;
display: flex;
align-items: center;
color: #ffffff;
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
height: 30px;
justify-content: space-between;
padding: 0px 20px;
}
.gauge-group-box-text1 {
font-size: 16px;
font-weight: 700;
font-style: normal;
display: flex;
align-items: center;
}
.gauge-group-box-text2 {
font-size: 24px;
color: #30F3FF;
color: #ff9900;
font-weight: 700;
}
@ -2252,6 +2300,7 @@ onUnmounted(() => {
.foot-container-content {
margin: 0px 20px;
text-align: center;
width: 300px;
}
.foot-container-margintop {
@ -2264,21 +2313,49 @@ onUnmounted(() => {
.foot-container-paddingcolor {
padding-left: 10px;
color: #30F3FF;
color: #ff9900;
font-size: 30px;
font-weight: 700;
}
.basic-info-content {
display: flex;
justify-content: center;
box-sizing: border-box;
padding-top: 10px;
/* justify-content: center;
box-sizing: border-box; */
padding-top: 15px;
width: 100%;
justify-content: space-between;
}
.basic-info-content-item {
display: flex;
align-items: center;
width: 50%;
}
.basic-info-text1 {
width: 85px;
text-align: center;
height: 46px;
line-height: 46px;
}
.basic-info-text2 {
width: 180px;
font-size: 20px;
background-color: rgba(36, 36, 36, 1);
border-radius: 4px;
color: #FFFFFF;
text-align: left;
height: 46px;
line-height: 46px;
padding-left: 15px;
}
.basic-info-text {
width: 33%;
text-align: center;
font-size: 13px;
font-size: 20px;
}
.basic-info-textcolor {
@ -2287,10 +2364,18 @@ onUnmounted(() => {
}
.basic-info-box {
display: flex;
/*
flex-wrap: wrap;
align-content: center;
align-content: center; */
width: 100%;
height: 100%;
/* display: flex; */
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0px 20px;
}
.dialog-title {
@ -2361,31 +2446,129 @@ onUnmounted(() => {
transform: scale(1);
}
}
.xline {
position: absolute;
width: 350px;
/* height: 1px; */
border-top: 1px dashed red;
top: 50%;
left: -25px;
}
.yline {
position: absolute;
/* width:1px; */
height: 350px;
/* height: 1px; */
border-left: 1px dashed red;
top: -25px;
left: 50%;
}
.icon-box {
display: flex;
align-items: center;
width: 100%;
padding: 0px 10px;
}
.icon-box-mark {
width: 4px;
height: 14px;
background-color: rgba(0, 153, 255, 1);
margin-right: 10px;
}
.icon-box-text {
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #0099FF;
}
.chart-title {
position: absolute;
top: 4px;
left: 7px;
z-index: 2000;
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-style: normal;
font-size: 14px;
color: #EEF1FA;
}
:deep(.el-table--border .el-table__inner-wrapper:after, .el-table--border:after, .el-table--border:before, .el-table__inner-wrapper:before) {
background-color: rgb(81, 81, 81) !important;
}
:deep(.el-table__body-wrapper) {
border-bottom: 1px solid rgb(81, 81, 81) !important;
}
:deep(.el-table thead.is-group th.el-table__cell) {
border-right: 1px solid rgb(81, 81, 81) !important;
border-bottom: 1px solid rgb(81, 81, 81) !important;
}
:deep(.el-table td.el-table__cell, .el-table th.el-table__cell.is-leaf) {
border-bottom: 1px solid rgb(81, 81, 81) !important;
background-color: #282828 !important;
border-right: 1px solid rgb(81, 81, 81) !important;
}
:deep(.el-scrollbar__wrap){
background: #282828 !important;
}
</style>
<style>
.dashboard-container.dashboard-container-home .el-table--border .el-table__inner-wrapper:after,
.el-table--border:after,
.el-table--border:before,
.el-table__inner-wrapper:before {
background: rgb(81, 81, 81) !important;
}
.dashboard-container.dashboard-container-home .el-table__border-bottom-patch,
.el-table__border-left-patch {
background: rgb(81, 81, 81) !important;
}
.dashboard-container .el-table {
background: transparent !important;
background: #464646 !important;
}
.dashboard-container .el-table tr {
background-color: transparent !important;
background-color: #464646 !important;
}
.dashboard-container .el-table thead.is-group th.el-table__cell {
background-color: transparent !important;
background-color: #464646 !important;
}
.dashboard-container .is-group .cell {
color: #C9C9C9;
font-size: 18px;
font-weight: 400;
}
.dashboard-container .cell {
color: #fff;
font-size: 18px;
color: #ffffff;
}
.dashboard-container tr>td.el-table__cell {
color: #ffffff;
}
.dashboard-container .el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell {
background-color: transparent !important;
background-color: #6F4200 !important;
}
.el-table td.el-table__cell,
.el-table th.el-table__cell.is-leaf {
background-color: transparent !important;
background-color: rgb(81, 81, 81) !important;
}
.top-bar .el-button {

View File

@ -4,7 +4,7 @@
<div class="header">
<div class="header-left">
<div class="system-logo">
<img src="@/assets/svg/logo.svg" alt="Logo" class="logo" />
<img src="@/assets/svg/u7.svg" alt="Logo" class="logo" />
</div>
<div class="system-title">平衡体态检测系统</div>
</div>
@ -105,13 +105,13 @@
.header {
height: 50px;
background: #000000;
border-bottom: 1px solid #434343;
background: #323232;
border-bottom: none;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); */
}
.header-left {
@ -127,18 +127,21 @@
}
.system-logo {
width: 32px;
height: 32px;
width: 26px;
height: 26px;
border-radius: 4px;
background: #136166;
background: #0099ff;
text-align: center;
padding-top: 3px;
}
.system-title {
font-size: 18px;
color: #AAAAAA;
margin: 0;
font-family: 微软雅黑, sans-serif;
font-weight: 400;
font-style: normal;
font-size: 22px;
color: rgb(255, 255, 255);
}
.header-right {

View File

@ -21,8 +21,8 @@
<!-- 患者基本信息 -->
<div v-for="(item, index) in profileInfo" :key="index" class="content-info">
<div class="content-left">
<el-checkbox v-model="item.checked" label=""/>
<div class="content-left-text1">{{index + 1}}</div>
<el-checkbox v-model="item.checked" label="" />
<div class="content-left-text1">{{ index + 1 }}</div>
<div class="content-left-text2">2025/04/01 14:35</div>
<div class="content-left-text3">初次就诊</div>
</div>
@ -30,49 +30,51 @@
</div>
<div class="content-right">
<div class="content-right-top">
<div class="content-right-top-title">
<div class="content-right-top-text">诊断信息</div>
<div style="display: flex;align-items: center;">
<div class="content-right-top-text2">未处理</div>
<div style="margin-left: 10px;" @click="editClick">
<img src="@/assets/svg/edit.svg" alt="">
</div>
<div class="content-right-top">
<div class="content-right-top-title">
<div class="content-right-top-text">诊断信息</div>
<div style="display: flex;align-items: center;">
<div class="content-right-top-text2">未处理</div>
<div style="margin-left: 10px;" @click="editClick">
<img src="@/assets/svg/edit.svg" alt="">
</div>
</div>
<div class="content-right-top-content">
<el-form :model="diagnosticForm" label-width="50px">
<el-form-item label="记录">
<el-input v-model="diagnosticForm.diagnosis_info" disabled :rows="6" type="textarea" placeholder="请输入" />
</el-form-item>
<el-form-item label="处理">
<el-input v-model="diagnosticForm.treatment_info" disabled :rows="6" type="textarea" placeholder="请输入" />
</el-form-item>
<el-form-item label="建议">
<el-input v-model="diagnosticForm.suggestion_info" disabled :rows="6" type="textarea" placeholder="请输入" />
</el-form-item>
</el-form>
</div>
</div>
<div class="content-right-bottom">
<div class="content-right-bottom-title">
<div class="content-right-bottom-text">保存数据列表</div>
</div>
<div class="content-right-bottom-content">
<div v-for="(item2, index2) in item.list" :key="index2" class="content-right-bottom-content-box">
<div class="content-right-bottom-img">截图</div>
<div class="content-right-top-content">
<el-form :model="diagnosticForm" label-width="50px">
<el-form-item label="记录">
<el-input v-model="diagnosticForm.diagnosis_info" disabled :rows="6" type="textarea"
placeholder="请输入" />
</el-form-item>
<el-form-item label="处理">
<el-input v-model="diagnosticForm.treatment_info" disabled :rows="6" type="textarea"
placeholder="请输入" />
</el-form-item>
<el-form-item label="建议">
<el-input v-model="diagnosticForm.suggestion_info" disabled :rows="6" type="textarea"
placeholder="请输入" />
</el-form-item>
</el-form>
</div>
</div>
<div class="content-right-bottom">
<div class="content-right-bottom-title">
<div class="content-right-bottom-text">保存数据列表</div>
</div>
<div class="content-right-bottom-content">
<div v-for="(item2, index2) in item.list" :key="index2" class="content-right-bottom-content-box">
<div class="content-right-bottom-img">截图</div>
<div style="margin-top: 15px;">
<div @click="patientdetails">
<img src="@/assets/svg/datalist.svg" alt="">
</div>
<div>
<div>
<img src="@/assets/svg/datalist.svg" alt="">
</div>
<div>
<img src="@/assets/svg/del.svg" alt="">
</div>
<img src="@/assets/svg/del.svg" alt="">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -135,17 +137,18 @@
<div class="data-item">
<span>足底压力</span>
<span>左足: {{ previewScreenshot.data.leftPressure }}%, 右足: {{ previewScreenshot.data.rightPressure
}}%</span>
}}%</span>
</div>
</div>
</div>
</div>
</el-dialog>
<!-- 修改诊断信息 -->
<el-dialog v-model="dialogVisible" center title="诊断信息" width="600" :before-close="handleClose">
<div>
<div class="dialog-title">
<div class="dialog-title-item">
<div>用户ID:</div>{{ patient.sessionId }}
<div>用户ID:</div>{{ patient.id }}
</div>
<div class="dialog-title-item">
<div>姓名:{{ patient.name }}</div>
@ -176,40 +179,143 @@
</span>
</template>
</el-dialog>
<el-dialog v-model="dialogVisible" center title="诊断信息" width="600" :before-close="handleClose">
<div>
<div class="dialog-title">
<div class="dialog-title-item">
<div>用户ID:</div>{{ patient.sessionId }}
</div>
<div class="dialog-title-item">
<div>姓名:{{ patient.name }}</div>
</div>
</div>
<!-- 数据详情 -->
<el-dialog class="detailsDialog" v-model="detailsDialogVisible" top="5vh" title="当前保存数据" width="50%"
:before-close="detailshandleClose">
<div style="margin: 20px 50px; height: calc(100vh - 200px);overflow: auto;">
<div>
<el-form :model="diagnosticForm" label-width="50px">
<el-form-item label="记录">
<el-input v-model="diagnosticForm.diagnosis_info" :rows="6" type="textarea" placeholder="请输入" />
</el-form-item>
<el-form-item label="处理">
<el-input v-model="diagnosticForm.treatment_info" :rows="6" type="textarea" placeholder="请输入" />
</el-form-item>
<el-form-item label="建议">
<el-input v-model="diagnosticForm.suggestion_info" :rows="6" type="textarea" placeholder="请输入" />
</el-form-item>
</el-form>
<div class="patient-detail-box">
<div class="detail-header">
<div class="module-title">
<div class="module-title-text">基础信息</div>
</div>
</div>
<div class="basic-info-box">
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">测试者ID</div>
<div>{{ selectedPatient.id || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">姓名</div>
<div>{{ selectedPatient.name || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">性别</div>
<div>{{ selectedPatient.gender || '-' }}</div>
</div>
</div>
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">出生日期</div>
<div>{{ selectedPatient.birth_date ? formatDate(selectedPatient.birth_date) : '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">年龄</div>
<div>{{ calculateAge(selectedPatient.birth_date) }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">民族</div>
<div>{{ selectedPatient.nationality || '-' }}</div>
</div>
</div>
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">身高cm</div>
<div>{{ selectedPatient.height || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">体重kg</div>
<div>{{ selectedPatient.weight || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">鞋码</div>
<div>{{ selectedPatient.shoe_size || '-' }}</div>
</div>
</div>
<div class="basic-info-content">
<div class="basic-info-text">
<div class="basic-info-textcolor">电话号码</div>
<div>{{ selectedPatient.phone || '-' }}</div>
</div>
<div class="basic-info-text">
<div class="basic-info-textcolor">建档时间</div>
<div>{{ selectedPatient.created_at ? formatDate(selectedPatient.created_at) : '-' }}</div>
</div>
<div class="basic-info-text">
</div>
</div>
</div>
</div>
</div>
<div class="patient-profile-dialog-box">
<div class="detail-header">
<div class="module-title">
<div class="module-title-text">身体姿态</div>
</div>
</div>
<div>
图片
</div>
</div>
<div class="patient-profile-dialog-box" style="height: 230px;">
<div class="detail-header">
<div class="module-title">
<div class="module-title-text">头部姿态</div>
</div>
</div>
<div class="detail-head-content">
<div style="margin-right: 100px;">
<img src="@/assets/u45.png" style="width: 90px;height: 90px;" alt="">
</div>
<div>
<div>
最大旋转角<span class="detail-head-text">-55.2°</span>
<span class="detail-head-text">-55.2°</span>
</div>
<div style="margin-top: 15px;">最大倾斜角<span class="detail-head-text">-55.2°</span>
<span class="detail-head-text">-55.2°</span></div>
<div style="margin-top: 15px;">最大俯仰角<span class="detail-head-text">-55.2°</span>
<span class="detail-head-text">-55.2°</span></div>
</div>
</div>
</div>
<div class="patient-profile-dialog-box" style="height: 370px;">
<div class="detail-header">
<div class="module-title">
<div class="module-title-text">足底压力</div>
</div>
</div>
<div>
<div>
<div>左前足<span>54%</span></div>
<div>右前足<span>54%</span></div>
</div>
<div>
<div></div>
<div></div>
<div></div>
</div>
<div>
<div>左后足<span>54%</span></div>
<div>右后足<span>54%</span></div>
</div>
</div>
</div>
<div class="patient-profile-dialog-box" style="height: 370px;">
<div class="detail-header">
<div class="module-title">
<div class="module-title-text">视频图片</div>
</div>
</div>
<div>
图片
</div>
</div>
<div style="display: flex;justify-content: flex-end;color: #ffffff;">测试医生李四</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button @click="handleDiagnosticInfo('diagnosed')">暂存</el-button>
<el-button type="primary" @click="handleDiagnosticInfo('completed')">
保存
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
@ -247,16 +353,33 @@ const filteredRecords = computed(() => {
formatDate(record.createdAt).includes(searchKeyword.value)
)
})
const profileInfo = ref([{list:[{},{}]}, {}])
const profileInfo = ref([{ list: [{}, {}] }, {}])
const diagnosticForm = ref({
diagnosis_info:'',
treatment_info:'',
suggestion_info:''
diagnosis_info: '',
treatment_info: '',
suggestion_info: ''
})
const dialogVisible = ref(false)
const handleClose = () => {
dialogVisible.value = false
}
const detailsDialogVisible = ref(false)
const selectedPatient = ref({})
const detailshandleClose = () => {
detailsDialogVisible.value = false
}
//
const calculateAge = (birthDate) => {
if (!birthDate) return '-'
const today = new Date()
const birth = new Date(birthDate)
let age = today.getFullYear() - birth.getFullYear()
const monthDiff = today.getMonth() - birth.getMonth()
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--
}
return age
}
//
const goBack = () => {
@ -474,10 +597,15 @@ const loadDetectionRecords = async () => {
]
}
}
function editClick(){
//
function editClick() {
dialogVisible.value = true
}
async function handleDiagnosticInfo(status){
//
function patientdetails() {
detailsDialogVisible.value = true
}
async function handleDiagnosticInfo(status) {
try {
// // ID
// if (!patientInfo.value.sessionId) {
@ -525,7 +653,7 @@ async function handleDiagnosticInfo(status){
//
onMounted(() => {
loadPatientInfo()
loadDetectionRecords()
// loadDetectionRecords()
})
</script>
@ -535,6 +663,7 @@ onMounted(() => {
padding: 10px 0px 10px 15px;
min-height: 700px;
}
.content-left {
width: 87px;
min-width: 87px;
@ -548,110 +677,127 @@ onMounted(() => {
color: #FFFFFF;
text-align: center;
display: flex;
flex-direction: column; /* 垂直排列子元素 */
justify-content: center; /* 垂直居中 */
align-items: center; /* 水平居中 */
flex-direction: column;
/* 垂直排列子元素 */
justify-content: center;
/* 垂直居中 */
align-items: center;
/* 水平居中 */
}
.content-left-text1{
}
.content-left-text2{
.content-left-text1 {}
}
.content-left-text3{
.content-left-text2 {}
}
.content-center{
.content-left-text3 {}
.content-center {
width: calc(100% - 327px);
margin: 0px 15px;
background-color: rgba(85, 85, 85, 0.6);
}
.content-right{
.content-right {
width: 260px;
min-width: 260px;
height: 100%;
/* background-color: rgba(85, 85, 85, 0.6); */
}
.content-right-top{
.content-right-top {
width: 100%;
height: 50%;
background-color: rgba(85, 85, 85, 0.6);
}
.content-right-top-title{
.content-right-top-title {
display: flex;
align-items: center;
justify-content: space-between;
color: #ffffff;
padding: 15px;
}
.content-right-top-text{
.content-right-top-text {
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #FFFFFF;
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #FFFFFF;
}
.content-right-top-text2{
.content-right-top-text2 {
width: 62px;
height: 32px;
line-height: 32px;
background: rgba(230,162,60,0.1);
background: rgba(230, 162, 60, 0.1);
color: #E6A23C;
text-align: center;
border-radius: 5px;
}
.content-right-top-content{
.content-right-top-content {
height: calc(100% - 75px);
overflow: auto;
}
:deep(.el-textarea__inner) {
background: transparent;
color: #ffffff;
}
:deep(.el-form-item__label) {
color: #ffffff;
}
:deep(.el-textarea.is-disabled .el-textarea__inner){
:deep(.el-textarea.is-disabled .el-textarea__inner) {
background: transparent;
color: #ffffff;
}
.content-right-bottom{
.content-right-bottom {
margin-top: 10px;
width: 100%;
height: calc(50% - 10px);
background-color: rgba(85, 85, 85, 0.6);
}
.content-right-bottom-title{
.content-right-bottom-title {
display: flex;
align-items: center;
justify-content: space-between;
color: #ffffff;
padding: 15px 15px 0px;
}
.content-right-bottom-text{
.content-right-bottom-text {
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #FFFFFF;
font-weight: 700;
font-style: normal;
font-size: 16px;
color: #FFFFFF;
}
.content-right-bottom-content{
.content-right-bottom-content {
height: calc(100% - 75px);
overflow: auto;
padding: 0px 15px;
}
.content-right-bottom-content-box{
.content-right-bottom-content-box {
color: #ffffff;
display: flex;
justify-content: center;
margin-top: 10px;
}
.content-right-bottom-img{
.content-right-bottom-img {
width: 180px;
height: 74px;
border: 1px solid #434343;
margin-right: 10px;
}
.dialog-title {
display: flex;
justify-content: space-between;
@ -962,4 +1108,105 @@ onMounted(() => {
color: #FFFFFF;
font-family: 'Arial Normal', 'Arial', sans-serif;
}
.patient-detail-box {
background: rgb(85, 85, 85);
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
color: #fff;
}
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 15px;
/* border-bottom: 1px solid #434343; */
}
.detail-header h3 {
margin: 0;
color: #2c3e50;
font-size: 18px;
}
.detail-content {
flex: 1;
margin-bottom: 20px;
}
.module-title {
width: 120px;
display: flex;
align-items: center;
justify-content: center;
/* border: 2px solid #ffffff; */
background: linear-gradient(to right, rgb(245, 173, 7), rgb(160, 5, 216));
border-radius: 20px;
font-size: 16px;
font-weight: bold;
color: #ffffff;
padding: 2px;
}
.module-title-text {
display: flex;
align-items: center;
width: 116px;
background: rgb(85, 85, 85);
border-radius: 20px;
padding: 0px 25px;
}
.basic-info-box {
display: flex;
flex-wrap: wrap;
align-content: center;
height: 100%;
}
.basic-info-content {
display: flex;
justify-content: center;
box-sizing: border-box;
padding-top: 30px;
width: 100%;
}
.basic-info-text {
width: 33%;
text-align: center;
font-size: 20px;
}
.basic-info-textcolor {
color: #30F3FF;
padding-bottom: 8px;
}
:deep(.detailsDialog.el-dialog) {
background-color: rgba(85, 85, 85, 0.9);
}
.patient-profile-dialog-box {
background-color: rgba(85, 85, 85, 0.6);
padding: 20px;
border-radius: 5px;
height: 550px;
margin-top: 20px;
}
.detail-head-content{
display: flex;
color: #ffffff;
padding: 20px;
font-family: 'Arial Negreta', 'Arial Normal', 'Arial', sans-serif;
font-weight: 700;
font-size:14px;
}
.detail-head-text{
margin: 0px 20px;
}
</style>