1.技术要点
mybatisplus;vue3,springboot2;javaguns框架
2实现导入功能
后端实现:
①controller层
@RestController
@ApiResource(name = "项目评价")
public class ProjectAppraisalController {/*** 导入excel表数据* @param file* @return*/@PostResource(name = "数据导入" ,path = "/projectAppraisal/import")public ResponseData<?> importData(MultipartFile file){return new SuccessResponseData<>(projectAppraisalService.importData(file));}}
-
这段代码是一个使用了Spring Boot框架的控制器方法。它使用了
@PostResource
注解来定义一个POST请求的资源,并指定了资源的名称为"数据导入",路径为"/awardPatent/import"。该方法接收一个
MultipartFile
类型的文件作为参数,表示要导入的文件。MultipartFile
是Spring框架提供的一个类,用于处理文件上传。在方法体内,调用了
awardPatentService.importData(file)
来处理文件导入的逻辑。awardPatentService
是一个服务类的实例,通过调用其importData
方法来处理文件导入操作。最后,将导入操作的结果封装在一个
SuccessResponseData
对象中,并作为响应返回。SuccessResponseData
是一个自定义的响应数据类,表示成功的响应,并包含了导入操作的结果数据。总结来说,这段代码定义了一个用于处理文件导入的控制器方法。它接收一个文件作为参数,调用服务类的方法来处理文件导入操作,并将结果封装在响应数据中返回。具体的实现逻辑需要根据代码的上下文来确定。
②service层:
public interface ProjectAppraisalService extends IService<ProjectAppraisal> {ResponseData<?> importData(MultipartFile file);}
-
ResponseData<?> importData(MultipartFile file)
是一个方法声明,其中ResponseData<?>
表示返回类型为ResponseData
,而MultipartFile file
是该方法的参数,表示接收一个文件作为输入。具体来说,这个方法可能是用于处理文件导入的逻辑。它接收一个
MultipartFile
类型的文件作为参数,表示要导入的文件。MultipartFile
是Spring框架提供的一个类,用于处理文件上传。ResponseData
是一个自定义的响应数据类,可能包含了请求的处理结果和相关的数据。<?>
表示泛型,表示可以是任意类型的数据。这个方法的作用可能是将接收到的文件进行处理,然后返回一个包含处理结果和相关数据的
ResponseData
对象。总结来说,
ResponseData<?> importData(MultipartFile file)
是一个方法声明,用于处理文件导入操作。它接收一个文件作为参数,并返回一个包含处理结果和相关数据的ResponseData
对象。具体的实现逻辑需要根据代码的上下文来确定。
③实体层:
@TableName("project_appraisal")
@Data
@ExcelIgnoreUnannotated
@EqualsAndHashCode(callSuper = true)
public class ProjectAppraisal extends BaseEntity {@ExcelProperty(value = "序号",index = 0)@TableField(exist = false)private Integer serialNum;/*** 主键*/@TableId(value = "id", type = IdType.ASSIGN_ID)@ChineseDescription("主键")private Long id;/*** 流程ID*/@TableField("process_id")@ChineseDescription("流程ID")private String processId;/*** 管理编号*/@TableField("manage_code")@ChineseDescription("管理编号")private String manageCode;/*** 案件状态*/@TableField("status")@ChineseDescription("案件状态")private String status;@TableField(exist = false)@ChineseDescription("工作流相关")private WorkflowModel workflowModel;/*** 项目名称*/@TableField("project_name")@ExcelProperty(value = "项目名称",index = 1)@ChineseDescription("项目名称")private String projectName;/*** 投产单位*/@TableField("production_unit")@ChineseDescription("投产单位")@ExcelProperty(value = "投产单位",index = 2)private String productionUnit;/*** 评价单位*/@TableField("evaluation_unit")@ChineseDescription("评价单位")@ExcelProperty(value = "评价单位",index = 3)private String evaluationUnit;/*** 评价方式*/@TableField("evaluation_method")@ChineseDescription("评价方式")@ExcelProperty(value = "评价方式",index = 4)private String evaluationMethod;/*** 评价时间*/@DateTimeFormat("yyyy-MM-dd")@TableField("evaluation_time")@ChineseDescription("评价时间")@ExcelProperty(value = "评价时间",index = 5)private Date evaluationTime;/*** 评价结果*/@TableField("evaluation_result")@ChineseDescription("评价结果")@ExcelProperty(value = "评价结果",index = 6)private String evaluationResult;/*** 附件*/@TableField("attachment")@ChineseDescription("附件")private String attachment;}
④serviceImpl
@Service
public class ProjectAppraisalServiceImpl extends ServiceImpl<ProjectAppraisalMapper, ProjectAppraisal> implements ProjectAppraisalService {@Overridepublic ResponseData<?> importData(MultipartFile file) {if (file != null){List<ProjectAppraisal> projectAppraisalList = null;try {//创建监听器GeneralListener<ProjectAppraisal> listener = new GeneralListener<>();//执行Excel的读取,read方法需要三个参数 ,文件(流) 大的Class实例 监听器EasyExcel.read(file.getInputStream() , ProjectAppraisal.class , listener).sheet().doRead();//获取监听器的数据projectAppraisalList = listener.getList();} catch (IOException e) {return new ErrorResponseData<>("F0002" ,"数据格式有误");}//处理表头的第一行数据、projectAppraisalList.stream().filter(item -> Pattern.matches("//d+", String.valueOf(item.getSerialNum())));//添加表中数据projectAppraisalList.forEach(projectAppraisal -> {String projectName = projectAppraisal.getProjectName();String productionUnit = projectAppraisal.getProductionUnit();LambdaQueryWrapper<ProjectAppraisal> wrapper = new LambdaQueryWrapper<>();wrapper.eq(ProjectAppraisal::getProjectName ,projectName);wrapper.eq(ProjectAppraisal::getProductionUnit,productionUnit);List<ProjectAppraisal> projectAppraisals = projectAppraisalService.list(wrapper);//如果不存在,加入if (projectAppraisals.isEmpty()){projectAppraisal.setStatus("完成");projectAppraisal.setCreateTime(new Date());projectAppraisalService.save(projectAppraisal);}});return new SuccessResponseData<>("00000" ,"上传成功" ,null);}else {return new ErrorResponseData<>("F0003" ,"上传失败");}}}
这段代码是一个实现了importData
方法的具体实现。该方法接收一个MultipartFile
类型的文件作为参数,并返回一个ResponseData<?>
类型的响应数据。
在方法体内,首先判断传入的文件是否为空。如果不为空,则继续执行文件导入的逻辑。
在文件导入的逻辑中,首先创建一个GeneralListener<ProjectAppraisal>
类型的监听器对象。然后使用EasyExcel库的read
方法,传入文件流、ProjectAppraisal
类的实例和监听器对象,来读取Excel文件的内容。通过监听器对象获取读取到的数据,将其赋值给projectAppraisalList
变量。
接下来,对projectAppraisalList
进行处理。首先使用stream()
方法和filter()
方法,过滤出表头的第一行数据。然后使用forEach()
方法遍历projectAppraisalList
,对每个ProjectAppraisal
对象进行处理。根据项目名称和生产单位查询数据库中是否存在相同的记录,如果不存在,则将该记录保存到数据库中。
最后,根据处理结果返回相应的响应数据。如果文件上传成功,返回一个SuccessResponseData
对象,包含成功的响应码和消息。如果文件上传失败,返回一个ErrorResponseData
对象,包含失败的响应码和消息
3.前端代码:
<template><div class="ele-body"><!-- 搜索表单 --><div class="block-interval"><a-card :bordered="false"><a-form :model="where"><a-row :gutter="20"><a-col><a-form-item label="项目名称:"><a-input v-model:value.trim="where.projectName" placeholder="请输入项目名称" allow-clear /></a-form-item></a-col><a-col><a-form-item label="评价单位:"><a-input v-model:value.trim="where.evaluationUnit" placeholder="请输入评价单位" allow-clear /></a-form-item></a-col><a-col><a-space class="ele-text-center"><a-button type="primary" @click="reload">查询</a-button><a-button @click="reset">重置</a-button></a-space></a-col></a-row></a-form></a-card></div><!-- 表格 --><div><a-card :bordered="false" class="table-height"><ele-pro-tableref="table"row-key="id":datasource="datasource":columns="columns":where="where"v-model:selection="selection":scroll="{ x: 'max-content' }"><!-- table上边工具栏 --><template #toolbar><a-space><a-button type="primary" @click="openEdit()" v-permission="'PROJECTEVALUATION_ADD_BUTTON'"><template #icon><plus-outlined /></template><span>新建</span></a-button><a-button class="export-excel-button" type="primary" @click="exportExcel" v-permission="'PROJECTEVALUATION_EXPORT_BUTTON'"><template #icon><download-outlined /></template><span>导出</span></a-button><a-button @click="showImport()" v-if="hasRole()"><upload-outlined />导入</a-button></a-space><a-modal v-model:visible="isShowImport" title="导入数据" :footer="null"><a-upload-draggerref="fileImport"v-model:file-list="fileList"name="file":multiple="true":accept="importAccept":action="baseUrl + '/projectAppraisal/import'":headers="headers"@change="handleChange"@reject="handleReject":before-upload="beforeImport"><p class="ant-upload-drag-icon"><inbox-outlined></inbox-outlined></p><p class="ant-upload-text">点击选择文件或拖拽文件到此处</p></a-upload-dragger><p style="margin-top: 20px; text-align: center; color: #ccc">请上传Excel格式文件,<a href="/static/template/projectappraisal.xlsx" download="项目评价数据导入模板.xlsx">下载模板</a></p></a-modal></template><template #bodyCell="{ column, record }"><template v-if="column.key === 'ended'"><a-tag color="green" v-if="(record.workflowModel ? record.workflowModel.isEnd : '') === 1">是</a-tag><a-tag color="red" v-else> 否</a-tag></template><!-- 当前节点 --><template v-if="column.key === 'active'"><span v-if="record.workflowModel"><a @click="tracking(record)" v-if="record.workflowModel.isEnd === 1">结束</a><a @click="tracking(record)" v-else>{{ record.workflowModel.actName }}</a></span><span v-else> - </span></template><!-- 申报结果 --><template v-if="column.key === 'evaluationResult'"><span v-if="record.evaluationResult"><a-tag color="green" v-if="record.evaluationResult === '是'">通过</a-tag><a-tag color="red" v-else>未通过</a-tag></span><span v-else> - </span></template><!-- table操作栏按钮 --><template v-if="column.key === 'action'"><a-space><a @click="openDetail(record)">查看</a><a-spacev-permission="'PROJECTEVALUATION_UPDATE_BUTTON'"v-if="(record.workflowModel && record.workflowModel.isEnd) !== 1 || hasRole()"><a-divider type="vertical" /><a @click="openEdit(record)">修改</a></a-space><a-space v-permission="'PROJECTEVALUATION_UPDATE_BUTTON'" v-if="record.status === '完成' && !record.evaluationResult"><a-divider type="vertical" /><a-popconfirmtitle="该记录是否通过申报?"ok-text="通过"cancel-text="不通过"@confirm="resultFun(record, '是')"@cancel="resultFun(record, '否')"><a>结果</a></a-popconfirm></a-space><a-space v-permission="'PROJECTEVALUATION_DEL_BUTTON'" v-if="record.status === '暂存' || hasRole()"><a-divider type="vertical" /><a-popconfirm title="确定要删除此记录吗?" @confirm="remove(record)"><a class="ele-text-danger">删除</a></a-popconfirm></a-space></a-space></template></template></ele-pro-table></a-card></div><common-tracking ref="tracking" /><!-- 编辑弹窗 --><projectAppraisal-edit v-model:visible="showEdit" :data="current" @done="reload" /></div>
</template>
<script>
import { message } from 'ant-design-vue';
import { PlusOutlined } from '@ant-design/icons-vue';
import ProjectAppraisalEdit from './project_appraisal_edit.vue';
import { ProjectAppraisalApi } from '@/api/bohua/ProjectAppraisalApi';
import CommonTracking from '@/views/workflow/tracking/common-tracking.vue';
import { useUserStore } from '@/store/modules/user';
import { hasRole } from '@/utils/permission';
import { toDateString } from 'ele-admin-pro';
import { ref } from 'vue';
import { getToken } from '@/utils/token-util';export default {name: 'ProjectAppraisal',components: {PlusOutlined,ProjectAppraisalEdit,CommonTracking},async mounted() {},data() {return {isShowImport: ref(false),fileList: [],importAccept: ['.xlsx', '.xls'],baseUrl: import.meta.env.VITE_API_URL,// 表格列配置columns: [{key: 'index',title: '序号',align: 'center',width: 48,customRender: ({ index }) => this.$refs.table.tableIndex + index},{title: '项目名称',dataIndex: 'projectName'},{title: '投产单位',dataIndex: 'productionUnit'},{title: '评价单位',dataIndex: 'evaluationUnit'},{title: '评价方式',dataIndex: 'evaluationMethod'},{title: '评价时间',dataIndex: 'evaluationTime',customRender: ({ text }) => {return !text ? '-' : toDateString(text, 'yyyy-MM-dd');}},{title: '评价结果',dataIndex: 'evaluationResult',key: 'evaluationResult'},{ellipsis: true,resizable: true,title: '审批节点',dataIndex: 'workflowModel.actName',key: 'active'},{title: '流程结束',dataIndex: 'workflowModel.isEnd',key: 'ended'},{title: '操作',key: 'action',width: 180,fixed: 'right',align: 'center'}],// 表格搜索条件where: {},// 表格选中数据selection: [],// 当前编辑数据current: null,// 是否显示编辑弹窗showEdit: false,// 是否查看isDetail: false,headers: {authorization: getToken()}};},methods: {showImport() {this.isShowImport = true;},isAllowedFile(fileName, allowedExtensions) {const fileExtension = '.' + fileName.split('.').pop().toLowerCase();return allowedExtensions.includes(fileExtension);},hasRole() {return hasRole('superAdmin');},handleChange(info) {if (!this.isAllowedFile(info.file.name, this.importAccept) || info.file.status !== 'uploading') {// 如果文件格式支持或不在上传if (info.file.status == 'done' || info.file.status == 'error') {const success = info.file?.response?.success || false;const msg = info.file?.response?.message || '';if (!success || info.file.status == 'error') {message.error(info.file.name + '导入失败!' + msg);} else if (info.file.status == 'done') {message.success(info.file.name + '导入成功!');}}//console.log('移除上传完成、上传错误或不允许上传的文件');this.fileList = info.fileList.filter(file => file.uid !== info.file.uid);}},handleReject() {message.error('上传文件格式不正确!');},beforeImport(file) {if (!this.isAllowedFile(file.name, this.importAccept)) {message.error('上传文件只能是' + this.importAccept.join('、') + '格式!');return false; // 阻止上传}return true; // 允许上传},/*** 打开追踪界面***/tracking(row) {this.$refs.tracking.tracking(row.processId);},/*** 搜索按钮** */reload() {this.selection = [];this.$refs.table.reload({ page: 1 });},/*** 重置搜索** */reset() {this.reloadPage = 1;this.where.projectName = '';this.where.evaluationUnit = '';this.$nextTick(() => {this.reload();});},/*** 删除** @author zhihui* @date 2023/12/26 09:38*/async remove(row) {const result = await ProjectAppraisalApi.delete({ id: row.id });message.success(result.message);this.reload();},/*** 打开新增或编辑弹窗** */openEdit(row) {if (row) this.current = row;else {//新建时,默认企业名称为用户所在单位const loginUserInfo = useUserStore().info;this.current = { companyName: loginUserInfo.orgName };}this.showEdit = true;this.isDetail = false;},openDetail(row) {this.current = row;this.showEdit = true;this.isDetail = true;},/*** 获取表格数据** */datasource({ page, limit, where, orders }) {return ProjectAppraisalApi.findPage({ ...where, ...orders, pageNo: page, pageSize: limit });},resultFun(record, i) {ProjectAppraisalApi.edit({ id: record.id, evaluationResult: i }).then(result => {message.success(result.message);this.reload();});},exportExcel() {ProjectAppraisalApi.exportExcel(this.where);}}
};
</script>