公共子组件编写

头部组件

components/admin/Header.vue

<template>
<a-popconfirm title="确认退出?" ok-text="是" cancel-text="否" @confirm="loginout">
		<a-button type="danger">登出</a-button>
		<!-- <a href="#">Delete</a> -->
</a-popconfirm>
</template>

<script>
export default {
	methods:{
		loginout(){
			window.sessionStorage.clear('token')
			this.$router.push('/login')
			this.$message.success("感谢您的使用")
		}
	}

}
</script>

侧边栏组件

components/admin/Nav.vue

<template>
<a-layout-sider breakpoint="lg" v-model="collapsed">
	<div class="log">
		<span>{{collapsed? "blog":"Salmon Blog"}}</span>
	</div>

	<a-menu theme="dark" mode="inline" @click="gotopage">
		<a-menu-item key="index">
			<a-icon type="dashboard"></a-icon><span>仪表盘</span>
		</a-menu-item>

		<a-sub-menu>
			<span slot="title"><a-icon type="file" /><span>文章管理</span></span>
			<a-menu-item key="addart"> 
				<a-icon type="form"></a-icon><span>新增文章</span>
			</a-menu-item>
			<a-menu-item key="artlist">
				<a-icon type="snippets"></a-icon><span>文章列表</span>
			</a-menu-item>
		</a-sub-menu>
		<a-menu-item key="catelist">
				<a-icon type="book"></a-icon><span>分类列表</span>
			</a-menu-item>
		<a-menu-item key="userlist">
				<a-icon type="user"></a-icon><span>用户列表</span>
			</a-menu-item>
	</a-menu>
</a-layout-sider>
</template>

<script>
export default {
	data(){
		return{
			collapsed: false
		}
	},
	methods:{
		gotopage(item){
			this.$router.push('/admin/'+item.key).catch((err)=>err)
		}
	}

}
</script>

<style>
	.log{
		height: 32px;
		margin: 16px;
		background-color: #fff;
		display: flex;
		justify-content: center;
		align-items: center;
		font-size: 17px;
	}

</style>

页脚组件

components/admin/Footer.vue

<template>
	<div class="footer">
		<span> -------Salmon------- </span>
	</div>
</template>

<script>
export default {

}
</script>

<style scoped>
	.footer{
		background-color: aliceblue;
		text-align: center;
		height: 100%;
	}
  .footer span{
		height: 100%;
		font-size: 20px;
	}

</style>

用户列表页编写

components/user/UserList.vue

<template>
	<div>
		<h3>用户列表页</h3>
		<a-card>
			<a-row :gutter="20">
				<a-col :span="6">
					<a-input-search placeholder="请输入用户名" enter-button />
				</a-col>
				<a-col :span="4">
					<a-button type="primary">新增</a-button>
				</a-col>
			</a-row>
			<a-table 
				:columns='columns' 
				rowKey='username' 
				:pagination="PaginationOption" 
				:dataSource="userlist"
				bordered
			>
			<span slot="role" slot-scope="role">{{role == 1 ? "管理员":"订阅者"}}</span>
			<template slot="action">
				<div class="actionSlot">
				<a-button type="primary" style="margin-right:15px">编辑</a-button>
				<a-button type="danger">删除</a-button>
			</div>
			</template>
			</a-table>
		</a-card>
	</div>
</template>

<script>
const columns = [
	{
    title: 'ID',
    dataIndex: 'ID',
    key: 'id',
    width: '10%',
		align:'center'
  },
	{
    title: '用户名',
    dataIndex: 'username',
    key: 'username',
    width: '20%',
		align:'center'
  },
	{
    title: '角色',
    dataIndex: 'role',
    key: 'role',
    width: '20%',
		scopedSlots:{customRender:'role'},
		align:'center'
  },
	{
    title: '操作',
    key: 'action',
    width: '30%',
		scopedSlots:{customRender:'action'},
		align:'center'
  },
]
export default {
	data(){
		return{
			columns,
			PaginationOption:{
				pageSizeOptions:['5','10','20'],
				defaultCurrent:1,
				defaultPageSize:5,
				total:0,
				showSizeChanger:true,
				showTotal:(total)=>`共${total}条`,
				onChage:(page, pageSize)=>{
					this.PaginationOption.defaultCurrent = page
					this.PaginationOption.defaultPageSize = pageSize
					this.getUserList()
				},
				onshowSizeChange:(current, size)=>{
					this.PaginationOption.defaultCurrent = current
					this.PaginationOption.defaultPageSize = size
					this.getUserList()
				}

			},
			userlist:[],
		}
	},
	created(){
		this.getUserList()

	},
	methods:{
		async getUserList(){
			const { data:res } = await this.$http.get('api/v1/user/', {
				params:{
					size:this.PaginationOption.defaultPageSize, 
					page:this.PaginationOption.defaultCurrent
					},
				})
				if(res.code != 200)return this.$message.error(res.msg)
				this.userlist = res.data
				this.PaginationOption.total = res.total
		}
	}

}
</script>

<style>
.actionSlot{
	display: flex;
	justify-content: center;
}

</style>

搜索功能

这里和之前的查看全部用户功能大部分是重复的,重构一下后端函数model/User.go

func GetUsers(username string, Size int, Page int)([]User,int64)  {
	var users []User
	var total int64
	if username != ""{
		if username != "" {
			db.Select("id,username,role").Where(
				"username LIKE ?", username+"%",
			).Limit(Size).Offset((Page - 1) * Size).Find(&users)
			db.Model(&users).Where(
				"username LIKE ?", username+"%",
			).Count(&total)
			return users, total
		}
	}
	// 分页
	err = db.Select("id,username,role").Offset((Page - 1) * Size).Limit(Size).Find(&users).Error
	db.Model(&users).Count(&total)
	if err != nil{
		return users,0
	}
	// 返回用户的列表
	return users,total
}

在接收的时候,接收一个username,绑定事件即可。

<a-col :span="6">
	  <a-input-search 
		v-model="queryParam.username"
		allowClear placeholder="请输入用户名" 
		enter-button 
		@search="getUserList" />
</a-col>

删除功能

在删除按钮处添加弹窗和绑定事件

<template slot="action" slot-scope="data">
				<div class="actionSlot">
				<a-button type="primary" style="margin-right:15px">编辑</a-button>
				<a-popconfirm title="确认删除?删除后无法恢复" ok-text="确认" cancel-text="取消" @confirm="delUser(data.ID)">
				  <a-button type="danger">删除</a-button>
				</a-popconfirm>
			</div>
</template>

<script>
async delUser(id){
		  const { data: res } = await this.$http.delete(`api/admin/user/${id}/`)
			if(res.code != 200)return this.$message.error(res.msg)
			this.queryParam.pagenum = 1
			this.getUserList()
		}
</script>

然后测试一下,ok,果然不行,忘了加权限的验证了。在main.js中,添加一个请求拦截器

// 请求拦截器
axios.interceptors.request.use(config => {
  config.headers.Authorization = `Bearer ${window.sessionStorage.getItem('token')}`
  return config
})

这样的话,每次都会携带上这个token,用来验证。