add 文件上传组件

This commit is contained in:
赵霄
2023-12-06 14:17:01 +08:00
parent a88fd94df6
commit b2c8556bee
13 changed files with 648 additions and 26 deletions
+3
View File
@@ -25,6 +25,8 @@ const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', para
// 通过文件的id获取文件的相应信息
const getFileInfo = (params) => getAction('/sys/oss/file/queryById', params)
// 文件上传
const uploadFile = (params) => postAction('/sys/common/upload', params)
// 获取部门列表数据
const getDepartmentList = (params) => getAction('/sys/sysDepart/queryTreeList', params)
@@ -79,6 +81,7 @@ export {
duplicateCheck,
checkRuleByCode,
getFileInfo,
uploadFile,
getDepartmentList,
getSSOUserInfo,
+14
View File
@@ -12,6 +12,7 @@
.operation-common-btn {
width: 2.19rem;
margin-right: 0.2rem;
.van-button__icon {
line-height: 100%;
margin-right: 0.12rem;
@@ -41,6 +42,15 @@
border-color: @primary-color;
}
/*朴素按钮样式调整*/
/deep/ .van-button--plain.van-button--primary {
color: @primary-color;
}
.van-button--plain {
background-color: #FFFFFF;
}
/*表单card*/
.process-part {
background-color: #FFFFFF;
@@ -72,9 +82,11 @@
/deep/ .vertical-form-item {
flex-direction: column;
.van-field__label {
width: 100%;
}
.van-field__value {
margin-top: 0.24rem;
border-radius: 0.04rem;
@@ -99,11 +111,13 @@
/deep/ .ant-table {
padding: 0.2rem 0.32rem;
color: @font-color;
th {
font-size: 0.26rem;
font-weight: 600;
padding: 0.44rem 0;
}
td {
font-size: 0.24rem;
font-weight: 400;
+19 -1
View File
@@ -35,6 +35,8 @@ module.exports = {
standardName: '标准名称',
serialNumber: '序号',
pleaseEnterRemarks: '请填写备注',
dispatchInformation: '业务分派信息',
clickToUpload: '点击上传',
// 标准法规入库/变更流程
standardEntryOrChange: {
source: '来源',
@@ -110,6 +112,22 @@ module.exports = {
standardConsultation: {
standardText: '标准文本',
relevantDocument: '相关文件',
closingDateForComments: '征求意见结束日期'
closingDateForComments: '征求意见结束日期',
senderType: '下发人员类型',
moduleOwner: '模块负责人',
designEngineer: '设计工程师'
},
uploadFile: {
clickUpload: '点击上传',
viewUploadedFiles: '查看已上传文件',
clickOrDragUpload: '将文件拖到此处或点击上传',
uploadFailed: '上传失败',
cannotPreview: '该文件类型不支持预览',
cannotUploadEmpty: '不能上传空文件',
maxSize: '文件大小限制为500M',
onlyUploadPic: '请上传图片',
pleaseUpload: '请上传',
theFollowingDocuments: 'M以下文件',
file: '文件'
}
}
+9 -1
View File
@@ -3,6 +3,12 @@
<template v-if="fileList && fileList.length > 0">
<div v-for="file in fileList" :key="file.id" class="file-name" @click="handlePreview(file)">{{ file.fileName }}</div>
</template>
<div id="images">
<div class="image" v-viewer="{movable: false}">
<img v-show="image" :src="imageUrl" alt="">
</div>
</div>
</div>
</template>
@@ -32,7 +38,9 @@ export default {
},
data () {
return {
fileList: []
fileList: [],
image: false,
imageUrl: null
}
},
watch: {
+1 -1
View File
@@ -3,7 +3,7 @@
<van-field
v-model="selectedDataNames"
:label="label"
:placeholder="$t('clickSelect') + label"
:placeholder="$t('pleaseSelect') + label"
readonly
rows="1"
autosize
+260
View File
@@ -0,0 +1,260 @@
<template>
<div class="upload-comp">
<div class="upload-box">
<input type="file" class="upload-box-input" @change="handleUpload" />
<van-button type="primary" plain>
<template #icon>
<van-icon class="iconfont" class-prefix="icon" name="shangchuan" />
</template>
{{ $t('clickToUpload') }}
</van-button>
</div>
<!--文件列表-->
<div class="file-list" v-if="fileList && fileList.length > 0">
<div class="file-item" v-for="file in fileList" :key="file.id">
<div class="file-item-name" @click="handlePreview(file)">{{ file.fileName }}</div>
<van-icon name="delete-o" @click="handleDelete(file)" />
</div>
</div>
<div id="images">
<div class="image" v-viewer="{movable: false}">
<img v-show="image" :src="imageUrl" alt="">
</div>
</div>
</div>
</template>
<script>
import { getFileInfo, uploadFile } from '../api/api'
import { previewPdf } from '../utils/previewPdf'
import Vue from 'vue'
import { ACCESS_TOKEN } from '../store/mutation-types'
import { getFileAccessHttpUrl } from '../api/manage'
const FILE_TYPE_ALL = 'all'
const FILE_TYPE_IMG = 'image'
const FILE_TYPE_IMGS = ['jpg', 'jpeg', 'png', 'raw']
const FILE_TYPE_PDF = 'pdf'
// 本系统限制可以上传的文件格式
const CAN_UPLOAD_FILE_TYPE = 'pdf,docx,doc,xlsx,xls,ppt,pptx,rar,zip,jpg,jpeg,png,avi,wmv,mov,rm,mp4,cad'
// 支持预览的文件后缀
const CAN_PREVIEW_FILE_SUFFIX = ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx']
const Base64 = require('js-base64').Base64
export default {
name: 'ZUpload',
props: {
value: {
type: String,
required: false,
default: null
},
// 文件最大大小,默认500MB
fileMaxSize: {
type: Number,
required: false,
default: 500
},
// 可以上传文件的类型
fileType: {
type: String,
required: false,
default: CAN_UPLOAD_FILE_TYPE
}
},
data () {
return {
fileList: [],
image: false,
imageUrl: null
}
},
watch: {
value: {
handler () {
this.fileList = []
if (this.value) {
this.getFileList()
}
},
immediate: true
}
},
methods: {
handleUpload (event) {
const e = window.event || event
const file = e.target.files[0]
/* 进行相关校验 */
const checkResult = this.beforeUpload(file)
if (!checkResult) {
return
}
const formData = new FormData()
formData.append('file', file)
formData.append('biz', 'temp')
uploadFile(formData).then(res => {
if (res.success) {
this.fileList.push(res.result)
this.$emit('change', this.fileList.map(item => item.id).join(','))
} else {
this.$message(res.message)
}
})
},
beforeUpload (file) {
// 校验大小
const fileSize = file.size
if (fileSize === 0) {
this.$message(this.$t('uploadFile.cannotUploadEmpty'))
return false
}
if (this.fileMaxSize && fileSize > 1024 * 1024 * this.fileMaxSize) {
this.$message(this.$t('uploadFile.pleaseUpload') + this.fileMaxSize + this.$t('uploadFile.theFollowingDocuments'))
return false
}
if (fileSize > 1024 * 1024 * 500) {
this.$message(this.$t('uploadFile.maxSize'))
return false
}
// 校验格式
const fileType = file.type
if (this.fileType === FILE_TYPE_ALL) {
return true
}
// 截取文件后缀名
const fileSuffix = (file.name ? file.name.split('.')[file.name.split('.').length - 1] : '').toLowerCase()
if (this.fileType === CAN_UPLOAD_FILE_TYPE && CAN_UPLOAD_FILE_TYPE.split(',').includes(fileSuffix)) {
return true
}
if (this.fileType === FILE_TYPE_IMG && fileType.indexOf('image') < 0) {
this.$message(this.$t('uploadFile.onlyUploadPic'))
return false
}
if (this.fileType === FILE_TYPE_IMG && FILE_TYPE_IMGS.includes(fileSuffix)) {
return true
}
if (this.fileType === FILE_TYPE_IMG && !FILE_TYPE_IMGS.includes(fileSuffix)) {
this.$message(this.$t('uploadFile.pleaseUpload') + FILE_TYPE_IMGS.join('、') + this.$t('uploadFile.file'))
return false
}
if (this.fileType.indexOf(fileSuffix) === -1) {
this.$message(this.$t('uploadFile.pleaseUpload') + `${this.fileType}` + this.$t('uploadFile.file'))
return false
}
return true
},
getFileList () {
this.fileList = []
const fileIdArr = this.value.split(',')
fileIdArr.forEach(async id => {
const fileObj = await this.getFileInfo(id)
if (fileObj.id) {
this.fileList.push(fileObj)
}
})
},
getFileInfo (id) {
let result = {}
return new Promise(resolve => {
getFileInfo({ id }).then(res => {
if (res.success) {
result = res.result
}
}).finally(() => {
resolve(result)
})
})
},
handlePreview (file) {
if (!file || !file.url) {
return
}
// 截取文件后缀名
const fileSuffix = (file.fileName ? file.fileName.split('.')[file.fileName.split('.').length - 1] : '').toLowerCase()
const canPreview = CAN_PREVIEW_FILE_SUFFIX.some(tt => fileSuffix === tt)
// 判断是否为可预览格式的文件
if (!canPreview) {
this.$message(this.$t('uploadFile.cannotPreview'))
return
}
const fileFullUrl = `${window._CONFIG.domianWebSocketURL}/sys/common/view/${file.id}?token=${Vue.ls.get(ACCESS_TOKEN)}&fullfilename=${file.fileName}`
// 图片预览,使用自己添加的组件
if (FILE_TYPE_IMGS.includes(fileSuffix)) {
this.imageUrl = getFileAccessHttpUrl(file.id)
// 获取viewer实例
const viewer = this.$el.querySelector('.image').$viewer
// 调用show方法进行显示预览图
viewer.show()
// this.$refs.imagePreviewModal.open(file)
return
}
// pdf预览
if (FILE_TYPE_PDF.includes(fileSuffix)) {
const url = previewPdf(file.id)
window.open(url)
return
}
// 其余可预览文件仍使用KKFile进行预览
const url = `${window._CONFIG.onlinePreviewDomainURL}?url=${encodeURIComponent(Base64.encode(fileFullUrl))}`
window.open(url)
},
handleDelete (file) {
const index = this.fileList.findIndex(tt => tt.id === file.id)
const fileTempList = JSON.parse(JSON.stringify(this.fileList))
this.fileList.splice(index, 1)
this.$emit('change', this.fileList.map(item => item.id).join(','))
}
},
model: {
event: 'change',
prop: 'value'
}
}
</script>
<style scoped lang="less">
@import '~@/assets/less/common.less';
.upload-comp {
padding: 0.2rem 0.32rem;
}
.upload-box {
position: relative;
width: fit-content;
&-input {
position: absolute;
z-index: 1;
height: 100%;
width: 100%;
opacity: 0;
}
}
.van-button--normal {
font-size: 0.28rem;
}
.file-list {
margin-top: 0.16rem;
}
.file-item {
color: @primary-color;
margin-bottom: 0.16rem;
display: flex;
align-items: baseline;
&-name {
word-break: break-word;
margin-right: 0.16rem;
}
}
.file-item:last-child {
margin-bottom: 0;
}
</style>
+6
View File
@@ -102,3 +102,9 @@ export const EsInitChangeNodes = new EsEnums({
relevantPersonnelWillSign: { text: '相关人员会签', value: 'sid-7BFD2753-B6CD-4637-8D4B-819903511925' },
mainDrafterCopy: { text: '主起草人抄送', value: 'sid-08D0381A-5C20-4708-9D73-C7EB5C51DB02' }
})
// 下发人员类型
export const SenderType = {
moduleOwner: { text: '模块负责人', value: '1' },
designEngineer: { text: '设计工程师', value: '2' }
}
+10
View File
@@ -18,12 +18,22 @@ import './assets/font/iconfont.css'
import { Table } from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
import Viewer from 'v-viewer'
import 'viewerjs/dist/viewer.css'
Vue.config.productionTip = false
Vue.use(Vant)
Vue.use(VueI18n)
Vue.prototype.$message = Toast
Vue.use(Table)
Vue.use(Viewer)
Viewer.setDefaults({
// 需要配置的属性 注意属性并没有引号
title: false,
toolbar: false
})
const i18n = new VueI18n({
locale: 'zh-CN',
@@ -68,7 +68,7 @@
rows="1"
:placeholder="$t('pleaseEnter')+$t('standardConsultation.standardText')"
:border="false">
<file-display :file-ids="basicInfo.standardTextFileId"/>
<file-display :file-ids="basicInfo.standardTextFileId" />
</van-field>
<!--相关文件-->
<van-field v-model="basicInfo.relatedFile"
@@ -79,7 +79,7 @@
rows="1"
:placeholder="$t('pleaseEnter')+$t('standardConsultation.relevantDocument')"
:border="false">
<file-display :file-ids="basicInfo.relatedFile"/>
<file-display :file-ids="basicInfo.relatedFile" />
</van-field>
<!--征求意见结束日期-->
<van-field v-model="basicInfo.consultationDueDate"
@@ -92,6 +92,49 @@
:border="false" />
</van-form>
</div>
<!--业务分派信息-->
<div class="process-part">
<div class="process-part-title">{{ $t('dispatchInformation') }}</div>
<van-form input-align="right">
<!--下发人员类型-->
<picker-dict-field
:label="$t('standardConsultation.senderType')"
:placeholder="$t('pleaseSelect') + $t('standardConsultation.senderType')"
dict-code="sender_type"
v-model="dispatchInfo.userType"
:rules="rules.userType" />
<!--模块负责人-->
<select-user-field v-model="dispatchInfo.moduleOwnerId"
:label="$t('standardConsultation.moduleOwner')"
v-if="dispatchInfo.userType === SenderType.moduleOwner.value" />
<!--设计工程师-->
<select-user-field v-model="dispatchInfo.designEngineerId"
:label="$t('standardConsultation.designEngineer')"
v-if="dispatchInfo.userType === SenderType.designEngineer.value" />
</van-form>
</div>
<!--流程审批信息-->
<div class="process-part">
<div class="process-part-title">{{ $t('processApprovalInfo') }}</div>
<van-form input-align="right" ref="approvalForm">
<!--备注-->
<van-field v-model="approvalInfo.handleText"
:label="$t('remark')"
type="textarea"
autosize
rows="1"
:placeholder="$t('pleaseEnter')+$t('remark')"
:border="false"
input-align="left"
:rules="rules.handleText"
class="vertical-form-item">
</van-field>
<!--附件-->
<z-upload v-model="approvalInfo.handleFile" />
</van-form>
</div>
</template>
</process-common-layout>
</template>
@@ -99,20 +142,29 @@
<script>
import ProcessCommonLayout from '../../../components/ProcessCommonLayout'
import FileDisplay from '../../../components/FileDisplay'
import PickerDictField from '../../../components/PickerDictField'
import { SenderType } from '../../../enums/commonEnums'
import SelectUserField from '../../../components/SelectUserField'
import ZUpload from '../../../components/ZUpload'
export default {
name: 'StandardConsultationProcess',
components: { ProcessCommonLayout, FileDisplay },
components: { ZUpload, SelectUserField, PickerDictField, ProcessCommonLayout, FileDisplay },
data () {
return {
SenderType,
loading: false,
processInfo: {}, // 流程信息数据
businessId: null,
basicInfo: {}, // 业务基本信息数据
dispatchInfo: {}, // 业务分派信息数据
approvalInfo: {} // 流程审批信息数据
approvalInfo: {}, // 流程审批信息数据
rules: {
userType: [{ required: true, message: this.$t('pleaseSelect') + this.$t('standardConsultation.senderType'), trigger: 'onChange' }]
}
}
}
},
methods: {}
}
</script>
@@ -92,6 +92,8 @@
:rules="rules.handleText"
class="vertical-form-item">
</van-field>
<!--附件-->
<z-upload v-model="approvalInfo.handleFile" />
</van-form>
</div>
</template>
@@ -137,10 +139,11 @@ import {
import { FieldType, StandardSource, ProcessKey } from '../../../enums/commonEnums'
import FileDisplay from '../../../components/FileDisplay'
import SelectUser from '../../../components/SelectUser'
import ZUpload from '../../../components/ZUpload'
export default {
name: 'StandardEntryOrChangeProcess',
components: { ProcessCommonLayout, FileDisplay, SelectUser },
components: { ZUpload, ProcessCommonLayout, FileDisplay, SelectUser },
data () {
return {
ProcessKey,