From 55ef5b8cc391b73337f7c1b8b05fb5b2fe4d3f38 Mon Sep 17 00:00:00 2001 From: Alfred Date: Mon, 9 Feb 2026 06:09:30 +0800 Subject: [PATCH] =?UTF-8?q?webui:=20=E5=85=A8=E7=AB=99=20emoji=E2=86=92Rem?= =?UTF-8?q?ixIcon/=E5=8E=BB=20emoji=EF=BC=9BOTA=20=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=89=8D=20--fresh=20=E7=BC=96=E8=AF=91=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - index.html/app.js: 文案与图标 emoji 改为 RemixIcon 或删除(保留 configTabs/RULE_ICON_OPTIONS 映射) - zh-CN.js/en-US.js: 语言包去 emoji - tools/ota_server/README: 增加「发布前用 build.sh --fresh」说明,便于 OTA 检测新固件 --- components/ts_webui/web/css/style.css | 102 +++- components/ts_webui/web/index.html | 6 +- components/ts_webui/web/js/app.js | 743 +++++++++++------------ components/ts_webui/web/js/lang/en-US.js | 322 +++++----- components/ts_webui/web/js/lang/zh-CN.js | 274 ++++----- tools/ota_server/README.md | 10 + 6 files changed, 779 insertions(+), 678 deletions(-) diff --git a/components/ts_webui/web/css/style.css b/components/ts_webui/web/css/style.css index 313f6fc..8459a5f 100644 --- a/components/ts_webui/web/css/style.css +++ b/components/ts_webui/web/css/style.css @@ -181,10 +181,23 @@ body { .btn-danger { background: #ffebee; - border-color: #ef9a9a; + border: 1px solid #ef9a9a; color: #c62828; } +/* 灰色小按钮规范:背景 #f5f6fa、文字 #666、边框 #dcdfe6(服务、USB、同步、取消、刷新等) */ +button.btn-gray, +.btn-gray { + background: #f5f6fa !important; + color: #666 !important; + border: 1px solid #dcdfe6 !important; +} +button.btn-gray:hover, +.btn-gray:hover { + background: #ebeef5 !important; + border-color: #c0c4cc !important; +} + /* MD 规范:运行中、添加 */ .btn-success { background: #e8f5e9; @@ -1083,6 +1096,17 @@ body { align-items: center; justify-content: center; padding: 60px; + gap: 20px; +} + +.loading .loading-icon { + font-size: 48px; + color: var(--primary-color); + animation: spin 1s linear infinite; +} + +.loading p { + margin: 0; } .spinner { @@ -3037,6 +3061,25 @@ body { padding: 5px 12px; font-size: 0.85rem; } +/* HTTPS 证书一行:CSR / 证书 / 删除 等按钮统一宽度,视觉一致(含表格行内按钮) */ +.page-security .button-group .btn { + min-width: 6rem; + box-sizing: border-box; +} +.page-security .data-table td .btn { + width: 6rem; + min-width: 6rem; + height: 2rem; + min-height: 2rem; + line-height: 2rem; + padding-top: 0; + padding-bottom: 0; + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + text-align: center; +} .page-security .form-actions .btn, .page-security .form-actions .btn-sm { @@ -3050,6 +3093,37 @@ body { margin-bottom: 20px; } +/* 安全页正文/表格/信息卡/弹窗字体与大小统一为与「TianShanOS Intermediate CA」一致 */ +.page-security .section, +.page-security .info-card, +.page-security .data-table, +.page-security .data-table th, +.page-security .data-table td, +.page-security .modal .modal-content { + font-size: 0.9rem; + font-family: inherit; +} +.page-security .section h2 { + font-size: 1.15rem; + font-weight: 600; +} +.page-security .modal .modal-content h2 { + font-size: 1.1rem; +} +/* 表格内 code、只读 input、CN/设备名等与「TianShanOS Intermediate CA」统一字号 */ +.page-security .data-table code { + font-size: 1em; +} +.page-security input[readonly], +.page-security .modal .modal-content input[type="text"], +.page-security .modal .modal-content label, +.page-security .modal .modal-content .form-group div { + font-size: inherit; +} +.page-security .modal .modal-content textarea { + font-size: inherit; +} + /* ========================================================================= 终端页面样式 ========================================================================= */ @@ -3274,7 +3348,7 @@ body { .btn-warning { background-color: #fff8e1; - border-color: #ffd54f; + border: 1px solid #ffd54f; color: #f57c00; } @@ -3302,7 +3376,21 @@ body { border-color: #007bff; } -/* 灰色 Tab 按钮样式(SD卡、SPIFFS) */ +/* 灰色 Tab 按钮样式(SD卡、SPIFFS),统一宽高 */ +.storage-tabs .tab-btn.btn-gray { + width: 6rem; + min-width: 6rem; + height: 2rem; + min-height: 2rem; + line-height: 2rem; + padding-top: 0; + padding-bottom: 0; + text-align: center; + box-sizing: border-box; + display: inline-flex; + align-items: center; + justify-content: center; +} .tab-btn.btn-gray { padding: 4px 12px; font-size: 0.85rem; @@ -6884,6 +6972,12 @@ body { opacity: 0.7; } +.quick-actions-empty .empty-icon { + font-size: 48px; + margin-bottom: 12px; + opacity: 0.35; +} + /* LPMu 监控面板 */ /* ==================== 数据监控面板组件 ==================== */ @@ -6920,7 +7014,7 @@ body { .data-widgets-empty .empty-icon { font-size: 48px; margin-bottom: 12px; - opacity: 0.5; + opacity: 0.35; } .data-widgets-empty p { diff --git a/components/ts_webui/web/index.html b/components/ts_webui/web/index.html index 68b2440..b9a1f47 100644 --- a/components/ts_webui/web/index.html +++ b/components/ts_webui/web/index.html @@ -48,7 +48,7 @@
-
+

加载中...

@@ -105,11 +105,11 @@

LED 设置

diff --git a/components/ts_webui/web/js/lang/en-US.js b/components/ts_webui/web/js/lang/en-US.js index 802229b..af59759 100644 --- a/components/ts_webui/web/js/lang/en-US.js +++ b/components/ts_webui/web/js/lang/en-US.js @@ -738,8 +738,8 @@ i18n.registerLanguage('en-US', { // Service serviceSuccess: 'Service {name} {action} successful', // Voltage protection - voltageProtectionEnabled: '✅ Voltage protection enabled', - voltageProtectionDisabled: '⚠️ Voltage protection disabled', + voltageProtectionEnabled: 'Voltage protection enabled', + voltageProtectionDisabled: 'Voltage protection disabled', switchFailed: 'Switch failed', // USB switch usbSwitching: 'Switching USB to {target}...', @@ -752,7 +752,7 @@ i18n.registerLanguage('en-US', { widgetBound: 'Bound {widget} → {var}', // Quick actions processRunning: 'Process is running, please stop it first', - cardNotFound: '❌ Action card not found', + cardNotFound: 'Action card not found', executionFailed: 'Execution failed', processTerminated: 'Process terminated', processNotExist: 'Process does not exist', @@ -809,7 +809,7 @@ i18n.registerLanguage('en-US', { rollbackFailed: 'Rollback failed', upgradeAborted: 'Upgrade aborted', abortFailed: 'Abort failed', - otaServerSaved: '✅ OTA server URL saved', + otaServerSaved: 'OTA server URL saved', otaServerCleared: 'OTA server URL cleared', enterOtaServer: 'Please enter OTA server URL first', upgradeFailed: 'Upgrade failed', @@ -830,8 +830,8 @@ i18n.registerLanguage('en-US', { deleteActionResult: 'Delete action {id}', deleteSourceResult: 'Delete source {id}', deleteSourceFailed: 'Failed to delete source', - shutdownSettingsSaved: '✅ Shutdown settings saved', - defaultsRestored: '✅ Defaults restored', + shutdownSettingsSaved: 'Shutdown settings saved', + defaultsRestored: 'Defaults restored', restoreFailed: 'Restore failed', deleteRuleResult: 'Delete rule {id}', deleteRuleFailed: 'Failed to delete rule', @@ -916,8 +916,8 @@ i18n.registerLanguage('en-US', { hostInfoEmpty: 'Host information is empty', testingConnection: 'Testing connection to {host}...', cannotGetHostInfo: 'Cannot get host information', - connectionSuccess: '✅ Connection to {host} successful!', - testConnectionFailed: '❌ Test failed', + connectionSuccess: 'Connection to {host} successful!', + testConnectionFailed: 'Test failed', hostConfigExported: 'Host config exported: {filename}', sshHostRemoved: 'SSH host {id} removed from list', removeFailed: 'Remove failed', @@ -938,9 +938,9 @@ i18n.registerLanguage('en-US', { clearFailed: 'Clear failed', certCopiedToClipboard: 'Certificate copied to clipboard', // PKI config - applyingConfig: '🔄 Applying config...', - configApplied: '✅ Config applied\nModules: {modules}', - applyFailed: '❌ Apply failed', + applyingConfig: 'Applying config...', + configApplied: 'Config applied\nModules: {modules}', + applyFailed: 'Apply failed', onlyDeveloperCanExport: 'Only Developer devices can export config packs', selectedJsonFiles: 'Selected all JSON files in current directory', configPackCopied: 'Config pack copied to clipboard', @@ -952,12 +952,12 @@ i18n.registerLanguage('en-US', { }, // Device Control device: { - agxRunning: '🟢 AGX Running', - agxStopped: '🔴 AGX Stopped', - lpmuRunning: '🟢 LPMU Running', - lpmuStopped: '🔴 LPMU Stopped', - lpmuDetecting: '⏳ Detecting Status', - lpmuUnknown: '⚠️ LPMU Status Unknown', + agxRunning: 'AGX Running', + agxStopped: 'AGX Stopped', + lpmuRunning: 'LPMU Running', + lpmuStopped: 'LPMU Stopped', + lpmuDetecting: 'Detecting Status', + lpmuUnknown: 'LPMU Status Unknown', lpmuOnlineHint: 'LPMU online (ping 10.10.99.99 reachable)\nClick to trigger power button', lpmuOfflineHint: 'LPMU offline (ping 10.10.99.99 unreachable)\nClick to trigger power button', lpmuDetectingHint: 'Detecting LPMU status...\nMax wait 80 seconds', @@ -1053,12 +1053,12 @@ i18n.registerLanguage('en-US', { filePage: { dirNotExist: 'Directory does not exist', createDir: 'Create Directory', - emptyFolder: '📂 Empty Folder', - noImages: '📂 No image files', + emptyFolder: 'Empty Folder', + noImages: 'No image files', noFonts: 'No available fonts', uploading: 'Uploading...', - uploadComplete: '✓ Complete', - uploadError: '✕ Failed', + uploadComplete: 'Complete', + uploadError: 'Failed', confirmDelete: 'Are you sure you want to delete this file?', // Dialogs uploadFiles: 'Upload Files', @@ -1149,12 +1149,12 @@ i18n.registerLanguage('en-US', { // SSH/Commands Page sshPage: { // Service status labels - statusReady: '✅ Ready', - statusChecking: '🔄 Checking', - statusTimeout: '⚠️ Timeout', - statusFailed: '❌ Failed', - statusIdle: '⏸️ Idle', - statusStopped: '⏹️ Stopped', + statusReady: 'Ready', + statusChecking: 'Checking', + statusTimeout: 'Timeout', + statusFailed: 'Failed', + statusIdle: 'Idle', + statusStopped: 'Stopped', // Error messages hostNotFound: 'Host not found', cmdNotFound: 'Command not found', @@ -1222,31 +1222,31 @@ i18n.registerLanguage('en-US', { exitCode: 'Exit Code', waitingOutput: 'Waiting for output...', sessionId: 'Session ID', - commandSubmitted: '✅ Command submitted to server background', - useButtonsAbove: '💡 Use buttons above to view logs, track output or check process status', - logFile: '📄 Log File', - processKeyword: '🔍 Process Keyword', - startTailLog: '📡 Start Real-time Tracking', + commandSubmitted: 'Command submitted to server background', + useButtonsAbove: 'Use buttons above to view logs, track output or check process status', + logFile: 'Log File', + processKeyword: 'Process Keyword', + startTailLog: 'Start Real-time Tracking', clickToExit: '(Click "Stop Tracking" button to exit)', - stoppedTailLog: '⏹️ Stopped Real-time Tracking', - viewServiceLog: '📄 View Service Log', + stoppedTailLog: 'Stopped Real-time Tracking', + viewServiceLog: 'View Service Log', file: 'File', - stopService: '🛑 Stop Service', + stopService: 'Stop Service', processRunningPid: 'Process running (PID: {pid}), stopping...', - serviceStopped: '✅ Service stopped', - tryForceKill: '⚠️ Process may still be running, trying force kill...', - forceKilled: '✅ Force killed', - processAlreadyStopped: '⚠️ Process already stopped', - pidFileNotExist: '⚠️ PID file not exist, service may not have started', + serviceStopped: 'Service stopped', + tryForceKill: 'Process may still be running, trying force kill...', + forceKilled: 'Force killed', + processAlreadyStopped: 'Process already stopped', + pidFileNotExist: 'PID file not exist, service may not have started', stopServiceFailed: 'Failed to stop service', executionFailed: 'Execution failed', getLogFailed: 'Failed to get log', - patternMatchSuccess: '🎯 Pattern Match Success!', - expectPatternMatch: '✅ Expect pattern matched: Yes', - failPatternMatch: '❌ Fail pattern matched: Yes', - extractedContent: '📋 Extracted Content', - cancelledExecution: '⏹️ Execution cancelled', - error: '❌ Error', + patternMatchSuccess: 'Pattern Match Success!', + expectPatternMatch: 'Expect pattern matched: Yes', + failPatternMatch: 'Fail pattern matched: Yes', + extractedContent: 'Extracted Content', + cancelledExecution: 'Execution cancelled', + error: 'Error', // nohup quick actions tailLog: 'Tail Log', stopTail: 'Stop Tail', @@ -1259,20 +1259,20 @@ i18n.registerLanguage('en-US', { commandLabel: 'Command', storeVar: 'Store Variable', // Config pack related - generatingConfigPack: '🔄 Generating config pack...', - exportSuccess: '✅ Export successful!', - verifyingConfigPack: '🔄 Verifying config pack...', - signatureVerified: '✅ Signature verified', - savingConfig: '🔄 Saving config...', - configExists: '⚠️ Config {id} already exists, please check "Overwrite"', - configSaved: '✅ Config saved', + generatingConfigPack: 'Generating config pack...', + exportSuccess: 'Export successful!', + verifyingConfigPack: 'Verifying config pack...', + signatureVerified: 'Signature verified', + savingConfig: 'Saving config...', + configExists: 'Config {id} already exists, please check "Overwrite"', + configSaved: 'Config saved', // SSH import/export modals exportSshCmdTitle: 'Export SSH Command Config', exportSshCmdDesc: 'Export command {cmdId} as encrypted config pack', includeHostConfig: 'Include dependent host config', - includeHostRecommend: '💡 Recommended for complete import on target device', + includeHostRecommend: 'Recommended for complete import on target device', targetCert: 'Target Device Certificate (PEM)', - targetCertHint: '💡 Paste target device certificate. Leave empty to use local certificate (self-encrypt)', + targetCertHint: 'Paste target device certificate. Leave empty to use local certificate (self-encrypt)', importSshCmdTitle: 'Import SSH Command Config', importSshCmdDesc: 'Select .tscfg config pack file to import SSH commands', selectFile: 'Select File', @@ -1287,14 +1287,14 @@ i18n.registerLanguage('en-US', { exportedWithoutHost: 'Exported command config: {filename}', importCommand: 'Import Command', // Deploy/Revoke - deployingKey: '🔄 Deploying key...', - deploySuccess: '✅ Deploy successful! Now you can use key "{keyId}" for passwordless login to {target}', - authVerified: '✓ Public key auth verified', - authSkipped: '⚠ Public key auth verification skipped', - revokingKey: '🔄 Revoking key...', - revokeSuccess: '✅ Revoke successful! Removed {count} matching public keys from {target}', - keyNotFound: '⚠️ Public key not found on {target}', - removeLocalOnly: '🗑️ Remove Local Record Only', + deployingKey: 'Deploying key...', + deploySuccess: 'Deploy successful! Now you can use key "{keyId}" for passwordless login to {target}', + authVerified: 'Public key auth verified', + authSkipped: 'Public key auth verification skipped', + revokingKey: 'Revoking key...', + revokeSuccess: 'Revoke successful! Removed {count} matching public keys from {target}', + keyNotFound: 'Public key not found on {target}', + removeLocalOnly: 'Remove Local Record Only', // Command editor placeholders cmdIdPlaceholder: 'e.g.: restart_nginx, check_status', cmdNamePlaceholder: 'e.g.: Restart Service', @@ -1378,7 +1378,7 @@ i18n.registerLanguage('en-US', { readyTimeoutHint: 'Mark as timeout if ready pattern not matched within this time', readyIntervalLabel: 'Check Interval (ms)', readyIntervalHint: 'How often to check the log file', - serviceLogHint: '💡 After service starts, system will monitor log file:', + serviceLogHint: 'After service starts, system will monitor log file:', serviceLogPath: '/tmp/ts_nohup_[cmd_name].log', serviceStatusHint: 'Variable [var_name].status will auto-update based on log matching', varNameLabel: 'Store Variable Name', @@ -1407,7 +1407,7 @@ i18n.registerLanguage('en-US', { connectingWaitingEvent: 'Connecting and waiting for event: {event}', connectingAutoDiscover: 'Connecting and auto-discovering events...', unknownEvent: '(Unknown event)', - sioConnectionSuccess: '✅ Connection successful', + sioConnectionSuccess: 'Connection successful', eventLabel: 'Event', timeout: 'Timeout', reconnectInterval: 'Reconnect Interval', @@ -1424,7 +1424,7 @@ i18n.registerLanguage('en-US', { deleteHttpsKeyAndCert: 'Delete HTTPS Key and Certificate', keyNotGenerated: 'Key not generated', generateHttpsKey: 'Generate HTTPS Key Pair', - generateKey: '🔑 Generate Key', + generateKey: 'Generate Key', // Certificate details subjectCN: 'Subject CN', issuer: 'Issuer', @@ -1459,18 +1459,18 @@ i18n.registerLanguage('en-US', { configFiles: 'config files', savedTo: 'Saved to', // Config pack export - configPackExport: '📦 Export Config Pack', + configPackExport: 'Export Config Pack', selectConfigFiles: 'Select Config Files', configName: 'Config Name', configNamePlaceholder: 'Auto-filled from filename', configDescPlaceholder: 'LED effect config', targetDeviceCert: 'Target Device Certificate (PEM)', certPlaceholder: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----', - certHint: '💡 Paste certificate exported from target device', - generateConfigPack: '📦 Generate Config Pack', + certHint: 'Paste certificate exported from target device', + generateConfigPack: 'Generate Config Pack', generatedConfigPack: 'Generated Config Pack (.tscfg)', configPackPlaceholder: 'Config pack will be displayed here...', - copyToClipboard: '📋 Copy to Clipboard', + copyToClipboard: 'Copy to Clipboard', downloadToLocal: '💾 Download', // File selection status selectedFiles: '{count} file(s) selected', @@ -1494,21 +1494,21 @@ i18n.registerLanguage('en-US', { keysTableCreated: 'Created', keysTableExportable: 'Exportable', keysTableActions: 'Actions', - hostsHint: '💡 After deploying public key via the "Deploy" button above, host will appear in this list', + hostsHint: 'After deploying public key via the "Deploy" button above, host will appear in this list', importHost: '📥 Import Host', hostId: 'Host ID', address: 'Address', port: 'Port', username: 'Username', deployKey: 'Deploy Key', - fingerprintHint: '💡 Server fingerprints recorded during SSH connection to prevent man-in-the-middle attacks. Update if server is reinstalled.', + fingerprintHint: 'Server fingerprints recorded during SSH connection to prevent man-in-the-middle attacks. Update if server is reinstalled.', keyType: 'Key Type', fingerprintSha256: 'Fingerprint (SHA256)', addedTime: 'Added', // SSH host import/export - exportSshHostTitle: '📤 Export SSH Host Config', + exportSshHostTitle: 'Export SSH Host Config', exportSshHostDesc: 'Export host {hostId} config as encrypted config package', - exportSshHostCertHint: '💡 Paste target device certificate. Leave empty to use local certificate (self-encrypt)', + exportSshHostCertHint: 'Paste target device certificate. Leave empty to use local certificate (self-encrypt)', importSshHostTitle: '📥 Import SSH Host Config', importSshHostDesc: 'Select .tscfg config package file to import SSH host config', confirmImport: '📥 Confirm Import', @@ -1517,29 +1517,29 @@ i18n.registerLanguage('en-US', { deployKeyDesc: 'Deploy public key {keyId} to remote server authorized_keys', targetHost: 'Target Host', authPassword: 'Auth Password (required for first deploy)', - deployHint: '💡 After successful deployment, host will be added to "Deployed Hosts" list for passwordless login', + deployHint: 'After successful deployment, host will be added to "Deployed Hosts" list for passwordless login', startDeploy: '🚀 Start Deploy', // Revoke key modal - revokeKeyTitle: '⚠️ Revoke Public Key', + revokeKeyTitle: 'Revoke Public Key', revokeKeyDesc: 'Remove public key {keyId} from remote server', - revokeWarning: '⚠️ Warning: After revocation, passwordless login with this key will be disabled', - revokePublicKey: '⚠️ Revoke Public Key', + revokeWarning: 'Warning: After revocation, passwordless login with this key will be disabled', + revokePublicKey: 'Revoke Public Key', // Host key mismatch warning - hostMismatchTitle: '⚠️ Security Warning: Host Key Mismatch!', + hostMismatchTitle: 'Security Warning: Host Key Mismatch!', hostMismatchDesc: 'Host key has changed! This may indicate:', hostMismatchReason1: 'Server has been reinstalled', hostMismatchReason2: 'Man-in-the-middle attack', hostMismatchReason3: 'Server IP assigned to different device', hostMismatchAdvice: 'Suggestion: If you confirm the server was reinstalled or key was updated, click "Update Host Key" to remove old record, then reconnect to trust new key.', - updateHostKey: '🔄 Update Host Key', - abortOperation: '❌ Abort Operation', + updateHostKey: 'Update Host Key', + abortOperation: 'Abort Operation', storedFingerprint: 'Stored Fingerprint', currentFingerprint: 'Current Fingerprint', // HTTPS certificate modals - genHttpsKeyPairTitle: '🔑 Generate HTTPS Key Pair', + genHttpsKeyPairTitle: 'Generate HTTPS Key Pair', genHttpsKeyPairDesc: 'Generate ECDSA P-256 key pair for mTLS authentication', - existingKeyWarning: '⚠️ Key pair already exists, continuing will overwrite!', - generate: '🔑 Generate', + existingKeyWarning: 'Key pair already exists, continuing will overwrite!', + generate: 'Generate', csrTitle: 'Certificate Signing Request (CSR)', deviceId: 'Device ID (CN)', deviceIdHint: 'Leave empty for default config', @@ -1553,25 +1553,25 @@ i18n.registerLanguage('en-US', { installCaTitle: 'Install CA Certificate Chain', installCaDesc: 'Paste root and intermediate certificates (PEM format, can concatenate)', caCertPem: 'CA Certificate Chain PEM', - deleteCredentialsTitle: '🗑️ Delete HTTPS Credentials', + deleteCredentialsTitle: 'Delete HTTPS Credentials', deleteCredentialsDesc: 'This will delete key pair and certificate, regeneration required after', - deleteCredentialsWarning: '⚠️ Warning: Device cannot perform mTLS auth after deletion until reconfigured', - confirmDelete: '⚠️ Confirm Delete', + deleteCredentialsWarning: 'Warning: Device cannot perform mTLS auth after deletion until reconfigured', + confirmDelete: 'Confirm Delete', viewCertTitle: 'View Certificate Details', close: 'Close', // Config pack verification configId: 'Config ID', type: 'Type', - sshCommandType: '📋 SSH Command', + sshCommandType: 'SSH Command', signerLabel: 'Signer', official: 'Official', noteLabel: 'Note', autoLoadAfterRestart: 'Auto-load after restart', - configExistsWarning: '⚠️ Config already exists, import will overwrite', + configExistsWarning: 'Config already exists, import will overwrite', typeWithComment: 'Type: {type} | Note: {comment}', // Config Pack UI configPack: 'Config Pack', - configPackDesc: '💡 Config pack system allows secure encryption and signing of config files for device-to-device distribution', + configPackDesc: 'Config pack system allows secure encryption and signing of config files for device-to-device distribution', exportDeviceCert: 'Export Device Cert', importConfigPack: 'Import Config Pack', exportConfigPack: 'Export Config Pack', @@ -1618,7 +1618,7 @@ i18n.registerLanguage('en-US', { otaServer: 'OTA Server', saveToDevice: 'Save to Device', save: 'Save', - checkUpdate: '🔍 Check Update', + checkUpdate: 'Check Update', preparing: 'Preparing...', valid: 'Valid', invalid: 'Invalid', @@ -1746,12 +1746,12 @@ i18n.registerLanguage('en-US', { loadingOptions: '-- Loading --', sourceNoData: 'No variable data for this source', configSourceFirst: 'Please configure and enable data source first', - testRequesting: '🔄 Requesting...', - testSuccess: '✅ Connection successful', - testFailed: '❌ Request failed', - testError: '❌ Error', - testConnecting: '🔄 Connecting...', - testConnected: '✅ Connected, data received', + testRequesting: 'Requesting...', + testSuccess: 'Connection successful', + testFailed: 'Request failed', + testError: 'Error', + testConnecting: 'Connecting...', + testConnected: 'Connected, data received', noExtraParams: 'No extra parameters for this filter', selectCmdHint: 'Select command to monitor (created in SSH page)', selectHostFirst: '-- Select host first --', @@ -1764,7 +1764,7 @@ i18n.registerLanguage('en-US', { // SSH command reference preview selectCommand: 'Select Command', selectCommandHint: 'Select a command configured in SSH management page', - commandDetails: '📋 Command Details', + commandDetails: 'Command Details', previewHost: 'Host', previewCommand: 'Command', previewVariable: 'Variable', @@ -1776,17 +1776,17 @@ i18n.registerLanguage('en-US', { selectDevice: '-- Select Device --', selectDeviceHint: 'Select LED device to control', controlType: 'Control Type', - colorFill: '🎨 Color Fill', + colorFill: 'Color Fill', effectAnim: '🎬 Effect Animation', - brightnessOnly: '☀️ Brightness Only', - turnOff: '⏹ Turn Off', + brightnessOnly: 'Brightness Only', + turnOff: 'Turn Off', textDisplay: '📝 Text Display', imageDisplay: '📷 Display Image', qrcodeDisplay: '📱 Display QR Code', - filterDisplay: '🎨 Post Filter', - filterStop: '⏹ Stop Filter', - textStop: '⏹ Stop Text', - turnOffDevice: '⏹ Turn Off Device', + filterDisplay: 'Post Filter', + filterStop: 'Stop Filter', + textStop: 'Stop Text', + turnOffDevice: 'Turn Off Device', logConfig: 'Log Config', logLevel: 'Level', logMessage: 'Message', @@ -1838,10 +1838,10 @@ i18n.registerLanguage('en-US', { viewLog: 'View Log', stopProcess: 'Stop', // Log viewer - logTitle: '📄 Log', + logTitle: 'Log', loading: 'Loading...', - stopTracking: '⏹️ Stop Tracking', - startTracking: '▶️ Start Tracking', + stopTracking: 'Stop Tracking', + startTracking: 'Start Tracking', interval: 'Interval', realTimeUpdating: '● Real-time updating', trackingStopped: 'Tracking stopped', @@ -1953,23 +1953,23 @@ i18n.registerLanguage('en-US', { filterLabel: 'Filter', filterPulse: '💓 Pulse', filterBreathing: '💨 Breathing', - filterBlink: '💡 Blink', + filterBlink: 'Blink', filterWave: '🌊 Wave', filterScanline: '📺 Scanline', filterGlitch: '⚡ Glitch', filterRainbow: '🌈 Rainbow', filterSparkle: '✨ Sparkle', filterPlasma: '🎆 Plasma', - filterSepia: '🖼️ Sepia', - filterPosterize: '🎨 Posterize', - filterContrast: '🔆 Contrast', - filterInvert: '🔄 Invert', - filterGrayscale: '⬜ Grayscale', + filterSepia: 'Sepia', + filterPosterize: 'Posterize', + filterContrast: 'Contrast', + filterInvert: 'Invert', + filterGrayscale: 'Grayscale', // Variable action placeholders varValuePlaceholder: 'Supports expressions and variable references', varValueHint: 'Example: true, 123, ${other_var}', // Search - searchVariablePlaceholder: '🔍 Search variables...' + searchVariablePlaceholder: 'Search variables...' }, // Fan Control @@ -1987,24 +1987,24 @@ i18n.registerLanguage('en-US', { cleared: 'Cleared', noWidgets: 'No widgets', // Fan card - fanTitle: '🌀 Fan {id}', + fanTitle: 'Fan {id}', modeOff: 'Off', modeManual: 'Manual', modeAuto: 'Auto', modeCurve: 'Curve', speedAdjust: 'Speed Adjust', - editTempCurve: '⚙️ Edit Temperature Curve', + editTempCurve: 'Edit Temperature Curve', manualModeHint: 'Switch to manual mode to adjust', // Curve management modal curveManagement: '📈 Fan Curve Management', selectFan: 'Select Fan', fanN: 'Fan {id}', - bindTempVar: '🌡️ Bind Temperature Variable', + bindTempVar: 'Bind Temperature Variable', unbound: 'Unbound', bound: 'Bound', selectVariableHint: 'Select a float variable as temperature source (e.g. agx.cpu_temp)', bind: '💾 Bind', - unbind: '🗑️ Unbind', + unbind: 'Unbind', tempSpeedCurve: '📊 Temperature-Speed Curve', addPoint: '➕ Add Point', curveHint: 'Uses min speed below lowest point, max speed above highest point', @@ -2018,7 +2018,7 @@ i18n.registerLanguage('en-US', { minInterval: 'Min Interval (ms)', intervalHint: 'Minimum time between adjustments', cancel: 'Cancel', - applyCurve: '✅ Apply Curve', + applyCurve: 'Apply Curve', // Curve points tempPlaceholder: 'Temp', speedPlaceholder: 'Speed' @@ -2075,7 +2075,7 @@ i18n.registerLanguage('en-US', { presetLog: 'Log Stream', // Management interface management: 'Data Component Management', - panelSettings: '⚙️ Panel Settings', + panelSettings: 'Panel Settings', autoRefreshInterval: 'Auto Refresh Interval', disabled: 'Disabled', second: 's', @@ -2086,7 +2086,7 @@ i18n.registerLanguage('en-US', { seconds10: '10 sec', seconds30: '30 sec', minute1: '1 min', - addedWidgets: '📦 Added Widgets', + addedWidgets: 'Added Widgets', addNewWidget: '➕ Add New Widget', selectWidgetHint: 'Select a widget to edit
or add a new one', moveUp: 'Move Up', @@ -2130,7 +2130,7 @@ i18n.registerLanguage('en-US', { statusAttention: 'Attention', statusWarning: 'Warning', // Temperature variable selection - tempVariables: '🌡️ Temperature Variables', + tempVariables: 'Temperature Variables', otherNumericVariables: '📊 Other Numeric Variables', // Error messages setDutyLimitFailed: 'Failed to set duty cycle limit', @@ -2153,8 +2153,8 @@ i18n.registerLanguage('en-US', { fillColor: 'Fill Color', quickColors: 'Quick Colors', // Original - on: '🔆 On', - off: '💡 Off', + on: 'On', + off: 'Off', defaultFont: 'Default', quickActionsLoadFailed: 'Failed to load quick actions', realTimeUpdating: '● Real-time updating', @@ -2294,14 +2294,14 @@ i18n.registerLanguage('en-US', { // PKI/Security Config pkiPage: { - signatureVerified: '✅ Signature verified', - configImported: '✅ Config package imported', + signatureVerified: 'Signature verified', + configImported: 'Config package imported', savedTo: 'Saved to', - loadingFiles: '🔄 Loading...', - noConfigFiles: '📁 No config files (.json)', - loadError: '❌ Load failed', + loadingFiles: 'Loading...', + noConfigFiles: 'No config files (.json)', + loadError: 'Load failed', noTscfgFiles: 'No .tscfg files in directory', - contentEmpty: '⚠️ Warning: Config package content is empty', + contentEmpty: 'Warning: Config package content is empty', // PKI Status statusNotInit: 'Not Initialized', statusKeyGenerated: 'Key Generated, Awaiting CSR', @@ -2311,26 +2311,26 @@ i18n.registerLanguage('en-US', { statusError: 'Error', statusLoadFailed: 'Load Failed', deviceType: '{type} Device', - certValid: '✅ Valid', - certInvalid: '❌ Invalid', + certValid: 'Valid', + certInvalid: 'Invalid', expiredDays: 'Expired {days} days ago', expiresInDays: 'Expires in {days} days', remainingDays: '{days} days remaining', - generatingKeyPair: '🔄 Generating key pair...', - generatingCsr: '🔄 Generating CSR...', - installFailed: '❌ Install failed', + generatingKeyPair: 'Generating key pair...', + generatingCsr: 'Generating CSR...', + installFailed: 'Install failed', // Config Pack enterConfigName: 'Please enter config name', selectConfigFile: 'Please select config file', pasteTargetCert: 'Please paste target device certificate', invalidJsonConfig: 'Config file is not valid JSON', - generatingPack: '🔄 Generating config pack', - savedToDevice: '✅ Saved to device', - generationFailed: '❌ Generation failed', - verifying: '🔄 Verifying...', - verifyFailed: '❌ Verification failed', - importing: '🔄 Importing...', - importFailed: '❌ Import failed', + generatingPack: 'Generating config pack', + savedToDevice: 'Saved to device', + generationFailed: 'Generation failed', + verifying: 'Verifying...', + verifyFailed: 'Verification failed', + importing: 'Importing...', + importFailed: 'Import failed', uploadOrPasteContent: 'Please upload file or paste config pack content' }, @@ -2341,10 +2341,10 @@ i18n.registerLanguage('en-US', { english: 'EN', notLoggedIn: 'Not Logged In', // Button States - stopTracking: '⏹️ Stop Tracking', - startTracking: '▶️ Start Tracking', - testing: '⏳ Testing...', - connecting: '⏳ Connecting...', + stopTracking: 'Stop Tracking', + startTracking: 'Start Tracking', + testing: 'Testing...', + connecting: 'Connecting...', cancelling: 'Cancelling...', // Hints noOutput: '(No output)', @@ -2357,9 +2357,9 @@ i18n.registerLanguage('en-US', { colorSettings: 'Color Settings', turnOffLight: 'Turn Off', // OTA - firmwareUpgradeComplete: '✅ Firmware upgrade complete, preparing WebUI upgrade...', - allUpgradeComplete: '✅ All upgrades complete', - preparingUpgrade: '⏳ Preparing upgrade...', + firmwareUpgradeComplete: 'Firmware upgrade complete, preparing WebUI upgrade...', + allUpgradeComplete: 'All upgrades complete', + preparingUpgrade: 'Preparing upgrade...', initializing: 'Initializing...', downloadingFromServer: 'Downloading from OTA server', connectingServer: 'Connecting to server...', @@ -2367,11 +2367,11 @@ i18n.registerLanguage('en-US', { writingFlash: 'Writing to Flash (this may take 1-2 minutes)...', webuiSize: 'WebUI size', writingSpiffs: 'Writing to SPIFFS...', - upgradeFailed: '❌ Upgrade failed', + upgradeFailed: 'Upgrade failed', downloading: 'Downloading...', waitedSeconds: 'Waited {elapsed} seconds...', step2Webui: '[2/2] Starting WebUI upgrade...', - firmwareOnlyComplete: '✅ Firmware upgrade complete (WebUI skipped)', + firmwareOnlyComplete: 'Firmware upgrade complete (WebUI skipped)', updateTime: 'Update time', // System psramUnavailable: 'Unavailable', @@ -2384,10 +2384,10 @@ i18n.registerLanguage('en-US', { displayStats: 'Showing {filtered}/{total} entries', // Modal Titles newCommand: '➕ New Command', - editCommand: '✏️ Edit Command', + editCommand: 'Edit Command', commandVariables: '📊 Command Variables', sourceVariables: '📊 {source} Variables', - editActionTemplate: '✏️ Edit Action Template', + editActionTemplate: 'Edit Action Template', // Actions updateAction: '💾 Update', // Validation Errors @@ -2403,7 +2403,7 @@ i18n.registerLanguage('en-US', { configNotSet: '(Not configured)', // Pattern Match Results expectPatternConfigured: 'Not configured', - failPatternDetected: '⚠️ true (Error detected)', + failPatternDetected: 'true (Error detected)', extractedNone: 'None', extracting: 'Extracting...', // Status Mapping @@ -2411,10 +2411,10 @@ i18n.registerLanguage('en-US', { statusFailed: 'Failed', statusRunning: 'Running', statusTimeout: 'Timeout', - expectMatchYes: '✅ Yes', - expectMatchNo: '❌ No', - failMatchYes: '⚠️ Yes', - failMatchNo: '✅ No', + expectMatchYes: 'Yes', + expectMatchNo: 'No', + failMatchYes: 'Yes', + failMatchNo: 'No', // innerHTML related translation keys loadFailed: 'Load Failed', noVariableData: 'No variable data for this command, please execute once first', @@ -2470,10 +2470,10 @@ i18n.registerLanguage('en-US', { confirmRemoveHostLocal: 'Are you sure you want to remove host "{id}" from the list?\n\nNote: This only removes the local record, not the public key deployed on the server. To revoke the key, use the "Revoke" button.', confirmRemoveHostLocal2: 'Are you sure you want to remove host "{id}" from the list?\n\nNote: This only removes the local record, not the public key deployed on the server. To revoke the key, use the "Revoke" function in Key Management.', confirmDeleteKey: 'Are you sure you want to delete key "{id}"? This action cannot be undone!', - confirmExportPrivateKey: '⚠️ Security Warning\n\nYou are about to export private key "{id}".\n\nPrivate keys are highly sensitive credentials. Please ensure:\n• Do not transmit over public networks\n• Do not share with others\n• Store securely locally\n\nAre you sure you want to continue?', + confirmExportPrivateKey: 'Security Warning\n\nYou are about to export private key "{id}".\n\nPrivate keys are highly sensitive credentials. Please ensure:\n• Do not transmit over public networks\n• Do not share with others\n• Store securely locally\n\nAre you sure you want to continue?', confirmRemoveKnownHost: 'Are you sure you want to remove the record for "{host}:{port}"?', confirmClearKnownHosts: 'Are you sure you want to clear all known host records? This action cannot be undone!', - confirmDeletePKI: '⚠️ Are you sure you want to delete all PKI credentials?\n\nThis will delete:\n• Private key\n• Device certificate\n• CA certificate chain\n\nThis action cannot be undone!', + confirmDeletePKI: 'Are you sure you want to delete all PKI credentials?\n\nThis will delete:\n• Private key\n• Device certificate\n• CA certificate chain\n\nThis action cannot be undone!', // Alert dialogs and other prompts alertHostFingerprint: 'Host: {host}:{port}\nType: {type}\nFingerprint (SHA256):\n{fingerprint}', alertEnterWsAddress: 'Please enter WebSocket address', diff --git a/components/ts_webui/web/js/lang/zh-CN.js b/components/ts_webui/web/js/lang/zh-CN.js index 27e3e5c..a2616f2 100644 --- a/components/ts_webui/web/js/lang/zh-CN.js +++ b/components/ts_webui/web/js/lang/zh-CN.js @@ -702,8 +702,8 @@ i18n.registerLanguage('zh-CN', { // 服务 serviceSuccess: '服务 {name} {action} 成功', // 电压保护 - voltageProtectionEnabled: '✅ 电压保护已启用', - voltageProtectionDisabled: '⚠️ 电压保护已禁用', + voltageProtectionEnabled: '电压保护已启用', + voltageProtectionDisabled: '电压保护已禁用', switchFailed: '切换失败', // USB 切换 usbSwitching: '切换 USB 到 {target}...', @@ -716,7 +716,7 @@ i18n.registerLanguage('zh-CN', { widgetBound: '已绑定 {widget} → {var}', // 快捷操作 processRunning: '进程正在运行中,请先停止', - cardNotFound: '❌ 无法找到操作卡片', + cardNotFound: '无法找到操作卡片', executionFailed: '执行失败', processTerminated: '已终止进程', processNotExist: '进程已不存在', @@ -776,7 +776,7 @@ i18n.registerLanguage('zh-CN', { rollbackFailed: '回滚失败', upgradeAborted: '升级已中止', abortFailed: '中止失败', - otaServerSaved: '✅ OTA 服务器地址已保存', + otaServerSaved: 'OTA 服务器地址已保存', otaServerCleared: 'OTA 服务器地址已清除', enterOtaServer: '请先输入 OTA 服务器地址', upgradeFailed: '升级失败', @@ -797,8 +797,8 @@ i18n.registerLanguage('zh-CN', { deleteActionResult: '删除动作 {id}', deleteSourceResult: '删除数据源 {id}', deleteSourceFailed: '删除数据源失败', - shutdownSettingsSaved: '✅ 关机设置已保存', - defaultsRestored: '✅ 已恢复默认设置', + shutdownSettingsSaved: '关机设置已保存', + defaultsRestored: '已恢复默认设置', restoreFailed: '恢复失败', deleteRuleResult: '删除规则 {id}', deleteRuleFailed: '删除规则失败', @@ -916,8 +916,8 @@ i18n.registerLanguage('zh-CN', { hostInfoEmpty: '主机信息为空', testingConnection: '正在测试连接 {host}...', cannotGetHostInfo: '无法获取主机信息', - connectionSuccess: '✅ 连接 {host} 成功!', - testConnectionFailed: '❌ 测试失败', + connectionSuccess: '连接 {host} 成功!', + testConnectionFailed: '测试失败', hostConfigExported: '已导出主机配置: {filename}', sshHostRemoved: 'SSH 主机 {id} 已从列表移除', removeFailed: '移除失败', @@ -938,9 +938,9 @@ i18n.registerLanguage('zh-CN', { clearFailed: '清除失败', certCopiedToClipboard: '证书已复制到剪贴板', // PKI 配置 - applyingConfig: '🔄 正在应用配置...', - configApplied: '✅ 配置已应用\n模块: {modules}', - applyFailed: '❌ 应用失败', + applyingConfig: '正在应用配置...', + configApplied: '配置已应用\n模块: {modules}', + applyFailed: '应用失败', onlyDeveloperCanExport: '仅 Developer 设备可导出配置包', selectedJsonFiles: '已选择当前目录下的所有 JSON 文件', configPackCopied: '配置包已复制到剪贴板', @@ -953,12 +953,12 @@ i18n.registerLanguage('zh-CN', { // 设备控制 device: { - agxRunning: '🟢 AGX 运行中', - agxStopped: '🔴 AGX 已关闭', - lpmuRunning: '🟢 LPMU 运行中', - lpmuStopped: '🔴 LPMU 已关闭', - lpmuDetecting: '⏳ 状态获取中', - lpmuUnknown: '⚠️ LPMU 状态未知', + agxRunning: 'AGX 运行中', + agxStopped: 'AGX 已关闭', + lpmuRunning: 'LPMU 运行中', + lpmuStopped: 'LPMU 已关闭', + lpmuDetecting: '状态获取中', + lpmuUnknown: 'LPMU 状态未知', lpmuOnlineHint: 'LPMU 在线 (ping 10.10.99.99 可达)\n点击触发电源按钮', lpmuOfflineHint: 'LPMU 离线 (ping 10.10.99.99 不可达)\n点击触发电源按钮', lpmuDetectingHint: '正在检测 LPMU 状态...\n最多等待 80 秒', @@ -1054,12 +1054,12 @@ i18n.registerLanguage('zh-CN', { filePage: { dirNotExist: '目录不存在', createDir: '创建目录', - emptyFolder: '📂 空文件夹', - noImages: '📂 无图片文件', + emptyFolder: '空文件夹', + noImages: '无图片文件', noFonts: '无可用字体', uploading: '上传中...', - uploadComplete: '✓ 完成', - uploadError: '✕ 失败', + uploadComplete: '完成', + uploadError: '失败', confirmDelete: '确定要删除这个文件吗?', // 对话框 uploadFiles: '上传文件', @@ -1150,12 +1150,12 @@ i18n.registerLanguage('zh-CN', { // SSH/Commands 页面 sshPage: { // 服务状态标签 - statusReady: '✅ 就绪', - statusChecking: '🔄 检测中', - statusTimeout: '⚠️ 超时', - statusFailed: '❌ 失败', + statusReady: '就绪', + statusChecking: '检测中', + statusTimeout: '超时', + statusFailed: '失败', statusIdle: '⏸️ 未启动', - statusStopped: '⏹️ 已停止', + statusStopped: '已停止', // 错误消息 hostNotFound: '主机信息不存在', cmdNotFound: '命令不存在', @@ -1223,31 +1223,31 @@ i18n.registerLanguage('zh-CN', { exitCode: '退出码', waitingOutput: '等待输出...', sessionId: '会话 ID', - commandSubmitted: '✅ 命令已提交到服务器后台', - useButtonsAbove: '💡 使用上方按钮查看日志、跟踪输出或检查进程状态', - logFile: '📄 日志文件', - processKeyword: '🔍 进程关键词', - startTailLog: '📡 开始实时跟踪', + commandSubmitted: '命令已提交到服务器后台', + useButtonsAbove: '使用上方按钮查看日志、跟踪输出或检查进程状态', + logFile: '日志文件', + processKeyword: '进程关键词', + startTailLog: '开始实时跟踪', clickToExit: '(点击"停止跟踪"按钮退出)', - stoppedTailLog: '⏹️ 已停止实时跟踪', - viewServiceLog: '📄 查看服务日志', + stoppedTailLog: '已停止实时跟踪', + viewServiceLog: '查看服务日志', file: '文件', - stopService: '🛑 停止服务', + stopService: '停止服务', processRunningPid: '进程运行中 (PID: {pid}),正在停止...', - serviceStopped: '✅ 服务已停止', - tryForceKill: '⚠️ 进程可能仍在运行,尝试强制终止...', - forceKilled: '✅ 已强制终止', - processAlreadyStopped: '⚠️ 进程已经停止', - pidFileNotExist: '⚠️ PID 文件不存在,服务可能未启动', + serviceStopped: '服务已停止', + tryForceKill: '进程可能仍在运行,尝试强制终止...', + forceKilled: '已强制终止', + processAlreadyStopped: '进程已经停止', + pidFileNotExist: 'PID 文件不存在,服务可能未启动', stopServiceFailed: '停止服务失败', executionFailed: '执行失败', getLogFailed: '获取日志失败', - patternMatchSuccess: '🎯 模式匹配成功!', - expectPatternMatch: '✅ 期望模式匹配: 是', - failPatternMatch: '❌ 失败模式匹配: 是', - extractedContent: '📋 提取内容', - cancelledExecution: '⏹️ 已取消执行', - error: '❌ 错误', + patternMatchSuccess: '模式匹配成功!', + expectPatternMatch: '期望模式匹配: 是', + failPatternMatch: '失败模式匹配: 是', + extractedContent: '提取内容', + cancelledExecution: '已取消执行', + error: '错误', // nohup 快捷操作 tailLog: '实时跟踪', stopTail: '停止跟踪', @@ -1260,20 +1260,20 @@ i18n.registerLanguage('zh-CN', { commandLabel: '命令', storeVar: '存储变量', // 配置包相关 - generatingConfigPack: '🔄 正在生成配置包...', - exportSuccess: '✅ 导出成功!', - verifyingConfigPack: '🔄 正在验证配置包...', - signatureVerified: '✅ 签名验证通过', - savingConfig: '🔄 正在保存配置...', - configExists: '⚠️ 配置 {id} 已存在,请勾选「覆盖」选项', - configSaved: '✅ 已保存配置', + generatingConfigPack: '正在生成配置包...', + exportSuccess: '导出成功!', + verifyingConfigPack: '正在验证配置包...', + signatureVerified: '签名验证通过', + savingConfig: '正在保存配置...', + configExists: '配置 {id} 已存在,请勾选「覆盖」选项', + configSaved: '已保存配置', // SSH 导入导出弹窗 exportSshCmdTitle: '导出 SSH 指令配置', exportSshCmdDesc: '导出指令 {cmdId} 的配置为加密配置包', includeHostConfig: '同时导出依赖的主机配置', - includeHostRecommend: '💡 推荐勾选,便于在目标设备完整导入', + includeHostRecommend: '推荐勾选,便于在目标设备完整导入', targetCert: '目标设备证书 (PEM)', - targetCertHint: '💡 粘贴目标设备的证书。留空则使用本机证书(自加密)', + targetCertHint: '粘贴目标设备的证书。留空则使用本机证书(自加密)', importSshCmdTitle: '导入 SSH 指令配置', importSshCmdDesc: '选择 .tscfg 配置包文件以导入 SSH 指令', selectFile: '选择文件', @@ -1288,14 +1288,14 @@ i18n.registerLanguage('zh-CN', { exportedWithoutHost: '已导出指令配置: {filename}', importCommand: '导入指令', // 部署/撤销 - deployingKey: '🔄 正在部署密钥...', - deploySuccess: '✅ 部署成功!现在可以使用密钥 "{keyId}" 免密登录 {target}', - authVerified: '✓ 公钥认证已验证', + deployingKey: '正在部署密钥...', + deploySuccess: '部署成功!现在可以使用密钥 "{keyId}" 免密登录 {target}', + authVerified: '公钥认证已验证', authSkipped: '⚠ 公钥认证验证跳过', - revokingKey: '🔄 正在撤销密钥...', - revokeSuccess: '✅ 撤销成功!已从 {target} 移除 {count} 个匹配的公钥', - keyNotFound: '⚠️ 该公钥未在 {target} 上找到', - removeLocalOnly: '🗑️ 仅移除本地记录', + revokingKey: '正在撤销密钥...', + revokeSuccess: '撤销成功!已从 {target} 移除 {count} 个匹配的公钥', + keyNotFound: '该公钥未在 {target} 上找到', + removeLocalOnly: '仅移除本地记录', // 命令编辑器 placeholder cmdIdPlaceholder: '例如:restart_nginx, check_status', cmdNamePlaceholder: '例如:重启服务', @@ -1379,7 +1379,7 @@ i18n.registerLanguage('zh-CN', { readyTimeoutHint: '超过此时间未匹配到就绪模式则标记为 timeout', readyIntervalLabel: '检测间隔(毫秒)', readyIntervalHint: '每隔多久检测一次日志文件', - serviceLogHint: '💡 服务启动后,系统将监测日志文件:', + serviceLogHint: '服务启动后,系统将监测日志文件:', serviceLogPath: '/tmp/ts_nohup_[命令名].log', serviceStatusHint: '变量 [变量名].status 会根据日志匹配自动更新状态', varNameLabel: '存储变量名', @@ -1408,7 +1408,7 @@ i18n.registerLanguage('zh-CN', { connectingWaitingEvent: '正在连接并等待事件: {event}', connectingAutoDiscover: '正在连接并自动发现事件...', unknownEvent: '(未知事件)', - sioConnectionSuccess: '✅ 连接成功', + sioConnectionSuccess: '连接成功', eventLabel: '事件', timeout: '超时时间', reconnectInterval: '断线重连间隔', @@ -1467,11 +1467,11 @@ i18n.registerLanguage('zh-CN', { configDescPlaceholder: 'LED 特效配置', targetDeviceCert: '目标设备证书 (PEM)', certPlaceholder: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----', - certHint: '💡 粘贴目标设备导出的证书', + certHint: '粘贴目标设备导出的证书', generateConfigPack: '📦 生成配置包', generatedConfigPack: '生成的配置包 (.tscfg)', configPackPlaceholder: '配置包将在此显示...', - copyToClipboard: '📋 复制到剪贴板', + copyToClipboard: '复制到剪贴板', downloadToLocal: '💾 下载到本地', // 文件选择状态 selectedFiles: '已选择 {count} 个文件', @@ -1495,21 +1495,21 @@ i18n.registerLanguage('zh-CN', { keysTableCreated: '创建时间', keysTableExportable: '可导出', keysTableActions: '操作', - hostsHint: '💡 通过上方密钥的「部署」按钮将公钥部署到远程服务器后,主机将自动出现在此列表', + hostsHint: '通过上方密钥的「部署」按钮将公钥部署到远程服务器后,主机将自动出现在此列表', importHost: '📥 导入主机', hostId: '主机 ID', address: '地址', port: '端口', username: '用户名', deployKey: '部署密钥', - fingerprintHint: '💡 SSH 连接时自动记录的服务器指纹,用于防止中间人攻击。如果服务器重装需要更新指纹。', + fingerprintHint: 'SSH 连接时自动记录的服务器指纹,用于防止中间人攻击。如果服务器重装需要更新指纹。', keyType: '密钥类型', fingerprintSha256: '指纹 (SHA256)', addedTime: '添加时间', // SSH 主机导入/导出 - exportSshHostTitle: '📤 导出 SSH 主机配置', + exportSshHostTitle: '导出 SSH 主机配置', exportSshHostDesc: '导出主机 {hostId} 的配置为加密配置包', - exportSshHostCertHint: '💡 粘贴目标设备的证书。留空则使用本机证书(自加密)', + exportSshHostCertHint: '粘贴目标设备的证书。留空则使用本机证书(自加密)', importSshHostTitle: '📥 导入 SSH 主机配置', importSshHostDesc: '选择 .tscfg 配置包文件以导入 SSH 主机配置', confirmImport: '📥 确认导入', @@ -1518,28 +1518,28 @@ i18n.registerLanguage('zh-CN', { deployKeyDesc: '将公钥 {keyId} 部署到远程服务器的 authorized_keys', targetHost: '目标主机', authPassword: '认证密码 (首次部署需要)', - deployHint: '💡 部署成功后,该主机将自动添加到「已部署主机」列表,之后可使用此密钥免密登录', + deployHint: '部署成功后,该主机将自动添加到「已部署主机」列表,之后可使用此密钥免密登录', startDeploy: '🚀 开始部署', // 撤销密钥弹窗 - revokeKeyTitle: '⚠️ 撤销公钥', + revokeKeyTitle: '撤销公钥', revokeKeyDesc: '从远程服务器移除公钥 {keyId}', - revokeWarning: '⚠️ 警告:撤销后将无法使用此密钥免密登录该服务器', - revokePublicKey: '⚠️ 撤销公钥', + revokeWarning: '警告:撤销后将无法使用此密钥免密登录该服务器', + revokePublicKey: '撤销公钥', // 主机指纹不匹配警告 - hostMismatchTitle: '⚠️ 安全警告:主机指纹不匹配!', + hostMismatchTitle: '安全警告:主机指纹不匹配!', hostMismatchDesc: '主机密钥已更改!这可能表明:', hostMismatchReason1: '服务器已重装系统', hostMismatchReason2: '存在中间人攻击', hostMismatchReason3: '服务器 IP 已分配给其他设备', hostMismatchAdvice: '建议:如果您确认服务器已重装或密钥已更新,可以点击"更新主机密钥"移除旧记录,然后重新连接以信任新密钥。', - updateHostKey: '🔄 更新主机密钥', - abortOperation: '❌ 中止操作', + updateHostKey: '更新主机密钥', + abortOperation: '中止操作', storedFingerprint: '存储的指纹', currentFingerprint: '当前指纹', // HTTPS 证书弹窗 genHttpsKeyPairTitle: '🔑 生成 HTTPS 密钥对', genHttpsKeyPairDesc: '为设备生成 ECDSA P-256 密钥对,用于 mTLS 身份验证', - existingKeyWarning: '⚠️ 已存在密钥对,继续将覆盖现有密钥!', + existingKeyWarning: '已存在密钥对,继续将覆盖现有密钥!', generate: '🔑 生成', csrTitle: '证书签名请求 (CSR)', deviceId: '设备 ID (CN)', @@ -1554,25 +1554,25 @@ i18n.registerLanguage('zh-CN', { installCaTitle: '安装 CA 证书链', installCaDesc: '粘贴根证书和中间证书(PEM 格式,可拼接多个)', caCertPem: 'CA 证书链 PEM', - deleteCredentialsTitle: '🗑️ 删除 HTTPS 凭证', + deleteCredentialsTitle: '删除 HTTPS 凭证', deleteCredentialsDesc: '此操作将删除密钥对和证书,删除后需要重新生成', - deleteCredentialsWarning: '⚠️ 警告:删除后设备将无法进行 mTLS 认证,直到重新配置', - confirmDelete: '⚠️ 确认删除', + deleteCredentialsWarning: '警告:删除后设备将无法进行 mTLS 认证,直到重新配置', + confirmDelete: '确认删除', viewCertTitle: '查看证书详情', close: '关闭', // 配置包验证 configId: '配置 ID', type: '类型', - sshCommandType: '📋 SSH 指令', + sshCommandType: 'SSH 指令', signerLabel: '签名者', official: '官方', noteLabel: '备注', autoLoadAfterRestart: '重启后自动加载', - configExistsWarning: '⚠️ 该配置已存在,导入将覆盖现有文件', + configExistsWarning: '该配置已存在,导入将覆盖现有文件', typeWithComment: '类型: {type} | 备注: {comment}', // 配置包 UI configPack: '配置包 (Config Pack)', - configPackDesc: '💡 配置包系统允许安全地加密和签名配置文件,用于设备间配置分发', + configPackDesc: '配置包系统允许安全地加密和签名配置文件,用于设备间配置分发', exportDeviceCert: '导出设备证书', importConfigPack: '导入配置包', exportConfigPack: '导出配置包', @@ -1619,7 +1619,7 @@ i18n.registerLanguage('zh-CN', { otaServer: 'OTA 服务器', saveToDevice: '保存到设备', save: '保存', - checkUpdate: '🔍 检查更新', + checkUpdate: '检查更新', preparing: '准备中...', valid: '有效', invalid: '无效', @@ -1747,12 +1747,12 @@ i18n.registerLanguage('zh-CN', { loadingOptions: '-- 加载中 --', sourceNoData: '该数据源暂无变量数据', configSourceFirst: '请先配置数据源并启用', - testRequesting: '🔄 正在请求...', - testSuccess: '✅ 连接成功', - testFailed: '❌ 请求失败', - testError: '❌ 错误', - testConnecting: '🔄 正在连接...', - testConnected: '✅ 连接成功,已收到数据', + testRequesting: '正在请求...', + testSuccess: '连接成功', + testFailed: '请求失败', + testError: '错误', + testConnecting: '正在连接...', + testConnected: '连接成功,已收到数据', noExtraParams: '此滤镜无额外参数', selectCmdHint: '选择要监视的指令(在 SSH 页面创建)', selectHostFirst: '-- 先选择主机 --', @@ -1765,7 +1765,7 @@ i18n.registerLanguage('zh-CN', { // SSH 命令引用预览 selectCommand: '选择命令', selectCommandHint: '选择已在 SSH 管理页面配置的命令', - commandDetails: '📋 命令详情', + commandDetails: '命令详情', previewHost: '主机', previewCommand: '命令', previewVariable: '变量', @@ -1839,9 +1839,9 @@ i18n.registerLanguage('zh-CN', { viewLog: '查看日志', stopProcess: '停止', // 日志查看 - logTitle: '📄 日志', + logTitle: '日志', loading: '加载中...', - stopTracking: '⏹️ 停止跟踪', + stopTracking: '停止跟踪', startTracking: '▶️ 开始跟踪', interval: '间隔', realTimeUpdating: '● 实时更新中', @@ -1954,7 +1954,7 @@ i18n.registerLanguage('zh-CN', { filterLabel: '滤镜', filterPulse: '💓 脉冲', filterBreathing: '💨 呼吸', - filterBlink: '💡 闪烁', + filterBlink: '闪烁', filterWave: '🌊 波浪', filterScanline: '📺 扫描线', filterGlitch: '⚡ 故障艺术', @@ -1964,13 +1964,13 @@ i18n.registerLanguage('zh-CN', { filterSepia: '🖼️ 怀旧', filterPosterize: '🎨 色阶分离', filterContrast: '🔆 对比度', - filterInvert: '🔄 反色', + filterInvert: '反色', filterGrayscale: '⬜ 灰度', // 变量动作 placeholder varValuePlaceholder: '支持表达式和变量引用', varValueHint: '示例: true, 123, ${other_var}', // 搜索 - searchVariablePlaceholder: '🔍 搜索变量...' + searchVariablePlaceholder: '搜索变量...' }, // 风扇控制 @@ -1988,13 +1988,13 @@ i18n.registerLanguage('zh-CN', { cleared: '已清空', noWidgets: '暂无组件', // 风扇卡片 - fanTitle: '🌀 风扇 {id}', + fanTitle: '风扇 {id}', modeOff: '关闭', modeManual: '手动', modeAuto: '自动', modeCurve: '曲线', speedAdjust: '转速调节', - editTempCurve: '⚙️ 编辑温度曲线', + editTempCurve: '编辑温度曲线', manualModeHint: '切换到手动模式后可调节', // 曲线管理模态框 curveManagement: '📈 风扇曲线管理', @@ -2005,7 +2005,7 @@ i18n.registerLanguage('zh-CN', { bound: '已绑定', selectVariableHint: '选择一个浮点类型变量作为温度源(如 agx.cpu_temp)', bind: '💾 绑定', - unbind: '🗑️ 解绑', + unbind: '解绑', tempSpeedCurve: '📊 温度-转速曲线', addPoint: '➕ 添加点', curveHint: '温度低于最小点时使用最小转速,高于最大点时使用最大转速', @@ -2019,7 +2019,7 @@ i18n.registerLanguage('zh-CN', { minInterval: '最小间隔 (ms)', intervalHint: '调速最小时间间隔', cancel: '取消', - applyCurve: '✅ 应用曲线', + applyCurve: '应用曲线', // 曲线点 tempPlaceholder: '温度', speedPlaceholder: '转速' @@ -2076,7 +2076,7 @@ i18n.registerLanguage('zh-CN', { presetLog: '日志流', // 管理界面 management: '数据组件管理', - panelSettings: '⚙️ 面板设置', + panelSettings: '面板设置', autoRefreshInterval: '自动刷新间隔', disabled: '禁用', second: '秒', @@ -2155,7 +2155,7 @@ i18n.registerLanguage('zh-CN', { quickColors: '快捷颜色', // 原有 on: '🔆 已开启', - off: '💡 已关闭', + off: '已关闭', defaultFont: '默认', quickActionsLoadFailed: '无法加载快捷操作', realTimeUpdating: '● 实时更新中', @@ -2295,14 +2295,14 @@ i18n.registerLanguage('zh-CN', { // PKI/安全配置 pkiPage: { - signatureVerified: '✅ 签名验证通过', - configImported: '✅ 配置包已导入', + signatureVerified: '签名验证通过', + configImported: '配置包已导入', savedTo: '保存至', - loadingFiles: '🔄 加载中...', - noConfigFiles: '📁 没有配置文件 (.json)', - loadError: '❌ 加载失败', + loadingFiles: '加载中...', + noConfigFiles: '没有配置文件 (.json)', + loadError: '加载失败', noTscfgFiles: '目录中没有 .tscfg 文件', - contentEmpty: '⚠️ 警告: 配置包内容为空', + contentEmpty: '警告: 配置包内容为空', // PKI 状态 statusNotInit: '未初始化', statusKeyGenerated: '密钥已生成,等待 CSR', @@ -2312,26 +2312,26 @@ i18n.registerLanguage('zh-CN', { statusError: '错误', statusLoadFailed: '加载失败', deviceType: '{type} 设备', - certValid: '✅ 有效', - certInvalid: '❌ 无效', + certValid: '有效', + certInvalid: '无效', expiredDays: '已过期 {days} 天', expiresInDays: '{days} 天后过期', remainingDays: '剩余 {days} 天', - generatingKeyPair: '🔄 正在生成密钥对...', - generatingCsr: '🔄 正在生成 CSR...', - installFailed: '❌ 安装失败', + generatingKeyPair: '正在生成密钥对...', + generatingCsr: '正在生成 CSR...', + installFailed: '安装失败', // 配置包 enterConfigName: '请输入配置名称', selectConfigFile: '请选择配置文件', pasteTargetCert: '请粘贴目标设备证书', invalidJsonConfig: '配置文件不是有效的 JSON', - generatingPack: '🔄 生成配置包中', - savedToDevice: '✅ 已保存到设备', - generationFailed: '❌ 生成失败', - verifying: '🔄 验证中...', - verifyFailed: '❌ 验证失败', - importing: '🔄 导入中...', - importFailed: '❌ 导入失败', + generatingPack: '生成配置包中', + savedToDevice: '已保存到设备', + generationFailed: '生成失败', + verifying: '验证中...', + verifyFailed: '验证失败', + importing: '导入中...', + importFailed: '导入失败', uploadOrPasteContent: '请上传文件或粘贴配置包内容' }, @@ -2342,10 +2342,10 @@ i18n.registerLanguage('zh-CN', { english: 'EN', notLoggedIn: '未登录', // 按钮状态 - stopTracking: '⏹️ 停止跟踪', + stopTracking: '停止跟踪', startTracking: '▶️ 开始跟踪', - testing: '⏳ 测试中...', - connecting: '⏳ 连接中...', + testing: '测试中...', + connecting: '连接中...', cancelling: '取消中...', // 提示 noOutput: '(无输出)', @@ -2358,9 +2358,9 @@ i18n.registerLanguage('zh-CN', { colorSettings: '颜色设置', turnOffLight: '关灯', // OTA - firmwareUpgradeComplete: '✅ 固件升级完成,准备升级 WebUI...', - allUpgradeComplete: '✅ 全部升级完成', - preparingUpgrade: '⏳ 准备升级...', + firmwareUpgradeComplete: '固件升级完成,准备升级 WebUI...', + allUpgradeComplete: '全部升级完成', + preparingUpgrade: '准备升级...', initializing: '正在初始化...', downloadingFromServer: '从 OTA 服务器下载', connectingServer: '正在连接服务器...', @@ -2368,11 +2368,11 @@ i18n.registerLanguage('zh-CN', { writingFlash: '正在写入 Flash(这可能需要1-2分钟)...', webuiSize: 'WebUI 大小', writingSpiffs: '正在写入 SPIFFS...', - upgradeFailed: '❌ 升级失败', + upgradeFailed: '升级失败', downloading: '下载中...', waitedSeconds: '已等待 {elapsed} 秒...', step2Webui: '[2/2] 开始升级 WebUI...', - firmwareOnlyComplete: '✅ 固件升级完成(WebUI 跳过)', + firmwareOnlyComplete: '固件升级完成(WebUI 跳过)', updateTime: '更新时间', // 系统 psramUnavailable: '不可用', @@ -2385,10 +2385,10 @@ i18n.registerLanguage('zh-CN', { displayStats: '显示 {filtered}/{total} 条', // 弹窗标题 newCommand: '➕ 新建指令', - editCommand: '✏️ 编辑指令', + editCommand: '编辑指令', commandVariables: '📊 指令变量', sourceVariables: '📊 {source} 变量', - editActionTemplate: '✏️ 编辑动作模板', + editActionTemplate: '编辑动作模板', // 动作 updateAction: '💾 更新', // 验证错误 @@ -2404,7 +2404,7 @@ i18n.registerLanguage('zh-CN', { configNotSet: '(未配置)', // 模式匹配结果 expectPatternConfigured: '未配置', - failPatternDetected: '⚠️ true (检测到错误)', + failPatternDetected: 'true (检测到错误)', extractedNone: '无', extracting: '提取中...', // 状态映射 @@ -2412,10 +2412,10 @@ i18n.registerLanguage('zh-CN', { statusFailed: '失败', statusRunning: '运行中', statusTimeout: '超时', - expectMatchYes: '✅ 是', - expectMatchNo: '❌ 否', - failMatchYes: '⚠️ 是', - failMatchNo: '✅ 否', + expectMatchYes: '是', + expectMatchNo: '否', + failMatchYes: '是', + failMatchNo: '否', // innerHTML 相关翻译键 loadFailed: '加载失败', noVariableData: '该指令暂无变量数据,请先执行一次', @@ -2471,10 +2471,10 @@ i18n.registerLanguage('zh-CN', { confirmRemoveHostLocal: '确定要从列表中移除主机 "{id}" 吗?\n\n注意:这只会移除本地记录,不会删除已部署到服务器上的公钥。如需撤销公钥,请点击「撤销」按钮。', confirmRemoveHostLocal2: '确定要从列表中移除主机 "{id}" 吗?\n\n注意:这只会移除本地记录,不会删除已部署到服务器上的公钥。如需撤销公钥,请使用密钥管理中的「撤销」功能。', confirmDeleteKey: '确定要删除密钥 "{id}" 吗?此操作不可撤销!', - confirmExportPrivateKey: '⚠️ 安全警告\n\n您正在导出私钥 "{id}"。\n\n私钥是高度敏感的安全凭证,请确保:\n• 不要在公共网络传输\n• 不要分享给他人\n• 安全存储在本地\n\n确定要继续吗?', + confirmExportPrivateKey: '安全警告\n\n您正在导出私钥 "{id}"。\n\n私钥是高度敏感的安全凭证,请确保:\n• 不要在公共网络传输\n• 不要分享给他人\n• 安全存储在本地\n\n确定要继续吗?', confirmRemoveKnownHost: '确定要移除主机 "{host}:{port}" 的记录吗?', confirmClearKnownHosts: '确定要清除所有已知主机记录吗?此操作不可撤销!', - confirmDeletePKI: '⚠️ 确定要删除所有 PKI 凭证吗?\n\n这将删除:\n• 私钥\n• 设备证书\n• CA 证书链\n\n此操作不可撤销!', + confirmDeletePKI: '确定要删除所有 PKI 凭证吗?\n\n这将删除:\n• 私钥\n• 设备证书\n• CA 证书链\n\n此操作不可撤销!', // Alert 对话框和其他提示 alertHostFingerprint: '主机: {host}:{port}\n类型: {type}\n指纹 (SHA256):\n{fingerprint}', alertEnterWsAddress: '请输入 WebSocket 地址', diff --git a/tools/ota_server/README.md b/tools/ota_server/README.md index 08689d7..5fefc79 100644 --- a/tools/ota_server/README.md +++ b/tools/ota_server/README.md @@ -46,6 +46,16 @@ http://<服务器IP>:57807 然后点击"检查更新"按钮。 +### 4. 发布前编译(让设备能检测到新固件) + +版本号仅在 **CMake 重新配置** 时更新。若只做增量编译(`idf.py build`),固件版本不变,设备上会显示「已是最新版本」。发布 OTA 前请用: + +```bash +./tools/build.sh --fresh +``` + +或 `rm -f build/CMakeCache.txt && idf.py build`,再用 `--build-dir build` 启动 OTA 服务器。 + ## API 端点 | 端点 | 方法 | 说明 |