/**
|
* CImagePicker
|
* @author Tevin
|
*/
|
|
<template>
|
<view class="c-image-picker">
|
<AtInput
|
ref="input"
|
:name="itemRes.name"
|
:title="itemRes.label"
|
:required="itemRes.required"
|
:error="itemRes.error"
|
/>
|
<AtImagePicker
|
ref="picker"
|
mode="aspectFit"
|
:multiple="count > 1"
|
:count="count"
|
:showAddBtn="!selectedFull"
|
:length="3"
|
:files="files"
|
:onChange="(files,operationType,index)=>handleChange(files,operationType,index)"
|
:onFail="evt=>handleFail(evt)"
|
:onImageClick="(index, file)=>handleImgView(index,file)"
|
/>
|
<CImageCompressor ref="compressor" />
|
</view>
|
</template>
|
|
<script>
|
import Taro from '@tarojs/taro';
|
import { $ } from '@tarojs/extend';
|
import { AtInput, AtImagePicker, AtCurtain } from 'taro-ui-vue';
|
import { Fetcher } from '@components/bases/Fetcher';
|
import { $fetchCommon } from '@fetchers/FCommon';
|
import { Tools } from '@components/common/Tools';
|
import CImageCompressor from './CImageCompressor.vue';
|
import './cImagePicker.scss';
|
|
export default {
|
name: 'CImagePicker',
|
components: {
|
CImageCompressor,
|
AtInput,
|
AtImagePicker,
|
AtCurtain,
|
},
|
props: {
|
// 表单数据资源(表单组件内部机制专用)
|
itemRes: Object,
|
// 最大图片张数
|
count: {
|
type: Number,
|
default: 1,
|
},
|
},
|
data() {
|
return {
|
fileNames: {},
|
};
|
},
|
computed: {
|
files() {
|
const value = this.itemRes.formData[this.itemRes.name];
|
let files = [];
|
if (Object.prototype.toString.call(value) === '[object String]') {
|
files = value.split(',').map(url => ({ url }));
|
} else if (Object.prototype.toString.call(value) === '[object Array]') {
|
files = value.map(url => ({ url }));
|
}
|
return files;
|
},
|
selectedFull() {
|
return this.files.length >= this.count;
|
},
|
},
|
methods: {
|
_triggerChange(files) {
|
const value = [];
|
files.forEach(file => {
|
value.push(file.url);
|
// 记录原文件名
|
if (file.file && file.file.originalFileObj) {
|
this.fileNames[file.url] = file.file.originalFileObj.name;
|
}
|
});
|
this.itemRes.onChange(value);
|
},
|
handleChange(files, operationType, index) {
|
// 添加图片
|
if (operationType === 'add') {
|
// 屏蔽其他格式
|
let nextFiles = files.filter(file => {
|
// 新添加
|
if (file.file && file.file.originalFileObj) {
|
if (
|
/image\/(gif|png|jpg|jpeg)/.test(
|
file.file.originalFileObj.type
|
)
|
) {
|
return true;
|
} else {
|
Tools.toast('不支持的格式,请选择其他图片!');
|
return false;
|
}
|
}
|
// 非本次添加的图片
|
else {
|
return true;
|
}
|
});
|
// 限制数量
|
if (nextFiles.length > this.count) {
|
Tools.toast('最多只能选 ' + this.count + ' 张图片!');
|
nextFiles = nextFiles.splice(0, this.count);
|
}
|
// 检查是否需要压缩
|
const needs = nextFiles
|
.map((file, needIndex) => {
|
const fileInfo = file.file;
|
// 没有 file 信息对象,或者不是 blob 类型
|
if (!fileInfo || fileInfo.path.indexOf('blob') < 0) {
|
return false;
|
}
|
// 尺寸小于 1M 的图片
|
if (fileInfo.size < 1 * 1024 * 1024) {
|
return false;
|
}
|
return [fileInfo, needIndex];
|
})
|
.filter(Boolean);
|
// 存在需要压缩的图片,一次性压缩
|
if (needs.length > 0) {
|
const files2 = [...nextFiles];
|
const needPaths = needs.map(need => need[0].path);
|
this.$refs.compressor.$compress(needPaths, compressedFiles => {
|
compressedFiles.forEach((cpPath, cpIndex) => {
|
const filesIndex = needs[cpIndex][1];
|
files2[filesIndex] = {
|
url: cpPath.compress,
|
};
|
});
|
this._triggerChange(files2);
|
});
|
}
|
// 不存在,直接显示
|
else {
|
this._triggerChange(nextFiles);
|
}
|
}
|
// 删除图片,直接显示
|
else {
|
this._triggerChange(files);
|
}
|
},
|
handleImgView(index, file) {
|
const urls = this.files
|
.map(file => (file.type === 'btn' ? false : file.url))
|
.filter(Boolean);
|
Taro.previewImage({
|
current: file.url, // 当前显示图片的http链接
|
urls, // 需要预览的图片http链接列表
|
});
|
},
|
handleImgClose() {
|
this.showImg = false;
|
},
|
handleFail(msg) {
|
Taro.showToast({
|
title: msg,
|
icon: 'none',
|
mask: true,
|
duration: 2000,
|
});
|
},
|
$uploadImage(callback) {
|
const url = Fetcher.host + $fetchCommon.getUploadImgURL();
|
const uploadTeam = [];
|
const imgs = [];
|
this.files.forEach(file => {
|
if (file.type === 'btn') {
|
return;
|
}
|
// 临时文件才上传
|
if (
|
file.url.indexOf('blob') >= 0 ||
|
file.url.indexOf('wxfile') >= 0 ||
|
file.url.indexOf('http://tmp/') >= 0
|
) {
|
let header = {};
|
if (process.env.TARO_ENV === 'weapp') {
|
const localCookies = JSON.parse(
|
Taro.getStorageSync('cookies') || '{}'
|
);
|
const cookiesArr = [];
|
Object.keys(localCookies).forEach(key => {
|
cookiesArr.push(key + '=' + localCookies[key]);
|
});
|
header['Cookie'] = cookiesArr.join('; ');
|
}
|
uploadTeam.push(
|
new Promise((resolve, reject) => {
|
Taro.uploadFile({
|
url,
|
header,
|
filePath: file.url,
|
fileName: this.fileNames[file.url],
|
name: 'file',
|
formData: {},
|
success(res) {
|
const res2 =
|
typeof res.data === 'string'
|
? JSON.parse(res.data)
|
: res.data;
|
if (res2.state.code === 2000) {
|
resolve(
|
$fetchCommon.transImgPath(
|
'fix',
|
res2.data.src ||
|
res2.data.file ||
|
res2.data.url
|
)
|
);
|
} else {
|
reject({ message: res2.state.msg });
|
}
|
},
|
cancel() {
|
reject({ message: '上传图片已取消!' });
|
},
|
fail() {
|
reject({ message: '上传图片失败!' });
|
},
|
});
|
})
|
);
|
}
|
// 其他类型视为 url,忽略
|
else {
|
uploadTeam.push(Promise.resolve(file.url));
|
}
|
});
|
Promise.all(uploadTeam)
|
.then(res => {
|
this.itemRes.onChange(res);
|
setTimeout(() => {
|
callback('success');
|
}, 0);
|
})
|
.catch(err => {
|
callback('error', err);
|
});
|
},
|
},
|
mounted() {
|
if (process.env.TARO_ENV === 'h5') {
|
$(this.$refs.input.$el)
|
.find('.at-input__input')
|
.prepend(this.$refs.picker.$el);
|
} else if (process.env.TARO_ENV === 'weapp') {
|
$(this.$refs.input.$el)
|
.find('.at-input__container')
|
.append(this.$refs.picker.$el);
|
}
|
},
|
};
|
</script>
|