全局模糊搜索
支持通过 UID、用户名、真实姓名、所属学校 四个维度进行实时匹配。
AdminUserList.vue 负责维护实验室的研究员名单。它通过多重过滤算法,确保管理员能在数百名用户中快速定位特定人员。
全局模糊搜索
支持通过 UID、用户名、真实姓名、所属学校 四个维度进行实时匹配。
科研机构统计
自动计算当前系统中覆盖的高校/科研机构数量。
const users = ref<any[]>([]); // 存放全量用户const searchQuery = ref(''); // 搜索框里的文字const loading = ref(false); // 加载转圈圈的状态const currentPage = ref(1); // 当前是第几页const itemsPerPage = 10; // 每页死磕10条数据// 作用:第一层过滤,把符合搜索条件的人挑出来const filteredUsers = computed(() => { if (!searchQuery.value) return users.value; const s = searchQuery.value.toLowerCase(); return users.value.filter(u => u.username?.toLowerCase().includes(s) || u.real_name?.toLowerCase().includes(s) || u.school?.toLowerCase().includes(s) || u.id.toString().includes(s) );});
// 作用:根据过滤后的结果,实时算出总共该有多少页const totalPages = computed(() => { return Math.ceil(filteredUsers.value.length / itemsPerPage) || 1;});
// 作用:最后从过滤后的结果里,切出当前页要显示的10个人const paginatedUsers = computed(() => { const start = (currentPage.value - 1) * itemsPerPage; const end = start + itemsPerPage; return filteredUsers.value.slice(start, end);});// 作用:显示“当前正在看第 X 到 Y 条”中的范围计算const startRange = computed(() => (currentPage.value - 1) * itemsPerPage + 1);const endRange = computed(() => Math.min(currentPage.value * itemsPerPage, filteredUsers.value.length));
// 作用:傻瓜页码条,只显示当前页前后的2页,防止页码太长const displayedPages = computed(() => { const pages: number[] = []; const start = Math.max(1, currentPage.value - 2); const end = Math.min(totalPages.value, currentPage.value + 2); for (let i = start; i <= end; i++) pages.push(i); return pages;});
// 翻页方法const nextPage = () => { if (currentPage.value < totalPages.value) currentPage.value++; };const prevPage = () => { if (currentPage.value > 1) currentPage.value--; };
// 统计:利用 Set 的去重特性算出有多少所学校const uniqueSchools = computed(() => { const schools = users.value.map(u => u.school).filter(s => !!s); return new Set(schools).size;});// 作用:从后端搬运研究员名单const fetchUsers = async () => { loading.value = true; try { const res = await axios.get('/admin/users'); users.value = res.data; } catch (err: any) { Swal.fire({ ...swalConfig, icon: 'error', title: '获取失败' }); } finally { loading.value = false; }};
// 作用:注销账户。删人前会弹出严厉的警告。const deleteUser = async (id: number) => { const result = await Swal.fire({ ...swalConfig, title: '确认注销账户?', text: "该操作将导致该研究员的所有历史计算记录被同步永久抹除。", icon: 'warning', showCancelButton: true, confirmButtonText: '确定删除' });
if (result.isConfirmed) { await axios.delete(`/admin/users/${id}`); await fetchUsers(); // 删完立刻重新拉取名单 }};为了保持实验室管理系统 UI 的统一,我们禁用了默认样式并应用了自定义类名:
const swalConfig = { customClass: { popup: 'my-swal-popup', // 自定义弹窗背景 confirmButton: 'my-swal-confirm', // 自定义确定按钮样式 cancelButton: 'my-swal-cancel' // 自定义取消按钮样式 }, buttonsStyling: false // 必须设置为 false 才能让 Tailwind 类名生效};