阅读量:0
utils/images/downLoadRemoteFile.js
/** * 获取 blob 实现不跳转下载 * @param {String} url 目标文件地址 * @return {Promise} */ const getBlob = (url) => { return new Promise(resolve => { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'blob'; xhr.onload = () => { if (xhr.status === 200) { resolve(xhr.response); } }; xhr.send(); }); } /** * 保存 * @param {Blob} blob * @param {String} filename 想要保存的文件名称 */ const saveAs = (blob, filename) => { if (window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, filename); } else { let link = document.createElement('a'); let body = document.querySelector('body'); link.href = window.URL.createObjectURL(blob); link.download = filename; // fix Firefox link.style.display = 'none'; body.appendChild(link); link.click(); body.removeChild(link); window.URL.revokeObjectURL(link.href); } } /** * 下载--获取文件 Blob,然后下载重命名 * @param {String} url 目标文件地址 * @param {String} filename 想要保存的文件名称 */ const downLoadRemoteFile = (url, filename) => { getBlob(url).then(blob => { saveAs(blob, filename); }); } export default downLoadRemoteFile;
页面:
<template> <div class="app-container"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px" > <el-form-item label="活动名称" prop="actName"> <el-input v-model="queryParams.actName" placeholder="请输入活动名称" clearable @keyup.enter.native="handleQuery" /> </el-form-item> <el-form-item label="归属区域" prop="officeId"> <!-- <el-input v-model="queryParams.officeId" placeholder="请输入归属区域" clearable @keyup.enter.native="handleQuery" /> --> <TreeSelect class="treeselect-main" v-model="queryParams.officeId" :options="areaBelongOptions" :normalizer="normalizer" placeholder="请输入归属区域" @keyup.enter.native="handleQuery" /> </el-form-item> <el-form-item label="活动创建时间" prop="dateRange"> <el-date-picker :picker-options="pickerOptions" v-model="dateRange" style="width: 300px" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始时间" end-placeholder="结束时间" :default-time="['00:00:00', '23:59:59']" ></el-date-picker> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery" >搜索</el-button > <el-button icon="el-icon-refresh" size="mini" @click="resetQuery" >重置</el-button > </el-form-item> </el-form> <el-row :gutter="10" class="mb8"> <el-col :span="1.5"> <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['edu:activity:add']" >新增</el-button > </el-col> <el-col :span="1.5"> <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['edu:activity:edit']" >修改</el-button > </el-col> <el-col :span="1.5"> <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['edu:activity:remove']" >删除</el-button > </el-col> <!-- <el-col :span="1.5"> <el-button type="warning" plain icon="el-icon-upload2" size="mini" @click="uploadQrcode" v-hasPermi="['edu:activity:export']" >上传二维码</el-button > </el-col> --> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" ></right-toolbar> </el-row> <qrcodeDialog :visible.sync="qrcodeShow" :actList.sync="actList" /> <!-- 表格内容 --> <div class="table"> <el-table border v-loading="loading" :data="activityList" @selection-change="handleSelectionChange" > <el-table-column align="center" label="活动主图" prop="actImg"> <template v-slot="scope"> <el-image style="width: 60px; height: 40px" :src="scope.row.actImg"> </el-image> </template> </el-table-column> <el-table-column show-overflow-tooltip v-for="column in columns" :key="column.prop" :label="column.label" :align="column.align" :prop="column.prop" height="200" > <template v-if="column.slot" v-slot="scope"> <div class="my-table-td-content"> <slot :name="column.prop" :scope="scope.row" :index="scope.$index" > <span>{{ column.slot(scope.row) }}</span> </slot> </div> </template> </el-table-column> <el-table-column align="center" prop="prop" label="报名时间" show-overflow-tooltip > <template v-slot="scope"> <span>{{ scope.row.signStart }}~{{ scope.row.signEnd }}</span> </template> </el-table-column> <el-table-column align="center" label="二维码" prop="actImg"> <template v-slot="scope"> <el-image @click.stop.prevent="clickImage" style="width: 40px; height: 40px" :src="scope.row.actQrcode" :preview-src-list="getPreviewList(scope.row.actQrcode)" > </el-image> </template> </el-table-column> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" > <template slot-scope="scope"> <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['edu:paper:edit']" >修改</el-button > <el-button size="mini" type="text" icon="el-icon-link" @click="uploadQrcode(scope.row)" v-hasPermi="['edu:paper:edit']" >生成二维码</el-button > <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['edu:paper:remove']" >删除</el-button > </template> </el-table-column> </el-table> </div> <div class="code" style="display: none"> <vue-qr v-if="vueQrStatus" ref="qrCode" :text="textValue" :logoSrc="logoPath" :logoScale="40" :size="190" :margin="10" :callback="testCallback" /> </div> <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /> <!-- 添加或修改活动对话框 --> <addEditActivityDialog :visible.sync="addEditVisible" :areaBelongOptions.sync="areaBelongOptions" :isEdit.sync="isEdit" :title.sync="title" :actId.sync="actId" :selectRow.sync="selectRow" @getList="getList()" /> </div> </template> <script> import { listActivity, getActivity, delActivity, saveQrcode, updateActivity, } from "@/api/edu/activity"; import { listDept } from "@/api/system/dept"; import addEditActivityDialog from "./component/addEditActivityDialog.vue"; import qrcodeDialog from "./component/qrcodeDialog.vue"; import logoImg from "@/assets/logo/logo.png"; import VueQr from "vue-qr"; import { uploadFile2 } from "@/utils/upload-file"; import dayjs from "dayjs"; import downLoadRemoteFile from "@/utils/images/downLoadRemoteFile"; export default { name: "Activity", components: { addEditActivityDialog, qrcodeDialog, VueQr, }, // data() { return { imageDisplay: "", //选中得id rowActId: "", // 控制二维码得生成 vueQrStatus: false, // 二维码logo logoPath: logoImg, // 二维码text textValue: "", qrcodeShow: false, actList: [], // 活动id actId: "", // 增加修改-table某一行row的值 selectRow: {}, // 增加修改-弹出层标题 title: "", // 增加修改-编辑状态 isEdit: false, // 归属区域list areaBelongOptions: [], // 增加编辑弹出框展示 addEditVisible: false, // 日期范围 dateRange: [], // 遮罩层 loading: true, // 选中数组 ids: [], // 子表选中数据 checkedEduActivityPaper: [], // 非单个禁用 single: true, // 非多个禁用 multiple: true, // 显示搜索条件 showSearch: true, // 总条数 total: 0, // 活动表格数据 activityList: [], // 活动竞赛试卷表格数据 eduActivityPaperList: [], // 是否显示弹出层 open: false, // 查询参数 queryParams: { pageNum: 1, pageSize: 10, actName: null, officeId: null, }, // 表单参数 form: {}, // 表单校验 rules: {}, columns: [ { label: "活动名称", align: "center", prop: "actName" }, // { label: "活动主图", align: "center", prop: "actImg" }, { label: "活动归属区域", align: "center", prop: "officeName" }, { label: "状态", align: "center", prop: "statusName" }, { label: "竞赛时间", align: "center", prop: "competitionTime" }, // { label: "活动海报", align: "center", prop: "actPoster" }, // { label: "活动简介", align: "center", prop: "actMemo" }, ], pickerOptions: { shortcuts: [ { text: "最近一周", onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); picker.$emit("pick", [start, end]); }, }, { text: "最近一个月", onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); picker.$emit("pick", [start, end]); }, }, ], }, }; }, created() { this.getList(); this.getTreeList(); }, methods: { // 二维码生成得callback testCallback(dataUrl, id) { const file = this.base64ToFile(dataUrl, "image.png"); // console.log(file, "dataUrl"); // const reader = new FileReader(); // reader.onload = function (event) { // document.getElementById("imageDisplay").src = event.target.result; // }; // reader.readAsDataURL(file); // return; console.log(file, "file"); // console.log(dataUrl, id); const TODAY = dayjs().format("YYYY/MM/DD"); uploadFile2(`/quiz/cover/${TODAY}/`, file, (err, data) => { if (err) { this.$modal.msgError(`上传失败:${err}`); } else { const imageUrl = `http://${data.Location}`; console.log(imageUrl, "imageUrl"); const qrcodeUrl = imageUrl; saveQrcode({ actId: this.rowActId, qrcodeUrl: qrcodeUrl }).then( (res) => { if (res.code === 200) { this.$modal.msgSuccess("生成二维码成功"); this.getList(); // this.open = false; } } ); } }); }, // 上传二维码 uploadQrcode(row) { this.rowActId = row.actId; this.textValue = `http://192.168.2.101:9000/?actId=${row.actId}`; this.$nextTick(() => { // 控制二维码得生成; this.vueQrStatus = true; }); // console.log(this.qrcodeUrl, this.rowActId, "this.qrcodeUrl"); }, // 转换base64图片方法 base64ToFile(base64Data, filename) { // 将base64的数据部分提取出来 const parts = base64Data.split(";base64,"); const contentType = parts[0].split(":")[1]; const raw = window.atob(parts[1]); // 将原始数据转换为Uint8Array const rawLength = raw.length; const uInt8Array = new Uint8Array(rawLength); for (let i = 0; i < rawLength; ++i) { uInt8Array[i] = raw.charCodeAt(i); } // 使用Blob对象创建File对象 const blob = new Blob([uInt8Array], { type: contentType }); blob.lastModifiedDate = new Date(); blob.name = filename; return new File([blob], filename, { type: contentType }); }, getTreeList() { listDept().then((response) => { this.areaBelongOptions = this.handleTree(response.data, "deptId"); }); }, /** 查询活动列表 */ getList() { this.loading = true; listActivity(this.addDateRange(this.queryParams, this.dateRange)).then( (response) => { this.activityList = response.rows; this.total = response.total; this.loading = false; } ); }, /** 搜索按钮操作 */ handleQuery() { this.queryParams.pageNum = 1; this.getList(); }, /** 重置按钮操作 */ resetQuery() { // 置空时间区间 this.dateRange = ""; this.resetForm("queryForm"); this.handleQuery(); }, // 多选框选中数据 handleSelectionChange(selection) { this.ids = selection.map((item) => item.actId); this.single = selection.length !== 1; this.multiple = !selection.length; }, /** 新增按钮操作 */ handleAdd() { this.addEditVisible = true; this.title = "添加活动"; // 增加状态 this.isEdit = false; // this.reset(); // this.open = true; }, /** 修改按钮操作 */ handleUpdate(row) { // 打开弹出层 this.addEditVisible = true; // 编辑状态; this.isEdit = true; //传入title this.title = "修改活动"; // 传入活动id this.actId = row.actId; // 获取详情传值子组件 getActivity(row.actId).then((response) => { this.selectRow = response.data; }); }, /** 删除按钮操作 */ handleDelete(row) { const actIds = row.actId; this.$modal .confirm('是否确认删除活动编号为"' + actIds + '"的数据项?') .then(function () { return delActivity(actIds); }) .then(() => { this.getList(); this.$modal.msgSuccess("删除成功"); }) .catch(() => {}); }, /** * @description: 查看-大图预览, 仅预览当前大图 * @param {String} imgUrl 当前图片URL * @return {Array} arr 当前图片为第一个的大图 */ getPreviewList(imgUrl) { return [imgUrl]; }, /** * @description: 预览的图片添加下载按钮 */ clickImage() { this.$nextTick(() => { let wrapper = document.getElementsByClassName( "el-image-viewer__actions__inner" ); if (wrapper.length > 0) { let downImg = document.createElement("i"); downImg.setAttribute("class", "el-icon-download"); downImg.style.cursor = "pointer"; wrapper[0].appendChild(downImg); this.cusClickHandler(downImg); } }); }, /** * @description: 预览的图片给下载按钮添加事件 * @param {HTMLElement} downImg 下载按钮元素 */ cusClickHandler(downImg) { downImg.addEventListener("click", () => { const imgUrl = document.getElementsByClassName( "el-image-viewer__img" )[0].src; const fileName = this.getFileNameFromUrl(imgUrl); downLoadRemoteFile(imgUrl, fileName); }); }, /** * @description: 从 URL 中提取文件名的辅助方法 * @param {String} url 图片的 URL * @return {String} 文件名 */ getFileNameFromUrl(url) { return url.substring(url.lastIndexOf("/") + 1); }, /** 转换部门数据结构 */ normalizer(node) { if (node.children && !node.children.length) { delete node.children; } return { id: node.deptId, label: node.deptName, children: node.children, }; }, }, }; </script> <style lang="scss"> .treeselect-main { width: 250px; line-height: 30px; .vue-treeselect__placeholder { line-height: 28px; } .vue-treeselect__control { height: 28px; } .vue-treeselect__menu { border: none; font-weight: 100; } } .table { .el-table__cell { .cell { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; word-break: break-all; } } } </style>