fix: WebUI 应用变更确认框改用 FlyonUI overlay 组件

原实现混用了 DaisyUI 的写法(<dialog class="modal"> + .modal-box),
而项目实际引入的是 FlyonUI:其 modal 由 HSOverlay 驱动,显示态靠
overlay-open 变体(&.open)生成,且该变体不会随 @plugin 自动注册
(Tailwind v4 只加载包内同名 flyonui.css,variants.css 被忽略)。

后果是 showModal() 只产生原生遮罩(页面变暗+其余按钮被锁),
对话框本身始终 opacity:0 不可见,也未发出任何请求。

本次改动:
- modal 结构迁移为官方 overlay 结构,开合改用 HSOverlay.open/close,
  取消/关闭按钮走 data-overlay 声明式关闭;
- input.css 注册 overlay-open 变体(带注释说明不可删);
- 顺带修正其余 DaisyUI 残留:tabs-border→tabs-bordered、
  btn-ghost/badge-ghost/badge-neutral→btn-soft/badge-soft。
This commit is contained in:
2026-09-30 00:41:03 +08:00
parent 6d31cba631
commit 1f11e615a9
6 changed files with 103 additions and 55 deletions
+17 -12
View File
@@ -31,7 +31,7 @@ const STATE_BADGES = {
leave_candidate: ['待发离职确认', 'badge-warning'],
pending_confirm: ['待人工确认离职', 'badge-warning'],
confirmed_leave: ['已确认离职', 'badge-error'],
deleted: ['已删除', 'badge-neutral'],
deleted: ['已删除', 'badge-soft'],
};
// ---------------------------------------------------------------- 主题
@@ -246,7 +246,7 @@ function renderUsers() {
});
$('#userRows').innerHTML = rows.map((u) => {
const st = STATE_BADGES[u.state] || [u.state || '未知', 'badge-neutral'];
const st = STATE_BADGES[u.state] || [u.state || '未知', 'badge-soft'];
return `<tr>
<td class="font-medium">${escapeHtml(u.uid)}</td>
<td>${escapeHtml(u.name || '')}</td>
@@ -337,7 +337,7 @@ function renderPlan(plan) {
const ops = plan.ops || [];
$('#planRows').innerHTML = ops.map((op) => `
<tr>
<td><span class="badge ${OP_BADGES[op.kind] || 'badge-neutral'} badge-sm">${OP_LABELS[op.kind] || op.kind}</span></td>
<td><span class="badge ${OP_BADGES[op.kind] || 'badge-soft'} badge-sm">${OP_LABELS[op.kind] || op.kind}</span></td>
<td class="font-medium">${escapeHtml(op.target)}</td>
<td>${escapeHtml(op.detail)}</td>
</tr>`).join('');
@@ -345,9 +345,18 @@ function renderPlan(plan) {
$('#planEmpty').classList.toggle('hidden', ops.length > 0);
}
// FlyonUI 的 overlay(modal)由 flyonui.js 的 HSOverlay 驱动:它切换 open/hidden class 来显隐。
// 不要改回原生 dialog.showModal()——那不会加上 .open,overlay-open 变体不生效,框就永远不可见。
function openApplyModal() {
if (window.HSOverlay) window.HSOverlay.open('#applyModal');
}
function closeApplyModal() {
if (window.HSOverlay) window.HSOverlay.close('#applyModal');
}
async function applyPlan(force = false) {
const modal = document.getElementById('applyModal');
if (modal && typeof modal.close === 'function') modal.close();
closeApplyModal();
try {
const d = await api('/api/sync', {
method: 'POST',
@@ -372,7 +381,7 @@ async function loadRuns() {
<tr>
<td class="whitespace-nowrap">${fmtTime(r.startedAt)}</td>
<td>${r.mode === 'dry-run'
? '<span class="badge badge-ghost badge-sm">预览</span>'
? '<span class="badge badge-soft badge-sm">预览</span>'
: '<span class="badge badge-primary badge-sm">执行</span>'}</td>
<td>${r.trigger === 'schedule' ? '定时' : '手动'}</td>
<td>${r.status === 'success'
@@ -443,14 +452,10 @@ document.addEventListener('DOMContentLoaded', () => {
<div>删除用户 <strong>${s.deleteUser || 0}</strong></div>
<div>新建分组 <strong>${s.createGroup || 0}</strong> · 加入分组 <strong>${s.addMember || 0}</strong> · 移出分组 <strong>${s.removeMember || 0}</strong></div>
</div>`;
const modal = document.getElementById('applyModal');
if (modal && typeof modal.showModal === 'function') modal.showModal();
openApplyModal();
});
$('#applyCancel').addEventListener('click', () => {
const modal = document.getElementById('applyModal');
if (modal && typeof modal.close === 'function') modal.close();
});
// 「取消」与右上角关闭按钮走 data-overlay 声明式关闭,无需额外监听。
$('#applyConfirm').addEventListener('click', () => applyPlan(false));
// 已有会话则直接进入主界面