1111
This commit is contained in:
@@ -294,7 +294,6 @@ h2 {
|
|||||||
.lock-screen {
|
.lock-screen {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
background: #0f0f1e;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -306,7 +305,6 @@ h2 {
|
|||||||
max-width: 320px;
|
max-width: 320px;
|
||||||
padding: 28px 24px;
|
padding: 28px 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
box-shadow: 0 8px 32px rgba(233, 69, 96, 0.15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lock-logo {
|
.lock-logo {
|
||||||
@@ -893,6 +891,21 @@ h2 {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 编辑域名配置对话框:字段较多,允许滚动并加宽 */
|
||||||
|
.edit-config-content {
|
||||||
|
max-width: 380px;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-config-content .modal-actions {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
background: #16213e;
|
||||||
|
padding-top: 10px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
/* 环境管理对话框列表 */
|
/* 环境管理对话框列表 */
|
||||||
.env-manage-list {
|
.env-manage-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
+69
@@ -223,6 +223,75 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑域名配置对话框 -->
|
||||||
|
<div id="editConfigModal" class="modal">
|
||||||
|
<div class="modal-content edit-config-content">
|
||||||
|
<h3 data-i18n="editConfigTitle">编辑域名配置</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="editDomain" data-i18n="domainLabel">域名 / URL 匹配规则</label>
|
||||||
|
<input type="text" id="editDomain" data-i18n-placeholder="domainPlaceholder" placeholder="example.com 或 *.example.com 或 site.com/admin/*">
|
||||||
|
<small data-i18n="domainHelp">支持通配符 *。带 / 时按 hostname+path 匹配,如 oa.com/login/*;不带 / 时只匹配域名</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="editUsername" data-i18n="usernameLabel">用户名</label>
|
||||||
|
<input type="text" id="editUsername" data-i18n-placeholder="usernamePlaceholder" placeholder="输入用户名">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="editPassword" data-i18n="passwordLabel">密码</label>
|
||||||
|
<div class="password-wrapper">
|
||||||
|
<input type="password" id="editPassword" data-i18n-placeholder="passwordPlaceholder" placeholder="输入密码">
|
||||||
|
<button class="toggle-pwd eye-open" type="button" data-target="editPassword" data-i18n-aria="togglePwdAria" aria-label="切换密码显示">👁</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="editAlias" data-i18n="aliasLabel">别名(可选)</label>
|
||||||
|
<input type="text" id="editAlias" data-i18n-placeholder="aliasPlaceholder" placeholder="例如: 公司OA、GitLab、邮箱">
|
||||||
|
<small data-i18n="aliasHelp">方便识别该配置,留空则显示域名</small>
|
||||||
|
</div>
|
||||||
|
<details class="advanced-options">
|
||||||
|
<summary data-i18n="advancedOptionsSummary">高级选项(选填,默认即可)</summary>
|
||||||
|
<div class="advanced-options-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="editAutoSubmit" data-i18n="autoSubmitLabel">自动提交登录</label>
|
||||||
|
<select id="editAutoSubmit">
|
||||||
|
<option value="true" data-i18n="autoSubmitYes">是 - 自动点击登录按钮</option>
|
||||||
|
<option value="false" data-i18n="autoSubmitNo">否 - 仅填充不提交</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="editEnabled" data-i18n="enabledLabel">启用 / 禁用</label>
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="editEnabled" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
<small data-i18n="enabledHelp">禁用后该条配置将不会生效</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="editDelayMs" data-i18n="delayMsLabel">填充延迟(毫秒,可选)</label>
|
||||||
|
<input type="number" id="editDelayMs" min="0" max="10000" step="100" data-i18n-placeholder="delayMsPlaceholder" placeholder="留空=默认 300ms,可填 500-2000 用于 SPA 页面">
|
||||||
|
<small data-i18n="delayMsHelp">某些页面(Ant Design、ASP.NET)需 JS 初始化,立即填充会失效</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label data-i18n="usernameSelectorLabel">用户名输入框位置</label>
|
||||||
|
<input type="text" id="editUsernameSelector" data-i18n-placeholder="usernameSelectorPlaceholder" placeholder="留空=自动查找,如 #username 或 input[name=account]">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label data-i18n="passwordSelectorLabel">密码输入框位置</label>
|
||||||
|
<input type="text" id="editPasswordSelector" data-i18n-placeholder="passwordSelectorPlaceholder" placeholder="留空=自动查找,如 #password 或 input[type=password]">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label data-i18n="submitSelectorLabel">登录按钮位置</label>
|
||||||
|
<input type="text" id="editSubmitSelector" data-i18n-placeholder="submitSelectorPlaceholder" placeholder="留空=自动查找,如 #loginBtn 或 button[type=submit]">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button type="button" id="editConfigCancel" class="btn-edit" data-i18n="cancelBtn">取消</button>
|
||||||
|
<button type="button" id="editConfigSave" class="btn-primary" data-i18n="updateConfigBtn">更新配置</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="utils.js"></script>
|
<script src="utils.js"></script>
|
||||||
<script src="env-store.js"></script>
|
<script src="env-store.js"></script>
|
||||||
<script src="crypto-store.js"></script>
|
<script src="crypto-store.js"></script>
|
||||||
|
|||||||
@@ -66,6 +66,22 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
const importFile = $("importFile");
|
const importFile = $("importFile");
|
||||||
const toast = $("toast");
|
const toast = $("toast");
|
||||||
|
|
||||||
|
// 编辑配置弹窗
|
||||||
|
const editConfigModal = $("editConfigModal");
|
||||||
|
const editDomainInput = $("editDomain");
|
||||||
|
const editUsernameInput = $("editUsername");
|
||||||
|
const editPasswordInput = $("editPassword");
|
||||||
|
const editAliasInput = $("editAlias");
|
||||||
|
const editAutoSubmitSelect = $("editAutoSubmit");
|
||||||
|
const editEnabledCheckbox = $("editEnabled");
|
||||||
|
const editDelayMsInput = $("editDelayMs");
|
||||||
|
const editUsernameSelectorInput = $("editUsernameSelector");
|
||||||
|
const editPasswordSelectorInput = $("editPasswordSelector");
|
||||||
|
const editSubmitSelectorInput = $("editSubmitSelector");
|
||||||
|
const editConfigCancel = $("editConfigCancel");
|
||||||
|
const editConfigSave = $("editConfigSave");
|
||||||
|
let editModalEditingId = null;
|
||||||
|
|
||||||
// 锁定界面
|
// 锁定界面
|
||||||
const lockScreen = $("lockScreen");
|
const lockScreen = $("lockScreen");
|
||||||
const mainContainer = $("mainContainer");
|
const mainContainer = $("mainContainer");
|
||||||
@@ -429,10 +445,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
submitSelectorInput.value = draft.submitSelector || "";
|
submitSelectorInput.value = draft.submitSelector || "";
|
||||||
enabledCheckbox.checked = draft.enabled !== false;
|
enabledCheckbox.checked = draft.enabled !== false;
|
||||||
delayMsInput.value = draft.delayMs || "";
|
delayMsInput.value = draft.delayMs || "";
|
||||||
editingId = draft.editingId || null;
|
editingId = null;
|
||||||
addBtn.textContent = editingId ? t("updateConfigBtn") : t("addConfigBtn");
|
// 编辑已改为弹窗,顶部表单仅用于新增;忽略历史 draft 中的 editingId
|
||||||
addConfigTitleEl.textContent = editingId ? t("editConfigTitle") : t("addConfigTitle");
|
addBtn.textContent = t("addConfigBtn");
|
||||||
cancelEditBtn.hidden = !editingId;
|
addConfigTitleEl.textContent = t("addConfigTitle");
|
||||||
|
cancelEditBtn.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearDraft() {
|
function clearDraft() {
|
||||||
@@ -706,22 +723,19 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
editBtn.className = "btn-edit";
|
editBtn.className = "btn-edit";
|
||||||
editBtn.textContent = t("editBtn");
|
editBtn.textContent = t("editBtn");
|
||||||
editBtn.addEventListener("click", () => {
|
editBtn.addEventListener("click", () => {
|
||||||
editingId = cfg.id;
|
editModalEditingId = cfg.id;
|
||||||
domainInput.value = cfg.domain;
|
editDomainInput.value = cfg.domain;
|
||||||
aliasInput.value = cfg.alias || "";
|
editAliasInput.value = cfg.alias || "";
|
||||||
usernameInput.value = cfg.username;
|
editUsernameInput.value = cfg.username;
|
||||||
passwordInput.value = cfg.password;
|
editPasswordInput.value = cfg.password;
|
||||||
autoSubmitSelect.value = String(cfg.autoSubmit);
|
editAutoSubmitSelect.value = String(cfg.autoSubmit);
|
||||||
usernameSelectorInput.value = cfg.usernameSelector || "";
|
editUsernameSelectorInput.value = cfg.usernameSelector || "";
|
||||||
passwordSelectorInput.value = cfg.passwordSelector || "";
|
editPasswordSelectorInput.value = cfg.passwordSelector || "";
|
||||||
submitSelectorInput.value = cfg.submitSelector || "";
|
editSubmitSelectorInput.value = cfg.submitSelector || "";
|
||||||
enabledCheckbox.checked = cfg.enabled !== false;
|
editEnabledCheckbox.checked = cfg.enabled !== false;
|
||||||
delayMsInput.value = cfg.delayMs || "";
|
editDelayMsInput.value = cfg.delayMs || "";
|
||||||
addBtn.textContent = t("updateConfigBtn");
|
editConfigModal.classList.add("show");
|
||||||
addConfigTitleEl.textContent = t("editConfigTitle");
|
editDomainInput.focus();
|
||||||
cancelEditBtn.hidden = false;
|
|
||||||
saveDraft();
|
|
||||||
domainInput.focus();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const delBtn = document.createElement("button");
|
const delBtn = document.createElement("button");
|
||||||
@@ -816,6 +830,59 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
if (envManageModal.classList.contains("show")) renderEnvManageList();
|
if (envManageModal.classList.contains("show")) renderEnvManageList();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 编辑配置弹窗:保存
|
||||||
|
editConfigSave.addEventListener("click", async () => {
|
||||||
|
const domain = editDomainInput.value.trim();
|
||||||
|
const username = editUsernameInput.value.trim();
|
||||||
|
const password = editPasswordInput.value;
|
||||||
|
|
||||||
|
if (!domain || !username || !password) {
|
||||||
|
showToast(t("toastRequired"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
id: editModalEditingId,
|
||||||
|
domain,
|
||||||
|
alias: editAliasInput.value.trim() || null,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
autoSubmit: editAutoSubmitSelect.value === "true",
|
||||||
|
usernameSelector: editUsernameSelectorInput.value.trim() || null,
|
||||||
|
passwordSelector: editPasswordSelectorInput.value.trim() || null,
|
||||||
|
submitSelector: editSubmitSelectorInput.value.trim() || null,
|
||||||
|
enabled: editEnabledCheckbox.checked,
|
||||||
|
delayMs: editDelayMsInput.value ? Number(editDelayMsInput.value) : null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs = await loadConfigs();
|
||||||
|
const idx = configs.findIndex((c) => c.id === editModalEditingId);
|
||||||
|
if (idx !== -1) {
|
||||||
|
configs[idx] = config;
|
||||||
|
}
|
||||||
|
await saveConfigs(configs);
|
||||||
|
editConfigModal.classList.remove("show");
|
||||||
|
editModalEditingId = null;
|
||||||
|
renderConfigList();
|
||||||
|
renderEnvSelect();
|
||||||
|
if (envManageModal.classList.contains("show")) renderEnvManageList();
|
||||||
|
showToast(t("toastUpdated"));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 编辑配置弹窗:取消
|
||||||
|
editConfigCancel.addEventListener("click", () => {
|
||||||
|
editConfigModal.classList.remove("show");
|
||||||
|
editModalEditingId = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 点击遮罩关闭编辑弹窗
|
||||||
|
editConfigModal.addEventListener("click", (e) => {
|
||||||
|
if (e.target === editConfigModal) {
|
||||||
|
editConfigModal.classList.remove("show");
|
||||||
|
editModalEditingId = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
fillCurrentBtn.addEventListener("click", async () => {
|
fillCurrentBtn.addEventListener("click", async () => {
|
||||||
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||||
if (!tab) {
|
if (!tab) {
|
||||||
|
|||||||
Reference in New Issue
Block a user