[FIX] 修復帳號管理角色下拉選單消失問題並優化初始化防護 & [STYLE] 新增個人檔案選單圖標
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 58s

This commit is contained in:
2026-03-25 09:47:17 +08:00
parent 2467d9db7a
commit 9f3a90b2b0
2 changed files with 60 additions and 35 deletions

View File

@@ -10,22 +10,12 @@ $roleSelectConfig = [
"hasSearch" => true,
"searchPlaceholder" => __('Search Role...'),
"isHidePlaceholder" => false,
"searchClasses" => "block w-[calc(100%-16px)] mx-2 py-2 px-3 text-sm border-slate-200 dark:border-white/10 rounded-lg
focus:border-cyan-500 focus:ring-cyan-500 bg-slate-50 dark:bg-slate-900/50 dark:text-slate-200
placeholder:text-slate-400 dark:placeholder:text-slate-500",
"searchClasses" => "block w-[calc(100%-16px)] mx-2 py-2 px-3 text-sm border-slate-200 dark:border-white/10 rounded-lg focus:border-cyan-500 focus:ring-cyan-500 bg-slate-50 dark:bg-slate-900/50 dark:text-slate-200 placeholder:text-slate-400 dark:placeholder:text-slate-500",
"searchWrapperClasses" => "sticky top-0 bg-white/95 dark:bg-slate-900/95 backdrop-blur-md p-2 z-10",
"toggleClasses" => "hs-select-toggle luxury-select-toggle",
"dropdownClasses" => "hs-select-menu w-full bg-white/95 dark:bg-slate-900/95 backdrop-blur-xl border border-slate-200
dark:border-white/10 rounded-xl shadow-[0_20px_50px_rgba(0,0,0,0.3)] mt-2 z-[100] animate-luxury-in",
"optionClasses" => "hs-select-option py-2.5 px-3 mb-0.5 text-sm text-slate-800 dark:text-slate-300 cursor-pointer
hover:bg-slate-100 dark:hover:bg-cyan-500/10 dark:hover:text-cyan-400 rounded-lg flex items-center justify-between
transition-all duration-300",
"optionTemplate" => '<div class="flex items-center justify-between w-full"><span data-title></span><span
class="hs-select-active-indicator hidden text-cyan-500"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"
stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"></polyline>
</svg></span></div>'
"dropdownClasses" => "hs-select-menu w-full bg-white/95 dark:bg-slate-900/95 backdrop-blur-xl border border-slate-200 dark:border-white/10 rounded-xl shadow-[0_20px_50px_rgba(0,0,0,0.3)] mt-2 z-[100] animate-luxury-in",
"optionClasses" => "hs-select-option py-2.5 px-3 mb-0.5 text-sm text-slate-800 dark:text-slate-300 cursor-pointer hover:bg-slate-100 dark:hover:bg-cyan-500/10 dark:hover:text-cyan-400 rounded-lg flex items-center justify-between transition-all duration-300",
"optionTemplate" => '<div class="flex items-center justify-between w-full"><span data-title></span><span class="hs-select-active-indicator hidden text-cyan-500"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg></span></div>'
];
@endphp
@@ -728,12 +718,17 @@ transition-all duration-300",
this.editing = false;
const initialCompanyId = initData.oldValues.company_id;
let initialRole = '';
const roles = this.filteredRoles;
let roles = [];
if (!initialCompanyId || initialCompanyId.toString().trim() === '') {
roles = this.allRoles.filter(r => !r.company_id || r.company_id.toString().trim() === '');
} else {
let companyRoles = this.allRoles.filter(r => r.company_id == initialCompanyId);
roles = companyRoles.length > 0 ? companyRoles : this.allRoles.filter(r => !r.company_id || r.company_id.toString().trim() === '');
}
if (roles.length > 0) {
initialRole = roles[0].name;
} else if (this.allRoles.length > 0) {
const systemRoles = this.allRoles.filter(r => !r.company_id || r.company_id.toString().trim() === '');
if (systemRoles.length > 0) initialRole = systemRoles[0].name;
}
this.currentUser = {
@@ -785,7 +780,11 @@ transition-all duration-300",
const wrapper = document.getElementById('role-select-wrapper');
if (!wrapper) return;
const configStr = JSON.stringify(this.roleSelectConfig);
// 🛡️ 終極防護:自動過濾配置中的換行符號,防止自動排版工具折行導致 Preline 崩潰
const cleanConfig = JSON.parse(JSON.stringify(this.roleSelectConfig), (key, value) => {
return typeof value === 'string' ? value.replace(/\r?\n|\r/g, ' ').trim() : value;
});
const configStr = JSON.stringify(cleanConfig);
const roles = this.filteredRoles;
if (roles.length > 0 && !roles.find(r => r.name === this.currentUser.role)) {
@@ -794,31 +793,40 @@ transition-all duration-300",
this.currentUser.role = '';
}
const oldSelect = document.getElementById('modal-account-role');
if (oldSelect && window.HSSelect && window.HSSelect.getInstance(oldSelect)) {
window.HSSelect.getInstance(oldSelect).destroy();
}
const oldSelects = wrapper.querySelectorAll('select');
oldSelects.forEach(oldSelect => {
if (window.HSSelect && window.HSSelect.getInstance(oldSelect)) {
try { window.HSSelect.getInstance(oldSelect).destroy(); } catch (e) { console.warn('HSSelect destroy warning:', e); }
}
});
wrapper.innerHTML = '';
const selectEl = document.createElement('select');
selectEl.name = 'role';
selectEl.id = 'modal-account-role';
const uniqueSelectId = 'modal-account-role-' + Date.now() + '-' + Math.round(Math.random() * 1000);
selectEl.id = uniqueSelectId;
selectEl.className = 'hidden';
selectEl.setAttribute('data-hs-select', configStr);
roles.forEach(r => {
if (roles.length === 0) {
const opt = document.createElement('option');
opt.value = r.name;
opt.textContent = r.name;
opt.setAttribute('data-title', r.name);
if (r.name === this.currentUser.role) opt.selected = true;
opt.value = '';
opt.textContent = '{{ __("No roles available") }}';
opt.disabled = true;
opt.selected = true;
selectEl.appendChild(opt);
});
} else {
roles.forEach(r => {
const opt = document.createElement('option');
opt.value = r.name;
opt.textContent = r.name;
opt.setAttribute('data-title', r.name);
if (r.name === this.currentUser.role) opt.selected = true;
selectEl.appendChild(opt);
});
}
wrapper.appendChild(selectEl);
if (window.HSStaticMethods && window.HSStaticMethods.autoInit) {
window.HSStaticMethods.autoInit(['select']);
}
selectEl.addEventListener('change', (e) => {
this.currentUser.role = e.target.value;
@@ -832,12 +840,28 @@ transition-all duration-300",
const select = window.HSSelect ? window.HSSelect.getInstance(selectEl) : null;
if (select) {
select.setValue(this.currentUser.role);
select.setValue(this.currentUser.role || '');
} else if (attempts < 20) {
setTimeout(() => waitForHSSelect(attempts + 1), 50);
}
};
waitForHSSelect();
const initPreline = (attempts = 0) => {
if (currentGen !== this._roleGeneration) return;
if (window.HSStaticMethods && window.HSStaticMethods.autoInit) {
try {
window.HSStaticMethods.autoInit(['select']);
waitForHSSelect();
} catch (e) {
console.warn('HSStaticMethods autoInit warning:', e);
}
} else if (attempts < 50) {
setTimeout(() => initPreline(attempts + 1), 50);
}
};
initPreline();
});
},
init() {