seeder-st2110-components 1.7.11 → 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 +1785 -1263
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1785 -1261
- 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,1279 +297,1708 @@ 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
|
-
|
|
873
|
-
// 显示遮罩
|
|
874
|
-
setReloading(true);
|
|
875
|
-
|
|
876
|
-
// 设置背景色
|
|
877
|
-
document.body.style.backgroundColor = '#282828';
|
|
878
|
-
document.body.style.transition = 'background-color 0.1s';
|
|
879
|
-
document.body.offsetHeight;
|
|
880
779
|
|
|
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
|
-
};
|
|
1065
|
-
const clearLogs = () => {
|
|
1066
|
-
logs.length = 0;
|
|
1067
|
-
log('INFO', '日志已清空');
|
|
1068
936
|
};
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
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
|
-
|
|
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
|
|
1380
|
+
});
|
|
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', '日志已清空');
|
|
1395
|
+
};
|
|
1396
|
+
return {
|
|
1397
|
+
log,
|
|
1398
|
+
exportLogs,
|
|
1399
|
+
getLogStats,
|
|
1400
|
+
clearLogs,
|
|
1401
|
+
logs
|
|
1402
|
+
};
|
|
1416
1403
|
};
|
|
1417
1404
|
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
const
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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
|
|
1441
1461
|
});
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1462
|
+
heartbeatTimerRef.current = setInterval(() => {
|
|
1463
|
+
// 检查组件是否挂载
|
|
1464
|
+
if (!isMountedRef.current || !heartbeatTimerRef.current) {
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1446
1467
|
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
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]);
|
|
1463
1488
|
|
|
1464
|
-
//
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
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();
|
|
1500
|
+
}
|
|
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;
|
|
1468
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);
|
|
1469
1534
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
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);
|
|
1597
|
+
|
|
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]);
|
|
1496
1619
|
return {
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
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
|
|
1500
1631
|
};
|
|
1501
1632
|
};
|
|
1633
|
+
var useWebSocketWithFeatures$1 = useWebSocketWithFeatures;
|
|
1502
1634
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
* 如果需要在运行时切换语言,可以调用此函数
|
|
1506
|
-
*
|
|
1507
|
-
* @param {string} locale - 语言代码,如 'zh-CN' 或 'en-US'
|
|
1508
|
-
*/
|
|
1509
|
-
const setLocale = locale => {
|
|
1510
|
-
if (typeof window !== 'undefined') {
|
|
1511
|
-
window.__COMPONENT_LOCALE__ = locale;
|
|
1512
|
-
}
|
|
1513
|
-
};
|
|
1635
|
+
// 在控制台中直接查看所有可用的导出方法 Object.keys(window).filter(key => key.startsWith('exportWebSocketLogs_'))
|
|
1636
|
+
// 导出特定连接的日志 window['exportWebSocketLogs_d3M6Ly8xOTIuMTY4LjEyMy4yMDQvd3MvZHZyL3ZpZGVvX3N0YXR1c19jaGFuZ2U=']();
|
|
1514
1637
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1638
|
+
// seeder-st2110-components 组件库中文语言包
|
|
1639
|
+
var zhCN = {
|
|
1640
|
+
// 通用按钮
|
|
1641
|
+
'button.ok': '确定',
|
|
1642
|
+
'button.cancel': '取消',
|
|
1643
|
+
'button.save': '保存',
|
|
1644
|
+
'button.delete': '删除',
|
|
1645
|
+
'button.edit': '编辑',
|
|
1646
|
+
'button.add': '添加',
|
|
1647
|
+
'button.confirm': '确认',
|
|
1648
|
+
'button.close': '关闭',
|
|
1649
|
+
'button.apply': '应用',
|
|
1650
|
+
'button.submit': '提交',
|
|
1651
|
+
'button.next': '下一步',
|
|
1652
|
+
'button.previous': '上一步',
|
|
1653
|
+
'button.refresh': '刷新',
|
|
1654
|
+
'button.retry': '重试',
|
|
1655
|
+
// 菜单
|
|
1656
|
+
'menu.networkSettings': '网络设置',
|
|
1657
|
+
'menu.ptp': 'PTP',
|
|
1658
|
+
'menu.nmos': 'NMOS',
|
|
1659
|
+
'menu.preset': '预设',
|
|
1660
|
+
'menu.license': '许可证',
|
|
1661
|
+
'menu.maintenance': '维护',
|
|
1662
|
+
'menu.system': '系统',
|
|
1663
|
+
// Network Settings Modal
|
|
1664
|
+
'networkSettings.title': '网络设置',
|
|
1665
|
+
'networkSettings.ipAddress': 'IP 地址',
|
|
1666
|
+
'networkSettings.subnetMask': '子网掩码',
|
|
1667
|
+
'networkSettings.restartRequired': '配置已修改。是否重启以应用更改?',
|
|
1668
|
+
'networkSettings.restartNow': '立即重启',
|
|
1669
|
+
'networkSettings.restartLater': '稍后重启',
|
|
1670
|
+
'networkSettings.saveSuccess': '保存成功',
|
|
1671
|
+
// PTP Modal
|
|
1672
|
+
'ptp.title': 'PTP 设置',
|
|
1673
|
+
'ptp.domainNumber': '域编号',
|
|
1674
|
+
'ptp.priority1': '优先级 1',
|
|
1675
|
+
'ptp.priority2': '优先级 2',
|
|
1676
|
+
'ptp.clockClass': '时钟等级',
|
|
1677
|
+
'ptp.clockClass.atomic': '原子钟 ({value})',
|
|
1678
|
+
'ptp.clockClass.gps': 'GPS ({value})',
|
|
1679
|
+
'ptp.clockClass.slaveOnly': '仅从时钟 ({value})',
|
|
1680
|
+
'ptp.clockAccuracy': '时钟精度',
|
|
1681
|
+
'ptp.offsetScaledLogVariance': '时钟稳定性',
|
|
1682
|
+
'ptp.portIdentity': '端口标识',
|
|
1683
|
+
'ptp.grandmasterIdentity': '主时钟标识',
|
|
1684
|
+
'ptp.utcOffset': 'UTC 偏移量',
|
|
1685
|
+
'ptp.connected': '已连接',
|
|
1686
|
+
'ptp.disconnected': '未连接',
|
|
1687
|
+
'ptp.locked': '已锁定',
|
|
1688
|
+
'ptp.unlocked': '未锁定',
|
|
1689
|
+
'ptp.saveSuccess': '保存成功',
|
|
1690
|
+
// NMOS Modal
|
|
1691
|
+
'nmos.title': 'NMOS 设置',
|
|
1692
|
+
'nmos.hostAddress': '主机地址',
|
|
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': '保存成功',
|
|
1701
|
+
// Preset Modal
|
|
1702
|
+
'preset.title': '预设管理',
|
|
1703
|
+
'preset.name': '名称',
|
|
1704
|
+
'preset.categories': '分类',
|
|
1705
|
+
'preset.description': '描述',
|
|
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 缺失',
|
|
1724
|
+
// License/Auth Modal
|
|
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': '许可证密钥不能为空',
|
|
1738
|
+
// 升级相关
|
|
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': '升级失败',
|
|
1750
|
+
// 系统操作
|
|
1751
|
+
'system.poweroff': '关机',
|
|
1752
|
+
'system.restart': '重启',
|
|
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': '确认',
|
|
1759
|
+
// 维护页面
|
|
1760
|
+
'maintenance.title': '系统维护',
|
|
1761
|
+
'maintenance.description': '设备正在维护中,请稍候...',
|
|
1762
|
+
'maintenance.restart': '设备正在重启',
|
|
1763
|
+
'maintenance.poweroff': '设备已关闭',
|
|
1764
|
+
'maintenance.redirecting': '页面跳转中...',
|
|
1765
|
+
'maintenance.backToHome': '返回首页',
|
|
1766
|
+
// 表单验证
|
|
1767
|
+
'validation.required': '此项为必填项',
|
|
1768
|
+
'validation.invalidIP': 'IP 地址格式不正确',
|
|
1769
|
+
'validation.invalidPort': '端口号范围应为 1-65535',
|
|
1770
|
+
'validation.invalidEmail': '邮箱格式不正确',
|
|
1771
|
+
'validation.minLength': '最少需要 {min} 个字符',
|
|
1772
|
+
'validation.maxLength': '最多只能有 {max} 个字符',
|
|
1773
|
+
'validation.min': '最小值为 {min}',
|
|
1774
|
+
'validation.max': '最大值为 {max}',
|
|
1775
|
+
'validation.pattern': '格式不正确',
|
|
1776
|
+
'validation.unique': '该值已存在',
|
|
1777
|
+
// 状态消息
|
|
1778
|
+
'status.loading': '加载中...',
|
|
1779
|
+
'status.saving': '保存中...',
|
|
1780
|
+
'status.deleting': '删除中...',
|
|
1781
|
+
'status.updating': '更新中...',
|
|
1782
|
+
'status.submitting': '提交中...',
|
|
1783
|
+
'status.success': '成功',
|
|
1784
|
+
'status.failed': '失败',
|
|
1785
|
+
'status.error': '错误',
|
|
1786
|
+
'status.pending': '等待中',
|
|
1787
|
+
'status.processing': '处理中',
|
|
1788
|
+
'status.completed': '已完成',
|
|
1789
|
+
'status.cancelled': '已取消',
|
|
1790
|
+
// 确认对话框
|
|
1791
|
+
'confirm.title': '确认操作',
|
|
1792
|
+
'confirm.message': '确定要执行此操作吗?',
|
|
1793
|
+
'confirm.cancel': '取消',
|
|
1794
|
+
'confirm.ok': '确定',
|
|
1795
|
+
// 空状态
|
|
1796
|
+
'empty.noData': '暂无数据',
|
|
1797
|
+
'empty.noResults': '暂无结果',
|
|
1798
|
+
'empty.noItems': '暂无项目',
|
|
1799
|
+
// 通用标签
|
|
1800
|
+
'label.name': '名称',
|
|
1801
|
+
'label.description': '描述',
|
|
1802
|
+
'label.status': '状态',
|
|
1803
|
+
'label.type': '类型',
|
|
1804
|
+
'label.action': '操作',
|
|
1805
|
+
'label.actions': '操作',
|
|
1806
|
+
'label.settings': '设置',
|
|
1807
|
+
'label.configuration': '配置',
|
|
1808
|
+
'label.information': '信息',
|
|
1809
|
+
'label.version': '版本',
|
|
1810
|
+
'label.time': '时间',
|
|
1811
|
+
'label.date': '日期',
|
|
1812
|
+
'label.enable': '启用',
|
|
1813
|
+
'label.disable': '禁用',
|
|
1814
|
+
// 占位符
|
|
1815
|
+
'placeholder.select': '请选择',
|
|
1816
|
+
'placeholder.enter': '请输入',
|
|
1817
|
+
'placeholder.search': '搜索',
|
|
1818
|
+
'placeholder.filter': '筛选'
|
|
1529
1819
|
};
|
|
1530
1820
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
})
|
|
1821
|
+
// seeder-st2110-components component library English language pack
|
|
1822
|
+
var enUS = {
|
|
1823
|
+
// General buttons
|
|
1824
|
+
'button.ok': 'OK',
|
|
1825
|
+
'button.cancel': 'Cancel',
|
|
1826
|
+
'button.save': 'Save',
|
|
1827
|
+
'button.delete': 'Delete',
|
|
1828
|
+
'button.edit': 'Edit',
|
|
1829
|
+
'button.add': 'Add',
|
|
1830
|
+
'button.confirm': 'Confirm',
|
|
1831
|
+
'button.close': 'Close',
|
|
1832
|
+
'button.apply': 'Apply',
|
|
1833
|
+
'button.submit': 'Submit',
|
|
1834
|
+
'button.next': 'Next',
|
|
1835
|
+
'button.previous': 'Previous',
|
|
1836
|
+
'button.refresh': 'Refresh',
|
|
1837
|
+
'button.retry': 'Retry',
|
|
1838
|
+
// Menu
|
|
1839
|
+
'menu.networkSettings': 'Network Settings',
|
|
1840
|
+
'menu.ptp': 'PTP',
|
|
1841
|
+
'menu.nmos': 'NMOS',
|
|
1842
|
+
'menu.preset': 'Preset',
|
|
1843
|
+
'menu.license': 'License',
|
|
1844
|
+
'menu.maintenance': 'Maintenance',
|
|
1845
|
+
'menu.system': 'System',
|
|
1846
|
+
// Network Settings Modal
|
|
1847
|
+
'networkSettings.title': 'Network Settings',
|
|
1848
|
+
'networkSettings.ipAddress': 'IP Address',
|
|
1849
|
+
'networkSettings.subnetMask': 'Netmask',
|
|
1850
|
+
'networkSettings.restartRequired': 'Configuration modified. Restart to apply changes?',
|
|
1851
|
+
'networkSettings.restartNow': 'Restart Now',
|
|
1852
|
+
'networkSettings.restartLater': 'Restart Later',
|
|
1853
|
+
'networkSettings.saveSuccess': 'Success',
|
|
1854
|
+
// PTP Modal
|
|
1855
|
+
'ptp.title': 'PTP Settings',
|
|
1856
|
+
'ptp.domainNumber': 'Domain Number',
|
|
1857
|
+
'ptp.priority1': 'Priority 1',
|
|
1858
|
+
'ptp.priority2': 'Priority 2',
|
|
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})',
|
|
1863
|
+
'ptp.clockAccuracy': 'Clock Accuracy',
|
|
1864
|
+
'ptp.offsetScaledLogVariance': 'Offset Scaled Log Variance',
|
|
1865
|
+
'ptp.portIdentity': 'Port Identity',
|
|
1866
|
+
'ptp.grandmasterIdentity': 'Grandmaster Identity',
|
|
1867
|
+
'ptp.utcOffset': 'UTC Offset',
|
|
1868
|
+
'ptp.connected': 'Connected',
|
|
1869
|
+
'ptp.disconnected': 'Disconnected',
|
|
1870
|
+
'ptp.locked': 'Locked',
|
|
1871
|
+
'ptp.unlocked': 'Unlocked',
|
|
1872
|
+
'ptp.saveSuccess': 'Success',
|
|
1873
|
+
// NMOS Modal
|
|
1874
|
+
'nmos.title': 'NMOS Settings',
|
|
1875
|
+
'nmos.hostAddress': 'Host Address',
|
|
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',
|
|
1884
|
+
// Preset Modal
|
|
1885
|
+
'preset.title': 'Preset Management',
|
|
1886
|
+
'preset.name': 'Name',
|
|
1887
|
+
'preset.categories': 'Categories',
|
|
1888
|
+
'preset.description': 'Description',
|
|
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',
|
|
1907
|
+
// License/Auth Modal
|
|
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',
|
|
1921
|
+
// Upgrade related
|
|
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',
|
|
1933
|
+
// System operations
|
|
1934
|
+
'system.poweroff': 'Power Off',
|
|
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',
|
|
1942
|
+
// Maintenance page
|
|
1943
|
+
'maintenance.title': 'System Maintenance',
|
|
1944
|
+
'maintenance.description': 'Device is under maintenance, please wait...',
|
|
1945
|
+
'maintenance.restart': 'Device is restarting',
|
|
1946
|
+
'maintenance.poweroff': 'Device is powered off',
|
|
1947
|
+
'maintenance.redirecting': 'Redirecting...',
|
|
1948
|
+
'maintenance.backToHome': 'Back to Home',
|
|
1949
|
+
// Form validation
|
|
1950
|
+
'validation.required': 'This field is required',
|
|
1951
|
+
'validation.invalidIP': 'Invalid IP address format',
|
|
1952
|
+
'validation.invalidPort': 'Port number should be 1-65535',
|
|
1953
|
+
'validation.invalidEmail': 'Invalid email format',
|
|
1954
|
+
'validation.minLength': 'Minimum {min} characters required',
|
|
1955
|
+
'validation.maxLength': 'Maximum {max} characters allowed',
|
|
1956
|
+
'validation.min': 'Minimum value is {min}',
|
|
1957
|
+
'validation.max': 'Maximum value is {max}',
|
|
1958
|
+
'validation.pattern': 'Invalid format',
|
|
1959
|
+
'validation.unique': 'This value already exists',
|
|
1960
|
+
// Status messages
|
|
1961
|
+
'status.loading': 'Loading...',
|
|
1962
|
+
'status.saving': 'Saving...',
|
|
1963
|
+
'status.deleting': 'Deleting...',
|
|
1964
|
+
'status.updating': 'Updating...',
|
|
1965
|
+
'status.submitting': 'Submitting...',
|
|
1966
|
+
'status.success': 'Success',
|
|
1967
|
+
'status.failed': 'Failed',
|
|
1968
|
+
'status.error': 'Error',
|
|
1969
|
+
'status.pending': 'Pending',
|
|
1970
|
+
'status.processing': 'Processing',
|
|
1971
|
+
'status.completed': 'Completed',
|
|
1972
|
+
'status.cancelled': 'Cancelled',
|
|
1973
|
+
// Confirmation dialogs
|
|
1974
|
+
'confirm.title': 'Confirm Action',
|
|
1975
|
+
'confirm.message': 'Are you sure you want to proceed?',
|
|
1976
|
+
'confirm.cancel': 'Cancel',
|
|
1977
|
+
'confirm.ok': 'OK',
|
|
1978
|
+
// Empty states
|
|
1979
|
+
'empty.noData': 'No Data',
|
|
1980
|
+
'empty.noResults': 'No Results',
|
|
1981
|
+
'empty.noItems': 'No Items',
|
|
1982
|
+
// General labels
|
|
1983
|
+
'label.name': 'Name',
|
|
1984
|
+
'label.description': 'Description',
|
|
1985
|
+
'label.status': 'Status',
|
|
1986
|
+
'label.type': 'Type',
|
|
1987
|
+
'label.action': 'Action',
|
|
1988
|
+
'label.actions': 'Actions',
|
|
1989
|
+
'label.settings': 'Settings',
|
|
1990
|
+
'label.configuration': 'Configuration',
|
|
1991
|
+
'label.information': 'Information',
|
|
1992
|
+
'label.version': 'Version',
|
|
1993
|
+
'label.time': 'Time',
|
|
1994
|
+
'label.date': 'Date',
|
|
1995
|
+
'label.enable': 'Enable',
|
|
1996
|
+
'label.disable': 'Disable',
|
|
1997
|
+
// Placeholders
|
|
1998
|
+
'placeholder.select': 'Please select',
|
|
1999
|
+
'placeholder.enter': 'Please enter',
|
|
2000
|
+
'placeholder.search': 'Search',
|
|
2001
|
+
'placeholder.filter': 'Filter'
|
|
1573
2002
|
};
|
|
1574
2003
|
|
|
1575
2004
|
const NetworkFieldGroup = _ref => {
|
|
@@ -1604,8 +2033,8 @@ const NetworkFieldGroup = _ref => {
|
|
|
1604
2033
|
};
|
|
1605
2034
|
const mergedFieldConfig = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, defaultFieldConfig), fieldConfig), {}, {
|
|
1606
2035
|
netmask: {
|
|
1607
|
-
label:
|
|
1608
|
-
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
|
|
1609
2038
|
}
|
|
1610
2039
|
});
|
|
1611
2040
|
return /*#__PURE__*/jsxs(Fragment, {
|
|
@@ -2007,86 +2436,86 @@ var NetworkSettingsModal$1 = /*#__PURE__*/memo(NetworkSettingsModal);
|
|
|
2007
2436
|
|
|
2008
2437
|
const defaultFieldConfigs = {
|
|
2009
2438
|
clock_class: {
|
|
2010
|
-
label: '
|
|
2439
|
+
label: 'ptp.clockClass',
|
|
2011
2440
|
formType: 'select',
|
|
2012
2441
|
options: [{
|
|
2013
2442
|
value: 6,
|
|
2014
|
-
label: '
|
|
2443
|
+
label: 'ptp.clockClass.atomic'
|
|
2015
2444
|
}, {
|
|
2016
2445
|
value: 7,
|
|
2017
|
-
label: '
|
|
2446
|
+
label: 'ptp.clockClass.gps'
|
|
2018
2447
|
}, {
|
|
2019
2448
|
value: 248,
|
|
2020
|
-
label: '
|
|
2449
|
+
label: 'ptp.clockClass.slaveOnly'
|
|
2021
2450
|
}],
|
|
2022
2451
|
readOnly: true
|
|
2023
2452
|
},
|
|
2024
2453
|
clock_accuracy: {
|
|
2025
|
-
label: '
|
|
2454
|
+
label: 'ptp.clockAccuracy',
|
|
2026
2455
|
formType: 'number',
|
|
2027
2456
|
readOnly: true
|
|
2028
2457
|
},
|
|
2029
2458
|
offset_scaled_log_variance: {
|
|
2030
|
-
label: '
|
|
2459
|
+
label: 'ptp.offsetScaledLogVariance',
|
|
2031
2460
|
formType: 'number',
|
|
2032
2461
|
readOnly: true
|
|
2033
2462
|
},
|
|
2034
2463
|
grandmaster_priority1: {
|
|
2035
|
-
label: '
|
|
2464
|
+
label: 'ptp.priority1',
|
|
2036
2465
|
formType: 'number',
|
|
2037
2466
|
readOnly: true
|
|
2038
2467
|
},
|
|
2039
2468
|
grandmaster_priority2: {
|
|
2040
|
-
label: '
|
|
2469
|
+
label: 'ptp.priority2',
|
|
2041
2470
|
formType: 'number',
|
|
2042
2471
|
readOnly: true
|
|
2043
2472
|
},
|
|
2044
2473
|
grandmaster_identity: {
|
|
2045
|
-
label: '
|
|
2474
|
+
label: 'ptp.grandmasterIdentity',
|
|
2046
2475
|
formType: 'text',
|
|
2047
2476
|
readOnly: true
|
|
2048
2477
|
},
|
|
2049
2478
|
master_port_id: {
|
|
2050
|
-
label: '
|
|
2479
|
+
label: 'ptp.portIdentity',
|
|
2051
2480
|
formType: 'text',
|
|
2052
2481
|
readOnly: true
|
|
2053
2482
|
},
|
|
2054
2483
|
t1_domain_number: {
|
|
2055
|
-
label: '
|
|
2484
|
+
label: 'ptp.domainNumber',
|
|
2056
2485
|
formType: 'number',
|
|
2057
2486
|
min: 0,
|
|
2058
2487
|
max: 127,
|
|
2059
2488
|
readOnly: false
|
|
2060
2489
|
},
|
|
2061
2490
|
master_utc_offset: {
|
|
2062
|
-
label: '
|
|
2491
|
+
label: 'ptp.utcOffset',
|
|
2063
2492
|
formType: 'number',
|
|
2064
2493
|
readOnly: true
|
|
2065
2494
|
},
|
|
2066
2495
|
is_connected: {
|
|
2067
|
-
label: '
|
|
2496
|
+
label: 'ptp.connected',
|
|
2068
2497
|
formType: 'badge',
|
|
2069
2498
|
statusMap: {
|
|
2070
2499
|
0: {
|
|
2071
|
-
text: '
|
|
2500
|
+
text: 'ptp.disconnected',
|
|
2072
2501
|
color: 'red'
|
|
2073
2502
|
},
|
|
2074
2503
|
1: {
|
|
2075
|
-
text: '
|
|
2504
|
+
text: 'ptp.connected',
|
|
2076
2505
|
color: 'green'
|
|
2077
2506
|
}
|
|
2078
2507
|
}
|
|
2079
2508
|
},
|
|
2080
2509
|
is_locked: {
|
|
2081
|
-
label: '
|
|
2510
|
+
label: 'ptp.locked',
|
|
2082
2511
|
formType: 'badge',
|
|
2083
2512
|
statusMap: {
|
|
2084
2513
|
0: {
|
|
2085
|
-
text: '
|
|
2514
|
+
text: 'ptp.unlocked',
|
|
2086
2515
|
color: 'red'
|
|
2087
2516
|
},
|
|
2088
2517
|
1: {
|
|
2089
|
-
text: '
|
|
2518
|
+
text: 'ptp.locked',
|
|
2090
2519
|
color: 'green'
|
|
2091
2520
|
}
|
|
2092
2521
|
}
|
|
@@ -2129,6 +2558,7 @@ const PtpModal = _ref => {
|
|
|
2129
2558
|
modalProps = {},
|
|
2130
2559
|
formProps = {}
|
|
2131
2560
|
} = _ref;
|
|
2561
|
+
const intl = useIntl();
|
|
2132
2562
|
const [ptpStatus, setPtpStatus] = useState(null);
|
|
2133
2563
|
const [loading, setLoading] = useState(false);
|
|
2134
2564
|
const [form] = Form.useForm();
|
|
@@ -2159,13 +2589,26 @@ const PtpModal = _ref => {
|
|
|
2159
2589
|
if (!ptpStatus) return [];
|
|
2160
2590
|
return convertPtpStatusToArray(ptpStatus, fieldConfigs, fieldOrder);
|
|
2161
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
|
+
};
|
|
2162
2603
|
const handleSubmit = async () => {
|
|
2163
2604
|
const values = await form.getFieldsValue();
|
|
2164
2605
|
setLoading(true);
|
|
2165
2606
|
try {
|
|
2166
2607
|
const response = await updatePtpInfo(values);
|
|
2167
2608
|
if (response) {
|
|
2168
|
-
message.success(
|
|
2609
|
+
message.success(intl.formatMessage({
|
|
2610
|
+
id: 'ptp.saveSuccess'
|
|
2611
|
+
}));
|
|
2169
2612
|
setTimeout(() => {
|
|
2170
2613
|
onClose();
|
|
2171
2614
|
}, 1500);
|
|
@@ -2177,11 +2620,18 @@ const PtpModal = _ref => {
|
|
|
2177
2620
|
}
|
|
2178
2621
|
};
|
|
2179
2622
|
const renderFormItem = item => {
|
|
2180
|
-
var _item$statusMap, _item$min, _item$max;
|
|
2623
|
+
var _item$options, _item$statusMap, _item$min, _item$max;
|
|
2181
2624
|
switch (item.formType) {
|
|
2182
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
|
+
}));
|
|
2183
2633
|
return /*#__PURE__*/jsx(Select, {
|
|
2184
|
-
options:
|
|
2634
|
+
options: selectOptions,
|
|
2185
2635
|
disabled: item.readOnly
|
|
2186
2636
|
});
|
|
2187
2637
|
case 'switch':
|
|
@@ -2202,7 +2652,9 @@ const PtpModal = _ref => {
|
|
|
2202
2652
|
},
|
|
2203
2653
|
children: /*#__PURE__*/jsx(Badge, {
|
|
2204
2654
|
color: status.color,
|
|
2205
|
-
text:
|
|
2655
|
+
text: intl.formatMessage({
|
|
2656
|
+
id: status.text
|
|
2657
|
+
})
|
|
2206
2658
|
})
|
|
2207
2659
|
});
|
|
2208
2660
|
case 'number':
|
|
@@ -2223,11 +2675,17 @@ const PtpModal = _ref => {
|
|
|
2223
2675
|
|
|
2224
2676
|
// 合并默认模态框属性和传入的属性
|
|
2225
2677
|
const mergedModalProps = _objectSpread2$1({
|
|
2226
|
-
title:
|
|
2678
|
+
title: intl.formatMessage({
|
|
2679
|
+
id: 'ptp.title'
|
|
2680
|
+
}),
|
|
2227
2681
|
width: 650,
|
|
2228
2682
|
open,
|
|
2229
|
-
okText:
|
|
2230
|
-
|
|
2683
|
+
okText: intl.formatMessage({
|
|
2684
|
+
id: 'button.apply'
|
|
2685
|
+
}),
|
|
2686
|
+
cancelText: intl.formatMessage({
|
|
2687
|
+
id: 'button.close'
|
|
2688
|
+
}),
|
|
2231
2689
|
onCancel: onClose,
|
|
2232
2690
|
onOk: handleSubmit,
|
|
2233
2691
|
confirmLoading: loading
|
|
@@ -2248,7 +2706,7 @@ const PtpModal = _ref => {
|
|
|
2248
2706
|
return /*#__PURE__*/jsx(StyledModal$3, _objectSpread2$1(_objectSpread2$1({}, mergedModalProps), {}, {
|
|
2249
2707
|
children: /*#__PURE__*/jsx(Form, _objectSpread2$1(_objectSpread2$1({}, mergedFormProps), {}, {
|
|
2250
2708
|
children: ptpStatusArray.map(item => /*#__PURE__*/jsx(Form.Item, {
|
|
2251
|
-
label: item
|
|
2709
|
+
label: renderLabel(item),
|
|
2252
2710
|
name: item.key,
|
|
2253
2711
|
initialValue: item.value,
|
|
2254
2712
|
children: renderFormItem(item)
|
|
@@ -2629,24 +3087,24 @@ const Preset = _ref => {
|
|
|
2629
3087
|
// 字段配置
|
|
2630
3088
|
fields = {
|
|
2631
3089
|
name: {
|
|
2632
|
-
label: "
|
|
2633
|
-
placeholder: "
|
|
3090
|
+
label: "preset.name",
|
|
3091
|
+
placeholder: "preset.placeholder.enterName",
|
|
2634
3092
|
required: true
|
|
2635
3093
|
}
|
|
2636
3094
|
},
|
|
2637
3095
|
texts = {
|
|
2638
|
-
title: "
|
|
2639
|
-
emptyText: "
|
|
2640
|
-
deleteConfirm: "
|
|
2641
|
-
loadConfirm: "
|
|
2642
|
-
loadText: "
|
|
2643
|
-
successText: "
|
|
2644
|
-
newButton: "
|
|
2645
|
-
removeButton: "
|
|
2646
|
-
loadButton: "
|
|
2647
|
-
saveButton: "
|
|
2648
|
-
editButton: "
|
|
2649
|
-
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"
|
|
2650
3108
|
},
|
|
2651
3109
|
// 样式定制
|
|
2652
3110
|
width = 1000,
|
|
@@ -2655,6 +3113,7 @@ const Preset = _ref => {
|
|
|
2655
3113
|
// 功能配置
|
|
2656
3114
|
enableEdit = true
|
|
2657
3115
|
} = _ref;
|
|
3116
|
+
const intl = useIntl();
|
|
2658
3117
|
const {
|
|
2659
3118
|
message,
|
|
2660
3119
|
modal
|
|
@@ -2664,6 +3123,16 @@ const Preset = _ref => {
|
|
|
2664
3123
|
const [loading, setLoading] = useState(false);
|
|
2665
3124
|
const [presetChanged, setPresetChanged] = useState(0);
|
|
2666
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]);
|
|
2667
3136
|
const fetchPresetList = useCallback(async () => {
|
|
2668
3137
|
try {
|
|
2669
3138
|
const data = await getPresetList();
|
|
@@ -2711,16 +3180,16 @@ const Preset = _ref => {
|
|
|
2711
3180
|
const handleRemove = useCallback(async () => {
|
|
2712
3181
|
if (!selectedPreset) return;
|
|
2713
3182
|
|
|
2714
|
-
// 检查是否为新建的未保存数据(无id)
|
|
3183
|
+
// 检查是否为新建的未保存数据(无 id)
|
|
2715
3184
|
const isUnsavedPreset = !selectedPreset.id;
|
|
2716
|
-
const presetName = selectedPreset.name || '
|
|
3185
|
+
const presetName = selectedPreset.name || fmt('preset.untitled');
|
|
2717
3186
|
try {
|
|
2718
3187
|
modal.confirm({
|
|
2719
3188
|
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
2720
|
-
title: '
|
|
2721
|
-
content: "".concat(
|
|
2722
|
-
cancelText: '
|
|
2723
|
-
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'),
|
|
2724
3193
|
onOk: async () => {
|
|
2725
3194
|
// 在删除前记录当前选中项的位置
|
|
2726
3195
|
const currentIndex = presetList.findIndex(item => isUnsavedPreset ? !item.id : item.id === selectedPreset.id);
|
|
@@ -2728,7 +3197,7 @@ const Preset = _ref => {
|
|
|
2728
3197
|
await removePreset({
|
|
2729
3198
|
id: selectedPreset.id
|
|
2730
3199
|
});
|
|
2731
|
-
message.success(
|
|
3200
|
+
message.success(fmt('preset.success'));
|
|
2732
3201
|
} else {
|
|
2733
3202
|
// 移除未保存的预设
|
|
2734
3203
|
setPresetList(prev => prev.filter(item => !!item.id));
|
|
@@ -2767,17 +3236,17 @@ const Preset = _ref => {
|
|
|
2767
3236
|
} catch (error) {
|
|
2768
3237
|
console.error('Failed to delete preset:', error);
|
|
2769
3238
|
}
|
|
2770
|
-
}, [selectedPreset, form, modal, message,
|
|
3239
|
+
}, [selectedPreset, form, modal, message, removePreset, getPresetList, fmt]);
|
|
2771
3240
|
const handleLoadPreset = useCallback(async loadData => {
|
|
2772
3241
|
if (!loadData) return;
|
|
2773
3242
|
let modalInstance = null;
|
|
2774
3243
|
let resolveOk = null; // 用于控制 confirm 关闭时机
|
|
2775
3244
|
|
|
2776
3245
|
modalInstance = modal.confirm({
|
|
2777
|
-
title: '
|
|
2778
|
-
content: "".concat(
|
|
2779
|
-
cancelText: '
|
|
2780
|
-
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'),
|
|
2781
3250
|
// onOk 返回一个 pending Promise
|
|
2782
3251
|
onOk: () => {
|
|
2783
3252
|
return new Promise((resolve, reject) => {
|
|
@@ -2785,7 +3254,7 @@ const Preset = _ref => {
|
|
|
2785
3254
|
|
|
2786
3255
|
// 立即切换为 loading 状态
|
|
2787
3256
|
modalInstance.update({
|
|
2788
|
-
title:
|
|
3257
|
+
title: fmt('preset.load.loading'),
|
|
2789
3258
|
content: /*#__PURE__*/jsx(Spin, {
|
|
2790
3259
|
size: "large",
|
|
2791
3260
|
className: "block mx-auto"
|
|
@@ -2811,11 +3280,11 @@ const Preset = _ref => {
|
|
|
2811
3280
|
category_list: loadData.category_list
|
|
2812
3281
|
}));
|
|
2813
3282
|
|
|
2814
|
-
// 成功:1秒后自动关闭
|
|
3283
|
+
// 成功:1 秒后自动关闭
|
|
2815
3284
|
setTimeout(() => {
|
|
2816
3285
|
var _resolveOk;
|
|
2817
3286
|
(_resolveOk = resolveOk) === null || _resolveOk === void 0 || _resolveOk();
|
|
2818
|
-
message.success(
|
|
3287
|
+
message.success(fmt('preset.success'));
|
|
2819
3288
|
// 加载成功的外部回调
|
|
2820
3289
|
if (onLoadSuccess) {
|
|
2821
3290
|
onLoadSuccess(loadData);
|
|
@@ -2837,7 +3306,7 @@ const Preset = _ref => {
|
|
|
2837
3306
|
// 用户取消
|
|
2838
3307
|
}
|
|
2839
3308
|
});
|
|
2840
|
-
}, [loadPreset,
|
|
3309
|
+
}, [loadPreset, message, modal, onLoadSuccess, onLoadError, fmt]);
|
|
2841
3310
|
const handleSave = useCallback(async () => {
|
|
2842
3311
|
setLoading(true);
|
|
2843
3312
|
try {
|
|
@@ -2847,7 +3316,7 @@ const Preset = _ref => {
|
|
|
2847
3316
|
// 验证预设名称
|
|
2848
3317
|
if ((_fields$name = fields.name) !== null && _fields$name !== void 0 && _fields$name.required) {
|
|
2849
3318
|
if (!values.name || values.name.trim() === '') {
|
|
2850
|
-
message.error('
|
|
3319
|
+
message.error(fmt('preset.validation.nameRequired'));
|
|
2851
3320
|
return; // 直接返回 不执行
|
|
2852
3321
|
}
|
|
2853
3322
|
}
|
|
@@ -2855,12 +3324,12 @@ const Preset = _ref => {
|
|
|
2855
3324
|
// 验证分类列表
|
|
2856
3325
|
if ((_fields$category_list2 = fields.category_list) !== null && _fields$category_list2 !== void 0 && _fields$category_list2.required) {
|
|
2857
3326
|
if (!values.category_list || values.category_list.length === 0) {
|
|
2858
|
-
message.error('
|
|
3327
|
+
message.error(fmt('preset.validation.categoryRequired'));
|
|
2859
3328
|
return;
|
|
2860
3329
|
}
|
|
2861
3330
|
}
|
|
2862
3331
|
await savePreset(values);
|
|
2863
|
-
message.success(
|
|
3332
|
+
message.success(fmt('preset.success'));
|
|
2864
3333
|
const savedPresetName = values.name;
|
|
2865
3334
|
|
|
2866
3335
|
// 刷新列表
|
|
@@ -2882,10 +3351,10 @@ const Preset = _ref => {
|
|
|
2882
3351
|
} finally {
|
|
2883
3352
|
setLoading(false);
|
|
2884
3353
|
}
|
|
2885
|
-
}, [form, message,
|
|
3354
|
+
}, [form, message, fields, savePreset, getPresetList, fmt]);
|
|
2886
3355
|
const handleUpdate = useCallback(async () => {
|
|
2887
3356
|
if (!selectedPreset || !selectedPreset.id) {
|
|
2888
|
-
message.error('
|
|
3357
|
+
message.error(fmt('preset.error.noSelectionOrIdMissing'));
|
|
2889
3358
|
return;
|
|
2890
3359
|
}
|
|
2891
3360
|
setLoading(true);
|
|
@@ -2896,7 +3365,7 @@ const Preset = _ref => {
|
|
|
2896
3365
|
// 验证预设名称
|
|
2897
3366
|
if ((_fields$name2 = fields.name) !== null && _fields$name2 !== void 0 && _fields$name2.required) {
|
|
2898
3367
|
if (!values.name || values.name.trim() === '') {
|
|
2899
|
-
message.error('
|
|
3368
|
+
message.error(fmt('preset.validation.nameRequired'));
|
|
2900
3369
|
return; // 直接返回 不执行
|
|
2901
3370
|
}
|
|
2902
3371
|
}
|
|
@@ -2916,21 +3385,21 @@ const Preset = _ref => {
|
|
|
2916
3385
|
if (updatedPreset) {
|
|
2917
3386
|
setSelectedPreset(updatedPreset);
|
|
2918
3387
|
}
|
|
2919
|
-
message.success(
|
|
3388
|
+
message.success(fmt('preset.success'));
|
|
2920
3389
|
} catch (error) {
|
|
2921
3390
|
console.error('Failed to update preset:', error);
|
|
2922
3391
|
throw error;
|
|
2923
3392
|
} finally {
|
|
2924
3393
|
setLoading(false);
|
|
2925
3394
|
}
|
|
2926
|
-
}, [form, message,
|
|
3395
|
+
}, [form, message, fields, updatePreset, selectedPreset, fmt]);
|
|
2927
3396
|
|
|
2928
3397
|
// 初始化数据
|
|
2929
3398
|
useEffect(() => {
|
|
2930
3399
|
fetchPresetList();
|
|
2931
3400
|
}, [fetchPresetList]);
|
|
2932
3401
|
return /*#__PURE__*/jsx(StyledModal$3, {
|
|
2933
|
-
title: texts.title,
|
|
3402
|
+
title: fmt(texts.title),
|
|
2934
3403
|
width: width,
|
|
2935
3404
|
open: open,
|
|
2936
3405
|
wrapClassName: "preset-management ".concat(className),
|
|
@@ -2956,8 +3425,8 @@ const Preset = _ref => {
|
|
|
2956
3425
|
onAddNew: handleAddNew,
|
|
2957
3426
|
onRemove: handleRemove,
|
|
2958
3427
|
texts: {
|
|
2959
|
-
newButton: texts.newButton,
|
|
2960
|
-
removeButton: texts.removeButton
|
|
3428
|
+
newButton: fmt(texts.newButton),
|
|
3429
|
+
removeButton: fmt(texts.removeButton)
|
|
2961
3430
|
}
|
|
2962
3431
|
})
|
|
2963
3432
|
}), /*#__PURE__*/jsx(Col, {
|
|
@@ -2974,10 +3443,10 @@ const Preset = _ref => {
|
|
|
2974
3443
|
,
|
|
2975
3444
|
fields: fields,
|
|
2976
3445
|
texts: {
|
|
2977
|
-
loadButton: texts.loadButton,
|
|
2978
|
-
saveButton: texts.saveButton,
|
|
2979
|
-
editButton: texts.editButton,
|
|
2980
|
-
cancelButton: texts.cancelButton
|
|
3446
|
+
loadButton: fmt(texts.loadButton),
|
|
3447
|
+
saveButton: fmt(texts.saveButton),
|
|
3448
|
+
editButton: fmt(texts.editButton),
|
|
3449
|
+
cancelButton: fmt(texts.cancelButton)
|
|
2981
3450
|
},
|
|
2982
3451
|
presetChanged: presetChanged,
|
|
2983
3452
|
enableEdit: enableEdit
|
|
@@ -2988,7 +3457,7 @@ const Preset = _ref => {
|
|
|
2988
3457
|
className: "h-full text-gray-400",
|
|
2989
3458
|
children: /*#__PURE__*/jsx(Empty, {
|
|
2990
3459
|
image: Empty.PRESENTED_IMAGE_SIMPLE,
|
|
2991
|
-
description: texts.emptyText
|
|
3460
|
+
description: fmt(texts.emptyText)
|
|
2992
3461
|
})
|
|
2993
3462
|
})
|
|
2994
3463
|
})]
|
|
@@ -4243,20 +4712,23 @@ const SystemOperations = _ref => {
|
|
|
4243
4712
|
onRestartSuccess,
|
|
4244
4713
|
beforeAction,
|
|
4245
4714
|
// 在执行关机/重启前调用
|
|
4246
|
-
powerOffLabel = "
|
|
4247
|
-
restartLabel = "
|
|
4715
|
+
powerOffLabel = "system.powerOff",
|
|
4716
|
+
restartLabel = "system.restart",
|
|
4248
4717
|
iconClassName = "seeder-iconfont seeder-icon-guanji1 text-xl text-neutral-400",
|
|
4249
|
-
confirmMessage = "
|
|
4250
|
-
confirmTitle = "
|
|
4251
|
-
cancelText = "
|
|
4252
|
-
okText = "
|
|
4718
|
+
confirmMessage = "system.confirm.message",
|
|
4719
|
+
confirmTitle = "system.confirm.title",
|
|
4720
|
+
cancelText = "system.button.cancel",
|
|
4721
|
+
okText = "system.button.confirm"
|
|
4253
4722
|
} = _ref;
|
|
4723
|
+
const intl = useIntl();
|
|
4254
4724
|
const {
|
|
4255
4725
|
modal
|
|
4256
4726
|
} = App.useApp();
|
|
4257
4727
|
const menuItems = [{
|
|
4258
4728
|
key: "poweroff",
|
|
4259
|
-
label: powerOffLabel
|
|
4729
|
+
label: typeof powerOffLabel === 'string' && powerOffLabel.includes('.') ? intl.formatMessage({
|
|
4730
|
+
id: powerOffLabel
|
|
4731
|
+
}) : powerOffLabel
|
|
4260
4732
|
},
|
|
4261
4733
|
// {
|
|
4262
4734
|
// key: "reboot",
|
|
@@ -4264,22 +4736,45 @@ const SystemOperations = _ref => {
|
|
|
4264
4736
|
// },
|
|
4265
4737
|
{
|
|
4266
4738
|
key: "restart",
|
|
4267
|
-
label: restartLabel
|
|
4739
|
+
label: typeof restartLabel === 'string' && restartLabel.includes('.') ? intl.formatMessage({
|
|
4740
|
+
id: restartLabel
|
|
4741
|
+
}) : restartLabel
|
|
4268
4742
|
}];
|
|
4269
4743
|
const doAction = action => {
|
|
4270
4744
|
try {
|
|
4271
|
-
// 根据action决定显示的确认信息
|
|
4745
|
+
// 根据 action 决定显示的确认信息
|
|
4272
4746
|
const actionLabels = {
|
|
4273
|
-
poweroff:
|
|
4274
|
-
|
|
4747
|
+
poweroff: intl.formatMessage({
|
|
4748
|
+
id: 'system.action.powerOff'
|
|
4749
|
+
}),
|
|
4750
|
+
restart: intl.formatMessage({
|
|
4751
|
+
id: 'system.action.restart'
|
|
4752
|
+
})
|
|
4275
4753
|
};
|
|
4276
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;
|
|
4277
4768
|
modal.confirm({
|
|
4278
4769
|
icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
|
|
4279
|
-
title:
|
|
4280
|
-
content:
|
|
4281
|
-
cancelText
|
|
4282
|
-
|
|
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,
|
|
4283
4778
|
onOk: async () => {
|
|
4284
4779
|
// 先执行 beforeAction(用于 enterMaintenanceMode)
|
|
4285
4780
|
if (typeof beforeAction === 'function') {
|
|
@@ -12978,6 +13473,7 @@ const NmosModal = _ref => {
|
|
|
12978
13473
|
modalProps = {},
|
|
12979
13474
|
formProps = {}
|
|
12980
13475
|
} = _ref;
|
|
13476
|
+
const intl = useIntl();
|
|
12981
13477
|
const [nmosSettings, setNmosSettings] = useState(null);
|
|
12982
13478
|
const [loading, setLoading] = useState(false);
|
|
12983
13479
|
const [form] = Form.useForm();
|
|
@@ -13018,7 +13514,9 @@ const NmosModal = _ref => {
|
|
|
13018
13514
|
try {
|
|
13019
13515
|
const response = await updateNmosSettings(_objectSpread2$1(_objectSpread2$1({}, nmosSettings), values));
|
|
13020
13516
|
if (response) {
|
|
13021
|
-
message.success(
|
|
13517
|
+
message.success(intl.formatMessage({
|
|
13518
|
+
id: 'nmos.saveSuccess'
|
|
13519
|
+
}));
|
|
13022
13520
|
setTimeout(() => {
|
|
13023
13521
|
onClose();
|
|
13024
13522
|
}, 1500);
|
|
@@ -13030,9 +13528,17 @@ const NmosModal = _ref => {
|
|
|
13030
13528
|
}
|
|
13031
13529
|
};
|
|
13032
13530
|
return /*#__PURE__*/jsx(StyledModal$1, _objectSpread2$1(_objectSpread2$1({
|
|
13033
|
-
title:
|
|
13531
|
+
title: intl.formatMessage({
|
|
13532
|
+
id: 'nmos.title'
|
|
13533
|
+
}),
|
|
13034
13534
|
width: 650,
|
|
13035
13535
|
open: open,
|
|
13536
|
+
okText: intl.formatMessage({
|
|
13537
|
+
id: 'button.apply'
|
|
13538
|
+
}),
|
|
13539
|
+
cancelText: intl.formatMessage({
|
|
13540
|
+
id: 'button.close'
|
|
13541
|
+
}),
|
|
13036
13542
|
onOk: handleSubmit,
|
|
13037
13543
|
onCancel: onClose,
|
|
13038
13544
|
confirmLoading: loading,
|
|
@@ -13051,7 +13557,9 @@ const NmosModal = _ref => {
|
|
|
13051
13557
|
disabled: loading
|
|
13052
13558
|
}, formProps), {}, {
|
|
13053
13559
|
children: [/*#__PURE__*/jsx(Form.Item, {
|
|
13054
|
-
label:
|
|
13560
|
+
label: intl.formatMessage({
|
|
13561
|
+
id: 'nmos.hostAddress'
|
|
13562
|
+
}),
|
|
13055
13563
|
name: "host_addresses",
|
|
13056
13564
|
children: /*#__PURE__*/jsx(Select, {
|
|
13057
13565
|
mode: "multiple",
|
|
@@ -13060,19 +13568,27 @@ const NmosModal = _ref => {
|
|
|
13060
13568
|
label: "display_name",
|
|
13061
13569
|
value: "ip_address"
|
|
13062
13570
|
},
|
|
13063
|
-
placeholder:
|
|
13571
|
+
placeholder: intl.formatMessage({
|
|
13572
|
+
id: 'nmos.placeholder.selectHostAddress'
|
|
13573
|
+
}),
|
|
13064
13574
|
allowClear: true
|
|
13065
13575
|
})
|
|
13066
13576
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13067
|
-
label:
|
|
13577
|
+
label: intl.formatMessage({
|
|
13578
|
+
id: 'nmos.domain'
|
|
13579
|
+
}),
|
|
13068
13580
|
name: "domain",
|
|
13069
13581
|
children: /*#__PURE__*/jsx(Input, {})
|
|
13070
13582
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13071
|
-
label:
|
|
13583
|
+
label: intl.formatMessage({
|
|
13584
|
+
id: 'nmos.registryAddress'
|
|
13585
|
+
}),
|
|
13072
13586
|
name: "registry_address",
|
|
13073
13587
|
children: /*#__PURE__*/jsx(Input, {})
|
|
13074
13588
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13075
|
-
label:
|
|
13589
|
+
label: intl.formatMessage({
|
|
13590
|
+
id: 'nmos.registrationPort'
|
|
13591
|
+
}),
|
|
13076
13592
|
name: "registration_port",
|
|
13077
13593
|
children: /*#__PURE__*/jsx(InputNumber, _objectSpread2$1(_objectSpread2$1({}, numberProps), {}, {
|
|
13078
13594
|
min: 0,
|
|
@@ -13082,7 +13598,9 @@ const NmosModal = _ref => {
|
|
|
13082
13598
|
}
|
|
13083
13599
|
}))
|
|
13084
13600
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13085
|
-
label:
|
|
13601
|
+
label: intl.formatMessage({
|
|
13602
|
+
id: 'nmos.registryVersion'
|
|
13603
|
+
}),
|
|
13086
13604
|
name: "registry_version",
|
|
13087
13605
|
children: /*#__PURE__*/jsx(Select, {
|
|
13088
13606
|
options: [{
|
|
@@ -13098,10 +13616,14 @@ const NmosModal = _ref => {
|
|
|
13098
13616
|
label: "v1.3",
|
|
13099
13617
|
value: "v1.3"
|
|
13100
13618
|
}],
|
|
13101
|
-
placeholder:
|
|
13619
|
+
placeholder: intl.formatMessage({
|
|
13620
|
+
id: 'nmos.placeholder.selectVersion'
|
|
13621
|
+
})
|
|
13102
13622
|
})
|
|
13103
13623
|
}), /*#__PURE__*/jsx(Form.Item, {
|
|
13104
|
-
label:
|
|
13624
|
+
label: intl.formatMessage({
|
|
13625
|
+
id: 'nmos.loggingLevel'
|
|
13626
|
+
}),
|
|
13105
13627
|
name: "logging_level",
|
|
13106
13628
|
children: /*#__PURE__*/jsx(InputNumber, _objectSpread2$1(_objectSpread2$1({}, numberProps), {}, {
|
|
13107
13629
|
min: -40,
|
|
@@ -13723,5 +14245,5 @@ const PayloadInput = props => /*#__PURE__*/jsx(BoundedInput, _objectSpread2$1({
|
|
|
13723
14245
|
placeholder: "Enter payload (96-127)"
|
|
13724
14246
|
}, props));
|
|
13725
14247
|
|
|
13726
|
-
export { AuthorizationModal$1 as AuthorizationModal, CommonHeader$1 as CommonHeader, DraggableNumberInput, LSMLabelField$1 as LSMLabelField, MaintenancePage, NetworkSettingsModal$1 as NetworkSettingsModal, NmosModal$1 as NmosModal, PayloadInput, PortInput, PresetModal, PtpModal$1 as PtpModal, StyledModal$3 as StyledModal, SystemOperations$1 as SystemOperations, UpgradeManager$1 as UpgradeManager, addMessages, debugI18n, initI18n, setLocale, useAuth, useHardwareUsage$1 as useHardwareUsage, useIntl, usePageReload$1 as usePageReload, useSystemOperations$1 as useSystemOperations, useUpgrade$1 as useUpgrade, useWebSocketWithFeatures$1 as useWebSocketWithFeatures };
|
|
14248
|
+
export { AuthorizationModal$1 as AuthorizationModal, CommonHeader$1 as CommonHeader, DraggableNumberInput, LSMLabelField$1 as LSMLabelField, MaintenancePage, NetworkSettingsModal$1 as NetworkSettingsModal, NmosModal$1 as NmosModal, PayloadInput, PortInput, PresetModal, PtpModal$1 as PtpModal, StyledModal$3 as StyledModal, SystemOperations$1 as SystemOperations, UpgradeManager$1 as UpgradeManager, addMessages, debugI18n, initI18n, enUS as localesEnUS, zhCN as localesZhCN, setLocale, useAuth, useHardwareUsage$1 as useHardwareUsage, useIntl, usePageReload$1 as usePageReload, useSystemOperations$1 as useSystemOperations, useUpgrade$1 as useUpgrade, useWebSocketWithFeatures$1 as useWebSocketWithFeatures };
|
|
13727
14249
|
//# sourceMappingURL=index.esm.js.map
|