使用vue-admin-template搭建简单增删改查导入导出项目及CentOs服务器部署
1. Vue-admin-template1. 简介vueAdmin-template是基于vue-element-admin的一套后台管理系统基础模板(最少精简版),可作为模板进行二次开发。**GitHub地址:**https://github.com/PanJiaChen/vue-admin-template**根据用户角色来动态生成侧边栏的分支:**https://github.com/Pa
1. Vue-admin-template
1. 简介
vueAdmin-template是基于vue-element-admin的一套后台管理系统基础模板(最少精简版),可作为模板进行二次开发。
GitHub地址:https://github.com/PanJiaChen/vue-admin-template
根据用户角色来动态生成侧边栏的分支:https://github.com/PanJiaChen/vue-admin-template/tree/permission-control
2. 安装和运行
# 首先使用git下载源码
git clone https://github.com/PanJiaChen/vue-admin-template.git
# 将文件夹修改成我们自己的项目名称 如 vue-demo
# 使用git窗口修改,强化linux命令
mv vue-admin-template vue-demo
# 使用cmd或者IDE打开文件夹 如 vscode webstorm
# 下载安装项目所需的依赖 此步需要有node
npm install
#运行
npm run dev
#前端打包
npm run build:prod
2. 前端相关配置
1. 禁用EsLint
在
vue.config.js
第30行禁用ESLint语法检查
lintOnSave: false,
2. 修改页面标题
在
src/setting.js
第三行处修改页面标题
module.exports = {
title: 'vue测试系统',
}
3. 国际化设置
在
src/main.js
第7行处修改语言
import locale from 'element-ui/lib/locale/lang/zh-CN' //lang i18n
4. 下拉菜单修改
5. 登录页修改
在
src/views/login/index.vue
修改登录页面标题和登录按钮等
3. 定义api
在
src/api
下创建文件夹report
1. 导出整个对象
此方法只导出一个
default
对象,使用的时候可以将一阵个文件导入成为一个对象来使用。在
report
文件夹下创建reportApi.js
import request from '@/utils/request'
export default {
/**
* 分页查询
* @param data 查询参数
* @returns {AxiosPromise}
*/
fetchReportList(data) {
return request({
url: `/manager/report/page`,
method: 'get',
params: data
})
},
/**
* 根据id获取数据
* @param data 要查询的id
* @returns {AxiosPromise}
*/
getReportById(data) {
return request({
url: `/manager/report/${data}`,
method: 'get'
})
},
/**
* 新增或更新方法, 后端判断,如果有id则更新没有id则创建,
* 也可以直接使用MybatisPlus的saveOrUpdate方法简化操作
* @param data 表单数据
* @returns {AxiosPromise}
*/
saveOrUpdateReport(data) {
return request({
url: '/manager/report/saveOrUpdate',
method: 'post',
data
})
},
/**
* 根据id删除数据,逻辑删除
* 实体类删除属性上添加 @TableLogic即可标记 使用MybatisPlus的removeById即可
* @param data
* @returns {AxiosPromise}
*/
removeReportById(data) {
return request({
url: `/manager/report/${data}`,
method: 'delete'
})
},
getReportErrorPage() {
return request({
url: '/manager/report/errorPage',
method: 'get'
})
},
/**
* 文件上传 批量
* @param url 要上传的文件地址
* @param file 文件数组
* @returns {AxiosPromise}
*/
upload(url, file) {
// 创建 FormData对象
let data = new FormData()
// 将文件放置到data里,files对应后端MultipartFile 的变量名
file.forEach(everyFile => {
data.append("files", everyFile.raw)
})
return request({
//这里可以直接写url,
url: url,
method: 'post',
data
})
}
}
使用的时候直接导出整个对象
<template></template>
<script>
import reportApi from "@/api/report/reportApi";
export default {
name: 'reportList',
data(){
return{
}
},
created() {
},
methods:{
fetchList(data){
reportApi.fetchReportList(data)
.then(resp => {
})
}
}
}
</script>
2. 单独导出每个方法
在
src/api/report
下创建report.js
import request from '@/utils/request'
export function fetchReportList(data){
return request({
url: `/manager/report/page`,
method: 'get',
params:data
})
}
export function getReportById(data){
return request({
url: `/manager/report/${data}`,
method:'get'
})
}
export function importExcel(data){
return request({
url: '/manager/report/importBatch',
method:'post',
data
})
}
export function export2Excel(data){
return request({
url: '/manager/report/export',
method:'get'
})
}
export function saveOrUpdateReport(data){
return request({
url: '/manager/report/saveOrUpdate',
method:'post',
data
})
}
export function removeReportById(data){
return request({
url : `/manager/report/${data}`,
method:'delete'
})
}
export function getReportErrorPage(){
return request({
url: '/manager/report/errorPage',
method:'get'
})
}
export function upload(url,file){
let data = new FormData()
file.forEach(everyFile => {
data.append("files",everyFile.raw)
})
return request({
url:url,
method:'post',
data
})
}
使用的时候按需引入即可,不需要都引入
<srcipt>
import {fetchReportList,removeReportById,upload} from '@/api/report/report'
export default {
name: 'reportList',
data(){
return{
reportList:[],
}
},
created(){
this.fetchList();
},
methods:{
clearSearchForm(){
this.searchForm = {}
this.fetchList()
},
fetchList() {
let data = {
name:this.searchForm.name,
phone:this.searchForm.phone,
idCard:this.searchForm.idCard,
testingResult:this.searchForm.testingResult,
queryStartTime:this.searchForm.queryStartTime,
queryEndTime:this.searchForm.queryEndTime,
pageNum:this.pageNum,
pageSize:this.pageSize
}
fetchReportList(data).then(resp => {
this.reportList = resp.data.list
this.total = resp.data.total
this.pageSize = resp.data.pageSize
this.pageNum = resp.data.pageNum
})
}
}
</srcipt>
3. 总结
我自己是使用第二种方式的,可能也是受到了身边前端同时的影响,第一种可以有效的避免方法名重复我觉得哈哈哈🤤
4. 配置项目路由
在
src/router/index.js
中的constatnRoutes
修改
{
path: '/report',
component: Layout,
redirect: '/report/list',
name: 'report',
meta:{title: '核酸检测管理',icon: 'el-icon-search'},
alwaysShow:true,
children: [
{
path: 'list',
name: 'reportList',
component: () => import('@/views/report/list'),
meta: { title: '统计结果', icon: 'form' }
},
{
path: 'save',
name: 'saveReport',
component: () => import('@/views/report/form'),
meta: { title: '添加核酸检测数据', icon: 'form' }
},
{
//相当于占位符,这个id可以用this.$route.params.id取出来
path: 'edit/:id',
name: 'editReport',
component: () => import('@/views/report/form'),
meta: { title: '修改核酸检测结果', icon: 'form' },
hidden:true
},
]
},
序号 | 属性 | 子属性 | 描述 |
---|---|---|---|
1 | path | 路由的路径 | |
2 | name | 路由的名称,不能重复 | |
3 | redirect | 重定向的地址 | |
4 | component | 引用的组件 | |
5 | meta | 组件的描述 | |
6 | title | 组件的标题 | |
7 | icon | 组件的标签 | |
8 | alwaysShow | 是否永远展示, false时 有且仅有一个子组件时不展示 | |
9 | hidden | 是否隐藏 | |
10 | children | 子组件 |
抽离出来的数据库实体类
create teble sys_menu(
id int primary key auto_increment comment '',
parent_id int comment '',
path varchar(50) not null unique comment '',
name varchar(50) not null unique comment '',
redirect varchar(100) comment '',
component varchar(50) comment '',
title varchar(50) comment '',
icon varchar(50) comment '',
always_show bit(1) comment '',
hidden bit(1) comment '',
create_by varchar(50) comment '',
create_time datetime default now() comment '',
update_by varchar(50) comment '',
update_time datetime comment '',
del_flag tinyint default 0 comment '0未删除 1已删除'
)comment '系统菜单表';
5. 创建组件(使用两个vue页面)
在
src/views
下创建文件夹report
1. 创建列表组件 list.vue
1. 基础的表格展示
在
report
文件夹下创建list.vue
,使用elementui
的el-table
组件,elementui
提供了一个slot-scope
可以用来将后端传过来的数据转换成我们自己想要的数据,scope.row
就是用户当前在操作的那一行
<template>
<div class="app-container">
<!-- 表格 -->
<el-table :data="reportList" border stripe>
<el-table-column type="index" width="50" label="序号"/>
<el-table-column prop="name" width="70" label="姓名"/>
<el-table-column prop="phone" width="110" label="联系方式"/>
<el-table-column prop="idType" width="80" label="证件类型">
<template slot-scope="scope">
<span v-if="scope.row.idType == '1'">身份证</span>
<span v-if="scope.row.idType == '2'">护 照</span>
<span v-if="scope.row.idType == '3'">其 他</span>
</template>
</el-table-column>
<el-table-column prop="idCard" width="150" label="证件号"/>
<el-table-column prop="address" label="受检者地址"/>
<el-table-column prop="samplingTime" label="采样时间"/>
<el-table-column prop="testingResult" label="核酸检测结果">
<template slot-scope="scope">
<span v-if="scope.row.testingResult == '1'">阳性</span>
<span v-if="scope.row.testingResult == '2'">阴性</span>
<span v-else>暂无结果</span>
</template>
</el-table-column>
<el-table-column prop="testingInstitutionName" label="检测机构名称"/>
</el-table>
</div>
</template>
<script>
import {fetchReportList} from '@/api/report/report'
export default {
data() {
return {
reportList: []
}
}
created() {
this.fetchList()
},
methods: {
fetchList() {
fetchReportList().then(resp => {
this.reportList = resp.data
})
}
}
}
</script>
2. 创建表单组件form.vue
在
src/view/report
下创建form.vue
,此页面并没有添加表单校验,如有需要请参考表单验证。为了更好的控制每行的展示,可以使用栅格组件中的
el-row
来实现。一行 24列, 在el-col
中使用:span
控制占用多少。在生命周期
created
函数中,判断当前路由中的id是不是空值,这个值可以在ver devtools
中查看到。如果存在id
的话,则调用查询的接口,将获取到的数据展示在表单中
<template>
<div class="app-container" >
<el-form :model="report" label-width="260px" label-position="right" >
<el-row>
<el-col :span="12">
<el-form-item label="姓名">
<el-input v-model="report.name" placeholder="请填写姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系方式">
<el-input v-model="report.phone" placeholder="请填写联系方式" min="3" max="11"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="证件类型">
<el-select v-model="report.idType" placeholder="请选择证件类型">
<el-option label="身份证" value="1" />
<el-option label="护照" value="2" />
<el-option label="其他" value="3" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="证件号">
<el-input v-model="report.idCard" placeholder="请填写证件号" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="受检者地址">
<el-input v-model="report.address" placeholder="请填写受检者地址" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="采样时间">
<el-date-picker
v-model="report.samplingTime"
align="right"
type="datetime"
placeholder="请选择采样时间"
:picker-options="pickerOptions">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="检测结果">
<el-select v-model="report.testingResult" placeholder="请选择核酸检测结果" >
<el-option label="无" value="" />
<el-option label="阳性" value="1" />
<el-option label="阴性" value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="检测机构">
<el-input v-model="report.testingInstitutionName" placeholder="请填写核酸检测机构名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="样品管编号">
<el-input v-model="report.tubeNo" placeholder="请填写样品管编号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="包号">
<el-input v-model="report.packageNo" placeholder="请填写包号" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="检测时间">
<el-date-picker
v-model="report.testingTime"
align="right"
type="datetime"
placeholder="请选择检测时间"
:picker-options="pickerOptions"
>
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="采样机构">
<el-input v-model="report.testingInstitution" placeholder="请填写采样机构" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="类别编码">
<el-input v-model="report.type" placeholder="请填写类别编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用人单位代码">
<el-input v-model="report.succ" placeholder="请填写用人社会统一信用代码" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-form-item label="备注说明" style="width: 80%;">
<el-input type="textarea" v-model="report.intro" placeholder="请填写备注说明" />
</el-form-item>
</el-row>
<el-divider/>
<el-row>
<el-form-item>
<el-button icon="el-icon-loading"
type="primary"
@click="saveOrUpdate"
>{{loadingText}}</el-button>
</el-form-item>
</el-row>
</el-form>
</div>
</template>
<script>
import {getReportById, saveOrUpdateReport} from "@/api/report/report";
export default {
data(){
return{
loadingText:'保存',
report:{
},
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
shortcuts: [{
text: '今天',
onClick(picker) {
picker.$emit('pick', new Date());
}
}, {
text: '昨天',
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
picker.$emit('pick', date);
}
}, {
text: '一周前',
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', date);
}
}]
}
}
},
created() {
let id = this.$route.params.id
if(id){
this.getById(id)
}
},
methods:{
getById(id){
getReportById(id).then(resp => {
this.report = resp.data
})
},
saveOrUpdate(){
saveOrUpdateReport(this.report).then(resp => {
this.$message.success(resp.message)
this.$router.push('/report/list')
})
}
}
}
</script>
当然,也可以给最下方的保存按钮添加加载中这种特效
<template>
<div class="app-container">
<el-row>
<el-form-item>
<el-button :icon="loadingIcon"
type="primary"
@click="saveOrUpdate"
:loading="loading"
>{{loadingText}}
</el-button>
</el-form-item>
</el-row>
</div>
</template>
<script>
import {saveOrUpdateReport} from '@/api/report/report'
export default {
data() {
return {
loadingIcon: 'el-icon-success',
loading: false,
loadingText: '保存',
form: {}
}
},
methods: {
saveOrUpdate() {
this.changeLoadBtn('el-icon-loading', true, '保存中...')
saveOrUpdateReport(this.form).then(resp => {
this.$message.success(resp.messge)
//保存成功跳转到列表页面
this.$router.push('/report/list')
}).catch(err => {
this.changeLoadBtn('el-icon-error', false.
'保存失败'
)
})
},
//变更加载按钮
changeLoadBtn(loadingIcon, loading, loadingText) {
this.loadingIcon = loadingIcon
this.loading = loading
this.loadingText = loadingText
}
}
}
</script>
3. 列表页新增操作列
在
el-table
最后添加一列操作列,用来编辑和删除
<template>
<div class="app-container">
<el-table>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<router-link :to="`/report/edit/${scope.row.id}`" style="margin-right: 5px">
<el-button type="primary" size="mini">修改</el-button>
</router-link>
<el-button type="danger" @click="delReport(scope.row.id)"
size="mini">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import {removeReportById} from '@/api/report/report'
export default {
data() {
return {
form: {}
}
},
methods: {
delReport(id) {
removeReportById(id).then(resp => {
this.$message.success(resp.message)
})
}
}
}
</script>
因为编辑按钮点击之后就跳转了
form.vue
,所以直接使用router-link
会比较方便,应该相当于下边这种写法,但是我没验证过。
<template>
<div class="app-container">
<el-table>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="editReport(scope.row.id)">修改</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
form: {}
}
},
methods: {
editReport(id) {
this.$router.push(`/report/edit/${id}`)
}
}
}
</script>
4. 新增查询功能
1. 修改页面组件
在页面的最上方添加查询字段,在需要输入框添加
@keyup.enter.native
可以使回车键松开的时候调用查询方法,添加@blur
是的输入框失去焦点的时候调用查询方法,下拉选择狂可以使用@change
来调用
<template>
<div class="app-container">
<el-form :inline="true">
<el-form-item label="姓名">
<el-input v-model="searchForm.name"
placeholder="姓名"
clearable @blur="fetchList"
@keyup.enter.native="fetchList"/>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="searchForm.phone"
placeholder="手机号"
clearable @blur="fetchList"
@keyup.enter.native="fetchList"/>
</el-form-item>
<el-form-item label="证件号">
<el-input v-model="searchForm.idCard" placeholder="证件号" clearable @blur="fetchList"
@keyup.enter.native="fetchList"/>
</el-form-item>
<el-form-item label="检测结果">
<el-select v-model="searchForm.testingResult" placeholder="请选择" clearable @blur="fetchList"
@keyup.enter.native="fetchList">
<el-option label="阳性" value="1"/>
<el-option label="阴性" value="2"/>
<el-option label="暂无结果" value=""/>
</el-select>
</el-form-item>
<el-form-item label="采样时间">
<el-date-picker
@blur="fetchList" @keyup.enter.native="fetchList"
v-model="searchForm.queryStartTime"
type="date"
clearable
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
/>
-
<el-date-picker
@blur="fetchList" @keyup.enter.native="fetchList"
v-model="searchForm.queryEndTime"
type="date"
clearable
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
/>
</el-form-item>
<el-button type="primary" icon="el-icon-error" @click="clearSearchForm">
清空条件
</el-button>
<el-button type="primary" icon="el-icon-search" @click="fetchList()">
查询
</el-button>
<el-button @click="downloadTemplate" type="primary" icon="el-icon-download">
下载模板
</el-button>
<el-button @click="dialogVisible = true" type="primary" icon="el-icon-upload2">
导入
</el-button>
<el-button type="primary" icon="el-icon-download" @click="export2Excel">
导出
</el-button>
<el-button type="danger" icon="el-icon-error" @click="getErrorPage">
错误数据
</el-button>
</el-form>
<el-table>...</el-table>
</div>
</template>
2. 修改api
将searchForm里边所有的值都赋值给我们要查询的data
<script>
import {fetchReportList, getReportErrorPage, removeReportById,upload} from '@/api/report/report'
export default {
name: 'reportList',
data(){
return{
reportList:[],
searchForm:{
name:'',
phone: '',
idCard:'',
testingResult:'',
queryStartTime:'',
queryEndTime:''
},
}
},
methods:{
fetchList(){
let data = {
name:this.searchForm.name,
phone:this.searchForm.phone,
idCard:this.searchForm.idCard,
testingResult:this.searchForm.testingResult,
queryStartTime:this.searchForm.queryStartTime,
queryEndTime:this.searchForm.queryEndTime,
}
fetchReportList(data).then(resp => {
this.reportList = resp.data.list
})
}
}
}
</script>
当然这种方法不叫繁琐,也可以使用
...
来进行赋值
<script>
import {fetchReportList, getReportErrorPage, removeReportById,upload} from '@/api/report/report'
export default {
name: 'reportList',
data(){
return{
reportList:[],
searchForm:{
name:'',
phone: '',
idCard:'',
testingResult:'',
queryStartTime:'',
queryEndTime:''
},
}
},
methods:{
fetchList(){
// 可以将searchForm对象解构赋值,与上边的挨个赋值效果一致
let data = {
...this.searchForm
}
fetchReportList(data).then(resp => {
this.reportList = resp.data.list
})
}
}
}
</script>
5. 添加分页功能
1. 修改页面
在
el-table
标签下添加分页组件el-pagination
<template>
<div class="app-container">
<el-table>...</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[10,50,100, 200, 300, 400]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total" />
</div>
</template>
2. 修改api
添加分页相关的方法和属性。
首先
data
中添加了三个属性total
总条数,pageNum
查询页数,pageSize
每页展示多少条。其次
methods
中需要添加pageSize
和pageNum
变化的方法。在
fetchList
方法查询参数data
中添加分页的参数pageNum
和pageSize
即可。分页可以使用
async
,这一部分我还没研究到。🤡
<script>
import {fetchReportList} from '@/api/report/report'
export default {
name: 'reportList',
data(){
return{
reportList:[],
searchForm:{
name:'',
phone: '',
idCard:'',
testingResult:'',
queryStartTime:'',
queryEndTime:''
},
total:0,
pageSize:10,
pageNum:1
}
},
created(){
this.fetchList();
},
methods:{
clearSearchForm(){
this.searchForm = {}
this.fetchList()
},
fetchList() {
let data = {
...this.searchForm,
pageNum:this.pageNum,
pageSize:this.pageSize
}
console.log(data,'data')
fetchReportList(data).then(resp => {
this.reportList = resp.data.list
this.total = resp.data.total
this.pageSize = resp.data.pageSize
this.pageNum = resp.data.pageNum
})
},
handleSizeChange(pageSize){
this.pageSize =pageSize
this.fetchList();
},
handleCurrentChange(pageNum){
this.pageNum = pageNum
this.fetchList();
}
}
}
</script>
6. 添加导入导出功能
在搜索的后边添加导入导出功能按钮
1. 修改页面
当然也可以将下载模板放置到弹出的
el-dialog
中
<template>
<div class="app-container">
<el-form :inline="true">
<el-button @click="downloadTemplate" type="primary" icon="el-icon-download">
下载模板
</el-button>
<el-button @click="dialogVisible = true" type="primary" icon="el-icon-upload2">
导入
</el-button>
<el-button type="primary" icon="el-icon-download" @click="export2Excel" >
导出
</el-button>
</el-form>
<el-dialog title="核酸检测结果数据导入"
:visible.sync="dialogVisible"
width="30%"
@close="fetchList">
<el-form>
<el-form-item label="请选择Excel文件">
<el-upload
class="upload-demo"
drag
ref="upload"
action="http://localhost:8090/manager/report/import"
:auto-upload="autoUpload"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:on-change="beforeUpload"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:data="extraParam"
:limit="fileSizeLimit"
:file-list="fileList"
:on-exceed="handleExceed"
:accept="fileType"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">
<span style="color: #FE6D68;">*</span>
请选择 .xls 或 .xlsx后缀的文件
</div>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="submitUpload" type="primary">
确认
</el-button>
<el-button @click="dialogVisible = false">
取消
</el-button>
</div>
</el-dialog>
</div>
</template>
2. 修改api
<script>
import {fetchReportList, getReportErrorPage, removeReportById,upload} from '@/api/report/report'
export default {
name: 'reportList',
data(){
return{
reportList:[],
searchForm:{
name:'',
phone: '',
idCard:'',
testingResult:'',
queryStartTime:'',
queryEndTime:''
},
dialogVisible: false, //文件上传对话框是否显示
BASE_API: process.env.VUE_APP_BASE_API, //获取后端接口地址
total:0,
pageSize:10,
pageNum:1,
/* 上传时附带的额外参数,返回是一个对象 */
extraParam: {},
/* 已上传的文件列表 */
fileList: [],
/* 是否在选取文件后立即进行上传 */
autoUpload: false,
fileSizeLimit:100,
fileType:'.xls,.xlsx',
uploadAction:'http://localhost:8090/manager/report/import'
}
},
created(){
this.fetchList();
},
methods:{
clearSearchForm(){
this.searchForm = {}
this.fetchList()
},
fetchList() {
let data = {
...this.searchForm,
pageNum:this.pageNum,
pageSize:this.pageSize
}
console.log(data,'data')
fetchReportList(data).then(resp => {
this.reportList = resp.data.list
this.total = resp.data.total
this.pageSize = resp.data.pageSize
this.pageNum = resp.data.pageNum
})
},
handleSizeChange(pageSize){
this.pageSize =pageSize
this.fetchList();
},
handleCurrentChange(pageNum){
this.pageNum = pageNum
this.fetchList();
},
export2Excel(){
window.location.href =this.BASE_API
+ `/manager/report/export?name=${this.searchForm.name}&phone=${this.searchForm.phone}&idCard=${this.searchForm.idCard}&testingResult=${this.searchForm.testingResult}`
},
/* 文件列表移除文件成功时的钩子 */
handleRemove(file, fileList) {
return this.$message.success(`已成功移除"${file.name}"文件`)
},
/* 处理上传失败时的勾子 */
handleUploadError(err, file, fileList) {
this.$message.error(`文件上传失败`)
},
/* 文件删除前的勾子 */
beforeRemove(file, fileList) {
return this.$confirm(`确定移除"${file.name}"文件吗?`)
},
/* 上传文件之前的钩子 因设置了auto-upload为false,如果使用before-upload,虽有提示,但是还是会请求服务器*/
beforeUpload(file,fileList) {
// 1、判断文件名是否重复,不允许上传相同文件
let existFile = fileList.slice(0, fileList.length - 1).find(f => f.name === file.name)
if(existFile){
fileList.pop()
this.$message.error(file.name+" 文件已存在!")
}
// 2、获取文件后缀
fileList.forEach(everyFile => {
const fileType = everyFile.name.substring(everyFile.name.lastIndexOf('.'))
if(this.fileType.search(fileType) === -1){
fileList.pop()
this.$message.error("上传文件的类型不正确"+"文件类型必须为" + this.fileType + '')
}
})
this.fileList = fileList;
},
/* 文件超出个数限制时的钩子 */
handleExceed(files, fileList) {
this.$message.error(`当前限制选择`+ this.fileSizeLimit +`个文件,本次选择了 ${files.length} 个文件,已超出了文件最大上传个数`)
},
/* 文件上传成功时的钩子 */
handleUploadSuccess(res, file, fileList) {
console.info(JSON.stringify(res))
},
/* 确定上传 */
submitUpload() {
upload(this.uploadAction,this.fileList).then(res => {
this.$message.success(res.message)
this.fileList = []
this.dialogVisible = false
});
},
downloadTemplate(){
window.location.href = this.BASE_API + '/manager/report/downloadTemplate'
}
}
}
</script>
7. 最终的list.vue
<template>
<div class="app-container">
<el-form :inline="true">
<el-form-item label="姓名">
<el-input v-model="searchForm.name" placeholder="姓名" clearable @blur="fetchList" @keyup.enter.native="fetchList"/>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="searchForm.phone" placeholder="手机号" clearable @blur="fetchList" @keyup.enter.native="fetchList"/>
</el-form-item>
<el-form-item label="证件号">
<el-input v-model="searchForm.idCard" placeholder="证件号" clearable @blur="fetchList" @keyup.enter.native="fetchList"/>
</el-form-item>
<el-form-item label="检测结果">
<el-select v-model="searchForm.testingResult" placeholder="请选择" clearable @blur="fetchList" @keyup.enter.native="fetchList">
<el-option label="阳性" value="1" />
<el-option label="阴性" value="2" />
<el-option label="暂无结果" value="" />
</el-select>
</el-form-item>
<el-form-item label="采样时间" >
<el-date-picker
@blur="fetchList" @keyup.enter.native="fetchList"
v-model="searchForm.queryStartTime"
type="date"
clearable
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
/>
-
<el-date-picker
@blur="fetchList" @keyup.enter.native="fetchList"
v-model="searchForm.queryEndTime"
type="date"
clearable
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
/>
</el-form-item>
<el-button type="primary" icon="el-icon-error" @click="clearSearchForm">
清空条件
</el-button>
<el-button type="primary" icon="el-icon-search" @click="fetchList()">
查询
</el-button>
<el-button @click="downloadTemplate" type="primary" icon="el-icon-download">
下载模板
</el-button>
<el-button @click="dialogVisible = true" type="primary" icon="el-icon-upload2">
导入
</el-button>
<el-button type="primary" icon="el-icon-download" @click="export2Excel" >
导出
</el-button>
<el-button type="danger" icon="el-icon-error" @click="getErrorPage">
错误数据
</el-button>
</el-form>
<el-divider />
<!-- 表格 -->
<el-table :data="reportList" border stripe>
<el-table-column type="index" width="50" label="序号"/>
<el-table-column prop="name" width="70" label="姓名" />
<el-table-column prop="phone" width="110" label="联系方式" />
<el-table-column prop="idType" width="80" label="证件类型">
<template slot-scope="scope">
<span v-if="scope.row.idType == '1'">身份证</span>
<span v-if="scope.row.idType == '2'">护 照</span>
<span v-if="scope.row.idType == '3'">其 他</span>
</template>
</el-table-column>
<el-table-column prop="idCard" width="150" label="证件号" />
<el-table-column prop="address" label="受检者地址" />
<el-table-column prop="samplingTime" label="采样时间" />
<el-table-column prop="testingResult" label="核酸检测结果">
<template slot-scope="scope">
<span v-if="scope.row.testingResult == '1'">阳性</span>
<span v-if="scope.row.testingResult == '2'">阴性</span>
<span v-else>暂无结果</span>
</template>
</el-table-column>
<el-table-column prop="testingInstitutionName" label="检测机构名称" />
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<router-link :to="`/report/edit/${scope.row.id}`" style="margin-right: 5px">
<el-button type="primary" size="mini">修改</el-button>
</router-link>
<el-button type="danger" @click="delReport(scope.row.id)"
size="mini">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[10,50,100, 200, 300, 400]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
size="">
</el-pagination>
<el-dialog title="核酸检测结果数据导入" :visible.sync="dialogVisible" width="30%" @close="fetchList">
<el-form>
<el-form-item label="请选择Excel文件">
<el-upload
class="upload-demo"
drag
ref="upload"
action="http://localhost:8090/manager/report/import"
:auto-upload="autoUpload"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:on-change="beforeUpload"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:data="extraParam"
:limit="fileSizeLimit"
:file-list="fileList"
:on-exceed="handleExceed"
:accept="fileType"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">
<span style="color: #FE6D68;">*</span>
请选择 .xls 或 .xlsx后缀的文件
</div>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="submitUpload" type="primary">
确认
</el-button>
<el-button @click="dialogVisible = false">
取消
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {fetchReportList, getReportErrorPage, removeReportById,upload} from '@/api/report/report'
export default {
name: 'reportList',
data(){
return{
reportList:[],
searchForm:{
name:'',
phone: '',
idCard:'',
testingResult:'',
queryStartTime:'',
queryEndTime:''
},
dialogVisible: false, //文件上传对话框是否显示
BASE_API: process.env.VUE_APP_BASE_API, //获取后端接口地址
total:0,
pageSize:10,
pageNum:1,
/* 上传时附带的额外参数,返回是一个对象 */
extraParam: {},
/* 已上传的文件列表 */
fileList: [],
/* 是否在选取文件后立即进行上传 */
autoUpload: false,
fileSizeLimit:100,
fileType:'.xls,.xlsx',
uploadAction:'http://localhost:8090/manager/report/import'
}
},
created(){
this.fetchList();
},
methods:{
clearSearchForm(){
this.searchForm = {}
this.fetchList()
},
fetchList() {
let data = {
...this.searchForm,
pageNum:this.pageNum,
pageSize:this.pageSize
}
console.log(data,'data')
fetchReportList(data).then(resp => {
this.reportList = resp.data.list
this.total = resp.data.total
this.pageSize = resp.data.pageSize
this.pageNum = resp.data.pageNum
})
},
delReport(id){
this.$confirm('此操作将永久删除该记录,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
removeReportById(id).then(resp => {
this.$message.success(resp.message)
this.fetchList()
})
}).catch(err => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
handleSizeChange(pageSize){
this.pageSize =pageSize
this.fetchList();
},
handleCurrentChange(pageNum){
this.pageNum = pageNum
this.fetchList();
},
export2Excel(){
window.location.href =this.BASE_API
+ `/manager/report/export?name=${this.searchForm.name}&phone=${this.searchForm.phone}&idCard=${this.searchForm.idCard}&testingResult=${this.searchForm.testingResult}`
},
getErrorPage(){
getReportErrorPage().then(resp => {
this.reportList = resp.data.list
this.total = resp.data.total
this.pageSize = resp.data.pageSize
this.pageNum = resp.data.pageNum
})
},
/* 文件列表移除文件成功时的钩子 */
handleRemove(file, fileList) {
return this.$message.success(`已成功移除"${file.name}"文件`)
},
/* 处理上传失败时的勾子 */
handleUploadError(err, file, fileList) {
this.$message.error(`文件上传失败`)
},
/* 文件删除前的勾子 */
beforeRemove(file, fileList) {
return this.$confirm(`确定移除"${file.name}"文件吗?`)
},
/* 上传文件之前的钩子 因设置了auto-upload为false,如果使用before-upload,虽有提示,但是还是会请求服务器*/
beforeUpload(file,fileList) {
// 1、判断文件名是否重复,不允许上传相同文件
let existFile = fileList.slice(0, fileList.length - 1).find(f => f.name === file.name)
if(existFile){
fileList.pop()
this.$message.error(file.name+" 文件已存在!")
}
// 2、获取文件后缀
fileList.forEach(everyFile => {
const fileType = everyFile.name.substring(everyFile.name.lastIndexOf('.'))
if(this.fileType.search(fileType) === -1){
fileList.pop()
this.$message.error("上传文件的类型不正确"+"文件类型必须为" + this.fileType + '')
}
})
this.fileList = fileList;
},
/* 文件超出个数限制时的钩子 */
handleExceed(files, fileList) {
this.$message.error(`当前限制选择`+ this.fileSizeLimit +`个文件,本次选择了 ${files.length} 个文件,已超出了文件最大上传个数`)
},
/* 文件上传成功时的钩子 */
handleUploadSuccess(res, file, fileList) {
console.info(JSON.stringify(res))
},
/* 确定上传 */
submitUpload() {
upload(this.uploadAction,this.fileList).then(res => {
this.$message.success(res.message)
this.fileList = []
this.dialogVisible = false
});
},
downloadTemplate(){
window.location.href = this.BASE_API + '/manager/report/downloadTemplate'
}
}
}
</script>
6. 创建组件(使用dialog弹出新增编辑页面)
暂时没时间写
7. 后端创建
创建出来后端项目,配置好跨域,添加
context-path
server:
port: 8090
servlet:
context-path: /manager
8. 运行前配置
前后端分离的配置一般都是通过
Nginx
来管理静态资源,在通过Nginx
将请求代理到后台的,所以需要对前端项目进行相关的配置
1. 本地运行
1. 修改 .env.development文件
将
VUE_APP_BASE_API
修改为Nginx
运行端口
VUE_APP_BASE_API = 'http://localhost'
2. 修改 request.js
将
src/utils/request.js
中的axios
相关哦诶之修改一下
- 修改baseURL
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout:5000
})
- 修改响应拦截器
service.interceptors.response.use(response =>{
const res = response.data
// 这里添加上自己后端返回正确的编码
if (res.code !== 20000 && res.code != 200) {}
})
3. 修改mock服务
本次未整合后端的登录注册服务,依旧使用原来的mock
- 修改
mock/mock-server.js
第39行
url: new RegExp(`/dev-api${url}`),
- 修改
src/api/user.js
为每一个接口添加baseURL
import request from '@/utils/request'
export function login(data) {
return request({
baseURL: '/dev-api',
url: '/vue-admin-template/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
baseURL: '/dev-api',
url: '/vue-admin-template/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
baseURL: '/dev-api',
url: '/vue-admin-template/user/logout',
method: 'post'
})
}
4. Nginx修改
前端打包
npm run bubild:prod
将前端打包后生成的
dist
文件夹复制到Nginx
解压目录下,修改conf/nginx.conf
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root dist;
index index.html index.htm;
}
location /manager/ {
proxy_pass http://localhost:8090;
}
}
在
nginx
解压目录的文件地址栏输入cmd
,在cmd
窗口运行Nginx
start nginx.exe
启动后端项目,并使用浏览器打开
localhost
进行测试
2. 部署线上环境
1. 后端修改
在
pom.xml
添加打包的相关配置,在IDEA
右侧maven
-->LifeCycle
-->package
或者直接执行mvn clean package
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>net.lesscoding.MainApp</mainClass>
</configuration>
<version>1.4.2.RELEASE</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.2</version>
</plugin>
</plugins>
</build>
2. 服务器相关配置
更多推荐
所有评论(0)