Просмотр исходного кода

新生信息完善

临城职教中职
杨晓琪 2 лет назад
Родитель
Сommit
c545d9962f
12 измененных файлов: 1489 добавлений и 110 удалений
  1. +2
    -14
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/components/learun-mpui/learun-ui-mp/upload.vue
  2. +88
    -90
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/components/upload-file.vue
  3. +2
    -2
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/config.js
  4. +0
    -3
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/myflow/single.vue
  5. +1
    -1
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/welcome/list.vue
  6. +92
    -0
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/changelog.md
  7. +392
    -0
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/components/lsj-upload/LsjFile.js
  8. +313
    -0
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/components/lsj-upload/lsj-upload.vue
  9. +8
    -0
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/hybrid/html/js/vue.min.js
  10. +179
    -0
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/hybrid/html/uploadFile.html
  11. +82
    -0
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/package.json
  12. +330
    -0
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/readme.md

+ 2
- 14
Learun.Framework.Ultimate V7/LearunApp-2.2.0/components/learun-mpui/learun-ui-mp/upload.vue Просмотреть файл

@@ -7,6 +7,7 @@
:key="index"
class="bg-img"
>
<!-- {{item.id?CONFIG('webHost')+item.url:item.url}} -->
<image
v-if="showfile()"
:src="item.id?CONFIG('webHost')+item.url:item.url"
@@ -89,20 +90,6 @@ export default {
},
uploadImage(){
// let array =
// function apiFn(item){
// return this.HTTP_POST('StuInfoFresh/savePhoto', postData, '图片上传失败!').then((data) => {
// if (data) {
// reslove([{
// url:data.Url,
// id:data.AnnexesFileId
// }])
// }else{
// reject('图片上传失败!')
// }
// })
// }
// return this.promiseAllLimit(5,array,apiFn)
// 单图上传
return new Promise(async (reslove,reject)=>{
let hasNotUpdatedList = this.imgList.every(item=>item.id)
@@ -232,6 +219,7 @@ export default {
// },
},
created() {
console.log(123)
this.imgList = JSON.parse(JSON.stringify(this.value.map(item=>{
item.isUploaded = true
return item


+ 88
- 90
Learun.Framework.Ultimate V7/LearunApp-2.2.0/components/upload-file.vue Просмотреть файл

@@ -8,12 +8,12 @@
class="bg-img"
>
<!-- {{API + '/user/img?data=' + (path.path ? path.path : path)}} -->
<!-- <image
v-if="showfile()"
:src="API + item.url"
<image
v-if="showfile()&&isImage(item.type)"
:src="CONFIG('webHost') + item.url"
mode="aspectFill"
></image> -->
<l-icon v-if="showfile()" type="text" />
></image>
<l-icon v-if="showfile()&&!isImage(item.type)" type="text" />
<text class="file-name">{{item.name}}</text>
<view v-if="!readonly" @tap.stop="delImg(index)" class="cu-tag bg-red" style="width: 18px; height: 18px; font-size: 24px">
<l-icon
@@ -23,15 +23,27 @@
</view>
</view>

<view
v-if="!readonly && imgList.length < Number(number)"
@tap="chooseImg"
<view
v-show="!readonly && imgList.length < Number(number)&&isShow"
class="solids"
>
<!-- @tap="chooseImg" -->
<l-icon type="file" />
<lsj-upload
ref="lsjUpload"
height="80px"
width="100%"
:size="20"
:option="{}"
:count="1"
@change="chooseChange"
style="opacity: 0;"
></lsj-upload>
</view>
</view>
</view>
</template>

<script>
@@ -46,67 +58,77 @@ export default {
data(){
return{
isShow:false,
imgList:[],
}
},

methods: {
chooseChange(files){
let array = Array.from(files);
if(array.length){
this.$refs.lsjUpload.clear()
}
let tempFilePaths = [],tempFiles=[];
array.forEach(item=>{
tempFilePaths.push(item[1].path)
tempFiles.push(item[1].file)
})
this.chooseChangeback(tempFilePaths,tempFiles)
},
delImg(index) {
this.LOADING('正在删除…');
const newList = JSON.parse(JSON.stringify(this.imgList));
this.HTTP_POST('StuInfoFresh/deleteFiles', {id:this.imgList[index].id},"文件删除失败").then((data) => {
this.HIDE_LOADING();
if (data) {
newList.splice(index, 1);
this.imgList = newList
this.$emit("update:value", newList);
this.$emit("input", newList);
this.$emit("change");
this.$emit("del");
}
})
this.LOADING('正在删除…');
const newList = JSON.parse(JSON.stringify(this.imgList));
this.HTTP_POST('StuInfoFresh/deleteFiles', {id:this.imgList[index].id},"文件删除失败").then((data) => {
this.HIDE_LOADING();
if (data) {
newList.splice(index, 1);
this.imgList = newList
this.$emit("update:value", newList);
this.$emit("input", newList);
this.$emit("change");
this.$emit("del");
}
})
},
showfile() {
return true;
},

chooseImg() {
uni.chooseFile({
// count: (Number(this.number) - this.imgList.length),
count: 1,
type:"all",
success: async (res) => {
let {tempFilePaths,tempFiles} = res
if(!this.validate(tempFiles))return
let uploadImageRes = await this.uploadImage(tempFilePaths[0])
async chooseChangeback(tempFilePaths,tempFiles) {
// let {tempFilePaths,tempFiles} = res
// if(!this.validate(tempFiles))return
let uploadImageRes = await this.uploadImage(tempFilePaths[0],tempFiles[0]?tempFiles[0].name:"")
let newList = this.imgList || []
if(uploadImageRes){
newList = JSON.parse(JSON.stringify(newList)).concat(uploadImageRes);
}
this.imgList = newList
this.$emit("update:value", newList);
this.$emit("input", newList);
this.$emit("change",newList);
this.$emit("add");
},
});
},
this.$emit("input", newList);
this.$emit("change",newList);
this.$emit("add");
},
uploadImage(url){
uploadImage(url,name){
if(!url)return
// 文件上传
return new Promise(async (reslove,reject)=>{
this.LOADING('正在上传…');
this.HTTP_UPLOAD2('StuInfoFresh/upload', url||this.imgList[0].url,{folderId:this.folderId}).then((data) => {
let params = name?{folderId:this.folderId,name}:{folderId:this.folderId}
this.HTTP_UPLOAD2('StuInfoFresh/upload', url,params).then((data) => {
this.HIDE_LOADING();
this.$refs.lsjUpload.show()
if (data) {
// this.HTTP_GET('StuInfoFresh/upload', {fileId:data})
reslove([{
id:data.F_Id,
name:data.F_FileName,
url:data.F_FilePath
url:data.F_FilePath,
type:data.F_FileType,
}])
}else{
reject('上传失败!')
@@ -115,48 +137,6 @@ export default {
})
},
// 图片文件转为 base64
getPictureBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
},
base64ToBlob (base64) {
const parts = base64.split(";base64,");
const contentType = parts[0].split(":")[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; i += 1) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
},
imgToBase64(url){
return new Promise((resolve,reject)=>{
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
img = new Image;
img.crossOrigin = 'Anonymous';
img.onload = function () {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL('image/png');
canvas = null;
resolve(dataURL)
};
img.src = url;
})
},
ceshi(){
function apiFn(params){
@@ -169,7 +149,8 @@ export default {
this.imgList[params.index] = [{
id:data.F_Id,
name:data.F_FileName,
url:data.F_FilePath
url:data.F_FilePath,
type:data.F_FileType
}]
reslove(this.imgList[params.index])
}else{
@@ -237,9 +218,24 @@ export default {
}
return true
},
isImage(type){
if(type&&type.length){
return ["png","jpg"].includes(type.substring(type.length-3,type.length))
}else{
return false
}
},

viewImg(item) {
window.location.href = this.CONFIG("webHost")+item.url
if(!this.isImage(item.type)){
window.location.href = this.CONFIG("webHost")+item.url
}else{
uni.previewImage({
urls: [this.CONFIG('webHost')+item.url],
current: this.CONFIG('webHost')+item.url
});
}
},
// previewFile() {
@@ -270,16 +266,17 @@ export default {
// },
},
created() {
// id name
console.log(this.value)
this.imgList = JSON.parse(JSON.stringify(this.value.map(item=>{
return {
id:item.F_Id,
name:item.F_FileName,
url:item.F_FilePath
url:item.F_FilePath,
type:item.F_FileType
}
})))
// [{url:"",id:""}]
this.$nextTick(()=>{
this.isShow = true
})
}
};
</script>
@@ -292,6 +289,7 @@ export default {
color: #606266;
font-size: 13px;
text-align: center;
background-color: rgba(255,255,255,0.6);
text-overflow: ellipsis;
overflow: hidden;


+ 2
- 2
Learun.Framework.Ultimate V7/LearunApp-2.2.0/config.js Просмотреть файл

@@ -27,8 +27,8 @@ export default {
"webHost":"http://192.168.10.85:8087/",
// 开发环境下自动填充登录账号密码,与接口地址一一对应,只在开发环境下显示
"devAccount": [
// 20201130230 21364200000400266 老师 420528196310072253 学生 420528200606205026
{ username: "420528200507261428", password: "www.qj.com" }
// 20201130230 21364200000400266 老师 420528196310072253 学生 420528200606205026 420528200507261428
{ username: "system", password: "www.qj.com" }
],
//是否分布式部署 指WebApi与Web不在一台服务器
"isDistributed":true,


+ 0
- 3
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/myflow/single.vue Просмотреть файл

@@ -14,8 +14,6 @@
:currentNode="currentNode"
:currentTask="currentTask"
/>
</view>
<!-- Tab #2:流程图页 -->
<view v-if="ready && tab === 1" class="progress"><l-workflow-timeline :processList="processList" /></view>
@@ -30,7 +28,6 @@ import workflowFormMixins from '../workflow.js'
export default {
data() {
return {
tab: 0,
editMode: false,
type: 'view',


+ 1
- 1
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/welcome/list.vue Просмотреть файл

@@ -184,7 +184,7 @@ export default {
},
refreshComponent(){
this.uploadVisiable = false
// this.uploadVisiable = false
this.$nextTick(()=>{
this.uploadVisiable = true
})


+ 92
- 0
Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/changelog.md Просмотреть файл

@@ -0,0 +1,92 @@
## 2.1.9(2022-07-13)
[修复] app端选择文件后初始化设置的文件列表被清空问题
## 2.1.8(2022-07-13)
[新增] ref方法初始化文件列表,用于已提交后再次编辑时需带入已上传文件:setFiles(files),可传入数组或Map对象,传入格式请与组件选择返回格式保持一致,且name为必须属性。
## 2.1.7(2022-07-12)
修复ios端偶现创建webview初始化参数未生效的问题
## 2.1.6(2022-07-11)
[修复]:修复上个版本更新导致nvue窗口组件不能选择文件的问题;
[新增]:
1.应群友建议(填写禁止格式太多)格式限制formats由原来填写禁止选择的格式改为填写允许被选择的格式;
2.应群友建议(增加上传结束回调事件),上传结束回调事件@uploadEnd
3.如能帮到你请留下你的免费好评,组件使用过程中有问题可以加QQ群交流,至于Map对象怎么使用这类前端基础问题请自行百度
## 2.1.5(2022-07-01)
app端组件销毁时添加自动销毁webview功能,避免v-if销毁组件的情况控件还能被点击的问题
## 2.1.4(2022-07-01)
修复小程序端回显问题
## 2.1.3(2022-06-30)
回调事件返回参数新增path字段(文件临时地址),用于回显
## 2.1.2(2022-06-16)
修复APP端Tabbar窗口无法选择文件的问题
## 2.1.1(2022-06-16)
优化:
1.组件优化为允许在v-if中使用;
2.允许option直接在data赋值,不再强制在onRead中初始化;
## 2.1.0(2022-06-13)
h5 pc端更改为单次可多选
## 2.0.9(2022-06-10)
更新演示内容,部分同学不知道怎么获取服务端返回的数据
## 2.0.8(2022-06-09)
优化动态更新上传参数函数,具体查看下方说明:动态更新参数演示
## 2.0.7(2022-06-07)
新增wxFileType属性,用于小程序端选择附件时可选文件类型
## 2.0.6(2022-06-07)
修复小程序端真机选择文件提示失败的问题
## 2.0.5(2022-06-02)
优化小程序端调用hide()后未阻止触发文件选择问题
## 2.0.4(2022-06-01)
优化APP端选择器初始定位
## 2.0.3(2022-05-31)
修复nvue窗口选择文件报错问题
## 2.0.2(2022-05-20)
修复ios端opiton设置过早未传入webview导致不自动上传问题
## 2.0.1(2022-05-19)
修复APP端子窗口点击选择文件不响应问题
## 2.0.0(2022-05-18)
此次组件更新至2.0版本,与1.0版本使用上略有差异,已使用1.0的同学请自行斟酌是否需要升级!
部分差异:
一、 2.0新增异步触发上传功能;
二、2.0新增文件批量上传功能;
三、2.0优化option,剔除属性,只保留上传接口所需字段,且允许异步更改option的值;
四、组件增加size(文件大小限制)、count(文件个数限制)、formats(文件后缀限制)、accept(文件类型限制)、instantly(是否立即自动上传)、debug(日志打印)等属性;
五、回调事件取消input事件、callback事件,新增change事件和progress事件;
六、ref事件新增upload事件、clear事件;
七、优化组件代码,show和hide函数改为显示隐藏,不再重复开关webview;

## 1.2.3(2022-03-22)
修复Demo里传入待完善功能[手动上传属性manual=true]导致不自动上传的问题,手动提交上传待下个版本更新
## 1.2.2(2022-02-21)
修复上版本APP优化导致H5和小程序端不自动初始化的问题,此次更新仅修复此问题。异步提交功能下个版本更新~
## 1.2.1(2022-01-25)
QQ1群已满,已开放2群:469580165
## 1.2.0(2021-12-09)
优化APP端页面中DOM重排后每次需要重新定位的问题
## 1.1.1(2021-12-09)
优化,与上版本使用方式有改变,请检查后确认是否需要更新,create更名为show, close更名为hide,取消初始化时手动create, 传参方式改为props=>option
## 1.1.0(2021-12-09)
新增refresh方法,用于DOM发生重排时重新定位控件(APP端)
## 1.0.9(2021-07-15)
修复上传进度未同步渲染,直接返回100%的BUG
## 1.0.8(2021-07-12)
修复H5端传入height和width未生效的bug
## 1.0.7(2021-07-07)
修复h5和小程序端上传完成callback未返回fileName字段问题
## 1.0.6(2021-07-07)
修复h5端提示信息debug
## 1.0.5(2021-06-29)
感谢小伙伴找出bug,上传成功回调success未置为true,已修复
## 1.0.4(2021-06-28)
新增兼容APP,H5,小程序手动关闭控件,关闭后不再弹出文件选择框,需要重新create再次开启
## 1.0.3(2021-06-28)
close增加条件编译,除app端外不需要close
## 1.0.2(2021-06-28)
1.修复页面滚动位置后再create控件导致控件位置不正确的问题;
2.修复nvue无法create控件;
3.示例项目新增nvue使用案例;
## 1.0.1(2021-06-28)
因为有的朋友不清楚app端切换tab时应该怎么处理webview,现重新上传一版示例项目,需要做tab切换的朋友可以导入示例项目查看
## 1.0.0(2021-06-25)
此插件为l-file插件中上传功能改版,更新内容为:
1. 按钮内嵌入页面,不再强制固定底部,可跟随页面滚动
2.无需再单独弹框点击上传,减去中间层
3.通过slot自定义按钮样式

+ 392
- 0
Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/components/lsj-upload/LsjFile.js Просмотреть файл

@@ -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: '-500px',
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);
}
})
});
}
}

+ 313
- 0
Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/components/lsj-upload/lsj-upload.vue Просмотреть файл

@@ -0,0 +1,313 @@
<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.$nextTick(()=>{
this._size = 0;
this.lsjFile = new LsjFile({
debug: this.debug,
id: this.childId,
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: '-500px',
left:'0px',
width: '1px',
height: '1px',
});
// #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 = '/uni_modules/lsj-upload/hybrid/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'
});
}
}
}
</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>

+ 8
- 0
Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/hybrid/html/js/vue.min.js
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 179
- 0
Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/hybrid/html/uploadFile.html Просмотреть файл

@@ -0,0 +1,179 @@
<!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);
}
}
}
},
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;
}
// 限制文件大小
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])
}
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>

+ 82
- 0
Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/package.json Просмотреть файл

@@ -0,0 +1,82 @@
{
"id": "lsj-upload",
"displayName": "全文件上传选择非原生2.0版",
"version": "2.1.9",
"description": "文件选择上传-支持APP-H5网页-微信小程序",
"keywords": [
"附件",
"file",
"upload",
"上传",
"文件管理器"
],
"repository": "",
"engines": {
"HBuilderX": "^3.2.0"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

+ 330
- 0
Learun.Framework.Ultimate V7/LearunApp-2.2.0/uni_modules/lsj-upload/readme.md Просмотреть файл

@@ -0,0 +1,330 @@
# lsj-upload

### 插件地址:https://ext.dcloud.net.cn/plugin?id=5459

### 不清楚使用方式可点击右侧导入示例项目运行完整示例
### 此次更新2.0与1.0使用方式略有差异,已使用1.0的同学自行斟酌是否更新到2.0版本!!!

使用插件有任何问题欢迎加入QQ讨论群:
- 群1:701468256(已满)
- 群2:469580165

若能帮到你请高抬贵手点亮5颗星~
------
## 重要提示
### 组件是窗口级滚动,不要在scroll-view内使用!!
### 组件是窗口级滚动,不要在scroll-view内使用!!
### 组件是窗口级滚动,不要在scroll-view内使用!!

### 控件的height高度应与slot自定义内容高度保持一致
### nvue窗口只能使用固定模式position=absolute
### show() 当DOM重排后在this.$nextTick内调用show(),控件定位会更加准确
### hide() APP端webview层级比view高,如不希望触发点击时,应调用hide隐藏控件,反之调用show
### 若iOS端跨域服务端同学实在配置不好,可把hybrid下html目录放到服务器去,同源则不存在跨域问题。
### 小程序端因hybrid不能使用本地HTML,所以插件提供的是从微信消息列表拉取文件并选择,请知悉。
------

## 使用说明
| 属性 | 是否必填 | 值类型 | 默认值 | 说明 |
| --------- | -------- | -----: | --: | :------------:|
| width | 否 | String |100% | 容器宽度 |
| height | 是 | String |80rpx | 容器高度 |
| debug | 否 | Boolean |false | 打印调试日志 |
| option | 是 | Object |- | [文件上传接口相关参数](#p1)|
| instantly | 否 | Boolean |false | true=自动上传 |
| count | 否 | Number |10 | 附件选择上限(个)|
| size | 否 | Number |10 | 附件大小上限(M)|
| wxFileType | 否 | String |all | 微信小程序文件选择器格式限制(all=从所有文件选择,video=只能选择视频文件,image=只能选择图片文件,file=可以选择除了图片和视频之外的其它的文件)|
| accept | 否 | String |- | 文件选择器input file格式限制(部分机型不兼容,建议使用formats)|
| formats | 否 | String |- | 限制允许上传的格式,空串=不限制,默认为空,多个格式以逗号隔开,例如png,jpg,pdf|
| childId | 否 | String |lsjUpload| 控件的id(仅APP有效,应用内每个控件命名一个唯一Id,不同窗口也不要同名Id)|
| position | 否 | String |static | 控件的定位模式(static=控件随页面滚动;absolute=控件在页面中绝对定位,不随窗口内容滚动)|
| top,left,right,bottom | 否 | [Number,String] |0 | 设置控件绝对位置,position=absolute时有效|
| @change | 否 | Function |Map | 选择文件触发,返回所有已选择文件Map集合|
| @progress | 否 | Function |Object | 上传过程中发生状态变化的文件对象,需通过set更新至Map集合|
| @uploadEnd| 否 | Function |Object | 上传结束回调,返回参数与progress一致|

## <a id="p1">option说明</a>
|参数 | 是否必填 | 说明|
|---- | ---- | :--: |
|url | 是 | 上传接口地址|
|name| 否 |上传接口文件key,默认为file|
|header| 否 |上传接口请求头|
|formData| 否 |上传接口额外参数|

## ref调用
|作用 | 方法名| 传入参数| 说明|
|---- | --------- | -------- | :--: |
|显示控件| show|-| 控件显示状态下可触发点击|
|隐藏控件| hide|-| 控件隐藏状态下不触发点击|
|动态设置文件列表| setFiles|[Array,Map] files| 传入格式请与组件选择返回格式保持一致,且name为必须属性,可查看下方演示|
|动态更新参数| setData|[String] name,[any] value| name支持a.b 和 a[b],可查看下方演示|
|移除选择的文件| clear|[String] name| 不传参数清空所有文件,传入文件name时删除该name的文件|
|手动上传| upload|[String] name| 不传参数默认依次上传所有type=waiting的文件,传入文件name时不关心type是否为waiting,单独上传指定name的文件|

## progress返回对象字段说明
|字段 | 说明|
|---- | :--: |
|file | 文件对象|
|name |文件名称|
|size |文件大小|
|type |文件上传状态:waiting(等待上传)、loading(上传中)、success(成功) 、fail(失败)|
|responseText|上传成功后服务端返回数据(仅type为success时存在)|

## 以下演示为vue窗口使用方式,nvue使用区别是必须传入控件绝对位置如top,bottom,left,right,且position只能为absolute,如不清楚可点击右侧导入示例项目有详细演示代码。

### vue:
``` javascript
<lsj-upload
ref="lsjUpload"
childId="upload1"
:width="width"
:height="height"
:option="option"
:size="size"
:formats="formats"
:debug="debug"
:instantly="instantly"
@progress="onprogress"
@change="onChange">
<view class="btn" :style="{width: width,height: height}">选择附件</view>
</lsj-upload>


<view class="padding">
<view>已选择文件列表:</view>
<!-- #ifndef MP-WEIXIN -->
<view v-for="(item,index) in files.values()" :key="index">
<image style="width: 100rpx;height: 100rpx;" :src="item.path" mode="widthFix"></image>
<text>{{item.path}}</text>
<text>{{item.name}}</text>
<text style="margin-left: 10rpx;">大小:{{item.size}}</text>
<text style="margin-left: 10rpx;">状态:{{item.type}}</text>
<text style="margin-left: 10rpx;">进度:{{item.progress}}</text>
<!-- <text style="margin-left: 10rpx;" v-if="item.responseText">服务端返回演示:{{item.responseText.code}}</text> -->
<text @click="clear(item.name)" style="margin-left: 10rpx;padding: 0 10rpx;border: 1rpx solid #007AFF;">删除</text>
</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view v-for="(item,index) in wxFiles" :key="index">
<text>{{item.name}}</text>
<text style="margin-left: 10rpx;">大小:{{item.size}}</text>
<text style="margin-left: 10rpx;">状态:{{item.type}}</text>
<text style="margin-left: 10rpx;">进度:{{item.progress}}</text>
<view>
<button>删除</button>
</view>
</view>
<!-- #endif -->
</view>


```

---
* 函数说明


``` javascript
export default {
data() {
return {
// 上传接口参数
option: {
// 上传服务器地址,此地址需要替换为你的接口地址
url: 'http://hlapi.j56.com/dropbox/document/upload',
// 上传附件的key
name: 'file',
// 根据你接口需求自定义请求头
header: {
'Authorization': 'bearer eyJhbGciOiJSUzI1NiIsI',
'uid': '27682',
'client': 'app',
'accountid': 'DP',
},
// 根据你接口需求自定义body参数
formData: {
// 'orderId': 1000
}
},
// 选择文件后是否立即自动上传,true=选择后立即上传
instantly: false,
// 必传宽高且宽高应与slot宽高保持一致
width: '180rpx',
height: '180rpx',
// 限制允许选择的格式,空串=不限制,默认为空
formats: 'png,jpg,mp4',
// 文件上传大小限制
size: 10,
// 文件回显列表
files: new Map(),
// 微信小程序Map对象for循环不显示,所以转成普通数组,不要问为什么,我也不知道
wxFiles: [],
// 是否打印日志
debug: true,
// 演示用
tabIndex: 0,
list:[],
}
},
onReady() {
setTimeout(()=>{
console.log('----演示动态更新参数-----');
this.$refs.lsjUpload.setData('formData.orderId','动态设置的参数');
console.log('以下注释内容为-动态更新参数更多演示,放开后可查看演示效果');
// 修改option对象的name属性
// this.$refs.lsjUpload.setData('name','myFile');
// 修改option对象的formData内的属性
// this.$refs.lsjUpload.setData('formData.appid','1111');
// 替换option对象的formData
// this.$refs.lsjUpload.setData('formData',{appid:'222'});
// option对象的formData新增属性
// this.$refs.lsjUpload.setData('formData.newkey','新插入到formData的属性');
// ---------演示初始化值,用于已提交后再次编辑时需带入已上传文件-------
// 方式1=传入数组
let files1 = [{
name: '1.png'
},
{
name: '2.png',
}];
// 方式2=传入Map对象
let files2 = new Map();
files2.set('1.png',{name: '1.png'})
// 设置初始files列表
this.$refs.lsjUpload.setFiles(files1);
},2000)
},
methods: {
// 某文件上传结束回调(成功失败都回调)
onuploadEnd(item) {
console.log(`${item.name}已上传结束,上传状态=${item.type}`);
// 更新当前状态变化的文件
this.files.set(item.name,item);
// 演示上传完成后取服务端数据
if (item['responseText']) {
console.log('演示服务器返回的字符串JSON转对象');
this.files.get(item.name).responseText = JSON.parse(item.responseText);
}
// 微信小程序Map对象for循环不显示,所以转成普通数组,不要问为什么,我也不知道
// #ifdef MP-WEIXIN
this.wxFiles = [...this.files.values()];
// #endif
// 强制更新视图
this.$forceUpdate();
// ---可删除--演示判断是否所有文件均已上传成功
let isAll = [...this.files.values()].find(item=>item.type!=='success');
if (!isAll) {
console.log('已全部上传完毕');
}
else {
console.log(isAll.name+'待上传');
}
},
// 上传进度回调
onprogress(item) {
// 更新当前状态变化的文件
this.files.set(item.name,item);
console.log('打印对象',JSON.stringify(this.files.get(item.name)));
// 微信小程序Map对象for循环不显示,所以转成普通数组,不要问为什么,我也不知道
// #ifdef MP-WEIXIN
this.wxFiles = [...this.files.values()];
// #endif
// 强制更新视图
this.$forceUpdate();
},
// 文件选择回调
onChange(files) {
// 更新选择的文件
this.files = files;
// 强制更新视图
this.$forceUpdate();
// 微信小程序Map对象for循环不显示,所以转成普通数组,不要问为什么,我也不知道
// #ifdef MP-WEIXIN
this.wxFiles = [...this.files.values()];
// #endif
},
// 手动上传
upload() {
// name=指定文件名,不指定则上传所有type等于waiting和fail的文件
this.$refs.lsjUpload.upload();
},
// 移除某个文件
clear(name) {
// name=指定文件名,不传name默认移除所有文件
this.$refs.lsjUpload.clear(name);
},
/**
* 以下为演示
*/
// DOM重排演示,重排后组件内部updated默认会触发show方法,若特殊情况未能触发updated也可以手动调用一次show()
// 什么是DOM重排?自行百度去~
add() {
this.list.push('DOM重排测试');
},
// 切换视图演示,APP端因为是webview,层级比view高,
// 此时若不希望点击触发选择文件,需要手动调用hide()
// 手动调用hide后,需要调用show()才能恢复触发面
onTab(tabIndex) {
this.tabIndex = tabIndex;
if (tabIndex == 0 ) {
this.$nextTick(()=>{
this.$refs.lsjUpload.show();
})
}
else {
this.$refs.lsjUpload.hide();
}
},
// 打开nvue窗口
open() {
uni.navigateTo({
url: '/pages/nvue-demo/nvue-demo'
});
}
}
}

```

## 温馨提示
* 文件上传
0. 如说明表达还不够清楚,不清楚怎么使用可导入完整示例项目运行体验和查看
1. APP端请优先联调Android,上传成功后再运行iOS端,如iOS返回status=0则需要后端开启允许跨域;
2. header的Content-Type类型需要与服务端要求一致,否则收不到附件(服务端若没有明文规定则可不写,使用默认匹配)
3. 服务端不清楚怎么配置跨域可加群咨询,具体百度~
4. 欢迎加入QQ讨论群:701468256(已满)
5. 欢迎加入QQ讨论群:469580165
6. 欢迎加入QQ讨论群:469580165
7. 若能帮到你还请点亮5颗小星星以作鼓励哈~
8. 若能帮到你还请点亮5颗小星星以作鼓励哈~
9. 若能帮到你还请点亮5颗小星星以作鼓励哈~

Загрузка…
Отмена
Сохранить