文章目录
- 1. 用户信息
- 1.1 整体设计
- 1.2 完整代码 User.vue
- 1.2.1 数据加载
- 1.2.2 表格 el-table
- 1.2.2.1 多选
- 1.2.2.2 自定义列的内容 Slot
- 1.2.2.3 图片 el-image
- 1.2.2.4 分页 el-pagination
- 1.2.3 编辑
- 1.2.3.1 弹出框 el-dialog
- 1.2.3.2 上传 el-upload
- 1.2.4 新增
- 1.2.5 删除
- 1.2.6 批量删除
- 1.2.7 批量导出
- 1.2.8 用户导入模版
- 1.2.9 批量导入
- 2. 新闻信息
- 2.1 整体设计
- 2.2 完整代码 News.vue
1. 用户信息
1.1 整体设计
1.2 完整代码 User.vue
<template>
<div>
<div>
<el-input style="width: 200px" placeholder="查询用户名" v-model="username"></el-input>
<el-input style="width: 200px; margin: 0 5px" placeholder="查询姓名" v-model="name"></el-input>
<el-button type="primary" @click="load(1)">查询</el-button>
<el-button type="info" @click="reset">重置</el-button>
</div>
<div style="margin: 10px 0">
<el-button type="primary" plain @click="handleAdd">新增</el-button>
<el-button type="danger" plain @click="delBatch">批量删除</el-button>
<el-button type="info" plain @click="exportData">批量导出</el-button>
<el-upload :action="$baseUrl + '/user/import'" :headers="{token: user.token}" :on-success="handleImport" style="display: inline-block; margin-left: 10px" :show-file-list="false">
<el-button type="primary" plain>批量导入</el-button>
</el-upload>
<el-button type="primary" plain @click="download" style="margin-left: 10px">用户导入模版</el-button>
</div>
<el-table :data="tableData" stripe :header-cell-style="{ backgroundColor: 'aliceblue', color: '#666' }" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column prop="id" label="序号" width="70" align="center"></el-table-column>
<el-table-column prop="username" label="用户名"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="phone" label="手机号"></el-table-column>
<el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column label="头像">
<template v-slot="scope">
<div style="display: flex; align-items: center">
<el-image style="width: 50px; height: 50px; border-radius: 50%" v-if="scope.row.avatar" :src="scope.row.avatar" :preview-src-list="[scope.row.avatar]"></el-image>
</div>
</template>
</el-table-column>
<el-table-column prop="role" label="角色"></el-table-column>
<el-table-column label="操作" align="center" width="180">
<template v-slot="scope">
<el-button size="mini" type="primary" plain @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="mini" type="danger" plain @click="del(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div style="margin: 10px 0">
<el-pagination
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-size="pageSize"
layout="total, prev, pager, next"
:total="total">
</el-pagination>
</div>
<el-dialog title="用户信息" :visible.sync="fromVisible" width="30%">
<el-form :model="form" label-width="80px" style="padding-right: 20px" :rules="rules" ref="formRef">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="姓名"></el-input>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input v-model="form.phone" placeholder="电话"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="邮箱"></el-input>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input type="textarea" v-model="form.address" placeholder="地址"></el-input>
</el-form-item>
<el-form-item label="角色" prop="role">
<el-radio-group v-model="form.role">
<el-radio label="管理员"></el-radio>
<el-radio label="用户"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="头像">
<el-upload
class="avatar-uploader"
:action="$baseUrl + '/file/upload'"
:headers="{ token: user.token }"
:file-list="form.avatar? [{url: form.avatar}] : []"
list-type="picture"
:on-success="handleAvatarSuccess"
>
<el-button type="primary">上传头像</el-button>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="fromVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: "User",
data() {
return {
tableData: [], // 所有的数据
pageNum: 1, // 当前的页码
pageSize: 5, // 每页显示的个数
username: '',
name: '',
total: 0,
fromVisible: false,
form: {},
user: JSON.parse(localStorage.getItem('honey-user') || '{}'),
rules: {
username: [
{ required: true, message: '请输入账号', trigger: 'blur' },
]
},
ids: []
}
},
created() {
this.load()
},
methods: {
handleImport(res, file, fileList) {
if (res.code === '200') {
this.$message.success("操作成功")
this.load(1)
} else {
this.$message.error(res.msg)
}
},
exportData() { // 批量导出数据
if (!this.ids.length) { // 没有选择行的时候,全部导出 或者根据我的搜索条件导出
window.open(this.$baseUrl + '/user/export?token=' + this.user.token + "&username="
+ this.username + "&name=" + this.name)
} else { // [1,2,3] => '1,2,3'
let idStr = this.ids.join(',')
window.open(this.$baseUrl + '/user/export?token=' + this.user.token + '&ids=' + idStr)
}
},
download () {
// 通过a标签来实现下载
const a = document.createElement('a') // 创建一个<a></a>标签
a.href = '/static/用户导入模板.xlsx' // 给a标签的href属性值加上地址,注意,这里是绝对路径,不用 加 点.
a.download = '用户导入模板.xlsx' // 设置下载文件文件名,这里加上.docx指定文件类型,pdf文件就指定.pdf即可
a.style.display = 'none' // 隐藏a标签
document.body.append('a') // 将a标签追加到document.body中
a.click() // 模拟点击a标签,会触发a标签的href的读取,浏览器就会自动下载了
a.remove() // 删除a标签(一次性的)
},
delBatch() {
if (!this.ids.length) {
this.$message.warning('请选择数据')
return
}
this.$confirm('您确认批量删除这些数据吗?', '确认删除', {type: "warning"}).then(response => {
this.$request.delete('/user/delete/batch', { data: this.ids }).then(res => {
if (res.code === '200') { // 表示操作成功
this.$message.success('操作成功')
this.load(1)
} else {
this.$message.error(res.msg) // 弹出错误的信息
}
})
}).catch(() => {})
},
handleSelectionChange(rows) { // 当前选中的所有的行数据
this.ids = rows.map(v => v.id)
},
del(id) {
this.$confirm('您确认删除吗?', '确认删除', {type: "warning"}).then(response => {
this.$request.delete('/user/delete/' + id).then(res => {
if (res.code === '200') { // 表示操作成功
this.$message.success('操作成功')
this.load(1)
} else {
this.$message.error(res.msg) // 弹出错误的信息
}
})
}).catch(() => {})
},
handleEdit(row) { // 编辑数据
this.form = JSON.parse(JSON.stringify(row)) // 给form对象赋值 注意要深拷贝数据
this.fromVisible = true // 打开弹窗
},
handleAdd() { // 新增数据
this.form = { role: '用户' } // 新增数据的时候清空数据
this.fromVisible = true // 打开弹窗
},
save() { // 保存按钮触发的逻辑 它会触发新增或者更新
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$request({
url: this.form.id ? '/user/update': '/user/add',
method: this.form.id ? 'PUT' : 'POST',
data: this.form
}).then(res => {
if (res.code === '200') { // 表示成功保存
this.$message.success('保存成功')
this.load(1)
this.fromVisible = false
} else {
this.$message.error(res.msg) // 弹出错误的信息
}
})
}
})
},
reset() {
this.name = ''
this.username = ''
this.load()
},
load(pageNum) { // 分页查询
if (pageNum) this.pageNum = pageNum
this.$request.get('/user/selectByPage', {
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
username: this.username,
name: this.name
}
}).then(res => {
this.tableData = res.data.records
this.total = res.data.total
})
},
handleCurrentChange(pageNum) {
this.load(pageNum)
},
handleAvatarSuccess(response, file, fileList) {
// 把user的头像属性换成上传的图片的链接
this.form.avatar = response.data
},
}
}
</script>
<style scoped>
</style>
1.2.1 数据加载
created() {
this.load()
}
load(pageNum) { // 分页查询
if (pageNum) this.pageNum = pageNum
this.$request.get('/user/selectByPage', {
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
username: this.username,
name: this.name
}
}).then(res => {
this.tableData = res.data.records
this.total = res.data.total
})
}
created
钩子在实例创建完成后被调用。此时实例已完成数据、事件配置。
1.2.2 表格 el-table
- data:显示的数据,此处绑定数据加载返回的 tableData。
- stripe:是否为斑马纹 table,默认 false。
- header-cell-style:表头单元格的 style
- selection-change:当选择项发生变化时会触发该事件,用于实现多选。手动添加一个
el-table-column
,设type
属性为selection
即可 - prop:对应列内容的字段名
- label:显示的标题
1.2.2.1 多选
增加多选项:
<el-table :data="tableData" stripe :header-cell-style="{ backgroundColor: 'aliceblue', color: '#666' }" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"></el-table-column>
...
</el-table>
@selection-change回调方法:
handleSelectionChange(rows) { // 当前选中的所有的行数据
this.ids = rows.map(v => v.id)
}
rows
为当前选中的所有的行数据。
1.2.2.2 自定义列的内容 Slot
通过 v-slot="scope"
作用域插槽 Slot 可以插入自定义内容,scope.row 获取行数据,然后操作行数据编辑自定义内容。比如,插入头像、格式化时间、插入操作按钮等等。
<el-table-column label="头像">
<template v-slot="scope">
<div style="display: flex; align-items: center">
<el-image style="width: 50px; height: 50px; border-radius: 50%" v-if="scope.row.avatar" :src="scope.row.avatar" :preview-src-list="[scope.row.avatar]"></el-image>
</div>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="180">
<template v-slot="scope">
<el-button size="mini" type="primary" plain @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="mini" type="danger" plain @click="del(scope.row.id)">删除</el-button>
</template>
</el-table-column>
1.2.2.3 图片 el-image
<el-image style="width: 50px; height: 50px; border-radius: 50%" v-if="scope.row.avatar" :src="scope.row.avatar" :preview-src-list="[scope.row.avatar]"></el-image>
- src:图片源
- preview-src-list:图片预览功能
1.2.2.4 分页 el-pagination
<div style="margin: 10px 0">
<el-pagination
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-size="pageSize"
layout="total, prev, pager, next"
:total="total">
</el-pagination>
</div>
handleCurrentChange(pageNum) {
this.load(pageNum)
}
- current-page:当前页数
- page-size:每页显示条目个数
- layout:组件布局,子组件名用逗号分隔。sizes, prev, pager, next, jumper, ->, total, slot
- total:总条目数
- current-change:currentPage 改变时会触发
1.2.3 编辑
handleEdit(row) { // 编辑数据
this.form = JSON.parse(JSON.stringify(row)) // 给form对象赋值 注意要深拷贝数据
this.fromVisible = true // 打开弹窗
}
点击 “编辑”,打开弹窗,弹窗内 el-form
表单数据对象赋值为传入的行数据,这就是 “回显” 功能。
1.2.3.1 弹出框 el-dialog
<el-dialog title="用户信息" :visible.sync="fromVisible" width="30%">
<el-form :model="form" label-width="80px" style="padding-right: 20px" :rules="rules" ref="formRef">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="姓名"></el-input>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input v-model="form.phone" placeholder="电话"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="邮箱"></el-input>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input type="textarea" v-model="form.address" placeholder="地址"></el-input>
</el-form-item>
<el-form-item label="角色" prop="role">
<el-radio-group v-model="form.role">
<el-radio label="管理员"></el-radio>
<el-radio label="用户"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="头像">
<el-upload
class="avatar-uploader"
:action="$baseUrl + '/file/upload'"
:headers="{ token: user.token }"
:file-list="form.avatar? [{url: form.avatar}] : []"
list-type="picture"
:on-success="handleAvatarSuccess"
>
<el-button type="primary">上传头像</el-button>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="fromVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
- visible:是否显示 Dialog,支持
.sync
修饰符 - title:Dialog 的标题,也可通过
具名 slot
传入 - footer:Dialog 按钮操作区的内容,通过
具名 slot
传入
1.2.3.2 上传 el-upload
handleAvatarSuccess(response, file, fileList) {
// 把user的头像属性换成上传的图片的链接
this.form.avatar = response.data
}
图片上传成功后,将服务返回的文件存储的服务器地址,赋值给 form 表单数据对象,用于保存用户信息。
1.2.4 新增
新增和编辑共用同一个 el-dialog
弹出框,区别在于:新增需要清空 form 表单数据对象。还有一点,保存按钮触发请求时,需要根据 this.form.id 是否为空,判断发送新增(为空)还是编辑(不为空)
handleAdd() { // 新增数据
this.form = { role: '用户' } // 新增数据的时候清空数据
this.fromVisible = true // 打开弹窗
}
1.2.5 删除
del(id) {
this.$confirm('您确认删除吗?', '确认删除', {type: "warning"}).then(response => {
this.$request.delete('/user/delete/' + id).then(res => {
if (res.code === '200') { // 表示操作成功
this.$message.success('操作成功')
this.load(1)
} else {
this.$message.error(res.msg) // 弹出错误的信息
}
})
}).catch(() => {})
}
$confirm(message, title, options)
确认消息弹出框进行删除提示,操作成功后调用 this.load(1) 刷新表格。
1.2.6 批量删除
delBatch() {
if (!this.ids.length) {
this.$message.warning('请选择数据')
return
}
this.$confirm('您确认批量删除这些数据吗?', '确认删除', {type: "warning"}).then(response => {
this.$request.delete('/user/delete/batch', { data: this.ids }).then(res => {
if (res.code === '200') { // 表示操作成功
this.$message.success('操作成功')
this.load(1)
} else {
this.$message.error(res.msg) // 弹出错误的信息
}
})
}).catch(() => {})
}
根据当前选中的所有的行数据 this.ids,进行批量操作,操作成功后调用 this.load(1) 刷新表格。
1.2.7 批量导出
exportData() { // 批量导出数据
if (!this.ids.length) { // 没有选择行的时候,全部导出;或者根据搜索条件导出
window.open(this.$baseUrl + '/user/export?token=' + this.user.token + "&username="
+ this.username + "&name=" + this.name)
} else { // [1,2,3] => '1,2,3'
let idStr = this.ids.join(',')
window.open(this.$baseUrl + '/user/export?token=' + this.user.token + '&ids=' + idStr)
}
}
window.open() 是 JavaScript 中用于打开新窗口或标签页的一个方法。它非常有用,尤其是在需要为用户提供额外信息而不离开当前页面的情况下。这个方法可以接受多个参数来定制打开的新窗口或标签页的行为和外观。
基本语法:
window.open(URL, target, features, replace);
- URL:要加载的网页的 URL。可以是绝对路径或相对路径。如果为空,则会加载 about:blank。
- target:指定目标窗口或标签页的名称。常见的值有:
_self
:在相同的框架中打开文档(默认)。_blank
:在一个新的未命名窗口中打开文档。- _parent:在父框架集中打开文档。
- _top:在整个窗口中打开文档。
- features:一个可选的字符串,定义了新窗口的特性(如宽度、高度、是否显示滚动条等)。每个特性之间用逗号分隔。例如,“width=500,height=400”。
- replace:这是一个布尔值参数,但在实际使用中很少使用。如果设置为 true,则表示不创建历史记录条目。
⚠️注1:因为 window.open()
没办法指定请求头 headers,故没法通过请求头传递 token。此处通过请求参数 ?token=
传递 token,后端服务器需要判断如果请求头没有获取 token,需要从请求参数中获取 token。
1.2.8 用户导入模版
点击下载用户导入模版
download () {
// 通过a标签来实现下载
const a = document.createElement('a') // 创建一个<a></a>标签
a.href = '/static/用户导入模板.xlsx' // 给a标签的href属性值加上地址,注意,这里是绝对路径,不用 加 点.
a.download = '用户导入模板.xlsx' // 设置下载文件文件名,这里加上.docx指定文件类型,pdf文件就指定.pdf即可
a.style.display = 'none' // 隐藏a标签
document.body.append('a') // 将a标签追加到document.body中
a.click() // 模拟点击a标签,会触发a标签的href的读取,浏览器就会自动下载了
a.remove() // 删除a标签(一次性的)
}
如果引用的静态资源位于 public 目录下,可以使用绝对路径。比如 用户导入模板.xlsx
存放在 public 目录下,public 目录和 src 目录同级。
使用 /static/用户导入模板.xlsx
可以访问资源。
1.2.9 批量导入
使用 <el-upload>
上传
<el-upload :action="$baseUrl + '/user/import'"
:headers="{token: user.token}"
:on-success="handleImport"
:show-file-list="false"
style="display: inline-block; margin-left: 10px" >
<el-button type="primary" plain>批量导入</el-button>
</el-upload>
上传成功后,回调 :on-success="handleImport"
,提示相应信息。
handleImport(res, file, fileList) {
if (res.code === '200') {
this.$message.success("操作成功")
this.load(1)
} else {
this.$message.error(res.msg)
}
}