|
@@ -0,0 +1,360 @@
|
|
|
+<template>
|
|
|
+ <div class="part-box is-filter">
|
|
|
+ <el-form :model="searchModel" inline @submit.prevent="toPage(1)">
|
|
|
+ <el-form-item label="登录名">
|
|
|
+ <el-input
|
|
|
+ v-model.trim="searchModel.loginName"
|
|
|
+ placeholder="请输入登录名"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="名称">
|
|
|
+ <el-input
|
|
|
+ v-model.trim="searchModel.name"
|
|
|
+ placeholder="请输入名称"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="状态">
|
|
|
+ <el-select
|
|
|
+ v-model="searchModel.status"
|
|
|
+ placeholder="请选择状态"
|
|
|
+ clearable
|
|
|
+ style="width: 100px"
|
|
|
+ >
|
|
|
+ <el-option label="启用" value="enabled" />
|
|
|
+ <el-option label="禁用" value="disabled" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="角色">
|
|
|
+ <el-select
|
|
|
+ v-model="searchModel.role"
|
|
|
+ placeholder="请选择角色"
|
|
|
+ clearable
|
|
|
+ style="width: 200px"
|
|
|
+ >
|
|
|
+ <el-option label="学校管理员" value="school_admin" />
|
|
|
+ <el-option label="扫描员" value="scanner" />
|
|
|
+ <el-option label="普通用户" value="user" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-space wrap>
|
|
|
+ <el-button type="primary" @click="toPage(1)">查询</el-button>
|
|
|
+ <el-button type="success" @click="onAdd">新建用户</el-button>
|
|
|
+
|
|
|
+ <el-dropdown @command="onImportCommand">
|
|
|
+ <el-button type="primary">
|
|
|
+ 导入
|
|
|
+ <el-icon class="el-icon--right"><ArrowDown /> </el-icon>
|
|
|
+ </el-button>
|
|
|
+ <template #dropdown>
|
|
|
+ <el-dropdown-menu>
|
|
|
+ <el-dropdown-item command="kzz">科组长</el-dropdown-item>
|
|
|
+ <el-dropdown-item command="fhy">复核员</el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </template>
|
|
|
+ </el-dropdown>
|
|
|
+ <el-button type="primary" @click="onImportMarker"
|
|
|
+ >导入班级评卷员</el-button
|
|
|
+ >
|
|
|
+
|
|
|
+ <el-dropdown @command="onExportCommand">
|
|
|
+ <el-button type="primary">
|
|
|
+ 导出
|
|
|
+ <el-icon class="el-icon--right"><ArrowDown /> </el-icon>
|
|
|
+ </el-button>
|
|
|
+ <template #dropdown>
|
|
|
+ <el-dropdown-menu>
|
|
|
+ <el-dropdown-item command="kzz">导出</el-dropdown-item>
|
|
|
+ <el-dropdown-item command="fhy"
|
|
|
+ >按考试导出全部</el-dropdown-item
|
|
|
+ >
|
|
|
+ <el-dropdown-item command="fhy"
|
|
|
+ >按考试导出科目拆分表</el-dropdown-item
|
|
|
+ >
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </template>
|
|
|
+ </el-dropdown>
|
|
|
+ <el-button type="success" @click="onBatchAdd">批量新增</el-button>
|
|
|
+
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ :disabled="!canBatchAction"
|
|
|
+ @click="onBatchEnable(true)"
|
|
|
+ >启用</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ type="warning"
|
|
|
+ :disabled="!canBatchAction"
|
|
|
+ @click="onBatchEnable(false)"
|
|
|
+ >禁用</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ type="danger"
|
|
|
+ :disabled="!canBatchAction"
|
|
|
+ @click="onBatchResetPassword"
|
|
|
+ >重置密码</el-button
|
|
|
+ >
|
|
|
+ </el-space>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="part-box">
|
|
|
+ <el-table
|
|
|
+ v-loading="loadingTable"
|
|
|
+ :data="dataList"
|
|
|
+ class="page-table"
|
|
|
+ @selection-change="handleSelectionChange"
|
|
|
+ >
|
|
|
+ <el-table-column type="selection" width="55" />
|
|
|
+ <el-table-column prop="loginName" label="登录名" />
|
|
|
+ <el-table-column prop="name" label="名称" />
|
|
|
+ <el-table-column prop="employeeId" label="工号" />
|
|
|
+ <el-table-column prop="source" label="来源" />
|
|
|
+ <el-table-column prop="role" label="角色">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ formatRole(row.role) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="status" label="状态">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-tag :type="row.status === 'enabled' ? 'success' : 'danger'">
|
|
|
+ {{ row.status === 'enabled' ? '启用' : '禁用' }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="140">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button size="small" type="primary" link @click="onEdit(row)"
|
|
|
+ >编辑</el-button
|
|
|
+ >
|
|
|
+ <el-button
|
|
|
+ size="small"
|
|
|
+ type="danger"
|
|
|
+ link
|
|
|
+ @click="onResetPassword(row)"
|
|
|
+ >重置密码</el-button
|
|
|
+ >
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="pagination.pageNumber"
|
|
|
+ v-model:page-size="pagination.pageSize"
|
|
|
+ :layout="pagination.layout"
|
|
|
+ :total="pagination.total"
|
|
|
+ @size-change="pageSizeChange"
|
|
|
+ @current-change="toPage"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 新增/编辑用户弹窗 -->
|
|
|
+ <ModifyUser ref="modifyUserRef" :row-data="curRow" @modified="getList" />
|
|
|
+
|
|
|
+ <!-- 导入用户 -->
|
|
|
+ <ImportDialog
|
|
|
+ ref="importUserDialogRef"
|
|
|
+ title="导入用户"
|
|
|
+ upload-url="/api/admin/site/import"
|
|
|
+ :format="['xls', 'xlsx']"
|
|
|
+ :download-handle="downloadTemplate"
|
|
|
+ download-filename="用户导入模板.xlsx"
|
|
|
+ />
|
|
|
+ <!-- 导入班级评卷员 -->
|
|
|
+ <ImportDialog
|
|
|
+ ref="importMarkerDialogRef"
|
|
|
+ title="导入班级评卷员"
|
|
|
+ upload-url="/api/admin/site/import"
|
|
|
+ :format="['xls', 'xlsx']"
|
|
|
+ :download-handle="downloadTemplate"
|
|
|
+ download-filename="导入班级评卷员模板.xlsx"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 批量新增用户弹窗 -->
|
|
|
+ <BatchCreateUserDialog ref="batchCreateUserDialogRef" @modified="getList" />
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+ import { reactive, ref, onMounted, computed } from 'vue';
|
|
|
+ import { ElMessage } from 'element-plus';
|
|
|
+ import { ArrowDown } from '@element-plus/icons-vue';
|
|
|
+ import { userListPage, resetUserPassword, enableUser } from '@/api/user';
|
|
|
+ import type { UserItem, UserListFilter } from '@/api/types/user';
|
|
|
+ import useTable from '@/hooks/table';
|
|
|
+ import { modalConfirm } from '@/utils/ui';
|
|
|
+
|
|
|
+ import ModifyUser from './ModifyUser.vue'; // 引入弹窗组件
|
|
|
+ import BatchCreateUserDialog from './components/BatchCreateUserDialog.vue';
|
|
|
+
|
|
|
+ defineOptions({
|
|
|
+ name: 'UserManage',
|
|
|
+ });
|
|
|
+
|
|
|
+ const searchModel = reactive<UserListFilter>({});
|
|
|
+
|
|
|
+ const {
|
|
|
+ dataList,
|
|
|
+ pagination,
|
|
|
+ getList,
|
|
|
+ toPage,
|
|
|
+ pageSizeChange,
|
|
|
+ loading: loadingTable,
|
|
|
+ } = useTable<UserItem>(userListPage, searchModel);
|
|
|
+
|
|
|
+ const modifyUserRef = ref<InstanceType<typeof ModifyUser> | null>(null);
|
|
|
+ const batchCreateUserDialogRef = ref<InstanceType<
|
|
|
+ typeof BatchCreateUserDialog
|
|
|
+ > | null>(null);
|
|
|
+ const curRow = ref<UserItem | undefined>(undefined);
|
|
|
+ const selectedRows = ref<UserItem[]>([]);
|
|
|
+
|
|
|
+ const canBatchAction = computed(() => {
|
|
|
+ return selectedRows.value.length > 0;
|
|
|
+ });
|
|
|
+
|
|
|
+ const onAdd = () => {
|
|
|
+ curRow.value = undefined; // 清除当前行数据,表示新增
|
|
|
+ modifyUserRef.value?.open();
|
|
|
+ };
|
|
|
+
|
|
|
+ const onBatchAdd = () => {
|
|
|
+ batchCreateUserDialogRef.value?.open();
|
|
|
+ };
|
|
|
+
|
|
|
+ const onEdit = (row: UserItem) => {
|
|
|
+ curRow.value = row;
|
|
|
+ modifyUserRef.value?.open();
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSelectionChange = (selection: UserItem[]) => {
|
|
|
+ selectedRows.value = selection;
|
|
|
+ };
|
|
|
+
|
|
|
+ const onResetPassword = async (row: UserItem) => {
|
|
|
+ const confirm = await modalConfirm(
|
|
|
+ `确定要重置用户 "${row.name}" 的密码吗?`,
|
|
|
+ '提示'
|
|
|
+ ).catch(() => false);
|
|
|
+ if (!confirm) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用重置密码接口,不传递新密码,由后端处理
|
|
|
+ await resetUserPassword({ ids: [row.id] });
|
|
|
+ ElMessage.success('密码重置成功!');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('操作失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // const onDelete = async (row: UserItem) => {
|
|
|
+ // const confirm = await modalConfirm(
|
|
|
+ // `确定要删除用户 "${row.name}" 吗?`,
|
|
|
+ // '警告'
|
|
|
+ // ).catch(() => false);
|
|
|
+ // if (!confirm) return;
|
|
|
+
|
|
|
+ // try {
|
|
|
+ // await deleteUser(row.id);
|
|
|
+ // ElMessage.success('用户删除成功!');
|
|
|
+ // getList(); // 刷新列表
|
|
|
+ // } catch (error) {
|
|
|
+ // if (error !== 'cancel') {
|
|
|
+ // console.error('删除用户失败:', error);
|
|
|
+ // // ElMessage.error('删除用户失败');
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // };
|
|
|
+
|
|
|
+ const formatRole = (roleKey: string) => {
|
|
|
+ const roleMap: Record<string, string> = {
|
|
|
+ school_admin: '学校管理员',
|
|
|
+ scanner: '扫描员',
|
|
|
+ user: '普通用户',
|
|
|
+ };
|
|
|
+ return roleMap[roleKey] || roleKey;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 导入用户
|
|
|
+ const importUserDialogRef = ref();
|
|
|
+ const importData = reactive({
|
|
|
+ importType: 'kzz',
|
|
|
+ });
|
|
|
+ const onImportCommand = (command: string) => {
|
|
|
+ console.log('导入命令:', command);
|
|
|
+ importData.importType = command;
|
|
|
+ importUserDialogRef.value?.open();
|
|
|
+ };
|
|
|
+ async function downloadTemplate() {
|
|
|
+ // const res = await downloadByApi(() => agentTemplate()).catch((e) => {
|
|
|
+ // Message.error(e || '下载失败,请重新尝试!');
|
|
|
+ // });
|
|
|
+ // if (!res) return;
|
|
|
+ // Message.success('下载成功!');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 导入班级评卷员
|
|
|
+ const importMarkerDialogRef = ref();
|
|
|
+ const onImportMarker = () => {
|
|
|
+ importMarkerDialogRef.value?.open();
|
|
|
+ };
|
|
|
+
|
|
|
+ // 导出
|
|
|
+ const onExportCommand = (command: string) => {
|
|
|
+ console.log('导出命令:', command);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 批量启用、禁用
|
|
|
+ const onBatchEnable = async (enabled: boolean) => {
|
|
|
+ if (canBatchAction.value) {
|
|
|
+ ElMessage.warning('请至少选择一个用户');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const action = enabled ? '启用' : '禁用';
|
|
|
+ const confirm = await modalConfirm(
|
|
|
+ `确定要${action}选中的 ${selectedRows.value.length} 个用户吗?`,
|
|
|
+ '提示'
|
|
|
+ ).catch(() => false);
|
|
|
+ if (!confirm) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用重置密码接口,不传递新密码,由后端处理
|
|
|
+ await enableUser({
|
|
|
+ ids: selectedRows.value.map((user) => user.id),
|
|
|
+ enabled,
|
|
|
+ });
|
|
|
+ ElMessage.success('操作成功!');
|
|
|
+ getList();
|
|
|
+ } catch (error) {
|
|
|
+ console.error('操作失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 批量重置密码
|
|
|
+ const onBatchResetPassword = async () => {
|
|
|
+ if (canBatchAction.value) {
|
|
|
+ ElMessage.warning('请至少选择一个用户');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const confirm = await modalConfirm(
|
|
|
+ `确定要重置选中 ${selectedRows.value.length} 个用户的密码吗?`,
|
|
|
+ '提示'
|
|
|
+ ).catch(() => false);
|
|
|
+ if (!confirm) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用重置密码接口,不传递新密码,由后端处理
|
|
|
+ await resetUserPassword({
|
|
|
+ ids: selectedRows.value.map((user) => user.id),
|
|
|
+ });
|
|
|
+ ElMessage.success('操作成功!');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('操作失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ // getList();
|
|
|
+ });
|
|
|
+</script>
|