| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- <template>
- <el-dialog :title="isPreview ? '预览附件' : '上传附件'" center :visible.sync="fileUploadVisible" width="600px"
- :before-close="dialogBeforeClose" append-to-body :close-on-press-escape="false" :close-on-click-modal="false">
- <div class="dialog-box scroll-bar" v-loading="loading">
- <el-upload v-if="!isPreview" ref="upload" action="#" :multiple="true" :limit="5" :http-request="oss_upload"
- :headers="$xtoken" :accept="acceptFile" :auto-upload="false" :on-change="handleChange"
- :on-preview="onFilePreView" :on-remove="handleRemove" :on-success="handleSuccess"
- :before-upload="beforeFilesUpload" :file-list="fileList">
- <span v-if="fileList.length >= 5" class="fontColorC">
- <strong style="color: red;">*</strong>
- (附件上传数量已经达到上限)
- </span>
- <el-button v-if="fileList.length < 5 && isOwner" slot="trigger" size="small"
- type="primary">选取文件</el-button>
- </el-upload>
- <template v-else>
- <div v-if="members && members.length > 0">
- <div class="member-item" v-for="member in members" :key="member.employeeId">
- <div class="employee-name flex-box-ce" style="justify-content: space-between;">
- <span>
- <i class="el-icon-user"></i>
- {{ employeeMap[member.employeeId].name }}
- </span>
-
-
- <span>
- <i class="el-icon-time"></i>
- {{ member.updateTime }}
- </span>
- </div>
- <div class="file-item" v-for="file in member.files" :key="file">
- <el-link type="primary" @click="onFilePreView2(file)">
- <i class="el-icon-document"></i>
- {{ parseUrlFile(file).fileName + parseUrlFile(file).ext }}
- </el-link>
- </div>
- </div>
- </div>
- <div v-else class="fontColorC">暂无附件,去上传</div>
- </template>
- </div>
- <el-dialog title="文件预览" :visible.sync="fileViewerDialogVisible" fullscreen append-to-body @open="onDialogOpen"
- :before-close="fileViewerDialogBeforeClose">
- <previewFile v-if="fileViewerDialogVisible" :file="currentFile" />
- </el-dialog>
- <div slot="footer">
- <el-button type="primary" size="small" @click="comfirm()">确 定</el-button>
- <!-- <el-button size="small" @click="cancel()">取 消</el-button> -->
- </div>
- </el-dialog>
- </template>
- <script>
- import axiosUpload from '@/utils/axiosUpload'
- import uploadOss from '@/components/upload';
- import { mapGetters } from 'vuex';
- import { _debounce } from '@/utils/auth';
- import axios from 'axios' // axios 兼容 IE;如不需要可换回 fetch
- import previewFile from './previewFile.vue';
- import moment from 'moment'
- export default {
- components: {
- uploadOss,
- previewFile
- },
- model: {
- prop: 'fileUploadVisible',
- event: 'close-dialog'
- },
- props: {
- goalId: {
- type: Number | String,
- default: 0
- },
- fileUploadVisible: {
- type: Boolean,
- default: false
- },
- files: {
- type: Array,
- default: () => []
- },
- members: {
- type: Array,
- default: () => []
- },
- isAllowUpload: {
- type: Boolean,
- default: true
- },
- isPreview: {
- type: Boolean,
- default: false
- },
- ownerId: {
- type: String | Number,
- default: ''
- },
- },
- data() {
- return {
- employeeMap: this.$getEmployeeMap(),
- loading: false,
- fileList: [],
- uploadFileList: [],
- imgUrl: '',
- uploadData: {
- ...this.$xtoken
- },
- initFiles: [],
- processLength: 0,
- showProcess: false,
- currentRow: null,
- acceptFile: '.jpg, .jpeg, .png, .gif, .bmp, .pdf, .JPG, .JPEG, .PBG, .GIF, .BMP, .PDF, .doc, .docx, .xls, .XLSX',
- currentFile: null,
- fileViewerDialogVisible: false,
- config: null,
- lastAction: "",
- }
- },
- computed: {
- ...mapGetters(['user_info']),
- isOwner() {
- return this.ownerId == this.user_info.id
- }
- },
- mounted() {
- if (this.fileUploadVisible) {
- this.initFiles = this.files
- this.uploadFileList = this.files
- if (this.files.length > 0) {
- this.fileList = this.files.map(file => ({
- uid: file,
- url: file,
- name: this.parseUrlFile(file).fileName + this.parseUrlFile(file).ext,
- type: this.parseUrlFile(file).ext.replace(".", ""),
- }));
- console.log(this.fileList)
- }
- // this.batchLoad();
- }
- },
- methods: {
- parseUrlFile(url) {
- const [, fileName, ext] = url.match(/\/([^/?#]+)(\.\w+)(?:[?#]|$)/) || [];
- return { fileName, ext };
- },
- onFilePreView(file) {
- this.currentFile = null;
- let index = file.name.indexOf(".");
- let suffix = file.name.substr(index + 1, file.url.length - 1); //文件后缀名
- let imgFiles = ['BMP', 'GIF', 'PNG', 'JPEG', 'JPG', 'bmp', 'gif', 'png', 'jpeg', 'jpg'];
- if (imgFiles.includes(suffix)) {
- this.imgUrl = ''
- this.imgUrl = file.url;
- this.$viewerApi({
- images: [this.imgUrl]
- })
- } else {
- let currentFile = {
- name: file.name,
- url: file.url,
- type: suffix
- }
- this.currentFile = currentFile
- this.fileViewerDialogVisible = true
- // window.open(file.url, '_blank');
- }
- },
- onFilePreView2(fileUrl) {
- this.currentFile = null;
- let fileObj = this.parseUrlFile(fileUrl);
- let type = fileObj.ext.replace(".", "")
- let imgFiles = ['BMP', 'GIF', 'PNG', 'JPEG', 'JPG', 'bmp', 'gif', 'png', 'jpeg', 'jpg'];
- if (imgFiles.includes(type)) {
- this.imgUrl = ''
- this.imgUrl = fileUrl;
- this.$viewerApi({
- images: [this.imgUrl]
- })
- } else {
- let currentFile = {
- name: fileObj.fileName + fileObj.ext,
- url: fileUrl,
- type
- }
- this.currentFile = currentFile;
- this.fileViewerDialogVisible = true;
- }
- },
- handleSuccess: _debounce(function (response, file, fileList) {
- this.uploadFileList = this.fileList.map(item => {
- return item.url;
- });
- if (this.isAllowUpload) {
- this.comfirmUploadFiles(this.uploadFileList)
- } else {
- this.$emit('close-dialog', false)
- this.$emit('confirm', this.uploadFileList)
- }
- // this.isAllowUpload && this.comfirmUploadFiles(this.uploadFileList);
- }),
- /* 新增文件(选择后) */
- handleChange(file, fileList) {
- console.log("文件改变了")
- const $ext_list = ['BMP', 'GIF', 'PNG', 'JPEG', 'JPG', 'bmp', 'gif', 'png', 'jpeg', 'jpg', 'xlsx', 'xls', 'doc', 'docx', 'pdf', 'XLSX', 'XLS', 'DOC', 'DOCX', 'PDF'];
- const isLt2M = file.size / 1024 / 1024 < 5;
- let len = file.name.split('.').length - 1;
- const $ext_name = file.name.split('.')[len];
- let isFile = $ext_list.indexOf($ext_name) != -1;
- if (!isLt2M) {
- return this.$message.error('文件大小不能超过 5MB!');
- }
- if (!isFile) {
- return this.$message.warning('文件格式上传错误,仅支持上传xlsx,xls,doc,docx,pdf)');
- }
-
- this.lastAction = 'hasChange'
- const url = URL.createObjectURL(file.raw)
- file.url = url
- // this.fileList = fileList
- // this.uploadFileList = this.fileList.map(item => {
- // return item.url;
- // });
- },
- handleRemove(file, fileList) {
- this.lastAction = 'hasChange'
- URL.revokeObjectURL(file.url) // 释放内存
- this.fileList = fileList; // 用来显示的文件列表
- this.uploadFileList = this.fileList.map(item => {
- return item.url;
- });
- // this.isAllowUpload && this.comfirmUploadFiles(this.uploadFileList);
- },
- beforeFilesUpload(file) {
- const $ext_list = ['BMP', 'GIF', 'PNG', 'JPEG', 'JPG', 'bmp', 'gif', 'png', 'jpeg', 'jpg', 'xlsx', 'xls', 'doc', 'docx', 'pdf', 'XLSX', 'XLS', 'DOC', 'DOCX', 'PDF'];
- const isLt2M = file.size / 1024 / 1024 < 5;
- let len = file.name.split('.').length - 1;
- const $ext_name = file.name.split('.')[len];
- let isFile = $ext_list.indexOf($ext_name) != -1;
- if (!isLt2M) {
- this.$message.error('文件大小不能超过 5MB!');
- }
- if (!isFile) {
- this.$message.warning('文件格式上传错误,仅支持上传xlsx,xls,doc,docx,pdf)');
- }
- return isFile && isLt2M;
- },
- // 手动上传
- submitUpload() {
- this.$refs.upload.submit();
- },
- get_sign(callback) {
- // 测试添加 'https://intesys.cms.g107.com'
- axiosUpload('get', 'https://intesys.cms.g107.com/integral.php/Api/get_signature').then(res => {
- this.config = res.data.data
- callback()
- })
- },
- beforeFilesUpload(file) {
- const $ext_list = ['BMP', 'GIF', 'PNG', 'JPEG', 'JPG', 'bmp', 'gif', 'png', 'jpeg', 'jpg', 'xlsx', 'xls', 'doc', 'docx', 'pdf', 'XLSX', 'XLS', 'DOC', 'DOCX', 'PDF'];
- const isLt2M = file.size / 1024 / 1024 < 5;
- let len = file.name.split('.').length - 1;
- const $ext_name = file.name.split('.')[len];
- let isFile = $ext_list.indexOf($ext_name) != -1;
- if (!isLt2M) {
- this.$message.error('文件大小不能超过 5MB!');
- }
- if (!isFile) {
- this.$message.warning('文件格式上传错误,仅支持上传xlsx,xls,doc,docx,pdf)');
- }
- return isFile && isLt2M;
- },
- oss_upload(upload_obj) {
- this.get_sign(() => {
- // this.beforeUpload_all(upload_obj.file).then(res=>{
- // this.upload(res)
- // });
- this.upload(upload_obj.file)
- })
- },
- upload(item) {
- let self = this
- const photo = item // 获取图片对象
- const photoName = item.name // 原图片的名称
- const url = 'https://integralsys.oss-cn-shenzhen.aliyuncs.com'
- let date = moment().format('YYYY/MM/DD')
- let param = new FormData()
- let site_id
- if (this.coursePath) {
- site_id = this.coursePath
- } else {
- site_id = this.$getCache('site_info').id
- }
- let randomStr = this.random_string(32)
- let key = 'intesys/' + site_id + '/' + date + '/' + randomStr + '/' + photoName
- // let loadingInstance = Loading.service({});
- param.append('Filename', photoName)
- param.append('key', key)
- param.append('policy', this.config.policy)
- param.append('OSSAccessKeyId', this.config.accessid)
- param.append('success_action_status', '200') // 不要问为什么,照做
- param.append('callback', this.config.callback)
- param.append('signature', this.config.signature)
- param.append('file', photo) // 这个**切记**一定要放到最后去 append ,不然阿里云会一直报 key 的错误
- axios.post(url, param, {
- headers: {
- 'Content-Type': 'multipart/form-data'
- }
- }).then(response => {
- if (response.data.Status == 'Ok') {
- self.fileList.push({
- name: randomStr + photoName, url: 'https://integralsys.oss-cn-shenzhen.aliyuncs.com/' + key, name: item.name, response: {
- url: 'https://integralsys.oss-cn-shenzhen.aliyuncs.com/' + key
- }
- })
- self.handleSuccess({ status: 1, url: 'https://integralsys.oss-cn-shenzhen.aliyuncs.com/' + key, file_name: randomStr + photoName }, item, self.fileList)
- }
- })
-
- this.showProcess = false
- },
- random_string(len) {
- len = len || 32
- var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
- var maxPos = chars.length
- var pwd = ''
- for (let i = 0; i < len; i++) {
- pwd += chars.charAt(Math.floor(Math.random() * maxPos))
- }
- return pwd
- },
- comfirmUploadFiles(files) {
- let url = `/okr/og/goals/files/${this.user_info.site_id}`
- let data = {
- goalId: this.goalId,
- files
- }
- this.$http.post(url, data).then(res => {
- let { code } = res
- if (code !== 1)
- return this.$message.error(res.message || "上传附件失败")
- else {
- this.$emit('close-dialog', false)
- this.$emit('confirm', this.uploadFileList)
- }
- this.currentRow = res.data
- })
- },
- cancel() {
- this.$emit('close-dialog', false)
- },
- comfirm() {
- console.log(this.fileList)
- // if (this.lastAction === 'hasChange') {
- // this.submitUpload()
- // // if (this.isAllowUpload) {
- // // this.comfirmUploadFiles(this.uploadFileList)
- // // } else {
- // // this.$emit('close-dialog', false)
- // // this.$emit('confirm', this.uploadFileList)
- // // }
- // }
- // else
- // this.$emit('close-dialog', false)
- },
- dialogBeforeClose() {
- this.$emit('close-dialog', false)
- },
- /* 主函数:接收 url 数组 → 批量回显 */
- async batchLoad() {
- const urlArr = this.files || []; // 已成功上传的文件列表
- if (!urlArr.length) return
- /* 并发下载并转成 File */
- const taskList = urlArr.map(u => this.url2File(u))
- try {
- const files = await Promise.all(taskList)
- this.fileList = files // 一次性塞给 el-upload
- // this.$message.success(`已回显 ${files.length} 个文件`)
- } catch (e) {
- this.$message.error('下载失败:' + e.message)
- }
- },
- /* 单条 url → File → el-upload 对象 */
- async url2File(url) {
- // this.loading = true
- // 1. 下载成 blob(axios 写法,IE 可用)
- const { data: blob, headers } = await axios.get(url, {
- responseType: 'blob'
- })
- // 2. 从 Content-Disposition 或 url 取文件名
- let fileName = 'unknown'
- const disposition = headers['content-disposition']
- if (disposition && disposition.includes('filename=')) {
- fileName = decodeURIComponent(disposition.split('filename=')[1].replace(/"/g, ''))
- } else {
- const temp = url.split('/').pop().split('?')[0]
- fileName = decodeURIComponent(temp)
- }
- // 3. 生成 File 对象
- const file = new File([blob], fileName, { type: blob.type })
- // this.loading = false
- // 4. 返回 el-upload 需要的格式
- return {
- name: fileName,
- url: url, // 预览图
- raw: file, // File 对象
- status: 'success'
- }
- },
- /* 拦截浏览器返回键 */
- blockPopstate(e) {
- // 阻止默认返回行为
- e.preventDefault();
- // 可以选择关闭 dialog
- this.fileViewerDialogBeforeClose();
- // 重新插入一条记录,防止再次返回
- history.pushState(null, null, location.href);
- },
- fileViewerDialogBeforeClose() {
- this.currentFile = null
- this.fileViewerDialogVisible = false
- },
- /* 开启 dialog 时:禁用返回键 */
- onDialogOpen() {
- // 立即往 history 里插一条空记录,拦截返回
- history.pushState(null, null, location.href);
- // 监听 popstate
- window.addEventListener('popstate', this.blockPopstate, false);
- },
- }
- }
- </script>
- <style scoped lang="scss">
- .dialog-box {
- width: 100%;
- max-height: 600px;
- overflow-y: auto;
- }
- .member-item {
- padding: 10px;
- box-sizing: border-box;
- border-bottom: 1px solid #f1f1f1;
- .employee-name {
- font-size: 14px;
- margin-bottom: 10px;
- }
- .file-item {
- margin-bottom: 10px;
- }
- }
- </style>
|