数据列表
直接使用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,就能知道是添加功能