feat: implement account archiving system and brand logo upgrade
This commit is contained in:
28
popup.css
28
popup.css
@@ -34,14 +34,26 @@ body {
|
|||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
.logo {
|
||||||
font-size: 16px;
|
display: flex;
|
||||||
font-weight: 600;
|
align-items: center;
|
||||||
margin: 0;
|
justify-content: center;
|
||||||
background: linear-gradient(90deg, #2563eb, #3b82f6);
|
filter: drop-shadow(0 2px 4px rgba(59, 130, 246, 0.2));
|
||||||
-webkit-background-clip: text;
|
transition: transform 0.3s ease;
|
||||||
background-clip: text;
|
}
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
|
.logo:hover {
|
||||||
|
transform: scale(1.05) rotate(2deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#archive-toggle {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
#archive-toggle:hover {
|
||||||
|
opacity: 1;
|
||||||
|
background: rgba(100, 116, 139, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-btn {
|
.icon-btn {
|
||||||
|
|||||||
91
popup.html
91
popup.html
@@ -11,7 +11,29 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="app-view">
|
<div id="app-view">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>清速登</h1>
|
<div style="display: flex; align-items: center; gap: 8px;">
|
||||||
|
<button id="archive-toggle" class="icon-btn" title="查看已归档项目" style="padding: 4px;">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M21 8v13H3V8M1 3h22v5H1V3zm10 8h2" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="logo">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 2L2 7L12 12L22 7L12 2Z" fill="url(#logo-grad)" stroke="white" stroke-width="1.5"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path d="M2 17L12 22L22 17" stroke="url(#logo-grad)" stroke-width="1.5" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path d="M2 12L12 17L22 12" stroke="url(#logo-grad)" stroke-width="1.5" stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="logo-grad" x1="2" y1="2" x2="22" y2="22" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#3b82f6" />
|
||||||
|
<stop offset="1" stop-color="#8b5cf6" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="#" id="logout-btn"
|
<a href="#" id="logout-btn"
|
||||||
style="font-size: 11px; color: var(--text-secondary); text-decoration: none; margin-right: 8px;">切换账号</a>
|
style="font-size: 11px; color: var(--text-secondary); text-decoration: none; margin-right: 8px;">切换账号</a>
|
||||||
@@ -22,36 +44,51 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="add-form" class="hidden">
|
<div id="main-view-content">
|
||||||
<h2 id="form-title">添加配置</h2>
|
<div id="add-form" class="hidden">
|
||||||
<input type="hidden" id="editing-id" />
|
<h2 id="form-title">添加配置</h2>
|
||||||
<div class="form-group">
|
<input type="hidden" id="editing-id" />
|
||||||
<select id="env-select">
|
<div class="form-group">
|
||||||
<option value="DD_PP">DD PP</option>
|
<select id="env-select">
|
||||||
<option value="DD_ATS">DD ATS</option>
|
<option value="DD_PP">DD PP</option>
|
||||||
<option value="STD_PP">STD PP</option>
|
<option value="DD_ATS">DD ATS</option>
|
||||||
<option value="STD_ATS">STD ATS</option>
|
<option value="STD_PP">STD PP</option>
|
||||||
</select>
|
<option value="STD_ATS">STD ATS</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" id="client-input" placeholder="客户名称 (例如: 某某测试)" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" id="username-input" placeholder="账号" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="password" id="password-input" placeholder="密码" autocomplete="new-password" />
|
||||||
|
</div>
|
||||||
|
<div class="form-actions">
|
||||||
|
<button id="cancel-btn" class="secondary-btn">取消</button>
|
||||||
|
<button id="save-btn" class="primary-btn">保存配置</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" id="client-input" placeholder="客户名称 (例如: 某某测试)" autocomplete="off" />
|
<div class="rules-container">
|
||||||
</div>
|
<ul id="rules-list">
|
||||||
<div class="form-group">
|
<!-- Rules will be dynamically inserted here by JS -->
|
||||||
<input type="text" id="username-input" placeholder="账号" autocomplete="off" />
|
</ul>
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="password" id="password-input" placeholder="密码" autocomplete="new-password" />
|
|
||||||
</div>
|
|
||||||
<div class="form-actions">
|
|
||||||
<button id="cancel-btn" class="secondary-btn">取消</button>
|
|
||||||
<button id="save-btn" class="primary-btn">保存配置</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rules-container">
|
<div id="archive-view-content" class="hidden">
|
||||||
<ul id="rules-list">
|
<div
|
||||||
<!-- Rules will be dynamically inserted here by JS -->
|
style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; border-bottom: 1px dashed var(--border-color); padding-bottom: 8px;">
|
||||||
</ul>
|
<h2 style="font-size: 13px; margin: 0; color: var(--text-secondary); font-weight: 500;">已归档账号</h2>
|
||||||
|
<button id="back-to-main" class="secondary-btn" style="padding: 2px 8px; font-size: 11px;">返回列表</button>
|
||||||
|
</div>
|
||||||
|
<div class="rules-container">
|
||||||
|
<ul id="archive-list">
|
||||||
|
<!-- Archived rules will be inserted here -->
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
101
popup.js
101
popup.js
@@ -21,6 +21,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const goToRegister = document.getElementById('go-to-register');
|
const goToRegister = document.getElementById('go-to-register');
|
||||||
const goToLogin = document.getElementById('go-to-login');
|
const goToLogin = document.getElementById('go-to-login');
|
||||||
const logoutBtn = document.getElementById('logout-btn');
|
const logoutBtn = document.getElementById('logout-btn');
|
||||||
|
const archiveToggle = document.getElementById('archive-toggle');
|
||||||
|
const backToMain = document.getElementById('back-to-main');
|
||||||
|
const mainViewContent = document.getElementById('main-view-content');
|
||||||
|
const archiveViewContent = document.getElementById('archive-view-content');
|
||||||
|
const archiveList = document.getElementById('archive-list');
|
||||||
|
|
||||||
if (logoutBtn) {
|
if (logoutBtn) {
|
||||||
logoutBtn.addEventListener('click', (e) => {
|
logoutBtn.addEventListener('click', (e) => {
|
||||||
@@ -294,8 +299,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
function renderRules() {
|
function renderRules() {
|
||||||
rulesList.innerHTML = '';
|
rulesList.innerHTML = '';
|
||||||
|
const activeRules = rules.filter(r => !r.archived);
|
||||||
|
|
||||||
if (rules.length === 0) {
|
if (activeRules.length === 0) {
|
||||||
rulesList.innerHTML = `
|
rulesList.innerHTML = `
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||||
@@ -308,7 +314,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rules.forEach((rule, index) => {
|
activeRules.forEach((rule, index) => {
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
li.className = 'rule-item';
|
li.className = 'rule-item';
|
||||||
li.setAttribute('draggable', 'true');
|
li.setAttribute('draggable', 'true');
|
||||||
@@ -331,8 +337,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="icon-btn btn-delete" data-id="${rule.id}" title="删除此配置">
|
<button class="icon-btn btn-delete" data-id="${rule.id}" title="归档此配置">
|
||||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8 8-4-4m12 4v5a2 2 0 01-2 2H6a2 2 0 01-2-2V9a2 2 0 012-2h5" />
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -341,21 +349,75 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
rulesList.appendChild(li);
|
rulesList.appendChild(li);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
attachRuleEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderArchive() {
|
||||||
|
archiveList.innerHTML = '';
|
||||||
|
const archivedRules = rules.filter(r => r.archived);
|
||||||
|
|
||||||
|
if (archivedRules.length === 0) {
|
||||||
|
archiveList.innerHTML = '<div class="empty-state" style="padding: 20px 0;"><span>暂无归档内容</span></div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
archivedRules.forEach(rule => {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
li.className = 'rule-item';
|
||||||
|
li.innerHTML = `
|
||||||
|
<div class="rule-info">
|
||||||
|
<div class="rule-domain">${rule.clientName} <span class="rule-env env-${rule.env.toLowerCase().replace('_', '-')}">${rule.env.replace('_', ' ')}</span></div>
|
||||||
|
<div class="rule-acc">帐号: ${rule.username}</div>
|
||||||
|
</div>
|
||||||
|
<div class="rule-actions">
|
||||||
|
<button class="icon-btn btn-restore" data-id="${rule.id}" title="恢复到主列表">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
|
||||||
|
</button>
|
||||||
|
<button class="icon-btn btn-delete-perm" data-id="${rule.id}" title="彻底删除">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
archiveList.appendChild(li);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.btn-restore').forEach(btn => {
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
const id = e.currentTarget.getAttribute('data-id');
|
||||||
|
const index = rules.findIndex(r => r.id === id);
|
||||||
|
if (index !== -1) {
|
||||||
|
rules[index].archived = false;
|
||||||
|
saveRules();
|
||||||
|
renderArchive();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.btn-delete-perm').forEach(btn => {
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
const id = e.currentTarget.getAttribute('data-id');
|
||||||
|
if (confirm('确定要彻底删除此配置吗?此操作不可撤销。')) {
|
||||||
|
rules = rules.filter(r => r.id !== id);
|
||||||
|
saveRules();
|
||||||
|
renderArchive();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachRuleEvents() {
|
||||||
document.querySelectorAll('.rule-info').forEach(infoArea => {
|
document.querySelectorAll('.rule-info').forEach(infoArea => {
|
||||||
infoArea.addEventListener('click', (e) => {
|
infoArea.addEventListener('click', (e) => {
|
||||||
const id = e.currentTarget.getAttribute('data-id');
|
const id = e.currentTarget.getAttribute('data-id');
|
||||||
const rule = rules.find(r => r.id === id);
|
const rule = rules.find(r => r.id === id);
|
||||||
if (rule) {
|
if (rule) executePurgeAndLogin(rule, e.currentTarget);
|
||||||
executePurgeAndLogin(rule, e.currentTarget);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.btn-edit').forEach(btn => {
|
document.querySelectorAll('.btn-edit').forEach(btn => {
|
||||||
btn.addEventListener('click', (e) => {
|
btn.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const id = e.currentTarget.getAttribute('data-id');
|
toggleAddForm('edit', e.currentTarget.getAttribute('data-id'));
|
||||||
toggleAddForm('edit', id);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -363,14 +425,31 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
btn.addEventListener('click', (e) => {
|
btn.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const id = e.currentTarget.getAttribute('data-id');
|
const id = e.currentTarget.getAttribute('data-id');
|
||||||
if (confirm('确定要删除此配置吗?')) {
|
const index = rules.findIndex(r => r.id === id);
|
||||||
rules = rules.filter(r => r.id !== id);
|
if (index !== -1) {
|
||||||
|
rules[index].archived = true;
|
||||||
saveRules();
|
saveRules();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (archiveToggle) {
|
||||||
|
archiveToggle.addEventListener('click', () => {
|
||||||
|
mainViewContent.classList.add('hidden');
|
||||||
|
archiveViewContent.classList.remove('hidden');
|
||||||
|
renderArchive();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backToMain) {
|
||||||
|
backToMain.addEventListener('click', () => {
|
||||||
|
archiveViewContent.classList.add('hidden');
|
||||||
|
mainViewContent.classList.remove('hidden');
|
||||||
|
renderRules();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// --- Drag and Drop functionality ---
|
// --- Drag and Drop functionality ---
|
||||||
function addDragEvents(item) {
|
function addDragEvents(item) {
|
||||||
item.addEventListener('dragstart', (e) => {
|
item.addEventListener('dragstart', (e) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user