31-实现分配角色弹框(表现列表和选中当前用户的角色)

下面我们要实现的分配角色的弹窗如下

在这里插入图片描述

先添加类型

admin.d.ts

interface AdminObjItf {
id?: number
username?: string
nickName?: string
email?: string
password?: string
note?: string
status?: number
}
interface AdminRoleFormData {
userRoles?: RoleObjItf[]
roleLists?: RoleObjItf[]
}

role.d.ts

interface RoleObjItf {
id: number
name: string
}

下面我们添加两个角色相关的接口,获取所有角色以及根据用户id获取角色

import request from './request'
interface ManageResponse<T = null> {
  code: number
  message: string
  data: T
  }
  type PromiseResponse<T = {}> = Promise<ManageResponse<T>>
    interface AdminListParams {
    keyword: string
    pageNum: number
    pageSize: number
    }
    interface AdminListResponse {
    list: {}[]
    pageNum: number
    pageSize: number
    total: number
    totalPage: number
    }
    // 获取用户数据列表
    export const getAdminListApi = (data: AdminListParams):PromiseResponse<AdminListResponse> => {
      return request.get('/admin/list', {
      params: data
      })
      }
      // 修改指定用户信息
      export const updateAdmin = (id: number, data: AdminObjItf):PromiseResponse => {
      return request.post('/admin/update/' + id, data)
      }
      // 获取所有角色
      export const getRoleListAll = ():PromiseResponse<RoleObjItf[]> => {
        return request.get('/role/listAll')
        }
        // 根据用户id获取角色
        export const getAdminRoleById = (id: number):PromiseResponse<RoleObjItf[]> => {
          return request.get('/admin/role/' + id)
          }

然后我们在mock里面实现这两个接口

新建两个json文件,一个存列表,一个存个人的

role-list.json

[
{
"adminCount": 0,
"createTime": "2018-09-29T05:55:39.000+00:00",
"description": "只能查看及操作商品",
"id": 1,
"loginTime": "2018-09-29T05:55:39.000+00:00",
"name": "商品管理员",
"sort": 0,
"status": 1
},
{
"adminCount": 0,
"createTime": "2018-09-29T05:55:39.000+00:00",
"description": "只能查看及操作订单",
"id": 2,
"loginTime": "2018-09-29T05:55:39.000+00:00",
"name": "订单管理员",
"sort": 0,
"status": 1
},
{
"adminCount": 0,
"createTime": "2018-09-29T05:55:39.000+00:00",
"description": "都能查看操作",
"id": 3,
"loginTime": "2018-09-29T05:55:39.000+00:00",
"name": "超级管理员",
"sort": 0,
"status": 1
}
]

role.json

[
{
"adminCount": 0,
"createTime": "2018-09-29T05:55:39.000+00:00",
"description": "只能查看及操作商品",
"id": 1,
"loginTime": "2018-09-29T05:55:39.000+00:00",
"name": "商品管理员",
"sort": 0,
"status": 1
},
{
"adminCount": 0,
"createTime": "2018-09-29T05:55:39.000+00:00",
"description": "只能查看及操作订单",
"id": 2,
"loginTime": "2018-09-29T05:55:39.000+00:00",
"name": "订单管理员",
"sort": 0,
"status": 1
}
]

mock实现

import { type MockMethod } from 'vite-plugin-mock'
import fs from 'fs'
import path from 'path'
import { validateToken } from '../utils'
const adminDataFile = path.join(process.cwd(), 'src/mock/data/admin-list.json')
const roleListDataFile = path.join(process.cwd(), 'src/mock/data/role-list.json')
const roleDataFile = path.join(process.cwd(), 'src/mock/data/role.json')
const readAdmins = () => {
try {
const raw = fs.readFileSync(adminDataFile, 'utf-8')
return JSON.parse(raw) as Array<Record<string, any>>
  } catch (e) {
  console.error('读取用户数据失败', e)
  return []
  }
  }
  const writeAdmins = (list: Array<Record<string, any>>) => {
    fs.writeFileSync(adminDataFile, JSON.stringify(list, null, 2), 'utf-8')
    }
    const readRoleLists = () => {
    try {
    const raw = fs.readFileSync(roleListDataFile, 'utf-8')
    return JSON.parse(raw) as Array<Record<string, any>>
      } catch (e) {
      console.error('读取角色列表数据失败', e)
      return []
      }
      }
      const readRole = () => {
      try {
      const raw = fs.readFileSync(roleDataFile, 'utf-8')
      return JSON.parse(raw) as Array<Record<string, any>>
        } catch (e) {
        console.error('读取角色数据失败', e)
        return []
        }
        }
        export default [
        {
        url: '/api/admin/list',
        method: 'get',
        response: ({ headers }: { headers: Record<string, string> }) => {
          const tokenCheck = validateToken(headers)
          if (!tokenCheck.valid) {
          return tokenCheck.response
          }
          const adminList = readAdmins()
          const pageSize = 10
          const pageNum = 1
          const total = adminList.length
          const totalPage = Math.max(1, Math.ceil(total / pageSize))
          return {
          code: 200,
          message: '获取用户数据列表',
          data: {
          list: adminList,
          pageNum,
          pageSize,
          total,
          totalPage
          }
          }
          }
          },
          {
          url: '/api/admin/update/:id',
          method: 'post',
          response: (options: {
          headers: Record<string, string>
            body: Record<string, unknown>
              url: string
              }) => {
              const { headers, body, url } = options
              const tokenCheck = validateToken(headers)
              if (!tokenCheck.valid) {
              return tokenCheck.response
              }
              const adminList = readAdmins()
              const id = Number((url.match(/\/api\/admin\/update\/(\d+)/) || [])[1])
              const target = adminList.find(item => item.id === id)
              if (!target) {
              return {
              code: 404,
              message: '未找到对应的用户',
              data: null
              }
              }
              // 合并更新,同时保留原有的 id
              Object.assign(target, body, { id: target.id })
              writeAdmins(adminList)
              return {
              code: 200,
              message: '修改用户信息成功',
              data: target
              }
              }
              },
              {
              url: '/api/role/listAll',
              method: 'get',
              response: ({ headers }: { headers: Record<string, string> }) => {
                const tokenCheck = validateToken(headers)
                if (!tokenCheck.valid) {
                return tokenCheck.response
                }
                const roleList = readRoleLists()
                return {
                code: 200,
                message: '获取角色列表成功',
                data: roleList
                }
                }
                },
                {
                url: '/api/admin/role/:id',
                method: 'get',
                response: ({ headers }: { headers: Record<string, string> }) => {
                  const tokenCheck = validateToken(headers)
                  if (!tokenCheck.valid) {
                  return tokenCheck.response
                  }
                  const roleList = readRole()
                  return {
                  code: 200,
                  message: '获取角色成功',
                  data: roleList
                  }
                  }
                  }
                  ] as MockMethod[]

最后我们来实现页面的逻辑

<template>
    <div class=''>
      <el-table :data="tableData" style="width: 100%">
      <el-table-column prop="id" label="编号"/>
      <el-table-column prop="username" label="账号"/>
      <el-table-column prop="nickName" label="姓名"/>
      <el-table-column prop="email" label="邮箱"/>
        <el-table-column label="添加时间">
          <template v-slot:default="scope">
          {{ formateDate(scope.row.createTime) }}
        </template>
      </el-table-column>
        <el-table-column label="最后登录">
          <template v-slot:default="scope">
          {{ formateDate(scope.row.loginTime) }}
        </template>
      </el-table-column>
        <el-table-column label="是否启用">
          <template v-slot:default="scope">
        <el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0"></el-switch>
        </template>
      </el-table-column>
        <el-table-column label="操作">
          <template #default="{row}">
        <el-button type="text" @click="allocRole(row.id)">分配角色</el-button>
        <el-button type="text" @click="editAdmin(row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 编辑 -->
    <EditAdmin v-model:visible="visible" :form="rowData" @sure="getTableData"></EditAdmin>
      <!-- 分配权限 -->
      <EditRole v-model:visible="roleVisible" :form="roleData" @sure="getTableData"></EditRole>
      </div>
    </template>
      <script lang='ts' setup>
      import { reactive, toRefs } from 'vue'
      import { getAdminListApi, getRoleListAll, getAdminRoleById } from '@/api/ums'
      import { ElMessage } from 'element-plus'
      import EditAdmin from './components/EditAdmin.vue'
      import EditRole from './components/EditRole.vue'
      const state = reactive<{
      tableData: {}[]
      visible: boolean,
      rowData: AdminObjItf
      roleVisible: boolean
      roleData: AdminRoleFormData
      }>({
      tableData: [],
      visible: false,
      rowData: {},
      roleVisible: false,
      roleData: {}
      })
      let { tableData, visible, rowData, roleVisible, roleData } = toRefs(state)
      const getTableData = () => {
      getAdminListApi({
      keyword: '',
      pageNum: 1,
      pageSize: 10
      }).then((res) => {
      if(res.code === 200) {
      tableData.value = res.data.list
      } else {
      ElMessage.error('获取用户数据列表失败')
      }
      })
      }
      getTableData();
      // 获取所有角色
      getRoleListAll().then((res) => {
      if(res.code === 200) {
      roleData.value.roleLists = res.data
      } else {
      ElMessage.error('获取所有角色失败')
      }
      })
      const addZero = (num: number) => {
      return num > 9 ? num : '0' + num
      }
      // 格式化时间
      const formateDate = (time: string | undefined) => {
      if (!time) return '';
      const date = new Date(time);
      const year = date.getFullYear();
      let month = addZero(date.getMonth() + 1);
      let day = addZero(date.getDate());
      let hour = addZero(date.getHours());
      let min = addZero(date.getMinutes());
      let sec = addZero(date.getSeconds());
      return  `${year}-${month}-${day} ${hour}:${min}:${sec}`
      }
      // 点击编辑按钮
      const editAdmin = (row: AdminObjItf) => {
      visible.value = true
      rowData.value = row
      }
      // 点击分配权限按钮
      const allocRole = (id: number) => {
      getAdminRoleById(id).then(res => {
      if(res.code === 200) {
      roleVisible.value = true
      roleData.value.userRoles = res.data
      }
      })
      }
    </script>
      <style lang='less' scoped>
    </style>

新建组件 EditRole.vue

<template>
    <el-dialog v-model="dialogVisible" title="分配角色" width="420" :before-close="close">
      <el-form :model="form" label-width="70px">
        <el-form-item label="权限">
          <el-select v-model="roles" multiple>
        <el-option v-for="role in form.roleLists" :label="role.name" :value="role.id"></el-option>
        </el-select>
      </el-form-item>
    </el-form>
      <template #footer>
        <div class="dialog-footer">
      <el-button @click="close">取消</el-button>
      <el-button type="primary" @click="modifyRole">确定</el-button>
      </div>
    </template>
  </el-dialog>
</template>
  <script lang='ts' setup>
  import { computed, reactive, toRefs, watch } from 'vue'
  const props = defineProps<{
  visible: boolean,
  form: AdminRoleFormData
  }>()
  const state = reactive<{
  roles: number[]
  }>({
  roles: []
  })
  const { roles } = toRefs(state)
  // 拷贝form
  watch(() => props.form.userRoles, () => {
  roles.value = props.form.userRoles?.map(el => el.id) || []
  })
  const emit = defineEmits<{
  (event: 'update:visible', value: boolean): void
  (event: 'sure'): void
  }>()
  // 双向绑定 dialog 显示状态(emit 更新父组件)
  const dialogVisible = computed({
  get: () => props.visible,
  set: (val: boolean) => emit('update:visible', val)
  })
  // 点击关闭
  const close = () => {
  dialogVisible.value = false
  }
  // 确定
  const modifyRole = () => {
  close()
  }
</script>
  <style lang='less' scoped>
</style>
posted on 2026-01-14 09:55  ljbguanli  阅读(12)  评论(0)    收藏  举报