@@ -1715,6 +1715,7 @@ select parentid from [dbo].[Acc_DormitoryBuild] where BuildType='5' and (student | |||
{ | |||
var parentEntity = db.FindEntity<Acc_DormitoryBuildEntity>(ParentID); | |||
entity.Create(); | |||
entity.DNo = entity.Name.Substring(0,entity.Name.Length-1); | |||
entity.ApartmentId = parentEntity.ApartmentId; | |||
entity.UnitId = parentEntity.UnitId; | |||
entity.FloorId = parentEntity.FloorId; | |||
@@ -2115,7 +2116,7 @@ where ID='{ParentID}' | |||
var dormitoryCode = dr["寝室编号"].ToString().Trim(); | |||
var dormitory = dormitoryBuildList.Where(x => x.Name == dormitoryName && x.DNo == dormitoryCode && x.BuildType == "4" && x.ParentID == floor.ID) | |||
.FirstOrDefault(); | |||
if (dormitory == null) | |||
if (dormitory == null && !string.IsNullOrEmpty(dormitoryName) && !string.IsNullOrEmpty(dormitoryCode)) | |||
{ | |||
//添加 | |||
dormitory = new Acc_DormitoryBuildEntity(); | |||
@@ -2146,9 +2147,9 @@ where ID='{ParentID}' | |||
//床位 | |||
var bedName = dr["床位"].ToString().Trim(); | |||
var bedCode = bedName.Replace("床", "").Replace("号", ""); | |||
var bed = dormitoryBuildList.Where(x => x.Name == bedName && x.DNo == bedCode && x.BuildType == "5" && x.ParentID == dormitory.ID) | |||
var bed = dormitoryBuildList.Where(x => x.Name == bedName && x.DNo == bedCode && x.BuildType == "5" && x.ParentID == dormitory?.ID) | |||
.FirstOrDefault(); | |||
if (bed == null) | |||
if (bed == null && !string.IsNullOrEmpty(bedName) && !string.IsNullOrEmpty(bedCode)) | |||
{ | |||
bed = new Acc_DormitoryBuildEntity(); | |||
bed.Create(); | |||
@@ -249,7 +249,7 @@ export default { | |||
} | |||
for (const item of val) { | |||
if (item.uid) { | |||
if (item.uid || item.folderId) { | |||
// uploadUid = item.uid | |||
continue | |||
} | |||
@@ -131,6 +131,7 @@ | |||
v-else-if="item.type === 'upload'" | |||
@input="setValue(item.__valuePath__, $event)" | |||
:value="getValue(item.__valuePath__)" | |||
:labelId="item.id" | |||
:required="Boolean(item.verify)" | |||
:readonly="!isEdit(item)" | |||
:title="item.title" | |||
@@ -1,213 +1,303 @@ | |||
<template> | |||
<view> | |||
<view class="cu-form-group" style="border-bottom: none; padding-bottom: 0;"> | |||
<view class="title"> | |||
<text v-if="required" class="lr-required">*</text> | |||
{{ title || '' }} | |||
</view> | |||
</view> | |||
<view class="cu-form-group" style="border-top: none;"> | |||
<view class="grid col-4 grid-square flex-sub"> | |||
<view v-for="(file, index) in value" :key="index" class="bg-img" style="position: relative;"> | |||
<view v-if="file.noUpdated" class="mask"></view> | |||
<image | |||
v-if="isImgFile(file.type)" | |||
@click="fileClick(index)" | |||
:src="file.path?file.path:file" | |||
:webp="file.type === 'webp'" | |||
mode="aspectFill" | |||
></image> | |||
<view v-else-if="isDocFile(file.type)" @click="fileClick(index)" class="file-icon solids"> | |||
<l-icon type="text" /> | |||
</view> | |||
<view v-else class="file-icon solids" @click="fileClick(index)"><l-icon type="text" /></view> | |||
<view v-if="!readonly" @click.stop="delFile(index,file.uid)" class="cu-tag bg-red" style="height: 24px; width: 24px;"> | |||
<l-icon type="close" color="white" style="width: 18px; height: 24px; font-size: 24px;" /> | |||
</view> | |||
<view class="fileName"> | |||
<text>{{file.name}}</text> | |||
</view> | |||
</view> | |||
<view v-if="!readonly && value.length < Number(number)" @click="chooseFile" class="solids"> | |||
<l-icon type="file" /> | |||
</view> | |||
</view> | |||
</view> | |||
</view> | |||
<view> | |||
<view class="cu-form-group" style="border-bottom: none; padding-bottom: 0;"> | |||
<view class="title"> | |||
<text v-if="required" class="lr-required">*</text> | |||
{{ title || '' }} | |||
</view> | |||
<!-- #ifdef APP-PLUS --> | |||
<view v-if="formData.folderId&&!readonly && value.length < Number(number)" style="display: inline-block;padding-left: 20px;"> | |||
<lsjupload ref="lsjUpload" height="32px" width="80px" :option="{ | |||
url:API+'/learun/adms/annexes/wxupload',formData | |||
}" :instantly="false" :count="1" :size="100" @change="chooseChange"> | |||
</lsjupload> | |||
</view> | |||
<!-- #endif --> | |||
</view> | |||
<view class="cu-form-group" style="border-top: none;"> | |||
<view class="grid col-4 grid-square flex-sub"> | |||
<view v-for="(file, index) in value" :key="index" class="bg-img" style="position: relative;"> | |||
<view v-if="file.noUpdated" class="mask"></view> | |||
<image v-if="isImgFile(file.type)" @click="fileClick(index)" :src="file.path?file.path:file" | |||
:webp="file.type === 'webp'" mode="aspectFill"></image> | |||
<view v-else-if="isDocFile(file.type)" @click="fileClick(index)" class="file-icon solids"> | |||
<l-icon type="text" /> | |||
</view> | |||
<view v-else class="file-icon solids" @click="fileClick(index)"> | |||
<l-icon type="text" /> | |||
</view> | |||
<view v-if="!readonly" @click.stop="delFile(index,file.uid)" class="cu-tag bg-red" | |||
style="height: 24px; width: 24px;"> | |||
<l-icon type="close" color="white" style="width: 18px; height: 24px; font-size: 24px;" /> | |||
</view> | |||
<view class="fileName"> | |||
<text>{{file.name}}</text> | |||
</view> | |||
</view> | |||
<!-- #ifndef APP-PLUS --> | |||
<view v-if="!readonly && value.length < Number(number)" @click="chooseFile" class="solids"> | |||
<l-icon type="file" /> | |||
</view> | |||
<!-- #endif --> | |||
</view> | |||
</view> | |||
</view> | |||
</template> | |||
<script> | |||
export default { | |||
name: 'l-upload-file', | |||
props: { | |||
number: { default: 1 }, | |||
readonly: {}, | |||
value: { default: () => [] }, | |||
title: {}, | |||
required: {} | |||
}, | |||
methods: { | |||
getFileExt(path) { | |||
return /\.(\w{2,5})$/.exec(path)[1] || null | |||
}, | |||
isImgFile(type) { | |||
const typeString = (type || '').toLowerCase() | |||
return ['jpg','image/jpg','jpeg','image/jpeg', 'png', 'image/png','gif', 'image/gif','bmp', 'image/bmp','webp', 'image/webp','image'].includes(typeString) | |||
}, | |||
isDocFile(type) { | |||
const typeString = (type || '').toLowerCase() | |||
return ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'].includes(typeString) | |||
}, | |||
async delFile(index,fileId) { | |||
if (!(await this.CONFIRM('删除文件', '确定要删除该文件吗?', true))) { | |||
return | |||
} | |||
const newList = JSON.parse(JSON.stringify(this.value)) | |||
newList.splice(index, 1) | |||
this.$emit('input', newList) | |||
this.$emit('change') | |||
this.$emit('del') | |||
//物理删除 | |||
this.DELETE_FILE(fileId); | |||
}, | |||
chooseFile() { | |||
// #ifdef MP-DINGTALK | |||
// dd.chooseImage({ | |||
// count: Number(this.number), | |||
// success: ({ filePaths }) => { | |||
// if (filePaths) { | |||
// const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | |||
// filePaths.map(t => ({ path: t, type: this.getFileExt(t) })) | |||
// ) | |||
// this.$emit('input', newList) | |||
// this.$emit('change', newList) | |||
// this.$emit('add') | |||
// } | |||
// } | |||
// }) | |||
// #endif | |||
// #ifndef MP-DINGTALK | |||
// uni.chooseFile({ | |||
// count: Number(this.number), | |||
// sizeType: ['original', 'compressed'], | |||
// sourceType: ['album', 'camera'], | |||
// success: ({ tempFilePaths }) => { | |||
// const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | |||
// tempFilePaths//.map(t => ({ path: t, type: this.getFileExt(t) })) | |||
// ) | |||
// this.$emit('input', newList) | |||
// this.$emit('change', newList) | |||
// this.$emit('add') | |||
// } | |||
// }) | |||
uni.chooseFile({ | |||
count: Number(this.number), | |||
sizeType: ['original', 'compressed'], | |||
sourceType: ['album', 'camera'], | |||
success: ({ tempFilePaths,tempFiles }) => { | |||
const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | |||
// tempFilePaths//.map(t => ({ path: t, type: this.getFileExt(t) })) | |||
tempFilePaths.map((t,i) => ({ path: t, type: tempFiles[i].type, size:tempFiles[i].size, name:tempFiles[i].name, noUpdated:true} )) | |||
) | |||
this.$emit('input', newList) | |||
this.$emit('change', newList) | |||
this.$emit('add') | |||
} | |||
}) | |||
// #endif | |||
}, | |||
async fileClick(index) { | |||
// if(typeof this.value[index] == "string"){ | |||
// uni.previewImage({ urls: this.value.filter(item=>typeof this.value[index] == "string"), current: this.value[index] }) | |||
// return | |||
// } | |||
const { path, type, uid, size = 0 } = this.value[index] | |||
if (this.isImgFile(type)) { | |||
uni.previewImage({ urls: [path], current: path }) | |||
}else{ | |||
uni.openDocument({ filePath: path, fileType: type }) | |||
} | |||
// if (this.isImgFile(type)) { | |||
// uni.previewImage({ urls: [path], current: path }) | |||
// } else if (this.isDocFile(type)) { | |||
// // #ifndef H5 || MP-DINGTALK | |||
// if (size >= 50 * 1024 * 1024) { | |||
// this.TOAST('小程序端无法下载超过50MB的文件,此文件大小为${size}KB,超过限制') | |||
// return | |||
// } | |||
// // #endif | |||
// // #ifndef MP-DINGTALK | |||
// const tempFilePath = await this.HTTP_DOWNLOAD(uid) | |||
// uni.openDocument({ filePath: tempFilePath, fileType: type }) | |||
// // #endif | |||
// // #ifdef MP-DINGTALK | |||
// this.TOAST('钉钉小程序只支持查看图片文件') | |||
// // #endif | |||
// } else { | |||
// // #ifndef MP-DINGTALK | |||
// this.TOAST('小程序端只支持打开图片和文档(word、pdf等)文件') | |||
// // #endif | |||
// // #ifdef MP-DINGTALK | |||
// this.TOAST('钉钉小程序只支持查看图片文件') | |||
// // #endif | |||
// // #ifdef APP-VUE | |||
// const tempFilePath = await this.HTTP_DOWNLOAD(uid) | |||
// uni.openDocument({ filePath: tempFilePath, fileType: type }) | |||
// // #endif | |||
// // #ifdef H5 | |||
// await this.HTTP_DOWNLOAD(uid) | |||
// // #endif | |||
// } | |||
} | |||
} | |||
} | |||
import lsjupload from '@/components/lsj-upload/lsj-upload.vue' | |||
export default { | |||
name: 'l-upload-file', | |||
components: { | |||
lsjupload, | |||
}, | |||
props: { | |||
number: { | |||
default: 1 | |||
}, | |||
labelId: { | |||
default: '' | |||
}, | |||
tableName: { | |||
default: '' | |||
}, | |||
fieldName: { | |||
default: '' | |||
}, | |||
readonly: {}, | |||
value: { | |||
default: () => [] | |||
}, | |||
title: {}, | |||
required: {} | |||
}, | |||
data() { | |||
return { | |||
formData: {} | |||
} | |||
}, | |||
created() { | |||
// #ifdef APP-PLUS | |||
if(this.labelId){ | |||
var guid = undefined | |||
// 先生成一个guid | |||
guid = this.newguid(); | |||
// 取出当前列对应的labelId | |||
var labeId = this.labelId | |||
// 从缓存取出当前审批流程所有的guid | |||
var guids = JSON.parse(uni.getStorageSync('guids')) | |||
if (guids && JSON.stringify(guids) !== '{}' && guids[labeId]) { | |||
guid = guids[labeId] | |||
} | |||
this.formData.loginMark=this.getLoginMark(), | |||
this.formData.token=this.GET_GLOBAL('token') | |||
this.formData['folderId'] = guid | |||
}else{ | |||
if(!this.tableName||!this.fieldName)return | |||
var uploadUid = '', | |||
tableName=this.tableName, | |||
fieldName=this.fieldName | |||
let folderIds = uni.getStorageSync('folderIds'); | |||
if(folderIds){ | |||
folderIds = JSON.parse(folderIds) | |||
if(folderIds[tableName]&&folderIds[tableName][fieldName]){ | |||
uploadUid = folderIds[tableName][fieldName] | |||
} | |||
} | |||
if(!uploadUid){ | |||
uploadUid = this.newguid() | |||
} | |||
this.formData.loginMark=this.getLoginMark(), | |||
this.formData.token=this.GET_GLOBAL('token') | |||
this.formData['folderId'] = uploadUid | |||
} | |||
// #endif | |||
}, | |||
methods: { | |||
async chooseChange(files) { | |||
this.LOADING('正在提交...') | |||
await this.$refs.lsjUpload.upload() | |||
this.HIDE_LOADING() | |||
let array = Array.from(files); | |||
if (array.length) { | |||
await this.$refs.lsjUpload.clear() | |||
} | |||
let tempFilePaths = [], | |||
tempFiles = []; | |||
array.forEach(item => { | |||
tempFilePaths.push(item[1].path) | |||
tempFiles.push({ | |||
name: item[1].name, | |||
size: item[1].size, | |||
folderId: this.formData.folderId | |||
}) | |||
}) | |||
if (!tempFilePaths.length) { | |||
return | |||
} | |||
// let fileName = tempFiles[tempFiles.length] | |||
// let uploadRes = await this.$refs.lsjUpload.upload(tempFiles[i].name) | |||
// if(!uploadRes){ | |||
// this.TOAST('上传失败!') | |||
// return | |||
// } | |||
const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | |||
tempFilePaths.map((t, i) => ({ | |||
path: t, | |||
type: tempFiles[i].type, | |||
size: tempFiles[i].size, | |||
name: tempFiles[i].name, | |||
folderId:tempFiles[i].folderId, | |||
noUpdated: false | |||
})) | |||
) | |||
this.$emit('input', newList) | |||
this.$emit('change', newList) | |||
this.$emit('add') | |||
}, | |||
getFileExt(path) { | |||
return /\.(\w{2,5})$/.exec(path)[1] || null | |||
}, | |||
isImgFile(type) { | |||
const typeString = (type || '').toLowerCase() | |||
return ['jpg', 'image/jpg', 'jpeg', 'image/jpeg', 'png', 'image/png', 'gif', 'image/gif', 'bmp', | |||
'image/bmp', 'webp', 'image/webp', 'image' | |||
].includes(typeString) | |||
}, | |||
isDocFile(type) { | |||
const typeString = (type || '').toLowerCase() | |||
return ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'].includes(typeString) | |||
}, | |||
async delFile(index, fileId) { | |||
if (!(await this.CONFIRM('删除文件', '确定要删除该文件吗?', true))) { | |||
return | |||
} | |||
const newList = JSON.parse(JSON.stringify(this.value)) | |||
newList.splice(index, 1) | |||
this.$emit('input', newList) | |||
this.$emit('change') | |||
this.$emit('del') | |||
//物理删除 | |||
this.DELETE_FILE(fileId); | |||
}, | |||
chooseFile() { | |||
// #ifdef APP-PLUS | |||
return | |||
// #endif | |||
uni.chooseFile({ | |||
count: Number(this.number), | |||
sizeType: ['original', 'compressed'], | |||
sourceType: ['album', 'camera'], | |||
success: ({ | |||
tempFilePaths, | |||
tempFiles | |||
}) => { | |||
const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | |||
tempFilePaths.map((t, i) => ({ | |||
path: t, | |||
type: tempFiles[i].type, | |||
size: tempFiles[i].size, | |||
name: tempFiles[i].name, | |||
noUpdated: false | |||
})) | |||
) | |||
this.$emit('input', newList) | |||
this.$emit('change', newList) | |||
this.$emit('add') | |||
} | |||
}) | |||
}, | |||
async fileClick(index) { | |||
const { | |||
path, | |||
type, | |||
uid, | |||
size = 0 | |||
} = this.value[index] | |||
if (this.isImgFile(type)) { | |||
uni.previewImage({ | |||
urls: [path], | |||
current: path | |||
}) | |||
} else { | |||
// #ifdef APP-PLUS | |||
uni.downloadFile({ | |||
url: path, //仅为示例,并非真实的资源 | |||
success: (res) => { | |||
if (res.statusCode === 200) { | |||
uni.openDocument({ | |||
filePath: res.tempFilePath, | |||
fileType: type | |||
}) | |||
}else{ | |||
this.TOAST('下载失败!') | |||
} | |||
} | |||
}); | |||
return | |||
// #endif | |||
uni.openDocument({ | |||
filePath: path, | |||
fileType: type | |||
}) | |||
} | |||
}, | |||
newguid() { | |||
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) { | |||
var r = Math.random() * 16 | 0, | |||
v = c == 'x' ? r : (r & 0x3 | 0x8); | |||
return v.toString(16); | |||
}); | |||
}, | |||
} | |||
} | |||
</script> | |||
<style lang="less" scoped> | |||
.file-icon { | |||
line-height: 100%; | |||
position: static; | |||
} | |||
.fileName{ | |||
padding: 2px 2px; | |||
margin-bottom: 2px; | |||
text-align: center; | |||
position: absolute; | |||
bottom: 0px; | |||
width: 100%; | |||
background: rgba(0,0,0,0.2); | |||
color: #fff; | |||
font-size: 12px; | |||
text-overflow: ellipsis; | |||
overflow: hidden; | |||
white-space: nowrap; | |||
} | |||
.mask{ | |||
position: absolute; | |||
top: 0;left: 0; | |||
width: 100%; | |||
height: 100%; | |||
// background: rgba(255,252,153,0.2); | |||
background: rgba(0,0,0,0.7); | |||
z-index: 100; | |||
pointer-events: none; | |||
} | |||
.file-icon { | |||
line-height: 100%; | |||
position: static; | |||
} | |||
.fileName { | |||
padding: 2px 2px; | |||
margin-bottom: 2px; | |||
text-align: center; | |||
position: absolute; | |||
bottom: 0px; | |||
width: 100%; | |||
background: rgba(0, 0, 0, 0.2); | |||
color: #fff; | |||
font-size: 12px; | |||
text-overflow: ellipsis; | |||
overflow: hidden; | |||
white-space: nowrap; | |||
} | |||
.mask { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
// background: rgba(255,252,153,0.2); | |||
background: rgba(0, 0, 0, 0.7); | |||
z-index: 100; | |||
pointer-events: none; | |||
} | |||
</style> |
@@ -0,0 +1,392 @@ | |||
export class LsjFile { | |||
constructor(data) { | |||
this.dom = null; | |||
// files.type = waiting(等待上传)|| loading(上传中)|| success(成功) || fail(失败) | |||
this.files = new Map(); | |||
this.debug = data.debug || false; | |||
this.id = data.id; | |||
this.width = data.width; | |||
this.height = data.height; | |||
this.option = data.option; | |||
this.instantly = data.instantly; | |||
this.prohibited = data.prohibited; | |||
this.onchange = data.onchange; | |||
this.onprogress = data.onprogress; | |||
this.uploadHandle = this._uploadHandle; | |||
// #ifdef MP-WEIXIN | |||
this.uploadHandle = this._uploadHandleWX; | |||
// #endif | |||
} | |||
/** | |||
* 创建File节点 | |||
* @param {string}path webview地址 | |||
*/ | |||
create(path) { | |||
if (!this.dom) { | |||
// #ifdef H5 | |||
let dom = document.createElement('input'); | |||
dom.type = 'file' | |||
dom.value = '' | |||
dom.style.height = this.height | |||
dom.style.width = this.width | |||
dom.style.position = 'absolute' | |||
dom.style.top = 0 | |||
dom.style.left = 0 | |||
dom.style.right = 0 | |||
dom.style.bottom = 0 | |||
dom.style.opacity = 0 | |||
dom.style.zIndex = 999 | |||
dom.accept = this.prohibited.accept; | |||
if (this.prohibited.count > 1) { | |||
dom.multiple = 'multiple'; | |||
} | |||
dom.onchange = event => { | |||
for (let file of event.target.files) { | |||
this.addFile(file); | |||
} | |||
this.dom.value = ''; | |||
}; | |||
this.dom = dom; | |||
// #endif | |||
// #ifdef APP-PLUS | |||
let styles = { | |||
top: '-100px', | |||
left: 0, | |||
width: '1px', | |||
height: '1px', | |||
background: 'transparent' | |||
}; | |||
let extras = { | |||
debug: this.debug, | |||
instantly: this.instantly, | |||
prohibited: this.prohibited, | |||
} | |||
this.dom = plus.webview.create(path, this.id, styles,extras); | |||
this.setData(this.option); | |||
this._overrideUrlLoading(); | |||
// #endif | |||
return this.dom; | |||
} | |||
} | |||
copyObject(obj) { | |||
if (typeof obj !== "undefined") { | |||
return JSON.parse(JSON.stringify(obj)); | |||
} else { | |||
return obj; | |||
} | |||
} | |||
/** | |||
* 自动根据字符串路径设置对象中的值 支持.和[] | |||
* @param {Object} dataObj 数据源 | |||
* @param {String} name 支持a.b 和 a[b] | |||
* @param {String} value 值 | |||
* setValue(dataObj, name, value); | |||
*/ | |||
setValue(dataObj, name, value) { | |||
// 通过正则表达式 查找路径数据 | |||
let dataValue; | |||
if (typeof value === "object") { | |||
dataValue = this.copyObject(value); | |||
} else { | |||
dataValue = value; | |||
} | |||
let regExp = new RegExp("([\\w$]+)|\\[(:\\d)\\]", "g"); | |||
const patten = name.match(regExp); | |||
// 遍历路径 逐级查找 最后一级用于直接赋值 | |||
for (let i = 0; i < patten.length - 1; i++) { | |||
let keyName = patten[i]; | |||
if (typeof dataObj[keyName] !== "object") dataObj[keyName] = {}; | |||
dataObj = dataObj[keyName]; | |||
} | |||
// 最后一级 | |||
dataObj[patten[patten.length - 1]] = dataValue; | |||
this.debug&&console.log('参数更新后',JSON.stringify(this.option)); | |||
} | |||
/** | |||
* 设置上传参数 | |||
* @param {object|string}name 上传参数,支持a.b 和 a[b] | |||
*/ | |||
setData() { | |||
let [name,value = ''] = arguments; | |||
if (typeof name === 'object') { | |||
Object.assign(this.option,name); | |||
} | |||
else { | |||
this.setValue(this.option,name,value); | |||
} | |||
this.debug&&console.log(JSON.stringify(this.option)); | |||
// #ifdef APP-PLUS | |||
this.dom.evalJS(`vm.setData('${JSON.stringify(this.option)}')`); | |||
// #endif | |||
} | |||
/** | |||
* 上传 | |||
* @param {string}name 文件名称 | |||
*/ | |||
async upload(name='') { | |||
if (!this.option.url) { | |||
throw Error('未设置上传地址'); | |||
} | |||
// #ifndef APP-PLUS | |||
if (name && this.files.has(name)) { | |||
await this.uploadHandle(this.files.get(name)); | |||
} | |||
else { | |||
for (let item of this.files.values()) { | |||
if (item.type === 'waiting' || item.type === 'fail') { | |||
await this.uploadHandle(item); | |||
} | |||
} | |||
} | |||
// #endif | |||
// #ifdef APP-PLUS | |||
this.dom&&this.dom.evalJS(`vm.upload('${name}')`); | |||
// #endif | |||
} | |||
// 选择文件change | |||
addFile(file) { | |||
let name = file.name; | |||
this.debug&&console.log('文件名称',name,'大小',file.size); | |||
if (file) { | |||
// 限制文件格式 | |||
let path = ''; | |||
let suffix = name.substring(name.lastIndexOf(".")+1).toLowerCase(); | |||
let formats = this.prohibited.formats.toLowerCase(); | |||
if (formats&&!formats.includes(suffix)) { | |||
this.toast(`不支持上传${suffix.toUpperCase()}格式文件`); | |||
return false; | |||
} | |||
// 限制文件大小 | |||
if (file.size > 1024 * 1024 * Math.abs(this.prohibited.size)) { | |||
this.toast(`附件大小请勿超过${this.prohibited.size}M`) | |||
return false; | |||
} | |||
// #ifndef MP-WEIXIN | |||
path = URL.createObjectURL(file); | |||
// #endif | |||
// #ifdef MP-WEIXIN | |||
path = file.path; | |||
// #endif | |||
this.files.set(file.name,{file,path,name: file.name,size: file.size,progress: 0,type: 'waiting'}); | |||
// #ifndef MP-WEIXIN | |||
this.onchange(this.files); | |||
this.instantly&&this.upload(); | |||
// #endif | |||
// #ifdef MP-WEIXIN | |||
return true; | |||
// #endif | |||
} | |||
} | |||
/** | |||
* 移除文件 | |||
* @param {string}name 不传name默认移除所有文件,传入name移除指定name的文件 | |||
*/ | |||
clear(name='') { | |||
// #ifdef APP-PLUS | |||
this.dom&&this.dom.evalJS(`vm.clear('${name}')`); | |||
// #endif | |||
if (!name) { | |||
this.files.clear(); | |||
} | |||
else { | |||
this.files.delete(name); | |||
} | |||
return this.onchange(this.files); | |||
} | |||
/** | |||
* 提示框 | |||
* @param {string}msg 轻提示内容 | |||
*/ | |||
toast(msg) { | |||
uni.showToast({ | |||
title: msg, | |||
icon: 'none' | |||
}); | |||
} | |||
/** | |||
* 微信小程序选择文件 | |||
* @param {number}count 可选择文件数量 | |||
*/ | |||
chooseMessageFile(type,count) { | |||
wx.chooseMessageFile({ | |||
count: count, | |||
type: type, | |||
success: ({ tempFiles }) => { | |||
for (let file of tempFiles) { | |||
let next = this.addFile(file); | |||
if (!next) {return} | |||
} | |||
this.onchange(this.files); | |||
this.instantly&&this.upload(); | |||
}, | |||
fail: () => { | |||
this.toast(`打开失败`); | |||
} | |||
}) | |||
} | |||
_overrideUrlLoading() { | |||
this.dom.overrideUrlLoading({ mode: 'reject' }, e => { | |||
let {retype,item,files,end} = this._getRequest( | |||
e.url | |||
); | |||
let _this = this; | |||
switch (retype) { | |||
case 'updateOption': | |||
this.dom.evalJS(`vm.setData('${JSON.stringify(_this.option)}')`); | |||
break | |||
case 'change': | |||
try { | |||
_this.files = new Map([..._this.files,...JSON.parse(unescape(files))]); | |||
} catch (e) { | |||
return console.error('出错了,请检查代码') | |||
} | |||
_this.onchange(_this.files); | |||
break | |||
case 'progress': | |||
try { | |||
item = JSON.parse(unescape(item)); | |||
} catch (e) { | |||
return console.error('出错了,请检查代码') | |||
} | |||
_this._changeFilesItem(item,end); | |||
break | |||
default: | |||
break | |||
} | |||
}) | |||
} | |||
_getRequest(url) { | |||
let theRequest = new Object() | |||
let index = url.indexOf('?') | |||
if (index != -1) { | |||
let str = url.substring(index + 1) | |||
let strs = str.split('&') | |||
for (let i = 0; i < strs.length; i++) { | |||
theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]) | |||
} | |||
} | |||
return theRequest | |||
} | |||
_changeFilesItem(item,end=false) { | |||
this.debug&&console.log('onprogress',JSON.stringify(item)); | |||
this.onprogress(item,end); | |||
this.files.set(item.name,item); | |||
} | |||
_uploadHandle(item) { | |||
item.type = 'loading'; | |||
delete item.responseText; | |||
return new Promise((resolve,reject)=>{ | |||
this.debug&&console.log('option',JSON.stringify(this.option)); | |||
let {url,name,method='POST',header,formData} = this.option; | |||
let form = new FormData(); | |||
for (let keys in formData) { | |||
form.append(keys, formData[keys]) | |||
} | |||
form.append(name, item.file); | |||
let xmlRequest = new XMLHttpRequest(); | |||
xmlRequest.open(method, url, true); | |||
for (let keys in header) { | |||
xmlRequest.setRequestHeader(keys, header[keys]) | |||
} | |||
xmlRequest.upload.addEventListener( | |||
'progress', | |||
event => { | |||
if (event.lengthComputable) { | |||
let progress = Math.ceil((event.loaded * 100) / event.total) | |||
if (progress <= 100) { | |||
item.progress = progress; | |||
this._changeFilesItem(item); | |||
} | |||
} | |||
}, | |||
false | |||
); | |||
xmlRequest.ontimeout = () => { | |||
console.error('请求超时') | |||
item.type = 'fail'; | |||
this._changeFilesItem(item,true); | |||
return resolve(false); | |||
} | |||
xmlRequest.onreadystatechange = ev => { | |||
if (xmlRequest.readyState == 4) { | |||
if (xmlRequest.status == 200) { | |||
this.debug&&console.log('上传完成:' + xmlRequest.responseText) | |||
item['responseText'] = xmlRequest.responseText; | |||
item.type = 'success'; | |||
this._changeFilesItem(item,true); | |||
return resolve(true); | |||
} else if (xmlRequest.status == 0) { | |||
console.error('status = 0 :请检查请求头Content-Type与服务端是否匹配,服务端已正确开启跨域,并且nginx未拦截阻止请求') | |||
} | |||
console.error('--ERROR--:status = ' + xmlRequest.status) | |||
item.type = 'fail'; | |||
this._changeFilesItem(item,true); | |||
return resolve(false); | |||
} | |||
} | |||
xmlRequest.send(form) | |||
}); | |||
} | |||
_uploadHandleWX(item) { | |||
item.type = 'loading'; | |||
delete item.responseText; | |||
return new Promise((resolve,reject)=>{ | |||
this.debug&&console.log('option',JSON.stringify(this.option)); | |||
let form = {filePath: item.file.path,...this.option }; | |||
form['fail'] = ({ errMsg = '' }) => { | |||
console.error('--ERROR--:' + errMsg) | |||
item.type = 'fail'; | |||
this._changeFilesItem(item,true); | |||
return resolve(false); | |||
} | |||
form['success'] = res => { | |||
if (res.statusCode == 200) { | |||
this.debug&&console.log('上传完成,微信端返回不一定是字符串,根据接口返回格式判断是否需要JSON.parse:' + res.data) | |||
item['responseText'] = res.data; | |||
item.type = 'success'; | |||
this._changeFilesItem(item,true); | |||
return resolve(true); | |||
} | |||
item.type = 'fail'; | |||
this._changeFilesItem(item,true); | |||
return resolve(false); | |||
} | |||
let xmlRequest = uni.uploadFile(form); | |||
xmlRequest.onProgressUpdate(({ progress = 0 }) => { | |||
if (progress <= 100) { | |||
item.progress = progress; | |||
this._changeFilesItem(item); | |||
} | |||
}) | |||
}); | |||
} | |||
} |
@@ -0,0 +1,320 @@ | |||
<template> | |||
<view class="lsj-file" :style="[getStyles]"> | |||
<view ref="lsj" class="hFile" :style="[getStyles]" @click="onClick"> | |||
<slot><view class="defview" :style="[getStyles]">点击上传</view></slot> | |||
</view> | |||
</view> | |||
</template> | |||
<script> | |||
// 查看文档:https://ext.dcloud.net.cn/plugin?id=5459 | |||
import {LsjFile} from './LsjFile.js' | |||
export default { | |||
name: 'Lsj-upload', | |||
props: { | |||
// 打印日志 | |||
debug: {type: Boolean,default: false}, | |||
// 自动上传 | |||
instantly: {type: Boolean,default: false}, | |||
// 上传接口参数设置 | |||
option: {type: Object,default: ()=>{}}, | |||
// 文件大小上限 | |||
size: { type: Number, default: 10 }, | |||
// 文件选择个数上限,超出后不触发点击 | |||
count: { type: Number, default: 9 }, | |||
// 允许上传的文件格式(多个以逗号隔开) | |||
formats: { type: String, default:''}, | |||
// input file选择限制 | |||
accept: {type: String,default: ''}, | |||
// 微信选择文件类型 | |||
//all=从所有文件选择, | |||
//video=只能选择视频文件, | |||
//image=只能选择图片文件, | |||
//file=可以选择除了图片和视频之外的其它的文件 | |||
wxFileType: { type: String, default: 'all' }, | |||
// webviewID需唯一,不同窗口也不要同Id | |||
childId: { type: String, default: 'lsjUpload' }, | |||
// 文件选择触发面宽度 | |||
width: { type: String, default: '100%' }, | |||
// 文件选择触发面高度 | |||
height: { type: String, default: '80rpx' }, | |||
// top,left,bottom,right仅position=absolute时才需要传入 | |||
top: { type: [String, Number], default: '' }, | |||
left: { type: [String, Number], default: '' }, | |||
bottom: { type: [String, Number], default: '' }, | |||
right: { type: [String, Number], default: '' }, | |||
// nvue不支持跟随窗口滚动 | |||
position: { | |||
type: String, | |||
// #ifdef APP-NVUE | |||
default: 'absolute', | |||
// #endif | |||
// #ifndef APP-NVUE | |||
default: 'static', | |||
// #endif | |||
}, | |||
}, | |||
data() { | |||
return { | |||
} | |||
}, | |||
watch: { | |||
option(v) { | |||
// #ifdef APP-PLUS | |||
this.lsjFile&&this.show(); | |||
// #endif | |||
} | |||
}, | |||
updated() { | |||
// #ifdef APP-PLUS | |||
if (this.isShow) { | |||
this.lsjFile&&this.show(); | |||
} | |||
// #endif | |||
}, | |||
computed: { | |||
getStyles() { | |||
let styles = { | |||
width: this.width, | |||
height: this.height | |||
} | |||
if (this.position == 'absolute') { | |||
styles['top'] = this.top | |||
styles['bottom'] = this.bottom | |||
styles['left'] = this.left | |||
styles['right'] = this.right | |||
styles['position'] = 'fixed' | |||
} | |||
return styles | |||
} | |||
}, | |||
mounted() { | |||
this._size = 0; | |||
let WEBID = this.childId + new Date().getTime(); | |||
this.lsjFile = new LsjFile({ | |||
id: WEBID, | |||
debug: this.debug, | |||
width: this.width, | |||
height: this.height, | |||
option: this.option, | |||
instantly: this.instantly, | |||
// 限制条件 | |||
prohibited: { | |||
// 大小 | |||
size: this.size, | |||
// 允许上传的格式 | |||
formats: this.formats, | |||
// 限制选择的格式 | |||
accept: this.accept, | |||
count: this.count | |||
}, | |||
onchange: this.onchange, | |||
onprogress: this.onprogress, | |||
}); | |||
this.create(); | |||
}, | |||
beforeDestroy() { | |||
// #ifdef APP-PLUS | |||
this.lsjFile.dom.close(); | |||
// #endif | |||
}, | |||
methods: { | |||
setFiles(array) { | |||
if (array instanceof Map) { | |||
for (let [key, item] of array) { | |||
item['progress'] = 100; | |||
item['type'] = 'success'; | |||
this.lsjFile.files.set(key,item); | |||
} | |||
} | |||
else if (Array.isArray(array)) { | |||
array.forEach(item=>{ | |||
if (item.name) { | |||
item['progress'] = 100; | |||
item['type'] = 'success'; | |||
this.lsjFile.files.set(item.name,item); | |||
} | |||
}); | |||
} | |||
this.onchange(this.lsjFile.files); | |||
}, | |||
setData() { | |||
this.lsjFile&&this.lsjFile.setData(...arguments); | |||
}, | |||
getDomStyles(callback) { | |||
// #ifndef APP-NVUE | |||
let view = uni | |||
.createSelectorQuery() | |||
.in(this) | |||
.select('.lsj-file') | |||
view.fields( | |||
{ | |||
size: true, | |||
rect: true | |||
}, | |||
({ height, width, top, left, right, bottom }) => { | |||
uni.createSelectorQuery() | |||
.selectViewport() | |||
.scrollOffset(({ scrollTop }) => { | |||
return callback({ | |||
top: parseInt(top) + parseInt(scrollTop) + 'px', | |||
left: parseInt(left) + 'px', | |||
width: parseInt(width) + 'px', | |||
height: parseInt(height) + 'px' | |||
}) | |||
}) | |||
.exec() | |||
} | |||
).exec() | |||
// #endif | |||
// #ifdef APP-NVUE | |||
const dom = weex.requireModule('dom') | |||
dom.getComponentRect(this.$refs.lsj, ({ size: { height, width, top, left, right, bottom } }) => { | |||
return callback({ | |||
top: parseInt(top) + 'px', | |||
left: parseInt(left) + 'px', | |||
width: parseInt(width) + 'px', | |||
height: parseInt(height) + 'px', | |||
right: parseInt(right) + 'px', | |||
bottom: parseInt(bottom) + 'px' | |||
}) | |||
}) | |||
// #endif | |||
}, | |||
show() { | |||
this.isShow = true; | |||
// #ifdef APP-PLUS | |||
this.lsjFile&&this.getDomStyles(styles => { | |||
this.lsjFile.dom.setStyle(styles) | |||
}); | |||
// #endif | |||
// #ifdef H5 | |||
this.lsjFile.dom.style.display = 'inline' | |||
// #endif | |||
}, | |||
hide() { | |||
this.isShow = false; | |||
// #ifdef APP-PLUS | |||
this.lsjFile&&this.lsjFile.dom.setStyle({ | |||
top: '-100px', | |||
left:'0px', | |||
width: '1px', | |||
height: '100px', | |||
}); | |||
// #endif | |||
// #ifdef H5 | |||
this.lsjFile.dom.style.display = 'none' | |||
// #endif | |||
}, | |||
/** | |||
* 手动提交上传 | |||
* @param {string}name 文件名称,不传则上传所有type等于waiting和fail的文件 | |||
*/ | |||
upload(name) { | |||
this.lsjFile&&this.lsjFile.upload(name); | |||
}, | |||
/** | |||
* @returns {Map} 已选择的文件Map集 | |||
*/ | |||
onchange(files) { | |||
this.$emit('change',files); | |||
this._size = files.size; | |||
return files.size >= this.count ? this.hide() : this.show(); | |||
}, | |||
/** | |||
* @returns {object} 当前上传中的对象 | |||
*/ | |||
onprogress(item,end=false) { | |||
this.$emit('progress',item); | |||
if (end) { | |||
setTimeout(()=>{ | |||
this.$emit('uploadEnd',item); | |||
},0); | |||
} | |||
}, | |||
/** | |||
* 移除组件内缓存的某条数据 | |||
* @param {string}name 文件名称,不指定默认清除所有文件 | |||
*/ | |||
clear(name) { | |||
this.lsjFile.clear(name); | |||
}, | |||
// 创建选择器 | |||
create() { | |||
// 若iOS端服务端处理不了跨域就将hybrid目录内的html放到服务端去,并将此处path改成服务器上的地址 | |||
let path = '/static/html/uploadFile.html'; | |||
let dom = this.lsjFile.create(path); | |||
// #ifdef H5 | |||
this.$refs.lsj.$el.appendChild(dom); | |||
// #endif | |||
// #ifndef APP-PLUS | |||
this.show(); | |||
// #endif | |||
// #ifdef APP-PLUS | |||
dom.setStyle({position: this.position}); | |||
dom.loadURL(path); | |||
setTimeout(()=>{ | |||
// #ifdef APP-NVUE | |||
plus.webview.currentWebview().append(dom); | |||
// #endif | |||
// #ifndef APP-NVUE | |||
this.$root.$scope.$getAppWebview().append(dom); | |||
// #endif | |||
this.show(); | |||
},300) | |||
// #endif | |||
}, | |||
// 点击选择附件 | |||
onClick() { | |||
if (this._size >= this.count) { | |||
this.toast(`只允许上传${this.count}个文件`); | |||
return; | |||
} | |||
// #ifdef MP-WEIXIN | |||
if (!this.isShow) {return;} | |||
let count = this.count - this._size; | |||
this.lsjFile.chooseMessageFile(this.wxFileType,count); | |||
// #endif | |||
}, | |||
toast(msg) { | |||
uni.showToast({ | |||
title: msg, | |||
icon: 'none' | |||
}); | |||
}, | |||
newguid() { | |||
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) { | |||
var r = Math.random() * 16 | 0, | |||
v = c == 'x' ? r : (r & 0x3 | 0x8); | |||
return v.toString(16); | |||
}); | |||
}, | |||
} | |||
} | |||
</script> | |||
<style scoped> | |||
.lsj-file { | |||
display: inline-block; | |||
} | |||
.defview { | |||
background-color: #007aff; | |||
color: #fff; | |||
border-radius: 10rpx; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
font-size: 28rpx; | |||
} | |||
.hFile { | |||
position: relative; | |||
overflow: hidden; | |||
} | |||
</style> |
@@ -38,7 +38,10 @@ | |||
@input="setValue('StuMail.Files', $event)" | |||
:value="getValue('StuMail.Files')" | |||
:readonly="!edit" | |||
:number="9" | |||
title="附件上传" | |||
tableName="StuMail" | |||
fieldName="Files" | |||
/> | |||
<l-textarea | |||
@input="setValue('StuMail.LeaveReason', $event)" | |||
@@ -72,6 +72,8 @@ | |||
:readonly="!edit" | |||
:number="9" | |||
title="附件上传" | |||
tableName="MeetingManagement" | |||
fieldName='Files' | |||
/> | |||
</view> | |||
@@ -2,7 +2,7 @@ | |||
<view class="page"> | |||
<div class="timeTable_sec1"> | |||
<div class="tSec1Box" id="semester"> | |||
<image src="~@/common/images/timeT1-1.png" mode="widthFix"></image> | |||
<image src="@/static/timeT1-1.png" mode="widthFix"></image> | |||
<span>2019年上半学期</span> | |||
</div> | |||
<view class="tSec1Box" id="weekTime"> | |||
@@ -234,6 +234,7 @@ export default { | |||
.tSec1Box image { | |||
width: 15px; | |||
margin-right: 2px; | |||
height: 15px; | |||
} | |||
.tSec1Box text:after { | |||
display: none; | |||
@@ -34,9 +34,11 @@ | |||
<l-icon slot="title" type="lock" /> | |||
</l-input> | |||
<l-button @click="login(null)" size="lg" color="blue" class="margin-top-sm block" block>登 录</l-button> | |||
<view class="otherLogin"> | |||
<navigator url="/pages/weixinLogin" class="textBtn">微信登录</text></navigator> | |||
</view> | |||
<!-- #ifndef APP-PLUS --> | |||
<view class="otherLogin"> | |||
<navigator url="/pages/weixinLogin" class="textBtn">微信登录</text></navigator> | |||
</view> | |||
<!-- #endif --> | |||
<!-- <l-button v-if="enableSignUp" @click="signUp" size="lg" line="blue" class="margin-top-sm block" block> | |||
教师注册 | |||
</l-button> --> | |||
@@ -2,7 +2,7 @@ | |||
<view class="page"> | |||
<view class="timeTable_sec1"> | |||
<view class="tSec1Box" id="semester"> | |||
<image src="~@/common/images/timeT1-1.png" mode="widthFix"></image> | |||
<image src="@/static/timeT1-1.png" mode="widthFix"></image> | |||
<text>{{ semester }}</text> | |||
</view> | |||
<!--<span class="tSec1Line"></span>--> | |||
@@ -236,6 +236,7 @@ export default { | |||
} | |||
.tSec1Box image { | |||
width: 15px; | |||
height: 15px; | |||
margin-right: 2px; | |||
} | |||
.tSec1Box text:after { | |||
@@ -2,7 +2,7 @@ | |||
<view class="page"> | |||
<view class="timeTable_sec1"> | |||
<view class="tSec1Box" id="semester"> | |||
<image src="~@/common/images/timeT1-1.png" mode="widthFix"></image> | |||
<image src="@/static/timeT1-1.png" mode="widthFix"></image> | |||
<text>{{ semester }}</text> | |||
</view> | |||
<!--<span class="tSec1Line"></span>--> | |||
@@ -236,6 +236,7 @@ export default { | |||
} | |||
.tSec1Box image { | |||
width: 15px; | |||
height: 15px; | |||
margin-right: 2px; | |||
} | |||
.tSec1Box text:after { | |||
@@ -2,7 +2,7 @@ | |||
<view class="page"> | |||
<view class="timeTable_sec1"> | |||
<view class="tSec1Box" id="semester2"> | |||
<image src="~@/common/images/timeT1-1.png" mode="widthFix"></image> | |||
<image src="@/static/timeT1-1.png" mode="widthFix"></image> | |||
<text>{{ semester }}</text> | |||
</view> | |||
<view class="tSec1Box" id="weekTime2"> | |||
@@ -201,6 +201,7 @@ export default { | |||
} | |||
.tSec1Box image { | |||
width: 15px; | |||
height: 15px; | |||
margin-right: 2px; | |||
} | |||
@@ -2,7 +2,7 @@ | |||
<view class="page"> | |||
<view class="timeTable_sec1"> | |||
<view class="tSec1Box" id="semester"> | |||
<image src="~@/common/images/timeT1-1.png" mode="widthFix"></image> | |||
<image src="@/static/timeT1-1.png" mode="widthFix"></image> | |||
<text>{{ semester }}</text> | |||
</view> | |||
<!--<span class="tSec1Line"></span>--> | |||
@@ -268,6 +268,7 @@ export default { | |||
} | |||
.tSec1Box image { | |||
width: 15px; | |||
height: 15px; | |||
margin-right: 2px; | |||
} | |||
.tSec1Box text:after { | |||
@@ -0,0 +1,184 @@ | |||
<!DOCTYPE html> | |||
<html lang="zh-cn"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<title class="title">[文件管理器]</title> | |||
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> | |||
<style type="text/css"> | |||
.content {background: transparent;} | |||
.btn {position: relative;top: 0;left: 0;bottom: 0;right: 0;} | |||
.btn .file {position: fixed;z-index: 93;left: 0;right: 0;top: 0;bottom: 0;width: 100%;opacity: 0;} | |||
</style> | |||
</head> | |||
<body> | |||
<div id="content" class="content"> | |||
<div class="btn"> | |||
<input @change="onChange" :accept="accept" ref="file" class="file" type="file" /> | |||
</div> | |||
</div> | |||
<script type="text/javascript" src="js/vue.min.js"></script> | |||
<script type="text/javascript"> | |||
let _this; | |||
var vm = new Vue({ | |||
el: '#content', | |||
data: { | |||
accept: '', | |||
}, | |||
mounted() { | |||
console.log('加载webview'); | |||
_this = this; | |||
this.files = new Map(); | |||
document.addEventListener('plusready', (e)=>{ | |||
let {debug,instantly,prohibited} = plus.webview.currentWebview(); | |||
this.debug = debug; | |||
this.instantly = instantly; | |||
this.prohibited = prohibited; | |||
this.accept = prohibited.accept; | |||
location.href = 'callback?retype=updateOption'; | |||
}, false); | |||
}, | |||
methods: { | |||
toast(msg) { | |||
plus.nativeUI.toast(msg); | |||
}, | |||
clear(name) { | |||
if (!name) { | |||
this.files.clear(); | |||
return; | |||
} | |||
this.files.delete(name); | |||
}, | |||
setData(option='{}') { | |||
this.debug&&console.log('更新参数:'+option); | |||
try{ | |||
_this.option = JSON.parse(option); | |||
}catch(e){ | |||
console.error('参数设置错误') | |||
} | |||
}, | |||
async upload(name=''){ | |||
if (name && this.files.has(name)) { | |||
await this.createUpload(this.files.get(name)); | |||
} | |||
else { | |||
for (let item of this.files.values()) { | |||
if (item.type === 'waiting' || item.type === 'fail') { | |||
await this.createUpload(item); | |||
} | |||
} | |||
} | |||
}, | |||
openFile(url){ | |||
plus.runtime.openFile(url) | |||
}, | |||
onChange(e) { | |||
let fileDom = this.$refs.file; | |||
let file = fileDom.files[0]; | |||
let name = file.name; | |||
fileDom.value = ''; | |||
this.debug&&console.log('文件名称',name,'大小',file.size); | |||
if (file) { | |||
// 限制文件格式 | |||
let suffix = name.substring(name.lastIndexOf(".")+1).toLowerCase(); | |||
let formats = this.prohibited.formats.toLowerCase(); | |||
if (formats&&!formats.includes(suffix)) { | |||
this.toast(`不支持上传${suffix.toUpperCase()}格式文件`); | |||
return; | |||
} | |||
console.log('this.size',this.prohibited.size); | |||
// 限制文件大小 | |||
if (file.size > 1024 * 1024 * Math.abs(this.prohibited.size)) { | |||
this.toast(`附件大小请勿超过${this.prohibited.size}M`) | |||
return; | |||
} | |||
let path = URL.createObjectURL(file); | |||
this.files.set(file.name,{file,path,name: file.name,size: file.size,progress: 0,type: 'waiting'}); | |||
this.callChange(); | |||
this.instantly&&this.upload(); | |||
} | |||
}, | |||
/** | |||
* @returns {Map} 已选择的文件Map集 | |||
*/ | |||
callChange() { | |||
location.href = 'callback?retype=change&files=' + escape(JSON.stringify([...this.files])); | |||
}, | |||
/** | |||
* @returns {object} 正在处理的当前对象 | |||
*/ | |||
changeFilesItem(item,end='') { | |||
this.files.set(item.name,item); | |||
location.href = 'callback?retype=progress&end='+ end +'&item=' + escape(JSON.stringify(item)); | |||
}, | |||
createUpload(item) { | |||
this.debug&&console.log('准备上传,option=:'+JSON.stringify(this.option)); | |||
item.type = 'loading'; | |||
delete item.responseText; | |||
return new Promise((resolve,reject)=>{ | |||
let {url,name,method='POST',header={},formData={}} = this.option; | |||
let form = new FormData(); | |||
for (let keys in formData) { | |||
form.append(keys, formData[keys]) | |||
console.log(keys,formData[keys]) | |||
} | |||
form.append(name, item.file); | |||
let xmlRequest = new XMLHttpRequest(); | |||
xmlRequest.open(method, url, true); | |||
for (let keys in header) { | |||
xmlRequest.setRequestHeader(keys, header[keys]) | |||
} | |||
xmlRequest.upload.addEventListener( | |||
'progress', | |||
event => { | |||
if (event.lengthComputable) { | |||
let progress = Math.ceil((event.loaded * 100) / event.total) | |||
if (progress <= 100) { | |||
item.progress = progress; | |||
this.changeFilesItem(item); | |||
} | |||
} | |||
}, | |||
false | |||
); | |||
xmlRequest.ontimeout = () => { | |||
console.error('请求超时') | |||
item.type = 'fail'; | |||
this.changeFilesItem(item,true); | |||
return resolve(false); | |||
} | |||
xmlRequest.onreadystatechange = ev => { | |||
if (xmlRequest.readyState == 4) { | |||
if (xmlRequest.status == 200) { | |||
this.debug && console.log('上传完成:' + xmlRequest.responseText) | |||
item['responseText'] = xmlRequest.responseText; | |||
item.type = 'success'; | |||
this.changeFilesItem(item,true); | |||
return resolve(true); | |||
} else if (xmlRequest.status == 0) { | |||
console.error('status = 0 :请检查请求头Content-Type与服务端是否匹配,服务端已正确开启跨域,并且nginx未拦截阻止请求') | |||
} | |||
console.error('--ERROR--:status = ' + xmlRequest.status) | |||
item.type = 'fail'; | |||
this.changeFilesItem(item,true); | |||
return resolve(false); | |||
} | |||
} | |||
xmlRequest.send(form) | |||
}); | |||
} | |||
} | |||
}); | |||
</script> | |||
</body> | |||
</html> |