guanghulab/docs/js/approval-ui.js
2026-05-10 13:12:44 +08:00

231 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 部署授权 UI · Phase 8
*
* 授权人在交互页面收到授权请求推送时,展示授权弹窗。
* 授权人必须主动点击确认,不回应视为不通过。
* 系统绝不自动跳过授权步骤。
*
* 版权:国作登字-2026-A-00037559
*/
/* global HOLOLAKE_ENV */
(function(window) {
'use strict';
var API_BASE = (typeof HOLOLAKE_ENV !== 'undefined' && HOLOLAKE_ENV === 'production')
? 'https://guanghulab.com/api' : '';
/**
* ApprovalUI 构造函数
*/
function ApprovalUI() {
this._pollTimer = null;
this._container = null;
}
/**
* 初始化:开始轮询待授权请求
* @param {string} devId - 当前登录的开发者编号
* @param {string} token - 认证 token
*/
ApprovalUI.prototype.init = function(devId, token) {
this.devId = devId;
this.token = token;
this._ensureContainer();
this._startPolling();
};
/**
* 确保授权容器存在
*/
ApprovalUI.prototype._ensureContainer = function() {
if (this._container) return;
this._container = document.createElement('div');
this._container.id = 'approval-container';
this._container.className = 'approval-container';
document.body.appendChild(this._container);
};
/**
* 开始轮询待授权请求(每 30 秒)
*/
ApprovalUI.prototype._startPolling = function() {
var self = this;
if (!API_BASE) return;
var poll = function() {
self._fetchPendingApprovals();
};
poll();
this._pollTimer = setInterval(poll, 30000);
};
/**
* 停止轮询
*/
ApprovalUI.prototype.destroy = function() {
if (this._pollTimer) {
clearInterval(this._pollTimer);
this._pollTimer = null;
}
};
/**
* 获取待处理的授权请求
*/
ApprovalUI.prototype._fetchPendingApprovals = function() {
var self = this;
if (!API_BASE) return;
fetch(API_BASE + '/approval', {
headers: {
'x-dev-id': this.devId,
'Authorization': 'Bearer ' + this.token
}
})
.then(function(res) { return res.json(); })
.then(function(data) {
if (data.success && data.pending && data.pending.length > 0) {
self._showApprovalBadge(data.pending.length);
self._renderPendingList(data.pending);
} else {
self._hideApprovalBadge();
}
})
.catch(function() { /* 静默失败 */ });
};
/**
* 显示授权提醒徽章
*/
ApprovalUI.prototype._showApprovalBadge = function(count) {
var badge = document.getElementById('approval-badge');
if (!badge) {
badge = document.createElement('div');
badge.id = 'approval-badge';
badge.className = 'approval-badge';
document.body.appendChild(badge);
}
badge.textContent = '🔔 ' + count + ' 个待授权';
badge.style.display = 'block';
var self = this;
badge.onclick = function() { self._togglePanel(); };
};
/**
* 隐藏授权徽章
*/
ApprovalUI.prototype._hideApprovalBadge = function() {
var badge = document.getElementById('approval-badge');
if (badge) badge.style.display = 'none';
if (this._container) this._container.style.display = 'none';
};
/**
* 切换授权面板显示
*/
ApprovalUI.prototype._togglePanel = function() {
if (this._container) {
this._container.style.display =
this._container.style.display === 'none' ? 'block' : 'none';
}
};
/**
* 渲染待授权列表
*/
ApprovalUI.prototype._renderPendingList = function(pending) {
if (!this._container) return;
var html = '<div class="approval-panel">' +
'<div class="approval-panel-header">' +
'<span>📋 待授权请求</span>' +
'<button class="approval-close-btn" id="approval-close">×</button>' +
'</div>' +
'<div class="approval-panel-body">';
for (var i = 0; i < pending.length; i++) {
var item = pending[i];
html += '<div class="approval-item" data-id="' + item.id + '">' +
'<div class="approval-item-info">' +
'<strong>' + item.module + '</strong>' +
'<span class="approval-channel">' + item.channel + '</span>' +
'<span class="approval-time">' + new Date(item.createdAt).toLocaleString('zh-CN') + '</span>' +
'</div>' +
'<div class="approval-item-actions">' +
'<button class="approval-btn approve" data-id="' + item.id + '" data-action="approved">✅ 授权通过</button>' +
'<button class="approval-btn reject" data-id="' + item.id + '" data-action="rejected">❌ 拒绝</button>' +
'</div></div>';
}
html += '</div></div>';
this._container.innerHTML = html;
this._container.style.display = 'block';
// 绑定事件
var self = this;
var closeBtn = document.getElementById('approval-close');
if (closeBtn) {
closeBtn.onclick = function() { self._container.style.display = 'none'; };
}
var buttons = this._container.querySelectorAll('.approval-btn');
for (var j = 0; j < buttons.length; j++) {
buttons[j].addEventListener('click', function() {
var approvalId = this.getAttribute('data-id');
var action = this.getAttribute('data-action');
self._submitDecision(approvalId, action);
});
}
};
/**
* 提交授权决定
*/
ApprovalUI.prototype._submitDecision = function(approvalId, decision) {
var self = this;
if (!API_BASE) return;
fetch(API_BASE + '/approval/' + approvalId + '/decide', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-dev-id': this.devId,
'Authorization': 'Bearer ' + this.token
},
body: JSON.stringify({ decision: decision })
})
.then(function(res) { return res.json(); })
.then(function(data) {
if (data.reply) {
self._showNotification(data.reply);
}
// 刷新列表
self._fetchPendingApprovals();
})
.catch(function(err) {
self._showNotification('❌ 操作失败:' + err.message);
});
};
/**
* 显示通知消息
*/
ApprovalUI.prototype._showNotification = function(message) {
var notif = document.createElement('div');
notif.className = 'approval-notification';
notif.textContent = message;
document.body.appendChild(notif);
setTimeout(function() {
notif.classList.add('fade-out');
setTimeout(function() { notif.remove(); }, 500);
}, 4000);
};
// 导出到全局
window.ApprovalUI = ApprovalUI;
})(window);