mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-23 00:00:52 +00:00
feat: Improve the license binding logic (#8457)
This commit is contained in:
@@ -63,6 +63,8 @@ ErrFreeNodeLimit: "Community version node limit reached, please go to www.lxware
|
||||
ErrNodeBound: "This license is bound to another node, please check and retry!"
|
||||
ErrNodeBoundDelete: "This license is bound and does not support delete operations. Please check and try again!"
|
||||
ErrNodeBoundLimit: "The current free node has reached its limit, please check and try again!"
|
||||
ErrLicenseFree: "Free nodes can only be used when the license is properly bound to a node. Please verify and try again!"
|
||||
ErrLicenseUnbind: "Community Edition nodes detected for this license. Please unbind in [Panel Settings - License] and try again!"
|
||||
ErrNoSuchNode: "Node information not found, please check and retry!"
|
||||
ErrNodeUnbind: "This node is not within the license binding range, please check and retry!"
|
||||
ErrNodeBind: "This node is already bound to a license, please check and retry!"
|
||||
|
||||
@@ -64,6 +64,8 @@ ErrFreeNodeLimit: "コミュニティ版のノード数が無料上限に達し
|
||||
ErrNodeBound: "このライセンスは他のノードにバインドされています、確認して再試行してください!"
|
||||
ErrNodeBoundDelete: "このライセンスはバインドされており、削除操作はサポートされていません。確認して再試行してください!"
|
||||
ErrNodeBoundLimit: "現在の無料ノードは上限に達しました。確認して再試行してください!"
|
||||
ErrLicenseFree: "ライセンスがノードに正常にバインドされている場合のみ、その無料ノードを使用できます。確認して再試行してください!"
|
||||
ErrLicenseUnbind: "このライセンスにコミュニティ版ノードが存在します。[パネル設定 - ライセンス]でバインド解除してから再試行してください!"
|
||||
ErrNoSuchNode: "そのノード情報が見つかりませんでした、確認して再試行してください!"
|
||||
ErrNodeUnbind: "そのノードはライセンスのバインド範囲内ではありません、確認して再試行してください!"
|
||||
ErrNodeBind: "そのノードはライセンスにバインドされています、確認して再試行してください!"
|
||||
|
||||
@@ -63,6 +63,8 @@ ErrFreeNodeLimit: "커뮤니티 에디션 노드 수가 무료 한도에 도달
|
||||
ErrNodeBound: "이 라이선스는 다른 노드에 바인딩되어 있습니다. 다시 확인하고 시도해 주세요!"
|
||||
ErrNodeBoundDelete: "이 라이센스는 바인딩되어 있으며 삭제 작업을 지원하지 않습니다. 확인 후 다시 시도해 주세요!"
|
||||
ErrNodeBoundLimit: "현재 무료 노드가 한도에 도달했습니다. 확인 후 다시 시도해 주세요!"
|
||||
ErrLicenseFree: "라이선스가 노드에 정상적으로 바인딩된 경우에만 무료 노드를 사용할 수 있습니다. 확인 후 다시 시도하세요!"
|
||||
ErrLicenseUnbind: "이 라이선스에 커뮤니티 에디션 노드가 존재합니다. [패널 설정 - 라이선스]에서 바인딩 해제 후 다시 시도하세요!"
|
||||
ErrNoSuchNode: "노드 정보를 찾을 수 없습니다. 다시 확인하고 시도해 주세요!"
|
||||
ErrNodeUnbind: "이 노드가 라이선스 바인딩 범위에 있지 않음을 감지하였습니다. 다시 확인하고 시도해 주세요!"
|
||||
ErrNodeBind: "이 노드가 이미 라이선스에 바인딩되어 있음을 감지하였습니다. 다시 확인하고 시도해 주세요!"
|
||||
|
||||
@@ -63,6 +63,8 @@ ErrFreeNodeLimit: "Jumlah nod versi komuniti telah mencapai had percuma, sila la
|
||||
ErrNodeBound: "Lesen ini telah diikat dengan nod lain, sila semak dan cuba lagi!"
|
||||
ErrNodeBoundDelete: "Lisensi ini telah diikat dan tidak menyokong operasi penghapusan. Sila semak dan cuba lagi!"
|
||||
ErrNodeBoundLimit: "Nod percuma semasa telah mencapai had, sila semak dan cuba lagi!"
|
||||
ErrLicenseFree: "Nod percuma hanya boleh digunakan apabila lesen terikat dengan betul pada nod. Sila semak dan cuba lagi!"
|
||||
ErrLicenseUnbind: "Nod Edisi Komuniti dikesan untuk lesen ini. Sila lepaskan ikatan dalam [Tetapan Panel - Lesen] dan cuba lagi!"
|
||||
ErrNoSuchNode: "Maklumat nod tidak ditemui, sila semak dan cuba lagi!"
|
||||
ErrNodeUnbind: "Nod di luar skop lesen dikesan, sila semak dan cuba lagi!"
|
||||
ErrNodeBind: "Nod ini telah diikat dengan lesen, sila semak dan cuba lagi!"
|
||||
|
||||
@@ -63,6 +63,8 @@ ErrFreeNodeLimit: "O número de nós da versão comunitária atingiu o limite gr
|
||||
ErrNodeBound: "Esta licença já está vinculada a outro nó, por favor verifique e tente novamente!"
|
||||
ErrNodeBoundDelete: "Esta licença está vinculada e não suporta operações de exclusão. Por favor, verifique e tente novamente!"
|
||||
ErrNodeBoundLimit: "O nó gratuito atual atingiu seu limite, por favor verifique e tente novamente!"
|
||||
ErrLicenseFree: "Nós gratuitos só podem ser usados quando a licença está devidamente vinculada a um nó. Por favor verifique e tente novamente!"
|
||||
ErrLicenseUnbind: "Nós da Edição Comunitária detectados para esta licença. Por favor desvincule em [Configurações do Painel - Licença] e tente novamente!"
|
||||
ErrNoSuchNode: "As informações deste nó não foram encontradas, por favor verifique e tente novamente!"
|
||||
ErrNodeUnbind: "Nó fora do escopo da licença detectado, por favor verifique e tente novamente!"
|
||||
ErrNodeBind: "Este nó já está vinculado a uma licença, por favor verifique e tente novamente!"
|
||||
|
||||
@@ -63,6 +63,8 @@ ErrFreeNodeLimit: "Количество узлов в версии сообще
|
||||
ErrNodeBound: "Эта лицензия уже связана с другим узлом, проверьте и повторите попытку!"
|
||||
ErrNodeBoundDelete: "Эта лицензия привязана и не поддерживает операции удаления. Пожалуйста, проверьте и попробуйте снова!"
|
||||
ErrNodeBoundLimit: "Текущий бесплатный узел достиг предела, пожалуйста, проверьте и попробуйте снова!"
|
||||
ErrLicenseFree: "Бесплатные узлы доступны только при правильной привязке лицензии к узлу. Проверьте и повторите попытку!"
|
||||
ErrLicenseUnbind: "Обнаружены узлы Community Edition для этой лицензии. Отвяжите в [Настройки панели - Лицензия] и повторите попытку!"
|
||||
ErrNoSuchNode: "Информация об узле не найдена, проверьте и повторите попытку!"
|
||||
ErrNodeUnbind: "Обнаружен узел вне области действия лицензии, проверьте и повторите попытку!"
|
||||
ErrNodeBind: "Этот узел уже связан с лицензией, проверьте и повторите попытку!"
|
||||
|
||||
@@ -63,6 +63,8 @@ ErrFreeNodeLimit: "社區版節點數量已達免費上限,請前往 www.lxwar
|
||||
ErrNodeBound: "該許可證已綁定到其他節點,請檢查後重試!"
|
||||
ErrNodeBoundDelete: "該許可證已被綁定,不支持刪除操作,請檢查後重試!"
|
||||
ErrNodeBoundLimit: "當前免費節點已達上限,請檢查後重試!"
|
||||
ErrLicenseFree: "僅當許可證正常綁定到節點後,才能使用其免費節點,請檢查後重試!"
|
||||
ErrLicenseUnbind: "檢測到該許可證存在社區版節點,請在 [面板設定 - 許可證] 中解除綁定後重試!"
|
||||
ErrNoSuchNode: "未能找到該節點信息,請檢查後重試!"
|
||||
ErrNodeUnbind: "檢測到該節點未在許可證綁定範圍內,請檢查後重試!"
|
||||
ErrNodeBind: "檢測到該節點已綁定許可證,請檢查後重試!"
|
||||
|
||||
@@ -63,6 +63,8 @@ ErrFreeNodeLimit: "社区版节点数量已达到免费上限,请前往 www.lx
|
||||
ErrNodeBound: "该许可证已绑定到其他节点,请检查后重试!"
|
||||
ErrNodeBoundDelete: "该许可证已被绑定,不支持删除操作,请检查后重试!"
|
||||
ErrNodeBoundLimit: "当前免费节点已经达到上限,请检查后重试!"
|
||||
ErrLicenseFree: "仅当许可证正常绑定到节点后,才能使用其免费节点,请检查后重试!"
|
||||
ErrLicenseUnbind: "检测到该许可证存在社区版节点,请在 [ 面板设置 - 许可证 ] 中解绑后重试!"
|
||||
ErrNoSuchNode: "未能找到该节点信息,请检查后重试!"
|
||||
ErrNodeUnbind: "检测到该节点未在许可证绑定范围内,请检查后重试!"
|
||||
ErrNodeBind: "检测到该节点已绑定许可证,请检查后重试!"
|
||||
|
||||
@@ -216,6 +216,13 @@ export namespace Setting {
|
||||
smsUsed: number;
|
||||
smsTotal: number;
|
||||
}
|
||||
export interface LicenseOptions {
|
||||
id: number;
|
||||
licenseName: string;
|
||||
totalFreeCount: number;
|
||||
availableXpackCount: number;
|
||||
availableFreeCount: number;
|
||||
}
|
||||
export interface LicenseStatus {
|
||||
productPro: string;
|
||||
status: string;
|
||||
@@ -227,5 +234,7 @@ export namespace Setting {
|
||||
addr: string;
|
||||
status: string;
|
||||
version: string;
|
||||
isXpack: boolean;
|
||||
isBound: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,11 @@ export const bindLicense = (id: number, nodeID: number) => {
|
||||
export const unbindLicense = (id: number, force: boolean) => {
|
||||
return http.post(`/core/licenses/unbind`, { id: id, force: force }, TimeoutEnum.T_60S);
|
||||
};
|
||||
export const changeBind = (id: number, nodeIDs: Array<number>) => {
|
||||
return http.post(`/core/licenses/bind/free`, { licenseID: id, nodeIDs: nodeIDs }, TimeoutEnum.T_60S);
|
||||
};
|
||||
export const loadLicenseOptions = () => {
|
||||
return http.get(`/core/licenses/options`);
|
||||
return http.get<Array<Setting.LicenseOptions>>(`/core/licenses/options`);
|
||||
};
|
||||
export const listNodeOptions = () => {
|
||||
return http.get<Array<Setting.NodeItem>>(`/core/nodes/list`);
|
||||
|
||||
@@ -301,6 +301,7 @@ const message = {
|
||||
uninstalling: 'Uninstalling',
|
||||
lost: 'Lost Contact',
|
||||
bound: 'Bound',
|
||||
unbind: 'Unbound',
|
||||
exceptional: 'Exceptional',
|
||||
free: 'Free',
|
||||
enable: 'Enabled',
|
||||
@@ -1880,6 +1881,10 @@ const message = {
|
||||
oss: 'Open Source Software',
|
||||
pro: 'Pro',
|
||||
trial: 'Trial',
|
||||
add: 'Add Community Edition',
|
||||
licenseAlert:
|
||||
'Community Edition nodes can only be added when the license is properly bound to a node. Only nodes properly bound to the license support switching.',
|
||||
licenseUnbindHelper: 'Community Edition nodes detected for this license. Please unbind and try again!',
|
||||
subscription: 'Subscription',
|
||||
perpetual: 'Perpetual',
|
||||
versionConstraint: '{0} Version Buyout',
|
||||
@@ -3242,6 +3247,11 @@ const message = {
|
||||
master: 'Main Node',
|
||||
node: 'Node',
|
||||
addr: 'Address',
|
||||
nodeUnhealthy: 'Node status abnormal',
|
||||
nodeUnhealthyHelper: 'Abnormal node status detected. Please check in [Node Management] and try again!',
|
||||
nodeUnbind: 'Node not bound to license',
|
||||
nodeUnbindHelper:
|
||||
'Detected that this node is not bound to a license. Please bind it in [Panel Settings - License] menu and try again!',
|
||||
memTotal: 'Total Memory',
|
||||
nodeManagement: 'Node Management',
|
||||
addNode: 'Add Node',
|
||||
@@ -3276,6 +3286,7 @@ const message = {
|
||||
'When the installation directory is empty, it will be installed in the /opt directory by default',
|
||||
nodePort: 'Node Port',
|
||||
offline: 'Offline mode',
|
||||
freeCount: 'Free quota [{0}]',
|
||||
offlineHelper: 'Used when the node is in an offline environment',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -293,6 +293,7 @@ const message = {
|
||||
uninstalling: 'アンインストール中',
|
||||
lost: '接続失効',
|
||||
bound: 'バインド済み',
|
||||
unbind: '未バインド',
|
||||
exceptional: '異常',
|
||||
free: '空き',
|
||||
enable: '有効',
|
||||
@@ -1787,6 +1788,11 @@ const message = {
|
||||
oss: '無料',
|
||||
pro: '専門',
|
||||
trial: '体験',
|
||||
add: 'コミュニティ版を追加',
|
||||
licenseAlert:
|
||||
'ライセンスがノードに正常にバインドされている場合のみ、コミュニティ版ノードを追加できます。ライセンスに正常にバインドされているノードのみ切り替えがサポートされます。',
|
||||
licenseUnbindHelper:
|
||||
'このライセンスにコミュニティ版ノードが存在します。バインドを解除してから再試行してください!',
|
||||
subscription: 'サブスクリプション',
|
||||
perpetual: '永久ライセンス',
|
||||
versionConstraint: '{0} バージョン買い取り',
|
||||
@@ -3100,6 +3106,11 @@ const message = {
|
||||
master: '主ノード',
|
||||
node: 'ノード',
|
||||
addr: 'アドレス',
|
||||
nodeUnhealthy: 'ノード状態異常',
|
||||
nodeUnhealthyHelper: 'ノード状態異常を検出しました。[ノード管理]で確認してから再試行してください!',
|
||||
nodeUnbind: 'ノードがライセンスにバインドされていません',
|
||||
nodeUnbindHelper:
|
||||
'このノードがライセンスにバインドされていないことを検出しました。[パネル設定 - ライセンス]メニューでバインドしてから再試行してください!',
|
||||
memTotal: '総メモリ',
|
||||
nodeManagement: 'ノード管理',
|
||||
addNode: 'ノードを追加',
|
||||
@@ -3134,6 +3145,7 @@ const message = {
|
||||
baseDirHelper: 'インストールディレクトリが空の場合、デフォルトで/optディレクトリにインストールされます',
|
||||
nodePort: 'ノードポート',
|
||||
offline: 'オフラインモード',
|
||||
freeCount: '無料枠 [{0}]',
|
||||
offlineHelper: 'ノードがオフライン環境にある場合に使用',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -295,6 +295,7 @@ const message = {
|
||||
uninstalling: '제거 중',
|
||||
lost: '연결 끊김',
|
||||
bound: '바인딩됨',
|
||||
unbind: '미바인드',
|
||||
exceptional: '예외',
|
||||
free: '여유',
|
||||
enable: '활성화됨',
|
||||
@@ -1760,6 +1761,10 @@ const message = {
|
||||
oss: '오픈 소스 소프트웨어',
|
||||
pro: 'Pro',
|
||||
trial: '체험판',
|
||||
add: '커뮤니티 에디션 추가',
|
||||
licenseAlert:
|
||||
'라이선스가 노드에 정상적으로 바인딩된 경우에만 커뮤니티 에디션 노드를 추가할 수 있습니다. 라이선스에 정상적으로 바인딩된 노드만 전환이 지원됩니다.',
|
||||
licenseUnbindHelper: '이 라이선스에 커뮤니티 에디션 노드가 존재합니다. 바인딩 해제 후 다시 시도하세요!',
|
||||
subscription: '구독',
|
||||
perpetual: '영구 라이선스',
|
||||
versionConstraint: '{0} 버전 일시불 구매',
|
||||
@@ -3049,6 +3054,11 @@ const message = {
|
||||
master: '주 노드',
|
||||
node: '노드',
|
||||
addr: '주소',
|
||||
nodeUnhealthy: '노드 상태 이상',
|
||||
nodeUnhealthyHelper: '노드 상태 이상이 감지되었습니다. [노드 관리]에서 확인 후 다시 시도하세요!',
|
||||
nodeUnbind: '노드가 라이선스에 바인딩되지 않음',
|
||||
nodeUnbindHelper:
|
||||
'이 노드가 라이선스에 바인딩되지 않은 것으로 감지되었습니다. [패널 설정 - 라이선스] 메뉴에서 바인딩 후 다시 시도하세요!',
|
||||
memTotal: '총 메모리',
|
||||
nodeManagement: '노드 관리',
|
||||
addNode: '노드 추가',
|
||||
@@ -3082,6 +3092,7 @@ const message = {
|
||||
baseDirHelper: '설치 디렉토리가 비어 있으면 기본적으로 /opt 디렉토리에 설치됩니다',
|
||||
nodePort: '노드 포트',
|
||||
offline: '오프라인 모드',
|
||||
freeCount: '무료 할당량 [{0}]',
|
||||
offlineHelper: '노드가 오프라인 환경일 때 사용',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -301,6 +301,7 @@ const message = {
|
||||
uninstalling: 'Menyahpasang',
|
||||
lost: 'Hilang',
|
||||
bound: 'Terikat',
|
||||
unbind: 'Tidak terikat',
|
||||
exceptional: 'Luar biasa',
|
||||
free: 'Bebas',
|
||||
enable: 'Aktif',
|
||||
@@ -1845,6 +1846,10 @@ const message = {
|
||||
oss: 'Perisian Sumber Terbuka',
|
||||
pro: 'Pro',
|
||||
trial: 'Percubaan',
|
||||
add: 'Tambah Edisi Komuniti',
|
||||
licenseAlert:
|
||||
'Nod Edisi Komuniti hanya boleh ditambah apabila lesen terikat dengan betul pada nod. Hanya nod yang terikat dengan betul pada lesen menyokong penukaran.',
|
||||
licenseUnbindHelper: 'Nod Edisi Komuniti dikesan untuk lesen ini. Sila lepaskan ikatan dan cuba lagi!',
|
||||
subscription: 'Langganan',
|
||||
perpetual: 'Lesen Perpetual',
|
||||
versionConstraint: '{0} Pembelian versi',
|
||||
@@ -3170,6 +3175,11 @@ const message = {
|
||||
master: 'Nod Utama',
|
||||
node: 'Nod',
|
||||
addr: 'Alamat',
|
||||
nodeUnhealthy: 'Status nod tidak normal',
|
||||
nodeUnhealthyHelper: 'Status nod tidak normal dikesan. Sila semak dalam [Pengurusan Nod] dan cuba lagi!',
|
||||
nodeUnbind: 'Nod tidak terikat pada lesen',
|
||||
nodeUnbindHelper:
|
||||
'Terdeteksi nod ini tidak terikat pada lesen. Sila ikat dalam menu [Tetapan Panel - Lesen] dan cuba lagi!',
|
||||
memTotal: 'Jumlah Memori',
|
||||
nodeManagement: 'Pengurusan Nod',
|
||||
addNode: 'Tambah Nod',
|
||||
@@ -3205,6 +3215,7 @@ const message = {
|
||||
baseDirHelper: 'Apabila direktori pemasangan kosong, secara lalai akan dipasang di direktori /opt',
|
||||
nodePort: 'Port Nod',
|
||||
offline: 'Mod luar talian',
|
||||
freeCount: 'Had percuma [{0}]',
|
||||
offlineHelper: 'Digunakan apabila nod berada dalam persekitaran luar talian',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -299,6 +299,7 @@ const message = {
|
||||
uninstalling: 'Desinstalando',
|
||||
lost: 'Perdido',
|
||||
bound: 'Vinculado',
|
||||
unbind: 'Desvinculado',
|
||||
exceptional: 'Excepcional',
|
||||
free: 'Livre',
|
||||
enable: 'Habilitado',
|
||||
@@ -1831,6 +1832,11 @@ const message = {
|
||||
oss: 'Open Source Software',
|
||||
pro: 'Pro',
|
||||
trial: 'Teste',
|
||||
add: 'Adicionar Edição Comunitária',
|
||||
licenseAlert:
|
||||
'Nós da Edição Comunitária só podem ser adicionados quando a licença está devidamente vinculada a um nó. Apenas nós devidamente vinculados à licença suportam troca.',
|
||||
licenseUnbindHelper:
|
||||
'Nós da Edição Comunitária detectados para esta licença. Por favor, desvincule e tente novamente!',
|
||||
subscription: 'Assinatura',
|
||||
perpetual: 'Licença Perpétua',
|
||||
versionConstraint: '{0} Compra do versão',
|
||||
@@ -3174,6 +3180,12 @@ const message = {
|
||||
master: 'Nó Principal',
|
||||
node: 'Nó',
|
||||
addr: 'Endereço',
|
||||
nodeUnhealthy: 'Estado do nó anormal',
|
||||
nodeUnhealthyHelper:
|
||||
'Estado anormal do nó detectado. Por favor verifique em [Gestão de Nós] e tente novamente!',
|
||||
nodeUnbind: 'Nó não vinculado à licença',
|
||||
nodeUnbindHelper:
|
||||
'Detectamos que este nó não está vinculado a uma licença. Por favor vincule no menu [Configurações do Painel - Licença] e tente novamente!',
|
||||
memTotal: 'Memória Total',
|
||||
nodeManagement: 'Gerenciamento de Nó',
|
||||
addNode: 'Adicionar Nó',
|
||||
@@ -3208,6 +3220,7 @@ const message = {
|
||||
baseDirHelper: 'Quando o diretório de instalação está vazio, será instalado por padrão no diretório /opt',
|
||||
nodePort: 'Porta do Nó',
|
||||
offline: 'Modo offline',
|
||||
freeCount: 'Cota gratuita [{0}]',
|
||||
offlineHelper: 'Usado quando o nó está em ambiente offline',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -296,6 +296,7 @@ const message = {
|
||||
uninstalling: 'Удаление',
|
||||
lost: 'Потеряно',
|
||||
bound: 'Привязано',
|
||||
unbind: 'Не привязано',
|
||||
exceptional: 'Исключение',
|
||||
free: 'Свободно',
|
||||
enable: 'Включено',
|
||||
@@ -1830,6 +1831,11 @@ const message = {
|
||||
oss: 'Open Source Software',
|
||||
pro: 'Pro',
|
||||
trial: 'Пробная версия',
|
||||
add: 'Добавить Community Edition',
|
||||
licenseAlert:
|
||||
'Узлы Community Edition можно добавлять только при правильной привязке лицензии к узлу. Переключение поддерживается только для узлов, правильно привязанных к лицензии.',
|
||||
licenseUnbindHelper:
|
||||
'Обнаружены узлы Community Edition для этой лицензии. Отвяжите лицензию и повторите попытку!',
|
||||
subscription: 'Подписка',
|
||||
perpetual: 'Пожизненная лицензия',
|
||||
versionConstraint: '{0} Выкуп версии',
|
||||
@@ -3162,6 +3168,12 @@ const message = {
|
||||
master: 'Главный узел',
|
||||
node: 'Узел',
|
||||
addr: 'Адрес',
|
||||
nodeUnhealthy: 'Некорректное состояние узла',
|
||||
nodeUnhealthyHelper:
|
||||
'Обнаружено некорректное состояние узла. Проверьте в [Управление узлами] и повторите попытку!',
|
||||
nodeUnbind: 'Узел не привязан к лицензии',
|
||||
nodeUnbindHelper:
|
||||
'Обнаружено, что узел не привязан к лицензии. Привяжите в меню [Настройки панели - Лицензия] и повторите попытку!',
|
||||
memTotal: 'Общая память',
|
||||
nodeManagement: 'Управление узлом',
|
||||
addNode: 'Добавить узел',
|
||||
@@ -3196,6 +3208,7 @@ const message = {
|
||||
baseDirHelper: 'Если каталог установки пуст, по умолчанию он будет установлен в каталоге /opt',
|
||||
nodePort: 'Порт узла',
|
||||
offline: 'Автономный режим',
|
||||
freeCount: 'Бесплатная квота [{0}]',
|
||||
offlineHelper: 'Используется, когда узел находится в автономной среде',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -295,6 +295,7 @@ const message = {
|
||||
uninstalling: '卸載中',
|
||||
lost: '已失聯',
|
||||
bound: '已綁定',
|
||||
unbind: '未綁定',
|
||||
exceptional: '異常',
|
||||
free: '空閒',
|
||||
enable: '已啟用',
|
||||
@@ -1747,6 +1748,9 @@ const message = {
|
||||
oss: '社區版',
|
||||
pro: '專業版:',
|
||||
trial: '試用',
|
||||
add: '添加社區版',
|
||||
licenseAlert: '僅當許可證正常綁定到節點時,該許可證才能添加社區版節點,只有正常綁定到許可證的節點支援切換。',
|
||||
licenseUnbindHelper: '檢測到該許可證存在社區版節點,請解除綁定後重試!',
|
||||
subscription: '訂閱',
|
||||
perpetual: '永久授權',
|
||||
versionConstraint: '{0} 版本買斷',
|
||||
@@ -3007,6 +3011,10 @@ const message = {
|
||||
master: '主節點',
|
||||
node: '節點',
|
||||
addr: '地址',
|
||||
nodeUnhealthy: '節點狀態異常',
|
||||
nodeUnhealthyHelper: '檢測到該節點狀態異常,請在 [節點管理] 中檢查後重試!',
|
||||
nodeUnbind: '節點未綁定許可證',
|
||||
nodeUnbindHelper: '檢測到該節點未綁定許可證,請在 [面板設定 - 許可證] 選單中綁定後重試!',
|
||||
memTotal: '記憶體總計',
|
||||
nodeManagement: '節點管理',
|
||||
addNode: '新增節點',
|
||||
@@ -3039,6 +3047,7 @@ const message = {
|
||||
baseDirHelper: '安裝目錄為空時,預設安裝於 /opt 目錄下',
|
||||
nodePort: '節點端口',
|
||||
offline: '離線模式',
|
||||
freeCount: '免費額度 [{0}]',
|
||||
offlineHelper: '當節點處於離線環境時使用',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -293,6 +293,7 @@ const message = {
|
||||
uninstalling: '卸载中',
|
||||
lost: '已失联',
|
||||
bound: '已绑定',
|
||||
unbind: '未绑定',
|
||||
exceptional: '异常',
|
||||
free: '空闲',
|
||||
enable: '已启用',
|
||||
@@ -1739,6 +1740,9 @@ const message = {
|
||||
oss: '社区版',
|
||||
pro: '专业版',
|
||||
trial: '试用',
|
||||
add: '添加社区版',
|
||||
licenseAlert: '仅当许可证正常绑定到节点时,该许可证才能添加社区版节点,只有正常绑定到许可证的节点支持切换。',
|
||||
licenseUnbindHelper: '检测到该许可证存在社区版节点,请解绑后重试!',
|
||||
subscription: '订阅',
|
||||
perpetual: '永久授权',
|
||||
versionConstraint: '{0} 版本买断',
|
||||
@@ -2989,6 +2993,10 @@ const message = {
|
||||
master: '主节点',
|
||||
node: '节点',
|
||||
addr: '地址',
|
||||
nodeUnhealthy: '节点状态异常',
|
||||
nodeUnhealthyHelper: '检测到该节点状态异常,请在 [节点管理] 中检查后重试!',
|
||||
nodeUnbind: '节点未绑定许可证',
|
||||
nodeUnbindHelper: '检测到该节点未绑定许可证,请在 [ 面板设置 - 许可证 ] 菜单中绑定后重试!',
|
||||
memTotal: '内存总计',
|
||||
nodeManagement: '节点管理',
|
||||
addNode: '添加节点',
|
||||
@@ -3021,6 +3029,7 @@ const message = {
|
||||
baseDirHelper: '安装目录为空时,默认安装在 /opt 目录下',
|
||||
nodePort: '节点端口',
|
||||
offline: '离线模式',
|
||||
freeCount: '免费额度 [{0}] ',
|
||||
offlineHelper: '节点为离线环境时使用',
|
||||
},
|
||||
customApp: {
|
||||
|
||||
@@ -41,9 +41,18 @@
|
||||
:key="item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
<el-icon class="icon-status" v-if="item.status !== 'Healthy'" type="danger">
|
||||
<Warning />
|
||||
</el-icon>
|
||||
<el-tooltip
|
||||
:content="item.isBound ? $t('xpack.node.nodeUnhealthy') : $t('xpack.node.nodeUnbind')"
|
||||
placement="right"
|
||||
>
|
||||
<el-icon
|
||||
class="icon-status"
|
||||
v-if="item.status !== 'Healthy' || !item.isBound"
|
||||
type="danger"
|
||||
>
|
||||
<Warning />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider class="divider" />
|
||||
@@ -120,16 +129,21 @@ const changeNode = (command: string) => {
|
||||
}
|
||||
for (const item of nodes.value) {
|
||||
if (item.name == command) {
|
||||
if (props.version == item.version) {
|
||||
globalStore.currentNode = command || 'local';
|
||||
globalStore.isOffline = item.isOffline;
|
||||
location.reload();
|
||||
if (!item.isBound) {
|
||||
MsgError(i18n.global.t('xpack.node.nodeUnbindHelper'));
|
||||
return;
|
||||
}
|
||||
if (item.version !== props.version) {
|
||||
if (item.status !== 'Healthy') {
|
||||
MsgError(i18n.global.t('xpack.node.nodeUnhealthyHelper'));
|
||||
return;
|
||||
}
|
||||
if (props.version != item.version) {
|
||||
MsgError(i18n.global.t('setting.versionNotSame'));
|
||||
return;
|
||||
}
|
||||
globalStore.currentNode = command || 'local';
|
||||
globalStore.isOffline = item.isOffline;
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<DrawerPro v-model="drawerVisible" :header="$t('setting.license')" :resource="licenseName" @close="handleClose">
|
||||
<el-form label-position="top" :model="form" @submit.prevent v-loading="loading">
|
||||
<el-form-item :label="$t('license.add')" prop="nodeID">
|
||||
<el-select filterable multiple v-model="form.nodeIDs" class="w-full">
|
||||
<div v-for="item in unboundOptions" :key="item.id">
|
||||
<el-option :label="item.name" :value="item.id" />
|
||||
</div>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onBind()">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { changeBind, listNodeOptions } from '@/api/modules/setting';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { Setting } from '@/api/interface/setting';
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
interface DialogProps {
|
||||
licenseID: number;
|
||||
licenseName: string;
|
||||
freeNodes: Array<Setting.NodeItem>;
|
||||
}
|
||||
const drawerVisible = ref();
|
||||
const loading = ref();
|
||||
const licenseName = ref();
|
||||
const unboundOptions = ref([]);
|
||||
|
||||
const form = reactive({
|
||||
licenseID: null,
|
||||
nodeIDs: [],
|
||||
});
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
licenseName.value = params.licenseName;
|
||||
form.licenseID = params.licenseID;
|
||||
form.nodeIDs = [];
|
||||
for (const item of params.freeNodes) {
|
||||
if (!item.isXpack) {
|
||||
form.nodeIDs.push(item.id);
|
||||
}
|
||||
}
|
||||
unboundOptions.value = [];
|
||||
loadNodes();
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const onBind = async () => {
|
||||
loading.value = true;
|
||||
await changeBind(form.licenseID, form.nodeIDs)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
globalStore.isProductPro = false;
|
||||
window.location.reload();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const loadNodes = async () => {
|
||||
await listNodeOptions().then((res) => {
|
||||
let nodeOptions = res.data || [];
|
||||
for (const item of nodeOptions) {
|
||||
if (!item.isBound) {
|
||||
unboundOptions.value.push(item);
|
||||
continue;
|
||||
}
|
||||
for (const item2 of form.nodeIDs) {
|
||||
if (item.id === item2) {
|
||||
unboundOptions.value.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
@@ -6,6 +6,9 @@
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<template #prompt>
|
||||
<el-alert type="info" :title="$t('license.licenseAlert')" :closable="false" />
|
||||
</template>
|
||||
<template #rightToolBar>
|
||||
<TableRefresh @search="search()" />
|
||||
<TableSetting title="backup-account-refresh" @search="search()" />
|
||||
@@ -36,32 +39,21 @@
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('setting.bindNode')">
|
||||
<el-table-column :label="$t('setting.bindNode')" :min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.freeCount !== 0 && (row.status === 'Free' || row.status === 'Exceptional')">
|
||||
-
|
||||
</span>
|
||||
<div v-else>
|
||||
<span v-if="row.freeCount === 0">{{ row.bindNode || '-' }}</span>
|
||||
<div v-else>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
:width="120"
|
||||
trigger="hover"
|
||||
v-if="row.freeNodes && row.freeNodes.length != 0"
|
||||
>
|
||||
<div v-for="(item, index) of row.freeNodes" :key="index">
|
||||
<el-tag>{{ item.name }}</el-tag>
|
||||
</div>
|
||||
<template #reference>
|
||||
<el-button link type="primary">
|
||||
({{ row.bindCount }} / {{ row.freeCount }})
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<span v-else link type="primary">({{ row.bindCount }} / {{ row.freeCount }})</span>
|
||||
<div v-if="row.status !== 'Free'">
|
||||
<div>
|
||||
{{ $t('license.pro') }}:
|
||||
{{ row.bindNode === '127.0.0.1' ? $t('xpack.node.master') : row.bindNode }}
|
||||
</div>
|
||||
<div>
|
||||
{{ $t('license.oss') }}:
|
||||
<el-button class="bind-button" @click="onBindFree(row)" link type="primary">
|
||||
{{ row.bindCount }} / {{ row.freeCount }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@@ -82,7 +74,8 @@
|
||||
</LayoutContent>
|
||||
|
||||
<LicenseImport ref="licenseRef" />
|
||||
<LicenseBind ref="bindRef" />
|
||||
<BindFree ref="bindFreeRef" />
|
||||
<BindXpack ref="bindXpackRef" />
|
||||
<OpDialog ref="opRef" @search="search" />
|
||||
<OpDialog ref="opRef2" @search="search" @submit="submitUnbind">
|
||||
<template #content>
|
||||
@@ -103,17 +96,19 @@
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { deleteLicense, searchLicense, syncLicense, unbindLicense } from '@/api/modules/setting';
|
||||
import LicenseImport from '@/components/license-import/index.vue';
|
||||
import LicenseBind from '@/views/setting/license/bind/index.vue';
|
||||
import BindFree from '@/views/setting/license/bind/free.vue';
|
||||
import BindXpack from '@/views/setting/license/bind/xpack.vue';
|
||||
import { dateFormat } from '@/utils/util';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { initFavicon } from '@/utils/xpack';
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
const loading = ref();
|
||||
const licenseRef = ref();
|
||||
const bindRef = ref();
|
||||
const bindFreeRef = ref();
|
||||
const bindXpackRef = ref();
|
||||
const opRef = ref();
|
||||
const opRef2 = ref();
|
||||
const forceUnbind = ref();
|
||||
@@ -152,7 +147,19 @@ const onSync = async (row: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
const onBindFree = async (row: any) => {
|
||||
bindFreeRef.value.acceptParams({
|
||||
licenseID: row.id,
|
||||
licenseName: row.licenseName,
|
||||
freeNodes: row.freeNodes || [],
|
||||
});
|
||||
};
|
||||
|
||||
const onUnbind = async (row: any) => {
|
||||
if (row.freeNodes && (row.freeNodes.length > 1 || !row.freeNodes[0].isXpack)) {
|
||||
MsgError(i18n.global.t('license.licenseUnbindHelper'));
|
||||
return;
|
||||
}
|
||||
unbindRow.value = row;
|
||||
opRef2.value.acceptParams({
|
||||
title: i18n.global.t('commons.button.unbind'),
|
||||
@@ -242,7 +249,7 @@ const buttons = [
|
||||
return row.status !== 'Free';
|
||||
},
|
||||
click: (row: any) => {
|
||||
bindRef.value.acceptParams({ licenseID: row.id, licenseName: row.licenseName });
|
||||
bindXpackRef.value.acceptParams({ licenseID: row.id, licenseName: row.licenseName });
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -256,9 +263,6 @@ const buttons = [
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.edit'),
|
||||
disabled: (row: any) => {
|
||||
return row.status === 'Free';
|
||||
},
|
||||
click: (row: any) => {
|
||||
licenseRef.value.acceptParams({ oldLicense: row.licenseName });
|
||||
},
|
||||
@@ -293,3 +297,9 @@ onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bind-button {
|
||||
margin-top: -2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -374,8 +374,10 @@ const onReconnect = async (item: any) => {
|
||||
ctx.refs[`t-${item.index}`][0].acceptParams({
|
||||
endpoint: '/api/v2/core/hosts/terminal',
|
||||
args: `id=${item.wsID}`,
|
||||
initCmd: initCmd.value,
|
||||
error: res.data ? '' : 'Failed to set up the connection. Please check the host information',
|
||||
});
|
||||
initCmd.value = '';
|
||||
});
|
||||
syncTerminal();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user