@@ -1715,6 +1715,7 @@ select parentid from [dbo].[Acc_DormitoryBuild] where BuildType='5' and (student | |||||
{ | { | ||||
var parentEntity = db.FindEntity<Acc_DormitoryBuildEntity>(ParentID); | var parentEntity = db.FindEntity<Acc_DormitoryBuildEntity>(ParentID); | ||||
entity.Create(); | entity.Create(); | ||||
entity.DNo = entity.Name.Substring(0,entity.Name.Length-1); | |||||
entity.ApartmentId = parentEntity.ApartmentId; | entity.ApartmentId = parentEntity.ApartmentId; | ||||
entity.UnitId = parentEntity.UnitId; | entity.UnitId = parentEntity.UnitId; | ||||
entity.FloorId = parentEntity.FloorId; | entity.FloorId = parentEntity.FloorId; | ||||
@@ -2115,7 +2116,7 @@ where ID='{ParentID}' | |||||
var dormitoryCode = dr["寝室编号"].ToString().Trim(); | var dormitoryCode = dr["寝室编号"].ToString().Trim(); | ||||
var dormitory = dormitoryBuildList.Where(x => x.Name == dormitoryName && x.DNo == dormitoryCode && x.BuildType == "4" && x.ParentID == floor.ID) | var dormitory = dormitoryBuildList.Where(x => x.Name == dormitoryName && x.DNo == dormitoryCode && x.BuildType == "4" && x.ParentID == floor.ID) | ||||
.FirstOrDefault(); | .FirstOrDefault(); | ||||
if (dormitory == null) | |||||
if (dormitory == null && !string.IsNullOrEmpty(dormitoryName) && !string.IsNullOrEmpty(dormitoryCode)) | |||||
{ | { | ||||
//添加 | //添加 | ||||
dormitory = new Acc_DormitoryBuildEntity(); | dormitory = new Acc_DormitoryBuildEntity(); | ||||
@@ -2146,9 +2147,9 @@ where ID='{ParentID}' | |||||
//床位 | //床位 | ||||
var bedName = dr["床位"].ToString().Trim(); | var bedName = dr["床位"].ToString().Trim(); | ||||
var bedCode = bedName.Replace("床", "").Replace("号", ""); | 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(); | .FirstOrDefault(); | ||||
if (bed == null) | |||||
if (bed == null && !string.IsNullOrEmpty(bedName) && !string.IsNullOrEmpty(bedCode)) | |||||
{ | { | ||||
bed = new Acc_DormitoryBuildEntity(); | bed = new Acc_DormitoryBuildEntity(); | ||||
bed.Create(); | bed.Create(); | ||||
@@ -249,7 +249,7 @@ export default { | |||||
} | } | ||||
for (const item of val) { | for (const item of val) { | ||||
if (item.uid) { | |||||
if (item.uid || item.folderId) { | |||||
// uploadUid = item.uid | // uploadUid = item.uid | ||||
continue | continue | ||||
} | } | ||||
@@ -131,6 +131,7 @@ | |||||
v-else-if="item.type === 'upload'" | v-else-if="item.type === 'upload'" | ||||
@input="setValue(item.__valuePath__, $event)" | @input="setValue(item.__valuePath__, $event)" | ||||
:value="getValue(item.__valuePath__)" | :value="getValue(item.__valuePath__)" | ||||
:labelId="item.id" | |||||
:required="Boolean(item.verify)" | :required="Boolean(item.verify)" | ||||
:readonly="!isEdit(item)" | :readonly="!isEdit(item)" | ||||
:title="item.title" | :title="item.title" | ||||
@@ -1,213 +1,303 @@ | |||||
<template> | <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> | </template> | ||||
<script> | <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> | </script> | ||||
<style lang="less" scoped> | <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> | </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)" | @input="setValue('StuMail.Files', $event)" | ||||
:value="getValue('StuMail.Files')" | :value="getValue('StuMail.Files')" | ||||
:readonly="!edit" | :readonly="!edit" | ||||
:number="9" | |||||
title="附件上传" | title="附件上传" | ||||
tableName="StuMail" | |||||
fieldName="Files" | |||||
/> | /> | ||||
<l-textarea | <l-textarea | ||||
@input="setValue('StuMail.LeaveReason', $event)" | @input="setValue('StuMail.LeaveReason', $event)" | ||||
@@ -72,6 +72,8 @@ | |||||
:readonly="!edit" | :readonly="!edit" | ||||
:number="9" | :number="9" | ||||
title="附件上传" | title="附件上传" | ||||
tableName="MeetingManagement" | |||||
fieldName='Files' | |||||
/> | /> | ||||
</view> | </view> | ||||
@@ -2,7 +2,7 @@ | |||||
<view class="page"> | <view class="page"> | ||||
<div class="timeTable_sec1"> | <div class="timeTable_sec1"> | ||||
<div class="tSec1Box" id="semester"> | <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> | <span>2019年上半学期</span> | ||||
</div> | </div> | ||||
<view class="tSec1Box" id="weekTime"> | <view class="tSec1Box" id="weekTime"> | ||||
@@ -234,6 +234,7 @@ export default { | |||||
.tSec1Box image { | .tSec1Box image { | ||||
width: 15px; | width: 15px; | ||||
margin-right: 2px; | margin-right: 2px; | ||||
height: 15px; | |||||
} | } | ||||
.tSec1Box text:after { | .tSec1Box text:after { | ||||
display: none; | display: none; | ||||
@@ -34,9 +34,11 @@ | |||||
<l-icon slot="title" type="lock" /> | <l-icon slot="title" type="lock" /> | ||||
</l-input> | </l-input> | ||||
<l-button @click="login(null)" size="lg" color="blue" class="margin-top-sm block" block>登 录</l-button> | <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 v-if="enableSignUp" @click="signUp" size="lg" line="blue" class="margin-top-sm block" block> | ||||
教师注册 | 教师注册 | ||||
</l-button> --> | </l-button> --> | ||||
@@ -2,7 +2,7 @@ | |||||
<view class="page"> | <view class="page"> | ||||
<view class="timeTable_sec1"> | <view class="timeTable_sec1"> | ||||
<view class="tSec1Box" id="semester"> | <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> | <text>{{ semester }}</text> | ||||
</view> | </view> | ||||
<!--<span class="tSec1Line"></span>--> | <!--<span class="tSec1Line"></span>--> | ||||
@@ -236,6 +236,7 @@ export default { | |||||
} | } | ||||
.tSec1Box image { | .tSec1Box image { | ||||
width: 15px; | width: 15px; | ||||
height: 15px; | |||||
margin-right: 2px; | margin-right: 2px; | ||||
} | } | ||||
.tSec1Box text:after { | .tSec1Box text:after { | ||||
@@ -2,7 +2,7 @@ | |||||
<view class="page"> | <view class="page"> | ||||
<view class="timeTable_sec1"> | <view class="timeTable_sec1"> | ||||
<view class="tSec1Box" id="semester"> | <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> | <text>{{ semester }}</text> | ||||
</view> | </view> | ||||
<!--<span class="tSec1Line"></span>--> | <!--<span class="tSec1Line"></span>--> | ||||
@@ -236,6 +236,7 @@ export default { | |||||
} | } | ||||
.tSec1Box image { | .tSec1Box image { | ||||
width: 15px; | width: 15px; | ||||
height: 15px; | |||||
margin-right: 2px; | margin-right: 2px; | ||||
} | } | ||||
.tSec1Box text:after { | .tSec1Box text:after { | ||||
@@ -2,7 +2,7 @@ | |||||
<view class="page"> | <view class="page"> | ||||
<view class="timeTable_sec1"> | <view class="timeTable_sec1"> | ||||
<view class="tSec1Box" id="semester2"> | <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> | <text>{{ semester }}</text> | ||||
</view> | </view> | ||||
<view class="tSec1Box" id="weekTime2"> | <view class="tSec1Box" id="weekTime2"> | ||||
@@ -201,6 +201,7 @@ export default { | |||||
} | } | ||||
.tSec1Box image { | .tSec1Box image { | ||||
width: 15px; | width: 15px; | ||||
height: 15px; | |||||
margin-right: 2px; | margin-right: 2px; | ||||
} | } | ||||
@@ -2,7 +2,7 @@ | |||||
<view class="page"> | <view class="page"> | ||||
<view class="timeTable_sec1"> | <view class="timeTable_sec1"> | ||||
<view class="tSec1Box" id="semester"> | <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> | <text>{{ semester }}</text> | ||||
</view> | </view> | ||||
<!--<span class="tSec1Line"></span>--> | <!--<span class="tSec1Line"></span>--> | ||||
@@ -268,6 +268,7 @@ export default { | |||||
} | } | ||||
.tSec1Box image { | .tSec1Box image { | ||||
width: 15px; | width: 15px; | ||||
height: 15px; | |||||
margin-right: 2px; | margin-right: 2px; | ||||
} | } | ||||
.tSec1Box text:after { | .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> |