标签
This commit is contained in:
1 parent
de39d17c75
commit
d61847b521
3 files changed
+78
-29
No files matched your search
@@ -29,6 +29,7 @@
|
||||
- 🔄 **OAuth2 助手** - 内置 OAuth2 授权流程,快速获取 Refresh Token
|
||||
- 💾 **邮件缓存** - 智能缓存邮件列表,切换邮箱/文件夹即时展示,刷新页面清空缓存(⭐ 2026-01-29 新增)
|
||||
- 🔓 **信任邮件模式** - 支持查看原始邮件内容,可选择绕过安全过滤(⭐ 2026-01-29 新增)
|
||||
- 🏷️ **标签管理** - 支持给邮箱账号打标签,支持批量打标签/去标签,支持按标签筛选(⭐ 2026-01-31 新增)
|
||||
|
||||
#### Token 刷新管理
|
||||
- 🔁 **全量刷新** - 一键刷新所有账号 Token,实时进度展示,防止 90 天过期(⭐ 2026-01-23 新增)
|
||||
@@ -95,6 +96,9 @@ Web 应用采用四栏式布局设计:
|
||||
### 登录速率限制保护
|
||||

|
||||
|
||||
### 标签管理功能(⭐ 2026-01-31 新增)
|
||||

|
||||
|
||||
### OAuth2 授权流程
|
||||
|
||||
#### 步骤 1:应用注册
|
||||
@@ -438,7 +442,38 @@ user@outlook.com----password123----24d9a0ed-8787-4584-883c-2fd79308940a----0.AXE
|
||||
- **删除分组** - 点击分组旁的「删除」按钮(默认分组不可删除)
|
||||
- **导出分组** - 点击分组旁的「导出」按钮,导出该分组下的所有邮箱账号
|
||||
|
||||
### 6. 系统设置
|
||||
### 6. 标签管理(⭐ 2026-01-31 新增)
|
||||
|
||||
标签功能允许您为邮箱账号添加自定义标签,方便分类和筛选。
|
||||
|
||||
#### 创建和管理标签
|
||||
1. 点击邮箱面板标题栏的「🏷️」按钮,打开标签管理弹窗
|
||||
2. 输入标签名称,选择标签颜色,点击「创建」
|
||||
3. 已有标签会显示在列表中,可点击右侧的「删除」按钮移除
|
||||
|
||||
#### 给邮箱打标签
|
||||
1. 在邮箱列表中,勾选一个或多个邮箱账号(每个邮箱左侧有复选框)
|
||||
2. 底部会出现批量操作栏,显示「已选 N 项」
|
||||
3. 点击「打标签」按钮,选择要添加的标签,确认即可
|
||||
4. 标签会以彩色徽章形式显示在邮箱备注下方
|
||||
|
||||
#### 去除邮箱标签
|
||||
1. 勾选已打标签的邮箱账号
|
||||
2. 点击底部操作栏的「去标签」按钮
|
||||
3. 选择要移除的标签,确认即可
|
||||
|
||||
#### 按标签筛选邮箱
|
||||
1. 在排序按钮下方,有一行标签筛选区(仅在有标签时显示)
|
||||
2. 勾选一个或多个标签复选框
|
||||
3. 邮箱列表会自动过滤,只显示包含所选标签的账号
|
||||
4. 取消所有勾选可恢复显示全部账号
|
||||
|
||||
#### 搜索标签
|
||||
- 在全局搜索框中输入标签名称,可搜索到带有该标签的邮箱账号
|
||||
|
||||

|
||||
|
||||
### 7. 系统设置
|
||||
|
||||
点击导航栏的「⚙️ 设置」按钮,可以修改以下配置:
|
||||
|
||||
@@ -454,7 +489,7 @@ user@outlook.com----password123----24d9a0ed-8787-4584-883c-2fd79308940a----0.AXE
|
||||
|
||||
设置会保存在数据库中,重启应用后仍然有效。
|
||||
|
||||
### 7. Token 刷新管理(⭐ 2026-01-23 新增,2026-01-25 增强)
|
||||
### 8. Token 刷新管理(⭐ 2026-01-23 新增,2026-01-25 增强)
|
||||
|
||||
为了防止 Refresh Token 因 90 天不使用而过期,系统提供了强大的 Token 刷新管理功能:
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 285 KiB |
+41
-27
@@ -391,12 +391,11 @@
|
||||
.account-remark {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
padding-left: 20px;
|
||||
padding-left: 0;
|
||||
margin-top: 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 300px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.account-email {
|
||||
@@ -1351,13 +1350,14 @@
|
||||
style="padding: 4px 10px; font-size: 12px; background-color: #ffffff; border: 1px solid #e5e5e5; border-radius: 4px; color: #666; cursor: pointer; transition: all 0.15s;">
|
||||
📧 邮箱名
|
||||
</button>
|
||||
<div style="width: 1px; height: 16px; background: #e5e5e5; margin: 0 4px;"></div>
|
||||
<select id="tagFilter" onchange="filterAccountsByTag(this.value)"
|
||||
style="padding: 4px; font-size: 12px; border: 1px solid #e5e5e5; border-radius: 4px; color: #666; outline: none; background: white;">
|
||||
<option value="">全部标签</option>
|
||||
</select>
|
||||
<!-- Tag Filter moved to new row -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tag Filter Row -->
|
||||
<div id="tagFilterContainer"
|
||||
style="padding: 8px 16px; border-bottom: 1px solid #e5e5e5; display: flex; flex-wrap: wrap; gap: 8px; background-color: #fafafa; display: none;">
|
||||
<!-- Tags checkboxes will be rendered here -->
|
||||
</div>
|
||||
<div class="account-list" id="accountList">
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">📁</div>
|
||||
@@ -2686,12 +2686,16 @@ ${details}
|
||||
let result = [...accounts];
|
||||
|
||||
// 1. Tag 筛选
|
||||
const tagFilter = document.getElementById('tagFilter');
|
||||
const selectedTagId = tagFilter ? tagFilter.value : '';
|
||||
if (selectedTagId) {
|
||||
// Get checked tags
|
||||
const checkedBoxes = document.querySelectorAll('.tag-filter-checkbox:checked');
|
||||
const selectedTagIds = Array.from(checkedBoxes).map(cb => parseInt(cb.value));
|
||||
|
||||
if (selectedTagIds.length > 0) {
|
||||
result = result.filter(acc => {
|
||||
if (!acc.tags) return false;
|
||||
return acc.tags.some(t => t.id === parseInt(selectedTagId));
|
||||
// Check if account has ANY of the selected tags (OR logic)
|
||||
// If you want AND logic, use every() instead of some()
|
||||
return acc.tags.some(t => selectedTagIds.includes(t.id));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2712,7 +2716,7 @@ ${details}
|
||||
}
|
||||
|
||||
// Tag Filter Change Handler
|
||||
function filterAccountsByTag(tagId) {
|
||||
function handleTagFilterChange() {
|
||||
if (accountsCache[currentGroupId]) {
|
||||
const filteredAccounts = applyFiltersAndSort(accountsCache[currentGroupId]);
|
||||
renderAccountList(filteredAccounts);
|
||||
@@ -5067,20 +5071,30 @@ ${details}
|
||||
|
||||
// 更新标签筛选下拉框
|
||||
function updateTagFilter() {
|
||||
const filterEl = document.getElementById('tagFilter');
|
||||
if (!filterEl) return;
|
||||
const container = document.getElementById('tagFilterContainer');
|
||||
if (!container) return;
|
||||
|
||||
const currentValue = filterEl.value;
|
||||
let html = '<option value="">全部标签</option>';
|
||||
allTags.forEach(tag => {
|
||||
html += `<option value="${tag.id}">${escapeHtml(tag.name)}</option>`;
|
||||
});
|
||||
filterEl.innerHTML = html;
|
||||
|
||||
// 尝试保持选中
|
||||
if (currentValue && allTags.find(t => t.id == currentValue)) {
|
||||
filterEl.value = currentValue;
|
||||
if (allTags.length === 0) {
|
||||
container.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
container.style.display = 'flex';
|
||||
|
||||
let html = '';
|
||||
allTags.forEach(tag => {
|
||||
html += `
|
||||
<label style="display: inline-flex; align-items: center; gap: 4px; font-size: 11px; cursor: pointer; padding: 2px 6px; border: 1px solid #e5e5e5; border-radius: 12px; background: white; user-select: none;">
|
||||
<input type="checkbox" class="tag-filter-checkbox" value="${tag.id}" onchange="handleTagFilterChange()" style="margin: 0;">
|
||||
<span style="width: 8px; height: 8px; border-radius: 50%; background-color: ${tag.color}; display: inline-block;"></span>
|
||||
${escapeHtml(tag.name)}
|
||||
</label>
|
||||
`;
|
||||
});
|
||||
container.innerHTML = html;
|
||||
/* Old dropdown code removed */
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 渲染标签列表
|
||||
|
||||
Reference in new issue
Block a user