no message
This commit is contained in:
@@ -63,8 +63,13 @@
|
||||
await storage().set({ [ACTIVE_ENV_KEY]: envId });
|
||||
}
|
||||
|
||||
const MAX_ENVIRONMENTS = 5;
|
||||
|
||||
async function createEnvironment(name) {
|
||||
const { environments } = await loadEnvironments();
|
||||
if (environments.length >= MAX_ENVIRONMENTS) {
|
||||
throw new Error(`最多 ${MAX_ENVIRONMENTS} 个环境`);
|
||||
}
|
||||
const env = { id: genId(), name, configs: [] };
|
||||
environments.push(env);
|
||||
await saveEnvironments(environments, env.id);
|
||||
@@ -133,6 +138,7 @@
|
||||
return {
|
||||
ENV_KEY,
|
||||
ACTIVE_ENV_KEY,
|
||||
MAX_ENVIRONMENTS,
|
||||
loadEnvironments,
|
||||
saveEnvironments,
|
||||
getActiveEnv,
|
||||
|
||||
@@ -386,6 +386,13 @@ h2 {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-lock {
|
||||
position: fixed;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
@@ -422,57 +429,59 @@ h2 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.selector-help {
|
||||
.advanced-options {
|
||||
background: #16213e;
|
||||
border: 1px solid #0f3460;
|
||||
border-radius: 6px;
|
||||
padding: 8px 10px;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.selector-help summary {
|
||||
.advanced-options summary {
|
||||
cursor: pointer;
|
||||
color: #a0a0b0;
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
list-style: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.selector-help summary::-webkit-details-marker {
|
||||
.advanced-options summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selector-help summary::before {
|
||||
content: "▶ ";
|
||||
.advanced-options summary::before {
|
||||
content: "▶";
|
||||
color: #e94560;
|
||||
font-size: 10px;
|
||||
margin-right: 10px;
|
||||
transition: transform 0.2s;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.selector-help[open] summary::before {
|
||||
content: "▼ ";
|
||||
.advanced-options[open] summary::before {
|
||||
content: "▼";
|
||||
}
|
||||
|
||||
.selector-help-body {
|
||||
margin-top: 10px;
|
||||
padding-top: 8px;
|
||||
.advanced-options-body {
|
||||
margin-top: 12px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px dashed #0f3460;
|
||||
}
|
||||
|
||||
.selector-help-body p {
|
||||
.advanced-options-body p {
|
||||
font-size: 11px;
|
||||
line-height: 1.6;
|
||||
color: #a0a0b0;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.selector-help-body .help-tip {
|
||||
.advanced-options-body .help-tip {
|
||||
color: #e94560;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.selector-help-body code {
|
||||
.advanced-options-body code {
|
||||
background: #0f1d3a;
|
||||
padding: 1px 4px;
|
||||
border-radius: 3px;
|
||||
@@ -481,7 +490,7 @@ h2 {
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
}
|
||||
|
||||
.selector-help-body kbd {
|
||||
.advanced-options-body kbd {
|
||||
background: #0f1d3a;
|
||||
border: 1px solid #0f3460;
|
||||
border-radius: 3px;
|
||||
@@ -491,7 +500,7 @@ h2 {
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
}
|
||||
|
||||
.selector-help-body .icon-arrow {
|
||||
.advanced-options-body .icon-arrow {
|
||||
display: inline-block;
|
||||
padding: 1px 5px;
|
||||
background: #0f3460;
|
||||
@@ -500,7 +509,7 @@ h2 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.selector-help-body .rule-tag {
|
||||
.advanced-options-body .rule-tag {
|
||||
display: inline-block;
|
||||
padding: 1px 5px;
|
||||
margin: 0 2px;
|
||||
@@ -512,6 +521,14 @@ h2 {
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
}
|
||||
|
||||
.selector-tutorial {
|
||||
margin: 8px 0 10px;
|
||||
padding: 8px 10px;
|
||||
background: rgba(15, 52, 96, 0.25);
|
||||
border-left: 3px solid #0f3460;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.password-wrapper {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
@@ -697,6 +714,47 @@ h2 {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 空状态:缺省图标 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 32px 16px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
color: #0f3460;
|
||||
margin-bottom: 14px;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.empty-icon svg {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 14px;
|
||||
color: #a0a0b0;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.empty-sub {
|
||||
font-size: 11px;
|
||||
color: #555;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 禁用按钮 */
|
||||
.btn-io.btn-disabled,
|
||||
.btn-io:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
@@ -810,6 +868,70 @@ h2 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 环境管理对话框列表 */
|
||||
.env-manage-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
max-height: 280px;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.env-manage-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 10px;
|
||||
background: #16213e;
|
||||
border: 1px solid #0f3460;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.env-manage-row.active {
|
||||
border-color: #e94560;
|
||||
background: rgba(233, 69, 96, 0.08);
|
||||
}
|
||||
|
||||
.env-manage-name {
|
||||
font-size: 13px;
|
||||
color: #e0e0e0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.env-manage-count {
|
||||
color: #a0a0b0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.env-manage-active-mark {
|
||||
display: inline-block;
|
||||
padding: 1px 6px;
|
||||
background: #e94560;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.env-manage-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.env-manage-actions button {
|
||||
padding: 4px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.env-manage-empty {
|
||||
text-align: center;
|
||||
color: #a0a0b0;
|
||||
font-size: 12px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.strength-block {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
+32
-21
@@ -28,23 +28,21 @@
|
||||
|
||||
<div class="container" id="mainContainer" style="display:none;">
|
||||
<header>
|
||||
<button type="button" id="lockBtn" class="btn-lock" title="锁定(清除内存中的明文)">🔒</button>
|
||||
<div class="header-title">
|
||||
<img src="icons/icon128.png" alt="logo" class="header-logo">
|
||||
<h1>Auto Login Manager</h1>
|
||||
<button type="button" id="lockBtn" class="btn-lock" title="锁定(清除内存中的明文)">🔒 锁定</button>
|
||||
</div>
|
||||
<div class="env-bar">
|
||||
<label class="env-label">当前环境</label>
|
||||
<div class="env-controls">
|
||||
<select id="envSelect" class="env-select"></select>
|
||||
<button type="button" id="addEnvBtn" class="btn-env" title="新建环境">+</button>
|
||||
<button type="button" id="renameEnvBtn" class="btn-env" title="重命名当前环境">✎</button>
|
||||
<button type="button" id="deleteEnvBtn" class="btn-env btn-env-danger" title="删除当前环境">🗑</button>
|
||||
<button type="button" id="envManageBtn" class="btn-env" title="管理环境(新建 / 重命名 / 删除)">⚙</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="add-section">
|
||||
<section class="add-section" id="addSection">
|
||||
<h2>添加域名配置</h2>
|
||||
<div class="form-group">
|
||||
<label for="domain">域名 / URL 匹配规则</label>
|
||||
@@ -54,11 +52,6 @@
|
||||
</div>
|
||||
<small>支持通配符 *。带 / 时按 hostname+path 匹配,如 oa.com/login/*;不带 / 时只匹配域名</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="alias">别名(可选)</label>
|
||||
<input type="text" id="alias" placeholder="例如: 公司OA、GitLab、邮箱">
|
||||
<small>方便识别该配置,留空则显示域名</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" id="username" placeholder="输入用户名">
|
||||
@@ -70,38 +63,41 @@
|
||||
<button class="toggle-pwd" type="button" data-target="password">显示</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group form-group-inline">
|
||||
<div class="form-group">
|
||||
<label for="alias">别名(可选)</label>
|
||||
<input type="text" id="alias" placeholder="例如: 公司OA、GitLab、邮箱">
|
||||
<small>方便识别该配置,留空则显示域名</small>
|
||||
</div>
|
||||
<details class="advanced-options">
|
||||
<summary>高级选项(选填,默认即可)</summary>
|
||||
<div class="advanced-options-body">
|
||||
<div class="form-group">
|
||||
<label for="autoSubmit">自动提交登录</label>
|
||||
<select id="autoSubmit">
|
||||
<option value="true">是 - 自动点击登录按钮</option>
|
||||
<option value="false">否 - 仅填充不提交</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group form-group-inline">
|
||||
<label for="enabled">启用</label>
|
||||
<div class="form-group">
|
||||
<label for="enabled">启用 / 禁用</label>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="enabled" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
<small>关闭后该配置不再参与匹配(保留数据)</small>
|
||||
</div>
|
||||
<small>禁用后该条配置将不会生效</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="delayMs">填充延迟(毫秒,可选)</label>
|
||||
<input type="number" id="delayMs" min="0" max="10000" step="100" placeholder="留空=默认 300ms,可填 500-2000 用于 SPA 页面">
|
||||
<small>某些页面(Ant Design、ASP.NET)需 JS 初始化,立即填充会失效</small>
|
||||
</div>
|
||||
<details class="selector-help">
|
||||
<summary>高级选项:自定义输入框和登录按钮位置(选填)</summary>
|
||||
<div class="selector-help-body">
|
||||
<div class="selector-tutorial">
|
||||
<p class="help-tip">下面三项通常<strong>留空即可</strong>,插件会自动找到登录框。只有当自动填充失败、或填错位置时才需要填。</p>
|
||||
<p class="help-step">1. 在登录页面按 <kbd>F12</kbd> 打开开发者工具,切到"Elements(元素)"标签</p>
|
||||
<p class="help-step">2. 点开发者工具左上角的 <span class="icon-arrow">箭头图标</span>,再去点页面上的输入框/按钮</p>
|
||||
<p class="help-step">3. 工具会跳到对应的 HTML 行,在 <code><input></code> 或 <code><button></code> 标签上看 <code>id</code>、<code>name</code>、<code>class</code>、<code>type</code> 属性</p>
|
||||
<p class="help-step">4. 按 <span class="rule-tag">#id</span>、<span class="rule-tag">.class</span>、<span class="rule-tag">[name=xxx]</span>、<span class="rule-tag">tag[属性=值]</span> 规则组合填写即可</p>
|
||||
</div>
|
||||
</details>
|
||||
<div class="form-group">
|
||||
<label>用户名输入框位置</label>
|
||||
<input type="text" id="usernameSelector" placeholder="留空=自动查找,如 #username 或 input[name=account]">
|
||||
@@ -117,10 +113,12 @@
|
||||
<input type="text" id="submitSelector" placeholder="留空=自动查找,如 #loginBtn 或 button[type=submit]">
|
||||
<small>留空即可。填错会导致不会自动点击登录。</small>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
<button id="addBtn" class="btn-primary">添加配置</button>
|
||||
</section>
|
||||
|
||||
<section class="list-section">
|
||||
<section class="list-section" id="listSection">
|
||||
<div class="list-header">
|
||||
<h2>已配置域名</h2>
|
||||
<div class="list-actions">
|
||||
@@ -144,6 +142,19 @@
|
||||
|
||||
<div id="toast" class="toast"></div>
|
||||
|
||||
<!-- 环境管理对话框:列出所有环境,每行带编辑/删除,底部新建按钮 -->
|
||||
<div id="envManageModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h3>环境管理</h3>
|
||||
<div id="envManageList" class="env-manage-list"></div>
|
||||
<div class="modal-warn" id="envManageWarn" style="display:none;"></div>
|
||||
<div class="modal-actions">
|
||||
<button type="button" id="envManageClose" class="btn-edit">关闭</button>
|
||||
<button type="button" id="envManageAdd" class="btn-primary">+ 新建环境</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="envModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h3 id="envModalTitle">新建环境</h3>
|
||||
|
||||
@@ -13,6 +13,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const submitSelectorInput = $("submitSelector");
|
||||
const addBtn = $("addBtn");
|
||||
const configList = $("configList");
|
||||
const addSection = $("addSection");
|
||||
const listSection = $("listSection");
|
||||
const fillCurrentBtn = $("fillCurrent");
|
||||
const fillDomainBtn = $("fillDomain");
|
||||
const exportBtn = $("exportBtn");
|
||||
@@ -34,9 +36,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
// 环境栏
|
||||
const envSelect = $("envSelect");
|
||||
const addEnvBtn = $("addEnvBtn");
|
||||
const renameEnvBtn = $("renameEnvBtn");
|
||||
const deleteEnvBtn = $("deleteEnvBtn");
|
||||
const envManageBtn = $("envManageBtn");
|
||||
const envManageModal = $("envManageModal");
|
||||
const envManageList = $("envManageList");
|
||||
const envManageWarn = $("envManageWarn");
|
||||
const envManageClose = $("envManageClose");
|
||||
const envManageAdd = $("envManageAdd");
|
||||
const envModal = $("envModal");
|
||||
const envModalTitle = $("envModalTitle");
|
||||
const envNameInput = $("envNameInput");
|
||||
@@ -474,41 +479,72 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
showToast("已切换环境");
|
||||
});
|
||||
|
||||
addEnvBtn.addEventListener("click", async () => {
|
||||
const name = await openEnvModal("create");
|
||||
if (!name) return;
|
||||
await createEnvironment(name);
|
||||
await renderEnvSelect();
|
||||
resetForm();
|
||||
await renderConfigList();
|
||||
showToast(`已创建环境「${name}」`);
|
||||
});
|
||||
// ---------- 环境管理对话框 ----------
|
||||
function openEnvManageModal() {
|
||||
envManageWarn.textContent = "";
|
||||
envManageWarn.style.display = "none";
|
||||
renderEnvManageList();
|
||||
envManageModal.classList.add("show");
|
||||
}
|
||||
|
||||
renameEnvBtn.addEventListener("click", async () => {
|
||||
const env = await getActiveEnv();
|
||||
if (!env) return;
|
||||
const name = await openEnvModal("rename", env.name);
|
||||
if (!name) return;
|
||||
await renameEnvironment(env.id, name);
|
||||
function closeEnvManageModal() {
|
||||
envManageModal.classList.remove("show");
|
||||
}
|
||||
|
||||
async function renderEnvManageList() {
|
||||
const { environments, activeEnvId } = await loadEnvironments();
|
||||
envManageList.innerHTML = "";
|
||||
|
||||
if (environments.length === 0) {
|
||||
envManageList.innerHTML = '<div class="env-manage-empty">暂无环境</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
environments.forEach((env) => {
|
||||
const row = document.createElement("div");
|
||||
row.className = "env-manage-row" + (env.id === activeEnvId ? " active" : "");
|
||||
|
||||
const nameSpan = document.createElement("span");
|
||||
nameSpan.className = "env-manage-name";
|
||||
const cnt = env.configs?.length || 0;
|
||||
const activeMark = env.id === activeEnvId ? '<span class="env-manage-active-mark">当前</span>' : "";
|
||||
nameSpan.innerHTML = `${escapeHtml(env.name)} <span class="env-manage-count">(${cnt})</span> ${activeMark}`;
|
||||
|
||||
const actions = document.createElement("div");
|
||||
actions.className = "env-manage-actions";
|
||||
|
||||
const editBtn = document.createElement("button");
|
||||
editBtn.className = "btn-edit";
|
||||
editBtn.textContent = "重命名";
|
||||
editBtn.addEventListener("click", async () => {
|
||||
const newName = await openEnvModal("rename", env.name);
|
||||
if (!newName) return;
|
||||
try {
|
||||
await renameEnvironment(env.id, newName);
|
||||
await renderEnvManageList();
|
||||
await renderEnvSelect();
|
||||
showToast("已重命名");
|
||||
} catch (err) {
|
||||
showToast(err.message || "重命名失败");
|
||||
}
|
||||
});
|
||||
|
||||
deleteEnvBtn.addEventListener("click", async () => {
|
||||
const env = await getActiveEnv();
|
||||
if (!env) return;
|
||||
const { environments } = await loadEnvironments();
|
||||
const delBtn = document.createElement("button");
|
||||
delBtn.className = "btn-danger";
|
||||
delBtn.textContent = "删除";
|
||||
delBtn.addEventListener("click", async () => {
|
||||
if (environments.length <= 1) {
|
||||
showToast("至少保留一个环境");
|
||||
return;
|
||||
}
|
||||
const cnt = env.configs?.length || 0;
|
||||
const msg = cnt > 0
|
||||
? `环境「${env.name}」下有 ${cnt} 条配置,确认删除?(将一并删除这些配置)`
|
||||
const cnt2 = env.configs?.length || 0;
|
||||
const msg = cnt2 > 0
|
||||
? `环境「${env.name}」下有 ${cnt2} 条配置,确认删除?(将一并删除这些配置)`
|
||||
: `确认删除环境「${env.name}」?`;
|
||||
if (!confirm(msg)) return;
|
||||
try {
|
||||
await deleteEnvironment(env.id);
|
||||
await renderEnvManageList();
|
||||
await renderEnvSelect();
|
||||
resetForm();
|
||||
await renderConfigList();
|
||||
@@ -518,13 +554,65 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
});
|
||||
|
||||
actions.appendChild(editBtn);
|
||||
actions.appendChild(delBtn);
|
||||
row.appendChild(nameSpan);
|
||||
row.appendChild(actions);
|
||||
envManageList.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
envManageBtn.addEventListener("click", openEnvManageModal);
|
||||
envManageClose.addEventListener("click", closeEnvManageModal);
|
||||
|
||||
envManageAdd.addEventListener("click", async () => {
|
||||
const name = await openEnvModal("create");
|
||||
if (!name) return;
|
||||
try {
|
||||
await createEnvironment(name);
|
||||
await renderEnvManageList();
|
||||
await renderEnvSelect();
|
||||
resetForm();
|
||||
await renderConfigList();
|
||||
showToast(`已创建环境「${name}」`);
|
||||
} catch (err) {
|
||||
showToast(err.message || "创建失败");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
async function renderConfigList() {
|
||||
const configs = await loadConfigs();
|
||||
configList.innerHTML = "";
|
||||
|
||||
if (configs.length === 0) {
|
||||
configList.innerHTML = '<div class="empty-msg">暂无配置,请在上方添加</div>';
|
||||
// 配置为 0:禁用导出,列表在前;非 0:启用导出,添加表单在前
|
||||
const isEmpty = configs.length === 0;
|
||||
exportBtn.disabled = isEmpty;
|
||||
exportBtn.classList.toggle("btn-disabled", isEmpty);
|
||||
const parent = addSection.parentElement;
|
||||
if (isEmpty) {
|
||||
// 空状态:add-section 在上,list-section 在下(已是默认顺序,确保如此)
|
||||
if (parent.children[0] !== addSection) parent.insertBefore(addSection, listSection);
|
||||
} else {
|
||||
// 非空:list-section 在上,add-section 在下
|
||||
if (parent.children[0] !== listSection) parent.insertBefore(listSection, addSection);
|
||||
}
|
||||
|
||||
if (isEmpty) {
|
||||
configList.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">
|
||||
<svg viewBox="0 0 24 24" width="56" height="56" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="5" width="18" height="14" rx="2"/>
|
||||
<path d="M3 10h18"/>
|
||||
<circle cx="7" cy="14.5" r="0.6" fill="currentColor"/>
|
||||
<path d="M11 14.5h6"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="empty-text">暂无配置</div>
|
||||
<div class="empty-sub">在上方填写域名 / 用户名 / 密码后点击「添加配置」</div>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -562,6 +650,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
);
|
||||
await saveConfigs(updated);
|
||||
renderConfigList();
|
||||
renderEnvSelect();
|
||||
if (envManageModal.classList.contains("show")) renderEnvManageList();
|
||||
showToast(cfg.enabled === false ? "已启用" : "已禁用");
|
||||
});
|
||||
|
||||
@@ -593,6 +683,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
await saveConfigs(updated);
|
||||
showToast("已删除");
|
||||
renderConfigList();
|
||||
renderEnvSelect();
|
||||
if (envManageModal.classList.contains("show")) renderEnvManageList();
|
||||
if (editingId === cfg.id) {
|
||||
resetForm();
|
||||
}
|
||||
@@ -670,6 +762,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
await saveConfigs(configs);
|
||||
resetForm();
|
||||
renderConfigList();
|
||||
renderEnvSelect();
|
||||
if (envManageModal.classList.contains("show")) renderEnvManageList();
|
||||
});
|
||||
|
||||
fillCurrentBtn.addEventListener("click", async () => {
|
||||
@@ -689,21 +783,42 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
|
||||
if (matched.length === 1) {
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
try {
|
||||
const resp = await chrome.tabs.sendMessage(tab.id, {
|
||||
action: "manualFill",
|
||||
config: matched[0],
|
||||
});
|
||||
showToast("已发送填充指令");
|
||||
if (resp && resp.success) {
|
||||
showToast("已填充,请确认");
|
||||
} else {
|
||||
showToast("已发送但未找到登录表单,请确认页面已加载完成");
|
||||
}
|
||||
} catch (err) {
|
||||
// content script 未注入:常见于安装扩展前已打开的页面
|
||||
if (/Could not establish connection|Receiving end does not exist/i.test(err.message)) {
|
||||
showToast("页面未注入脚本,请刷新页面后重试");
|
||||
} else {
|
||||
showToast("发送失败:" + (err.message || err));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 多个环境命中:发到 content.js 由它弹选择菜单
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
try {
|
||||
await chrome.tabs.sendMessage(tab.id, {
|
||||
action: "manualFillMulti",
|
||||
configs: matched,
|
||||
tabUrl: tab.url,
|
||||
});
|
||||
showToast(`命中 ${matched.length} 个环境配置,请在页面选择`);
|
||||
} catch (err) {
|
||||
if (/Could not establish connection|Receiving end does not exist/i.test(err.message)) {
|
||||
showToast("页面未注入脚本,请刷新页面后重试");
|
||||
} else {
|
||||
showToast("发送失败:" + (err.message || err));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fillDomainBtn.addEventListener("click", async () => {
|
||||
|
||||
@@ -118,6 +118,18 @@ describe("env-store - 环境 CRUD", () => {
|
||||
const env = await EnvStore.getActiveEnv();
|
||||
assert.equal(env.id, "e3");
|
||||
});
|
||||
|
||||
it("超过 5 个环境时抛错", async () => {
|
||||
// 已有 3 个,再加 2 个到上限
|
||||
await EnvStore.createEnvironment("env4");
|
||||
await EnvStore.createEnvironment("env5");
|
||||
const { environments } = await EnvStore.loadEnvironments();
|
||||
assert.equal(environments.length, 5);
|
||||
// 第 6 个应被拒绝
|
||||
await assert.rejects(() => EnvStore.createEnvironment("env6"), /最多 5 个环境/);
|
||||
const after = await EnvStore.loadEnvironments();
|
||||
assert.equal(after.environments.length, 5);
|
||||
});
|
||||
});
|
||||
|
||||
describe("env-store - 配置 CRUD", () => {
|
||||
|
||||
Reference in New Issue
Block a user