Files
SMANAGE/TempLate/GERP/pages/system/tenant-review.html
T

198 lines
8.5 KiB
HTML

<style>
.tenant-review-page { padding: 24px; height: 100%; display: flex; flex-direction: column; box-sizing: border-box; }
.tenant-review-header { display: flex; align-items: center; margin-bottom: 16px; gap: 12px; flex-shrink: 0; }
.tenant-review-header h1 { margin: 0; flex: 1; }
.tenant-review-container { flex: 1; min-height: 0; overflow: auto; }
.tenant-review-list { display: grid; gap: 12px; }
.tenant-review-card { background: var(--CardBackground, #fff); border: 1px solid var(--BorderColor, #e2e8f0); border-radius: 10px; padding: 20px; display: flex; align-items: center; gap: 16px; }
.tenant-review-card .info { flex: 1; min-width: 0; }
.tenant-review-card .name { font-size: 16px; font-weight: 600; color: var(--TextPrimary, #1e293b); margin-bottom: 4px; }
.tenant-review-card .meta { font-size: 13px; color: var(--TextSecondary, #64748b); display: flex; gap: 16px; flex-wrap: wrap; }
.tenant-review-card .remark { font-size: 13px; color: var(--TextSecondary, #64748b); margin-top: 6px; padding: 8px 12px; background: var(--BgSecondary, #f8fafc); border-radius: 6px; }
.tenant-review-card .actions { display: flex; gap: 8px; flex-shrink: 0; }
.tenant-review-empty { text-align: center; padding: 60px 20px; color: var(--TextSecondary, #64748b); }
.tenant-review-empty i { font-size: 48px; margin-bottom: 12px; display: block; color: var(--TextTertiary, #94a3b8); }
.reject-modal { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: none; align-items: center; justify-content: center; z-index: 1000; }
.reject-modal.show { display: flex; }
.reject-modal-content { background: var(--CardBackground, #fff); border-radius: 12px; padding: 24px; max-width: 400px; width: 90%; }
.reject-modal-content h3 { margin: 0 0 16px; font-size: 16px; }
.reject-modal-content textarea { width: 100%; margin-bottom: 16px; resize: vertical; }
.reject-modal-content .actions { display: flex; gap: 8px; justify-content: flex-end; }
</style>
<div class="tenant-review-page">
<div class="tenant-review-header">
<h1 class="PageTitle">
<i class="fas fa-clipboard-check icon-primary icon-left-lg"></i>
<span>租户审核工作台</span>
</h1>
<button class="GERPBtn Secondary" onclick="loadPending()" style="display:flex;align-items:center;gap:6px;">
<i class="fas fa-sync"></i> 刷新
</button>
</div>
<div class="tenant-review-container">
<div class="tenant-review-list" id="pendingList"></div>
<div class="tenant-review-empty" id="emptyState" style="display:none;">
<i class="fas fa-inbox"></i>
<div>暂无待审核的租户申请</div>
</div>
<div id="errorState" style="display:none;color:var(--DangerColor);padding:40px;text-align:center;"></div>
</div>
</div>
<div class="reject-modal" id="rejectModal">
<div class="reject-modal-content">
<h3>拒绝入驻申请</h3>
<p style="font-size:13px;color:var(--TextSecondary);margin-bottom:12px;">租户:<span id="rejectTenantName"></span></p>
<textarea class="GERPInput" id="rejectReason" placeholder="请输入拒绝理由" rows="4"></textarea>
<div class="actions">
<button class="GERPBtn Secondary" onclick="closeRejectModal()">取消</button>
<button class="GERPBtn Danger" id="confirmRejectBtn" onclick="confirmReject()">确认拒绝</button>
</div>
</div>
</div>
<script>
let _pendingTenants = [];
let _rejectTargetUuid = null;
GERP.SetTitle('租户审核工作台');
async function loadPending() {
const listEl = document.getElementById('pendingList');
const emptyEl = document.getElementById('emptyState');
const errorEl = document.getElementById('errorState');
listEl.innerHTML = '';
emptyEl.style.display = 'none';
errorEl.style.display = 'none';
listEl.innerHTML = '<div style="text-align:center;padding:40px;color:var(--TextSecondary);"><i class="fas fa-spinner fa-spin"></i> 加载中...</div>';
try {
const resp = await fetch('/API/Tenant/Pending', { credentials: 'include' });
const result = await resp.json();
listEl.innerHTML = '';
if (result.code === 403) {
errorEl.textContent = '无权访问审核工作台';
errorEl.style.display = 'block';
return;
}
if (result.code !== 0) {
errorEl.textContent = result.msg || '加载失败';
errorEl.style.display = 'block';
return;
}
_pendingTenants = result.data || [];
if (_pendingTenants.length === 0) {
emptyEl.style.display = 'block';
return;
}
renderList();
} catch (err) {
listEl.innerHTML = '';
errorEl.textContent = '网络错误: ' + err.message;
errorEl.style.display = 'block';
}
}
function renderList() {
const listEl = document.getElementById('pendingList');
listEl.innerHTML = _pendingTenants.map(t => `
<div class="tenant-review-card">
<div class="info">
<div class="name">${escapeHtml(t.TenantName)}</div>
<div class="meta">
<span><i class="fas fa-calendar"></i> 有效期: ${formatTime(t.TenantExpireTime)}</span>
<span><i class="fas fa-clock"></i> 申请时间: ${formatTime(t.CreateTime)}</span>
</div>
${t.ReviewRemark ? `<div class="remark"><i class="fas fa-comment"></i> ${escapeHtml(t.ReviewRemark)}</div>` : ''}
</div>
<div class="actions">
<button class="GERPBtn Primary" onclick="approveTenant('${t.TenantUUID}')">
<i class="fas fa-check"></i> 批准
</button>
<button class="GERPBtn Danger" onclick="openRejectModal('${t.TenantUUID}', '${escapeHtml(t.TenantName)}')">
<i class="fas fa-times"></i> 拒绝
</button>
</div>
</div>
`).join('');
}
async function approveTenant(uuid) {
if (!confirm('确认批准该租户入驻申请?')) return;
try {
const resp = await fetch(`/API/Tenant/Approve/${uuid}`, {
method: 'POST',
credentials: 'include',
});
const result = await resp.json();
if (result.code === 0) {
if (window.GERPLayui) GERPLayui.Toast('审核通过', 'success');
loadPending();
} else {
if (window.GERPLayui) GERPLayui.Toast(result.msg || '操作失败', 'error');
}
} catch (err) {
if (window.GERPLayui) GERPLayui.Toast('网络错误: ' + err.message, 'error');
}
}
function openRejectModal(uuid, name) {
_rejectTargetUuid = uuid;
document.getElementById('rejectTenantName').textContent = name;
document.getElementById('rejectReason').value = '';
document.getElementById('rejectModal').classList.add('show');
}
function closeRejectModal() {
_rejectTargetUuid = null;
document.getElementById('rejectModal').classList.remove('show');
}
async function confirmReject() {
if (!_rejectTargetUuid) return;
const reason = document.getElementById('rejectReason').value.trim();
if (!reason) {
if (window.GERPLayui) GERPLayui.Toast('请输入拒绝理由', 'warning');
return;
}
const btn = document.getElementById('confirmRejectBtn');
btn.disabled = true;
btn.textContent = '处理中...';
try {
const resp = await fetch(`/API/Tenant/Reject/${_rejectTargetUuid}`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ReviewRemark: reason })
});
const result = await resp.json();
btn.disabled = false;
btn.textContent = '确认拒绝';
if (result.code === 0) {
if (window.GERPLayui) GERPLayui.Toast('已拒绝申请', 'success');
closeRejectModal();
loadPending();
} else {
if (window.GERPLayui) GERPLayui.Toast(result.msg || '操作失败', 'error');
}
} catch (err) {
btn.disabled = false;
btn.textContent = '确认拒绝';
if (window.GERPLayui) GERPLayui.Toast('网络错误: ' + err.message, 'error');
}
}
function escapeHtml(str) {
if (!str) return '';
return String(str).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
}
function formatTime(t) {
if (!t) return '-';
return t.replace('T', ' ').substring(0, 19);
}
loadPending();
</script>