seeder-st2110-components 1.7.12 → 1.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +1555 -1409
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1554 -1408
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { memo, useState, useCallback, useMemo, useEffect, useRef } from 'react';
|
|
2
|
-
import { Tooltip, Modal, App, Form, Input,
|
|
2
|
+
import { Tooltip, Modal, App, Alert, Form, Input, message, Dropdown, Spin, Divider, Typography, InputNumber, ConfigProvider, Badge, Switch, Select, List, Empty, Button, Space, Flex, Checkbox, Row, Col, Result } from 'antd';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { useWebSocket, useInterval } from 'ahooks';
|
|
5
5
|
import { LoadingOutlined, ExclamationCircleFilled, PlusOutlined } from '@ant-design/icons';
|
|
@@ -297,1280 +297,1343 @@ const StyledModal$2 = props => {
|
|
|
297
297
|
};
|
|
298
298
|
var StyledModal$3 = StyledModal$2;
|
|
299
299
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
authData,
|
|
305
|
-
title = 'Register License',
|
|
306
|
-
okText,
|
|
307
|
-
cancelText = 'Ignore',
|
|
308
|
-
width = 600
|
|
309
|
-
} = _ref;
|
|
310
|
-
const {
|
|
311
|
-
message
|
|
312
|
-
} = App.useApp();
|
|
313
|
-
const [code, setCode] = useState('');
|
|
314
|
-
const {
|
|
315
|
-
accredit_status: isActivated,
|
|
316
|
-
message: statusMessage = 'Unactivated',
|
|
317
|
-
bios_id: uuid,
|
|
318
|
-
expires_time: expiresTime
|
|
319
|
-
} = authData || {};
|
|
320
|
-
const handleOk = () => {
|
|
321
|
-
const trimmedCode = code.trim();
|
|
322
|
-
if (!trimmedCode) {
|
|
323
|
-
message.error('License key cannot be empty');
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
onOk(trimmedCode);
|
|
327
|
-
};
|
|
328
|
-
const statusAlert = isActivated ? /*#__PURE__*/jsx(Alert, {
|
|
329
|
-
message: "".concat(statusMessage, ", will expire on ").concat(expiresTime),
|
|
330
|
-
type: "success",
|
|
331
|
-
showIcon: true
|
|
332
|
-
}) : /*#__PURE__*/jsx(Alert, {
|
|
333
|
-
message: statusMessage,
|
|
334
|
-
type: "warning",
|
|
335
|
-
showIcon: true
|
|
336
|
-
});
|
|
337
|
-
const defaultOkText = isActivated ? "Reactivate" : "Activate Now";
|
|
338
|
-
return /*#__PURE__*/jsx(StyledModal$3, {
|
|
339
|
-
title: title,
|
|
340
|
-
width: width,
|
|
341
|
-
open: true,
|
|
342
|
-
onCancel: onCancel,
|
|
343
|
-
onOk: handleOk,
|
|
344
|
-
okText: okText || defaultOkText,
|
|
345
|
-
cancelText: cancelText,
|
|
346
|
-
cancelButtonProps: {
|
|
347
|
-
disabled: !isActivated
|
|
348
|
-
},
|
|
349
|
-
maskClosable: false,
|
|
350
|
-
closable: false,
|
|
351
|
-
children: /*#__PURE__*/jsxs(Form, {
|
|
352
|
-
name: "auth_form",
|
|
353
|
-
labelCol: {
|
|
354
|
-
span: 6
|
|
355
|
-
},
|
|
356
|
-
wrapperCol: {
|
|
357
|
-
span: 18
|
|
358
|
-
},
|
|
359
|
-
autoComplete: "off",
|
|
360
|
-
children: [/*#__PURE__*/jsx("div", {
|
|
361
|
-
style: {
|
|
362
|
-
marginBottom: 16
|
|
363
|
-
},
|
|
364
|
-
children: statusAlert
|
|
365
|
-
}), /*#__PURE__*/jsx(Form.Item, {
|
|
366
|
-
label: "Machine Code",
|
|
367
|
-
required: true,
|
|
368
|
-
children: /*#__PURE__*/jsx(Input, {
|
|
369
|
-
value: uuid,
|
|
370
|
-
readOnly: true
|
|
371
|
-
})
|
|
372
|
-
}), /*#__PURE__*/jsx(Form.Item, {
|
|
373
|
-
label: "License Key",
|
|
374
|
-
required: true,
|
|
375
|
-
children: /*#__PURE__*/jsx(Input.TextArea, {
|
|
376
|
-
value: code,
|
|
377
|
-
onChange: e => setCode(e.target.value),
|
|
378
|
-
autoSize: {
|
|
379
|
-
minRows: 6,
|
|
380
|
-
maxRows: 6
|
|
381
|
-
},
|
|
382
|
-
placeholder: "Enter your license key"
|
|
383
|
-
})
|
|
384
|
-
})]
|
|
385
|
-
})
|
|
386
|
-
});
|
|
387
|
-
};
|
|
388
|
-
var AuthorizationModal$1 = AuthorizationModal;
|
|
389
|
-
|
|
390
|
-
const DEFAULT_AUTH = {
|
|
391
|
-
accredit_status: false,
|
|
392
|
-
// 授权状态
|
|
393
|
-
bios_id: '',
|
|
394
|
-
// 主机id
|
|
395
|
-
message: 'Unactivated',
|
|
396
|
-
// 激活信息
|
|
397
|
-
expires_time: '' // 授权到期时间
|
|
398
|
-
};
|
|
399
|
-
const useAuth = options => {
|
|
400
|
-
const {
|
|
401
|
-
fetchAuthInfo,
|
|
402
|
-
authorize,
|
|
403
|
-
defaultAuthData = DEFAULT_AUTH,
|
|
404
|
-
autoShowModal = true
|
|
405
|
-
} = options || {};
|
|
406
|
-
const [messageApi, contextHolder] = message.useMessage();
|
|
407
|
-
const [showModal, setShowModal] = useState(false); // 默认隐藏
|
|
408
|
-
const [authData, setAuthData] = useState(defaultAuthData);
|
|
409
|
-
const [isRegistered, setIsRegistered] = useState(false);
|
|
410
|
-
const [loading, setLoading] = useState(false);
|
|
411
|
-
const openModal = useCallback(() => setShowModal(true), []);
|
|
412
|
-
const closeModal = useCallback(() => setShowModal(false), []);
|
|
413
|
-
useEffect(() => {
|
|
414
|
-
async function loadAuthInfo() {
|
|
415
|
-
try {
|
|
416
|
-
setLoading(true);
|
|
417
|
-
const result = await fetchAuthInfo();
|
|
418
|
-
if (result !== null && result !== void 0 && result.commands) {
|
|
419
|
-
const commands = result.commands;
|
|
420
|
-
setAuthData(commands);
|
|
421
|
-
setIsRegistered(commands.accredit_status);
|
|
422
|
-
if (autoShowModal) {
|
|
423
|
-
commands.accredit_status ? closeModal() : openModal();
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
} catch (error) {
|
|
427
|
-
console.error('Failed to fetch auth info:', error);
|
|
428
|
-
} finally {
|
|
429
|
-
setLoading(false);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
loadAuthInfo();
|
|
433
|
-
}, [fetchAuthInfo, autoShowModal, openModal, closeModal]);
|
|
434
|
-
const auth = async code => {
|
|
435
|
-
try {
|
|
436
|
-
setLoading(true);
|
|
437
|
-
const result = await authorize({
|
|
438
|
-
type: "accredit_command",
|
|
439
|
-
commands: {
|
|
440
|
-
id: "LICENSE",
|
|
441
|
-
license_data: code
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
if (result !== null && result !== void 0 && result.commands) {
|
|
445
|
-
const commands = result.commands;
|
|
446
|
-
// type accredit_message
|
|
447
|
-
if (commands !== null && commands !== void 0 && commands.accredit_status) {
|
|
448
|
-
setIsRegistered(true);
|
|
449
|
-
setAuthData(commands);
|
|
450
|
-
closeModal();
|
|
451
|
-
} else {
|
|
452
|
-
messageApi.error(commands.ciphertext_status || 'Authorization failed');
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
} catch (error) {
|
|
456
|
-
console.error('Authorization error:', error);
|
|
457
|
-
} finally {
|
|
458
|
-
setLoading(false);
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
const modal = showModal && /*#__PURE__*/jsxs(Fragment, {
|
|
462
|
-
children: [/*#__PURE__*/jsx(AuthorizationModal$1, {
|
|
463
|
-
onOk: auth,
|
|
464
|
-
onCancel: closeModal,
|
|
465
|
-
authData: authData
|
|
466
|
-
}), contextHolder]
|
|
467
|
-
});
|
|
468
|
-
return {
|
|
469
|
-
AuthModal: modal,
|
|
470
|
-
openAuthModal: openModal,
|
|
471
|
-
closeAuthModal: closeModal,
|
|
472
|
-
isRegistered,
|
|
473
|
-
authData,
|
|
474
|
-
loading
|
|
475
|
-
};
|
|
476
|
-
};
|
|
300
|
+
/**
|
|
301
|
+
* 国际化调试工具
|
|
302
|
+
* 在浏览器控制台运行 window.debugI18n() 查看当前国际化状态
|
|
303
|
+
*/
|
|
477
304
|
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
upgradeStatus,
|
|
486
|
-
// 状态轮询接口:(config) => Promise<response>
|
|
487
|
-
acceptFileTypes = "application/octet-stream",
|
|
488
|
-
uploadCompleteDelay = 3000,
|
|
489
|
-
statusPollingInterval = 1000
|
|
490
|
-
} = _ref;
|
|
491
|
-
const [isSpinning, setIsSpinning] = useState(false);
|
|
492
|
-
const [pollingInterval, setPollingInterval] = useState(undefined); // 间隔时间,当设置值为 undefined 时会停止计时器
|
|
493
|
-
const [currentStatus, setCurrentStatus] = useState('idle'); // 'idle' | 'uploading' | 'Upload complete, starting upgrade...' | 'upgrading'
|
|
494
|
-
const [uploadProgress, setUploadProgress] = useState(0);
|
|
495
|
-
const inputRef = useRef(null);
|
|
496
|
-
// 控制并发上传
|
|
497
|
-
const isUploadingRef = useRef(false);
|
|
498
|
-
// 标记组件是否已卸载
|
|
499
|
-
const isMountedRef = useRef(true);
|
|
305
|
+
const debugI18n = () => {
|
|
306
|
+
var _window$g_initialProp, _window$g_initialProp2, _window$g_initialProp3, _window$g_initialProp4, _window$g_initialProp5, _window$g_initialProp6;
|
|
307
|
+
if (typeof window === 'undefined') {
|
|
308
|
+
console.log('[i18n debug] Not in browser environment');
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
console.group('🌍 I18n Debug Information');
|
|
500
312
|
|
|
501
|
-
//
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
313
|
+
// 1. 当前语言环境
|
|
314
|
+
console.log('📍 Current Locale Sources:');
|
|
315
|
+
console.log(' - window.g_initialProps?.locale:', (_window$g_initialProp = window.g_initialProps) === null || _window$g_initialProp === void 0 ? void 0 : _window$g_initialProp.locale);
|
|
316
|
+
console.log(' - window.g_initialProps?.___g_initialPropsFromServer?.locale:', (_window$g_initialProp2 = window.g_initialProps) === null || _window$g_initialProp2 === void 0 || (_window$g_initialProp2 = _window$g_initialProp2.___g_initialPropsFromServer) === null || _window$g_initialProp2 === void 0 ? void 0 : _window$g_initialProp2.locale);
|
|
317
|
+
try {
|
|
318
|
+
console.log(' - localStorage.umi-locale:', localStorage.getItem('umi-locale'));
|
|
319
|
+
} catch (e) {
|
|
320
|
+
console.log(' - localStorage: not available');
|
|
321
|
+
}
|
|
322
|
+
console.log(' - window.__COMPONENT_LOCALE__:', window.__COMPONENT_LOCALE__);
|
|
506
323
|
|
|
507
|
-
//
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if (hasDownload && hasUpload) {
|
|
513
|
-
return menuItems;
|
|
514
|
-
}
|
|
515
|
-
const licenseIndex = menuItems.findIndex(item => item.key === 'license');
|
|
324
|
+
// 2. 语言包
|
|
325
|
+
console.log('\n📦 Available Message Sources:');
|
|
326
|
+
console.log(' - window.__COMPONENT_I18N_MESSAGES__:', window.__COMPONENT_I18N_MESSAGES__);
|
|
327
|
+
console.log(' - window.__PROJECT_I18N_MESSAGES__:', window.__PROJECT_I18N_MESSAGES__);
|
|
328
|
+
console.log(' - window.g_initialProps?.messages:', (_window$g_initialProp3 = window.g_initialProps) === null || _window$g_initialProp3 === void 0 ? void 0 : _window$g_initialProp3.messages);
|
|
516
329
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
});
|
|
528
|
-
return [...menuItems, ...itemsToAdd];
|
|
529
|
-
}
|
|
330
|
+
// 3. 合并后的语言包
|
|
331
|
+
const componentMessages = window.__COMPONENT_I18N_MESSAGES__ || {};
|
|
332
|
+
const projectMessages = window.__PROJECT_I18N_MESSAGES__ || {};
|
|
333
|
+
const umiMessages = ((_window$g_initialProp4 = window.g_initialProps) === null || _window$g_initialProp4 === void 0 ? void 0 : _window$g_initialProp4.messages) || {};
|
|
334
|
+
const allLocales = new Set([...Object.keys(componentMessages), ...Object.keys(projectMessages), ...Object.keys(umiMessages)]);
|
|
335
|
+
console.log('\n🔧 Merged Locales:', Array.from(allLocales));
|
|
336
|
+
allLocales.forEach(locale => {
|
|
337
|
+
const merged = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
|
|
338
|
+
console.log("\n \uD83D\uDCC4 ".concat(locale, " (").concat(Object.keys(merged).length, " keys):"), merged);
|
|
339
|
+
});
|
|
530
340
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
341
|
+
// 4. 测试几个关键的 key
|
|
342
|
+
console.log('\n🧪 Test Translation:');
|
|
343
|
+
const testKeys = ['networkSettings.title', 'button.ok', 'button.cancel', 'button.apply', 'button.close'];
|
|
344
|
+
const currentLocale = ((_window$g_initialProp5 = window.g_initialProps) === null || _window$g_initialProp5 === void 0 ? void 0 : _window$g_initialProp5.locale) || ((_window$g_initialProp6 = window.g_initialProps) === null || _window$g_initialProp6 === void 0 || (_window$g_initialProp6 = _window$g_initialProp6.___g_initialPropsFromServer) === null || _window$g_initialProp6 === void 0 ? void 0 : _window$g_initialProp6.locale) || localStorage.getItem('umi-locale') || 'zh-CN';
|
|
345
|
+
const allMessages = {};
|
|
346
|
+
allLocales.forEach(locale => {
|
|
347
|
+
allMessages[locale] = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
|
|
348
|
+
});
|
|
349
|
+
testKeys.forEach(key => {
|
|
350
|
+
var _allMessages$currentL, _allMessages$enUS;
|
|
351
|
+
const translation = ((_allMessages$currentL = allMessages[currentLocale]) === null || _allMessages$currentL === void 0 ? void 0 : _allMessages$currentL[key]) || ((_allMessages$enUS = allMessages['en-US']) === null || _allMessages$enUS === void 0 ? void 0 : _allMessages$enUS[key]) || '❌ NOT FOUND';
|
|
352
|
+
console.log(" - ".concat(key, ": ").concat(translation));
|
|
353
|
+
});
|
|
354
|
+
console.groupEnd();
|
|
355
|
+
};
|
|
536
356
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
357
|
+
// 自动在开发环境注册到 window
|
|
358
|
+
if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
|
|
359
|
+
window.debugI18n = debugI18n;
|
|
360
|
+
console.log('💡 I18n debug tool available. Run window.debugI18n() in console to check i18n status.');
|
|
361
|
+
}
|
|
543
362
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
363
|
+
/**
|
|
364
|
+
* seeder-st2110-components 组件库国际化 Hook
|
|
365
|
+
*
|
|
366
|
+
* 设计目标:
|
|
367
|
+
* 1. 不依赖特定的国际化库(react-intl, i18next 等)
|
|
368
|
+
* 2. 可以与主项目(Umi)的国际化集成
|
|
369
|
+
* 3. 支持简单的变量替换
|
|
370
|
+
* 4. 降级处理:如果没有翻译,显示 key 本身
|
|
371
|
+
*/
|
|
550
372
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
case 'download':
|
|
563
|
-
onDownload();
|
|
564
|
-
return;
|
|
565
|
-
case 'upload':
|
|
566
|
-
onUpload();
|
|
567
|
-
return;
|
|
568
|
-
default:
|
|
569
|
-
// 其他菜单项交给外部回调处理
|
|
570
|
-
if (onMenuClick) {
|
|
571
|
-
onMenuClick(key);
|
|
572
|
-
} else {
|
|
573
|
-
console.warn("Unknown menu key: ".concat(key, " and no onMenuClick provided"));
|
|
574
|
-
}
|
|
373
|
+
/**
|
|
374
|
+
* 获取当前语言环境
|
|
375
|
+
* 优先从 Umi 全局变量读取,其次使用默认值
|
|
376
|
+
*/
|
|
377
|
+
const getLocale = () => {
|
|
378
|
+
// 尝试从 Umi 获取语言设置
|
|
379
|
+
if (typeof window !== 'undefined') {
|
|
380
|
+
var _window$g_initialProp, _window$g_initialProp2;
|
|
381
|
+
// 方式 1:Umi 的 g_initialProps
|
|
382
|
+
if ((_window$g_initialProp = window.g_initialProps) !== null && _window$g_initialProp !== void 0 && _window$g_initialProp.locale) {
|
|
383
|
+
return window.g_initialProps.locale;
|
|
575
384
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
console.error('downloadFiles function is required for download operation');
|
|
580
|
-
message.error('Download functionality not configured');
|
|
581
|
-
return;
|
|
385
|
+
// 方式 2:Umi 的全局语言标记
|
|
386
|
+
if ((_window$g_initialProp2 = window.g_initialProps) !== null && _window$g_initialProp2 !== void 0 && (_window$g_initialProp2 = _window$g_initialProp2.___g_initialPropsFromServer) !== null && _window$g_initialProp2 !== void 0 && _window$g_initialProp2.locale) {
|
|
387
|
+
return window.g_initialProps.___g_initialPropsFromServer.locale;
|
|
582
388
|
}
|
|
389
|
+
// 方式 3:从 localStorage 读取(Umi 默认行为)
|
|
583
390
|
try {
|
|
584
|
-
const
|
|
585
|
-
if (
|
|
586
|
-
|
|
391
|
+
const storedLocale = localStorage.getItem('umi-locale');
|
|
392
|
+
if (storedLocale) {
|
|
393
|
+
return storedLocale;
|
|
587
394
|
}
|
|
395
|
+
} catch (e) {
|
|
396
|
+
// localStorage 不可用时忽略
|
|
397
|
+
}
|
|
398
|
+
// 方式 4:组件库自定义语言标记
|
|
399
|
+
if (window.__COMPONENT_LOCALE__) {
|
|
400
|
+
return window.__COMPONENT_LOCALE__;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// 默认语言
|
|
404
|
+
return 'zh-CN';
|
|
405
|
+
};
|
|
588
406
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
407
|
+
/**
|
|
408
|
+
* 获取语言包
|
|
409
|
+
* 优先从主项目读取,其次使用组件库自带的语言包
|
|
410
|
+
*/
|
|
411
|
+
const getMessages = () => {
|
|
412
|
+
if (typeof window !== 'undefined') {
|
|
413
|
+
var _window$g_initialProp3;
|
|
414
|
+
// 尝试从多个来源读取语言包
|
|
415
|
+
const messages = {};
|
|
592
416
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const filenameMatch = contentDisposition.match(/filename\s*=\s*"?([^";]+)"?/i);
|
|
596
|
-
if (filenameMatch !== null && filenameMatch !== void 0 && filenameMatch[1]) {
|
|
597
|
-
fileName = decodeURIComponent(filenameMatch[1]); // 处理编码后的文件名(如 %20 转空格)
|
|
598
|
-
}
|
|
599
|
-
}
|
|
417
|
+
// 1. 组件库注册的语言包
|
|
418
|
+
const componentMessages = window.__COMPONENT_I18N_MESSAGES__ || {};
|
|
600
419
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
type: 'application/octet-stream'
|
|
604
|
-
});
|
|
605
|
-
const url = window.URL.createObjectURL(blob);
|
|
420
|
+
// 2. 主项目的语言包
|
|
421
|
+
const projectMessages = window.__PROJECT_I18N_MESSAGES__ || {};
|
|
606
422
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
link.style.display = 'none';
|
|
610
|
-
link.href = url;
|
|
611
|
-
link.target = '_blank';
|
|
612
|
-
link.download = fileName;
|
|
613
|
-
document.body.appendChild(link);
|
|
614
|
-
link.click();
|
|
423
|
+
// 3. Umi 的语言包
|
|
424
|
+
const umiMessages = ((_window$g_initialProp3 = window.g_initialProps) === null || _window$g_initialProp3 === void 0 ? void 0 : _window$g_initialProp3.messages) || {};
|
|
615
425
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
426
|
+
// 合并语言包(组件库的优先级最高,其次是主项目,最后是 Umi)
|
|
427
|
+
const allLocales = new Set([...Object.keys(componentMessages), ...Object.keys(projectMessages), ...Object.keys(umiMessages)]);
|
|
428
|
+
allLocales.forEach(locale => {
|
|
429
|
+
messages[locale] = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
|
|
430
|
+
});
|
|
431
|
+
return messages;
|
|
432
|
+
}
|
|
433
|
+
return {};
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* 格式化消息
|
|
438
|
+
* @param {string} id - 国际化 key
|
|
439
|
+
* @param {object} values - 变量替换值
|
|
440
|
+
* @param {string} locale - 语言环境
|
|
441
|
+
* @param {object} messages - 语言包
|
|
442
|
+
*/
|
|
443
|
+
const formatMessage = function (_ref) {
|
|
444
|
+
var _messages$locale, _messages$enUS;
|
|
445
|
+
let {
|
|
446
|
+
id
|
|
447
|
+
} = _ref;
|
|
448
|
+
let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
449
|
+
let locale = arguments.length > 2 ? arguments[2] : undefined;
|
|
450
|
+
let messages = arguments.length > 3 ? arguments[3] : undefined;
|
|
451
|
+
const message = ((_messages$locale = messages[locale]) === null || _messages$locale === void 0 ? void 0 : _messages$locale[id]) || ((_messages$enUS = messages['en-US']) === null || _messages$enUS === void 0 ? void 0 : _messages$enUS[id]) || id;
|
|
452
|
+
|
|
453
|
+
// 支持变量替换 {min}, {max}, {value} 等
|
|
454
|
+
return message.replace(/\{(\w+)\}/g, (match, key) => {
|
|
455
|
+
return values[key] !== undefined ? values[key] : match;
|
|
456
|
+
});
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* 国际化 Hook
|
|
461
|
+
*
|
|
462
|
+
* @returns {{
|
|
463
|
+
* locale: string,
|
|
464
|
+
* formatMessage: function,
|
|
465
|
+
* messages: object
|
|
466
|
+
* }}
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* const intl = useIntl();
|
|
470
|
+
* const title = intl.formatMessage({ id: 'networkSettings.title' });
|
|
471
|
+
* const message = intl.formatMessage({ id: 'validation.minLength' }, { min: 3 });
|
|
472
|
+
*/
|
|
473
|
+
const useIntl = () => {
|
|
474
|
+
const locale = getLocale();
|
|
475
|
+
const messages = getMessages();
|
|
476
|
+
const formatMessageFn = function (_ref2) {
|
|
477
|
+
let {
|
|
478
|
+
id
|
|
479
|
+
} = _ref2;
|
|
480
|
+
let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
481
|
+
return formatMessage({
|
|
482
|
+
id
|
|
483
|
+
}, values, locale, messages);
|
|
623
484
|
};
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
485
|
+
return {
|
|
486
|
+
locale,
|
|
487
|
+
formatMessage: formatMessageFn,
|
|
488
|
+
messages
|
|
628
489
|
};
|
|
629
|
-
|
|
630
|
-
var _event$target$files;
|
|
631
|
-
if (isUploadingRef.current) return; // 防止重复上传
|
|
490
|
+
};
|
|
632
491
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
492
|
+
/**
|
|
493
|
+
* 设置语言环境(可选)
|
|
494
|
+
* 如果需要在运行时切换语言,可以调用此函数
|
|
495
|
+
*
|
|
496
|
+
* @param {string} locale - 语言代码,如 'zh-CN' 或 'en-US'
|
|
497
|
+
*/
|
|
498
|
+
const setLocale = locale => {
|
|
499
|
+
if (typeof window !== 'undefined') {
|
|
500
|
+
window.__COMPONENT_LOCALE__ = locale;
|
|
501
|
+
}
|
|
502
|
+
};
|
|
642
503
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
504
|
+
/**
|
|
505
|
+
* 注册语言包(可选)
|
|
506
|
+
* 如果需要在运行时注册语言包,可以调用此函数
|
|
507
|
+
*
|
|
508
|
+
* @param {string} locale - 语言代码
|
|
509
|
+
* @param {object} messages - 语言包对象
|
|
510
|
+
*/
|
|
511
|
+
const addMessages = (locale, messages) => {
|
|
512
|
+
if (typeof window !== 'undefined') {
|
|
513
|
+
if (!window.__COMPONENT_I18N_MESSAGES__) {
|
|
514
|
+
window.__COMPONENT_I18N_MESSAGES__ = {};
|
|
515
|
+
}
|
|
516
|
+
window.__COMPONENT_I18N_MESSAGES__[locale] = messages;
|
|
517
|
+
}
|
|
518
|
+
};
|
|
649
519
|
|
|
650
|
-
|
|
651
|
-
|
|
520
|
+
/**
|
|
521
|
+
* 初始化国际化
|
|
522
|
+
* 在组件库初始化时调用,注册默认语言包
|
|
523
|
+
*/
|
|
524
|
+
const initI18n = () => {
|
|
525
|
+
// 注册中文语言包
|
|
526
|
+
addMessages('zh-CN', {
|
|
527
|
+
'button.ok': '确定',
|
|
528
|
+
'button.cancel': '取消',
|
|
529
|
+
'button.save': '保存',
|
|
530
|
+
'button.delete': '删除',
|
|
531
|
+
'button.edit': '编辑',
|
|
532
|
+
'button.add': '添加',
|
|
533
|
+
'button.confirm': '确认',
|
|
534
|
+
'button.close': '关闭',
|
|
535
|
+
'button.apply': '应用',
|
|
536
|
+
'menu.networkSettings': '网络设置',
|
|
537
|
+
'menu.ptp': 'PTP',
|
|
538
|
+
'menu.nmos': 'NMOS',
|
|
539
|
+
'menu.preset': '预设',
|
|
540
|
+
'menu.license': '许可证'
|
|
541
|
+
// ... 其他默认翻译
|
|
542
|
+
});
|
|
652
543
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
544
|
+
// 注册英文语言包
|
|
545
|
+
addMessages('en-US', {
|
|
546
|
+
'button.ok': 'OK',
|
|
547
|
+
'button.cancel': 'Cancel',
|
|
548
|
+
'button.save': 'Save',
|
|
549
|
+
'button.delete': 'Delete',
|
|
550
|
+
'button.edit': 'Edit',
|
|
551
|
+
'button.add': 'Add',
|
|
552
|
+
'button.confirm': 'Confirm',
|
|
553
|
+
'button.close': 'Close',
|
|
554
|
+
'button.apply': 'Apply',
|
|
555
|
+
'menu.networkSettings': 'Network Settings',
|
|
556
|
+
'menu.ptp': 'PTP',
|
|
557
|
+
'menu.nmos': 'NMOS',
|
|
558
|
+
'menu.preset': 'Preset',
|
|
559
|
+
'menu.license': 'License'
|
|
560
|
+
// ... 其他默认翻译
|
|
561
|
+
});
|
|
562
|
+
};
|
|
663
563
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
564
|
+
const AuthorizationModal = _ref => {
|
|
565
|
+
let {
|
|
566
|
+
onCancel,
|
|
567
|
+
onOk,
|
|
568
|
+
authData,
|
|
569
|
+
title = 'license.title',
|
|
570
|
+
okText,
|
|
571
|
+
cancelText = 'license.button.ignore',
|
|
572
|
+
width = 600
|
|
573
|
+
} = _ref;
|
|
574
|
+
const intl = useIntl();
|
|
575
|
+
const {
|
|
576
|
+
message
|
|
577
|
+
} = App.useApp();
|
|
578
|
+
const [code, setCode] = useState('');
|
|
579
|
+
const {
|
|
580
|
+
accredit_status: isActivated,
|
|
581
|
+
message: statusMessage,
|
|
582
|
+
bios_id: uuid,
|
|
583
|
+
expires_time: expiresTime
|
|
584
|
+
} = authData || {};
|
|
674
585
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
586
|
+
// 服务端返回的状态文本映射到国际化 key
|
|
587
|
+
const getStatusMessageKey = msg => {
|
|
588
|
+
if (!msg) return 'license.status.unactivated';
|
|
678
589
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
if (!axios.isCancel(error)) {
|
|
688
|
-
console.error("Upload error:", error);
|
|
689
|
-
message.error('Upload failed');
|
|
690
|
-
}
|
|
691
|
-
cancelRequest();
|
|
692
|
-
} finally {
|
|
693
|
-
if (isMountedRef.current) {
|
|
694
|
-
isUploadingRef.current = false;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
590
|
+
// 根据服务端返回的英文文本映射
|
|
591
|
+
const statusMap = {
|
|
592
|
+
'Already activated': 'license.status.activated',
|
|
593
|
+
'Unactivated': 'license.status.unactivated',
|
|
594
|
+
'Expired': 'license.status.expired',
|
|
595
|
+
'Invalid': 'license.status.invalid'
|
|
596
|
+
};
|
|
597
|
+
return statusMap[msg] || 'license.status.unactivated';
|
|
697
598
|
};
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
});
|
|
705
|
-
|
|
706
|
-
const {
|
|
707
|
-
code,
|
|
708
|
-
message: statusMessage
|
|
709
|
-
} = response.data;
|
|
710
|
-
|
|
711
|
-
// 状态处理
|
|
712
|
-
switch (code) {
|
|
713
|
-
case 200:
|
|
714
|
-
// 升级成功
|
|
715
|
-
message.success(statusMessage, 2.5, () => {
|
|
716
|
-
if (isMountedRef.current) {
|
|
717
|
-
cancelRequest();
|
|
718
|
-
}
|
|
719
|
-
window.location.reload();
|
|
720
|
-
});
|
|
721
|
-
break;
|
|
722
|
-
case 201:
|
|
723
|
-
// 升级中 — 继续轮询
|
|
724
|
-
break;
|
|
725
|
-
case 202: // 升级失败
|
|
726
|
-
case 203:
|
|
727
|
-
// 升级异常
|
|
728
|
-
if (isMountedRef.current) {
|
|
729
|
-
message.error(statusMessage);
|
|
730
|
-
cancelRequest();
|
|
731
|
-
}
|
|
732
|
-
break;
|
|
733
|
-
default:
|
|
734
|
-
// 其他 code 如 500、400 等
|
|
735
|
-
if (isMountedRef.current) {
|
|
736
|
-
message.error(statusMessage || 'Upgrade process failed');
|
|
737
|
-
cancelRequest();
|
|
738
|
-
}
|
|
739
|
-
break;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
} catch (error) {
|
|
743
|
-
if (!isMountedRef.current) return;
|
|
744
|
-
if (!axios.isCancel(error)) {
|
|
745
|
-
console.error('Status check failed:', error);
|
|
746
|
-
}
|
|
599
|
+
const statusMessageKey = getStatusMessageKey(statusMessage);
|
|
600
|
+
const handleOk = () => {
|
|
601
|
+
const trimmedCode = code.trim();
|
|
602
|
+
if (!trimmedCode) {
|
|
603
|
+
message.error(intl.formatMessage({
|
|
604
|
+
id: 'license.validation.keyRequired'
|
|
605
|
+
}));
|
|
606
|
+
return;
|
|
747
607
|
}
|
|
608
|
+
onOk(trimmedCode);
|
|
748
609
|
};
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
610
|
+
const statusAlert = isActivated ? /*#__PURE__*/jsx(Alert, {
|
|
611
|
+
message: "".concat(intl.formatMessage({
|
|
612
|
+
id: statusMessageKey
|
|
613
|
+
}), ", ").concat(intl.formatMessage({
|
|
614
|
+
id: 'license.status.expiresOn'
|
|
615
|
+
}), " ").concat(expiresTime),
|
|
616
|
+
type: "success",
|
|
617
|
+
showIcon: true
|
|
618
|
+
}) : /*#__PURE__*/jsx(Alert, {
|
|
619
|
+
message: intl.formatMessage({
|
|
620
|
+
id: statusMessageKey
|
|
621
|
+
}),
|
|
622
|
+
type: "warning",
|
|
623
|
+
showIcon: true
|
|
624
|
+
});
|
|
625
|
+
const defaultOkText = isActivated ? intl.formatMessage({
|
|
626
|
+
id: 'license.button.reactivate'
|
|
627
|
+
}) : intl.formatMessage({
|
|
628
|
+
id: 'license.button.activate'
|
|
629
|
+
});
|
|
630
|
+
return /*#__PURE__*/jsx(StyledModal$3, {
|
|
631
|
+
title: intl.formatMessage({
|
|
632
|
+
id: title
|
|
633
|
+
}),
|
|
634
|
+
width: width,
|
|
635
|
+
open: true,
|
|
636
|
+
onCancel: onCancel,
|
|
637
|
+
onOk: handleOk,
|
|
638
|
+
okText: okText || defaultOkText,
|
|
639
|
+
cancelText: intl.formatMessage({
|
|
640
|
+
id: cancelText
|
|
641
|
+
}),
|
|
642
|
+
cancelButtonProps: {
|
|
643
|
+
disabled: !isActivated
|
|
644
|
+
},
|
|
645
|
+
maskClosable: false,
|
|
646
|
+
closable: false,
|
|
647
|
+
children: /*#__PURE__*/jsxs(Form, {
|
|
648
|
+
name: "auth_form",
|
|
649
|
+
labelCol: {
|
|
650
|
+
span: 6
|
|
780
651
|
},
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
})
|
|
787
|
-
})
|
|
788
|
-
}), /*#__PURE__*/jsx("input", {
|
|
789
|
-
ref: inputRef,
|
|
790
|
-
type: "file",
|
|
791
|
-
onChange: updatePackage,
|
|
792
|
-
className: "hidden",
|
|
793
|
-
accept: acceptFileTypes
|
|
794
|
-
}), /*#__PURE__*/jsx(Spin, {
|
|
795
|
-
spinning: isSpinning,
|
|
796
|
-
indicator: /*#__PURE__*/jsx(LoadingOutlined, {
|
|
652
|
+
wrapperCol: {
|
|
653
|
+
span: 18
|
|
654
|
+
},
|
|
655
|
+
autoComplete: "off",
|
|
656
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
797
657
|
style: {
|
|
798
|
-
|
|
658
|
+
marginBottom: 16
|
|
799
659
|
},
|
|
800
|
-
|
|
801
|
-
}),
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
660
|
+
children: statusAlert
|
|
661
|
+
}), /*#__PURE__*/jsx(Form.Item, {
|
|
662
|
+
label: intl.formatMessage({
|
|
663
|
+
id: 'license.machineCode'
|
|
664
|
+
}),
|
|
665
|
+
required: true,
|
|
666
|
+
children: /*#__PURE__*/jsx(Input, {
|
|
667
|
+
value: uuid,
|
|
668
|
+
readOnly: true
|
|
669
|
+
})
|
|
670
|
+
}), /*#__PURE__*/jsx(Form.Item, {
|
|
671
|
+
label: intl.formatMessage({
|
|
672
|
+
id: 'license.key'
|
|
673
|
+
}),
|
|
674
|
+
required: true,
|
|
675
|
+
children: /*#__PURE__*/jsx(Input.TextArea, {
|
|
676
|
+
value: code,
|
|
677
|
+
onChange: e => setCode(e.target.value),
|
|
678
|
+
autoSize: {
|
|
679
|
+
minRows: 6,
|
|
680
|
+
maxRows: 6
|
|
681
|
+
},
|
|
682
|
+
placeholder: intl.formatMessage({
|
|
683
|
+
id: 'license.placeholder.enterKey'
|
|
684
|
+
})
|
|
685
|
+
})
|
|
686
|
+
})]
|
|
687
|
+
})
|
|
806
688
|
});
|
|
807
|
-
return [upgradeElement];
|
|
808
689
|
};
|
|
809
|
-
var
|
|
810
|
-
|
|
811
|
-
const useSystemOperations = function () {
|
|
812
|
-
let {
|
|
813
|
-
onPowerOff,
|
|
814
|
-
onRestart,
|
|
815
|
-
confirmTitle = "Confirm",
|
|
816
|
-
cancelText = "No",
|
|
817
|
-
okText = "Yes",
|
|
818
|
-
run
|
|
819
|
-
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
820
|
-
const {
|
|
821
|
-
modal: AntdModal
|
|
822
|
-
} = App.useApp();
|
|
823
|
-
const doAction = useCallback(action => {
|
|
824
|
-
try {
|
|
825
|
-
AntdModal.confirm({
|
|
826
|
-
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
827
|
-
title: "".concat(confirmTitle, " ").concat(action, "?"),
|
|
828
|
-
cancelText,
|
|
829
|
-
okText,
|
|
830
|
-
onOk: () => {
|
|
831
|
-
if (action === 'poweroff' && onPowerOff) {
|
|
832
|
-
onPowerOff();
|
|
833
|
-
} else if (action === 'restart' && onRestart) {
|
|
834
|
-
onRestart();
|
|
835
|
-
}
|
|
690
|
+
var AuthorizationModal$1 = AuthorizationModal;
|
|
836
691
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
692
|
+
const DEFAULT_AUTH = {
|
|
693
|
+
accredit_status: false,
|
|
694
|
+
// 授权状态
|
|
695
|
+
bios_id: '',
|
|
696
|
+
// 主机id
|
|
697
|
+
message: 'Unactivated',
|
|
698
|
+
// 激活信息
|
|
699
|
+
expires_time: '' // 授权到期时间
|
|
700
|
+
};
|
|
701
|
+
const useAuth = options => {
|
|
702
|
+
const {
|
|
703
|
+
fetchAuthInfo,
|
|
704
|
+
authorize,
|
|
705
|
+
defaultAuthData = DEFAULT_AUTH,
|
|
706
|
+
autoShowModal = true
|
|
707
|
+
} = options || {};
|
|
708
|
+
const [messageApi, contextHolder] = message.useMessage();
|
|
709
|
+
const [showModal, setShowModal] = useState(false); // 默认隐藏
|
|
710
|
+
const [authData, setAuthData] = useState(defaultAuthData);
|
|
711
|
+
const [isRegistered, setIsRegistered] = useState(false);
|
|
712
|
+
const [loading, setLoading] = useState(false);
|
|
713
|
+
const openModal = useCallback(() => setShowModal(true), []);
|
|
714
|
+
const closeModal = useCallback(() => setShowModal(false), []);
|
|
715
|
+
useEffect(() => {
|
|
716
|
+
async function loadAuthInfo() {
|
|
717
|
+
try {
|
|
718
|
+
setLoading(true);
|
|
719
|
+
const result = await fetchAuthInfo();
|
|
720
|
+
if (result !== null && result !== void 0 && result.commands) {
|
|
721
|
+
const commands = result.commands;
|
|
722
|
+
setAuthData(commands);
|
|
723
|
+
setIsRegistered(commands.accredit_status);
|
|
724
|
+
if (autoShowModal) {
|
|
725
|
+
commands.accredit_status ? closeModal() : openModal();
|
|
840
726
|
}
|
|
841
727
|
}
|
|
728
|
+
} catch (error) {
|
|
729
|
+
console.error('Failed to fetch auth info:', error);
|
|
730
|
+
} finally {
|
|
731
|
+
setLoading(false);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
loadAuthInfo();
|
|
735
|
+
}, [fetchAuthInfo, autoShowModal, openModal, closeModal]);
|
|
736
|
+
const auth = async code => {
|
|
737
|
+
try {
|
|
738
|
+
setLoading(true);
|
|
739
|
+
const result = await authorize({
|
|
740
|
+
type: "accredit_command",
|
|
741
|
+
commands: {
|
|
742
|
+
id: "LICENSE",
|
|
743
|
+
license_data: code
|
|
744
|
+
}
|
|
842
745
|
});
|
|
746
|
+
if (result !== null && result !== void 0 && result.commands) {
|
|
747
|
+
const commands = result.commands;
|
|
748
|
+
// type accredit_message
|
|
749
|
+
if (commands !== null && commands !== void 0 && commands.accredit_status) {
|
|
750
|
+
setIsRegistered(true);
|
|
751
|
+
setAuthData(commands);
|
|
752
|
+
closeModal();
|
|
753
|
+
} else {
|
|
754
|
+
messageApi.error(commands.ciphertext_status || 'Authorization failed');
|
|
755
|
+
}
|
|
756
|
+
}
|
|
843
757
|
} catch (error) {
|
|
844
|
-
console.error(
|
|
758
|
+
console.error('Authorization error:', error);
|
|
759
|
+
} finally {
|
|
760
|
+
setLoading(false);
|
|
845
761
|
}
|
|
846
|
-
}
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
}
|
|
854
|
-
const handleMenuClick = useCallback(_ref => {
|
|
855
|
-
let {
|
|
856
|
-
key
|
|
857
|
-
} = _ref;
|
|
858
|
-
doAction(key);
|
|
859
|
-
}, [doAction]);
|
|
762
|
+
};
|
|
763
|
+
const modal = showModal && /*#__PURE__*/jsxs(Fragment, {
|
|
764
|
+
children: [/*#__PURE__*/jsx(AuthorizationModal$1, {
|
|
765
|
+
onOk: auth,
|
|
766
|
+
onCancel: closeModal,
|
|
767
|
+
authData: authData
|
|
768
|
+
}), contextHolder]
|
|
769
|
+
});
|
|
860
770
|
return {
|
|
861
|
-
|
|
862
|
-
|
|
771
|
+
AuthModal: modal,
|
|
772
|
+
openAuthModal: openModal,
|
|
773
|
+
closeAuthModal: closeModal,
|
|
774
|
+
isRegistered,
|
|
775
|
+
authData,
|
|
776
|
+
loading
|
|
863
777
|
};
|
|
864
778
|
};
|
|
865
|
-
var useSystemOperations$1 = useSystemOperations;
|
|
866
|
-
|
|
867
|
-
const usePageReload = () => {
|
|
868
|
-
const [reloading, setReloading] = useState(false);
|
|
869
|
-
const startReload = useCallback(function () {
|
|
870
|
-
let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 800;
|
|
871
|
-
if (reloading) return; // 防止重复触发
|
|
872
779
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
//
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
780
|
+
const useUpgrade = _ref => {
|
|
781
|
+
let {
|
|
782
|
+
menuItems = [],
|
|
783
|
+
onMenuClick,
|
|
784
|
+
downloadFiles,
|
|
785
|
+
upgradeExecute,
|
|
786
|
+
// 上传接口:(formData, config) => Promise<response>
|
|
787
|
+
upgradeStatus,
|
|
788
|
+
// 状态轮询接口:(config) => Promise<response>
|
|
789
|
+
acceptFileTypes = "application/octet-stream",
|
|
790
|
+
uploadCompleteDelay = 3000,
|
|
791
|
+
statusPollingInterval = 1000
|
|
792
|
+
} = _ref;
|
|
793
|
+
const intl = useIntl();
|
|
794
|
+
const [isSpinning, setIsSpinning] = useState(false);
|
|
795
|
+
const [pollingInterval, setPollingInterval] = useState(undefined); // 间隔时间,当设置值为 undefined 时会停止计时器
|
|
796
|
+
const [currentStatus, setCurrentStatus] = useState(intl.formatMessage({
|
|
797
|
+
id: 'upgrade.status.idle'
|
|
798
|
+
})); // 'idle' | 'uploading' | 'Upload complete, starting upgrade...' | 'upgrading'
|
|
799
|
+
const [uploadProgress, setUploadProgress] = useState(0);
|
|
800
|
+
const inputRef = useRef(null);
|
|
801
|
+
// 控制并发上传
|
|
802
|
+
const isUploadingRef = useRef(false);
|
|
803
|
+
// 标记组件是否已卸载
|
|
804
|
+
const isMountedRef = useRef(true);
|
|
885
805
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
return /*#__PURE__*/jsxs("div", {
|
|
892
|
-
style: {
|
|
893
|
-
position: 'fixed',
|
|
894
|
-
top: 0,
|
|
895
|
-
left: 0,
|
|
896
|
-
right: 0,
|
|
897
|
-
bottom: 0,
|
|
898
|
-
backgroundColor: '#282828',
|
|
899
|
-
display: 'flex',
|
|
900
|
-
flexDirection: 'column',
|
|
901
|
-
alignItems: 'center',
|
|
902
|
-
justifyContent: 'center',
|
|
903
|
-
zIndex: 999999,
|
|
904
|
-
color: 'white'
|
|
905
|
-
},
|
|
906
|
-
children: [/*#__PURE__*/jsx(Spin, {
|
|
907
|
-
size: "large"
|
|
908
|
-
}), /*#__PURE__*/jsx("div", {
|
|
909
|
-
style: {
|
|
910
|
-
marginTop: 20,
|
|
911
|
-
fontSize: 16
|
|
912
|
-
},
|
|
913
|
-
children: "Loading preset configuration..."
|
|
914
|
-
}), /*#__PURE__*/jsx("div", {
|
|
915
|
-
style: {
|
|
916
|
-
marginTop: 10,
|
|
917
|
-
fontSize: 12,
|
|
918
|
-
color: '#aaa'
|
|
919
|
-
},
|
|
920
|
-
children: "Page will refresh shortly"
|
|
921
|
-
})]
|
|
922
|
-
});
|
|
923
|
-
};
|
|
924
|
-
return {
|
|
925
|
-
startReload,
|
|
926
|
-
ReloadOverlay
|
|
927
|
-
};
|
|
928
|
-
};
|
|
929
|
-
var usePageReload$1 = usePageReload;
|
|
806
|
+
// 分别创建独立的取消令牌
|
|
807
|
+
const uploadCancelToken = useRef(axios.CancelToken.source());
|
|
808
|
+
const statusCancelToken = useRef(axios.CancelToken.source());
|
|
809
|
+
const showLoader = () => setIsSpinning(true);
|
|
810
|
+
const hideLoader = () => setIsSpinning(false);
|
|
930
811
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
812
|
+
// 构建菜单项 - 确保至少包含download和upload
|
|
813
|
+
// 构建菜单项 - 最终完美版本
|
|
814
|
+
const finalMenuItems = useMemo(() => {
|
|
815
|
+
const hasDownload = menuItems.some(item => item.key === 'download');
|
|
816
|
+
const hasUpload = menuItems.some(item => item.key === 'upload');
|
|
817
|
+
if (hasDownload && hasUpload) {
|
|
818
|
+
return menuItems;
|
|
819
|
+
}
|
|
820
|
+
const licenseIndex = menuItems.findIndex(item => item.key === 'license');
|
|
940
821
|
|
|
941
|
-
//
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
};
|
|
957
|
-
};
|
|
822
|
+
// 如果没有 license,在末尾添加
|
|
823
|
+
if (licenseIndex === -1) {
|
|
824
|
+
const itemsToAdd = [];
|
|
825
|
+
if (menuItems.length > 0) itemsToAdd.push({
|
|
826
|
+
type: 'divider'
|
|
827
|
+
});
|
|
828
|
+
// if (!hasDownload) itemsToAdd.push({ key: "download", label: intl.formatMessage({ id: 'upgrade.menu.download' }) });
|
|
829
|
+
if (!hasUpload) itemsToAdd.push({
|
|
830
|
+
key: "upload",
|
|
831
|
+
label: intl.formatMessage({
|
|
832
|
+
id: 'upgrade.menu.softwareUpdate'
|
|
833
|
+
})
|
|
834
|
+
});
|
|
835
|
+
return [...menuItems, ...itemsToAdd];
|
|
836
|
+
}
|
|
958
837
|
|
|
959
|
-
//
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
838
|
+
// 有 license,在 license 前面插入
|
|
839
|
+
const beforeLicense = menuItems.slice(0, licenseIndex);
|
|
840
|
+
const licenseItem = menuItems[licenseIndex];
|
|
841
|
+
const afterLicense = menuItems.slice(licenseIndex + 1);
|
|
842
|
+
const itemsToInsert = [];
|
|
964
843
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
day: '2-digit',
|
|
979
|
-
hour: '2-digit',
|
|
980
|
-
minute: '2-digit',
|
|
981
|
-
second: '2-digit',
|
|
982
|
-
hour12: false
|
|
844
|
+
// 1. 前面的分隔符(如果 beforeLicense 不为空且最后一项不是分隔符)
|
|
845
|
+
if (beforeLicense.length > 0 && beforeLicense[beforeLicense.length - 1].type !== 'divider') {
|
|
846
|
+
itemsToInsert.push({
|
|
847
|
+
type: 'divider'
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// 2. 添加缺少的项
|
|
852
|
+
// if (!hasDownload) itemsToInsert.push({ key: "download", label: intl.formatMessage({ id: 'upgrade.menu.download' }) });
|
|
853
|
+
if (!hasUpload) itemsToInsert.push({
|
|
854
|
+
key: "upload",
|
|
855
|
+
label: intl.formatMessage({
|
|
856
|
+
id: 'upgrade.menu.softwareUpdate'
|
|
983
857
|
})
|
|
984
|
-
};
|
|
985
|
-
logs.push(logEntry);
|
|
986
|
-
if (logs.length > maxLogs) logs.shift();
|
|
858
|
+
});
|
|
987
859
|
|
|
988
|
-
//
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
860
|
+
// 3. 后面的分隔符(与 license 之间)
|
|
861
|
+
itemsToInsert.push({
|
|
862
|
+
type: 'divider'
|
|
863
|
+
});
|
|
864
|
+
return [...beforeLicense, ...itemsToInsert, licenseItem, ...afterLicense];
|
|
865
|
+
}, [menuItems, intl]);
|
|
866
|
+
const handleMenuClick = _ref2 => {
|
|
867
|
+
let {
|
|
868
|
+
key
|
|
869
|
+
} = _ref2;
|
|
870
|
+
switch (key) {
|
|
871
|
+
case 'download':
|
|
872
|
+
onDownload();
|
|
873
|
+
return;
|
|
874
|
+
case 'upload':
|
|
875
|
+
onUpload();
|
|
876
|
+
return;
|
|
877
|
+
default:
|
|
878
|
+
// 其他菜单项交给外部回调处理
|
|
879
|
+
if (onMenuClick) {
|
|
880
|
+
onMenuClick(key);
|
|
881
|
+
} else {
|
|
882
|
+
console.warn("Unknown menu key: ".concat(key, " and no onMenuClick provided"));
|
|
883
|
+
}
|
|
1006
884
|
}
|
|
1007
|
-
return logEntry;
|
|
1008
885
|
};
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
});
|
|
886
|
+
const onDownload = async () => {
|
|
887
|
+
if (!downloadFiles) {
|
|
888
|
+
console.error('downloadFiles function is required for download operation');
|
|
889
|
+
message.error(intl.formatMessage({
|
|
890
|
+
id: 'upgrade.error.downloadNotConfigured'
|
|
891
|
+
}));
|
|
1015
892
|
return;
|
|
1016
893
|
}
|
|
1017
|
-
const logText = logs.map(entry => "[".concat(entry.timestampDisplay, "] [").concat(entry.level, "] ").concat(entry.message, "\n\u6570\u636E: ").concat(JSON.stringify(entry.data, null, 2))).join('\n' + '='.repeat(50) + '\n');
|
|
1018
|
-
const blob = new Blob([logText], {
|
|
1019
|
-
type: 'text/plain;charset=utf-8'
|
|
1020
|
-
});
|
|
1021
|
-
const blobUrl = URL.createObjectURL(blob);
|
|
1022
|
-
let hostname = 'unknown';
|
|
1023
|
-
let pathname = 'unknown';
|
|
1024
894
|
try {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
895
|
+
const res = await downloadFiles();
|
|
896
|
+
if (res.status !== 200) {
|
|
897
|
+
throw new Error("Unexpected status code: ".concat(res.status));
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// 默认值,兼容接口响应头没有定义文件名
|
|
901
|
+
let fileName = 'config.tar.gz';
|
|
902
|
+
const contentDisposition = res.headers['content-disposition'] || '';
|
|
903
|
+
|
|
904
|
+
// 获取接口响应的content-disposition字段值,以便获取到文件名
|
|
905
|
+
if (contentDisposition) {
|
|
906
|
+
const filenameMatch = contentDisposition.match(/filename\s*=\s*"?([^";]+)"?/i);
|
|
907
|
+
if (filenameMatch !== null && filenameMatch !== void 0 && filenameMatch[1]) {
|
|
908
|
+
fileName = decodeURIComponent(filenameMatch[1]); // 处理编码后的文件名(如 %20 转空格)
|
|
909
|
+
}
|
|
1029
910
|
}
|
|
911
|
+
|
|
912
|
+
// 创建并下载文件
|
|
913
|
+
const blob = new Blob([res.data], {
|
|
914
|
+
type: 'application/octet-stream'
|
|
915
|
+
});
|
|
916
|
+
const url = window.URL.createObjectURL(blob);
|
|
917
|
+
|
|
918
|
+
// 下面就是创建一个 a 标签并触发 click 事件,来下载该文件
|
|
919
|
+
const link = document.createElement('a');
|
|
920
|
+
link.style.display = 'none';
|
|
921
|
+
link.href = url;
|
|
922
|
+
link.target = '_blank';
|
|
923
|
+
link.download = fileName;
|
|
924
|
+
document.body.appendChild(link);
|
|
925
|
+
link.click();
|
|
926
|
+
|
|
927
|
+
// 最后移除 a 标签并删除创建的 ObjectURL 对象,防止内存泄漏
|
|
928
|
+
link.parentNode.removeChild(link);
|
|
929
|
+
window.URL.revokeObjectURL(url);
|
|
1030
930
|
} catch (error) {
|
|
1031
|
-
console.
|
|
931
|
+
console.error('Download failed:', error);
|
|
932
|
+
message.error(intl.formatMessage({
|
|
933
|
+
id: 'upgrade.error.downloadFailed'
|
|
934
|
+
}));
|
|
1032
935
|
}
|
|
1033
|
-
const readableTime = new Date().toLocaleString('zh-CN', {
|
|
1034
|
-
year: 'numeric',
|
|
1035
|
-
month: '2-digit',
|
|
1036
|
-
day: '2-digit',
|
|
1037
|
-
hour: '2-digit',
|
|
1038
|
-
minute: '2-digit',
|
|
1039
|
-
second: '2-digit',
|
|
1040
|
-
hour12: false
|
|
1041
|
-
}).replace(/[\/:\s]/g, '-');
|
|
1042
|
-
const filename = "".concat(filenamePrefix, "-").concat(hostname, "-").concat(pathname, "-").concat(readableTime, ".log");
|
|
1043
|
-
const a = document.createElement('a');
|
|
1044
|
-
a.href = blobUrl;
|
|
1045
|
-
a.download = filename;
|
|
1046
|
-
document.body.appendChild(a);
|
|
1047
|
-
a.click();
|
|
1048
|
-
document.body.removeChild(a);
|
|
1049
|
-
URL.revokeObjectURL(blobUrl);
|
|
1050
|
-
log('INFO', '日志文件已导出', {
|
|
1051
|
-
count: logs.length,
|
|
1052
|
-
filename
|
|
1053
|
-
});
|
|
1054
|
-
};
|
|
1055
|
-
const getLogStats = () => {
|
|
1056
|
-
var _logs;
|
|
1057
|
-
return {
|
|
1058
|
-
total: logs.length,
|
|
1059
|
-
errors: logs.filter(l => l.level === 'ERROR').length,
|
|
1060
|
-
warnings: logs.filter(l => l.level === 'WARN').length,
|
|
1061
|
-
info: logs.filter(l => l.level === 'INFO').length,
|
|
1062
|
-
lastTimestamp: (_logs = logs[logs.length - 1]) === null || _logs === void 0 ? void 0 : _logs.timestampDisplay
|
|
1063
|
-
};
|
|
1064
936
|
};
|
|
1065
|
-
const
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
return {
|
|
1070
|
-
log,
|
|
1071
|
-
exportLogs,
|
|
1072
|
-
getLogStats,
|
|
1073
|
-
clearLogs,
|
|
1074
|
-
logs
|
|
937
|
+
const onUpload = () => {
|
|
938
|
+
if (inputRef !== null && inputRef !== void 0 && inputRef.current && !isUploadingRef.current) {
|
|
939
|
+
inputRef.current.click();
|
|
940
|
+
}
|
|
1075
941
|
};
|
|
1076
|
-
|
|
942
|
+
const updatePackage = async event => {
|
|
943
|
+
var _event$target$files;
|
|
944
|
+
if (isUploadingRef.current) return; // 防止重复上传
|
|
1077
945
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
const lastHeartbeatTimeRef = useRef(Date.now());
|
|
1083
|
-
const isMountedRef = useRef(true);
|
|
1084
|
-
const configRef = useRef({
|
|
1085
|
-
interval: (config === null || config === void 0 ? void 0 : config.interval) || 20000,
|
|
1086
|
-
message: (config === null || config === void 0 ? void 0 : config.message) || {
|
|
1087
|
-
type: 'ping'
|
|
1088
|
-
}
|
|
1089
|
-
});
|
|
1090
|
-
const stateRef = useRef({
|
|
1091
|
-
sendMessage,
|
|
1092
|
-
readyState,
|
|
1093
|
-
enabled
|
|
1094
|
-
});
|
|
1095
|
-
useEffect(() => {
|
|
1096
|
-
configRef.current = {
|
|
1097
|
-
interval: (config === null || config === void 0 ? void 0 : config.interval) || 20000,
|
|
1098
|
-
message: (config === null || config === void 0 ? void 0 : config.message) || {
|
|
1099
|
-
type: 'ping'
|
|
1100
|
-
}
|
|
1101
|
-
};
|
|
1102
|
-
}, [config === null || config === void 0 ? void 0 : config.interval, config === null || config === void 0 ? void 0 : config.message]);
|
|
1103
|
-
useEffect(() => {
|
|
1104
|
-
stateRef.current = {
|
|
1105
|
-
sendMessage,
|
|
1106
|
-
readyState,
|
|
1107
|
-
enabled
|
|
1108
|
-
};
|
|
1109
|
-
}, [sendMessage, readyState, enabled]);
|
|
1110
|
-
useEffect(() => {
|
|
1111
|
-
return () => {
|
|
1112
|
-
isMountedRef.current = false;
|
|
1113
|
-
if (heartbeatTimerRef.current) {
|
|
1114
|
-
clearInterval(heartbeatTimerRef.current);
|
|
1115
|
-
}
|
|
1116
|
-
};
|
|
1117
|
-
}, []);
|
|
1118
|
-
const stopHeartbeat = useCallback(() => {
|
|
1119
|
-
if (heartbeatTimerRef.current) {
|
|
1120
|
-
clearInterval(heartbeatTimerRef.current);
|
|
1121
|
-
heartbeatTimerRef.current = null;
|
|
1122
|
-
if (stateRef.current.enabled) {
|
|
1123
|
-
logger.log('INFO', '停止心跳机制');
|
|
1124
|
-
}
|
|
946
|
+
const file = (_event$target$files = event.target.files) === null || _event$target$files === void 0 ? void 0 : _event$target$files[0];
|
|
947
|
+
if (!file || !upgradeExecute) {
|
|
948
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
949
|
+
return;
|
|
1125
950
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
logger.log('INFO', '启动心跳机制', {
|
|
1133
|
-
interval: currentConfig.interval
|
|
1134
|
-
});
|
|
1135
|
-
heartbeatTimerRef.current = setInterval(() => {
|
|
1136
|
-
// 检查组件是否挂载
|
|
1137
|
-
if (!isMountedRef.current || !heartbeatTimerRef.current) {
|
|
1138
|
-
return;
|
|
1139
|
-
}
|
|
951
|
+
isUploadingRef.current = true;
|
|
952
|
+
showLoader();
|
|
953
|
+
setCurrentStatus(intl.formatMessage({
|
|
954
|
+
id: 'upgrade.status.uploading'
|
|
955
|
+
}));
|
|
956
|
+
setUploadProgress(0);
|
|
1140
957
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
958
|
+
// 重置取消令牌
|
|
959
|
+
uploadCancelToken.current.cancel();
|
|
960
|
+
uploadCancelToken.current = axios.CancelToken.source();
|
|
961
|
+
try {
|
|
962
|
+
const formData = new FormData();
|
|
963
|
+
formData.append('file', file);
|
|
964
|
+
|
|
965
|
+
// 清除文件选择
|
|
966
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
967
|
+
|
|
968
|
+
// 上传后立即检查业务状态码
|
|
969
|
+
// upgradeExecute 使用 umi request 返回的数据是过滤过的
|
|
970
|
+
const response = await upgradeExecute(formData, {
|
|
971
|
+
onUploadProgress: progressEvent => {
|
|
972
|
+
if (!isMountedRef.current) return;
|
|
973
|
+
const percentCompleted = Math.round(progressEvent.loaded * 100 / progressEvent.total);
|
|
974
|
+
setUploadProgress(percentCompleted); // 更新进度状态
|
|
975
|
+
},
|
|
976
|
+
cancelToken: uploadCancelToken.current.token
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
// 检查业务 code
|
|
980
|
+
if ((response === null || response === void 0 ? void 0 : response.code) !== 200) {
|
|
981
|
+
// 即使上传成功,但如果服务器返回非 200,说明有问题
|
|
982
|
+
if (isMountedRef.current) {
|
|
983
|
+
const errorMsg = (response === null || response === void 0 ? void 0 : response.message) || intl.formatMessage({
|
|
984
|
+
id: 'upgrade.error.invalidFileFormat'
|
|
1156
985
|
});
|
|
986
|
+
message.error(errorMsg);
|
|
987
|
+
cancelRequest();
|
|
1157
988
|
}
|
|
989
|
+
return;
|
|
1158
990
|
}
|
|
1159
|
-
}, currentConfig.interval);
|
|
1160
|
-
}, [stopHeartbeat, logger]);
|
|
1161
991
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
992
|
+
// 上传成功,进入等待升级阶段
|
|
993
|
+
if (!isMountedRef.current) return;
|
|
994
|
+
setCurrentStatus(intl.formatMessage({
|
|
995
|
+
id: 'upgrade.status.uploadComplete'
|
|
996
|
+
}));
|
|
997
|
+
|
|
998
|
+
// 延迟后启动轮询
|
|
999
|
+
setTimeout(() => {
|
|
1000
|
+
if (!isMountedRef.current) return;
|
|
1001
|
+
setPollingInterval(statusPollingInterval);
|
|
1002
|
+
setCurrentStatus(intl.formatMessage({
|
|
1003
|
+
id: 'upgrade.status.upgrading'
|
|
1004
|
+
}));
|
|
1005
|
+
}, uploadCompleteDelay);
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
if (!isMountedRef.current) return;
|
|
1008
|
+
if (!axios.isCancel(error)) {
|
|
1009
|
+
console.error("Upload error:", error);
|
|
1010
|
+
message.error(intl.formatMessage({
|
|
1011
|
+
id: 'upgrade.error.uploadFailed'
|
|
1012
|
+
}));
|
|
1013
|
+
}
|
|
1014
|
+
cancelRequest();
|
|
1015
|
+
} finally {
|
|
1016
|
+
if (isMountedRef.current) {
|
|
1017
|
+
isUploadingRef.current = false;
|
|
1170
1018
|
}
|
|
1171
|
-
} else {
|
|
1172
|
-
stopHeartbeat();
|
|
1173
1019
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1020
|
+
};
|
|
1021
|
+
const fetchUpgradeStatus = async () => {
|
|
1022
|
+
if (!upgradeStatus || !isMountedRef.current) return;
|
|
1023
|
+
try {
|
|
1024
|
+
// upgradeStatus 使用 axios request 返回的数据没有过滤
|
|
1025
|
+
const response = await upgradeStatus({
|
|
1026
|
+
cancelToken: statusCancelToken.current.token
|
|
1027
|
+
});
|
|
1028
|
+
if ((response === null || response === void 0 ? void 0 : response.status) === 200) {
|
|
1029
|
+
const {
|
|
1030
|
+
code,
|
|
1031
|
+
message: statusMessage
|
|
1032
|
+
} = response.data;
|
|
1033
|
+
|
|
1034
|
+
// 状态处理
|
|
1035
|
+
switch (code) {
|
|
1036
|
+
case 200:
|
|
1037
|
+
// 升级成功
|
|
1038
|
+
message.success(statusMessage, 2.5, () => {
|
|
1039
|
+
if (isMountedRef.current) {
|
|
1040
|
+
cancelRequest();
|
|
1041
|
+
}
|
|
1042
|
+
window.location.reload();
|
|
1043
|
+
});
|
|
1044
|
+
break;
|
|
1045
|
+
case 201:
|
|
1046
|
+
// 升级中 — 继续轮询
|
|
1047
|
+
break;
|
|
1048
|
+
case 202: // 升级失败
|
|
1049
|
+
case 203:
|
|
1050
|
+
// 升级异常
|
|
1051
|
+
if (isMountedRef.current) {
|
|
1052
|
+
message.error(statusMessage);
|
|
1053
|
+
cancelRequest();
|
|
1054
|
+
}
|
|
1055
|
+
break;
|
|
1056
|
+
default:
|
|
1057
|
+
// 其他 code 如 500、400 等
|
|
1058
|
+
if (isMountedRef.current) {
|
|
1059
|
+
message.error(statusMessage || intl.formatMessage({
|
|
1060
|
+
id: 'upgrade.error.upgradeFailed'
|
|
1061
|
+
}));
|
|
1062
|
+
cancelRequest();
|
|
1063
|
+
}
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
} catch (error) {
|
|
1068
|
+
if (!isMountedRef.current) return;
|
|
1069
|
+
if (!axios.isCancel(error)) {
|
|
1070
|
+
console.error('Status check failed:', error);
|
|
1178
1071
|
}
|
|
1179
|
-
};
|
|
1180
|
-
}, [readyState, enabled, startHeartbeat, stopHeartbeat]);
|
|
1181
|
-
const heartbeatImpl = useMemo(() => {
|
|
1182
|
-
if (!enabled) {
|
|
1183
|
-
return {
|
|
1184
|
-
startHeartbeat: () => {},
|
|
1185
|
-
stopHeartbeat: () => {},
|
|
1186
|
-
getLastHeartbeatTime: () => null,
|
|
1187
|
-
isEnabled: false
|
|
1188
|
-
};
|
|
1189
1072
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1073
|
+
};
|
|
1074
|
+
const cancelRequest = () => {
|
|
1075
|
+
// 取消状态轮询
|
|
1076
|
+
uploadCancelToken.current.cancel('Operation canceled');
|
|
1077
|
+
statusCancelToken.current.cancel('Operation canceled');
|
|
1078
|
+
uploadCancelToken.current = axios.CancelToken.source();
|
|
1079
|
+
statusCancelToken.current = axios.CancelToken.source();
|
|
1080
|
+
|
|
1081
|
+
// 重置所有状态
|
|
1082
|
+
setPollingInterval(undefined);
|
|
1083
|
+
setCurrentStatus('idle');
|
|
1084
|
+
setUploadProgress(0);
|
|
1085
|
+
isUploadingRef.current = false;
|
|
1086
|
+
hideLoader();
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
// 轮询状态
|
|
1090
|
+
useInterval(fetchUpgradeStatus, pollingInterval);
|
|
1091
|
+
|
|
1092
|
+
// 组件卸载时清理
|
|
1093
|
+
useEffect(() => {
|
|
1094
|
+
return () => {
|
|
1095
|
+
isMountedRef.current = false;
|
|
1096
|
+
uploadCancelToken.current.cancel();
|
|
1097
|
+
statusCancelToken.current.cancel();
|
|
1195
1098
|
};
|
|
1196
|
-
}, [
|
|
1197
|
-
|
|
1099
|
+
}, []);
|
|
1100
|
+
const upgradeElement = /*#__PURE__*/jsxs("div", {
|
|
1101
|
+
children: [/*#__PURE__*/jsx(Dropdown, {
|
|
1102
|
+
menu: {
|
|
1103
|
+
items: finalMenuItems,
|
|
1104
|
+
onClick: handleMenuClick
|
|
1105
|
+
},
|
|
1106
|
+
trigger: ["hover"],
|
|
1107
|
+
children: /*#__PURE__*/jsx("a", {
|
|
1108
|
+
onClick: e => e.preventDefault(),
|
|
1109
|
+
children: /*#__PURE__*/jsx("i", {
|
|
1110
|
+
className: "seeder-iconfont seeder-icon-liebiao2 text-xl text-neutral-400"
|
|
1111
|
+
})
|
|
1112
|
+
})
|
|
1113
|
+
}), /*#__PURE__*/jsx("input", {
|
|
1114
|
+
ref: inputRef,
|
|
1115
|
+
type: "file",
|
|
1116
|
+
onChange: updatePackage,
|
|
1117
|
+
className: "hidden",
|
|
1118
|
+
accept: acceptFileTypes
|
|
1119
|
+
}), /*#__PURE__*/jsx(Spin, {
|
|
1120
|
+
spinning: isSpinning,
|
|
1121
|
+
indicator: /*#__PURE__*/jsx(LoadingOutlined, {
|
|
1122
|
+
style: {
|
|
1123
|
+
fontSize: 60
|
|
1124
|
+
},
|
|
1125
|
+
spin: true
|
|
1126
|
+
}),
|
|
1127
|
+
tip: currentStatus === intl.formatMessage({
|
|
1128
|
+
id: 'upgrade.status.uploading'
|
|
1129
|
+
}) ? "".concat(currentStatus, " ").concat(uploadProgress, "%") : currentStatus,
|
|
1130
|
+
size: "large",
|
|
1131
|
+
fullscreen: true
|
|
1132
|
+
})]
|
|
1133
|
+
});
|
|
1134
|
+
return [upgradeElement];
|
|
1198
1135
|
};
|
|
1199
|
-
|
|
1200
|
-
const {
|
|
1201
|
-
url,
|
|
1202
|
-
options = {},
|
|
1203
|
-
heartbeat: heartbeatConfig = false,
|
|
1204
|
-
enableLog = true
|
|
1205
|
-
} = config;
|
|
1206
|
-
const [isConnected, setIsConnected] = useState(false);
|
|
1136
|
+
var useUpgrade$1 = useUpgrade;
|
|
1207
1137
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
var _options$onOpen;
|
|
1218
|
-
logger.log('INFO', 'WebSocket 连接成功', {
|
|
1219
|
-
url,
|
|
1220
|
-
readyState: getReadyStateText(1),
|
|
1221
|
-
// 连接成功时 readyState 为 1
|
|
1222
|
-
eventCode: event === null || event === void 0 ? void 0 : event.code
|
|
1223
|
-
});
|
|
1224
|
-
setIsConnected(true);
|
|
1225
|
-
(_options$onOpen = options.onOpen) === null || _options$onOpen === void 0 || _options$onOpen.call(options, event);
|
|
1226
|
-
},
|
|
1227
|
-
onError: error => {
|
|
1228
|
-
var _options$onError;
|
|
1229
|
-
logger.log('ERROR', 'WebSocket 连接错误', {
|
|
1230
|
-
url,
|
|
1231
|
-
error: error.message,
|
|
1232
|
-
errorType: error.type,
|
|
1233
|
-
readyState: getReadyStateText(3) // 错误时 readyState 为 3
|
|
1234
|
-
});
|
|
1235
|
-
setIsConnected(false);
|
|
1236
|
-
(_options$onError = options.onError) === null || _options$onError === void 0 || _options$onError.call(options, error);
|
|
1237
|
-
},
|
|
1238
|
-
onClose: event => {
|
|
1239
|
-
var _options$onClose;
|
|
1240
|
-
logger.log('WARN', 'WebSocket 连接断开', {
|
|
1241
|
-
url,
|
|
1242
|
-
code: event.code,
|
|
1243
|
-
reason: event.reason,
|
|
1244
|
-
wasClean: event.wasClean,
|
|
1245
|
-
readyState: getReadyStateText(3) // 关闭时 readyState 为 3
|
|
1246
|
-
});
|
|
1247
|
-
setIsConnected(false);
|
|
1248
|
-
(_options$onClose = options.onClose) === null || _options$onClose === void 0 || _options$onClose.call(options, event);
|
|
1249
|
-
},
|
|
1250
|
-
onReconnect: count => {
|
|
1251
|
-
var _options$onReconnect;
|
|
1252
|
-
logger.log('INFO', '尝试重新连接', {
|
|
1253
|
-
url,
|
|
1254
|
-
attempt: count,
|
|
1255
|
-
maxAttempts: options.reconnectLimit || 10
|
|
1256
|
-
});
|
|
1257
|
-
(_options$onReconnect = options.onReconnect) === null || _options$onReconnect === void 0 || _options$onReconnect.call(options, count);
|
|
1258
|
-
}
|
|
1259
|
-
}), [url, options, logger]);
|
|
1138
|
+
const useSystemOperations = function () {
|
|
1139
|
+
let {
|
|
1140
|
+
onPowerOff,
|
|
1141
|
+
onRestart,
|
|
1142
|
+
confirmTitle = "Confirm",
|
|
1143
|
+
cancelText = "No",
|
|
1144
|
+
okText = "Yes",
|
|
1145
|
+
run
|
|
1146
|
+
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1260
1147
|
const {
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1148
|
+
modal: AntdModal
|
|
1149
|
+
} = App.useApp();
|
|
1150
|
+
const doAction = useCallback(action => {
|
|
1151
|
+
try {
|
|
1152
|
+
AntdModal.confirm({
|
|
1153
|
+
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
1154
|
+
title: "".concat(confirmTitle, " ").concat(action, "?"),
|
|
1155
|
+
cancelText,
|
|
1156
|
+
okText,
|
|
1157
|
+
onOk: () => {
|
|
1158
|
+
if (action === 'poweroff' && onPowerOff) {
|
|
1159
|
+
onPowerOff();
|
|
1160
|
+
} else if (action === 'restart' && onRestart) {
|
|
1161
|
+
onRestart();
|
|
1162
|
+
}
|
|
1270
1163
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1164
|
+
// Call the run callback after successful operation
|
|
1165
|
+
if (typeof run === 'function') {
|
|
1166
|
+
run();
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
console.error("".concat(action.toUpperCase(), " ERROR: "), error);
|
|
1278
1172
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1173
|
+
}, [AntdModal, confirmTitle, cancelText, okText, onPowerOff, onRestart]);
|
|
1174
|
+
const getMenuItems = useCallback(() => [{
|
|
1175
|
+
key: "poweroff",
|
|
1176
|
+
label: "Power Off"
|
|
1177
|
+
}, {
|
|
1178
|
+
key: "restart",
|
|
1179
|
+
label: "Restart"
|
|
1180
|
+
}], []);
|
|
1181
|
+
const handleMenuClick = useCallback(_ref => {
|
|
1182
|
+
let {
|
|
1183
|
+
key
|
|
1184
|
+
} = _ref;
|
|
1185
|
+
doAction(key);
|
|
1186
|
+
}, [doAction]);
|
|
1292
1187
|
return {
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
sendMessage,
|
|
1296
|
-
connect,
|
|
1297
|
-
disconnect,
|
|
1298
|
-
isConnected,
|
|
1299
|
-
readyStateText: getReadyStateText(readyState),
|
|
1300
|
-
// 心跳功能
|
|
1301
|
-
heartbeat,
|
|
1302
|
-
// 日志功能
|
|
1303
|
-
logger: enableLog ? loggerMethods : null
|
|
1188
|
+
menuItems: getMenuItems(),
|
|
1189
|
+
handleMenuClick
|
|
1304
1190
|
};
|
|
1305
1191
|
};
|
|
1306
|
-
var
|
|
1192
|
+
var useSystemOperations$1 = useSystemOperations;
|
|
1307
1193
|
|
|
1308
|
-
|
|
1309
|
-
|
|
1194
|
+
const usePageReload = () => {
|
|
1195
|
+
const [reloading, setReloading] = useState(false);
|
|
1196
|
+
const startReload = useCallback(function () {
|
|
1197
|
+
let delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 800;
|
|
1198
|
+
if (reloading) return; // 防止重复触发
|
|
1310
1199
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
* 在浏览器控制台运行 window.debugI18n() 查看当前国际化状态
|
|
1314
|
-
*/
|
|
1200
|
+
// 显示遮罩
|
|
1201
|
+
setReloading(true);
|
|
1315
1202
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
return;
|
|
1321
|
-
}
|
|
1322
|
-
console.group('🌍 I18n Debug Information');
|
|
1203
|
+
// 设置背景色
|
|
1204
|
+
document.body.style.backgroundColor = '#282828';
|
|
1205
|
+
document.body.style.transition = 'background-color 0.1s';
|
|
1206
|
+
document.body.offsetHeight;
|
|
1323
1207
|
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
try {
|
|
1329
|
-
console.log(' - localStorage.umi-locale:', localStorage.getItem('umi-locale'));
|
|
1330
|
-
} catch (e) {
|
|
1331
|
-
console.log(' - localStorage: not available');
|
|
1332
|
-
}
|
|
1333
|
-
console.log(' - window.__COMPONENT_LOCALE__:', window.__COMPONENT_LOCALE__);
|
|
1208
|
+
// 延迟刷新
|
|
1209
|
+
const timer = setTimeout(() => {
|
|
1210
|
+
window.location.reload();
|
|
1211
|
+
}, delay);
|
|
1334
1212
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1213
|
+
// 清理函数(防止内存泄漏)
|
|
1214
|
+
return () => clearTimeout(timer);
|
|
1215
|
+
}, [reloading]);
|
|
1216
|
+
const ReloadOverlay = () => {
|
|
1217
|
+
if (!reloading) return null;
|
|
1218
|
+
return /*#__PURE__*/jsxs("div", {
|
|
1219
|
+
style: {
|
|
1220
|
+
position: 'fixed',
|
|
1221
|
+
top: 0,
|
|
1222
|
+
left: 0,
|
|
1223
|
+
right: 0,
|
|
1224
|
+
bottom: 0,
|
|
1225
|
+
backgroundColor: '#282828',
|
|
1226
|
+
display: 'flex',
|
|
1227
|
+
flexDirection: 'column',
|
|
1228
|
+
alignItems: 'center',
|
|
1229
|
+
justifyContent: 'center',
|
|
1230
|
+
zIndex: 999999,
|
|
1231
|
+
color: 'white'
|
|
1232
|
+
},
|
|
1233
|
+
children: [/*#__PURE__*/jsx(Spin, {
|
|
1234
|
+
size: "large"
|
|
1235
|
+
}), /*#__PURE__*/jsx("div", {
|
|
1236
|
+
style: {
|
|
1237
|
+
marginTop: 20,
|
|
1238
|
+
fontSize: 16
|
|
1239
|
+
},
|
|
1240
|
+
children: "Loading preset configuration..."
|
|
1241
|
+
}), /*#__PURE__*/jsx("div", {
|
|
1242
|
+
style: {
|
|
1243
|
+
marginTop: 10,
|
|
1244
|
+
fontSize: 12,
|
|
1245
|
+
color: '#aaa'
|
|
1246
|
+
},
|
|
1247
|
+
children: "Page will refresh shortly"
|
|
1248
|
+
})]
|
|
1249
|
+
});
|
|
1250
|
+
};
|
|
1251
|
+
return {
|
|
1252
|
+
startReload,
|
|
1253
|
+
ReloadOverlay
|
|
1254
|
+
};
|
|
1255
|
+
};
|
|
1256
|
+
var usePageReload$1 = usePageReload;
|
|
1340
1257
|
|
|
1341
|
-
|
|
1342
|
-
const
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
});
|
|
1258
|
+
const getReadyStateText = state => {
|
|
1259
|
+
const states = {
|
|
1260
|
+
0: 'CONNECTING',
|
|
1261
|
+
1: 'OPEN',
|
|
1262
|
+
2: 'CLOSING',
|
|
1263
|
+
3: 'CLOSED'
|
|
1264
|
+
};
|
|
1265
|
+
return states[state] || "UNKNOWN(".concat(state, ")");
|
|
1266
|
+
};
|
|
1351
1267
|
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1268
|
+
// 创建空日志器
|
|
1269
|
+
const createDummyLogger = () => {
|
|
1270
|
+
const dummyFn = () => {};
|
|
1271
|
+
return {
|
|
1272
|
+
log: dummyFn,
|
|
1273
|
+
exportLogs: dummyFn,
|
|
1274
|
+
getLogStats: () => ({
|
|
1275
|
+
total: 0,
|
|
1276
|
+
errors: 0,
|
|
1277
|
+
warnings: 0,
|
|
1278
|
+
info: 0,
|
|
1279
|
+
lastTimestamp: null
|
|
1280
|
+
}),
|
|
1281
|
+
clearLogs: dummyFn,
|
|
1282
|
+
logs: []
|
|
1283
|
+
};
|
|
1366
1284
|
};
|
|
1367
1285
|
|
|
1368
|
-
//
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1286
|
+
// 创建通用的日志器
|
|
1287
|
+
const createGlobalLogger = function () {
|
|
1288
|
+
let webSocketUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
1289
|
+
const logs = [];
|
|
1290
|
+
const maxLogs = 1000;
|
|
1373
1291
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1292
|
+
// 判断是否为开发环境
|
|
1293
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
1294
|
+
const log = function (level, message) {
|
|
1295
|
+
let data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
1296
|
+
const timestamp = new Date().toISOString();
|
|
1297
|
+
const logEntry = {
|
|
1298
|
+
timestamp,
|
|
1299
|
+
level,
|
|
1300
|
+
message,
|
|
1301
|
+
data,
|
|
1302
|
+
timestampDisplay: new Date().toLocaleString('zh-CN', {
|
|
1303
|
+
year: 'numeric',
|
|
1304
|
+
month: '2-digit',
|
|
1305
|
+
day: '2-digit',
|
|
1306
|
+
hour: '2-digit',
|
|
1307
|
+
minute: '2-digit',
|
|
1308
|
+
second: '2-digit',
|
|
1309
|
+
hour12: false
|
|
1310
|
+
})
|
|
1311
|
+
};
|
|
1312
|
+
logs.push(logEntry);
|
|
1313
|
+
if (logs.length > maxLogs) logs.shift();
|
|
1383
1314
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1315
|
+
// 只在开发环境下输出到控制台
|
|
1316
|
+
if (isDevelopment) {
|
|
1317
|
+
const consoleMessage = "[".concat(logEntry.timestampDisplay, "] [WebSocket] [").concat(level, "] ").concat(message);
|
|
1318
|
+
const consoleArgs = [consoleMessage];
|
|
1319
|
+
if (Object.keys(data).length > 0) consoleArgs.push(data);
|
|
1320
|
+
switch (level) {
|
|
1321
|
+
case 'ERROR':
|
|
1322
|
+
console.error(...consoleArgs);
|
|
1323
|
+
break;
|
|
1324
|
+
case 'WARN':
|
|
1325
|
+
console.warn(...consoleArgs);
|
|
1326
|
+
break;
|
|
1327
|
+
case 'INFO':
|
|
1328
|
+
console.info(...consoleArgs);
|
|
1329
|
+
break;
|
|
1330
|
+
default:
|
|
1331
|
+
console.log(...consoleArgs);
|
|
1332
|
+
}
|
|
1395
1333
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1334
|
+
return logEntry;
|
|
1335
|
+
};
|
|
1336
|
+
const exportLogs = function () {
|
|
1337
|
+
let filenamePrefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'websocket';
|
|
1338
|
+
if (logs.length === 0) {
|
|
1339
|
+
log('WARN', '没有日志可导出', {
|
|
1340
|
+
filenamePrefix
|
|
1341
|
+
});
|
|
1342
|
+
return;
|
|
1399
1343
|
}
|
|
1400
|
-
|
|
1344
|
+
const logText = logs.map(entry => "[".concat(entry.timestampDisplay, "] [").concat(entry.level, "] ").concat(entry.message, "\n\u6570\u636E: ").concat(JSON.stringify(entry.data, null, 2))).join('\n' + '='.repeat(50) + '\n');
|
|
1345
|
+
const blob = new Blob([logText], {
|
|
1346
|
+
type: 'text/plain;charset=utf-8'
|
|
1347
|
+
});
|
|
1348
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
1349
|
+
let hostname = 'unknown';
|
|
1350
|
+
let pathname = 'unknown';
|
|
1401
1351
|
try {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1352
|
+
if (webSocketUrl) {
|
|
1353
|
+
const urlObj = new URL(webSocketUrl.replace(/^ws/, 'http'));
|
|
1354
|
+
hostname = urlObj.hostname.replace(/\./g, '-');
|
|
1355
|
+
pathname = urlObj.pathname.replace(/\//g, '-').replace(/^-|-$/g, '') || 'root';
|
|
1405
1356
|
}
|
|
1406
|
-
} catch (
|
|
1407
|
-
|
|
1408
|
-
}
|
|
1409
|
-
// 方式 4:组件库自定义语言标记
|
|
1410
|
-
if (window.__COMPONENT_LOCALE__) {
|
|
1411
|
-
return window.__COMPONENT_LOCALE__;
|
|
1357
|
+
} catch (error) {
|
|
1358
|
+
console.warn('无法解析WebSocket URL:', error);
|
|
1412
1359
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
const
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
// 3. Umi 的语言包
|
|
1435
|
-
const umiMessages = ((_window$g_initialProp3 = window.g_initialProps) === null || _window$g_initialProp3 === void 0 ? void 0 : _window$g_initialProp3.messages) || {};
|
|
1436
|
-
|
|
1437
|
-
// 合并语言包(组件库的优先级最高,其次是主项目,最后是 Umi)
|
|
1438
|
-
const allLocales = new Set([...Object.keys(componentMessages), ...Object.keys(projectMessages), ...Object.keys(umiMessages)]);
|
|
1439
|
-
allLocales.forEach(locale => {
|
|
1440
|
-
messages[locale] = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
|
|
1360
|
+
const readableTime = new Date().toLocaleString('zh-CN', {
|
|
1361
|
+
year: 'numeric',
|
|
1362
|
+
month: '2-digit',
|
|
1363
|
+
day: '2-digit',
|
|
1364
|
+
hour: '2-digit',
|
|
1365
|
+
minute: '2-digit',
|
|
1366
|
+
second: '2-digit',
|
|
1367
|
+
hour12: false
|
|
1368
|
+
}).replace(/[\/:\s]/g, '-');
|
|
1369
|
+
const filename = "".concat(filenamePrefix, "-").concat(hostname, "-").concat(pathname, "-").concat(readableTime, ".log");
|
|
1370
|
+
const a = document.createElement('a');
|
|
1371
|
+
a.href = blobUrl;
|
|
1372
|
+
a.download = filename;
|
|
1373
|
+
document.body.appendChild(a);
|
|
1374
|
+
a.click();
|
|
1375
|
+
document.body.removeChild(a);
|
|
1376
|
+
URL.revokeObjectURL(blobUrl);
|
|
1377
|
+
log('INFO', '日志文件已导出', {
|
|
1378
|
+
count: logs.length,
|
|
1379
|
+
filename
|
|
1441
1380
|
});
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
let {
|
|
1457
|
-
id
|
|
1458
|
-
} = _ref;
|
|
1459
|
-
let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1460
|
-
let locale = arguments.length > 2 ? arguments[2] : undefined;
|
|
1461
|
-
let messages = arguments.length > 3 ? arguments[3] : undefined;
|
|
1462
|
-
const message = ((_messages$locale = messages[locale]) === null || _messages$locale === void 0 ? void 0 : _messages$locale[id]) || ((_messages$enUS = messages['en-US']) === null || _messages$enUS === void 0 ? void 0 : _messages$enUS[id]) || id;
|
|
1463
|
-
|
|
1464
|
-
// 支持变量替换 {min}, {max}, {value} 等
|
|
1465
|
-
return message.replace(/\{(\w+)\}/g, (match, key) => {
|
|
1466
|
-
return values[key] !== undefined ? values[key] : match;
|
|
1467
|
-
});
|
|
1468
|
-
};
|
|
1469
|
-
|
|
1470
|
-
/**
|
|
1471
|
-
* 国际化 Hook
|
|
1472
|
-
*
|
|
1473
|
-
* @returns {{
|
|
1474
|
-
* locale: string,
|
|
1475
|
-
* formatMessage: function,
|
|
1476
|
-
* messages: object
|
|
1477
|
-
* }}
|
|
1478
|
-
*
|
|
1479
|
-
* @example
|
|
1480
|
-
* const intl = useIntl();
|
|
1481
|
-
* const title = intl.formatMessage({ id: 'networkSettings.title' });
|
|
1482
|
-
* const message = intl.formatMessage({ id: 'validation.minLength' }, { min: 3 });
|
|
1483
|
-
*/
|
|
1484
|
-
const useIntl = () => {
|
|
1485
|
-
const locale = getLocale();
|
|
1486
|
-
const messages = getMessages();
|
|
1487
|
-
const formatMessageFn = function (_ref2) {
|
|
1488
|
-
let {
|
|
1489
|
-
id
|
|
1490
|
-
} = _ref2;
|
|
1491
|
-
let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1492
|
-
return formatMessage({
|
|
1493
|
-
id
|
|
1494
|
-
}, values, locale, messages);
|
|
1381
|
+
};
|
|
1382
|
+
const getLogStats = () => {
|
|
1383
|
+
var _logs;
|
|
1384
|
+
return {
|
|
1385
|
+
total: logs.length,
|
|
1386
|
+
errors: logs.filter(l => l.level === 'ERROR').length,
|
|
1387
|
+
warnings: logs.filter(l => l.level === 'WARN').length,
|
|
1388
|
+
info: logs.filter(l => l.level === 'INFO').length,
|
|
1389
|
+
lastTimestamp: (_logs = logs[logs.length - 1]) === null || _logs === void 0 ? void 0 : _logs.timestampDisplay
|
|
1390
|
+
};
|
|
1391
|
+
};
|
|
1392
|
+
const clearLogs = () => {
|
|
1393
|
+
logs.length = 0;
|
|
1394
|
+
log('INFO', '日志已清空');
|
|
1495
1395
|
};
|
|
1496
1396
|
return {
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1397
|
+
log,
|
|
1398
|
+
exportLogs,
|
|
1399
|
+
getLogStats,
|
|
1400
|
+
clearLogs,
|
|
1401
|
+
logs
|
|
1500
1402
|
};
|
|
1501
1403
|
};
|
|
1502
1404
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
const
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
}
|
|
1405
|
+
// 心跳管理器
|
|
1406
|
+
const useHeartbeat = function (sendMessage, readyState, config, logger) {
|
|
1407
|
+
let enabled = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
|
|
1408
|
+
const heartbeatTimerRef = useRef(null);
|
|
1409
|
+
const lastHeartbeatTimeRef = useRef(Date.now());
|
|
1410
|
+
const isMountedRef = useRef(true);
|
|
1411
|
+
const configRef = useRef({
|
|
1412
|
+
interval: (config === null || config === void 0 ? void 0 : config.interval) || 20000,
|
|
1413
|
+
message: (config === null || config === void 0 ? void 0 : config.message) || {
|
|
1414
|
+
type: 'ping'
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
const stateRef = useRef({
|
|
1418
|
+
sendMessage,
|
|
1419
|
+
readyState,
|
|
1420
|
+
enabled
|
|
1421
|
+
});
|
|
1422
|
+
useEffect(() => {
|
|
1423
|
+
configRef.current = {
|
|
1424
|
+
interval: (config === null || config === void 0 ? void 0 : config.interval) || 20000,
|
|
1425
|
+
message: (config === null || config === void 0 ? void 0 : config.message) || {
|
|
1426
|
+
type: 'ping'
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
}, [config === null || config === void 0 ? void 0 : config.interval, config === null || config === void 0 ? void 0 : config.message]);
|
|
1430
|
+
useEffect(() => {
|
|
1431
|
+
stateRef.current = {
|
|
1432
|
+
sendMessage,
|
|
1433
|
+
readyState,
|
|
1434
|
+
enabled
|
|
1435
|
+
};
|
|
1436
|
+
}, [sendMessage, readyState, enabled]);
|
|
1437
|
+
useEffect(() => {
|
|
1438
|
+
return () => {
|
|
1439
|
+
isMountedRef.current = false;
|
|
1440
|
+
if (heartbeatTimerRef.current) {
|
|
1441
|
+
clearInterval(heartbeatTimerRef.current);
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
}, []);
|
|
1445
|
+
const stopHeartbeat = useCallback(() => {
|
|
1446
|
+
if (heartbeatTimerRef.current) {
|
|
1447
|
+
clearInterval(heartbeatTimerRef.current);
|
|
1448
|
+
heartbeatTimerRef.current = null;
|
|
1449
|
+
if (stateRef.current.enabled) {
|
|
1450
|
+
logger.log('INFO', '停止心跳机制');
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}, [logger]);
|
|
1454
|
+
const startHeartbeat = useCallback(() => {
|
|
1455
|
+
stopHeartbeat();
|
|
1456
|
+
const currentState = stateRef.current;
|
|
1457
|
+
const currentConfig = configRef.current;
|
|
1458
|
+
if (!currentState.enabled) return;
|
|
1459
|
+
logger.log('INFO', '启动心跳机制', {
|
|
1460
|
+
interval: currentConfig.interval
|
|
1461
|
+
});
|
|
1462
|
+
heartbeatTimerRef.current = setInterval(() => {
|
|
1463
|
+
// 检查组件是否挂载
|
|
1464
|
+
if (!isMountedRef.current || !heartbeatTimerRef.current) {
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
// 目的: 总是获取最新的值
|
|
1469
|
+
const latestState = stateRef.current;
|
|
1470
|
+
const latestConfig = configRef.current;
|
|
1471
|
+
if (latestState.sendMessage && latestState.readyState === 1) {
|
|
1472
|
+
try {
|
|
1473
|
+
latestState.sendMessage(JSON.stringify(latestConfig.message));
|
|
1474
|
+
lastHeartbeatTimeRef.current = Date.now();
|
|
1475
|
+
logger.log('DEBUG', '发送心跳包', {
|
|
1476
|
+
timeSinceLastHeartbeat: Date.now() - lastHeartbeatTimeRef.current,
|
|
1477
|
+
readyState: getReadyStateText(latestState.readyState)
|
|
1478
|
+
});
|
|
1479
|
+
} catch (error) {
|
|
1480
|
+
logger.log('ERROR', '发送心跳失败', {
|
|
1481
|
+
error: error.message,
|
|
1482
|
+
readyState: getReadyStateText(latestState.readyState)
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}, currentConfig.interval);
|
|
1487
|
+
}, [stopHeartbeat, logger]);
|
|
1514
1488
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1489
|
+
// 自动管理心跳
|
|
1490
|
+
useEffect(() => {
|
|
1491
|
+
const currentState = stateRef.current;
|
|
1492
|
+
if (currentState.enabled) {
|
|
1493
|
+
if (currentState.readyState === 1) {
|
|
1494
|
+
startHeartbeat();
|
|
1495
|
+
} else {
|
|
1496
|
+
stopHeartbeat();
|
|
1497
|
+
}
|
|
1498
|
+
} else {
|
|
1499
|
+
stopHeartbeat();
|
|
1526
1500
|
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1501
|
+
return () => {
|
|
1502
|
+
if (heartbeatTimerRef.current) {
|
|
1503
|
+
clearInterval(heartbeatTimerRef.current);
|
|
1504
|
+
heartbeatTimerRef.current = null;
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
}, [readyState, enabled, startHeartbeat, stopHeartbeat]);
|
|
1508
|
+
const heartbeatImpl = useMemo(() => {
|
|
1509
|
+
if (!enabled) {
|
|
1510
|
+
return {
|
|
1511
|
+
startHeartbeat: () => {},
|
|
1512
|
+
stopHeartbeat: () => {},
|
|
1513
|
+
getLastHeartbeatTime: () => null,
|
|
1514
|
+
isEnabled: false
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
return {
|
|
1518
|
+
startHeartbeat,
|
|
1519
|
+
stopHeartbeat,
|
|
1520
|
+
getLastHeartbeatTime: () => lastHeartbeatTimeRef.current,
|
|
1521
|
+
isEnabled: true
|
|
1522
|
+
};
|
|
1523
|
+
}, [enabled, startHeartbeat, stopHeartbeat]);
|
|
1524
|
+
return heartbeatImpl;
|
|
1529
1525
|
};
|
|
1526
|
+
const useWebSocketWithFeatures = config => {
|
|
1527
|
+
const {
|
|
1528
|
+
url,
|
|
1529
|
+
options = {},
|
|
1530
|
+
heartbeat: heartbeatConfig = false,
|
|
1531
|
+
enableLog = true
|
|
1532
|
+
} = config;
|
|
1533
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
1530
1534
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1535
|
+
// 创建 logger 实例
|
|
1536
|
+
const logger = useMemo(() => {
|
|
1537
|
+
if (enableLog) {
|
|
1538
|
+
return createGlobalLogger(url);
|
|
1539
|
+
}
|
|
1540
|
+
return createDummyLogger();
|
|
1541
|
+
}, [url, enableLog]);
|
|
1542
|
+
const websocketOptions = useMemo(() => _objectSpread2$1(_objectSpread2$1({}, options), {}, {
|
|
1543
|
+
onOpen: event => {
|
|
1544
|
+
var _options$onOpen;
|
|
1545
|
+
logger.log('INFO', 'WebSocket 连接成功', {
|
|
1546
|
+
url,
|
|
1547
|
+
readyState: getReadyStateText(1),
|
|
1548
|
+
// 连接成功时 readyState 为 1
|
|
1549
|
+
eventCode: event === null || event === void 0 ? void 0 : event.code
|
|
1550
|
+
});
|
|
1551
|
+
setIsConnected(true);
|
|
1552
|
+
(_options$onOpen = options.onOpen) === null || _options$onOpen === void 0 || _options$onOpen.call(options, event);
|
|
1553
|
+
},
|
|
1554
|
+
onError: error => {
|
|
1555
|
+
var _options$onError;
|
|
1556
|
+
logger.log('ERROR', 'WebSocket 连接错误', {
|
|
1557
|
+
url,
|
|
1558
|
+
error: error.message,
|
|
1559
|
+
errorType: error.type,
|
|
1560
|
+
readyState: getReadyStateText(3) // 错误时 readyState 为 3
|
|
1561
|
+
});
|
|
1562
|
+
setIsConnected(false);
|
|
1563
|
+
(_options$onError = options.onError) === null || _options$onError === void 0 || _options$onError.call(options, error);
|
|
1564
|
+
},
|
|
1565
|
+
onClose: event => {
|
|
1566
|
+
var _options$onClose;
|
|
1567
|
+
logger.log('WARN', 'WebSocket 连接断开', {
|
|
1568
|
+
url,
|
|
1569
|
+
code: event.code,
|
|
1570
|
+
reason: event.reason,
|
|
1571
|
+
wasClean: event.wasClean,
|
|
1572
|
+
readyState: getReadyStateText(3) // 关闭时 readyState 为 3
|
|
1573
|
+
});
|
|
1574
|
+
setIsConnected(false);
|
|
1575
|
+
(_options$onClose = options.onClose) === null || _options$onClose === void 0 || _options$onClose.call(options, event);
|
|
1576
|
+
},
|
|
1577
|
+
onReconnect: count => {
|
|
1578
|
+
var _options$onReconnect;
|
|
1579
|
+
logger.log('INFO', '尝试重新连接', {
|
|
1580
|
+
url,
|
|
1581
|
+
attempt: count,
|
|
1582
|
+
maxAttempts: options.reconnectLimit || 10
|
|
1583
|
+
});
|
|
1584
|
+
(_options$onReconnect = options.onReconnect) === null || _options$onReconnect === void 0 || _options$onReconnect.call(options, count);
|
|
1585
|
+
}
|
|
1586
|
+
}), [url, options, logger]);
|
|
1587
|
+
const {
|
|
1588
|
+
latestMessage,
|
|
1589
|
+
readyState,
|
|
1590
|
+
sendMessage,
|
|
1591
|
+
connect,
|
|
1592
|
+
disconnect
|
|
1593
|
+
} = useWebSocket(url, websocketOptions);
|
|
1594
|
+
const heartbeatOptions = useMemo(() => heartbeatConfig === true ? {} : heartbeatConfig, [heartbeatConfig]);
|
|
1595
|
+
const heartbeatEnabled = useMemo(() => heartbeatConfig !== false, [heartbeatConfig]);
|
|
1596
|
+
const heartbeat = useHeartbeat(sendMessage, readyState, heartbeatOptions, logger, heartbeatEnabled);
|
|
1554
1597
|
|
|
1555
|
-
//
|
|
1556
|
-
|
|
1557
|
-
'
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1598
|
+
// 在全局暴露日志方法
|
|
1599
|
+
useEffect(() => {
|
|
1600
|
+
if (typeof window !== 'undefined' && enableLog) {
|
|
1601
|
+
// 生成唯一的键名:基于URL进行base64编码
|
|
1602
|
+
const key = "exportWebSocketLogs_".concat(btoa(url));
|
|
1603
|
+
// 在window对象上添加方法
|
|
1604
|
+
window[key] = () => logger.exportLogs();
|
|
1605
|
+
}
|
|
1606
|
+
return () => {
|
|
1607
|
+
if (typeof window !== 'undefined' && enableLog) {
|
|
1608
|
+
const key = "exportWebSocketLogs_".concat(btoa(url));
|
|
1609
|
+
delete window[key];
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
}, [url, enableLog, logger]);
|
|
1613
|
+
const loggerMethods = useMemo(() => ({
|
|
1614
|
+
log: (level, message, data) => logger.log(level, message, data),
|
|
1615
|
+
exportLogs: () => logger.exportLogs(),
|
|
1616
|
+
getLogStats: () => logger.getLogStats(),
|
|
1617
|
+
clearLogs: () => logger.clearLogs()
|
|
1618
|
+
}), [logger]);
|
|
1619
|
+
return {
|
|
1620
|
+
latestMessage,
|
|
1621
|
+
readyState,
|
|
1622
|
+
sendMessage,
|
|
1623
|
+
connect,
|
|
1624
|
+
disconnect,
|
|
1625
|
+
isConnected,
|
|
1626
|
+
readyStateText: getReadyStateText(readyState),
|
|
1627
|
+
// 心跳功能
|
|
1628
|
+
heartbeat,
|
|
1629
|
+
// 日志功能
|
|
1630
|
+
logger: enableLog ? loggerMethods : null
|
|
1631
|
+
};
|
|
1573
1632
|
};
|
|
1633
|
+
var useWebSocketWithFeatures$1 = useWebSocketWithFeatures;
|
|
1634
|
+
|
|
1635
|
+
// 在控制台中直接查看所有可用的导出方法 Object.keys(window).filter(key => key.startsWith('exportWebSocketLogs_'))
|
|
1636
|
+
// 导出特定连接的日志 window['exportWebSocketLogs_d3M6Ly8xOTIuMTY4LjEyMy4yMDQvd3MvZHZyL3ZpZGVvX3N0YXR1c19jaGFuZ2U=']();
|
|
1574
1637
|
|
|
1575
1638
|
// seeder-st2110-components 组件库中文语言包
|
|
1576
1639
|
var zhCN = {
|
|
@@ -1607,97 +1670,92 @@ var zhCN = {
|
|
|
1607
1670
|
'networkSettings.saveSuccess': '保存成功',
|
|
1608
1671
|
// PTP Modal
|
|
1609
1672
|
'ptp.title': 'PTP 设置',
|
|
1610
|
-
'ptp.enable': '启用 PTP',
|
|
1611
|
-
'ptp.status': 'PTP 状态',
|
|
1612
1673
|
'ptp.domainNumber': '域编号',
|
|
1613
1674
|
'ptp.priority1': '优先级 1',
|
|
1614
1675
|
'ptp.priority2': '优先级 2',
|
|
1615
1676
|
'ptp.clockClass': '时钟等级',
|
|
1677
|
+
'ptp.clockClass.atomic': '原子钟 ({value})',
|
|
1678
|
+
'ptp.clockClass.gps': 'GPS ({value})',
|
|
1679
|
+
'ptp.clockClass.slaveOnly': '仅从时钟 ({value})',
|
|
1616
1680
|
'ptp.clockAccuracy': '时钟精度',
|
|
1617
|
-
'ptp.offsetScaledLogVariance': '
|
|
1618
|
-
'ptp.
|
|
1619
|
-
'ptp.
|
|
1620
|
-
'ptp.
|
|
1621
|
-
'ptp.
|
|
1681
|
+
'ptp.offsetScaledLogVariance': '时钟稳定性',
|
|
1682
|
+
'ptp.portIdentity': '端口标识',
|
|
1683
|
+
'ptp.grandmasterIdentity': '主时钟标识',
|
|
1684
|
+
'ptp.utcOffset': 'UTC 偏移量',
|
|
1685
|
+
'ptp.connected': '已连接',
|
|
1686
|
+
'ptp.disconnected': '未连接',
|
|
1622
1687
|
'ptp.locked': '已锁定',
|
|
1623
1688
|
'ptp.unlocked': '未锁定',
|
|
1624
|
-
'ptp.saveSuccess': '
|
|
1625
|
-
'ptp.saveFailed': 'PTP 设置保存失败',
|
|
1689
|
+
'ptp.saveSuccess': '保存成功',
|
|
1626
1690
|
// NMOS Modal
|
|
1627
1691
|
'nmos.title': 'NMOS 设置',
|
|
1628
|
-
'nmos.enable': '启用 NMOS',
|
|
1629
1692
|
'nmos.hostAddress': '主机地址',
|
|
1630
|
-
'nmos.
|
|
1631
|
-
'nmos.
|
|
1632
|
-
'nmos.
|
|
1633
|
-
'nmos.
|
|
1634
|
-
'nmos.
|
|
1635
|
-
'nmos.
|
|
1636
|
-
'nmos.
|
|
1693
|
+
'nmos.domain': '域',
|
|
1694
|
+
'nmos.registrationPort': '注册端口',
|
|
1695
|
+
'nmos.registryAddress': '注册地址',
|
|
1696
|
+
'nmos.registryVersion': '注册版本',
|
|
1697
|
+
'nmos.loggingLevel': '日志级别',
|
|
1698
|
+
'nmos.placeholder.selectHostAddress': '选择主机地址',
|
|
1699
|
+
'nmos.placeholder.selectVersion': '选择版本',
|
|
1700
|
+
'nmos.saveSuccess': '保存成功',
|
|
1637
1701
|
// Preset Modal
|
|
1638
1702
|
'preset.title': '预设管理',
|
|
1639
1703
|
'preset.name': '名称',
|
|
1640
1704
|
'preset.categories': '分类',
|
|
1641
1705
|
'preset.description': '描述',
|
|
1642
|
-
'preset.
|
|
1643
|
-
'preset.
|
|
1644
|
-
'preset.delete': '
|
|
1645
|
-
'preset.
|
|
1646
|
-
'preset.
|
|
1647
|
-
'preset.
|
|
1648
|
-
'preset.
|
|
1649
|
-
'preset.
|
|
1650
|
-
'preset.
|
|
1651
|
-
'preset.
|
|
1652
|
-
'preset.
|
|
1653
|
-
'preset.
|
|
1654
|
-
'preset.
|
|
1655
|
-
'preset.
|
|
1656
|
-
'preset.
|
|
1657
|
-
'preset.
|
|
1706
|
+
'preset.placeholder.enterName': '请输入名称',
|
|
1707
|
+
'preset.button.new': '新建预设',
|
|
1708
|
+
'preset.button.delete': '删除',
|
|
1709
|
+
'preset.button.load': '加载',
|
|
1710
|
+
'preset.button.save': '保存',
|
|
1711
|
+
'preset.button.edit': '编辑',
|
|
1712
|
+
'preset.button.cancel': '取消',
|
|
1713
|
+
'preset.empty.noData': '从列表中选择一个预设查看详情',
|
|
1714
|
+
'preset.untitled': '未命名预设',
|
|
1715
|
+
'preset.delete.title': '删除预设',
|
|
1716
|
+
'preset.delete.confirmMessage': '确定要删除预设',
|
|
1717
|
+
'preset.load.title': '加载预设',
|
|
1718
|
+
'preset.load.confirmMessage': '确定要加载预设',
|
|
1719
|
+
'preset.load.loading': '加载中...',
|
|
1720
|
+
'preset.success': '成功',
|
|
1721
|
+
'preset.validation.nameRequired': '名称是必填项',
|
|
1722
|
+
'preset.validation.categoryRequired': '请选择分类',
|
|
1723
|
+
'preset.error.noSelectionOrIdMissing': '未选择预设或预设 ID 缺失',
|
|
1658
1724
|
// License/Auth Modal
|
|
1659
|
-
'license.title': '
|
|
1660
|
-
'license.
|
|
1661
|
-
'license.
|
|
1662
|
-
'license.
|
|
1663
|
-
'license.
|
|
1664
|
-
'license.
|
|
1665
|
-
'license.
|
|
1666
|
-
'license.
|
|
1667
|
-
'license.
|
|
1668
|
-
'license.
|
|
1669
|
-
'license.
|
|
1670
|
-
'license.
|
|
1671
|
-
'license.
|
|
1672
|
-
'license.expiryDate': '到期日期',
|
|
1673
|
-
'license.features': '功能特性',
|
|
1725
|
+
'license.title': '注册许可证',
|
|
1726
|
+
'license.machineCode': '机器码',
|
|
1727
|
+
'license.key': '许可证密钥',
|
|
1728
|
+
'license.placeholder.enterKey': '请输入许可证密钥',
|
|
1729
|
+
'license.button.activate': '立即激活',
|
|
1730
|
+
'license.button.reactivate': '重新激活',
|
|
1731
|
+
'license.button.ignore': '忽略',
|
|
1732
|
+
'license.status.unactivated': '未激活',
|
|
1733
|
+
'license.status.activated': '已激活',
|
|
1734
|
+
'license.status.expired': '已过期',
|
|
1735
|
+
'license.status.invalid': '无效',
|
|
1736
|
+
'license.status.expiresOn': '到期时间',
|
|
1737
|
+
'license.validation.keyRequired': '许可证密钥不能为空',
|
|
1674
1738
|
// 升级相关
|
|
1675
|
-
'upgrade.
|
|
1676
|
-
'upgrade.
|
|
1677
|
-
'upgrade.
|
|
1678
|
-
'upgrade.
|
|
1679
|
-
'upgrade.
|
|
1680
|
-
'upgrade.
|
|
1681
|
-
'upgrade.
|
|
1682
|
-
'upgrade.
|
|
1683
|
-
'upgrade.
|
|
1684
|
-
'upgrade.
|
|
1685
|
-
'upgrade.
|
|
1686
|
-
'upgrade.releaseNotes': '更新说明',
|
|
1687
|
-
'upgrade.download': '下载',
|
|
1688
|
-
'upgrade.install': '安装',
|
|
1689
|
-
'upgrade.cancel': '取消',
|
|
1739
|
+
'upgrade.menu.download': '下载配置文件',
|
|
1740
|
+
'upgrade.menu.softwareUpdate': '软件升级',
|
|
1741
|
+
'upgrade.status.idle': '空闲',
|
|
1742
|
+
'upgrade.status.uploading': '上传中',
|
|
1743
|
+
'upgrade.status.uploadComplete': '上传完成,开始升级...',
|
|
1744
|
+
'upgrade.status.upgrading': '升级中...',
|
|
1745
|
+
'upgrade.error.downloadNotConfigured': '下载功能未配置',
|
|
1746
|
+
'upgrade.error.downloadFailed': '下载失败',
|
|
1747
|
+
'upgrade.error.uploadFailed': '上传失败',
|
|
1748
|
+
'upgrade.error.invalidFileFormat': '上传失败:文件格式无效',
|
|
1749
|
+
'upgrade.error.upgradeFailed': '升级失败',
|
|
1690
1750
|
// 系统操作
|
|
1751
|
+
'system.poweroff': '关机',
|
|
1691
1752
|
'system.restart': '重启',
|
|
1692
|
-
'system.
|
|
1693
|
-
'system.
|
|
1694
|
-
'system.
|
|
1695
|
-
'system.
|
|
1696
|
-
'system.
|
|
1697
|
-
'system.
|
|
1698
|
-
'system.shutdownConfirmMessage': '确定要关闭设备吗?',
|
|
1699
|
-
'system.restarting': '设备重启中...',
|
|
1700
|
-
'system.shuttingDown': '设备关机中...',
|
|
1753
|
+
'system.action.powerOff': '关闭',
|
|
1754
|
+
'system.action.restart': '重启',
|
|
1755
|
+
'system.confirm.title': '确认操作',
|
|
1756
|
+
'system.confirm.message': '确定要{action}系统吗?此操作无法撤销。',
|
|
1757
|
+
'system.button.cancel': '取消',
|
|
1758
|
+
'system.button.confirm': '确认',
|
|
1701
1759
|
// 维护页面
|
|
1702
1760
|
'maintenance.title': '系统维护',
|
|
1703
1761
|
'maintenance.description': '设备正在维护中,请稍候...',
|
|
@@ -1792,100 +1850,95 @@ var enUS = {
|
|
|
1792
1850
|
'networkSettings.restartRequired': 'Configuration modified. Restart to apply changes?',
|
|
1793
1851
|
'networkSettings.restartNow': 'Restart Now',
|
|
1794
1852
|
'networkSettings.restartLater': 'Restart Later',
|
|
1795
|
-
'networkSettings.saveSuccess': '
|
|
1853
|
+
'networkSettings.saveSuccess': 'Success',
|
|
1796
1854
|
// PTP Modal
|
|
1797
1855
|
'ptp.title': 'PTP Settings',
|
|
1798
|
-
'ptp.enable': 'Enable PTP',
|
|
1799
|
-
'ptp.status': 'PTP Status',
|
|
1800
1856
|
'ptp.domainNumber': 'Domain Number',
|
|
1801
1857
|
'ptp.priority1': 'Priority 1',
|
|
1802
1858
|
'ptp.priority2': 'Priority 2',
|
|
1803
1859
|
'ptp.clockClass': 'Clock Class',
|
|
1860
|
+
'ptp.clockClass.atomic': 'Atomic Clock ({value})',
|
|
1861
|
+
'ptp.clockClass.gps': 'GPS ({value})',
|
|
1862
|
+
'ptp.clockClass.slaveOnly': 'Slave-Only ({value})',
|
|
1804
1863
|
'ptp.clockAccuracy': 'Clock Accuracy',
|
|
1805
1864
|
'ptp.offsetScaledLogVariance': 'Offset Scaled Log Variance',
|
|
1806
|
-
'ptp.
|
|
1807
|
-
'ptp.
|
|
1808
|
-
'ptp.
|
|
1809
|
-
'ptp.
|
|
1865
|
+
'ptp.portIdentity': 'Port Identity',
|
|
1866
|
+
'ptp.grandmasterIdentity': 'Grandmaster Identity',
|
|
1867
|
+
'ptp.utcOffset': 'UTC Offset',
|
|
1868
|
+
'ptp.connected': 'Connected',
|
|
1869
|
+
'ptp.disconnected': 'Disconnected',
|
|
1810
1870
|
'ptp.locked': 'Locked',
|
|
1811
1871
|
'ptp.unlocked': 'Unlocked',
|
|
1812
|
-
'ptp.saveSuccess': '
|
|
1813
|
-
'ptp.saveFailed': 'Failed to save PTP settings',
|
|
1872
|
+
'ptp.saveSuccess': 'Success',
|
|
1814
1873
|
// NMOS Modal
|
|
1815
1874
|
'nmos.title': 'NMOS Settings',
|
|
1816
|
-
'nmos.enable': 'Enable NMOS',
|
|
1817
1875
|
'nmos.hostAddress': 'Host Address',
|
|
1818
|
-
'nmos.
|
|
1819
|
-
'nmos.
|
|
1820
|
-
'nmos.
|
|
1821
|
-
'nmos.
|
|
1822
|
-
'nmos.
|
|
1823
|
-
'nmos.
|
|
1824
|
-
'nmos.
|
|
1876
|
+
'nmos.domain': 'Domain',
|
|
1877
|
+
'nmos.registryAddress': 'Registry Address',
|
|
1878
|
+
'nmos.registrationPort': 'Registry Port',
|
|
1879
|
+
'nmos.registryVersion': 'Registry Version',
|
|
1880
|
+
'nmos.loggingLevel': 'Logging Level',
|
|
1881
|
+
'nmos.placeholder.selectHostAddress': 'Select host address',
|
|
1882
|
+
'nmos.placeholder.selectVersion': 'Select version',
|
|
1883
|
+
'nmos.saveSuccess': 'Success',
|
|
1825
1884
|
// Preset Modal
|
|
1826
1885
|
'preset.title': 'Preset Management',
|
|
1827
1886
|
'preset.name': 'Name',
|
|
1828
1887
|
'preset.categories': 'Categories',
|
|
1829
1888
|
'preset.description': 'Description',
|
|
1830
|
-
'preset.
|
|
1831
|
-
'preset.
|
|
1832
|
-
'preset.delete': 'Delete
|
|
1833
|
-
'preset.
|
|
1834
|
-
'preset.
|
|
1835
|
-
'preset.
|
|
1836
|
-
'preset.
|
|
1837
|
-
'preset.
|
|
1838
|
-
'preset.
|
|
1839
|
-
'preset.
|
|
1840
|
-
'preset.
|
|
1841
|
-
'preset.
|
|
1842
|
-
'preset.
|
|
1843
|
-
'preset.
|
|
1844
|
-
'preset.
|
|
1845
|
-
'preset.
|
|
1889
|
+
'preset.placeholder.enterName': 'Enter name',
|
|
1890
|
+
'preset.button.new': 'New Preset',
|
|
1891
|
+
'preset.button.delete': 'Delete',
|
|
1892
|
+
'preset.button.load': 'Load',
|
|
1893
|
+
'preset.button.save': 'Save',
|
|
1894
|
+
'preset.button.edit': 'Edit',
|
|
1895
|
+
'preset.button.cancel': 'Cancel',
|
|
1896
|
+
'preset.empty.noData': 'Select a preset from the list to view details',
|
|
1897
|
+
'preset.untitled': 'Untitled Preset',
|
|
1898
|
+
'preset.delete.title': 'Delete Preset',
|
|
1899
|
+
'preset.delete.confirmMessage': 'Are you sure you want to delete preset',
|
|
1900
|
+
'preset.load.title': 'Load Preset',
|
|
1901
|
+
'preset.load.confirmMessage': 'Are you sure you want to load preset',
|
|
1902
|
+
'preset.load.loading': 'Loading...',
|
|
1903
|
+
'preset.success': 'Success',
|
|
1904
|
+
'preset.validation.nameRequired': 'Name is required',
|
|
1905
|
+
'preset.validation.categoryRequired': 'No category selected',
|
|
1906
|
+
'preset.error.noSelectionOrIdMissing': 'No preset selected or preset ID is missing',
|
|
1846
1907
|
// License/Auth Modal
|
|
1847
|
-
'license.title': 'License
|
|
1848
|
-
'license.
|
|
1849
|
-
'license.
|
|
1850
|
-
'license.
|
|
1851
|
-
'license.
|
|
1852
|
-
'license.
|
|
1853
|
-
'license.
|
|
1854
|
-
'license.
|
|
1855
|
-
'license.
|
|
1856
|
-
'license.
|
|
1857
|
-
'license.
|
|
1858
|
-
'license.
|
|
1859
|
-
'license.
|
|
1860
|
-
'license.expiryDate': 'Expiry Date',
|
|
1861
|
-
'license.features': 'Features',
|
|
1908
|
+
'license.title': 'Register License',
|
|
1909
|
+
'license.machineCode': 'Machine Code',
|
|
1910
|
+
'license.key': 'License Key',
|
|
1911
|
+
'license.placeholder.enterKey': 'Enter your license key',
|
|
1912
|
+
'license.button.activate': 'Activate Now',
|
|
1913
|
+
'license.button.reactivate': 'Reactivate',
|
|
1914
|
+
'license.button.ignore': 'Ignore',
|
|
1915
|
+
'license.status.unactivated': 'Unactivated',
|
|
1916
|
+
'license.status.activated': 'Already activated',
|
|
1917
|
+
'license.status.expired': 'Expired',
|
|
1918
|
+
'license.status.invalid': 'Invalid',
|
|
1919
|
+
'license.status.expiresOn': 'Expires on',
|
|
1920
|
+
'license.validation.keyRequired': 'License key cannot be empty',
|
|
1862
1921
|
// Upgrade related
|
|
1863
|
-
'upgrade.
|
|
1864
|
-
'upgrade.
|
|
1865
|
-
'upgrade.
|
|
1866
|
-
'upgrade.
|
|
1867
|
-
'upgrade.
|
|
1868
|
-
'upgrade.
|
|
1869
|
-
'upgrade.
|
|
1870
|
-
'upgrade.
|
|
1871
|
-
'upgrade.
|
|
1872
|
-
'upgrade.
|
|
1873
|
-
'upgrade.
|
|
1874
|
-
'upgrade.releaseNotes': 'Release Notes',
|
|
1875
|
-
'upgrade.download': 'Download',
|
|
1876
|
-
'upgrade.install': 'Install',
|
|
1877
|
-
'upgrade.cancel': 'Cancel',
|
|
1922
|
+
'upgrade.menu.download': 'Download Config File',
|
|
1923
|
+
'upgrade.menu.softwareUpdate': 'Software Update',
|
|
1924
|
+
'upgrade.status.idle': 'Idle',
|
|
1925
|
+
'upgrade.status.uploading': 'Uploading...',
|
|
1926
|
+
'upgrade.status.uploadComplete': 'Upload complete, starting upgrade...',
|
|
1927
|
+
'upgrade.status.upgrading': 'Upgrading...',
|
|
1928
|
+
'upgrade.error.downloadNotConfigured': 'Download functionality not configured',
|
|
1929
|
+
'upgrade.error.downloadFailed': 'Download failed',
|
|
1930
|
+
'upgrade.error.uploadFailed': 'Upload failed',
|
|
1931
|
+
'upgrade.error.invalidFileFormat': 'Upload failed: Invalid file format',
|
|
1932
|
+
'upgrade.error.upgradeFailed': 'Upgrade failed',
|
|
1878
1933
|
// System operations
|
|
1879
|
-
'system.restart': 'Restart',
|
|
1880
|
-
'system.shutdown': 'Shutdown',
|
|
1881
1934
|
'system.poweroff': 'Power Off',
|
|
1882
|
-
'system.
|
|
1883
|
-
'system.
|
|
1884
|
-
'system.
|
|
1885
|
-
'system.
|
|
1886
|
-
'system.
|
|
1887
|
-
'system.
|
|
1888
|
-
'system.
|
|
1935
|
+
'system.restart': 'Restart',
|
|
1936
|
+
'system.action.powerOff': 'power off',
|
|
1937
|
+
'system.action.restart': 'restart',
|
|
1938
|
+
'system.confirm.title': 'Confirmation Required',
|
|
1939
|
+
'system.confirm.message': 'Are you sure you want to {action} the system? This action cannot be undone.',
|
|
1940
|
+
'system.button.cancel': 'Cancel',
|
|
1941
|
+
'system.button.confirm': 'Confirm',
|
|
1889
1942
|
// Maintenance page
|
|
1890
1943
|
'maintenance.title': 'System Maintenance',
|
|
1891
1944
|
'maintenance.description': 'Device is under maintenance, please wait...',
|
|
@@ -1980,8 +2033,8 @@ const NetworkFieldGroup = _ref => {
|
|
|
1980
2033
|
};
|
|
1981
2034
|
const mergedFieldConfig = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, defaultFieldConfig), fieldConfig), {}, {
|
|
1982
2035
|
netmask: {
|
|
1983
|
-
label:
|
|
1984
|
-
enabled: (_fieldConfig$netmask$ = (_fieldConfig$netmask = fieldConfig.netmask) === null || _fieldConfig$netmask === void 0 ? void 0 : _fieldConfig$netmask.enabled) !== null && _fieldConfig$netmask$ !== void 0 ? _fieldConfig$netmask$ : defaultFieldConfig.netmask.enabled
|
|
2036
|
+
label: defaultFieldConfig.netmask.label,
|
|
2037
|
+
enabled: (_fieldConfig$netmask$ = (_fieldConfig$netmask = fieldConfig.netmask) === null || _fieldConfig$netmask === void 0 ? void 0 : _fieldConfig$netmask.enabled) !== null && _fieldConfig$netmask$ !== void 0 ? _fieldConfig$netmask$ : defaultFieldConfig.netmask.enabled
|
|
1985
2038
|
}
|
|
1986
2039
|
});
|
|
1987
2040
|
return /*#__PURE__*/jsxs(Fragment, {
|
|
@@ -2383,86 +2436,86 @@ var NetworkSettingsModal$1 = /*#__PURE__*/memo(NetworkSettingsModal);
|
|
|
2383
2436
|
|
|
2384
2437
|
const defaultFieldConfigs = {
|
|
2385
2438
|
clock_class: {
|
|
2386
|
-
label: '
|
|
2439
|
+
label: 'ptp.clockClass',
|
|
2387
2440
|
formType: 'select',
|
|
2388
2441
|
options: [{
|
|
2389
2442
|
value: 6,
|
|
2390
|
-
label: '
|
|
2443
|
+
label: 'ptp.clockClass.atomic'
|
|
2391
2444
|
}, {
|
|
2392
2445
|
value: 7,
|
|
2393
|
-
label: '
|
|
2446
|
+
label: 'ptp.clockClass.gps'
|
|
2394
2447
|
}, {
|
|
2395
2448
|
value: 248,
|
|
2396
|
-
label: '
|
|
2449
|
+
label: 'ptp.clockClass.slaveOnly'
|
|
2397
2450
|
}],
|
|
2398
2451
|
readOnly: true
|
|
2399
2452
|
},
|
|
2400
2453
|
clock_accuracy: {
|
|
2401
|
-
label: '
|
|
2454
|
+
label: 'ptp.clockAccuracy',
|
|
2402
2455
|
formType: 'number',
|
|
2403
2456
|
readOnly: true
|
|
2404
2457
|
},
|
|
2405
2458
|
offset_scaled_log_variance: {
|
|
2406
|
-
label: '
|
|
2459
|
+
label: 'ptp.offsetScaledLogVariance',
|
|
2407
2460
|
formType: 'number',
|
|
2408
2461
|
readOnly: true
|
|
2409
2462
|
},
|
|
2410
2463
|
grandmaster_priority1: {
|
|
2411
|
-
label: '
|
|
2464
|
+
label: 'ptp.priority1',
|
|
2412
2465
|
formType: 'number',
|
|
2413
2466
|
readOnly: true
|
|
2414
2467
|
},
|
|
2415
2468
|
grandmaster_priority2: {
|
|
2416
|
-
label: '
|
|
2469
|
+
label: 'ptp.priority2',
|
|
2417
2470
|
formType: 'number',
|
|
2418
2471
|
readOnly: true
|
|
2419
2472
|
},
|
|
2420
2473
|
grandmaster_identity: {
|
|
2421
|
-
label: '
|
|
2474
|
+
label: 'ptp.grandmasterIdentity',
|
|
2422
2475
|
formType: 'text',
|
|
2423
2476
|
readOnly: true
|
|
2424
2477
|
},
|
|
2425
2478
|
master_port_id: {
|
|
2426
|
-
label: '
|
|
2479
|
+
label: 'ptp.portIdentity',
|
|
2427
2480
|
formType: 'text',
|
|
2428
2481
|
readOnly: true
|
|
2429
2482
|
},
|
|
2430
2483
|
t1_domain_number: {
|
|
2431
|
-
label: '
|
|
2484
|
+
label: 'ptp.domainNumber',
|
|
2432
2485
|
formType: 'number',
|
|
2433
2486
|
min: 0,
|
|
2434
2487
|
max: 127,
|
|
2435
2488
|
readOnly: false
|
|
2436
2489
|
},
|
|
2437
2490
|
master_utc_offset: {
|
|
2438
|
-
label: '
|
|
2491
|
+
label: 'ptp.utcOffset',
|
|
2439
2492
|
formType: 'number',
|
|
2440
2493
|
readOnly: true
|
|
2441
2494
|
},
|
|
2442
2495
|
is_connected: {
|
|
2443
|
-
label: '
|
|
2496
|
+
label: 'ptp.connected',
|
|
2444
2497
|
formType: 'badge',
|
|
2445
2498
|
statusMap: {
|
|
2446
2499
|
0: {
|
|
2447
|
-
text: '
|
|
2500
|
+
text: 'ptp.disconnected',
|
|
2448
2501
|
color: 'red'
|
|
2449
2502
|
},
|
|
2450
2503
|
1: {
|
|
2451
|
-
text: '
|
|
2504
|
+
text: 'ptp.connected',
|
|
2452
2505
|
color: 'green'
|
|
2453
2506
|
}
|
|
2454
2507
|
}
|
|
2455
2508
|
},
|
|
2456
2509
|
is_locked: {
|
|
2457
|
-
label: '
|
|
2510
|
+
label: 'ptp.locked',
|
|
2458
2511
|
formType: 'badge',
|
|
2459
2512
|
statusMap: {
|
|
2460
2513
|
0: {
|
|
2461
|
-
text: '
|
|
2514
|
+
text: 'ptp.unlocked',
|
|
2462
2515
|
color: 'red'
|
|
2463
2516
|
},
|
|
2464
2517
|
1: {
|
|
2465
|
-
text: '
|
|
2518
|
+
text: 'ptp.locked',
|
|
2466
2519
|
color: 'green'
|
|
2467
2520
|
}
|
|
2468
2521
|
}
|
|
@@ -2505,6 +2558,7 @@ const PtpModal = _ref => {
|
|
|
2505
2558
|
modalProps = {},
|
|
2506
2559
|
formProps = {}
|
|
2507
2560
|
} = _ref;
|
|
2561
|
+
const intl = useIntl();
|
|
2508
2562
|
const [ptpStatus, setPtpStatus] = useState(null);
|
|
2509
2563
|
const [loading, setLoading] = useState(false);
|
|
2510
2564
|
const [form] = Form.useForm();
|
|
@@ -2535,13 +2589,26 @@ const PtpModal = _ref => {
|
|
|
2535
2589
|
if (!ptpStatus) return [];
|
|
2536
2590
|
return convertPtpStatusToArray(ptpStatus, fieldConfigs, fieldOrder);
|
|
2537
2591
|
}, [ptpStatus, fieldConfigs, fieldOrder]);
|
|
2592
|
+
|
|
2593
|
+
// 渲染 Form.Item 的 label
|
|
2594
|
+
const renderLabel = item => {
|
|
2595
|
+
// 如果 label 是国际化 key(包含点号),则使用 formatMessage
|
|
2596
|
+
if (item.label && typeof item.label === 'string' && item.label.includes('.')) {
|
|
2597
|
+
return intl.formatMessage({
|
|
2598
|
+
id: item.label
|
|
2599
|
+
});
|
|
2600
|
+
}
|
|
2601
|
+
return item.label;
|
|
2602
|
+
};
|
|
2538
2603
|
const handleSubmit = async () => {
|
|
2539
2604
|
const values = await form.getFieldsValue();
|
|
2540
2605
|
setLoading(true);
|
|
2541
2606
|
try {
|
|
2542
2607
|
const response = await updatePtpInfo(values);
|
|
2543
2608
|
if (response) {
|
|
2544
|
-
message.success(
|
|
2609
|
+
message.success(intl.formatMessage({
|
|
2610
|
+
id: 'ptp.saveSuccess'
|
|
2611
|
+
}));
|
|
2545
2612
|
setTimeout(() => {
|
|
2546
2613
|
onClose();
|
|
2547
2614
|
}, 1500);
|
|
@@ -2553,11 +2620,18 @@ const PtpModal = _ref => {
|
|
|
2553
2620
|
}
|
|
2554
2621
|
};
|
|
2555
2622
|
const renderFormItem = item => {
|
|
2556
|
-
var _item$statusMap, _item$min, _item$max;
|
|
2623
|
+
var _item$options, _item$statusMap, _item$min, _item$max;
|
|
2557
2624
|
switch (item.formType) {
|
|
2558
2625
|
case 'select':
|
|
2626
|
+
const selectOptions = (_item$options = item.options) === null || _item$options === void 0 ? void 0 : _item$options.map(opt => _objectSpread2$1(_objectSpread2$1({}, opt), {}, {
|
|
2627
|
+
label: intl.formatMessage({
|
|
2628
|
+
id: opt.label
|
|
2629
|
+
}, {
|
|
2630
|
+
value: opt.value
|
|
2631
|
+
})
|
|
2632
|
+
}));
|
|
2559
2633
|
return /*#__PURE__*/jsx(Select, {
|
|
2560
|
-
options:
|
|
2634
|
+
options: selectOptions,
|
|
2561
2635
|
disabled: item.readOnly
|
|
2562
2636
|
});
|
|
2563
2637
|
case 'switch':
|
|
@@ -2578,7 +2652,9 @@ const PtpModal = _ref => {
|
|
|
2578
2652
|
},
|
|
2579
2653
|
children: /*#__PURE__*/jsx(Badge, {
|
|
2580
2654
|
color: status.color,
|
|
2581
|
-
text:
|
|
2655
|
+
text: intl.formatMessage({
|
|
2656
|
+
id: status.text
|
|
2657
|
+
})
|
|
2582
2658
|
})
|
|
2583
2659
|
});
|
|
2584
2660
|
case 'number':
|
|
@@ -2599,11 +2675,17 @@ const PtpModal = _ref => {
|
|
|
2599
2675
|
|
|
2600
2676
|
// 合并默认模态框属性和传入的属性
|
|
2601
2677
|
const mergedModalProps = _objectSpread2$1({
|
|
2602
|
-
title:
|
|
2678
|
+
title: intl.formatMessage({
|
|
2679
|
+
id: 'ptp.title'
|
|
2680
|
+
}),
|
|
2603
2681
|
width: 650,
|
|
2604
2682
|
open,
|
|
2605
|
-
okText:
|
|
2606
|
-
|
|
2683
|
+
okText: intl.formatMessage({
|
|
2684
|
+
id: 'button.apply'
|
|
2685
|
+
}),
|
|
2686
|
+
cancelText: intl.formatMessage({
|
|
2687
|
+
id: 'button.close'
|
|
2688
|
+
}),
|
|
2607
2689
|
onCancel: onClose,
|
|
2608
2690
|
onOk: handleSubmit,
|
|
2609
2691
|
confirmLoading: loading
|
|
@@ -2624,7 +2706,7 @@ const PtpModal = _ref => {
|
|
|
2624
2706
|
return /*#__PURE__*/jsx(StyledModal$3, _objectSpread2$1(_objectSpread2$1({}, mergedModalProps), {}, {
|
|
2625
2707
|
children: /*#__PURE__*/jsx(Form, _objectSpread2$1(_objectSpread2$1({}, mergedFormProps), {}, {
|
|
2626
2708
|
children: ptpStatusArray.map(item => /*#__PURE__*/jsx(Form.Item, {
|
|
2627
|
-
label: item
|
|
2709
|
+
label: renderLabel(item),
|
|
2628
2710
|
name: item.key,
|
|
2629
2711
|
initialValue: item.value,
|
|
2630
2712
|
children: renderFormItem(item)
|
|
@@ -3005,24 +3087,24 @@ const Preset = _ref => {
|
|
|
3005
3087
|
// 字段配置
|
|
3006
3088
|
fields = {
|
|
3007
3089
|
name: {
|
|
3008
|
-
label: "
|
|
3009
|
-
placeholder: "
|
|
3090
|
+
label: "preset.name",
|
|
3091
|
+
placeholder: "preset.placeholder.enterName",
|
|
3010
3092
|
required: true
|
|
3011
3093
|
}
|
|
3012
3094
|
},
|
|
3013
3095
|
texts = {
|
|
3014
|
-
title: "
|
|
3015
|
-
emptyText: "
|
|
3016
|
-
deleteConfirm: "
|
|
3017
|
-
loadConfirm: "
|
|
3018
|
-
loadText: "
|
|
3019
|
-
successText: "
|
|
3020
|
-
newButton: "
|
|
3021
|
-
removeButton: "
|
|
3022
|
-
loadButton: "
|
|
3023
|
-
saveButton: "
|
|
3024
|
-
editButton: "
|
|
3025
|
-
cancelButton: "
|
|
3096
|
+
title: "preset.title",
|
|
3097
|
+
emptyText: "preset.empty.noData",
|
|
3098
|
+
deleteConfirm: "preset.delete.confirmMessage",
|
|
3099
|
+
loadConfirm: "preset.load.confirmMessage",
|
|
3100
|
+
loadText: "preset.load.loading",
|
|
3101
|
+
successText: "preset.success",
|
|
3102
|
+
newButton: "preset.button.new",
|
|
3103
|
+
removeButton: "preset.button.delete",
|
|
3104
|
+
loadButton: "preset.button.load",
|
|
3105
|
+
saveButton: "preset.button.save",
|
|
3106
|
+
editButton: "preset.button.edit",
|
|
3107
|
+
cancelButton: "preset.button.cancel"
|
|
3026
3108
|
},
|
|
3027
3109
|
// 样式定制
|
|
3028
3110
|
width = 1000,
|
|
@@ -3031,6 +3113,7 @@ const Preset = _ref => {
|
|
|
3031
3113
|
// 功能配置
|
|
3032
3114
|
enableEdit = true
|
|
3033
3115
|
} = _ref;
|
|
3116
|
+
const intl = useIntl();
|
|
3034
3117
|
const {
|
|
3035
3118
|
message,
|
|
3036
3119
|
modal
|
|
@@ -3040,6 +3123,16 @@ const Preset = _ref => {
|
|
|
3040
3123
|
const [loading, setLoading] = useState(false);
|
|
3041
3124
|
const [presetChanged, setPresetChanged] = useState(0);
|
|
3042
3125
|
const [form] = Form.useForm();
|
|
3126
|
+
|
|
3127
|
+
// 格式化文本的辅助函数
|
|
3128
|
+
const fmt = useCallback(key => {
|
|
3129
|
+
if (typeof key === 'string' && key.includes('.')) {
|
|
3130
|
+
return intl.formatMessage({
|
|
3131
|
+
id: key
|
|
3132
|
+
});
|
|
3133
|
+
}
|
|
3134
|
+
return key;
|
|
3135
|
+
}, [intl]);
|
|
3043
3136
|
const fetchPresetList = useCallback(async () => {
|
|
3044
3137
|
try {
|
|
3045
3138
|
const data = await getPresetList();
|
|
@@ -3087,16 +3180,16 @@ const Preset = _ref => {
|
|
|
3087
3180
|
const handleRemove = useCallback(async () => {
|
|
3088
3181
|
if (!selectedPreset) return;
|
|
3089
3182
|
|
|
3090
|
-
// 检查是否为新建的未保存数据(无id)
|
|
3183
|
+
// 检查是否为新建的未保存数据(无 id)
|
|
3091
3184
|
const isUnsavedPreset = !selectedPreset.id;
|
|
3092
|
-
const presetName = selectedPreset.name || '
|
|
3185
|
+
const presetName = selectedPreset.name || fmt('preset.untitled');
|
|
3093
3186
|
try {
|
|
3094
3187
|
modal.confirm({
|
|
3095
3188
|
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
3096
|
-
title: '
|
|
3097
|
-
content: "".concat(
|
|
3098
|
-
cancelText: '
|
|
3099
|
-
okText: '
|
|
3189
|
+
title: fmt('preset.delete.title'),
|
|
3190
|
+
content: "".concat(fmt('preset.delete.confirmMessage'), " \"").concat(presetName, "\"?"),
|
|
3191
|
+
cancelText: fmt('button.cancel'),
|
|
3192
|
+
okText: fmt('button.delete'),
|
|
3100
3193
|
onOk: async () => {
|
|
3101
3194
|
// 在删除前记录当前选中项的位置
|
|
3102
3195
|
const currentIndex = presetList.findIndex(item => isUnsavedPreset ? !item.id : item.id === selectedPreset.id);
|
|
@@ -3104,7 +3197,7 @@ const Preset = _ref => {
|
|
|
3104
3197
|
await removePreset({
|
|
3105
3198
|
id: selectedPreset.id
|
|
3106
3199
|
});
|
|
3107
|
-
message.success(
|
|
3200
|
+
message.success(fmt('preset.success'));
|
|
3108
3201
|
} else {
|
|
3109
3202
|
// 移除未保存的预设
|
|
3110
3203
|
setPresetList(prev => prev.filter(item => !!item.id));
|
|
@@ -3143,17 +3236,17 @@ const Preset = _ref => {
|
|
|
3143
3236
|
} catch (error) {
|
|
3144
3237
|
console.error('Failed to delete preset:', error);
|
|
3145
3238
|
}
|
|
3146
|
-
}, [selectedPreset, form, modal, message,
|
|
3239
|
+
}, [selectedPreset, form, modal, message, removePreset, getPresetList, fmt]);
|
|
3147
3240
|
const handleLoadPreset = useCallback(async loadData => {
|
|
3148
3241
|
if (!loadData) return;
|
|
3149
3242
|
let modalInstance = null;
|
|
3150
3243
|
let resolveOk = null; // 用于控制 confirm 关闭时机
|
|
3151
3244
|
|
|
3152
3245
|
modalInstance = modal.confirm({
|
|
3153
|
-
title: '
|
|
3154
|
-
content: "".concat(
|
|
3155
|
-
cancelText: '
|
|
3156
|
-
okText: '
|
|
3246
|
+
title: fmt('preset.load.title'),
|
|
3247
|
+
content: "".concat(fmt('preset.load.confirmMessage'), " \"").concat(loadData.name, "\"?"),
|
|
3248
|
+
cancelText: fmt('button.cancel'),
|
|
3249
|
+
okText: fmt('preset.button.load'),
|
|
3157
3250
|
// onOk 返回一个 pending Promise
|
|
3158
3251
|
onOk: () => {
|
|
3159
3252
|
return new Promise((resolve, reject) => {
|
|
@@ -3161,7 +3254,7 @@ const Preset = _ref => {
|
|
|
3161
3254
|
|
|
3162
3255
|
// 立即切换为 loading 状态
|
|
3163
3256
|
modalInstance.update({
|
|
3164
|
-
title:
|
|
3257
|
+
title: fmt('preset.load.loading'),
|
|
3165
3258
|
content: /*#__PURE__*/jsx(Spin, {
|
|
3166
3259
|
size: "large",
|
|
3167
3260
|
className: "block mx-auto"
|
|
@@ -3187,11 +3280,11 @@ const Preset = _ref => {
|
|
|
3187
3280
|
category_list: loadData.category_list
|
|
3188
3281
|
}));
|
|
3189
3282
|
|
|
3190
|
-
// 成功:1秒后自动关闭
|
|
3283
|
+
// 成功:1 秒后自动关闭
|
|
3191
3284
|
setTimeout(() => {
|
|
3192
3285
|
var _resolveOk;
|
|
3193
3286
|
(_resolveOk = resolveOk) === null || _resolveOk === void 0 || _resolveOk();
|
|
3194
|
-
message.success(
|
|
3287
|
+
message.success(fmt('preset.success'));
|
|
3195
3288
|
// 加载成功的外部回调
|
|
3196
3289
|
if (onLoadSuccess) {
|
|
3197
3290
|
onLoadSuccess(loadData);
|
|
@@ -3213,7 +3306,7 @@ const Preset = _ref => {
|
|
|
3213
3306
|
// 用户取消
|
|
3214
3307
|
}
|
|
3215
3308
|
});
|
|
3216
|
-
}, [loadPreset,
|
|
3309
|
+
}, [loadPreset, message, modal, onLoadSuccess, onLoadError, fmt]);
|
|
3217
3310
|
const handleSave = useCallback(async () => {
|
|
3218
3311
|
setLoading(true);
|
|
3219
3312
|
try {
|
|
@@ -3223,7 +3316,7 @@ const Preset = _ref => {
|
|
|
3223
3316
|
// 验证预设名称
|
|
3224
3317
|
if ((_fields$name = fields.name) !== null && _fields$name !== void 0 && _fields$name.required) {
|
|
3225
3318
|
if (!values.name || values.name.trim() === '') {
|
|
3226
|
-
message.error('
|
|
3319
|
+
message.error(fmt('preset.validation.nameRequired'));
|
|
3227
3320
|
return; // 直接返回 不执行
|
|
3228
3321
|
}
|
|
3229
3322
|
}
|
|
@@ -3231,12 +3324,12 @@ const Preset = _ref => {
|
|
|
3231
3324
|
// 验证分类列表
|
|
3232
3325
|
if ((_fields$category_list2 = fields.category_list) !== null && _fields$category_list2 !== void 0 && _fields$category_list2.required) {
|
|
3233
3326
|
if (!values.category_list || values.category_list.length === 0) {
|
|
3234
|
-
message.error('
|
|
3327
|
+
message.error(fmt('preset.validation.categoryRequired'));
|
|
3235
3328
|
return;
|
|
3236
3329
|
}
|
|
3237
3330
|
}
|
|
3238
3331
|
await savePreset(values);
|
|
3239
|
-
message.success(
|
|
3332
|
+
message.success(fmt('preset.success'));
|
|
3240
3333
|
const savedPresetName = values.name;
|
|
3241
3334
|
|
|
3242
3335
|
// 刷新列表
|
|
@@ -3258,10 +3351,10 @@ const Preset = _ref => {
|
|
|
3258
3351
|
} finally {
|
|
3259
3352
|
setLoading(false);
|
|
3260
3353
|
}
|
|
3261
|
-
}, [form, message,
|
|
3354
|
+
}, [form, message, fields, savePreset, getPresetList, fmt]);
|
|
3262
3355
|
const handleUpdate = useCallback(async () => {
|
|
3263
3356
|
if (!selectedPreset || !selectedPreset.id) {
|
|
3264
|
-
message.error('
|
|
3357
|
+
message.error(fmt('preset.error.noSelectionOrIdMissing'));
|
|
3265
3358
|
return;
|
|
3266
3359
|
}
|
|
3267
3360
|
setLoading(true);
|
|
@@ -3272,7 +3365,7 @@ const Preset = _ref => {
|
|
|
3272
3365
|
// 验证预设名称
|
|
3273
3366
|
if ((_fields$name2 = fields.name) !== null && _fields$name2 !== void 0 && _fields$name2.required) {
|
|
3274
3367
|
if (!values.name || values.name.trim() === '') {
|
|
3275
|
-
message.error('
|
|
3368
|
+
message.error(fmt('preset.validation.nameRequired'));
|
|
3276
3369
|
return; // 直接返回 不执行
|
|
3277
3370
|
}
|
|
3278
3371
|
}
|
|
@@ -3292,21 +3385,21 @@ const Preset = _ref => {
|
|
|
3292
3385
|
if (updatedPreset) {
|
|
3293
3386
|
setSelectedPreset(updatedPreset);
|
|
3294
3387
|
}
|
|
3295
|
-
message.success(
|
|
3388
|
+
message.success(fmt('preset.success'));
|
|
3296
3389
|
} catch (error) {
|
|
3297
3390
|
console.error('Failed to update preset:', error);
|
|
3298
3391
|
throw error;
|
|
3299
3392
|
} finally {
|
|
3300
3393
|
setLoading(false);
|
|
3301
3394
|
}
|
|
3302
|
-
}, [form, message,
|
|
3395
|
+
}, [form, message, fields, updatePreset, selectedPreset, fmt]);
|
|
3303
3396
|
|
|
3304
3397
|
// 初始化数据
|
|
3305
3398
|
useEffect(() => {
|
|
3306
3399
|
fetchPresetList();
|
|
3307
3400
|
}, [fetchPresetList]);
|
|
3308
3401
|
return /*#__PURE__*/jsx(StyledModal$3, {
|
|
3309
|
-
title: texts.title,
|
|
3402
|
+
title: fmt(texts.title),
|
|
3310
3403
|
width: width,
|
|
3311
3404
|
open: open,
|
|
3312
3405
|
wrapClassName: "preset-management ".concat(className),
|
|
@@ -3332,8 +3425,8 @@ const Preset = _ref => {
|
|
|
3332
3425
|
onAddNew: handleAddNew,
|
|
3333
3426
|
onRemove: handleRemove,
|
|
3334
3427
|
texts: {
|
|
3335
|
-
newButton: texts.newButton,
|
|
3336
|
-
removeButton: texts.removeButton
|
|
3428
|
+
newButton: fmt(texts.newButton),
|
|
3429
|
+
removeButton: fmt(texts.removeButton)
|
|
3337
3430
|
}
|
|
3338
3431
|
})
|
|
3339
3432
|
}), /*#__PURE__*/jsx(Col, {
|
|
@@ -3350,10 +3443,10 @@ const Preset = _ref => {
|
|
|
3350
3443
|
,
|
|
3351
3444
|
fields: fields,
|
|
3352
3445
|
texts: {
|
|
3353
|
-
loadButton: texts.loadButton,
|
|
3354
|
-
saveButton: texts.saveButton,
|
|
3355
|
-
editButton: texts.editButton,
|
|
3356
|
-
cancelButton: texts.cancelButton
|
|
3446
|
+
loadButton: fmt(texts.loadButton),
|
|
3447
|
+
saveButton: fmt(texts.saveButton),
|
|
3448
|
+
editButton: fmt(texts.editButton),
|
|
3449
|
+
cancelButton: fmt(texts.cancelButton)
|
|
3357
3450
|
},
|
|
3358
3451
|
presetChanged: presetChanged,
|
|
3359
3452
|
enableEdit: enableEdit
|
|
@@ -3364,7 +3457,7 @@ const Preset = _ref => {
|
|
|
3364
3457
|
className: "h-full text-gray-400",
|
|
3365
3458
|
children: /*#__PURE__*/jsx(Empty, {
|
|
3366
3459
|
image: Empty.PRESENTED_IMAGE_SIMPLE,
|
|
3367
|
-
description: texts.emptyText
|
|
3460
|
+
description: fmt(texts.emptyText)
|
|
3368
3461
|
})
|
|
3369
3462
|
})
|
|
3370
3463
|
})]
|
|
@@ -4619,20 +4712,23 @@ const SystemOperations = _ref => {
|
|
|
4619
4712
|
onRestartSuccess,
|
|
4620
4713
|
beforeAction,
|
|
4621
4714
|
// 在执行关机/重启前调用
|
|
4622
|
-
powerOffLabel = "
|
|
4623
|
-
restartLabel = "
|
|
4715
|
+
powerOffLabel = "system.powerOff",
|
|
4716
|
+
restartLabel = "system.restart",
|
|
4624
4717
|
iconClassName = "seeder-iconfont seeder-icon-guanji1 text-xl text-neutral-400",
|
|
4625
|
-
confirmMessage = "
|
|
4626
|
-
confirmTitle = "
|
|
4627
|
-
cancelText = "
|
|
4628
|
-
okText = "
|
|
4718
|
+
confirmMessage = "system.confirm.message",
|
|
4719
|
+
confirmTitle = "system.confirm.title",
|
|
4720
|
+
cancelText = "system.button.cancel",
|
|
4721
|
+
okText = "system.button.confirm"
|
|
4629
4722
|
} = _ref;
|
|
4723
|
+
const intl = useIntl();
|
|
4630
4724
|
const {
|
|
4631
4725
|
modal
|
|
4632
4726
|
} = App.useApp();
|
|
4633
4727
|
const menuItems = [{
|
|
4634
4728
|
key: "poweroff",
|
|
4635
|
-
label: powerOffLabel
|
|
4729
|
+
label: typeof powerOffLabel === 'string' && powerOffLabel.includes('.') ? intl.formatMessage({
|
|
4730
|
+
id: powerOffLabel
|
|
4731
|
+
}) : powerOffLabel
|
|
4636
4732
|
},
|
|
4637
4733
|
// {
|
|
4638
4734
|
// key: "reboot",
|
|
@@ -4640,22 +4736,45 @@ const SystemOperations = _ref => {
|
|
|
4640
4736
|
// },
|
|
4641
4737
|
{
|
|
4642
4738
|
key: "restart",
|
|
4643
|
-
label: restartLabel
|
|
4739
|
+
label: typeof restartLabel === 'string' && restartLabel.includes('.') ? intl.formatMessage({
|
|
4740
|
+
id: restartLabel
|
|
4741
|
+
}) : restartLabel
|
|
4644
4742
|
}];
|
|
4645
4743
|
const doAction = action => {
|
|
4646
4744
|
try {
|
|
4647
|
-
// 根据action决定显示的确认信息
|
|
4745
|
+
// 根据 action 决定显示的确认信息
|
|
4648
4746
|
const actionLabels = {
|
|
4649
|
-
poweroff:
|
|
4650
|
-
|
|
4747
|
+
poweroff: intl.formatMessage({
|
|
4748
|
+
id: 'system.action.powerOff'
|
|
4749
|
+
}),
|
|
4750
|
+
restart: intl.formatMessage({
|
|
4751
|
+
id: 'system.action.restart'
|
|
4752
|
+
})
|
|
4651
4753
|
};
|
|
4652
4754
|
const actionText = actionLabels[action] || action;
|
|
4755
|
+
|
|
4756
|
+
// 处理标题和消息的国际化
|
|
4757
|
+
const titleText = typeof confirmTitle === 'string' && confirmTitle.includes('.') ? intl.formatMessage({
|
|
4758
|
+
id: confirmTitle
|
|
4759
|
+
}) : confirmTitle;
|
|
4760
|
+
|
|
4761
|
+
// 如果是国际化 key,使用 intl.formatMessage 处理参数
|
|
4762
|
+
// 如果是普通文本,使用 replace 替换占位符
|
|
4763
|
+
const messageText = typeof confirmMessage === 'string' && confirmMessage.includes('.') ? intl.formatMessage({
|
|
4764
|
+
id: confirmMessage
|
|
4765
|
+
}, {
|
|
4766
|
+
action: actionText
|
|
4767
|
+
}) : typeof confirmMessage === 'string' ? confirmMessage.replace('{action}', actionText) : confirmMessage;
|
|
4653
4768
|
modal.confirm({
|
|
4654
4769
|
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
4655
|
-
title:
|
|
4656
|
-
content:
|
|
4657
|
-
cancelText
|
|
4658
|
-
|
|
4770
|
+
title: titleText,
|
|
4771
|
+
content: messageText,
|
|
4772
|
+
cancelText: typeof cancelText === 'string' && cancelText.includes('.') ? intl.formatMessage({
|
|
4773
|
+
id: cancelText
|
|
4774
|
+
}) : cancelText,
|
|
4775
|
+
okText: typeof okText === 'string' && okText.includes('.') ? intl.formatMessage({
|
|
4776
|
+
id: okText
|
|
4777
|
+
}) : okText,
|
|
4659
4778
|
onOk: async () => {
|
|
4660
4779
|
// 先执行 beforeAction(用于 enterMaintenanceMode)
|
|
4661
4780
|
if (typeof beforeAction === 'function') {
|
|
@@ -13354,6 +13473,7 @@ const NmosModal = _ref => {
|
|
|
13354
13473
|
modalProps = {},
|
|
13355
13474
|
formProps = {}
|
|
13356
13475
|
} = _ref;
|
|
13476
|
+
const intl = useIntl();
|
|
13357
13477
|
const [nmosSettings, setNmosSettings] = useState(null);
|
|
13358
13478
|
const [loading, setLoading] = useState(false);
|
|
13359
13479
|
const [form] = Form.useForm();
|
|
@@ -13394,7 +13514,9 @@ const NmosModal = _ref => {
|
|
|
13394
13514
|
try {
|
|
13395
13515
|
const response = await updateNmosSettings(_objectSpread2$1(_objectSpread2$1({}, nmosSettings), values));
|
|
13396
13516
|
if (response) {
|
|
13397
|
-
message.success(
|
|
13517
|
+
message.success(intl.formatMessage({
|
|
13518
|
+
id: 'nmos.saveSuccess'
|
|
13519
|
+
}));
|
|
13398
13520
|
setTimeout(() => {
|
|
13399
13521
|
onClose();
|
|
13400
13522
|
}, 1500);
|
|
@@ -13406,9 +13528,17 @@ const NmosModal = _ref => {
|
|
|
13406
13528
|
}
|
|
13407
13529
|
};
|
|
13408
13530
|
return /*#__PURE__*/jsx(StyledModal$1, _objectSpread2$1(_objectSpread2$1({
|
|
13409
|
-
title:
|
|
13531
|
+
title: intl.formatMessage({
|
|
13532
|
+
id: 'nmos.title'
|
|
13533
|
+
}),
|
|
13410
13534
|
width: 650,
|
|
13411
13535
|
open: open,
|
|
13536
|
+
okText: intl.formatMessage({
|
|
13537
|
+
id: 'button.apply'
|
|
13538
|
+
}),
|
|
13539
|
+
cancelText: intl.formatMessage({
|
|
13540
|
+
id: 'button.close'
|
|
13541
|
+
}),
|
|
13412
13542
|
onOk: handleSubmit,
|
|
13413
13543
|
onCancel: onClose,
|
|
13414
13544
|
confirmLoading: loading,
|
|
@@ -13427,7 +13557,9 @@ const NmosModal = _ref => {
|
|
|
13427
13557
|
disabled: loading
|
|
13428
13558
|
}, formProps), {}, {
|
|
13429
13559
|
children: [/*#__PURE__*/jsx(Form.Item, {
|
|
13430
|
-
label:
|
|
13560
|
+
label: intl.formatMessage({
|
|
13561
|
+
id: 'nmos.hostAddress'
|
|
13562
|
+
}),
|
|
13431
13563
|
name: "host_addresses",
|
|
13432
13564
|
children: /*#__PURE__*/jsx(Select, {
|
|
13433
13565
|
mode: "multiple",
|
|
@@ -13436,19 +13568,27 @@ const NmosModal = _ref => {
|
|
|
13436
13568
|
label: "display_name",
|
|
13437
13569
|
value: "ip_address"
|
|
13438
13570
|
},
|
|
13439
|
-
placeholder:
|
|
13571
|
+
placeholder: intl.formatMessage({
|
|
13572
|
+
id: 'nmos.placeholder.selectHostAddress'
|
|
13573
|
+
}),
|
|
13440
13574
|
allowClear: true
|
|
13441
13575
|
})
|
|
13442
13576
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13443
|
-
label:
|
|
13577
|
+
label: intl.formatMessage({
|
|
13578
|
+
id: 'nmos.domain'
|
|
13579
|
+
}),
|
|
13444
13580
|
name: "domain",
|
|
13445
13581
|
children: /*#__PURE__*/jsx(Input, {})
|
|
13446
13582
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13447
|
-
label:
|
|
13583
|
+
label: intl.formatMessage({
|
|
13584
|
+
id: 'nmos.registryAddress'
|
|
13585
|
+
}),
|
|
13448
13586
|
name: "registry_address",
|
|
13449
13587
|
children: /*#__PURE__*/jsx(Input, {})
|
|
13450
13588
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13451
|
-
label:
|
|
13589
|
+
label: intl.formatMessage({
|
|
13590
|
+
id: 'nmos.registrationPort'
|
|
13591
|
+
}),
|
|
13452
13592
|
name: "registration_port",
|
|
13453
13593
|
children: /*#__PURE__*/jsx(InputNumber, _objectSpread2$1(_objectSpread2$1({}, numberProps), {}, {
|
|
13454
13594
|
min: 0,
|
|
@@ -13458,7 +13598,9 @@ const NmosModal = _ref => {
|
|
|
13458
13598
|
}
|
|
13459
13599
|
}))
|
|
13460
13600
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13461
|
-
label:
|
|
13601
|
+
label: intl.formatMessage({
|
|
13602
|
+
id: 'nmos.registryVersion'
|
|
13603
|
+
}),
|
|
13462
13604
|
name: "registry_version",
|
|
13463
13605
|
children: /*#__PURE__*/jsx(Select, {
|
|
13464
13606
|
options: [{
|
|
@@ -13474,10 +13616,14 @@ const NmosModal = _ref => {
|
|
|
13474
13616
|
label: "v1.3",
|
|
13475
13617
|
value: "v1.3"
|
|
13476
13618
|
}],
|
|
13477
|
-
placeholder:
|
|
13619
|
+
placeholder: intl.formatMessage({
|
|
13620
|
+
id: 'nmos.placeholder.selectVersion'
|
|
13621
|
+
})
|
|
13478
13622
|
})
|
|
13479
13623
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13480
|
-
label:
|
|
13624
|
+
label: intl.formatMessage({
|
|
13625
|
+
id: 'nmos.loggingLevel'
|
|
13626
|
+
}),
|
|
13481
13627
|
name: "logging_level",
|
|
13482
13628
|
children: /*#__PURE__*/jsx(InputNumber, _objectSpread2$1(_objectSpread2$1({}, numberProps), {}, {
|
|
13483
13629
|
min: -40,
|