数据列表
直接使用element+的列表组件
<template><el-table :data="tableData" border 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 prop="createTime" label="添加时间" /><el-table-column prop="loginTime" label="最后登录" /><el-table-column prop="status" label="是否启用" /><el-table-column label="操作" /></el-table></template>
定义接口获取数据
//获取用户数据列表的接口interface AdminListParams {keyword: string;pageNum: Number;pageSize: Number}//获取用户数据列表export const getAdminList = (data :AdminListParams):PromiseRes<{list: {}[]}> => request.get('/admin/list',{params: data})
因为我们只用到返回数据的list,因此在返回值类型的定义只写list为对象数组格式即可
获取并渲染数据
<script setup lang='ts'>import { reactive,toRefs } from 'vue';import {getAdminList} from '../../request/api'const state = reactive<{tableData: {}[]}>({tableData: []})const {tableData} = toRefs(state);getAdminList({keyword: '',pageSize: 10,pageNum: 1}).then(res => {if(res.code === 200) {tableData.value = res.data.list}})</script>
格式化时间
使用第三方库,打包的时候体积太大
推荐day.js,体积小,核心功能都有
但是能自己封装组件才是最优选择
先写格式化时间函数
//补0函数const addZero = (num: number) => {return num < 10? '0'+num : num}//格式化时间const formatDate = (time?: string) => {if(!time) return '';let date = new Date(time);let year = addZero(date.getFullYear());let month = addZero(date.getMonth()+1);let day = addZero(date.getDay());let hours = addZero(date.getHours());let minutes = addZero(date.getMinutes());let seconds = addZero(date.getSeconds());return `${year}-${month}-${day} ${hours}-${minutes}-${seconds}`}
:::info 这里使用addZero时有个小技巧,year这些如果直接赋值为date.getFullYear(),则为number类型,但是在补0函数里的返回值有可能是string,因此直接一步到位,使用addZero之后再赋值,便可以自动转换类型。 :::
使用格式化函数
<template><el-table :data="tableData" border 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">{{formatDate(scope.row.createTime)}}</template></el-table-column><el-table-column label="最后登录" ><template v-slot:default="scope">{{formatDate(scope.row.loginTime)}}</template></el-table-column><el-table-column prop="status" label="是否启用" /><el-table-column label="操作" /></el-table></template>
是否启用
实质是一个开关,使用element+的switch组件
<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>
弹框组件
在操作这一栏,应该包含两种操作,“分配角色”和“编辑”
其实就是“增”和“改”
其效果都是弹出一个表单
组件内遇到可复用的模块,依然封装为组件
在ums文件夹下新建components文件夹存放ums菜单内的公共组件EditAdmin.vue
但是这个组件只能在执行点击操作后才展示,因此应该进行父子组件的通信
并且展示位置应该是在表单之外,与表单平级
<EditAdmit :visible="visible" @close="closeDialog" @modifyAdmin="modifyAdmin"></EditAdmit>//点击编辑按钮const editAdmin = () => {visible.value = true;}//隐藏弹框const closeDialog = () => {visible.value = false;}//接受信息后关闭弹窗const modifyAdmin = () => {visible.value = false;}
其中visible控制其展示,close和modifyAdmin则是弹窗组件里点击取消和确定之后的事件
<template><el-dialog v-model="visible" title="Shipping address" :before-close="close"><el-form :model="newForm" :label-width="formLabelWidth"><el-form-item label="Promotion name"><el-input v-model="newForm.username" autocomplete="off" /></el-form-item><el-form-item label="Zones"><el-select v-model="newForm.username" placeholder="Please select a zone"><el-option label="Zone No.1" value="shanghai" /><el-option label="Zone No.2" value="beijing" /></el-select></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="close">取消</el-button><el-button type="primary" @click="modifyAdmin">确定</el-button></span></template></el-dialog></template>
<script setup lang='ts'>import { reactive, toRefs, watch } from 'vue';const props = defineProps<{ visible: boolean;form: {username: string} }>();const state = reactive<{formLabelWidth: string;newForm: {username?: string}}>({formLabelWidth: '120px',newForm: {}})const { formLabelWidth,newForm } = toRefs(state)watch(() => props.form,() => {newForm.value = {...props.form}})const emit = defineEmits<{(event: 'close' ): void}>();//自定义事件 关闭弹窗表单const close = () => {emit('close')}//自定义事件 修改弹窗表单const modifyAdmin = () => {emit('modifyAdmin')}</script>
如果点击弹窗组件的外面,弹窗组件依然会关闭,这是组件封装的默认行为。但是再次点击编辑按钮就发现,无法顺利开启弹窗组件了。因此必须对弹窗自带的关闭时间进行拦截
<el-dialog v-model="visible" title="Shipping address" :before-close="close">
:before-close=”close” 使得点击弹窗组件外面的行为会被拦截,随后触发组件里的close事件
传递所在行数据
最终弹窗组件接受的数据来自父组件,也就是用户点击表单的那一行
<el-table-column label="操作"><template #default="{row}"><el-button text>分配角色</el-button><el-button @click="editAdmin(row)" text>编辑</el-button></template></el-table-column>
结构出row
本地设置变量rowData用于记录数据
在点击事件里赋值
const editAdmin = (row :{}) => {rowData.value = row;visible.value = true;}
通过props传递
<EditAdmit :visible="visible" :form="rowData" @close="closeDialog" @modifyAdmin="modifyAdmin"></EditAdmit>
浅拷贝对象
直接使用父组件传过来的rowData,发现数据无法渲染。因为setup钩子的原因。
此时使用watch监听props.rowData
const props = defineProps<{ visible: boolean;form: {username: string} }>();const state = reactive<{formLabelWidth: string;newForm: {username?: string}}>({formLabelWidth: '120px',newForm: {}})const { formLabelWidth,newForm } = toRefs(state)watch(() => props.form,() => {newForm.value = {...props.form}})
:::info
使用浅拷贝的原因:
会发现子组件里修改了rowData之后,点击“取消”,父组件里的内容也一样会跟着被修改。
因为props传递的数据的对象,对象里都是基础数据,需要进行浅拷贝.
newForm.value = {…props.form}
:::
watch在监听对象数据时,需要使用函数得到返回值
watch(() => props.form,() => {newForm.value = {...props.form}})
定义用户对象类型
src下新建types文件夹,里面再创建admin.d.ts,存放admin组件的接口类型
interface AdminObjItf {username?: string}
因为父组件跟子组件里传递的rowData对象里有很多变量,其格式应该统一,写公共接口很方便使用
更新用户信息
api.ts
//修改用户信息export const updateAdmin = (id:number, data :AdminObjItf):PromiseRes => request.get('/admin/update/'+id,{params: data})
因为不需要返回值,因此这里的PromsieRes不需要定义返回值类型。
此时会报错
//定义Promise类型type PromiseRes<T = {}> = Promise<ManageResult<T>>
给T一个空对象即可
//确定事件const modifyAdmin = () => {updateAdmin(newForm.value.id as number,newForm.value).then(res => {if(res.code === 200){close('reload')}})}
//获取最新表格数据const fetchData = () => {getAdminList({keyword: '',pageSize: 10,pageNum: 1}).then(res => {if (res.code === 200) {tableData.value = res.data.list}})}fetchData()
//隐藏弹框const closeDialog = (r?: string) => {visible.value = false;rowData.value = {};if (r === 'reload'){fetchData()}}
如果自定义事件里有参数,且值为reload,则发请求更新表单
添加用户时间
如果需要“添加”功能,则rowData只需要传递空对象即可
而子组件里发请求的时候不带id,就能知道是添加功能
