Sfoglia il codice sorgente

用户管理页面

zhudie 2 anni fa
parent
commit
3b69cad773

public/upload-user-templete/用户批量导入模板.xlsx → public/upload-user-templete/templete.xlsx


+ 2 - 1
src/api/system/user-operate.ts

@@ -8,7 +8,8 @@ export interface UserType {
   mobile?: string;
   isEnable?: boolean;
   nickname?: string;
-  roleIds?: string[];
+  roleIds?: number[];
+  passwordRe?: string;
 }
 
 //添加用户

+ 63 - 66
src/views/system/user/CreateDrawer.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-drawer v-model="isDrawer" :size="width" :title="title" @close="handleReset">
+  <el-drawer v-model="isDrawer" :size="width" :title="props.title" @close="handleReset">
     <el-form
       :model="formParams"
       :rules="rules"
@@ -8,22 +8,19 @@
       :label-width="80"
     >
       <el-form-item label="登录账号" prop="username">
-        <el-input
-          placeholder="请输入登录账号"
-          v-model="formParams.username"
-          :disabled="formParams.userId ? true : false"
-        />
+        <el-input placeholder="请输入登录账号" v-model="formParams.username" />
       </el-form-item>
       <el-form-item label="所属部门" prop="deptId">
-        <el-tree-select
-          :data="deptList"
-          clearable
-          check-strictly
-          v-model="formParams.deptId"
-          placeholder="请选择部门"
-        />
+        <el-select v-model="formParams.deptId" placeholder="请选择组织" class="protocal-select">
+          <el-option
+            v-for="item in departmentList"
+            :key="item.deptId"
+            :label="item.deptName"
+            :value="item.deptId"
+          />
+        </el-select>
       </el-form-item>
-      <el-form-item label="密码" :prop="!formParams.userId ? 'password' : ''">
+      <el-form-item label="密码" prop="password">
         <el-input
           type="password"
           show-password-on="mousedown"
@@ -31,7 +28,7 @@
           v-model="formParams.password"
         />
       </el-form-item>
-      <el-form-item label="确认密码" :prop="!formParams.userId ? 'passwordRe' : ''">
+      <el-form-item label="确认密码" :prop="!formParams.username ? 'passwordRe' : ''">
         <el-input
           type="password"
           show-password-on="mousedown"
@@ -43,10 +40,10 @@
       <el-form-item label="角色" prop="roleIds">
         <el-select clearable v-model="formParams.roleIds" multiple>
           <el-option
-            v-for="(item, index) in getRoleList"
-            :key="index"
-            :label="item.label"
-            :value="item.value"
+            v-for="item in roleList!"
+            :key="item.roleId"
+            :label="item.roleName"
+            :value="item.roleId"
           />
         </el-select>
       </el-form-item>
@@ -56,17 +53,20 @@
       <el-form-item label="手机" prop="mobile">
         <el-input placeholder="请输入手机" v-model="formParams.mobile" />
       </el-form-item>
-      <el-form-item label="邮箱" prop="email">
-        <el-input placeholder="请输入邮箱" v-model="formParams.email" />
+      <el-form-item label="工号" prop="staffNo">
+        <el-input placeholder="请输入工号" v-model="formParams.staffNo" />
       </el-form-item>
-      <el-form-item label="性别" prop="sex">
+      <!-- <el-form-item label="邮箱" prop="email">
+        <el-input placeholder="请输入邮箱" v-model="formParams.email" />
+      </el-form-item> -->
+      <!-- <el-form-item label="性别" prop="sex">
         <el-radio-group v-model="formParams.sex" name="sexGroup">
           <el-radio v-for="item in sexList" :key="item.dictValue" :label="item.dictLabel">
             {{ item.dictLabel }}
           </el-radio>
         </el-radio-group>
-      </el-form-item>
-      <el-form-item label="所在岗位" prop="postId">
+      </el-form-item> -->
+      <!-- <el-form-item label="所在岗位" prop="postId">
         <el-select clearable multiple v-model="formParams.postId" placeholder="请选择所在岗位">
           <el-option
             v-for="(item, index) in postDataList"
@@ -75,10 +75,10 @@
             :value="item.postId"
           />
         </el-select>
-      </el-form-item>
-      <el-form-item label="个人介绍" prop="remark">
+      </el-form-item> -->
+      <!-- <el-form-item label="个人介绍" prop="remark">
         <el-input type="textarea" placeholder="请输入个人介绍" v-model="formParams.remark" />
-      </el-form-item>
+      </el-form-item> -->
       <el-form-item label="是否启用" prop="isEnable">
         <el-switch v-model="formParams.isEnable" />
       </el-form-item>
@@ -94,16 +94,21 @@
 </template>
 
 <script lang="ts" setup>
-  import { ref, onMounted, computed } from 'vue';
+  import { ref, onMounted } from 'vue';
   import { FormRules, ElMessage } from 'element-plus';
-  import type { formParamsType } from './types';
+  // import type { formParamsType } from './types';
   import { useDictionary } from '@/hooks/web/useDictionary';
 
   import { addUsur, editUsur, userInfo } from '@/api/system/user';
   import { postList } from '@/api/common/index';
-  import { deptTreeList } from '@/api/auth/dept';
+  // import { deptTreeList } from '@/api/auth/dept';
   import { cloneDeep } from 'lodash-es';
-  import { replaceParams } from '@/utils/helper/treeHelper';
+  // import { replaceParams } from '@/utils/helper/treeHelper';
+  import { UserType } from '@/api/system/user-operate';
+  import useSelectContent from './hooks/use-user-para';
+
+  const selectContent = useSelectContent();
+  const { roleList, departmentList } = selectContent;
 
   const rules: FormRules = {
     username: {
@@ -146,54 +151,46 @@
   const props = defineProps({
     title: {
       type: String,
-      default: '添加会员',
+      default: '添加用户',
     },
     width: {
       type: Number,
       default: 450,
     },
-    roleList: {
-      type: Array,
-    },
   });
 
   const sexList = ref<any[]>();
-  const deptList = ref<any[]>();
+  // const deptList = ref<any[]>();
   const postDataList = ref<PostOption[]>([]);
   const defaultValueRef = () => ({
-    userId: null,
-    roleIds: [],
-    isEnable: true,
-    deptId: null,
-    email: '',
-    mobile: '',
-    nickname: '',
     password: '',
-    passwordRe: '',
-    remark: '',
-    sex: '',
+    deptId: -1,
     username: '',
-    postId: [],
+    staffNo: '',
+    mobile: '',
+    isEnable: true,
+    nickname: '',
+    roleIds: [],
   });
 
-  const getRoleList = computed(() => {
-    return props.roleList as SelectOption[];
-  });
+  // const getRoleList = computed(() => {
+  //   return props.roleList as SelectOption[];
+  // });
 
   const message = ElMessage;
   const formRef: any = ref(null);
   const isDrawer = ref(false);
   const subLoading = ref(false);
 
-  const formParams = ref<formParamsType>(defaultValueRef());
+  const formParams = ref<UserType>(defaultValueRef());
 
-  async function openDrawer(userId?) {
-    const deptResList = await deptTreeList();
-    deptList.value = replaceParams(deptResList, 'deptName', 'deptId');
+  async function openDrawer(username?) {
+    // const deptResList = await deptTreeList();
+    // deptList.value = replaceParams(deptResList, 'deptName', 'deptId');
     const postListRes = await postList();
     postDataList.value = postListRes;
-    if (userId) {
-      formParams.value.userId = userId;
+    if (username) {
+      formParams.value.username = username;
       getInfo();
       return;
     }
@@ -212,20 +209,20 @@
       // 克隆
       const params = cloneDeep(formParams.value);
       // 处理岗位
-      if (params.postId && params.postId.length) {
-        params.postId = params.postId.join(',');
-      } else {
-        params.postId = '';
-      }
+      // if (params.postId && params.postId.length) {
+      //   params.postId = params.postId.join(',');
+      // } else {
+      //   params.postId = '';
+      // }
       // 处理部门
       if (params.deptId) {
-        params.deptId = params.deptId + '';
+        params.deptId = params.deptId;
       }
       if (params.password != params.passwordRe) {
         return message.error('两次密码不一致');
       }
-      const msg = params.userId ? '编辑成功' : '添加成功';
-      if (params.userId) {
+      const msg = params.username ? '编辑成功' : '添加成功';
+      if (params.username) {
         editUsur(params).then((_) => {
           message.success(msg);
           emit('change');
@@ -249,9 +246,9 @@
   }
 
   function getInfo() {
-    userInfo({ userId: formParams.value.userId }).then((res) => {
+    userInfo({ userId: formParams.value.username }).then((res) => {
       const params = {
-        userId: formParams.value.userId,
+        userId: formParams.value.username,
         deleteStatus: parseInt(res.deleteStatus),
         email: res.email,
         mobile: res.mobile,

+ 68 - 15
src/views/system/user/columns.ts

@@ -2,17 +2,70 @@ import { h } from 'vue';
 import { ElTag } from 'element-plus';
 import { BasicColumn } from '@/components/Table';
 
+// export const columns: BasicColumn[] = [
+//   // {
+//   //   type: 'selection',
+//   // },
+//   {
+//     label: '账号',
+//     prop: 'username',
+//   },
+//   {
+//     label: '用户名',
+//     prop: 'nickname',
+//   },
+//   {
+//     label: '手机',
+//     prop: 'mobile',
+//   },
+//   {
+//     label: '状态',
+//     prop: 'isEnable',
+//     render(record) {
+//       return h(
+//         ElTag,
+//         {
+//           type: record.row.isEnable ? 'success' : 'danger',
+//         },
+//         {
+//           default: () => (record.row.isEnable ? '启用' : '禁用'),
+//         },
+//       );
+//     },
+//   },
+//   {
+//     label: '角色',
+//     prop: 'roleName',
+//   },
+//   {
+//     label: '租户',
+//     prop: 'tenantName',
+//   },
+//   {
+//     label: '部门',
+//     prop: 'deptName',
+//   },
+//   {
+//     label: '岗位',
+//     prop: 'postName',
+//   },
+//   // {
+//   //   label: '描述',
+//   //   prop: 'remark',
+//   // },
+//   {
+//     label: '创建时间',
+//     prop: 'createTime',
+//   },
+// ];
+
 export const columns: BasicColumn[] = [
-  {
-    type: 'selection',
-  },
-  {
-    label: '账号',
-    prop: 'username',
-  },
+  // {
+  //   type: 'selection',
+  // },
   {
     label: '用户名',
-    prop: 'nickname',
+    prop: 'username',
   },
   {
     label: '手机',
@@ -28,7 +81,7 @@ export const columns: BasicColumn[] = [
           type: record.row.isEnable ? 'success' : 'danger',
         },
         {
-          default: () => (record.row.isEnable ? '启用' : '禁用'),
+          default: () => (record.row.isEnable ? '正常' : '锁定'),
         },
       );
     },
@@ -46,15 +99,15 @@ export const columns: BasicColumn[] = [
     prop: 'deptName',
   },
   {
-    label: '岗位',
-    prop: 'postName',
+    label: '创建时间',
+    prop: 'createTime',
   },
   // {
   //   label: '描述',
   //   prop: 'remark',
   // },
-  {
-    label: '创建时间',
-    prop: 'createTime',
-  },
+  // {
+  //   label: '创建时间',
+  //   prop: 'createTime',
+  // },
 ];

+ 32 - 0
src/views/system/user/component/ActionColomns.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="flex items-center justify-center">
+    <el-space :size="space">
+      <div v-for="item in props.actionIcons" :key="item.label" @click="item.onClick">
+        <el-tooltip :content="item.label" effect="light">
+          <el-icon v-if="props.style === 'icon'" :color="props.color" :size="props.size">
+            <component :is="item.icon" />
+          </el-icon>
+          <img
+            v-if="props.style === 'img'"
+            :src="item.icon"
+            :style="{ width: `${props.size}px` }"
+          />
+        </el-tooltip>
+      </div>
+    </el-space>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ActionItem } from '@/components/Table';
+
+  const props = defineProps<{
+    space: number;
+    size: number;
+    color: string;
+    style: 'img' | 'icon';
+    actionIcons: ActionItem[];
+  }>();
+</script>
+
+<style scoped></style>

+ 108 - 0
src/views/system/user/component/AddUser.vue

@@ -0,0 +1,108 @@
+<template>
+  <el-card v-if="props.modelValue" class="pop-card">
+    <template #header>
+      <div class="flex justify-between items-center pop-head">
+        <div style="font-size: 16px">批量导入</div>
+        <el-icon :size="16" class="mr-3" @click="updateValue(false)"><Close /></el-icon
+      ></div>
+    </template>
+    <div class="upload-content">
+      <el-upload
+        ref="upload"
+        class="upload-demo"
+        drag
+        action="http://localhost:8092/api/user/import"
+        :headers="headers"
+        :with-credentials="true"
+        :auto-upload="false"
+        :before-upload="beforeUpload"
+        :on-success="handleUploadSuccess"
+        :on-error="handleUploadError"
+        style="width: 384px; height: 192px; border-radius: 8px"
+      >
+        <el-icon class="el-icon--upload" style="width: 33px; height: 42px"><Document /></el-icon>
+        <div class="el-upload__text">
+          <div style="font-size: 16px">点击或将文件拖拽到这里上传</div>
+          <div style="font-size: 14px; color: rgba(0, 0, 0, 0.45)"
+            >文件只支持:.xlsx .xls .仅支持上传一个文件</div
+          ></div
+        >
+      </el-upload>
+      <div style="margin-top: 52px; margin-left: 288px; display: flex">
+        <el-button @click="handleDownload" style="margin-right: 10px">下载模板</el-button>
+        <el-button type="primary" @click="handleImport">导入</el-button></div
+      ></div
+    >
+  </el-card>
+</template>
+
+<script setup lang="ts">
+  import { Close, Document } from '@element-plus/icons-vue';
+  import { ref } from 'vue';
+  import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
+  import { downloadByUrl } from '@/utils/file/download';
+  //   import templateUrl from './templete.xlsx';
+  import { useUserStore } from '@/store/modules/user';
+  //   http://localhost:8092/api/user/import
+
+  const userStore = useUserStore();
+
+  const headers = {
+    Satoken: userStore.getToken,
+    Tenantid: userStore.getTenantId,
+  };
+
+  const isSuc = ref<boolean>(true);
+  const errDetail = ref<string[]>([]);
+  const sucCount = ref<number>(0);
+  //   console.log('headers', headers);
+
+  const props = defineProps<{ modelValue: boolean }>();
+  const emits = defineEmits(['update:modelValue']);
+
+  const updateValue = (value) => {
+    emits('update:modelValue', value);
+  };
+  const upload = ref<UploadInstance>();
+
+  const handleDownload = () => {
+    downloadByUrl({
+      url: 'http://localhost:3000/dist/upload-user-templete/templete.xlsx',
+      target: '_self',
+    });
+  };
+  const handleImport = async () => {
+    upload.value!.submit();
+
+    // emits('update:modelValue', false);
+  };
+
+  const beforeUpload = (file) => {
+    const isExcel = /\.(xlsx|xls)$/.test(file.name.toLowerCase());
+    if (!isExcel) {
+      // 提示用户选择正确的文件类型
+      return false; // 阻止上传
+    }
+    return true; // 允许上传
+  };
+
+  const handleUploadSuccess = (response, file, fileList) => {
+    // const res = JSON.parse(response);
+    console.log('response', response);
+    isSuc.value = response.data.isSuc;
+    errDetail.value = response.data.failedInfo;
+    sucCount.value = response.data.sucCount;
+    console.log(isSuc.value, errDetail.value);
+  };
+  const handleUploadError = (err, file, fileList) => {
+    console.log('222');
+    console.log(err);
+  };
+</script>
+
+<style scoped>
+  .upload-content {
+    margin-left: 96px;
+    margin-top: 36px;
+  }
+</style>

+ 2 - 0
src/views/system/user/hooks/use-user.ts

@@ -82,6 +82,8 @@ export const useUser = defineStore('user-list', () => {
   const getList = () => {
     getUserList(null).then((res) => {
       userList.value = res.list;
+      console.log('userList.value', userList.value);
+
       totalCount.value = res.totalCount;
     });
   };

+ 62 - 18
src/views/system/user/user.vue

@@ -23,18 +23,34 @@
       >
         <template #tableTitle>
           <el-space align="center">
-            <el-button type="primary" @click="openCreateDrawer">
+            <el-button type="primary" @click="openAddSingleDrawer">
               <template #icon>
                 <el-icon>
-                  <FileAddOutlined />
+                  <Plus />
                 </el-icon>
               </template>
               添加
             </el-button>
+            <el-button
+              color="#1890FF"
+              @click="openAddMultipleDrawer"
+              style="margin-left: 18px"
+              plain
+            >
+              <template #icon>
+                <el-icon>
+                  <DocumentAdd />
+                </el-icon>
+              </template>
+              批量导入
+            </el-button>
           </el-space>
         </template>
       </BasicTable>
     </div>
+    <CreateDrawer ref="createDrawerRef" :title="drawerTitle" @change="reloadTable" />
+    <!-- <Download /> -->
+    <AddUser v-model="showAddPopover" class="add-popover" />
   </div>
   <!-- <PageWrapper>
     <el-card :bordered="false" class="proCard"> </el-card>
@@ -53,11 +69,17 @@
   import { ElMessage } from 'element-plus';
   import { BasicTable, TableAction, BasicColumn } from '@/components/Table';
   import { getUserList } from '@/api/system/user';
+  import { Plus, DocumentAdd } from '@element-plus/icons-vue';
   import { FileAddOutlined } from '@vicons/antd';
+  import Download from '@/views/feature/download/download.vue';
   import { roleAllList } from '@/api/system/role';
   import { delUser } from '@/api/system/user';
-  // import CreateDrawer from './CreateDrawer.vue';
+  import editIcon from '@/assets/images/table/table-edit.png';
+  import deleteIcon from '@/assets/images/table/table-delete.png';
+  import CreateDrawer from './CreateDrawer.vue';
   import { columns } from './columns';
+  import ActionColomns from './component/ActionColomns.vue';
+  import AddUser from './component/AddUser.vue';
   // import { Search } from '@element-plus/icons-vue';
   import UserQuery from './component/UserQuery.vue';
   import useUser from './hooks/use-user';
@@ -110,25 +132,25 @@
     width: 150,
     title: '操作',
     prop: 'action',
+    key: 'action',
     fixed: 'right',
-    align: 'center',
     render(record) {
-      return h(TableAction as any, {
-        actions: [
-          {
-            label: '删除',
-            isConfirm: true,
-            popConfirm: {
-              onConfirm: handleDelete.bind(null, record.row),
-              title: '您确定要删除吗?',
-              confirmButtonText: '确定',
-              cancelButtonText: '取消',
-            },
-          },
+      return h(ActionColomns as any, {
+        space: 20,
+        color: '#629bf9',
+        style: 'img',
+        size: 16,
+        actionIcons: [
           {
             label: '编辑',
+            icon: editIcon,
             onClick: handleEdit.bind(null, record.row),
           },
+          {
+            label: '删除',
+            icon: deleteIcon,
+            onClick: handleDelete.bind(null, record.row),
+          },
         ],
       });
     },
@@ -156,10 +178,21 @@
     basicTableRef.value.reload();
   }
 
-  function openCreateDrawer() {
+  // function openAddSingleDrawer() {
+  //   const { openDrawer } = createDrawerRef.value;
+  //   openDrawer();
+  // }
+
+  const openAddSingleDrawer = () => {
     const { openDrawer } = createDrawerRef.value;
     openDrawer();
-  }
+  };
+
+  const showAddPopover = ref<boolean>(false);
+
+  const openAddMultipleDrawer = () => {
+    showAddPopover.value = true;
+  };
 
   function handleEdit(record: Recordable) {
     console.log('点击了编辑', record);
@@ -195,4 +228,15 @@
   .user-list {
     padding: 0 21px;
   }
+
+  .add-popover {
+    position: absolute;
+    width: 593px;
+    height: 435px;
+    left: 50%;
+    top: 50%;
+    margin-top: -218px;
+    margin-left: -297px;
+    z-index: 99;
+  }
 </style>