first commit

This commit is contained in:
2026-09-08 10:06:45 +08:00
commit c6e9a82fe5
12 changed files with 2289 additions and 0 deletions

53
static/shared.js Normal file
View File

@@ -0,0 +1,53 @@
async function api(path, options = {}) {
const config = {
method: options.method || 'GET',
headers: {},
credentials: 'same-origin'
};
if (options.json !== undefined) {
config.headers['Content-Type'] = 'application/json';
config.body = JSON.stringify(options.json);
} else if (options.body) {
config.body = options.body;
}
const response = await fetch(`/api/${path}`, config);
let data;
try {
data = await response.json();
} catch (_) {
data = { ok: false, message: '服务器响应异常,请刷新后重试' };
}
if (!response.ok && !data.message) data.message = `请求失败(${response.status})`;
return data;
}
function toast(message, isError = false) {
let element = document.querySelector('#toast');
if (!element) {
element = document.createElement('div');
element.id = 'toast';
element.className = 'toast';
document.body.appendChild(element);
}
element.textContent = message;
element.classList.toggle('error', Boolean(isError));
element.classList.add('show');
clearTimeout(element.timer);
element.timer = setTimeout(() => element.classList.remove('show'), 3800);
}
function text(value) {
return String(value ?? '').replace(/[&<>"']/g, ch => ({
'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
}[ch]));
}
function requireConfirm(message) {
return window.confirm(message);
}
function setButtonsDisabled(root, disabled) {
root.querySelectorAll('button[data-working]').forEach(button => {
button.disabled = disabled || button.dataset.alwaysDisabled === '1';
});
}