fix: 兼容旧浏览器后台与截图开关

This commit is contained in:
2025-12-31 19:04:42 +08:00
parent d108f3b51d
commit 7cf39f80bc
32 changed files with 152 additions and 72 deletions

View File

@@ -17,6 +17,7 @@ const scheduleEnabled = ref(false)
const scheduleTime = ref('02:00') const scheduleTime = ref('02:00')
const scheduleBrowseType = ref('应读') const scheduleBrowseType = ref('应读')
const scheduleWeekdays = ref(['1', '2', '3', '4', '5', '6', '7']) const scheduleWeekdays = ref(['1', '2', '3', '4', '5', '6', '7'])
const scheduleScreenshotEnabled = ref(true)
// 代理 // 代理
const proxyEnabled = ref(false) const proxyEnabled = ref(false)
@@ -77,6 +78,7 @@ async function loadAll() {
.map((x) => x.trim()) .map((x) => x.trim())
.filter(Boolean) .filter(Boolean)
scheduleWeekdays.value = weekdays.length ? weekdays : ['1', '2', '3', '4', '5', '6', '7'] scheduleWeekdays.value = weekdays.length ? weekdays : ['1', '2', '3', '4', '5', '6', '7']
scheduleScreenshotEnabled.value = (system.enable_screenshot ?? 1) === 1
autoApproveEnabled.value = (system.auto_approve_enabled ?? 0) === 1 autoApproveEnabled.value = (system.auto_approve_enabled ?? 0) === 1
autoApproveHourlyLimit.value = system.auto_approve_hourly_limit ?? 10 autoApproveHourlyLimit.value = system.auto_approve_hourly_limit ?? 10
@@ -128,10 +130,12 @@ async function saveSchedule() {
schedule_time: scheduleTime.value, schedule_time: scheduleTime.value,
schedule_browse_type: scheduleBrowseType.value, schedule_browse_type: scheduleBrowseType.value,
schedule_weekdays: (scheduleWeekdays.value || []).join(','), schedule_weekdays: (scheduleWeekdays.value || []).join(','),
enable_screenshot: scheduleScreenshotEnabled.value ? 1 : 0,
} }
const screenshotText = scheduleScreenshotEnabled.value ? '截图' : '不截图'
const message = scheduleEnabled.value const message = scheduleEnabled.value
? `确定启用定时任务吗?\n\n执行时间: 每天 ${payload.schedule_time}\n执行日期: ${scheduleWeekdayDisplay.value}\n浏览类型: ${payload.schedule_browse_type}\n\n系统将自动执行所有账号的浏览任务(不包含截图)` ? `确定启用定时任务吗?\n\n执行时间: 每天 ${payload.schedule_time}\n执行日期: ${scheduleWeekdayDisplay.value}\n浏览类型: ${payload.schedule_browse_type}\n截图: ${screenshotText}\n\n系统将自动执行所有账号的浏览任务`
: '确定关闭定时任务吗?' : '确定关闭定时任务吗?'
try { try {
@@ -274,6 +278,7 @@ onMounted(loadAll)
<el-form label-width="130px"> <el-form label-width="130px">
<el-form-item label="启用定时任务"> <el-form-item label="启用定时任务">
<el-switch v-model="scheduleEnabled" /> <el-switch v-model="scheduleEnabled" />
<div class="help">开启后系统会按计划自动执行浏览任务</div>
</el-form-item> </el-form-item>
<el-form-item v-if="scheduleEnabled" label="执行时间"> <el-form-item v-if="scheduleEnabled" label="执行时间">
@@ -294,6 +299,11 @@ onMounted(loadAll)
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item v-if="scheduleEnabled" label="定时任务截图">
<el-switch v-model="scheduleScreenshotEnabled" />
<div class="help">开启后定时任务执行时会生成截图</div>
</el-form-item>
</el-form> </el-form>
<div class="row-actions"> <div class="row-actions">

View File

@@ -186,6 +186,7 @@ def update_system_config(
schedule_weekdays=None, schedule_weekdays=None,
max_concurrent_per_account=None, max_concurrent_per_account=None,
max_screenshot_concurrent=None, max_screenshot_concurrent=None,
enable_screenshot=None,
proxy_enabled=None, proxy_enabled=None,
proxy_api_url=None, proxy_api_url=None,
proxy_expire_minutes=None, proxy_expire_minutes=None,
@@ -202,6 +203,7 @@ def update_system_config(
schedule_weekdays=schedule_weekdays, schedule_weekdays=schedule_weekdays,
max_concurrent_per_account=max_concurrent_per_account, max_concurrent_per_account=max_concurrent_per_account,
max_screenshot_concurrent=max_screenshot_concurrent, max_screenshot_concurrent=max_screenshot_concurrent,
enable_screenshot=enable_screenshot,
proxy_enabled=proxy_enabled, proxy_enabled=proxy_enabled,
proxy_api_url=proxy_api_url, proxy_api_url=proxy_api_url,
proxy_expire_minutes=proxy_expire_minutes, proxy_expire_minutes=proxy_expire_minutes,

View File

@@ -184,6 +184,7 @@ def update_system_config(
schedule_weekdays=None, schedule_weekdays=None,
max_concurrent_per_account=None, max_concurrent_per_account=None,
max_screenshot_concurrent=None, max_screenshot_concurrent=None,
enable_screenshot=None,
proxy_enabled=None, proxy_enabled=None,
proxy_api_url=None, proxy_api_url=None,
proxy_expire_minutes=None, proxy_expire_minutes=None,
@@ -200,6 +201,7 @@ def update_system_config(
"schedule_weekdays", "schedule_weekdays",
"max_concurrent_per_account", "max_concurrent_per_account",
"max_screenshot_concurrent", "max_screenshot_concurrent",
"enable_screenshot",
"proxy_enabled", "proxy_enabled",
"proxy_api_url", "proxy_api_url",
"proxy_expire_minutes", "proxy_expire_minutes",
@@ -232,6 +234,9 @@ def update_system_config(
if max_screenshot_concurrent is not None: if max_screenshot_concurrent is not None:
updates.append("max_screenshot_concurrent = ?") updates.append("max_screenshot_concurrent = ?")
params.append(max_screenshot_concurrent) params.append(max_screenshot_concurrent)
if enable_screenshot is not None:
updates.append("enable_screenshot = ?")
params.append(enable_screenshot)
if schedule_weekdays is not None: if schedule_weekdays is not None:
updates.append("schedule_weekdays = ?") updates.append("schedule_weekdays = ?")
params.append(schedule_weekdays) params.append(schedule_weekdays)

View File

@@ -605,6 +605,7 @@ def update_system_config_api():
schedule_weekdays = data.get("schedule_weekdays") schedule_weekdays = data.get("schedule_weekdays")
new_max_concurrent_per_account = data.get("max_concurrent_per_account") new_max_concurrent_per_account = data.get("max_concurrent_per_account")
new_max_screenshot_concurrent = data.get("max_screenshot_concurrent") new_max_screenshot_concurrent = data.get("max_screenshot_concurrent")
enable_screenshot = data.get("enable_screenshot")
auto_approve_enabled = data.get("auto_approve_enabled") auto_approve_enabled = data.get("auto_approve_enabled")
auto_approve_hourly_limit = data.get("auto_approve_hourly_limit") auto_approve_hourly_limit = data.get("auto_approve_hourly_limit")
auto_approve_vip_days = data.get("auto_approve_vip_days") auto_approve_vip_days = data.get("auto_approve_vip_days")
@@ -621,6 +622,12 @@ def update_system_config_api():
if not isinstance(new_max_screenshot_concurrent, int) or new_max_screenshot_concurrent < 1: if not isinstance(new_max_screenshot_concurrent, int) or new_max_screenshot_concurrent < 1:
return jsonify({"error": "截图并发数必须大于0建议根据服务器配置设置wkhtmltoimage 资源占用较低)"}), 400 return jsonify({"error": "截图并发数必须大于0建议根据服务器配置设置wkhtmltoimage 资源占用较低)"}), 400
if enable_screenshot is not None:
if isinstance(enable_screenshot, bool):
enable_screenshot = 1 if enable_screenshot else 0
if enable_screenshot not in (0, 1):
return jsonify({"error": "截图开关必须是0或1"}), 400
if schedule_time is not None: if schedule_time is not None:
import re import re
@@ -659,6 +666,7 @@ def update_system_config_api():
schedule_weekdays=schedule_weekdays, schedule_weekdays=schedule_weekdays,
max_concurrent_per_account=new_max_concurrent_per_account, max_concurrent_per_account=new_max_concurrent_per_account,
max_screenshot_concurrent=new_max_screenshot_concurrent, max_screenshot_concurrent=new_max_screenshot_concurrent,
enable_screenshot=enable_screenshot,
auto_approve_enabled=auto_approve_enabled, auto_approve_enabled=auto_approve_enabled,
auto_approve_hourly_limit=auto_approve_hourly_limit, auto_approve_hourly_limit=auto_approve_hourly_limit,
auto_approve_vip_days=auto_approve_vip_days, auto_approve_vip_days=auto_approve_vip_days,

View File

@@ -6,7 +6,7 @@ import json
import os import os
from typing import Optional from typing import Optional
from flask import Blueprint, current_app, redirect, render_template, session, url_for from flask import Blueprint, current_app, redirect, render_template, request, session, url_for
from flask_login import current_user, login_required from flask_login import current_user, login_required
from routes.decorators import admin_required from routes.decorators import admin_required
@@ -72,6 +72,13 @@ def _get_asset_build_id(static_root: str, rel_paths: list[str]) -> Optional[str]
return str(int(max(mtimes))) return str(int(max(mtimes)))
def _is_legacy_admin_user_agent(user_agent: str) -> bool:
if not user_agent:
return False
ua = user_agent.lower()
return "msie" in ua or "trident/" in ua
@pages_bp.route("/") @pages_bp.route("/")
def index(): def index():
"""主页 - 重定向到登录或应用""" """主页 - 重定向到登录或应用"""
@@ -118,6 +125,8 @@ def admin_login_page():
@admin_required @admin_required
def admin_page(): def admin_page():
"""后台管理页面""" """后台管理页面"""
if request.args.get("legacy") == "1" or _is_legacy_admin_user_agent(request.headers.get("User-Agent", "")):
return render_template("admin_legacy.html")
logger = get_logger() logger = get_logger()
manifest_path = os.path.join(current_app.root_path, "static", "admin", ".vite", "manifest.json") manifest_path = os.path.join(current_app.root_path, "static", "admin", ".vite", "manifest.json")
try: try:

View File

@@ -1,34 +1,34 @@
{ {
"_email-JmyL2jV4.js": { "_email-ByiJ74rd.js": {
"file": "assets/email-JmyL2jV4.js", "file": "assets/email-ByiJ74rd.js",
"name": "email", "name": "email",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"_system-DIc9L1cQ.js": { "_system-CS-UmZao.js": {
"file": "assets/system-DIc9L1cQ.js", "file": "assets/system-CS-UmZao.js",
"name": "system", "name": "system",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"_tasks-DILta43B.js": { "_tasks-DM1Bwi9j.js": {
"file": "assets/tasks-DILta43B.js", "file": "assets/tasks-DM1Bwi9j.js",
"name": "tasks", "name": "tasks",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"_users-BxS2U-Si.js": { "_users-B1w166uc.js": {
"file": "assets/users-BxS2U-Si.js", "file": "assets/users-B1w166uc.js",
"name": "users", "name": "users",
"imports": [ "imports": [
"index.html" "index.html"
] ]
}, },
"index.html": { "index.html": {
"file": "assets/index-B9zsNTKQ.js", "file": "assets/index-DL8gIzDq.js",
"name": "index", "name": "index",
"src": "index.html", "src": "index.html",
"isEntry": true, "isEntry": true,
@@ -48,7 +48,7 @@
] ]
}, },
"src/pages/AnnouncementsPage.vue": { "src/pages/AnnouncementsPage.vue": {
"file": "assets/AnnouncementsPage-C3uZDqOR.js", "file": "assets/AnnouncementsPage-Btl9JP7M.js",
"name": "AnnouncementsPage", "name": "AnnouncementsPage",
"src": "src/pages/AnnouncementsPage.vue", "src": "src/pages/AnnouncementsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
@@ -60,12 +60,12 @@
] ]
}, },
"src/pages/EmailPage.vue": { "src/pages/EmailPage.vue": {
"file": "assets/EmailPage-DmFgLrFm.js", "file": "assets/EmailPage-Cp_IS7bH.js",
"name": "EmailPage", "name": "EmailPage",
"src": "src/pages/EmailPage.vue", "src": "src/pages/EmailPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_email-JmyL2jV4.js", "_email-ByiJ74rd.js",
"index.html" "index.html"
], ],
"css": [ "css": [
@@ -73,7 +73,7 @@
] ]
}, },
"src/pages/FeedbacksPage.vue": { "src/pages/FeedbacksPage.vue": {
"file": "assets/FeedbacksPage-BEa--2pl.js", "file": "assets/FeedbacksPage-BqmEZmow.js",
"name": "FeedbacksPage", "name": "FeedbacksPage",
"src": "src/pages/FeedbacksPage.vue", "src": "src/pages/FeedbacksPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
@@ -85,13 +85,13 @@
] ]
}, },
"src/pages/LogsPage.vue": { "src/pages/LogsPage.vue": {
"file": "assets/LogsPage-CQsGwFRH.js", "file": "assets/LogsPage-CcePQXnM.js",
"name": "LogsPage", "name": "LogsPage",
"src": "src/pages/LogsPage.vue", "src": "src/pages/LogsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_users-BxS2U-Si.js", "_users-B1w166uc.js",
"_tasks-DILta43B.js", "_tasks-DM1Bwi9j.js",
"index.html" "index.html"
], ],
"css": [ "css": [
@@ -99,22 +99,22 @@
] ]
}, },
"src/pages/ReportPage.vue": { "src/pages/ReportPage.vue": {
"file": "assets/ReportPage-nXQwTJlk.js", "file": "assets/ReportPage-CHVUWk0n.js",
"name": "ReportPage", "name": "ReportPage",
"src": "src/pages/ReportPage.vue", "src": "src/pages/ReportPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"index.html", "index.html",
"_email-JmyL2jV4.js", "_email-ByiJ74rd.js",
"_tasks-DILta43B.js", "_tasks-DM1Bwi9j.js",
"_system-DIc9L1cQ.js" "_system-CS-UmZao.js"
], ],
"css": [ "css": [
"assets/ReportPage-D7trjjOv.css" "assets/ReportPage-Q8rCsG8A.css"
] ]
}, },
"src/pages/SecurityPage.vue": { "src/pages/SecurityPage.vue": {
"file": "assets/SecurityPage-Czxm2GJx.js", "file": "assets/SecurityPage-DTjNosEF.js",
"name": "SecurityPage", "name": "SecurityPage",
"src": "src/pages/SecurityPage.vue", "src": "src/pages/SecurityPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
@@ -122,11 +122,11 @@
"index.html" "index.html"
], ],
"css": [ "css": [
"assets/SecurityPage-CH3QeiaV.css" "assets/SecurityPage-Dv9jYTtC.css"
] ]
}, },
"src/pages/SettingsPage.vue": { "src/pages/SettingsPage.vue": {
"file": "assets/SettingsPage-IGV4in6c.js", "file": "assets/SettingsPage-68qb85yN.js",
"name": "SettingsPage", "name": "SettingsPage",
"src": "src/pages/SettingsPage.vue", "src": "src/pages/SettingsPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
@@ -138,25 +138,25 @@
] ]
}, },
"src/pages/SystemPage.vue": { "src/pages/SystemPage.vue": {
"file": "assets/SystemPage-BPHukDdR.js", "file": "assets/SystemPage-DHToRQFv.js",
"name": "SystemPage", "name": "SystemPage",
"src": "src/pages/SystemPage.vue", "src": "src/pages/SystemPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_system-DIc9L1cQ.js", "_system-CS-UmZao.js",
"index.html" "index.html"
], ],
"css": [ "css": [
"assets/SystemPage-DhVR0HeO.css" "assets/SystemPage-DdMZ1omu.css"
] ]
}, },
"src/pages/UsersPage.vue": { "src/pages/UsersPage.vue": {
"file": "assets/UsersPage-DLsmihq2.js", "file": "assets/UsersPage-lUtZTPoX.js",
"name": "UsersPage", "name": "UsersPage",
"src": "src/pages/UsersPage.vue", "src": "src/pages/UsersPage.vue",
"isDynamicEntry": true, "isDynamicEntry": true,
"imports": [ "imports": [
"_users-BxS2U-Si.js", "_users-B1w166uc.js",
"index.html" "index.html"
], ],
"css": [ "css": [

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.page-stack[data-v-ea9240bd]{display:flex;flex-direction:column;gap:12px}.toolbar[data-v-ea9240bd]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.stats-row[data-v-ea9240bd]{margin-bottom:2px}.card[data-v-ea9240bd]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.sub-card[data-v-ea9240bd]{margin-top:12px;border-radius:var(--app-radius);border:1px solid var(--app-border)}.stat-card[data-v-ea9240bd]{border-radius:var(--app-radius);border:1px solid var(--app-border);box-shadow:var(--app-shadow)}.stat-value[data-v-ea9240bd]{font-size:22px;font-weight:800;line-height:1.1}.stat-label[data-v-ea9240bd]{margin-top:6px;font-size:12px;color:var(--app-muted)}.filters[data-v-ea9240bd]{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:12px}.table-wrap[data-v-ea9240bd]{overflow-x:auto}.ellipsis[data-v-ea9240bd]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mono[data-v-ea9240bd]{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.pagination[data-v-ea9240bd]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-ea9240bd]{font-size:12px}.inner-tabs[data-v-ea9240bd]{margin-top:6px}.risk-head[data-v-ea9240bd]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px;flex-wrap:wrap}.risk-title[data-v-ea9240bd]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.dialog-actions[data-v-ea9240bd]{display:flex;align-items:center;gap:10px}.spacer[data-v-ea9240bd]{flex:1}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.page-stack[data-v-22d57053]{display:flex;flex-direction:column;gap:12px}.toolbar[data-v-22d57053]{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.stats-row[data-v-22d57053]{margin-bottom:2px}.card[data-v-22d57053]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.sub-card[data-v-22d57053]{margin-top:12px;border-radius:var(--app-radius);border:1px solid var(--app-border)}.stat-card[data-v-22d57053]{border-radius:var(--app-radius);border:1px solid var(--app-border);box-shadow:var(--app-shadow)}.stat-value[data-v-22d57053]{font-size:22px;font-weight:800;line-height:1.1}.stat-label[data-v-22d57053]{margin-top:6px;font-size:12px;color:var(--app-muted)}.filters[data-v-22d57053]{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:12px}.table-wrap[data-v-22d57053]{overflow-x:auto}.ellipsis[data-v-22d57053]{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mono[data-v-22d57053]{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.pagination[data-v-22d57053]{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}.page-hint[data-v-22d57053]{font-size:12px}.inner-tabs[data-v-22d57053]{margin-top:6px}.risk-head[data-v-22d57053]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px;flex-wrap:wrap}.risk-title[data-v-22d57053]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.dialog-actions[data-v-22d57053]{display:flex;align-items:center;gap:10px}.spacer[data-v-22d57053]{flex:1}

View File

@@ -1 +1 @@
import{a as m,_ as B,r as p,f as u,g as T,h as P,j as r,m as a,w as l,q as x,L as i,K as b}from"./index-B9zsNTKQ.js";async function C(o){const{data:s}=await m.put("/admin/username",{new_username:o});return s}async function S(o){const{data:s}=await m.put("/admin/password",{new_password:o});return s}async function U(){const{data:o}=await m.post("/logout");return o}const A={class:"page-stack"},E={__name:"SettingsPage",setup(o){const s=p(""),d=p(""),n=p(!1);function k(t){const e=String(t||"");return e.length<8?{ok:!1,message:"密码长度至少8位"}:e.length>128?{ok:!1,message:"密码长度不能超过128个字符"}:!/[a-zA-Z]/.test(e)||!/\d/.test(e)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}async function f(){try{await U()}catch{}finally{window.location.href="/yuyx"}}async function V(){const t=s.value.trim();if(!t){i.error("请输入新用户名");return}try{await b.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await C(t),i.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function h(){const t=d.value;if(!t){i.error("请输入新密码");return}const e=k(t);if(!e.ok){i.error(e.message);return}try{await b.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await S(t),i.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=u("el-input"),w=u("el-form-item"),v=u("el-form"),y=u("el-button"),_=u("el-card");return P(),T("div",A,[e[7]||(e[7]=r("div",{class:"app-page-title"},[r("h2",null,"设置"),r("span",{class:"app-muted"},"管理员账号设置")],-1)),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(v,{"label-width":"120px"},{default:l(()=>[a(w,{label:"新用户名"},{default:l(()=>[a(g,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=c=>s.value=c),placeholder:"输入新用户名",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:V},{default:l(()=>[...e[2]||(e[2]=[x("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(v,{"label-width":"120px"},{default:l(()=>[a(w,{label:"新密码"},{default:l(()=>[a(g,{modelValue:d.value,"onUpdate:modelValue":e[1]||(e[1]=c=>d.value=c),type:"password","show-password":"",placeholder:"输入新密码",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:h},{default:l(()=>[...e[4]||(e[4]=[x("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码至少8位且包含字母与数字。",-1))]),_:1})])}}},M=B(E,[["__scopeId","data-v-12a26d11"]]);export{M as default}; import{a as m,_ as B,r as p,f as u,g as T,h as P,j as r,m as a,w as l,q as x,L as i,K as b}from"./index-DL8gIzDq.js";async function C(o){const{data:s}=await m.put("/admin/username",{new_username:o});return s}async function S(o){const{data:s}=await m.put("/admin/password",{new_password:o});return s}async function U(){const{data:o}=await m.post("/logout");return o}const A={class:"page-stack"},E={__name:"SettingsPage",setup(o){const s=p(""),d=p(""),n=p(!1);function k(t){const e=String(t||"");return e.length<8?{ok:!1,message:"密码长度至少8位"}:e.length>128?{ok:!1,message:"密码长度不能超过128个字符"}:!/[a-zA-Z]/.test(e)||!/\d/.test(e)?{ok:!1,message:"密码必须包含字母和数字"}:{ok:!0,message:""}}async function f(){try{await U()}catch{}finally{window.location.href="/yuyx"}}async function V(){const t=s.value.trim();if(!t){i.error("请输入新用户名");return}try{await b.confirm(`确定将管理员用户名修改为「${t}」吗?修改后需要重新登录。`,"修改用户名",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await C(t),i.success("用户名修改成功,请重新登录"),s.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}async function h(){const t=d.value;if(!t){i.error("请输入新密码");return}const e=k(t);if(!e.ok){i.error(e.message);return}try{await b.confirm("确定修改管理员密码吗?修改后需要重新登录。","修改密码",{confirmButtonText:"确认修改",cancelButtonText:"取消",type:"warning"})}catch{return}n.value=!0;try{await S(t),i.success("密码修改成功,请重新登录"),d.value="",setTimeout(f,1200)}catch{}finally{n.value=!1}}return(t,e)=>{const g=u("el-input"),w=u("el-form-item"),v=u("el-form"),y=u("el-button"),_=u("el-card");return P(),T("div",A,[e[7]||(e[7]=r("div",{class:"app-page-title"},[r("h2",null,"设置"),r("span",{class:"app-muted"},"管理员账号设置")],-1)),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[e[3]||(e[3]=r("h3",{class:"section-title"},"修改管理员用户名",-1)),a(v,{"label-width":"120px"},{default:l(()=>[a(w,{label:"新用户名"},{default:l(()=>[a(g,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=c=>s.value=c),placeholder:"输入新用户名",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:V},{default:l(()=>[...e[2]||(e[2]=[x("保存用户名",-1)])]),_:1},8,["loading"])]),_:1}),a(_,{shadow:"never","body-style":{padding:"16px"},class:"card"},{default:l(()=>[e[5]||(e[5]=r("h3",{class:"section-title"},"修改管理员密码",-1)),a(v,{"label-width":"120px"},{default:l(()=>[a(w,{label:"新密码"},{default:l(()=>[a(g,{modelValue:d.value,"onUpdate:modelValue":e[1]||(e[1]=c=>d.value=c),type:"password","show-password":"",placeholder:"输入新密码",disabled:n.value},null,8,["modelValue","disabled"])]),_:1})]),_:1}),a(y,{type:"primary",loading:n.value,onClick:h},{default:l(()=>[...e[4]||(e[4]=[x("保存密码",-1)])]),_:1},8,["loading"]),e[6]||(e[6]=r("div",{class:"help"},"建议使用更强密码至少8位且包含字母与数字。",-1))]),_:1})])}}},M=B(E,[["__scopeId","data-v-12a26d11"]]);export{M as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.page-stack[data-v-5ced7917]{display:flex;flex-direction:column;gap:12px}.card[data-v-5ced7917]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.section-title[data-v-5ced7917]{margin:0 0 12px;font-size:14px;font-weight:800}.help[data-v-5ced7917]{margin-top:6px;font-size:12px;color:var(--app-muted)}.row-actions[data-v-5ced7917]{display:flex;flex-wrap:wrap;gap:10px}

View File

@@ -1 +0,0 @@
.page-stack[data-v-bb187149]{display:flex;flex-direction:column;gap:12px}.card[data-v-bb187149]{border-radius:var(--app-radius);border:1px solid var(--app-border)}.section-title[data-v-bb187149]{margin:0 0 12px;font-size:14px;font-weight:800}.help[data-v-bb187149]{margin-top:6px;font-size:12px;color:var(--app-muted)}.row-actions[data-v-bb187149]{display:flex;flex-wrap:wrap;gap:10px}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
import{a as n}from"./index-B9zsNTKQ.js";async function i(){const{data:a}=await n.get("/email/settings");return a}async function e(a){const{data:t}=await n.post("/email/settings",a);return t}async function c(){const{data:a}=await n.get("/email/stats");return a}async function o(a){const{data:t}=await n.get("/email/logs",{params:a});return t}async function l(a){const{data:t}=await n.post("/email/logs/cleanup",{days:a});return t}export{o as a,i as b,l as c,c as f,e as u}; import{a as n}from"./index-DL8gIzDq.js";async function i(){const{data:a}=await n.get("/email/settings");return a}async function e(a){const{data:t}=await n.post("/email/settings",a);return t}async function c(){const{data:a}=await n.get("/email/stats");return a}async function o(a){const{data:t}=await n.get("/email/logs",{params:a});return t}async function l(a){const{data:t}=await n.post("/email/logs/cleanup",{days:a});return t}export{o as a,i as b,l as c,c as f,e as u};

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
import{a}from"./index-B9zsNTKQ.js";async function s(){const{data:t}=await a.get("/system/config");return t}async function c(t){const{data:e}=await a.post("/system/config",t);return e}async function o(){const{data:t}=await a.post("/schedule/execute",{});return t}export{o as e,s as f,c as u}; import{a}from"./index-DL8gIzDq.js";async function s(){const{data:t}=await a.get("/system/config");return t}async function c(t){const{data:e}=await a.post("/system/config",t);return e}async function o(){const{data:t}=await a.post("/schedule/execute",{});return t}export{o as e,s as f,c as u};

View File

@@ -1 +1 @@
import{a}from"./index-B9zsNTKQ.js";async function c(){const{data:t}=await a.get("/server/info");return t}async function e(){const{data:t}=await a.get("/docker_stats");return t}async function o(){const{data:t}=await a.get("/task/stats");return t}async function r(){const{data:t}=await a.get("/task/running");return t}async function i(t){const{data:s}=await a.get("/task/logs",{params:t});return s}async function f(t){const{data:s}=await a.post("/task/logs/clear",{days:t});return s}export{r as a,c as b,e as c,i as d,f as e,o as f}; import{a}from"./index-DL8gIzDq.js";async function c(){const{data:t}=await a.get("/server/info");return t}async function e(){const{data:t}=await a.get("/docker_stats");return t}async function o(){const{data:t}=await a.get("/task/stats");return t}async function r(){const{data:t}=await a.get("/task/running");return t}async function i(t){const{data:s}=await a.get("/task/logs",{params:t});return s}async function f(t){const{data:s}=await a.post("/task/logs/clear",{days:t});return s}export{r as a,c as b,e as c,i as d,f as e,o as f};

View File

@@ -1 +1 @@
import{a as t}from"./index-B9zsNTKQ.js";async function n(){const{data:s}=await t.get("/users");return s}async function o(s){const{data:a}=await t.post(`/users/${s}/approve`);return a}async function c(s){const{data:a}=await t.post(`/users/${s}/reject`);return a}async function i(s){const{data:a}=await t.delete(`/users/${s}`);return a}async function u(s,a){const{data:e}=await t.post(`/users/${s}/vip`,{days:a});return e}async function p(s){const{data:a}=await t.delete(`/users/${s}/vip`);return a}async function d(s,a){const{data:e}=await t.post(`/users/${s}/reset_password`,{new_password:a});return e}export{o as a,p as b,d as c,i as d,n as f,c as r,u as s}; import{a as t}from"./index-DL8gIzDq.js";async function n(){const{data:s}=await t.get("/users");return s}async function o(s){const{data:a}=await t.post(`/users/${s}/approve`);return a}async function c(s){const{data:a}=await t.post(`/users/${s}/reject`);return a}async function i(s){const{data:a}=await t.delete(`/users/${s}`);return a}async function u(s,a){const{data:e}=await t.post(`/users/${s}/vip`,{days:a});return e}async function p(s){const{data:a}=await t.delete(`/users/${s}/vip`);return a}async function d(s,a){const{data:e}=await t.post(`/users/${s}/reset_password`,{new_password:a});return e}export{o as a,p as b,d as c,i as d,n as f,c as r,u as s};

View File

@@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="./vite.svg" /> <link rel="icon" type="image/svg+xml" href="./vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>后台管理 - 知识管理平台</title> <title>后台管理 - 知识管理平台</title>
<script type="module" crossorigin src="./assets/index-B9zsNTKQ.js"></script> <script type="module" crossorigin src="./assets/index-DL8gIzDq.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-_5Ec1Hmd.css"> <link rel="stylesheet" crossorigin href="./assets/index-_5Ec1Hmd.css">
</head> </head>
<body> <body>

View File

@@ -14,6 +14,34 @@
</head> </head>
<body> <body>
<noscript>该页面需要启用 JavaScript 才能使用。</noscript> <noscript>该页面需要启用 JavaScript 才能使用。</noscript>
<script>
(function () {
var search = window.location.search || ''
if (search.indexOf('legacy=1') !== -1) {
return
}
var needsLegacy = false
try {
new Function('let a = 1; const b = 2;')
} catch (e) {
needsLegacy = true
}
if (!window.Promise || !window.Proxy) {
needsLegacy = true
}
if (needsLegacy) {
var href = window.location.href
var hash = ''
var hashIndex = href.indexOf('#')
if (hashIndex !== -1) {
hash = href.slice(hashIndex)
href = href.slice(0, hashIndex)
}
var sep = href.indexOf('?') !== -1 ? '&' : '?'
window.location.replace(href + sep + 'legacy=1' + hash)
}
})()
</script>
<div id="app"></div> <div id="app"></div>
{% if admin_spa_build_id %} {% if admin_spa_build_id %}
<script type="module" src="{{ url_for('serve_static', filename=admin_spa_js_file, v=admin_spa_build_id) }}"></script> <script type="module" src="{{ url_for('serve_static', filename=admin_spa_js_file, v=admin_spa_build_id) }}"></script>

View File

@@ -822,7 +822,7 @@
启用定时任务 启用定时任务
</label> </label>
<div style="font-size: 12px; color: #666; margin-top: 5px;"> <div style="font-size: 12px; color: #666; margin-top: 5px;">
开启后,系统将在指定时间自动执行所有账号的浏览任务(不包含截图) 开启后,系统将在指定时间自动执行所有账号的浏览任务,是否截图由下方开关决定。
</div> </div>
</div> </div>
@@ -879,6 +879,16 @@
</div> </div>
</div> </div>
<div class="form-group" id="scheduleScreenshotGroup" style="display: none;">
<label style="display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="enableScreenshot" style="width: auto; max-width: none;">
定时任务截图
</label>
<div style="font-size: 12px; color: #666; margin-top: 5px;">
开启后,定时任务执行时会生成截图。
</div>
</div>
<div id="scheduleActions" style="margin-top: 15px; display: flex; gap: 10px;"> <div id="scheduleActions" style="margin-top: 15px; display: flex; gap: 10px;">
<button class="btn btn-primary" onclick="updateSchedule()">保存定时任务配置</button> <button class="btn btn-primary" onclick="updateSchedule()">保存定时任务配置</button>
<button class="btn btn-success" onclick="executeScheduleNow()" style="background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);"> <button class="btn btn-success" onclick="executeScheduleNow()" style="background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);">
@@ -2108,6 +2118,8 @@
document.getElementById('scheduleEnabled').checked = config.schedule_enabled === 1; document.getElementById('scheduleEnabled').checked = config.schedule_enabled === 1;
document.getElementById('scheduleTime').value = config.schedule_time || '02:00'; document.getElementById('scheduleTime').value = config.schedule_time || '02:00';
document.getElementById('scheduleBrowseType').value = config.schedule_browse_type || '应读'; document.getElementById('scheduleBrowseType').value = config.schedule_browse_type || '应读';
var enableScreenshot = config.enable_screenshot;
document.getElementById('enableScreenshot').checked = enableScreenshot === 1 || enableScreenshot === true || enableScreenshot === undefined;
// 加载星期选择 // 加载星期选择
const weekdays = config.schedule_weekdays || '1,2,3,4,5,6,7'; const weekdays = config.schedule_weekdays || '1,2,3,4,5,6,7';
@@ -2133,15 +2145,18 @@
const timeGroup = document.getElementById('scheduleTimeGroup'); const timeGroup = document.getElementById('scheduleTimeGroup');
const browseTypeGroup = document.getElementById('scheduleBrowseTypeGroup'); const browseTypeGroup = document.getElementById('scheduleBrowseTypeGroup');
const weekdaysGroup = document.getElementById('scheduleWeekdaysGroup'); const weekdaysGroup = document.getElementById('scheduleWeekdaysGroup');
const screenshotGroup = document.getElementById('scheduleScreenshotGroup');
if (enabled) { if (enabled) {
timeGroup.style.display = 'block'; timeGroup.style.display = 'block';
browseTypeGroup.style.display = 'block'; browseTypeGroup.style.display = 'block';
weekdaysGroup.style.display = 'block'; weekdaysGroup.style.display = 'block';
screenshotGroup.style.display = 'block';
} else { } else {
timeGroup.style.display = 'none'; timeGroup.style.display = 'none';
browseTypeGroup.style.display = 'none'; browseTypeGroup.style.display = 'none';
weekdaysGroup.style.display = 'none'; weekdaysGroup.style.display = 'none';
screenshotGroup.style.display = 'none';
} }
// 保存按钮始终显示,无论是开启还是关闭定时任务 // 保存按钮始终显示,无论是开启还是关闭定时任务
} }
@@ -2314,6 +2329,7 @@
const enabled = document.getElementById('scheduleEnabled').checked; const enabled = document.getElementById('scheduleEnabled').checked;
const time = document.getElementById('scheduleTime').value; const time = document.getElementById('scheduleTime').value;
const browseType = document.getElementById('scheduleBrowseType').value; const browseType = document.getElementById('scheduleBrowseType').value;
const enableScreenshot = document.getElementById('enableScreenshot').checked;
// 获取选中的星期 // 获取选中的星期
const selectedWeekdays = []; const selectedWeekdays = [];
@@ -2331,7 +2347,7 @@
const weekdayDisplay = selectedWeekdays.map(d => weekdayNames[parseInt(d)]).join('、'); const weekdayDisplay = selectedWeekdays.map(d => weekdayNames[parseInt(d)]).join('、');
const message = enabled const message = enabled
? `确定启用定时任务吗?\n\n执行时间: 每天 ${time}\n执行日期: ${weekdayDisplay}\n浏览类型: ${browseType}\n\n系统将自动执行所有账号的浏览任务(不包含截图)` ? `确定启用定时任务吗?\n\n执行时间: 每天 ${time}\n执行日期: ${weekdayDisplay}\n浏览类型: ${browseType}\n截图: ${enableScreenshot ? '截图' : '不截图'}\n\n系统将自动执行所有账号的浏览任务`
: `确定关闭定时任务吗?`; : `确定关闭定时任务吗?`;
if (!confirm(message)) return; if (!confirm(message)) return;
@@ -2344,7 +2360,8 @@
schedule_enabled: enabled ? 1 : 0, schedule_enabled: enabled ? 1 : 0,
schedule_time: time, schedule_time: time,
schedule_browse_type: browseType, schedule_browse_type: browseType,
schedule_weekdays: weekdaysStr schedule_weekdays: weekdaysStr,
enable_screenshot: enableScreenshot ? 1 : 0
}) })
}); });