oak-general-business/app/components/extraFile/gallery/index.ts

301 lines
10 KiB
TypeScript

import assert from 'assert';
import { EntityDict } from 'general-app-domain';
import { DeduceCreateOperationData } from "oak-domain/lib/types";
import { isMockId } from "oak-frontend-base/lib/utils/mockId";
import { composeFileUrl } from '../../../../lib/utils/extraFile';
import Dialog from '../../../utils/dialog/index';
export default OakComponent({
entity: 'extraFile',
isList: true,
async formData({ data: files, features }) {
const application = await features.application.getApplication();
const number2 = this.props.maxNumber;
if (
typeof number2 === 'number' &&
(number2 === 0 || files?.length >= number2)
) {
return {
files,
disableInsert: true,
systemConfig: application?.system?.config,
};
}
return {
files,
disableInsert: false,
systemConfig: application?.system?.config,
};
},
data: {
selected: -1,
// 根据 size 不同,计算的图片显示大小不同
itemSizePercentage: '',
},
externalClasses: ['l-class', 'l-item-class'],
properties: {
oakFullpath: String,
oakParent: String,
oakPath: String,
maxNumber: {
type: Number,
value: 100,
},
selectCount: {
type: Number,
value: 1,
},
sourceType: {
type: Array,
value: ['album', 'camera'],
},
mediaType: {
type: Array,
value: ['image'],
},
// 图片显示模式
mode: {
type: String,
value: 'aspectFit',
},
// 图片是否可预览
preview: {
type: Boolean,
value: true,
},
// 每行可显示的个数
size: {
type: Number,
value: 3,
},
// 图片是否可预览
disableDelete: {
type: Boolean,
value: false,
},
type: String,
origin: String,
tag1: String,
tag2: String,
entity: String,
},
methods: {
/**
* 获取组件内部节点位置信息(单个)
* @param component 组件实例
* @param selector {String} css选择器
* @returns boundingClientRect() 回调函数的值
*/
async getNodeRectFromComponent(component: any, selector: any) {
return await new Promise((resolve) => {
component
.createSelectorQuery()
.select(selector)
.boundingClientRect((res: any) => {
resolve(res);
})
.exec();
});
},
/**
// * px 转 rpx
// * @param px 像素值
// */
px2rpx(px: number) {
const windowWidth = wx.getSystemInfoSync().windowWidth;
return (750 / windowWidth) * px;
},
async onPick() {
const {
selectCount,
mediaType,
sourceType,
} = this.props;
try {
const { errMsg, tempFiles } = await wx.chooseMedia({
count: selectCount,
mediaType,
sourceType,
});
if (errMsg !== 'chooseMedia:ok') {
this.triggerEvent('error', {
level: 'warning',
msg: errMsg,
});
} else {
await Promise.all(
tempFiles.map(async (tempExtraFile) => {
const {
tempFilePath,
thumbTempFilePath,
fileType,
size,
} = tempExtraFile;
const filePath = tempFilePath || thumbTempFilePath;
const fileFullName =
filePath.match(/[^/]+(?!.*\/)/g)![0];
this.pushExtraFile({
name: fileFullName,
fileType,
size,
extra1: filePath,
});
})
);
}
} catch (err: any) {
console.error(err);
if (err.errMsg !== 'chooseMedia:fail cancel') {
this.triggerEvent('error', {
level: 'error',
msg: err.errMsg,
});
}
}
},
async onWebPick(value) {
await Promise.all(
value.map(async (uploadFile) => {
const { name, type: fileType, size, raw } = uploadFile;
this.pushExtraFile({
name,
fileType,
size,
extra1: raw,
});
})
);
},
async pushExtraFile(options: { name: string, extra1: any, fileType: string, size: number }) {
const { type, origin, tag1, tag2, entity } = this.props;
const { name, extra1, fileType, size } = options;
const extension = name.substring(name.lastIndexOf('.') + 1);
const filename = name.substring(0, name.lastIndexOf('.'));
assert(entity, '必须传入entity');
assert(origin === 'qiniu', '目前只支持七牛上传'); // 目前只支持七牛上传
const ele: Parameters<typeof this['pushNode']>[1] = {
updateData: {
extra1,
origin,
type: type || fileType,
tag1,
tag2,
objectId: await generateNewId(),
entity,
filename,
size,
extension,
},
beforeExecute: async (updateData) => {
const { url, bucket } =
await this.features.extraFile.upload(
updateData as DeduceCreateOperationData<
EntityDict['extraFile']['Schema']
>
);
Object.assign(updateData, {
bucket,
extra1: null,
});
},
};
this.pushNode(undefined, ele);
},
async onItemTapped(event: WechatMiniprogram.Touch) {
const { files, systemConfig } = this.state;
const { index } = event.currentTarget.dataset;
const imageUrl = composeFileUrl(files[index]!, systemConfig);
const urls = files
?.filter((ele) => !!ele)
.map((ele) => composeFileUrl(ele!, systemConfig));
const detail = {
all: files,
index,
urls: urls,
current: imageUrl,
};
this.triggerEvent('tap', detail);
// 预览图片
if (this.props.preview) {
const result = await wx.previewImage({
urls: urls,
current: imageUrl,
});
this.triggerEvent('preview', detail);
}
},
async onDelete(event: WechatMiniprogram.Touch) {
const { value, index } = event.currentTarget.dataset;
const { id } = value;
if (isMockId(id)) {
this.removeNode('', `${index}`);
} else {
const result = await wx.showModal({
title: '确认删除吗',
content: '删除现有文件',
});
const { confirm } = result;
if (confirm) {
this.removeNode('', `${index}`);
}
}
},
async onWebDelete(value, index) {
const { id } = value;
if (isMockId(id)) {
this.removeNode('', `${index}`);
} else {
const confirm = Dialog.confirm({
header: '确认删除当前文件?',
body: '删除后,文件不可恢复',
title: '确认删除当前文件?',
content: '删除后,文件不可恢复',
cancelBtn: '取消',
confirmBtn: '确定',
onConfirm: () => {
this.removeNode('', `${index}`);
confirm.hide();
},
onCancel: () => {
confirm.hide();
},
onClose: () => {
confirm.hide();
},
});
}
},
},
observers: {
maxNumber: function () {
this.reRender();
},
/**
* size 属性变化时,重新调整图片大小
* @param size 新值
*/
size: async function (size: number) {
if (!size) {
this.setState({ itemSizePercentage: '' });
return;
}
// 获取 .file-list__container 容器宽度
const res: any = await this.getNodeRectFromComponent(
this,
'.file-list__container'
);
const widthRpx = this.px2rpx(res.right - res.left);
// 根据容器宽度计算单张图片宽度百分比
const itemSizePercentage =
(10 / size) * 10 - (20 / widthRpx) * 100 + '%;';
this.setState({ itemSizePercentage: itemSizePercentage });
},
},
});