320 lines
14 KiB
HTML
320 lines
14 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Office 365 User Management Platform</title>
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||
</head>
|
||
<body>
|
||
<div class="background-glow glow-a"></div>
|
||
<div class="background-glow glow-b"></div>
|
||
<div class="shell">
|
||
<header class="hero">
|
||
<div class="hero-copy">
|
||
<p class="eyebrow">Microsoft Graph + Web Console</p>
|
||
<h1>Office 365 账号管理平台</h1>
|
||
<p class="hero-text">
|
||
基于你提供的 <code>office365-tools</code> 能力升级而来,当前默认按国际版 Microsoft 365 / Microsoft Graph 工作,支持账号单个与批量增删改查、许可证查看、密码重置与批处理回显。
|
||
</p>
|
||
</div>
|
||
<div class="hero-side">
|
||
<div class="status-card">
|
||
<span class="status-label">平台状态</span>
|
||
<strong id="platform-status">检测中</strong>
|
||
<span id="platform-substatus" class="muted">正在读取配置</span>
|
||
</div>
|
||
<div class="hero-actions">
|
||
<button id="refresh-all-btn" class="btn btn-secondary">刷新数据</button>
|
||
<button id="logout-btn" class="btn btn-ghost">退出</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="dashboard">
|
||
<section id="login-section" class="panel panel-login hidden">
|
||
<div class="panel-head">
|
||
<div>
|
||
<h2>后台登录</h2>
|
||
<p>如果启用了平台登录保护,请先输入后台管理员账号。</p>
|
||
</div>
|
||
</div>
|
||
<form id="login-form" class="inline-form">
|
||
<label>
|
||
<span>用户名</span>
|
||
<input id="login-username" name="username" autocomplete="username" required>
|
||
</label>
|
||
<label>
|
||
<span>密码</span>
|
||
<input id="login-password" name="password" type="password" autocomplete="current-password" required>
|
||
</label>
|
||
<button class="btn btn-primary" type="submit">登录平台</button>
|
||
</form>
|
||
</section>
|
||
|
||
<section class="metrics">
|
||
<article class="metric-card">
|
||
<span class="metric-label">匹配用户数</span>
|
||
<strong id="metric-total">0</strong>
|
||
<span class="metric-foot" id="metric-total-foot">当前筛选结果</span>
|
||
</article>
|
||
<article class="metric-card">
|
||
<span class="metric-label">启用账号</span>
|
||
<strong id="metric-active">0</strong>
|
||
<span class="metric-foot">accountEnabled = true</span>
|
||
</article>
|
||
<article class="metric-card">
|
||
<span class="metric-label">停用账号</span>
|
||
<strong id="metric-disabled">0</strong>
|
||
<span class="metric-foot">便于快速排查离职或冻结账号</span>
|
||
</article>
|
||
<article class="metric-card">
|
||
<span class="metric-label">可用许可证</span>
|
||
<strong id="metric-license">0</strong>
|
||
<span class="metric-foot">来自当前租户订阅</span>
|
||
</article>
|
||
</section>
|
||
|
||
<section class="panel panel-users">
|
||
<div class="panel-head">
|
||
<div>
|
||
<h2>用户列表</h2>
|
||
<p>支持搜索、查看详情、全选当前页或全部搜索结果,并执行批量删除 / 启停 / 改密。</p>
|
||
</div>
|
||
<form id="search-form" class="search-form">
|
||
<input id="search-input" placeholder="搜索邮箱、显示名、部门、职位">
|
||
<button class="btn btn-secondary" type="submit">搜索</button>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="selection-toolbar">
|
||
<div class="selection-meta">
|
||
<span id="selected-count" class="tag">未选择账号</span>
|
||
<button id="select-all-results-btn" class="btn btn-ghost" type="button">选中全部搜索结果</button>
|
||
<button id="clear-selection-btn" class="btn btn-ghost" type="button">清空选择</button>
|
||
</div>
|
||
<div class="selection-actions">
|
||
<button id="bulk-enable-btn" class="btn btn-secondary" type="button">批量启用</button>
|
||
<button id="bulk-disable-btn" class="btn btn-secondary" type="button">批量停用</button>
|
||
<button id="bulk-reset-btn" class="btn btn-secondary" type="button">批量改密</button>
|
||
<button id="bulk-delete-btn" class="btn btn-danger" type="button">批量删除</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th class="check-col">
|
||
<label class="table-checkbox">
|
||
<input id="select-page-checkbox" type="checkbox">
|
||
<span>全选</span>
|
||
</label>
|
||
</th>
|
||
<th>显示名</th>
|
||
<th>登录名</th>
|
||
<th>部门 / 职位</th>
|
||
<th>状态</th>
|
||
<th>许可证</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="users-table-body">
|
||
<tr>
|
||
<td colspan="7" class="empty-cell">暂无数据</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="table-footer">
|
||
<span id="pagination-info" class="muted">第 1 页</span>
|
||
<div class="pager">
|
||
<button id="prev-page-btn" class="btn btn-ghost" type="button">上一页</button>
|
||
<button id="next-page-btn" class="btn btn-ghost" type="button">下一页</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel panel-editor">
|
||
<div class="panel-head">
|
||
<div>
|
||
<h2>单个账号维护</h2>
|
||
<p>新建账号时支持只填用户名;若配置了 <code>DEFAULT_DOMAIN</code>,系统会自动补全 UPN。</p>
|
||
</div>
|
||
<div class="editor-actions">
|
||
<button id="new-user-btn" class="btn btn-secondary" type="button">新建用户</button>
|
||
<button id="delete-user-btn" class="btn btn-danger" type="button">删除当前</button>
|
||
</div>
|
||
</div>
|
||
|
||
<form id="user-form" class="user-form">
|
||
<input id="selected-user-id" type="hidden">
|
||
<label>
|
||
<span>账号 / 邮箱</span>
|
||
<input id="userPrincipalName" name="userPrincipalName" required>
|
||
</label>
|
||
<label>
|
||
<span>显示名</span>
|
||
<input id="displayName" name="displayName">
|
||
</label>
|
||
<label>
|
||
<span>名字</span>
|
||
<input id="givenName" name="givenName">
|
||
</label>
|
||
<label>
|
||
<span>姓氏</span>
|
||
<input id="surname" name="surname">
|
||
</label>
|
||
<label>
|
||
<span>部门</span>
|
||
<input id="department" name="department">
|
||
</label>
|
||
<label>
|
||
<span>职位</span>
|
||
<input id="jobTitle" name="jobTitle">
|
||
</label>
|
||
<label>
|
||
<span>办公地点</span>
|
||
<input id="officeLocation" name="officeLocation">
|
||
</label>
|
||
<label>
|
||
<span>手机号</span>
|
||
<input id="mobilePhone" name="mobilePhone">
|
||
</label>
|
||
<label>
|
||
<span>使用地区</span>
|
||
<input id="usageLocation" name="usageLocation" placeholder="US">
|
||
</label>
|
||
<label>
|
||
<span>许可证 SKU</span>
|
||
<input id="skuPartNumber" name="skuPartNumber" placeholder="如 O365_BUSINESS">
|
||
</label>
|
||
<label>
|
||
<span>临时密码</span>
|
||
<input id="password" name="password" type="password" placeholder="不填则使用默认密码">
|
||
</label>
|
||
<label class="checkbox">
|
||
<input id="accountEnabled" name="accountEnabled" type="checkbox" checked>
|
||
<span>启用账号</span>
|
||
</label>
|
||
<label class="checkbox">
|
||
<input id="forceChangePasswordNextSignIn" name="forceChangePasswordNextSignIn" type="checkbox" checked>
|
||
<span>首次登录强制改密</span>
|
||
</label>
|
||
<div class="form-actions">
|
||
<button id="save-user-btn" class="btn btn-primary" type="submit">保存用户</button>
|
||
<button id="reset-password-btn" class="btn btn-secondary" type="button">重置密码</button>
|
||
<button id="clear-form-btn" class="btn btn-ghost" type="button">清空表单</button>
|
||
</div>
|
||
</form>
|
||
</section>
|
||
|
||
<section class="panel panel-license">
|
||
<div class="panel-head">
|
||
<div>
|
||
<h2>许可证概览</h2>
|
||
<p>实时读取租户已订阅 SKU 和剩余席位。</p>
|
||
</div>
|
||
</div>
|
||
<div id="license-list" class="license-list">
|
||
<div class="empty-card">正在加载许可证信息...</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel panel-batch">
|
||
<div class="panel-head">
|
||
<div>
|
||
<h2>批量管理中心</h2>
|
||
<p>支持 CSV 或 JSON。删除也支持纯文本,一行一个账号。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="batch-grid">
|
||
<article class="batch-card">
|
||
<div class="batch-card-top">
|
||
<div>
|
||
<h3>批量创建</h3>
|
||
<p>先下载示例 CSV,编辑后再上传执行。</p>
|
||
</div>
|
||
<a class="btn btn-ghost" href="{{ url_for('static', filename='examples/batch-create-template.csv') }}" download>下载示例 CSV</a>
|
||
</div>
|
||
<p>CSV 表头示例:<code>userPrincipalName,displayName,givenName,surname,department,jobTitle,usageLocation,skuPartNumber,password</code></p>
|
||
<input data-target="batch-create-content" class="file-input" type="file" accept=".csv,.json,.txt">
|
||
<textarea id="batch-create-content" placeholder='或直接粘贴 JSON 数组 / CSV 内容'></textarea>
|
||
<button data-batch-action="create" class="btn btn-primary" type="button">执行批量创建</button>
|
||
</article>
|
||
|
||
<article class="batch-card">
|
||
<div class="batch-card-top">
|
||
<div>
|
||
<h3>批量更新</h3>
|
||
<p>下载模板后只改需要更新的列,再上传执行。</p>
|
||
</div>
|
||
<a class="btn btn-ghost" href="{{ url_for('static', filename='examples/batch-update-template.csv') }}" download>下载示例 CSV</a>
|
||
</div>
|
||
<p>CSV 至少需要一列账号标识。空值默认忽略,不会清空原字段。</p>
|
||
<input data-target="batch-update-content" class="file-input" type="file" accept=".csv,.json,.txt">
|
||
<textarea id="batch-update-content" placeholder='示例:userPrincipalName,department,jobTitle,accountEnabled'></textarea>
|
||
<button data-batch-action="update" class="btn btn-primary" type="button">执行批量更新</button>
|
||
</article>
|
||
|
||
<article class="batch-card">
|
||
<div class="batch-card-top">
|
||
<div>
|
||
<h3>批量删除</h3>
|
||
<p>可以直接下载删除模板,编辑后上传执行。</p>
|
||
</div>
|
||
<a class="btn btn-ghost" href="{{ url_for('static', filename='examples/batch-delete-template.csv') }}" download>下载示例 CSV</a>
|
||
</div>
|
||
<p>支持 CSV/JSON,也支持纯文本,一行一个 UPN 或用户名。</p>
|
||
<input data-target="batch-delete-content" class="file-input" type="file" accept=".csv,.json,.txt">
|
||
<textarea id="batch-delete-content" placeholder="alice bob@contoso.com"></textarea>
|
||
<button data-batch-action="delete" class="btn btn-danger" type="button">执行批量删除</button>
|
||
</article>
|
||
|
||
<article class="batch-card">
|
||
<div class="batch-card-top">
|
||
<div>
|
||
<h3>批量重置密码</h3>
|
||
<p>可先下载模板,编辑密码后上传执行。</p>
|
||
</div>
|
||
<a class="btn btn-ghost" href="{{ url_for('static', filename='examples/batch-reset-password-template.csv') }}" download>下载示例 CSV</a>
|
||
</div>
|
||
<p>可使用纯文本账号列表,也可传入 CSV:<code>userPrincipalName,password,forceChangePasswordNextSignIn</code></p>
|
||
<input data-target="batch-reset-content" class="file-input" type="file" accept=".csv,.json,.txt">
|
||
<textarea id="batch-reset-content" placeholder="一行一个账号,默认使用系统默认密码"></textarea>
|
||
<button data-batch-action="reset-password" class="btn btn-secondary" type="button">执行批量改密</button>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="panel panel-console">
|
||
<div class="panel-head">
|
||
<div>
|
||
<h2>执行结果</h2>
|
||
<p>界面只展示简要摘要,详细逐条处理信息写入服务日志。</p>
|
||
</div>
|
||
</div>
|
||
<div id="task-status-card" class="task-status-card hidden">
|
||
<div class="task-status-head">
|
||
<strong id="task-status-title">暂无任务</strong>
|
||
<span id="task-status-state" class="tag">待命</span>
|
||
</div>
|
||
<div class="task-progress-track">
|
||
<div id="task-progress-fill" class="task-progress-fill"></div>
|
||
</div>
|
||
<div id="task-status-text" class="muted">等待任务提交</div>
|
||
</div>
|
||
<pre id="result-console" class="console">等待操作...</pre>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
window.APP_BOOTSTRAP = {{ bootstrap | tojson }};
|
||
</script>
|
||
<script src="{{ url_for('static', filename='app.js') }}"></script>
|
||
</body>
|
||
</html>
|