add licensed random user creation flow
This commit is contained in:
@@ -10,6 +10,8 @@ const state = {
|
||||
const elements = {
|
||||
userList: document.getElementById('user-list'),
|
||||
userCount: document.getElementById('user-count'),
|
||||
createUser: document.getElementById('create-user'),
|
||||
sidebarStatus: document.getElementById('sidebar-status'),
|
||||
searchInput: document.getElementById('search-input'),
|
||||
refreshUsers: document.getElementById('refresh-users'),
|
||||
refreshMail: document.getElementById('refresh-mail'),
|
||||
@@ -56,6 +58,16 @@ function clearStatus() {
|
||||
elements.mailStatus.className = 'status hidden';
|
||||
}
|
||||
|
||||
function setSidebarStatus(message, tone = 'neutral') {
|
||||
elements.sidebarStatus.textContent = message;
|
||||
elements.sidebarStatus.className = `sidebar-status ${tone}`;
|
||||
}
|
||||
|
||||
function clearSidebarStatus() {
|
||||
elements.sidebarStatus.textContent = '';
|
||||
elements.sidebarStatus.className = 'sidebar-status hidden';
|
||||
}
|
||||
|
||||
function renderUserList() {
|
||||
elements.userCount.textContent = `共 ${state.filteredUsers.length} 个账号`;
|
||||
|
||||
@@ -184,8 +196,8 @@ function renderMessage(message) {
|
||||
renderMessageBody(message);
|
||||
}
|
||||
|
||||
async function requestJson(url) {
|
||||
const response = await fetch(url);
|
||||
async function requestJson(url, init) {
|
||||
const response = await fetch(url, init);
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
|
||||
if (response.status === 401) {
|
||||
@@ -237,6 +249,56 @@ async function loadUsers() {
|
||||
}
|
||||
}
|
||||
|
||||
function wait(ms) {
|
||||
return new Promise((resolve) => {
|
||||
window.setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
async function refreshUsersUntilPresent(userPrincipalName, attempts = 6) {
|
||||
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
||||
await loadUsers();
|
||||
|
||||
const createdUser = state.users.find((user) => user.userPrincipalName === userPrincipalName);
|
||||
if (createdUser) {
|
||||
return createdUser;
|
||||
}
|
||||
|
||||
if (attempt < attempts - 1) {
|
||||
await wait(1500);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function createRandomUser() {
|
||||
elements.createUser.disabled = true;
|
||||
setSidebarStatus('正在创建随机用户...', 'loading');
|
||||
|
||||
try {
|
||||
const payload = await requestJson('/api/users/random', {
|
||||
method: 'POST',
|
||||
});
|
||||
setSidebarStatus('用户已创建,正在同步账号列表...', 'loading');
|
||||
|
||||
const createdUser = await refreshUsersUntilPresent(payload.user.userPrincipalName);
|
||||
if (createdUser) {
|
||||
state.selectedUser = createdUser;
|
||||
renderUserList();
|
||||
setSidebarStatus(`已创建: ${payload.user.userPrincipalName}`, 'success');
|
||||
await loadLatestEmail(createdUser.id);
|
||||
return;
|
||||
}
|
||||
|
||||
setSidebarStatus(`用户已创建,但列表尚未同步: ${payload.user.userPrincipalName}`, 'warning');
|
||||
} catch (error) {
|
||||
setSidebarStatus(error.message, 'warning');
|
||||
} finally {
|
||||
elements.createUser.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadLatestEmail(userId) {
|
||||
const user = state.users.find((entry) => entry.id === userId);
|
||||
|
||||
@@ -297,6 +359,10 @@ elements.refreshUsers.addEventListener('click', () => {
|
||||
loadUsers();
|
||||
});
|
||||
|
||||
elements.createUser.addEventListener('click', () => {
|
||||
createRandomUser();
|
||||
});
|
||||
|
||||
elements.refreshMail.addEventListener('click', () => {
|
||||
if (state.selectedUser) {
|
||||
loadLatestEmail(state.selectedUser.id);
|
||||
|
||||
@@ -11,8 +11,12 @@
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<p class="eyebrow">Microsoft 365</p>
|
||||
<h1>邮箱控制台</h1>
|
||||
<div class="sidebar-title-row">
|
||||
<h1>邮箱控制台</h1>
|
||||
<button id="create-user" type="button">随机建号</button>
|
||||
</div>
|
||||
<p class="sidebar-copy">列出租户账号,点击后读取该账号收件箱中的最新一封邮件。</p>
|
||||
<p id="sidebar-status" class="sidebar-status hidden"></p>
|
||||
</div>
|
||||
|
||||
<label class="search-box" for="search-input">
|
||||
|
||||
@@ -62,11 +62,41 @@ input {
|
||||
.user-address,
|
||||
.user-meta,
|
||||
.user-empty,
|
||||
.sidebar-status,
|
||||
.status,
|
||||
.empty-block p {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.sidebar-title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.sidebar-title-row button {
|
||||
padding: 9px 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar-status {
|
||||
margin: 12px 0 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.sidebar-status.loading {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.sidebar-status.success {
|
||||
color: #9fe8b2;
|
||||
}
|
||||
|
||||
.sidebar-status.warning {
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 8px;
|
||||
color: var(--accent);
|
||||
@@ -292,4 +322,9 @@ a {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar-title-row {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user