Vue3上传下载的样式模版 | 附Demo(Vue3 + Java)

ops/2024/10/22 15:40:20/

目录

  • 前言
  • 1. 基本知识
  • 2. Demo
  • 3. 彩蛋
    • 3.1 下载
    • 3.2 上传

前言

基本的Vue3知识推荐阅读:Vue 目录

1. 基本知识

对于下述Demo涉及以下知识点:

  1. Vue 组件基础

使用 defineComponent 定义一个 Vue 组件
script setup 是一种新的 <script> 语法糖,用于简化组件的定义
Dialog 组件用于创建一个弹出对话框,包含 v-model 双向绑定来控制对话框的显示和隐藏
el-upload 组件用于文件上传,提供多种属性和事件来处理文件上传逻辑
template #footer 是一个具名插槽,用于定义对话框底部的按钮

  1. Vue 3 Composition API

ref 和 reactive
ref 用于创建响应式的数据对象,如 dialogVisible、formLoading、fileList 等
reactive 可以创建一个响应式对象,用于更复杂的状态管理

方法和事件
通过 ref 和 defineExpose 提供方法给父组件调用,如 open 方法
详细分析Vue3中的defineExpose(附Demo)
使用 defineEmits 定义组件触发的事件,如 success 事件
详细分析Vue3中的defineEmits基本知识(子传父)

  1. Element Plus 组件库

Dialog 对话框
Dialog 组件用于创建弹出对话框,使用 v-model 绑定显示状态
width 属性设置对话框的宽度,title 属性设置对话框的标题

el-upload 文件上传
el-upload 组件用于文件上传,支持拖拽上传和点击上传
action 属性指定上传文件的服务器地址
headers 属性用于设置上传请求的头部信息

  1. 异步操作和 API 调用

API 调用
使用 axios 或其他 HTTP 客户端库进行 API 调用,如 AppointmentCommissionApi.importUserTemplate()
处理文件下载时,使用 download 工具函数下载模板文件

4.2. 异步函数
使用 async/await 语法处理异步操作,确保操作按预期顺序执行

2. Demo

基本的语法知识只是点睛一下

如下Demo:
AppointmentImportForm(负责渲染一个对话框,允许用户上传文件以导入预约委托)

<template><Dialog v-model="dialogVisible" title="危品预约委托导入" width="400"><!-- 文件上传组件 --><el-uploadref="uploadRef"v-model:file-list="fileList":action="importUrl + '?updateSupport=' + updateSupport":auto-upload="false":disabled="formLoading":headers="uploadHeaders":limit="1":on-error="submitFormError":on-exceed="handleExceed":on-success="submitFormSuccess"accept=".xlsx, .xls"drag><Icon icon="ep:upload" /><div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div><!-- 上传提示信息 --><template #tip><div class="el-upload__tip text-center"><div class="el-upload__tip"><el-checkbox v-model="updateSupport" />是否更新已经存在的委托数据</div><span>仅允许导入 xls、xlsx 格式文件。</span><el-link:underline="false"style="font-size: 12px; vertical-align: baseline"type="primary"@click="importTemplate">下载模板</el-link></div></template></el-upload><!-- 对话框底部的按钮 --><template #footer><el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button><el-button @click="dialogVisible = false">取 消</el-button></template></Dialog>
</template><script lang="ts" setup>javascript">
import * as AppointmentCommissionApi from '@/api/dangerous/appointmentcommission'
import { getAccessToken, getTenantId } from '@/utils/auth'
import download from '@/utils/download'defineOptions({ name: 'AppointmentImportForm' })// 消息弹窗
const message = useMessage()// 对话框的显示控制
const dialogVisible = ref(false)
const formLoading = ref(false)
const uploadRef = ref()
const importUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/dangerous/appointment-commission/import'
const uploadHeaders = ref()
const fileList = ref([])
const updateSupport = ref(0)// 打开对话框
const open = () => {dialogVisible.value = trueupdateSupport.value = 0fileList.value = []resetForm()
}
defineExpose({ open })// 提交表单
const submitForm = async () => {if (fileList.value.length == 0) {message.error('请上传文件')return}// 设置上传请求头uploadHeaders.value = {Authorization: 'Bearer ' + getAccessToken(),'tenant-id': getTenantId()}formLoading.value = trueuploadRef.value!.submit()
}// 文件上传成功的处理
const emits = defineEmits(['success'])
const submitFormSuccess = (response: any) => {if (response.code !== 0) {message.error(response.msg)formLoading.value = falsereturn}// 构建成功提示信息const data = response.datalet text = '上传成功数量:' + data.createUsernames.length + ';'for (let username of data.createUsernames) {text += '< ' + username + ' >'}text += '更新成功数量:' + data.updateUsernames.length + ';'for (const username of data.updateUsernames) {text += '< ' + username + ' >'}text += '更新失败数量:' + Object.keys(data.failureUsernames).length + ';'for (const username in data.failureUsernames) {text += '< ' + username + ': ' + data.failureUsernames[username] + ' >'}message.alert(text)formLoading.value = falsedialogVisible.value = falseemits('success')
}// 文件上传失败的处理
const submitFormError = (): void => {message.error('上传失败,请您重新上传!')formLoading.value = false
}// 重置表单
const resetForm = async (): Promise<void> => {formLoading.value = falseuploadRef.value?.clearFiles()
}// 文件超出数量限制的处理
const handleExceed = (): void => {message.error('最多只能上传一个文件!')
}// 下载模板
const importTemplate = async () => {const res = await AppointmentCommissionApi.importUserTemplate()download.excel(res, '危品预约委托模版.xls')
}
</script>

按钮触发对话框:(以下为抽取实战中的Demo)

<template><el-buttontype="warning"plain@click="handleImport"v-hasPermi="['dangerous:appointment-commission:import']"><Icon icon="ep:upload" class="mr-5px" /> 导入</el-button><!-- 用户导入对话框 --><AppointmentImportForm ref="importFormRef" @success="getList" />
</template><script lang="ts" setup>javascript">
import AppointmentImportForm from '@/components/AppointmentImportForm.vue'
import { ref } from 'vue'
import * as AppointmentCommissionApi from '@/api/dangerous/appointmentcommission'// 引用导入表单组件
const importFormRef = ref()// 触发导入对话框
const handleImport = () => {importFormRef.value.open()
}// 获取列表数据
const getList = async () => {loading.value = truetry {const data = await AppointmentCommissionApi.getAppointmentCommissionPage(queryParams)list.value = data.listtotal.value = data.total} finally {loading.value = false}
}
</script>

以及接口文件:

// 下载危品导入模板
export const importUserTemplate = () => {return request.download({ url: '/dangerous/appointment-commission/get-import-template' })
}

Demo如下:

在这里插入图片描述

3. 彩蛋

由于是Java作为后端,此处补充Java的基本接口:(只提供思路,后端代码给的不全)

对应的上传下载推荐阅读:【Java项目】实战CRUD的功能整理(持续更新)

3.1 下载

其模版接口如下:

java">@GetMapping("/get-import-template")
@Operation(summary = "获得导入危品委托管理的模板")
public void importTemplate(HttpServletResponse response) throws IOException {// 手动创建导出 demoList<AppointmentCommissionImportExcelVO> list = Arrays.asList(AppointmentCommissionImportExcelVO.builder().chineseShipName("xx").shipVoyage("xx").appointmentCompany("xx").appointmentType("装船").appointmentEntryTime(LocalDate.parse("2024-05-29").atStartOfDay()).build(),AppointmentCommissionImportExcelVO.builder().chineseShipName("xx").shipVoyage("xx").appointmentCompany("xx").appointmentType("卸船").appointmentEntryTime(LocalDate.parse("2024-05-29").atStartOfDay()).build());// 输出ExcelUtils.write(response, "危品预约委托管理导入模板.xls", "危品预约", AppointmentCommissionImportExcelVO.class, list);
}

对应的导入类如下:

java">package cn.iocoder.yudao.module.dangerous.controller.admin.appointmentcommission.vo;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;import java.time.LocalDateTime;@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
public class AppointmentCommissionImportExcelVO {@ExcelProperty("中文船名")private String chineseShipName;@ExcelProperty("船舶航次")private String shipVoyage;@ExcelProperty("预约公司")private String appointmentCompany;@ExcelProperty("预约类型")private String appointmentType;@ExcelProperty("预约进场时间")private LocalDateTime appointmentEntryTime;
}

3.2 上传

java">@PostMapping("/import")
@Operation(summary = "导入危品预约委托")
@Parameters({@Parameter(name = "file", description = "Excel 文件", required = true),@Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
})
@PreAuthorize("@ss.hasPermission('dangerous:appointment-commission:import')")
public CommonResult<AppointmentCommissionImportResqVO> importExcel(@RequestParam("file") MultipartFile file,@RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {List<AppointmentCommissionImportExcelVO> list = ExcelUtils.read(file, AppointmentCommissionImportExcelVO.class);return success(appointmentCommissionService.importAppointmentCommissionList(list, updateSupport));
}

对应的实现类如下:

java">@Override
@Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入
public AppointmentCommissionImportResqVO importAppointmentCommissionList(List<AppointmentCommissionImportExcelVO> importAppointmentCommissionDatas, boolean isUpdateSupport) {if(CollUtil.isEmpty(importAppointmentCommissionDatas)){throw exception(APPOINTMENT_COMMISSION_IMPORT_LIST_IS_EMPTY);}AppointmentCommissionImportResqVO respVO = AppointmentCommissionImportResqVO.builder().createChineseShipName(new ArrayList<>()).updateChineseShipName(new ArrayList<>()).failureChineseShipName(new LinkedHashMap<>()).build();importAppointmentCommissionDatas.forEach(importAppointmentCommissionData ->{try {AppointmentCommissionDO insertDo = BeanUtils.toBean(importAppointmentCommissionData, AppointmentCommissionDO.class);String orderNo = redisIdGeneratorService.generatorOrderNo("SQ");insertDo.setAppointmentId(orderNo);insertDo.setAppointmentStatus("未提交");appointmentCommissionMapper.insert(insertDo);respVO.getCreateChineseShipName().add(importAppointmentCommissionData.getChineseShipName());} catch (Exception e) {respVO.getFailureChineseShipName().put(importAppointmentCommissionData.getChineseShipName(), e.getMessage());}});return respVO;
}

对应的类如下:

java">@Schema(description = "危品导入 Response VO")
@Data
@Builder
public class AppointmentCommissionImportResqVO {@Schema(description = "创建成功中文船名", requiredMode = Schema.RequiredMode.REQUIRED)private List<String> createChineseShipName;@Schema(description = "更新成功的中文船名", requiredMode = Schema.RequiredMode.REQUIRED)private List<String> updateChineseShipName;@Schema(description = "导入失败的中文船名,key 为用户名,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)private Map<String, String> failureChineseShipName;
}

http://www.ppmy.cn/ops/45492.html

相关文章

大厂Java面试题:MyBatis的映射器(Mapper.xml)中有哪些常见的元素?

大家好&#xff0c;我是王有志。今天给大家带来的是一道来自京东的 MyBatis 面试题&#xff1a;MyBatis的映射器&#xff08;Mapper.xml&#xff09;中有哪些常见的元素&#xff1f;MyBatis 的映射器中提供了 9 个顶级元素&#xff0c;按照功能可以分为 3 类&#xff1a; SQL …

辅助科技照亮道路,携手共促盲文书写技能新飞跃

在这个科技日新月异的时代&#xff0c;创新的力量正以前所未有的方式融入我们的日常生活&#xff0c;特别是对于视觉障碍群体而言&#xff0c;技术的每一次进步都是通往更加独立生活的桥梁。今天&#xff0c;让我们聚焦于一款名为“蝙蝠避障”的辅助软件&#xff0c;它不仅为盲…

树与图的深度优先遍历

数和图的存储方式与遍历 数和图的存储方式&#xff1a; 一般有两种 树是一种特殊的图&#xff08;即无环联通图&#xff09;。所以下面只讲图。 图的话分为两种&#xff1a;①有向图&#xff08;边是有方向的&#xff1a;a➡️b&#xff09;和 ②无向图&#xff08;边是无方…

Elasticsearch集群许可证过期问题解决方法汇总

最近在使用elasticsearch的过程中,使用elastic-head进行可视化展示集群的状态和信息,从2024年5月18日突然elastic-head无法现在集群的状态界面啦,elasticsearch集群状态是正常,命令如下: curl -X GET "localhost:9200/_cluster/health?pretty" 在google页面上通过…

面试阿里算法岗,艰难走到终面了。。。

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接…

HTML用法介绍

文章目录 一、HTML概念和模版二、常用标签及用法1.p标签2.span标签3.h标签4.hr标签5.img标签6.a标签7.input标签8.table标签 一、HTML概念和模版 HTML的全称为超文本标记语言&#xff0c;它包括一系列标签组成&#xff0c;模版及各部分注释如下&#xff1a; <!--声明文档类…

Postman进阶功能-工作空间

1、工作空间介绍 Postman 的工作空间是一个充满无限可能和创造力的领域。它就像是一个专门为接口测试精心打造的独特空间&#xff0c;在这里&#xff0c;各种元素和功能相互交织、协同作用。工作空间为我们提供了一个集中管理和组织接口相关信息的场所&#xff0c;让我们能够清…

GPT-4O神器来袭!自动生成Figma设计稿,移动端开发瞬间加速!

2024年5月29日- 近日&#xff0c;一款基于GPT-4O技术的创新工具成功实现根据产品需求文档&#xff08;PRD&#xff09;自动生成Figma设计稿的功能&#xff0c;为移动端应用开发者带来革命性的便捷。据悉&#xff0c;该功能主要针对移动端应用进行优化&#xff0c;并支持使用高质…