소스 검색

feat: 添加User

Gaokun Wang 3 주 전
부모
커밋
61767905d8

+ 32 - 3
src/api/interface/system/user.ts

@@ -8,7 +8,17 @@ export interface UserInfo {
 }
 
 /**
- * 用户返回对象
+ * 查询参数
+ */
+export interface UserQuery extends PageQuery {
+  account?: string
+  userName?: string
+  nickName?: string
+  status?: number
+}
+
+/**
+ * 接收后端返回信息
  */
 export interface UserVO extends BaseEntity {
   userId: string | number
@@ -22,9 +32,28 @@ export interface UserVO extends BaseEntity {
   gender: string
   avatar: string
   url: string
-  status: string
-  delFlag: string
   loginIp: string
   loginDate: string
   remark: string
 }
+
+/**
+ * 传入后端的表单信息
+ */
+export interface UserBO {
+  userId: string | number
+  orgId: string
+  account: string
+  userName: string
+  nickName: string
+  userType: string
+  email: string
+  phoneNumber: string
+  gender: string
+  avatar: string
+  url: string
+  loginIp: string
+  loginDate: string
+  remark?: string
+  status?: string
+}

+ 41 - 1
src/api/module/system/user.ts

@@ -1,9 +1,49 @@
 import http from '@/axios'
-import { UserInfo } from '@/api/interface/system/user'
+import { UserBO, UserInfo, UserQuery, UserVO } from '@/api/interface/system/user'
 
 class UserApi {
   static getInfo = (): Promise<ResultData<any>> => {
     return http.get<UserInfo[]>({ url: '/system/user/info' })
   }
+
+  /**
+   * @name 查询分页
+   * @returns returns
+   */
+  static page = (params: UserQuery): Promise<ResultData<any>> => {
+    return http.get<UserVO>({ url: '/system/user/page', params })
+  }
+
+  /**
+   * @name 查询列表
+   * @returns returns
+   */
+  static list = (params: UserBO): Promise<ResultData<any>> => {
+    return http.get<UserVO>({ url: '/system/user/list', params })
+  }
+
+  /**
+   * @name 添加
+   * @returns returns
+   */
+  static add = (data: UserBO): Promise<ResultData<any>> => {
+    return http.post({ url: '/system/user/add', data })
+  }
+
+  /**
+   * @name 更新
+   * @returns returns
+   */
+  static edit = (data: UserBO): Promise<ResultData<any>> => {
+    return http.post({ url: '/system/user/edit', data })
+  }
+
+  /**
+   * @name 删除
+   * @returns returns
+   */
+  static delete = (data: string[]): Promise<ResultData<any>> => {
+    return http.delete({ url: '/system/user/delete', data })
+  }
 }
 export default UserApi

+ 0 - 1
src/axios/config.ts

@@ -30,7 +30,6 @@ const defaultResponseInterceptors = (response: AxiosResponse) => {
     authStore.clear()
     router.replace(LOGIN_URL)
     ElMessage.error(msg)
-    return
   } else {
     console.error(msg)
     ElMessage.error(msg)

+ 1 - 0
src/types/auto-components.d.ts

@@ -83,6 +83,7 @@ declare module 'vue' {
     SvgIcon: typeof import('./../components/SvgIcon/index.vue')['default']
     TableColumn: typeof import('./../components/ProTable/TableColumn.vue')['default']
     TreeFilter: typeof import('./../components/TreeFilter/index.vue')['default']
+    UserDrawer: typeof import('./../views/system/user/components/UserDrawer.vue')['default']
   }
   export interface GlobalDirectives {
     vLoading: typeof import('element-plus/es')['ElLoadingDirective']

+ 1 - 63
src/views/home/index.vue

@@ -1,65 +1,3 @@
 <template>
-  <div class="main-box">
-    <TreeFilter title="组织架构" :request-api="OrgApi.tree" label="name" :default-value="'0'" @change="changeTreeFilter" />
-
-    <div class="table-box">
-      <ProTable
-        ref="proTableRef"
-        title="角色列表"
-        row-key="roleId"
-        :indent="20"
-        :columns="columns"
-        :search-columns="searchColumns"
-        :request-api="getTableList">
-        <!-- 表格 header 按钮 -->
-        <template #tableHeader="scope">
-          <el-button type="primary" icon="CirclePlus"> 新增角色 </el-button>
-          <el-button type="danger" icon="Delete" plain :disabled="!scope.isSelected"> 批量删除角色 </el-button>
-        </template>
-
-        <template #operation="{ row }">
-          <el-button type="primary" link icon="Lock"> 权限 </el-button>
-          <el-button type="primary" link icon="EditPen"> 编辑 </el-button>
-          <el-button v-if="row.id !== 1" type="primary" link icon="Delete"> 删除 </el-button>
-        </template>
-      </ProTable>
-    </div>
-  </div>
+  <div>首页</div>
 </template>
-<script lang="tsx" setup name="Home">
-import { RoleInfo, RoleQuery } from '@/api/interface/system/role'
-import OrgApi from '@/api/module/system/org'
-import RoleApi from '@/api/module/system/role'
-import { ColumnProps, SearchProps } from '@/components/ProTable/interface'
-// 树形筛选切换
-const changeTreeFilter = (val: string) => {
-  ElMessage.success({ message: `请注意查看请求参数变化 🤔${val}`, duration: 500 })
-}
-// 表格配置项
-const columns: ColumnProps<RoleInfo>[] = [
-  { type: 'selection', width: 60, selectable: row => row.isLock == '1' },
-  { prop: 'roleId', label: '编号', width: 80 },
-  { prop: 'name', label: '角色名称' },
-  { prop: 'code', tag: true, label: '权限标识' },
-  { prop: 'remark', label: '备注' },
-  { prop: 'createByName', label: '创建人' },
-  { prop: 'createTime', label: '创建时间' },
-  { prop: 'updateTime', label: '修改时间' },
-  { prop: 'operation', label: '操作', width: 250, fixed: 'right' }
-]
-
-// 表格配置项
-const searchColumns: SearchProps[] = [
-  { prop: 'name', label: '角色名称', el: 'input' },
-  { prop: 'name', label: '角色名称', el: 'input' },
-  { prop: 'name', label: '角色名称', el: 'input' },
-  { prop: 'name', label: '角色名称', el: 'input' },
-  { prop: 'name', label: '角色名称', el: 'input' },
-  { prop: 'name', label: '角色名称', el: 'input' },
-  { prop: 'name', label: '角色名称', el: 'input' },
-  { prop: 'code', label: '标识', el: 'input' }
-]
-
-// 获取table列表
-const getTableList = (params: RoleQuery) => RoleApi.page(params)
-</script>

+ 1 - 0
src/views/system/config/components/ConfigDrawer.vue

@@ -80,6 +80,7 @@ const emit = defineEmits(['submit'])
 const acceptParams = (params: EcoDrawerProps) => {
   drawerProps.value = params
   drawerVisible.value = true
+  drawerProps.value.row.status = drawerProps.value.row.status || '1'
 }
 
 // 提交数据(新增/编辑)

+ 2 - 0
src/views/system/dict/components/DictDrawer.vue

@@ -114,6 +114,8 @@ const acceptParams = (params: EcoDrawerProps) => {
   drawerProps.value = params
   drawerVisible.value = true
   loadTree()
+  drawerProps.value.row.status = drawerProps.value.row.status || '1'
+  drawerProps.value.row.callbackShowStyle = drawerProps.value.row.callbackShowStyle || 'primary'
 }
 
 const loadTree = () => {

+ 17 - 4
src/views/system/dict/index.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="main-box">
-    <TreeFilter title="字典类型" ref="treeRef" :request-api="DictApi.tree" label="name" :default-value="initParam.dictId" @change="changeTree" />
+    <TreeFilter
+      title="字典类型"
+      ref="treeFilterRef"
+      :request-api="DictApi.tree"
+      label="name"
+      :default-value="initParam.dictId"
+      @change="changeTree" />
     <div class="table-box">
       <ProTable
         ref="proTableRef"
@@ -10,7 +16,8 @@
         :columns="columns"
         :init-param="initParam"
         :search-columns="searchColumns"
-        :request-api="getTableList">
+        :request-api="getTableList"
+        @reset="reset">
         <!-- 表格 header 按钮 -->
         <template #tableHeader="scope">
           <el-button type="primary" icon="CirclePlus" @click="openDrawer('新增')"> 新增 </el-button>
@@ -39,7 +46,7 @@ const initParam = reactive({ dictId: '', parentId: '' })
 
 const selectTreeId = ref<string>('')
 const proTableRef = ref<ProTableInstance>()
-const treeRef = ref<InstanceType<typeof TreeFilter>>()
+const treeFilterRef = ref<InstanceType<typeof TreeFilter>>()
 
 // 树形筛选切换
 const changeTree = (val: string) => {
@@ -52,7 +59,7 @@ const changeTree = (val: string) => {
 
 // 刷新树表
 const refreshTree = () => {
-  treeRef.value?.refresh()
+  treeFilterRef.value?.refresh()
 }
 
 // 表格配置项
@@ -81,6 +88,12 @@ const searchColumns: SearchProps[] = [{ prop: 'dictLabel', label: '字典标签'
 // 获取table列表
 const getTableList = (params: DictQuery) => DictApi.page(params)
 
+// 重置
+const reset = () => {
+  initParam.parentId = ''
+  proTableRef.value?.clearSelection()
+  treeFilterRef.value?.treeRef?.setCurrentKey()
+}
 // 单行删除
 const deleteRow = async (row: DictVO) => {
   await useHandleData(DictApi.delete, [row.dictId], `删除【${row.dictLabel}】字典`)

+ 2 - 1
src/views/system/org/components/OrgDrawer.vue

@@ -29,7 +29,7 @@
         <el-input-number v-model="drawerProps.row.orderNum" :precision="0" :min="1" :max="999999" />
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-radio-group v-model="drawerProps.row.status" default-value="1">
+        <el-radio-group v-model="drawerProps.row.status">
           <el-radio-button :value="item.dictValue" v-for="(item, index) in commonStatus" :key="index" :label="item.dictLabel" />
         </el-radio-group>
       </el-form-item>
@@ -94,6 +94,7 @@ const acceptParams = (params: EcoDrawerProps) => {
   drawerProps.value = params
   drawerVisible.value = true
   loadTree()
+  drawerProps.value.row.status = drawerProps.value.row.status || '1'
 }
 
 const loadTree = () => {

+ 2 - 1
src/views/system/position/components/PositionDrawer.vue

@@ -29,7 +29,7 @@
         <el-input-number v-model="drawerProps.row.orderNum" :precision="0" :min="1" :max="999999" />
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-radio-group v-model="drawerProps.row.status" default-value="1">
+        <el-radio-group v-model="drawerProps.row.status">
           <el-radio-button :value="item.dictValue" v-for="(item, index) in commonStatus" :key="index" :label="item.dictLabel" />
         </el-radio-group>
       </el-form-item>
@@ -92,6 +92,7 @@ const acceptParams = (params: EcoDrawerProps) => {
   drawerProps.value = params
   drawerVisible.value = true
   loadTree()
+  drawerProps.value.row.status = drawerProps.value.row.status || '1'
 }
 
 const loadTree = () => {

+ 17 - 5
src/views/system/position/index.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="main-box">
-    <TreeFilter title="组织架构" ref="treeRef" :request-api="OrgApi.tree" label="name" :default-value="initParam.positionId" @change="changeTree" />
+    <TreeFilter
+      title="组织架构"
+      ref="treeFilterRef"
+      :request-api="OrgApi.tree"
+      label="name"
+      :default-value="initParam.positionId"
+      @change="changeTree" />
     <div class="table-box">
       <ProTable
         ref="proTableRef"
@@ -10,7 +16,8 @@
         :columns="columns"
         :init-param="initParam"
         :search-columns="searchColumns"
-        :request-api="getTableList">
+        :request-api="getTableList"
+        @reset="reset">
         <!-- 表格 header 按钮 -->
         <template #tableHeader="scope">
           <el-button type="primary" icon="CirclePlus" @click="openDrawer('新增')"> 新增职位 </el-button>
@@ -21,7 +28,7 @@
 
         <template #operation="{ row }">
           <el-button type="primary" link icon="EditPen" @click="openDrawer('编辑', row)"> 编辑 </el-button>
-          <el-button v-if="row.id !== 1" type="primary" link icon="Delete" @click="deleteRow(row)"> 删除 </el-button>
+          <el-button type="primary" link icon="Delete" @click="deleteRow(row)"> 删除 </el-button>
         </template>
       </ProTable>
     </div>
@@ -41,7 +48,7 @@ const initParam = reactive({ positionId: '', orgId: '' })
 
 const selectTreeId = ref<string>('')
 const proTableRef = ref<ProTableInstance>()
-const treeRef = ref<InstanceType<typeof TreeFilter>>()
+const treeFilterRef = ref<InstanceType<typeof TreeFilter>>()
 
 // 树形筛选切换
 const changeTree = (val: string) => {
@@ -76,7 +83,12 @@ const searchColumns: SearchProps[] = [{ prop: 'name', label: '职位名称', el:
 
 // 获取table列表
 const getTableList = (params: PositionQuery) => PositionApi.page(params)
-
+// 重置
+const reset = () => {
+  initParam.orgId = ''
+  proTableRef.value?.clearSelection()
+  treeFilterRef.value?.treeRef?.setCurrentKey()
+}
 // 单行删除
 const deleteRow = async (row: PositionVO) => {
   await useHandleData(PositionApi.delete, [row.positionId], `删除【${row.name}】职位`)

+ 148 - 0
src/views/system/user/components/UserDrawer.vue

@@ -0,0 +1,148 @@
+<template>
+  <ElDrawer ref="elDrawerRef" v-model="drawerVisible" :title="drawerProps.title" v-bind="$attrs" destroy-on-close>
+    <template #header="scope">
+      <slot name="header" v-bind="scope">
+        <div style="display: flex">
+          <slot name="title">
+            <span style="flex: 1">{{ drawerProps.title }}</span>
+          </slot>
+        </div>
+      </slot>
+    </template>
+
+    <el-form ref="ruleFormRef" label-width="100px" label-suffix=" :" :rules="rules" :model="drawerProps.row" @submit.enter.prevent="handleConfirm">
+      <el-form-item label="所属组织" prop="orgId">
+        <el-tree-select
+          v-model="drawerProps.row.orgId"
+          :data="treeData"
+          check-strictly
+          placeholder="请选择组织"
+          :render-after-expand="false"
+          clearable
+          :default-expand-all="true"
+          :props="treeProps" />
+      </el-form-item>
+      <el-form-item label="账号" prop="account">
+        <el-input v-model="drawerProps.row.account" placeholder="请填写账号" clearable />
+      </el-form-item>
+      <el-form-item label="名称" prop="userName">
+        <el-input v-model="drawerProps.row.userName" placeholder="请填写名称" clearable />
+      </el-form-item>
+      <el-form-item label="昵称" prop="nickName">
+        <el-input v-model="drawerProps.row.nickName" placeholder="请填写昵称" clearable />
+      </el-form-item>
+      <el-form-item label="性别" prop="gender">
+        <el-input v-model="drawerProps.row.gender" placeholder="请选择性别" clearable />
+      </el-form-item>
+      <el-form-item label="手机号" prop="phoneNumber">
+        <el-input v-model="drawerProps.row.phoneNumber" placeholder="请填写手机号" clearable />
+      </el-form-item>
+      <el-form-item label="邮箱" prop="email">
+        <el-input v-model="drawerProps.row.email" placeholder="请填写邮箱" clearable />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-radio-group v-model="drawerProps.row.status">
+          <el-radio-button :value="item.dictValue" v-for="(item, index) in commonStatus" :key="index" :label="item.dictLabel" />
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="drawerProps.row.remark" placeholder="请填写备注" clearable />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <slot name="footer">
+        <ElButton @click="drawerVisible = false">取 消</ElButton>
+        <ElButton type="primary" @click="handleConfirm()">确 定</ElButton>
+      </slot>
+    </template>
+  </ElDrawer>
+</template>
+
+<script setup lang="ts" name="OrgForm">
+import { UserBO } from '@/api/interface/system/user'
+import OrgApi from '@/api/module/system/org'
+import { ResultEnum } from '@/enums/HttpEnum'
+import { FormInstance } from 'element-plus'
+import { useDictOptions } from '@/hooks'
+import { OrgTreeVO } from '@/api/interface/system/org'
+
+const commonStatus = useDictOptions('COMMON_STATUS')
+const rules = reactive({
+  account: [{ required: true, message: '请填写账号' }],
+  userName: [{ required: true, message: '请填写姓名' }],
+  status: [{ required: true, message: '状态不能为空' }]
+})
+
+interface EcoDrawerProps {
+  api?: (params: any) => Promise<any> // 调用接口
+  title: string // 顶部标题
+  isView: boolean
+  row: Partial<UserBO>
+  getTableList?: () => void
+}
+
+const treeData = ref<OrgTreeVO[]>([])
+const treeProps = {
+  label: 'name',
+  value: 'orgId'
+}
+
+const drawerVisible = ref(false)
+const drawerProps = ref<EcoDrawerProps>({
+  isView: false,
+  title: '',
+  row: {}
+})
+
+// emit
+const emit = defineEmits(['submit'])
+
+// 接收父组件传过来的参数
+const acceptParams = (params: EcoDrawerProps) => {
+  drawerProps.value = params
+  drawerVisible.value = true
+  loadTree()
+  drawerProps.value.row.status = drawerProps.value.row.status || '1'
+}
+
+const loadTree = () => {
+  OrgApi.tree().then(res => {
+    treeData.value = [
+      {
+        parentId: '-1',
+        orgId: '0',
+        name: '顶层',
+        children: res.data
+      }
+    ]
+  })
+}
+
+// 提交数据(新增/编辑)
+const ruleFormRef = ref<FormInstance>()
+const handleConfirm = () => {
+  ruleFormRef.value!.validate(async valid => {
+    if (!valid) return
+    try {
+      console.log(drawerProps.value.row)
+
+      const { code } = await drawerProps.value.api!(drawerProps.value.row)
+      if (code == ResultEnum.SUCCESS) {
+        ElMessage.success({ message: `${drawerProps.value.title}成功!` })
+        drawerProps.value.getTableList!()
+        emit('submit')
+        drawerVisible.value = false
+      }
+    } catch (error) {
+      console.log(error)
+    }
+  })
+}
+
+defineExpose({
+  acceptParams
+})
+</script>
+
+<style scoped lang="scss"></style>

+ 118 - 1
src/views/system/user/index.vue

@@ -1,3 +1,120 @@
 <template>
-  <div>用户</div>
+  <div class="main-box">
+    <TreeFilter title="组织架构" ref="treeFilterRef" :request-api="OrgApi.tree" label="name" :default-value="initParam.userId" @change="changeTree" />
+    <div class="table-box">
+      <ProTable
+        ref="proTableRef"
+        title="组织列表"
+        row-key="userId"
+        :indent="20"
+        :columns="columns"
+        :init-param="initParam"
+        :search-columns="searchColumns"
+        :request-api="getTableList"
+        @reset="reset">
+        <!-- 表格 header 按钮 -->
+        <template #tableHeader="scope">
+          <el-button type="primary" icon="CirclePlus" @click="openDrawer('新增')"> 新增用户 </el-button>
+          <el-button type="danger" icon="Delete" plain :disabled="!scope.isSelected" @click="batchDelete(scope.selectedListIds)">
+            批量删除
+          </el-button>
+        </template>
+
+        <template #operation="{ row }">
+          <el-button type="primary" link icon="EditPen" @click="openDrawer('编辑', row)"> 编辑 </el-button>
+          <el-button v-if="row.userId !== '1'" type="primary" link icon="Delete" @click="deleteRow(row)"> 删除 </el-button>
+        </template>
+      </ProTable>
+    </div>
+    <UserDrawer ref="drawerRef" />
+  </div>
 </template>
+<script lang="tsx" setup name="OrgManage">
+import OrgApi from '@/api/module/system/org'
+import UserApi from '@/api/module/system/user'
+import UserDrawer from './components/UserDrawer.vue'
+import TreeFilter from '@/components/TreeFilter/index.vue'
+import { ColumnProps, ProTableInstance, SearchProps } from '@/components/ProTable/interface'
+import { UserBO, UserQuery, UserVO } from '@/api/interface/system/user'
+import { useDictOptions, useHandleData } from '@/hooks'
+
+const initParam = reactive({ userId: '', orgId: '' })
+
+const selectTreeId = ref<string>('')
+const proTableRef = ref<ProTableInstance>()
+const treeFilterRef = ref<InstanceType<typeof TreeFilter>>()
+
+// 树形筛选切换
+const changeTree = (val: string) => {
+  if (val) {
+    selectTreeId.value = val
+    initParam.orgId = val
+    proTableRef.value?.clearSelection()
+  }
+}
+
+// 表格配置项
+const columns: ColumnProps<UserVO>[] = [
+  { type: 'selection', width: 60, selectable: row => row.userId !== '1' },
+  { prop: 'account', label: '账号', width: 120 },
+  { prop: 'userName', label: '姓名', width: 120 },
+  { prop: 'nickName', label: '昵称', width: 120 },
+  { prop: 'userType', label: '用户类型', tag: true, width: 120 },
+  { prop: 'phoneNumber', label: '手机号码', tag: true, width: 120 },
+  { prop: 'roles', label: '角色', width: 120 },
+  {
+    prop: 'status',
+    label: '状态',
+    tag: true,
+    enum: useDictOptions('COMMON_STATUS'),
+    width: 80,
+    fieldNames: { label: 'dictLabel', value: 'dictValue', tagType: 'callbackShowStyle' }
+  },
+  { prop: 'remark', label: '备注', width: 100 },
+  { prop: 'createByName', label: '创建人', width: 120 },
+  { prop: 'createTime', label: '创建时间', width: 160 },
+  { prop: 'operation', label: '操作', width: 200, fixed: 'right' }
+]
+
+// 表格配置项
+const searchColumns: SearchProps[] = [
+  { prop: 'account', label: '账号', el: 'input' },
+  { prop: 'userName', label: '姓名', el: 'input' }
+]
+
+// 重置
+const reset = () => {
+  initParam.orgId = ''
+  proTableRef.value?.clearSelection()
+  treeFilterRef.value?.treeRef?.setCurrentKey()
+}
+
+// 获取table列表
+const getTableList = (params: UserQuery) => UserApi.page(params)
+
+// 单行删除
+const deleteRow = async (row: UserVO) => {
+  await useHandleData(UserApi.delete, [row.userId], `删除【${row.account}】用户`)
+  proTableRef.value?.getTableList()
+}
+
+// 批量删除信息
+const batchDelete = async (ids: (string | number)[]) => {
+  await useHandleData(UserApi.delete, ids, '删除所选用户信息')
+  proTableRef.value?.clearSelection()
+  proTableRef.value?.getTableList()
+}
+
+// 打开 drawer(新增、查看、编辑)
+const drawerRef = ref<InstanceType<typeof UserDrawer> | null>(null)
+const openDrawer = (title: string, row: Partial<UserBO> = {}) => {
+  const params = {
+    title,
+    row: title === '新增' ? { orgId: selectTreeId.value } : { ...row },
+    isView: title === '查看',
+    api: title === '新增' ? UserApi.add : title === '编辑' ? UserApi.edit : undefined,
+    getTableList: proTableRef.value?.getTableList
+  }
+  drawerRef.value?.acceptParams(params)
+}
+</script>