调通qiniu的delete file,brc适配改动

This commit is contained in:
Xu Chang 2023-10-10 22:00:26 +08:00
commit 4903b992bd
147 changed files with 3730 additions and 1194 deletions

View File

@ -82,7 +82,8 @@ export async function createSession(params, context) {
}
case 'wechatMp':
case 'wechatPublic': {
assert(data, '');
assert(data);
assert(entity === 'application');
const { ToUserName, FromUserName, CreateTime, MsgType,
// Event,
Content,
@ -98,6 +99,22 @@ export async function createSession(params, context) {
openId: FromUserName,
}
}, {});
const result = await context.select('session', {
data: {
id: 1,
entity: 1,
entityId: 1,
userId: 1,
lmts: 1,
openId: 1,
},
filter: {
entity: entity,
entityId: entityId,
openId: FromUserName,
}
}, {});
session = result[0];
sessionMessage$session = [
{
id: await generateNewIdAsync(),
@ -105,8 +122,7 @@ export async function createSession(params, context) {
data: {
id: await generateNewIdAsync(),
applicationId: wechatUser?.applicationId,
// sessionId: session[0]?.id,
wechatUser: wechatUser?.id,
wechatUserId: wechatUser?.id,
createTime: CreateTime,
type: MsgType,
text: Content,
@ -148,6 +164,7 @@ export async function createSession(params, context) {
entityId,
userId,
lmts: Date.now(),
openId: data?.FromUserName,
}, sessionMessage$session && { sessionMessage$session }),
}, {
dontCollect: true,

View File

@ -7,6 +7,7 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
type: string;
executeText: string;
buttonProps: {};
afterCommit: () => undefined;
afterCommit: () => void;
beforeCommit: () => true;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -2,7 +2,7 @@ import assert from 'assert';
export default OakComponent({
formData({ features }) {
const ids = this.getEfIds();
const states = ids.map(id => features.extraFile2.getFileState(id));
const states = ids.map((id) => features.extraFile2.getFileState(id));
let state = 'uploaded';
states.forEach((ele) => {
if (ele) {
@ -25,20 +25,20 @@ export default OakComponent({
type: 'primary',
executeText: '',
buttonProps: {},
afterCommit: () => undefined,
afterCommit: () => { },
beforeCommit: () => true,
},
methods: {
getEfIds() {
const { efPaths } = this.props;
const { oakFullpath } = this.state;
assert(efPaths);
assert(efPaths && efPaths.length > 0);
if (oakFullpath) {
const ids = efPaths.map((path) => {
const path2 = path ? `${oakFullpath}.${path}` : oakFullpath;
const data = this.features.runningTree.getFreshValue(path2);
if (data) {
return data.map(ele => ele.id);
}
assert(data, `efPath为${path}的路径上取不到extraFile数据请设置正确的相对路径`);
return data.map(ele => ele.id);
}).flat().filter(ele => !!ele);
return ids;
}
@ -46,6 +46,7 @@ export default OakComponent({
},
async upload() {
const ids = this.getEfIds();
assert(ids.length > 0);
const promises = [];
ids.forEach((id) => {
const fileState = this.features.extraFile2.getFileState(id);
@ -59,7 +60,7 @@ export default OakComponent({
if (promises.length > 0) {
await Promise.all(promises);
}
}
},
},
features: ['extraFile2'],
});

View File

@ -9,7 +9,8 @@ export default function render(props: WebComponentProps<EntityDict, any, true, {
type?: ButtonProps['type'];
executeText?: string;
buttonProps?: ButtonProps;
beforeCommit?: () => Promise<boolean> | boolean;
afterCommit?: () => void;
}, {
upload: () => Promise<void>;
afterCommit?: () => void;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -1,9 +1,11 @@
import { jsx as _jsx } from "react/jsx-runtime";
import { Button } from 'antd-mobile';
export default function render(props) {
const { state, oakExecutable, oakExecuting, oakDirty, size, block, type, executeText, buttonProps } = props.data;
const { t, upload, execute, afterCommit } = props.methods;
const disabled = oakExecuting || ['uploading'].includes(state) || (oakExecutable === false && ['uploaded'].includes(state));
const { state, oakExecutable, oakExecuting, oakDirty, size, block, type, executeText, buttonProps, beforeCommit, afterCommit, } = props.data;
const { t, upload, execute } = props.methods;
const disabled = oakExecuting ||
['uploading'].includes(state) ||
(oakExecutable === false && ['uploaded'].includes(state));
let text = executeText || t('common::action.confirm');
if (oakExecuting) {
text = t('executing', { text });
@ -18,6 +20,12 @@ export default function render(props) {
}
return (_jsx(Button, { type: type, size: size, block: block, disabled: disabled, onClick: async () => {
if (oakExecutable) {
if (beforeCommit) {
const beforeCommitResult = await beforeCommit();
if (beforeCommitResult === false) {
return;
}
}
await execute();
await upload();
if (afterCommit) {

View File

@ -10,6 +10,7 @@ export default function render(props: WebComponentProps<EntityDict, any, true, {
executeText?: string;
buttonProps?: ButtonProps;
afterCommit?: () => void;
beforeCommit?: () => Promise<boolean> | boolean;
}, {
upload: () => Promise<void>;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -1,9 +1,11 @@
import { jsx as _jsx } from "react/jsx-runtime";
import { Button } from 'antd';
export default function render(props) {
const { state, oakExecutable, oakExecuting, afterCommit, size, block, type, executeText, buttonProps = {} } = props.data;
const { state, oakExecutable, oakExecuting, size, block, type, executeText, buttonProps = {}, afterCommit, beforeCommit, } = props.data;
const { t, upload, execute } = props.methods;
const disabled = oakExecuting || ['uploading'].includes(state) || (oakExecutable !== true && ['uploaded'].includes(state));
const disabled = oakExecuting ||
['uploading'].includes(state) ||
(oakExecutable !== true && ['uploaded'].includes(state));
let text = executeText || t('common::action.confirm');
if (oakExecuting) {
text = t('executing', { text });
@ -18,6 +20,12 @@ export default function render(props) {
}
return (_jsx(Button, { type: type, size: size, block: block, disabled: disabled, onClick: async () => {
if (oakExecutable) {
if (beforeCommit) {
const beforeCommitResult = await beforeCommit();
if (beforeCommitResult === false) {
return;
}
}
await execute();
await upload();
if (afterCommit) {

View File

@ -163,7 +163,6 @@ export default OakComponent({
type: 'image',
tag1,
tag2,
objectId: generateNewId(),
bucket: '',
id: generateNewId(),
};

View File

@ -3,14 +3,12 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
type SourceType = 'album' | 'camera';
type Theme = 'file' | 'image' | 'image-flow' | 'custom';
type FileType = 'all' | 'video' | 'image' | 'file';
type ImgMode = 'scaleToFill' | 'aspectFit' | 'aspectFill' | 'widthFix' | "heightFix" | 'top' | 'bottom' | 'left' | 'right' | 'center' | 'top left' | 'top right' | 'bottom left' | 'bottom right';
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
removeLater: boolean;
autoUpload: boolean;
maxNumber: number;
extension: string[];
fileType: FileType;
selectCount: number;
sourceType: SourceType[];
mediaType: ('image' | 'video')[];
@ -18,7 +16,7 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
size: number;
showUploadList: boolean;
accept: string;
preview: boolean;
disablePreview: boolean;
disableDelete: boolean;
disableAdd: boolean;
disableDownload: boolean;

View File

@ -1,5 +1,5 @@
import { generateNewId } from 'oak-domain/lib/utils/uuid';
import assert from 'assert';
import { assert } from 'oak-domain/lib/utils/assert';
import Dialog from '../../../utils/dialog/index';
export default OakComponent({
entity: 'extraFile',
@ -23,7 +23,9 @@ export default OakComponent({
uploadState: 1,
},
formData({ data: originalFiles, features }) {
let files = originalFiles?.filter((ele) => !ele.$$deleteAt$$).sort((ele1, ele2) => ele1.sort - ele2.sort);
let files = originalFiles
?.filter((ele) => !ele.$$deleteAt$$)
.sort((ele1, ele2) => ele1.sort - ele2.sort);
if (this.props.tag1) {
files = files?.filter((ele) => ele?.tag1 === this.props.tag1);
}
@ -39,7 +41,7 @@ export default OakComponent({
data: {
// 根据 size 不同,计算的图片显示大小不同
itemSizePercentage: '',
fileList: {}
fileList: {},
},
wechatMp: {
externalClasses: ['oak-class', 'oak-item-class'],
@ -64,23 +66,17 @@ export default OakComponent({
autoUpload: false,
maxNumber: 20,
extension: [],
fileType: 'all',
selectCount: 1,
sourceType: ['album', 'camera'],
mediaType: ['image'],
// 图片显示模式
mode: 'aspectFit',
// 每行可显示的个数
size: 3,
showUploadList: true,
showUploadProgress: false,
accept: 'image/*',
// 图片是否可预览
preview: true,
// 图片是否可删除
disablePreview: false,
disableDelete: false,
// 上传按钮隐藏
disableAdd: false,
// 下按按钮隐藏
disableDownload: false,
disabled: false,
type: '',
@ -90,13 +86,14 @@ export default OakComponent({
entity: '',
entityId: '',
theme: 'image',
showUploadProgress: false,
},
methods: {
getUrl(extraFile) {
const { fileList } = this.state;
if (fileList[extraFile?.id]) {
const url = this.features.extraFile.getUrl(Object.assign({}, extraFile, { extra1: fileList[extraFile?.id] }));
const url = this.features.extraFile.getUrl(Object.assign({}, extraFile, {
extra1: fileList[extraFile?.id],
}));
return url;
}
return this.features.extraFile.getUrl(extraFile);
@ -104,7 +101,7 @@ export default OakComponent({
getFileName(extraFile) {
return this.features.extraFile.getFileName(extraFile);
},
eFFormatBytes(value) {
formatBytes(value) {
return this.features.extraFile.formatBytes(value);
},
/**
@ -171,12 +168,12 @@ export default OakComponent({
}
},
async chooseFileByMp() {
const { selectCount, extension, fileType } = this.props;
const { selectCount, extension } = this.props;
try {
const { errMsg, tempFiles } = await wx.chooseMessageFile({
count: selectCount,
type: 'all',
...(fileType === 'file' ? { extension } : {}),
extension,
});
if (errMsg !== 'chooseMessageFile:ok') {
this.triggerEvent('error', {
@ -217,7 +214,9 @@ export default OakComponent({
},
async onPickByWeb(uploadFiles, callback) {
const { files } = this.state;
const currentSort = files?.length ? files[files.length - 1].sort : 0;
const currentSort = files?.length
? files[files.length - 1].sort
: 0;
await Promise.all(uploadFiles.map(async (uploadFile, index) => {
const { name, type, size, originFileObj } = uploadFile;
await this.pushExtraFile({
@ -225,7 +224,7 @@ export default OakComponent({
fileType: type,
size,
extra1: originFileObj,
sort: currentSort + (index + 1) * 100
sort: currentSort + (index + 1) * 100,
}, callback);
}));
},
@ -236,7 +235,6 @@ export default OakComponent({
const filename = name.substring(0, name.lastIndexOf('.'));
assert(entity, '必须传入entity');
assert(origin === 'qiniu', '目前只支持七牛上传'); // 目前只支持七牛上传
const id = generateNewId();
const updateData = {
origin,
type: type || 'file',
@ -248,9 +246,8 @@ export default OakComponent({
size,
extension,
fileType,
id,
entityId,
sort
sort,
};
// autoUpload为true, 选择直接上传七牛再提交extraFile
if (autoUpload) {
@ -270,16 +267,17 @@ export default OakComponent({
if (callback) {
callback(updateData, 'failed');
}
//todo 保存extraFile失败 需要remove七牛图片
throw error;
}
}
else {
this.addItem(updateData, undefined, async () => {
const id = this.addItem(updateData, undefined, async () => {
await this.features.extraFile.upload(updateData, extra1);
});
this.setState({
fileList: Object.assign(this.state.fileList, { [id]: extra1 })
fileList: Object.assign(this.state.fileList, {
[id]: extra1,
}),
});
}
},
@ -298,7 +296,7 @@ export default OakComponent({
};
this.triggerEvent('tap', detail);
// 预览图片
if (this.props.preview) {
if (!this.props.disablePreview) {
const result = await wx.previewImage({
urls: urls,
current: imageUrl,
@ -317,7 +315,7 @@ export default OakComponent({
[id]: null,
});
this.setState({
fileList
fileList,
});
}
else {
@ -332,7 +330,7 @@ export default OakComponent({
id: null,
});
this.setState({
fileList
fileList,
});
await this.execute();
}
@ -349,7 +347,7 @@ export default OakComponent({
id: null,
});
this.setState({
fileList
fileList,
});
}
else {
@ -364,7 +362,7 @@ export default OakComponent({
id: null,
});
this.setState({
fileList
fileList,
});
await this.execute();
confirm.destroy();

View File

@ -5,14 +5,14 @@ interface NewUploadFile extends UploadFile {
id?: string;
}
type Theme = "file" | "image" | "image-flow" | "custom";
export default function render(props: WebComponentProps<EntityDict, "extraFile", true, {
export default function render(props: WebComponentProps<EntityDict, 'extraFile', true, {
accept?: string;
maxNumber?: number;
multiple?: boolean;
draggable?: boolean;
theme?: Theme;
tips?: string;
beforeUpload?: (file: File) => Promise<boolean>;
beforeUpload?: (file: File) => Promise<boolean> | boolean;
disabled?: boolean;
style?: Record<string, string>;
className?: string;
@ -21,17 +21,17 @@ export default function render(props: WebComponentProps<EntityDict, "extraFile",
onDownload?: (file: UploadFile<any>) => void;
showUploadList?: boolean;
children?: JSX.Element;
files?: EntityDict["extraFile"]["OpSchema"][];
files?: EntityDict['extraFile']['OpSchema'][];
disableInsert?: boolean;
disableAdd?: boolean;
disableDownload?: boolean;
disableDelete?: boolean;
preview?: boolean;
disablePreview?: boolean;
}, {
onPickByWeb: (files: UploadFile[], callback?: (file: NewUploadFile, status: string) => void) => void;
onDeleteByWeb: (file: UploadFile) => void;
getUrl: (extraFile: EntityDict['extraFile']['OpSchema']) => string;
getFileName: (extraFile: EntityDict['extraFile']['OpSchema']) => string;
eFFormatBytes: (value: number) => string;
formatBytes: (value: number) => string;
}>): import("react/jsx-runtime").JSX.Element;
export {};

View File

@ -18,8 +18,8 @@ function getListType(theme) {
};
return themeMap[theme];
}
const type = "DragableUploadList";
const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const type = 'DraggableUploadList';
const DraggableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const ref = React.useRef(null);
const index = fileList.indexOf(file);
const [{ isOver, dropClassName }, drop] = useDrop({
@ -31,7 +31,9 @@ const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
}
return {
isOver: monitor.isOver(),
dropClassName: dragIndex < index ? " drop-over-downward" : " drop-over-upward",
dropClassName: dragIndex < index
? ' drop-over-downward'
: ' drop-over-upward',
};
},
drop: (item) => {
@ -46,11 +48,11 @@ const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
}),
});
drop(drag(ref));
return (_jsx("div", { ref: ref, className: `ant-upload-draggable-list-item ${isOver ? dropClassName : ""}`, style: { cursor: "move", height: "100%" }, children: originNode }));
return (_jsx("div", { ref: ref, className: `ant-upload-draggable-list-item ${isOver ? dropClassName : ''}`, style: { cursor: 'move', height: '100%' }, children: originNode }));
};
export default function render(props) {
const { accept = "image/*", maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = "image", tips, beforeUpload, disabled, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files, disableInsert = false, disableAdd = false, disableDownload = false, disableDelete = false, preview = true, } = props.data;
const { onPickByWeb, onDeleteByWeb, updateItem, t, getFileName, getUrl, eFFormatBytes } = props.methods;
const { accept = 'image/*', maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = 'image', tips, beforeUpload, disabled, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files, disableInsert = false, disableAdd = false, disableDownload = false, disableDelete = false, disablePreview = false, } = props.data;
const { onPickByWeb, onDeleteByWeb, updateItem, t, getFileName, getUrl, formatBytes, } = props.methods;
const [newFiles, setNewFiles] = useState([]);
const [newUploadFiles, setNewUploadFiles] = useState([]);
const listType = getListType(theme);
@ -111,7 +113,7 @@ export default function render(props) {
if (children) {
return children;
}
if (listType === "picture-card") {
if (listType === 'picture-card') {
return (_jsxs("div", { children: [_jsx(PlusOutlined, {}), _jsx("div", { style: { marginTop: 8 }, children: "\u8BF7\u9009\u62E9\u56FE\u7247" })] }));
}
return _jsx(Button, { type: "default", children: "\u9009\u62E9\u6587\u4EF6" });
@ -131,7 +133,10 @@ export default function render(props) {
sort = newFiles[hoverIndex].sort + 100;
}
else {
sort = (newFiles[hoverIndex].sort + newFiles[hoverIndex + 1].sort) / 2;
sort =
(newFiles[hoverIndex].sort +
newFiles[hoverIndex + 1].sort) /
2;
}
}
else {
@ -139,35 +144,38 @@ export default function render(props) {
sort = newFiles[hoverIndex].sort / 2;
}
else {
sort = (newFiles[hoverIndex].sort + newFiles[hoverIndex - 1].sort) / 2;
sort =
(newFiles[hoverIndex].sort +
newFiles[hoverIndex - 1].sort) /
2;
}
}
if (checkLimit(sort)) {
alert("当前的sort值为:" + sort);
alert('当前的sort值为:' + sort);
return;
}
updateItem({ sort }, dragRow.id);
}, [newFiles]);
return (_jsxs(Space, { direction: "vertical", className: Style["oak-upload"], style: { width: "100%" }, children: [_jsx(DndProvider, { backend: isPc ? HTML5Backend : TouchBackend, children: _jsx(Upload, { className: classNames(Style["oak-upload__upload"], className), style: style, disabled: disabled, directory: directory, showUploadList: showUploadList
return (_jsxs(Space, { direction: "vertical", className: Style['oak-upload'], style: { width: '100%' }, children: [_jsx(DndProvider, { backend: isPc ? HTML5Backend : TouchBackend, children: _jsx(Upload, { className: classNames(Style['oak-upload__upload'], className), style: style, disabled: disabled, directory: directory, showUploadList: showUploadList
? {
showPreviewIcon: preview,
showPreviewIcon: !disablePreview,
showRemoveIcon: !disableDelete,
showDownloadIcon: !disableDownload,
}
: false, beforeUpload: async (file) => {
if (typeof beforeUpload === "function") {
if (typeof beforeUpload === 'function') {
const result = await beforeUpload(file);
if (result) {
return false;
}
}
return false;
}, multiple: multiple, maxCount: maxNumber, accept: accept, listType: listType, fileList: theme === "custom"
}, multiple: multiple, maxCount: maxNumber, accept: accept, listType: listType, fileList: theme === 'custom'
? []
: newFiles?.map((ele) => extraFileToUploadFile(ele)), onChange: ({ file, fileList, event }) => {
// id不存在就是file对象
if (!file.id) {
if (theme !== "custom") {
if (theme !== 'custom') {
onPickByWeb([file2Obj(file)]);
}
else {
@ -175,54 +183,54 @@ export default function render(props) {
}
}
}, onRemove: onDeleteByWeb, onPreview: onPreview, onDownload: onDownload, itemRender: (originNode, currentFile, currentFileList) => {
return (_jsx(DragableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && !disableAdd ? getUploadButton() : null }) }), tips && _jsx("small", { className: Style["oak-upload__tips"], children: tips }), theme === "custom" && (_jsxs(_Fragment, { children: [_jsx(Table, { dataSource: newUploadFiles || [], rowKey: "id", columns: [
return (_jsx(DraggableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && !disableAdd ? getUploadButton() : null }) }), tips && (_jsx("small", { className: Style['oak-upload__tips'], children: tips })), theme === 'custom' && (_jsxs(_Fragment, { children: [_jsx(Table, { dataSource: newUploadFiles || [], rowKey: "id", columns: [
{
align: "center",
dataIndex: "tableIndex",
title: "#",
align: 'center',
dataIndex: 'tableIndex',
title: '#',
render: (value, record, index) => index + 1,
width: 50,
},
{
dataIndex: "name",
title: "文件名",
dataIndex: 'name',
title: '文件名',
},
{
dataIndex: "size",
title: "文件大小",
dataIndex: 'size',
title: '文件大小',
render: (value, record, index) => {
return eFFormatBytes(value);
return formatBytes(value);
},
},
{
dataIndex: "status",
title: "状态",
dataIndex: 'status',
title: '状态',
render: (value, record, index) => {
switch (value) {
case "success":
return _jsx(Tag, { color: "success", children: t("success") });
case "uploading":
return _jsx(Tag, { color: "processing", children: t("uploading") });
case 'success':
return (_jsx(Tag, { color: "success", children: t('success') }));
case 'uploading':
return (_jsx(Tag, { color: "processing", children: t('uploading') }));
default:
return _jsx(Tag, { color: "warning", children: t("waiting") });
return (_jsx(Tag, { color: "warning", children: t('waiting') }));
}
},
},
{
dataIndex: "op",
dataIndex: 'op',
width: 300,
title: "操作",
align: "center",
title: '操作',
align: 'center',
render: (value, record, index) => {
// 只处理state的文件 这时候可以直接删除
return (_jsx(_Fragment, { children: !record.id && (_jsx(Button, { type: "link", onClick: () => {
customDelete(index);
}, children: "\u5220\u9664" })) }));
},
fixed: "right",
fixed: 'right',
},
] }), _jsx("div", { style: { display: "flex", justifyContent: "flex-end" }, children: _jsxs(Space, { children: [_jsx(Button, { danger: true, type: "default", onClick: () => setNewUploadFiles([]), children: "\u6E05\u7A7A" }), _jsx(Button, { type: "primary", onClick: () => {
] }), _jsx("div", { style: { display: 'flex', justifyContent: 'flex-end' }, children: _jsxs(Space, { children: [_jsx(Button, { danger: true, type: "default", onClick: () => setNewUploadFiles([]), children: "\u6E05\u7A7A" }), _jsx(Button, { type: "primary", onClick: () => {
onPickByWeb(newUploadFiles, (file, status) => {
setNewUploadFilesByStatus(file, status);
});

View File

@ -0,0 +1,16 @@
import { EntityDict } from '../../../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
type ImgMode = 'scaleToFill' | 'aspectFit' | 'aspectFill' | 'widthFix' | "heightFix" | 'top' | 'bottom' | 'left' | 'right' | 'center' | 'top left' | 'top right' | 'bottom left' | 'bottom right';
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
mode: ImgMode;
size: number;
disablePreview: boolean;
disableDownload: boolean;
tag1: string;
tag2: string;
entity: keyof ED2;
entityId: string;
style: string;
}>) => React.ReactElement;
export default _default;

View File

@ -0,0 +1,139 @@
;
export default OakComponent({
entity: 'extraFile',
isList: true,
projection: {
id: 1,
tag1: 1,
tag2: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
fileType: 1,
sort: 1,
isBridge: 1,
uploadState: 1,
},
features: ['extraFile2'],
formData({ data, features }) {
let files = data?.sort((ele1, ele2) => ele1.sort - ele2.sort);
if (this.props.tag1) {
files = files?.filter((ele) => ele?.tag1 === this.props.tag1);
}
if (this.props.tag2) {
files = files?.filter((ele) => ele?.tag2 === this.props.tag2);
}
const files2 = files.map((ele) => {
const url = features.extraFile2.getUrl(ele);
const thumbUrl = features.extraFile2.getUrl(ele, this.props.style);
const fileName = features.extraFile2.getFileName(ele);
return {
url,
thumbUrl,
fileName,
...ele,
};
});
return {
files: files2,
};
},
data: {
// 根据 size 不同,计算的图片显示大小不同
itemSizePercentage: '',
},
wechatMp: {
externalClasses: ['oak-class', 'oak-item-class'],
},
filters: [
{
filter() {
const { tag1, tag2 } = this.props;
const filter1 = {};
if (tag1) {
Object.assign(filter1, { tag1 });
}
if (tag2) {
Object.assign(filter1, { tag2 });
}
return filter1;
},
},
],
properties: {
mode: 'aspectFit',
size: 3,
disablePreview: false,
disableDownload: false,
tag1: '',
tag2: '',
entity: '',
entityId: '',
style: '',
},
methods: {
/**
* 获取组件内部节点位置信息单个
* @param component 组件实例
* @param selector {String} css选择器
* @returns boundingClientRect() 回调函数的值
*/
async getNodeRectFromComponent(component, selector) {
return await new Promise((resolve) => {
component
.createSelectorQuery()
.select(selector)
.boundingClientRect((res) => {
resolve(res);
})
.exec();
});
},
/**
// * px 转 rpx
// * @param px 像素值
// */
px2rpx(px) {
const windowWidth = wx.getSystemInfoSync().windowWidth;
return (750 / windowWidth) * px;
},
async onPreviewByMp(event) {
const files = this.state.files;
const { index } = event.currentTarget.dataset;
const imageUrl = files[index].url;
const urls = files?.filter((ele) => !!ele).map((ele) => ele.url);
// 预览图片
if (!this.props.disablePreview) {
const result = await wx.previewImage({
urls: urls,
current: imageUrl,
});
}
},
},
listeners: {
async size(prev, next) {
if (process.env.OAK_PLATFORM === 'wechatMp') {
const size = next.size;
if (!size) {
this.setState({ itemSizePercentage: '' });
return;
}
// 获取 .file-list__container 容器宽度
const res = 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,
});
}
},
},
});

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,61 @@
@import "../../../config/styles/mp/index.less";
@import "../../../config/styles/mp/mixins.less";
.file-list__container {
position: relative;
display: flex;
flex-wrap: wrap;
}
.file-list__item {
position: relative;
width: 220rpx;
padding-bottom: 220rpx;
height: 0;
}
// size 不同时,对应的图片间距设置
// size 仅支持 1-10
each(range(2, 10), {
@valuePlusOne : @value+1;
.file-list__item--@{value}:nth-of-type(n+@{valuePlusOne}) {
margin-top : 20rpx;
}
.file-list__item--@{value}:not(:nth-of-type(@{value}n+1)) {
margin-left : 20rpx;
}
}) // 当 size 为 null每行会显示 3 张图片
.file-list__item--null:nth-of-type(n+4) {
margin-top: 20rpx;
}
.file-list__item--null:not(:nth-of-type(3n+1)) {
margin-left: 20rpx;
}
.file-list__image {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 1rpx solid #eee;
border-radius: 4rpx;
}
.file-list__item--selected {
width: 100%;
height: 100%;
z-index: 10;
background-color: #000;
filter: Alpha(Opacity=50);
opacity: 0.5;
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}

View File

@ -0,0 +1,9 @@
<view class="file-list__container oak-class">
<block wx:for="{{files}}" wx:key="index">
<block wx:if="{{item}}">
<view class="file-list__item file-list__item--{{size}} oak-item-class" style="{{itemSizePercentage?'width:'+itemSizePercentage+'padding-bottom:'+itemSizePercentage:'xxx'}}">
<image data-index="{{index}}" bind:tap="onPreviewByMp" src="{{item.thumbUrl}}" mode="{{mode}}" class="file-list__image"/>
</view>
</block>
</block>
</view>

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,3 @@
.container {
display: flex;
}

View File

@ -0,0 +1,18 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
type ExtraFile = EntityDict['extraFile']['OpSchema'];
interface EnhancedExtraFile extends ExtraFile {
url: string;
thumbUrl: string;
fileFullName: string;
}
export default function render(props: WebComponentProps<EntityDict, 'extraFile', true, {
files: EnhancedExtraFile[];
style?: Record<string, string>;
className?: string;
onDownload?: (file: EnhancedExtraFile) => void;
showUploadList?: boolean;
disableDownload?: boolean;
disablePreview?: boolean;
}, {}>): import("react/jsx-runtime").JSX.Element;
export {};

View File

@ -0,0 +1,15 @@
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useRef } from 'react';
import { Image, ImageViewer, Space } from 'antd-mobile';
export default function render(props) {
const { style, className, onDownload, files = [], disableDownload = false, disablePreview = false, } = props.data;
const { t } = props.methods;
const [visible, setVisible] = useState(false);
const imageViewerMultiRef = useRef(null);
return (_jsxs(_Fragment, { children: [_jsx(Space, { children: files?.map((ele, index) => (_jsx(Image, { src: ele.thumbUrl, width: 100, height: 100, fit: "contain", onClick: !disablePreview ? () => {
setVisible(true);
imageViewerMultiRef.current.swipeTo(index);
} : undefined }))) }), _jsx(ImageViewer.Multi, { ref: imageViewerMultiRef, images: files?.map((ele) => ele.url) || [], visible: visible, onClose: () => {
setVisible(false);
} })] }));
}

View File

@ -0,0 +1,3 @@
.container {
display: flex;
}

View File

@ -0,0 +1,18 @@
import { WebComponentProps } from "oak-frontend-base";
import { EntityDict } from "../../../oak-app-domain";
type ExtraFile = EntityDict['extraFile']['OpSchema'];
interface EnhancedExtraFile extends ExtraFile {
url: string;
thumbUrl: string;
fileFullName: string;
}
export default function render(props: WebComponentProps<EntityDict, 'extraFile', true, {
files: EnhancedExtraFile[];
style?: Record<string, string>;
className?: string;
onDownload?: (file: EnhancedExtraFile) => void;
showUploadList?: boolean;
disableDownload?: boolean;
disablePreview?: boolean;
}, {}>): import("react/jsx-runtime").JSX.Element;
export {};

View File

@ -0,0 +1,14 @@
import { jsx as _jsx } from "react/jsx-runtime";
import { Image, Space } from 'antd';
;
export default function render(props) {
const { style, className, onDownload, files = [], disableDownload = false, disablePreview = false, } = props.data;
const { t } = props.methods;
return (_jsx(Image.PreviewGroup, { preview: {
onChange: (current, prev) => { },
}, children: _jsx(Space, { children: files?.map((ele) => (_jsx(Image, { width: 120, src: ele.thumbUrl, preview: !disablePreview
? {
src: ele.url,
}
: true, fallback: "data:image/png;base64,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" }))) }) }));
}

View File

@ -6,13 +6,12 @@ type ExtraFile = EntityDict['extraFile']['OpSchema'];
export interface EnhancedExtraFile extends ExtraFile {
url: string;
thumbUrl: string;
filename: string;
fileName: string;
fileState?: FileState;
percentage?: number;
}
type SourceType = 'album' | 'camera';
export type Theme = 'file' | 'image' | 'image-flow' | 'custom';
type FileType = 'all' | 'video' | 'image' | 'file';
type ImgMode = 'scaleToFill' | 'aspectFit' | 'aspectFill' | 'widthFix' | "heightFix" | 'top' | 'bottom' | 'left' | 'right' | 'center' | 'top left' | 'top right' | 'bottom left' | 'bottom right';
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
bucket: string;
@ -20,15 +19,15 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
autoUpload: boolean;
maxNumber: number;
extension: string[];
fileType: FileType;
selectCount: number;
sourceType: SourceType[];
mediaType: ('image' | 'video')[];
mode: ImgMode;
size: number;
showUploadList: boolean;
showUploadProgress: boolean;
accept: string;
preview: boolean;
disablePreview: boolean;
disableDelete: boolean;
disableAdd: boolean;
disableDownload: boolean;
@ -40,7 +39,6 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
entity: keyof ED2;
entityId: string;
theme: Theme;
showUploadProgress: boolean;
children?: React.ReactNode;
}>) => React.ReactElement;
export default _default;

View File

@ -26,7 +26,7 @@ export default OakComponent({
itemSizePercentage: '',
},
wechatMp: {
externalClasses: ['oak-class', 'oak-item-class'],
externalClasses: ['oak-class', 'oak-item-class', 'oak-item-add-class'],
},
filters: [
{
@ -49,32 +49,25 @@ export default OakComponent({
autoUpload: false,
maxNumber: 20,
extension: [],
fileType: 'all',
selectCount: 1,
sourceType: ['album', 'camera'],
mediaType: ['image'],
// 图片显示模式
mode: 'aspectFit',
// 每行可显示的个数
size: 3,
showUploadList: true,
showUploadProgress: false,
accept: 'image/*',
// 图片是否可预览
preview: true,
// 图片是否可删除
disablePreview: false,
disableDelete: false,
// 上传按钮隐藏
disableAdd: false,
// 下按按钮隐藏
disableDownload: false,
type: 'file',
type: 'image',
origin: 'qiniu',
tag1: '',
tag2: '',
entity: '',
entityId: '',
theme: 'image',
showUploadProgress: false,
},
listeners: {
maxNumber(prev, next) {
@ -104,22 +97,29 @@ export default OakComponent({
},
features: ['extraFile2'],
formData({ data, features }) {
const files = data.map(ele => {
let files = data?.sort((ele1, ele2) => ele1.sort - ele2.sort);
if (this.props.tag1) {
files = files?.filter((ele) => ele?.tag1 === this.props.tag1);
}
if (this.props.tag2) {
files = files?.filter((ele) => ele?.tag2 === this.props.tag2);
}
const files2 = files.map((ele) => {
const url = features.extraFile2.getUrl(ele);
const thumbUrl = features.extraFile2.getUrl(ele, 'thumbnail');
const fileState = features.extraFile2.getFileState(ele.id);
const filename = features.extraFile2.getFileName(ele);
const fileName = features.extraFile2.getFileName(ele);
return {
url,
thumbUrl,
filename,
fileName,
fileState: fileState?.state,
percentage: fileState?.percentage,
...ele,
};
});
return {
files,
files: files2,
};
},
methods: {
@ -128,16 +128,17 @@ export default OakComponent({
this.features.extraFile2.removeLocalFiles([file.id]);
},
addExtraFileInner(options, file) {
const { type, origin, tag1, tag2, entity, entityId, bucket } = this.props;
const { type, origin = 'qiniu', // 默认qiniu
tag1, tag2, entity, entityId, bucket, } = this.props;
const { name, fileType, size } = options;
const extension = name.substring(name.lastIndexOf('.') + 1);
const filename = name.substring(0, name.lastIndexOf('.'));
const { files } = this.state;
const sort = files.length * 10000;
let bucket2 = bucket;
if (!bucket2) {
if (origin === 'qiniu' && !bucket2) {
const context = this.features.cache.begin();
const { config } = getConfig(context, 'Cos', 'qiniu');
const { config } = getConfig(context, 'Cos', origin);
this.features.cache.commit();
const { defaultBucket } = config;
bucket2 = defaultBucket;
@ -169,6 +170,124 @@ export default OakComponent({
fileType: type,
size,
}, file);
}
}
},
// 小程序端
async chooseMediaByMp() {
//图片和视频使用
const { selectCount, mediaType, sourceType } = this.props;
try {
const { errMsg, tempFiles } = await wx.chooseMedia({
count: selectCount,
mediaType,
sourceType,
});
if (errMsg !== 'chooseMedia:ok') {
this.triggerEvent('onError', {
level: 'warning',
msg: errMsg,
});
}
else {
tempFiles.map((tempExtraFile) => {
const { tempFilePath, thumbTempFilePath, fileType, size, } = tempExtraFile;
const filePath = tempFilePath || thumbTempFilePath;
const fileFullName = filePath.match(/[^/]+(?!.*\/)/g)[0];
this.addExtraFileInner({
name: fileFullName,
fileType,
size,
}, filePath);
});
}
}
catch (err) {
if (err.errMsg !== 'chooseMedia:fail cancel') {
this.triggerEvent('onError', {
level: 'error',
msg: err.errMsg,
});
}
}
},
async chooseMessageFileByMp() {
const { selectCount, extension } = this.props;
try {
const { errMsg, tempFiles } = await wx.chooseMessageFile({
count: selectCount,
type: 'all',
extension,
});
if (errMsg !== 'chooseMessageFile:ok') {
this.triggerEvent('onError', {
level: 'warning',
msg: errMsg,
});
}
else {
tempFiles.map((tempExtraFile) => {
const { path, type, size, name } = tempExtraFile;
this.addExtraFileInner({
name,
fileType: type,
size,
}, path);
});
}
}
catch (err) {
if (err.errMsg !== 'chooseMessageFile:fail cancel') {
this.triggerEvent('onError', {
level: 'error',
msg: err.errMsg,
});
}
}
},
async addFileByMp(evt) {
const { type } = this.props;
//小程序 根据type类型调用api
if (['image', 'video'].includes(type)) {
this.chooseMediaByMp();
}
else {
this.chooseMessageFileByMp();
}
},
onRemoveByMp(event) {
const { value } = event.currentTarget.dataset;
this.onRemove(value);
},
async onPreviewByMp(event) {
const files = this.state.files;
const { index } = event.currentTarget.dataset;
const imageUrl = files[index].url;
const urls = files?.filter((ele) => !!ele).map((ele) => ele.url);
const detail = {
all: files,
index,
urls,
current: imageUrl,
};
// 预览图片
if (!this.props.disablePreview) {
const result = await wx.previewImage({
urls: urls,
current: imageUrl,
});
this.triggerEvent('onPreview', detail);
}
},
//检查排序是否超过上限
checkSort(sort) {
const reg = /^\d+\.(?:9+)$/;
if (reg.test(sort.toString())) {
this.setMessage({
type: 'warning',
content: this.t('dragSort'),
});
return false;
}
return true;
},
},
});

View File

@ -0,0 +1,152 @@
@import "../../../config/styles/mp/index.less";
@import "../../../config/styles/mp/mixins.less";
.file-list__container {
position: relative;
display: flex;
flex-wrap: wrap;
}
.file-list__item {
position: relative;
width: 220rpx;
padding-bottom: 220rpx;
height: 0;
}
// size 不同时,对应的图片间距设置
// size 仅支持 1-10
each(range(2, 10), {
@valuePlusOne : @value+1;
.file-list__item--@{value}:nth-of-type(n+@{valuePlusOne}) {
margin-top : 20rpx;
}
.file-list__item--@{value}:not(:nth-of-type(@{value}n+1)) {
margin-left : 20rpx;
}
}) // 当 size 为 null每行会显示 3 张图片
.file-list__item--null:nth-of-type(n+4) {
margin-top: 20rpx;
}
.file-list__item--null:not(:nth-of-type(3n+1)) {
margin-left: 20rpx;
}
.file-list__image {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 1rpx solid #eee;
border-radius: 4rpx;
}
.file-list__item--selected {
width: 100%;
height: 100%;
z-index: 10;
background-color: #000;
filter: Alpha(Opacity=50);
opacity: 0.5;
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
.file-list__remove {
position: absolute;
right: 10rpx;
top: 10rpx;
height: 40rpx;
width: 40rpx;
border-radius: 50%;
background: rgb(0 0 0 / 40%);
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.file-list__item--add {
border: 1rpx solid #eee;
border-radius: 4rpx;
background-color: white;
}
.file-list__image--add {
visibility: hidden;
position: absolute;
width: 50%;
height: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
align-items: center;
justify-content: center;
display: flex;
}
.file-list__item-slot-wrapper {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.file-list__item-slot-wrapper:empty+.file-list__image--add {
visibility: visible;
}
.file-list-flow__container {
position: relative;
display: flex;
flex-direction: column;
}
.file-list-flow__item {
display: flex;
flex-direction: row;
align-items: center;
margin: 10rpx 10rpx 10rpx 0;
}
.file-list-flow__item--name {
display: flex;
flex-direction: row;
fleX: 1;
font-size: 28rpx;
}
.file-list-flow__item--btns {
display: flex;
flex-direction: row;
}
.file-list-flow__download {
width: 48rpx;
height: 48rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.file-list-flow__remove {
width: 48rpx;
height: 48rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

View File

@ -0,0 +1,47 @@
<block wx:if="{{ type === 'image' }}">
<view class="file-list__container oak-class">
<block wx:for="{{files}}" wx:key="index">
<block wx:if="{{item}}">
<view class="file-list__item file-list__item--{{size}} oak-item-class" style="{{itemSizePercentage?'width:'+itemSizePercentage+'padding-bottom:'+itemSizePercentage:'xxx'}}">
<image data-index="{{index}}" bind:tap="onPreviewByMp" src="{{item.url}}" mode="{{mode}}" class="file-list__image"/>
<view wx:if="{{!disableDelete}}" mut-bind:tap="onRemoveByMp" class="file-list__remove" data-value="{{item}}">
<l-icon name="close" color="#ffffff" size="18" />
</view>
</view>
</block>
</block>
<view class="file-list__item file-list__item--add file-list__item--{{size}} oak-item-add-class" style="{{itemSizePercentage?'width:'+itemSizePercentage+'padding-bottom:'+itemSizePercentage:''}}" wx:if="{{!disableInsert && !disableAdd}}" bind:tap="addFileByMp">
<view class="file-list__item-slot-wrapper">
<slot />
</view>
<view class="file-list__image--add">
<l-icon name="add" size="80" />
</view>
</view>
</view>
</block>
<block wx:else >
<view class="file-list-flow__container oak-class">
<view class="file-list-flow__item--add oak-item-add-class" wx:if="{{!disableInsert && !disableAdd}}">
<l-button bind:lintap="addFileByMp" plain="{{true}}" type="default">{{ t('chooseFile') }}</l-button>
</view>
<block wx:for="{{files}}" wx:key="index">
<block wx:if="{{item}}">
<view class="file-list-flow__item oak-item-class">
<view class="file-list-flow__item--name" mut-bind:tap="onOpenByMp" data-value="{{item}}">
{{ item.fileName }}
</view>
<view class="file-list-flow__item--btns">
<!-- <view wx:if="{{!disableDownload}}" mut-bind:tap="onDownloadByMp" class="file-list-flow__download" data-value="{{item}}">
<l-icon name="download" size="36" />
</view> -->
<view wx:if="{{!disableDelete}}" mut-bind:tap="onRemoveByMp" class="file-list-flow__remove" data-value="{{item}}">
<l-icon name="delete" size="36" />
</view>
<view>
</view>
</block>
</block>
</view>
</block>

View File

@ -1,4 +1,5 @@
{
"choosePicture": "请选择图片",
"chooseFile": "请选择文件"
"chooseFile": "请选择文件",
"dragSort": "当前拖拽排序值超过上限范围"
}

View File

@ -10,7 +10,7 @@ export default function render(props: WebComponentProps<EntityDict, 'extraFile',
draggable?: boolean;
theme?: Theme;
tips?: string;
beforeUpload?: (file: File) => Promise<boolean>;
beforeUpload?: (file: File) => Promise<boolean> | boolean;
style?: Record<string, string>;
className?: string;
directory?: boolean;
@ -21,8 +21,9 @@ export default function render(props: WebComponentProps<EntityDict, 'extraFile',
disableInsert?: boolean;
disableDownload?: boolean;
disableDelete?: boolean;
preview?: boolean;
disablePreview?: boolean;
}, {
onRemove: (file: UploadFile) => void;
addFileByWeb: (file: UploadFile) => void;
checkSort: (sort: number) => boolean;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -17,8 +17,8 @@ function getListType(theme) {
};
return themeMap[theme];
}
const type = "DragableUploadList";
const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const type = "DraggableUploadList";
const DraggableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const ref = React.useRef(null);
const index = fileList.indexOf(file);
const [{ isOver, dropClassName }, drop] = useDrop({
@ -48,14 +48,14 @@ const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
return (_jsx("div", { ref: ref, className: `ant-upload-draggable-list-item ${isOver ? dropClassName : ""}`, style: { cursor: "move", height: "100%" }, children: originNode }));
};
export default function render(props) {
const { accept = "image/*", maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = "image", tips, beforeUpload, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files = [], disableInsert = false, disableDownload = false, disableDelete = false, preview = true, } = props.data;
const { t, onRemove, addFileByWeb } = props.methods;
const { accept = 'image/*', maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = 'image', tips, beforeUpload, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files = [], disableInsert = false, disableDownload = false, disableDelete = false, disablePreview = false, } = props.data;
const { t, updateItem, onRemove, addFileByWeb, checkSort } = props.methods;
const listType = getListType(theme);
const getUploadButton = () => {
if (children) {
return children;
}
if (listType === "picture-card") {
if (listType === 'picture-card') {
return (_jsxs("div", { children: [_jsx(PlusOutlined, {}), _jsx("div", { style: { marginTop: 8 }, children: t('choosePicture') })] }));
}
return _jsx(Button, { type: "default", children: t('chooseFile') });
@ -107,23 +107,53 @@ export default function render(props) {
return {
...file,
status,
name: file.filename,
name: file.fileName,
uid: file.id,
size: file.size,
fileName: file.fileName,
};
});
};
const moveRow = useCallback((dragIndex, hoverIndex) => {
console.log('dragIndex', dragIndex, 'hoverIndex', hoverIndex);
const dragRow = files[dragIndex];
let sort;
if (hoverIndex === dragIndex) {
return;
}
else if (hoverIndex > dragIndex) {
if (hoverIndex === files.length - 1) {
sort = files[hoverIndex].sort + 100;
}
else {
sort =
(files[hoverIndex].sort +
files[hoverIndex + 1].sort) /
2;
}
}
else {
if (hoverIndex === 0) {
sort = files[hoverIndex].sort / 2;
}
else {
sort =
(files[hoverIndex].sort +
files[hoverIndex - 1].sort) /
2;
}
}
if (checkSort(sort)) {
updateItem({ sort }, dragRow.id);
}
}, [files]);
return (_jsxs(Space, { direction: "vertical", className: Style["oak-upload"], style: { width: "100%" }, children: [_jsx(DndProvider, { backend: isPc ? HTML5Backend : TouchBackend, children: _jsx(Upload, { className: classNames(Style["oak-upload__upload"], className), style: style, directory: directory, showUploadList: showUploadList
return (_jsxs(Space, { direction: "vertical", className: Style['oak-upload'], style: { width: '100%' }, children: [_jsx(DndProvider, { backend: isPc ? HTML5Backend : TouchBackend, children: _jsx(Upload, { className: classNames(Style['oak-upload__upload'], className), style: style, directory: directory, showUploadList: showUploadList
? {
showPreviewIcon: preview,
showPreviewIcon: !disablePreview,
showRemoveIcon: !disableDelete,
showDownloadIcon: !disableDownload,
}
: false, beforeUpload: async (file) => {
if (typeof beforeUpload === "function") {
if (typeof beforeUpload === 'function') {
const result = await beforeUpload(file);
if (result) {
return false;
@ -135,6 +165,8 @@ export default function render(props) {
addFileByWeb(file);
}
}, onRemove: onRemove, onPreview: onPreview, onDownload: onDownload, itemRender: (originNode, currentFile, currentFileList) => {
return (_jsx(DragableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && files.length < maxNumber ? getUploadButton() : null }) }), tips && _jsx("small", { className: Style["oak-upload__tips"], children: tips })] }));
return (_jsx(DraggableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && files.length < maxNumber
? getUploadButton()
: null }) }), tips && (_jsx("small", { className: Style['oak-upload__tips'], children: tips }))] }));
}

View File

@ -6,6 +6,7 @@ export default OakComponent({
entity: 1,
entityId: 1,
lmts: 1,
openId: 1,
user: {
id: 1,
name: 1,
@ -137,7 +138,7 @@ export default OakComponent({
}
},
getName() {
const { user, entity } = this.state;
const { user, entity, openId } = this.state;
const { entityFilter } = this.props;
if (entityFilter) {
const userName = user?.name;
@ -150,6 +151,9 @@ export default OakComponent({
if (userMobile) {
return '用户' + userMobile;
}
if (openId) {
return '微信用户' + openId;
}
return userNickname;
}
else {

View File

@ -8,6 +8,7 @@ export default function render(props: WebComponentProps<EntityDict, 'session', f
selectedId: string;
onSelect: (id: string) => void;
name: string;
lmts: number;
}, {
getName: () => string;
getAvatarUrl: () => string;

View File

@ -5,22 +5,21 @@ import classNames from 'classnames';
import Style from './web.module.less';
export default function render(props) {
const { methods, data } = props;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], name, } = data;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], name, lmts, } = data;
const { t, getName, getAvatarUrl } = methods;
const sessiontMessage = sessiontMessages && sessiontMessages[0];
const createAt = sessiontMessage?.$$createAt$$;
const type = sessiontMessage?.type;
const text = sessiontMessage?.text;
const today = dayjs().startOf('day').valueOf();
const createAt2 = createAt && dayjs(createAt).startOf('day').valueOf();
const createAt2 = lmts && dayjs(lmts).startOf('day').valueOf();
return (_jsxs("div", { className: classNames(Style.cell, {
[Style.cell_selected]: id === selectedId,
}), onClick: () => {
onSelect(id);
}, children: [_jsx(Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: _jsx(Image, { className: Style.avatar, src: getAvatarUrl(), preview: false }) }), _jsxs("div", { className: Style.inner, children: [_jsxs("div", { className: Style.top, children: [_jsx("div", { className: Style.title, children: name || getName() }), _jsx("div", { className: Style.date, children: sessiontMessage &&
}, children: [_jsx(Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: _jsx(Image, { className: Style.avatar, src: getAvatarUrl(), preview: false }) }), _jsxs("div", { className: Style.inner, children: [_jsxs("div", { className: Style.top, children: [_jsx("div", { className: Style.title, children: name || getName() }), _jsx("div", { className: Style.date, children: lmts &&
(today === createAt2
? dayjs(createAt).format('HH:mm')
: dayjs(createAt).format('YYYY-MM-DD')) })] }), _jsx("div", { className: Style.message, children: type &&
? dayjs(lmts).format('HH:mm')
: dayjs(lmts).format('YYYY-MM-DD')) })] }), _jsx("div", { className: Style.message, children: type &&
(type === 'text'
? `${text}`
: `[${t(`sessiontMessage:v.type.${type}`)}消息]`) })] })] }));

View File

@ -2,5 +2,7 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
sessionId: string;
isEntity: boolean;
entityDisplay: (data: any) => any[];
entityProjection: any;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -93,9 +93,12 @@ export default OakComponent({
properties: {
sessionId: '',
isEntity: false,
entityDisplay: (data) => [],
entityProjection: {}, // user端指示需要取哪些entity的属性来显示entityDisplay
},
methods: {
getSession(sessionId) {
const { entityProjection } = this.props;
const [session] = this.features.cache.get('session', {
data: {
id: 1,
@ -132,6 +135,7 @@ export default OakComponent({
},
},
},
...entityProjection,
},
filter: {
id: sessionId
@ -152,7 +156,7 @@ export default OakComponent({
},
getName() {
const { session, entity } = this.state;
const { isEntity } = this.props;
const { isEntity, entityDisplay } = this.props;
if (isEntity) {
const userName = session?.user?.name;
const userNickname = session?.user?.name || session?.user?.nickname;
@ -167,6 +171,10 @@ export default OakComponent({
return userNickname;
}
else {
if (entityDisplay && session) {
const sessions = entityDisplay([session]);
return sessions[0]?.name;
}
return '未知';
}
},

View File

@ -2,7 +2,7 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "session", true, {
entity: string;
entityFilter: any;
entityDisplay: (data: any) => "";
entityDisplay: (data: any) => any[];
entityProjection: any;
sessionId: string;
dialog: boolean;

View File

@ -1,3 +1,4 @@
import { DATA_SUBSCRIBER_KEYS } from '../../../config/constants';
export default OakComponent({
entity: 'session',
projection() {
@ -6,6 +7,8 @@ export default OakComponent({
id: 1,
entity: 1,
entityId: 1,
lmts: 1,
openId: 1,
userId: 1,
user: {
id: 1,
@ -83,8 +86,9 @@ export default OakComponent({
// const unReadLength = wechatSessions?.filter(
// (ele) => ele.isRead
// )
//排序待框架实现
return {
sessions,
sessions: sessions?.sort((a, b) => b.lmts - a.lmts),
};
},
lifetimes: {
@ -107,6 +111,22 @@ export default OakComponent({
this.setSelectedSessionId(sessionId);
}
},
async ready() {
const { entityFilter } = this.props;
const userId = this.features.token.getUserId();
await this.subData([
{
entity: 'session',
filter: entityFilter ? { ...entityFilter } : { userId },
id: `${DATA_SUBSCRIBER_KEYS.sessionList}`,
}
], () => { console.log(123); });
},
detached() {
this.unSubData([
`${DATA_SUBSCRIBER_KEYS.sessionList}`
]);
},
},
data: {
unReadLength: 0,
@ -115,7 +135,7 @@ export default OakComponent({
properties: {
entity: '',
entityFilter: undefined,
entityDisplay: (data) => '',
entityDisplay: (data) => [],
entityProjection: {},
sessionId: '',
dialog: false,

View File

@ -6,6 +6,8 @@ export default function Render(props: WebComponentProps<EntityDict, 'session', f
className: string;
dialog: boolean;
entityFilter: object;
entityDisplay: (data: any) => any[];
entityProjection: object;
}, {
setSelectedSessionId: (conversationId: string) => void;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -8,7 +8,7 @@ export default function Render(props) {
const { data, methods } = props;
const { sessions, selectedSessionId, oakFullpath,
// unReadConversation = 0,
entityFilter, dialog = false, className, } = data;
entityFilter, dialog = false, className, entityDisplay, entityProjection, } = data;
const { setSelectedSessionId } = methods;
return (_jsx("div", { className: Style.container, children: _jsxs("div", { className: classNames(Style.bothContainer, className, {
[Style.dialogContainer]: dialog,
@ -20,7 +20,7 @@ export default function Render(props) {
: '' }, session.id));
}) })] }), selectedSessionId && (_jsx(MessageList, { sessionId: selectedSessionId,
// isCombine={true}
isEntity: entityFilter ? true : false, isUser: entityFilter ? false : true, oakAutoUnmount: true, oakPath: oakFullpath
isEntity: entityFilter ? true : false, isUser: entityFilter ? false : true, oakAutoUnmount: true, entityDisplay: entityDisplay, entityProjection: entityProjection, oakPath: oakFullpath
? `$$sessionMessage/list`
: undefined }))] }) }));
}

View File

@ -1,4 +1,3 @@
// import { Schema as ExtraFile } from '../../../
export default OakComponent({
entity: 'sessionMessage',
isList: false,
@ -91,13 +90,12 @@ export default OakComponent({
userAvatar: this.features.extraFile.getUrl(session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]),
};
// if (type === 'image') {
// const extraFile$entity =
// wechatMessage?.extraFile$entity as ExtraFile[];
// Object.assign(newWechatMessage, {
// picUrl: features.extraFile.getUrl(extraFile$entity[0]),
// });
// }
if (type === 'image') {
const extraFile$entity = sessionMessage?.extraFile$entity;
Object.assign(newSessionMessage, {
picUrl: features.extraFile.getUrl(extraFile$entity && extraFile$entity[0]),
});
}
return newSessionMessage;
},
properties: {

View File

@ -7,5 +7,7 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
dialog: boolean;
entity: string;
entityId: string;
entityDisplay: (data: any) => any[];
entityProjection: any;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -1,5 +1,6 @@
import { generateNewId } from 'oak-domain/lib/utils/uuid';
import { DATA_SUBSCRIBER_KEYS } from '../../../config/constants';
import { getConfig } from '../../../utils/getContextConfig';
export default OakComponent({
entity: 'sessionMessage',
projection: {
@ -8,6 +9,7 @@ export default OakComponent({
type: 1,
userId: 1,
wechatUserId: 1,
applicationId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
@ -43,40 +45,18 @@ export default OakComponent({
lifetimes: {
async ready() {
const { sessionId } = this.props;
await this.subData([
this.subData([
{
entity: 'sessionMessage',
filter: {
sessionId: sessionId,
},
id: `${DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`,
}
], async () => { await this.pageScroll('comment'); });
// const userId = this.features.token.getUserId(true);
// const applicationId = this.features.application.getApplicationId();
// if (!sessionId) {
// const entity = 'application';
// const entityId = applicationId;
// const type = 'web';
// const { result: newSessionId } = await this.features.cache.exec('createSession', { type, entity, entityId });
// this.setState({
// newSessionId,
// })
// }
// if (!userId) {
// this.redirectTo(
// {
// url: '/login',
// backUrl: encodeURIComponent(window.location.href),
// },
// undefined,
// true
// );
// return;
// }
// (this as any).timer = setInterval(() => {
// this.refresh();
// }, 2000);
},
], async () => {
await this.pageScroll('comment');
});
this.createItem();
this.getConversationInfo();
},
detached() {
@ -85,34 +65,42 @@ export default OakComponent({
}
const { sessionId } = this.props;
this.unSubData([
`${DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`
`${DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`,
]);
},
},
listeners: {
num(prev, next) {
if (prev.num !== next.num) {
if (next.num > 0 && next.num <= 20) {
this.pageScroll('comment');
}
this.pageScroll('comment');
}
},
sessionId(prev, next) {
if (this.state.oakFullpath) {
if (prev.sessionId !== next.sessionId) {
if (next.sessionId) {
const { sessionMessageId } = this.state;
this.getConversationInfo();
// 如果sessionId变了需要重新刷新下
this.refresh();
this.removeItem(sessionMessageId);
this.setState({
text: '',
});
this.createItem();
this.pageScroll('comment');
}
}
}
},
},
formData({ data: sessionMessageList = [], features }) {
const sessionMessageType = sessionMessageList?.find((ele) => ele.$$createAt$$ === 1)?.type;
this.getUserLastMessage();
return {
sessionMessageList,
num: sessionMessageList?.length,
sessionMessageType,
};
},
properties: {
@ -122,6 +110,8 @@ export default OakComponent({
dialog: false,
entity: '',
entityId: '',
entityDisplay: (data) => [],
entityProjection: {}, // user端指示需要取哪些entity的属性来显示entityDisplay
},
filters: [
{
@ -129,9 +119,6 @@ export default OakComponent({
const { sessionId } = this.props;
return {
sessionId,
// type: {
// $exists: true,
// },
};
},
},
@ -153,10 +140,49 @@ export default OakComponent({
newSessionId: '',
},
methods: {
getUserLastMessage() {
const { sessionId } = this.props;
const [lastMessage] = this.features.cache.get('sessionMessage', {
data: {
id: 1,
sessionId: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
applicationId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
filter: {
sessionId,
aaoe: false,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
count: 1,
});
const isWeChat = !!lastMessage?.wechatUserId;
console.log(lastMessage);
this.setState({ isWeChat });
},
setContent(text) {
const { sessionMessageId } = this.state;
console.log(sessionMessageId);
this.setState({
text,
});
this.updateItem({
text,
type: 'text',
}, sessionMessageId);
},
setButtonHidden(isHidden) {
this.setState({
@ -222,8 +248,24 @@ export default OakComponent({
const doc = window.document.getElementById(id);
setTimeout(() => doc.scrollTo(0, 10000), 500);
},
async createItem() {
const { text, wechatUserId } = this.state;
const { sessionId, isEntity } = this.props;
const userId = this.features.token.getUserId();
const applicationId = this.features.application.getApplicationId();
const sessionMessageId = this.addItem({
applicationId,
userId,
wechatUserId,
sessionId: sessionId,
aaoe: isEntity,
});
this.setState({
sessionMessageId,
});
},
async createMessage() {
const { text, wechatUserId, newSessionId } = this.state;
const { text, wechatUserId, newSessionId, sessionMessageId } = this.state;
const { sessionId, isEntity } = this.props;
const userId = this.features.token.getUserId();
const applicationId = this.features.application.getApplicationId();
@ -234,67 +276,83 @@ export default OakComponent({
});
return;
}
this.addItem({
applicationId,
text,
userId,
wechatUserId,
sessionId: sessionId || newSessionId,
type: 'text',
// this.addItem({
// applicationId,
// text,
// userId,
// wechatUserId,
// sessionId: sessionId || newSessionId,
// type: 'text',
// createTime: Date.now(),
// aaoe: isEntity,
// } as EntityDict['sessionMessage']['CreateSingle']['data']);
this.updateItem({
createTime: Date.now(),
aaoe: isEntity,
});
}, sessionMessageId);
await this.execute(undefined, false);
this.setState({
text: '',
});
this.pageScroll('comment');
this.createItem();
},
async customUpload(file) {
const { sessionId } = this.props;
const { sessionId, isEntity } = this.props;
// TS 语法
// file 即选中的文件
const { name, size, type, originFileObj } = file;
const applicationId = this.features.application.getApplicationId();
const extension = name.substring(name.lastIndexOf('.') + 1);
const filename = name.substring(0, name.lastIndexOf('.'));
let bucket2 = '';
if (!bucket2) {
const context = this.features.cache.begin();
const { config } = getConfig(context, 'Cos', 'qiniu');
this.features.cache.commit();
const { defaultBucket } = config;
bucket2 = defaultBucket;
}
const extraFile = {
extra1: originFileObj,
applicationId,
bucket: bucket2,
origin: 'qiniu',
type: 'image',
tag1: 'image',
objectId: generateNewId(),
filename,
fileType: type,
size,
extension,
entity: 'sessionMessage',
bucket: '',
id: generateNewId(),
};
// try {
// // 自己实现上传,并得到图片 url alt href
// const { url, bucket } = await this.features.extraFile.upload(
// extraFile
// );
// extraFile.bucket = bucket;
// extraFile.extra1 = null;
// const userId = this.features.token.getUserId();
// this.addItem({
// id: generateNewId(),
// sessionId,
// type: 'image',
// extraFile$entity: [
// {
// id: generateNewId(),
// action: 'create',
// data: extraFile,
// },
// ],
// } as EntityDict['sessionMessage']['CreateSingle']['data']);
// await this.execute(undefined, false);
// } catch (err) {
// throw err;
// }
try {
// await this.features.extraFile.upload(
// extraFile,
// originFileObj
// );
const userId = this.features.token.getUserId();
this.addItem({
id: generateNewId(),
applicationId,
sessionId,
createTime: Date.now(),
aaoe: isEntity,
type: 'image',
extraFile$entity: [
{
id: generateNewId(),
action: 'create',
data: extraFile,
},
],
});
this.features.extraFile2.addLocalFile(extraFile?.id, originFileObj);
await this.execute(undefined, false);
this.features.extraFile2.upload(extraFile?.id);
}
catch (err) {
throw err;
}
},
},
});

View File

@ -14,6 +14,11 @@ export default function Render(props: WebComponentProps<EntityDict, 'sessionMess
isEntity: boolean;
isUser: boolean;
employerId: string;
sessionMessageType: string;
sessionMessageId: string;
entityDisplay: (data: any) => any[];
entityProjection: object;
isWeChat: boolean;
}, {
setButtonHidden: (isHidden: boolean) => void;
customUpload: (file: customFile) => void;

View File

@ -7,7 +7,7 @@ import Header from '../../../components/session/forMessage';
import Style from './web.module.less';
export default function Render(props) {
const { data, methods } = props;
const { sessionId, isEntity, isUser, sessionMessageList, oakFullpath, text, employerId, buttonHidden, } = data;
const { sessionId, isEntity, isUser, sessionMessageList, oakFullpath, text, buttonHidden, sessionMessageType, sessionMessageId, entityDisplay, entityProjection, isWeChat, } = data;
const { setButtonHidden, customUpload, setContent, pageScroll, createMessage, } = methods;
const [bottomHeight, setBottomHeight] = useState(0);
const textareaRef = useRef(null);
@ -58,7 +58,7 @@ export default function Render(props) {
// showBack={false}
sessionId: sessionId, isEntity: isEntity,
// userId={employerId}
oakPath: 'session:header1', oakAutoUnmount: true }), _jsx("div", { className: Style.inner, style: {
oakPath: 'session:header1', oakAutoUnmount: true, entityDisplay: entityDisplay, entityProjection: entityProjection }), _jsx("div", { className: Style.inner, style: {
marginBottom: bottomHeight ? `${bottomHeight}px` : '168px',
}, id: "comment", onClick: () => setButtonHidden(true), children: sessionMessageList
?.sort((a, b) => a.$$createAt$$ -

View File

@ -11,4 +11,5 @@ export declare const LOCAL_STORAGE_KEYS: {
};
export declare const DATA_SUBSCRIBER_KEYS: {
sessionMessageList: string;
sessionList: string;
};

View File

@ -15,4 +15,5 @@ export const LOCAL_STORAGE_KEYS = {
};
export const DATA_SUBSCRIBER_KEYS = {
sessionMessageList: 'sessionM-l',
sessionList: 'session-l',
};

View File

@ -1,11 +1,8 @@
/// <reference types="node" />
import { RuntimeContext } from './RuntimeContext';
import { EntityDict } from '../oak-app-domain';
import { SerializedData } from './FrontendRuntimeContext';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { BackendRuntimeContext as BRC } from 'oak-frontend-base';
import { AsyncRowStore } from 'oak-domain';
import { IncomingHttpHeaders } from 'http';
/**
* general数据结构要求的后台上下文
*/
@ -16,16 +13,10 @@ export declare abstract class BackendRuntimeContext<ED extends EntityDict & Base
protected amIReallyRoot?: boolean;
protected rootMode?: boolean;
private temporaryUserId?;
private initializedMark;
constructor(store: AsyncRowStore<ED, BackendRuntimeContext<ED>>, data?: SerializedData, headers?: IncomingHttpHeaders);
refineOpRecords(): Promise<void>;
setTokenValue(tokenValue: string): Promise<void>;
setApplication(appId: string): Promise<void>;
/**
*
*/
protected initialized(): Promise<void>;
protected initialize(data?: SerializedData): Promise<void>;
initialize(data?: SerializedData): Promise<void>;
getApplicationId(): ED["application"]["Schema"]["id"] | undefined;
getSystemId(): ED["application"]["Schema"]["systemId"] | undefined;
getApplication(): Partial<ED["application"]["Schema"]> | undefined;

View File

@ -17,11 +17,6 @@ export class BackendRuntimeContext extends BRC {
amIReallyRoot;
rootMode;
temporaryUserId;
initializedMark;
constructor(store, data, headers) {
super(store, data, headers);
this.initializedMark = this.initialize(data);
}
async refineOpRecords() {
for (const opRecord of this.opRecords) {
if (opRecord.a === 's') {
@ -101,19 +96,12 @@ export class BackendRuntimeContext extends BRC {
assert(result.length > 0, `构建BackendRuntimeContext对应appId「${appId}」找不到application`);
this.application = result[0];
}
/**
* 异步等待初始化完成
*/
async initialized() {
await super.initialized();
await this.initializedMark;
}
async initialize(data) {
await super.initialize(data);
if (data) {
await this.begin();
const closeRootMode = this.openRootMode();
try {
const { a: appId, t: tokenValue } = data;
const { a: appId, t: tokenValue, rm } = data;
const promises = [];
if (appId) {
promises.push(this.setApplication(appId));
@ -124,12 +112,12 @@ export class BackendRuntimeContext extends BRC {
if (promises.length > 0) {
await Promise.all(promises);
}
closeRootMode();
await this.commit();
if (!rm) {
closeRootMode();
}
}
catch (err) {
closeRootMode();
await this.rollback();
throw err;
}
}

View File

@ -195,6 +195,14 @@ const i18ns = [
"uploading": "上传中"
}
},
{
id: "d30e4a47c1d768d74efae1fade371595",
namespace: "oak-general-business-c-extraFile-gallery2",
language: "zh-CN",
module: "oak-general-business",
position: "src/components/extraFile/gallery2",
data: {}
},
{
id: "a0e4461f6283d6ecd0b6bba64c0560c2",
namespace: "oak-general-business-c-extraFile-upload",
@ -203,7 +211,8 @@ const i18ns = [
position: "src/components/extraFile/upload",
data: {
"choosePicture": "请选择图片",
"chooseFile": "请选择文件"
"chooseFile": "请选择文件",
"dragSort": "当前拖拽排序值超过上限范围"
}
},
{

View File

@ -17,13 +17,6 @@ export declare class ExtraFile<ED extends EntityDict, Cxt extends BackendRuntime
}>;
upload(extraFile: EntityDict['extraFile']['CreateSingle']['data'], file: string | File): Promise<void>;
getUrl(extraFile?: EntityDict['extraFile']['OpSchema'] | EntityDict['extraFile']['Schema'] | null, style?: string): string;
/**
* 使使url时URL.revokeObjectURL释放缓存
*
* @param url 访
* @returns img可访问的url
*/
getBridgeUrl(url: string): Promise<string>;
getFileName(extraFile: EntityDict['extraFile']['OpSchema']): string;
formatBytes(size: number): string;
}

View File

@ -113,21 +113,6 @@ export class ExtraFile extends Feature {
url = cos.composeFileUrl(extraFile, context, style);
return url;
}
/**
* 使用该方法要在使用完url时通过URL.revokeObjectURL释放缓存
*
* @param url 需要桥接访问的图片链接
* @returns 浏览器 img可访问的url
*/
async getBridgeUrl(url) {
const { result } = await this.cache.exec('crossBridge', {
url,
});
const blob = new Blob([result], {
type: 'image/png',
});
return URL.createObjectURL(blob);
}
getFileName(extraFile) {
const name = extraFile.filename +
(extraFile.extension ? `.${extraFile.extension}` : '');

View File

@ -22,13 +22,6 @@ export declare class ExtraFile2<ED extends EntityDict, Cxt extends BackendRuntim
state: FileState;
percentage?: number;
} | undefined;
/**
* 使使url时URL.revokeObjectURL释放缓存
*
* @param url 访
* @returns img可访问的url
*/
getBridgeUrl(url: string): Promise<string>;
getFileName(extraFile: EntityDict['extraFile']['OpSchema']): string;
formatBytes(size: number): string;
}

View File

@ -115,21 +115,6 @@ export class ExtraFile2 extends Feature {
return this.files[id];
}
}
/**
* 使用该方法要在使用完url时通过URL.revokeObjectURL释放缓存
*
* @param url 需要桥接访问的图片链接
* @returns 浏览器 img可访问的url
*/
async getBridgeUrl(url) {
const { result } = await this.cache.exec('crossBridge', {
url,
});
const blob = new Blob([result], {
type: 'image/png',
});
return URL.createObjectURL(blob);
}
getFileName(extraFile) {
const name = extraFile.filename +
(extraFile.extension ? `.${extraFile.extension}` : '');

View File

@ -1,6 +1,7 @@
import { assert } from 'oak-domain/lib/utils/assert';
import { getConfig } from '../getContextConfig';
import { OakUploadException } from '../../types/Exception';
import { OakExternalException } from 'oak-domain';
const QiniuSearchUrl = 'https://rs.qiniuapi.com/stat/EncodedEntryURI';
export default class Qiniu {
name = 'qiniu';
@ -72,16 +73,40 @@ export default class Qiniu {
const { instance, config } = getConfig(context, 'Cos', 'qiniu');
// web环境下访问不了七牛接口用mockData过
const mockData = process.env.OAK_PLATFORM === 'web' ? { fsize: 100 } : undefined;
const result = await instance.getKodoFileStat(extraFile.bucket, key, mockData);
const { fsize } = result;
return fsize > 0;
try {
const result = await instance.getKodoFileStat(extraFile.bucket, key, mockData);
const { fsize } = result;
return fsize > 0;
}
catch (err) {
// 七牛如果文件不存在会抛出status 612的异常
if (err instanceof OakExternalException) {
const data = err.data;
if (data && data.status === 612) {
return false;
}
}
throw err;
}
}
async removeFile(extraFile, context) {
const key = this.formKey(extraFile);
const { instance, config } = getConfig(context, 'Cos', 'qiniu');
// web环境下访问不了七牛接口用mockData过
const mockData = process.env.OAK_PLATFORM === 'web' ? true : undefined;
await instance.removeKodoFile(extraFile.bucket, key, mockData);
try {
await instance.removeKodoFile(extraFile.bucket, key, mockData);
}
catch (err) {
// 七牛如果文件不存在会抛出status 612的异常
if (err instanceof OakExternalException) {
const data = err.data;
if (data && data.status === 612) {
return;
}
}
throw err;
}
}
}
;

View File

@ -32,7 +32,7 @@ async function checkWhetherSuccess(context, applicationId, rows) {
}
}, {});
}
else {
if (failedIds.length > 0) {
await context.operate('extraFile', {
id: await generateNewIdAsync(),
action: 'update',

View File

@ -86,7 +86,8 @@ async function createSession(params, context) {
}
case 'wechatMp':
case 'wechatPublic': {
(0, assert_1.default)(data, '');
(0, assert_1.default)(data);
(0, assert_1.default)(entity === 'application');
const { ToUserName, FromUserName, CreateTime, MsgType,
// Event,
Content,
@ -102,6 +103,22 @@ async function createSession(params, context) {
openId: FromUserName,
}
}, {});
const result = await context.select('session', {
data: {
id: 1,
entity: 1,
entityId: 1,
userId: 1,
lmts: 1,
openId: 1,
},
filter: {
entity: entity,
entityId: entityId,
openId: FromUserName,
}
}, {});
session = result[0];
sessionMessage$session = [
{
id: await (0, uuid_1.generateNewIdAsync)(),
@ -109,8 +126,7 @@ async function createSession(params, context) {
data: {
id: await (0, uuid_1.generateNewIdAsync)(),
applicationId: wechatUser?.applicationId,
// sessionId: session[0]?.id,
wechatUser: wechatUser?.id,
wechatUserId: wechatUser?.id,
createTime: CreateTime,
type: MsgType,
text: Content,
@ -152,6 +168,7 @@ async function createSession(params, context) {
entityId,
userId,
lmts: Date.now(),
openId: data?.FromUserName,
}, sessionMessage$session && { sessionMessage$session }),
}, {
dontCollect: true,

View File

@ -7,6 +7,7 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
type: string;
executeText: string;
buttonProps: {};
afterCommit: () => undefined;
afterCommit: () => void;
beforeCommit: () => true;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -5,7 +5,7 @@ const assert_1 = tslib_1.__importDefault(require("assert"));
exports.default = OakComponent({
formData({ features }) {
const ids = this.getEfIds();
const states = ids.map(id => features.extraFile2.getFileState(id));
const states = ids.map((id) => features.extraFile2.getFileState(id));
let state = 'uploaded';
states.forEach((ele) => {
if (ele) {
@ -28,20 +28,20 @@ exports.default = OakComponent({
type: 'primary',
executeText: '',
buttonProps: {},
afterCommit: () => undefined,
afterCommit: () => { },
beforeCommit: () => true,
},
methods: {
getEfIds() {
const { efPaths } = this.props;
const { oakFullpath } = this.state;
(0, assert_1.default)(efPaths);
(0, assert_1.default)(efPaths && efPaths.length > 0);
if (oakFullpath) {
const ids = efPaths.map((path) => {
const path2 = path ? `${oakFullpath}.${path}` : oakFullpath;
const data = this.features.runningTree.getFreshValue(path2);
if (data) {
return data.map(ele => ele.id);
}
(0, assert_1.default)(data, `efPath为${path}的路径上取不到extraFile数据请设置正确的相对路径`);
return data.map(ele => ele.id);
}).flat().filter(ele => !!ele);
return ids;
}
@ -49,6 +49,7 @@ exports.default = OakComponent({
},
async upload() {
const ids = this.getEfIds();
(0, assert_1.default)(ids.length > 0);
const promises = [];
ids.forEach((id) => {
const fileState = this.features.extraFile2.getFileState(id);
@ -62,7 +63,7 @@ exports.default = OakComponent({
if (promises.length > 0) {
await Promise.all(promises);
}
}
},
},
features: ['extraFile2'],
});

View File

@ -9,7 +9,8 @@ export default function render(props: WebComponentProps<EntityDict, any, true, {
type?: ButtonProps['type'];
executeText?: string;
buttonProps?: ButtonProps;
beforeCommit?: () => Promise<boolean> | boolean;
afterCommit?: () => void;
}, {
upload: () => Promise<void>;
afterCommit?: () => void;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const antd_mobile_1 = require("antd-mobile");
function render(props) {
const { state, oakExecutable, oakExecuting, oakDirty, size, block, type, executeText, buttonProps } = props.data;
const { t, upload, execute, afterCommit } = props.methods;
const disabled = oakExecuting || ['uploading'].includes(state) || (oakExecutable === false && ['uploaded'].includes(state));
const { state, oakExecutable, oakExecuting, oakDirty, size, block, type, executeText, buttonProps, beforeCommit, afterCommit, } = props.data;
const { t, upload, execute } = props.methods;
const disabled = oakExecuting ||
['uploading'].includes(state) ||
(oakExecutable === false && ['uploaded'].includes(state));
let text = executeText || t('common::action.confirm');
if (oakExecuting) {
text = t('executing', { text });
@ -20,6 +22,12 @@ function render(props) {
}
return ((0, jsx_runtime_1.jsx)(antd_mobile_1.Button, { type: type, size: size, block: block, disabled: disabled, onClick: async () => {
if (oakExecutable) {
if (beforeCommit) {
const beforeCommitResult = await beforeCommit();
if (beforeCommitResult === false) {
return;
}
}
await execute();
await upload();
if (afterCommit) {

View File

@ -10,6 +10,7 @@ export default function render(props: WebComponentProps<EntityDict, any, true, {
executeText?: string;
buttonProps?: ButtonProps;
afterCommit?: () => void;
beforeCommit?: () => Promise<boolean> | boolean;
}, {
upload: () => Promise<void>;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const antd_1 = require("antd");
function render(props) {
const { state, oakExecutable, oakExecuting, afterCommit, size, block, type, executeText, buttonProps = {} } = props.data;
const { state, oakExecutable, oakExecuting, size, block, type, executeText, buttonProps = {}, afterCommit, beforeCommit, } = props.data;
const { t, upload, execute } = props.methods;
const disabled = oakExecuting || ['uploading'].includes(state) || (oakExecutable !== true && ['uploaded'].includes(state));
const disabled = oakExecuting ||
['uploading'].includes(state) ||
(oakExecutable !== true && ['uploaded'].includes(state));
let text = executeText || t('common::action.confirm');
if (oakExecuting) {
text = t('executing', { text });
@ -20,6 +22,12 @@ function render(props) {
}
return ((0, jsx_runtime_1.jsx)(antd_1.Button, { type: type, size: size, block: block, disabled: disabled, onClick: async () => {
if (oakExecutable) {
if (beforeCommit) {
const beforeCommitResult = await beforeCommit();
if (beforeCommitResult === false) {
return;
}
}
await execute();
await upload();
if (afterCommit) {

View File

@ -165,7 +165,6 @@ exports.default = OakComponent({
type: 'image',
tag1,
tag2,
objectId: (0, uuid_1.generateNewId)(),
bucket: '',
id: (0, uuid_1.generateNewId)(),
};

View File

@ -3,14 +3,12 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
type SourceType = 'album' | 'camera';
type Theme = 'file' | 'image' | 'image-flow' | 'custom';
type FileType = 'all' | 'video' | 'image' | 'file';
type ImgMode = 'scaleToFill' | 'aspectFit' | 'aspectFill' | 'widthFix' | "heightFix" | 'top' | 'bottom' | 'left' | 'right' | 'center' | 'top left' | 'top right' | 'bottom left' | 'bottom right';
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
removeLater: boolean;
autoUpload: boolean;
maxNumber: number;
extension: string[];
fileType: FileType;
selectCount: number;
sourceType: SourceType[];
mediaType: ('image' | 'video')[];
@ -18,7 +16,7 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
size: number;
showUploadList: boolean;
accept: string;
preview: boolean;
disablePreview: boolean;
disableDelete: boolean;
disableAdd: boolean;
disableDownload: boolean;

View File

@ -2,7 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const uuid_1 = require("oak-domain/lib/utils/uuid");
const assert_1 = tslib_1.__importDefault(require("assert"));
const assert_1 = require("oak-domain/lib/utils/assert");
const index_1 = tslib_1.__importDefault(require("../../../utils/dialog/index"));
exports.default = OakComponent({
entity: 'extraFile',
@ -26,7 +26,9 @@ exports.default = OakComponent({
uploadState: 1,
},
formData({ data: originalFiles, features }) {
let files = originalFiles?.filter((ele) => !ele.$$deleteAt$$).sort((ele1, ele2) => ele1.sort - ele2.sort);
let files = originalFiles
?.filter((ele) => !ele.$$deleteAt$$)
.sort((ele1, ele2) => ele1.sort - ele2.sort);
if (this.props.tag1) {
files = files?.filter((ele) => ele?.tag1 === this.props.tag1);
}
@ -42,7 +44,7 @@ exports.default = OakComponent({
data: {
// 根据 size 不同,计算的图片显示大小不同
itemSizePercentage: '',
fileList: {}
fileList: {},
},
wechatMp: {
externalClasses: ['oak-class', 'oak-item-class'],
@ -67,23 +69,17 @@ exports.default = OakComponent({
autoUpload: false,
maxNumber: 20,
extension: [],
fileType: 'all',
selectCount: 1,
sourceType: ['album', 'camera'],
mediaType: ['image'],
// 图片显示模式
mode: 'aspectFit',
// 每行可显示的个数
size: 3,
showUploadList: true,
showUploadProgress: false,
accept: 'image/*',
// 图片是否可预览
preview: true,
// 图片是否可删除
disablePreview: false,
disableDelete: false,
// 上传按钮隐藏
disableAdd: false,
// 下按按钮隐藏
disableDownload: false,
disabled: false,
type: '',
@ -93,13 +89,14 @@ exports.default = OakComponent({
entity: '',
entityId: '',
theme: 'image',
showUploadProgress: false,
},
methods: {
getUrl(extraFile) {
const { fileList } = this.state;
if (fileList[extraFile?.id]) {
const url = this.features.extraFile.getUrl(Object.assign({}, extraFile, { extra1: fileList[extraFile?.id] }));
const url = this.features.extraFile.getUrl(Object.assign({}, extraFile, {
extra1: fileList[extraFile?.id],
}));
return url;
}
return this.features.extraFile.getUrl(extraFile);
@ -107,7 +104,7 @@ exports.default = OakComponent({
getFileName(extraFile) {
return this.features.extraFile.getFileName(extraFile);
},
eFFormatBytes(value) {
formatBytes(value) {
return this.features.extraFile.formatBytes(value);
},
/**
@ -174,12 +171,12 @@ exports.default = OakComponent({
}
},
async chooseFileByMp() {
const { selectCount, extension, fileType } = this.props;
const { selectCount, extension } = this.props;
try {
const { errMsg, tempFiles } = await wx.chooseMessageFile({
count: selectCount,
type: 'all',
...(fileType === 'file' ? { extension } : {}),
extension,
});
if (errMsg !== 'chooseMessageFile:ok') {
this.triggerEvent('error', {
@ -220,7 +217,9 @@ exports.default = OakComponent({
},
async onPickByWeb(uploadFiles, callback) {
const { files } = this.state;
const currentSort = files?.length ? files[files.length - 1].sort : 0;
const currentSort = files?.length
? files[files.length - 1].sort
: 0;
await Promise.all(uploadFiles.map(async (uploadFile, index) => {
const { name, type, size, originFileObj } = uploadFile;
await this.pushExtraFile({
@ -228,7 +227,7 @@ exports.default = OakComponent({
fileType: type,
size,
extra1: originFileObj,
sort: currentSort + (index + 1) * 100
sort: currentSort + (index + 1) * 100,
}, callback);
}));
},
@ -237,9 +236,8 @@ exports.default = OakComponent({
const { name, extra1, fileType, size, sort } = options;
const extension = name.substring(name.lastIndexOf('.') + 1);
const filename = name.substring(0, name.lastIndexOf('.'));
(0, assert_1.default)(entity, '必须传入entity');
(0, assert_1.default)(origin === 'qiniu', '目前只支持七牛上传'); // 目前只支持七牛上传
const id = (0, uuid_1.generateNewId)();
(0, assert_1.assert)(entity, '必须传入entity');
(0, assert_1.assert)(origin === 'qiniu', '目前只支持七牛上传'); // 目前只支持七牛上传
const updateData = {
origin,
type: type || 'file',
@ -251,9 +249,8 @@ exports.default = OakComponent({
size,
extension,
fileType,
id,
entityId,
sort
sort,
};
// autoUpload为true, 选择直接上传七牛再提交extraFile
if (autoUpload) {
@ -273,16 +270,17 @@ exports.default = OakComponent({
if (callback) {
callback(updateData, 'failed');
}
//todo 保存extraFile失败 需要remove七牛图片
throw error;
}
}
else {
this.addItem(updateData, undefined, async () => {
const id = this.addItem(updateData, undefined, async () => {
await this.features.extraFile.upload(updateData, extra1);
});
this.setState({
fileList: Object.assign(this.state.fileList, { [id]: extra1 })
fileList: Object.assign(this.state.fileList, {
[id]: extra1,
}),
});
}
},
@ -301,7 +299,7 @@ exports.default = OakComponent({
};
this.triggerEvent('tap', detail);
// 预览图片
if (this.props.preview) {
if (!this.props.disablePreview) {
const result = await wx.previewImage({
urls: urls,
current: imageUrl,
@ -320,7 +318,7 @@ exports.default = OakComponent({
[id]: null,
});
this.setState({
fileList
fileList,
});
}
else {
@ -335,7 +333,7 @@ exports.default = OakComponent({
id: null,
});
this.setState({
fileList
fileList,
});
await this.execute();
}
@ -352,7 +350,7 @@ exports.default = OakComponent({
id: null,
});
this.setState({
fileList
fileList,
});
}
else {
@ -367,7 +365,7 @@ exports.default = OakComponent({
id: null,
});
this.setState({
fileList
fileList,
});
await this.execute();
confirm.destroy();

View File

@ -5,14 +5,14 @@ interface NewUploadFile extends UploadFile {
id?: string;
}
type Theme = "file" | "image" | "image-flow" | "custom";
export default function render(props: WebComponentProps<EntityDict, "extraFile", true, {
export default function render(props: WebComponentProps<EntityDict, 'extraFile', true, {
accept?: string;
maxNumber?: number;
multiple?: boolean;
draggable?: boolean;
theme?: Theme;
tips?: string;
beforeUpload?: (file: File) => Promise<boolean>;
beforeUpload?: (file: File) => Promise<boolean> | boolean;
disabled?: boolean;
style?: Record<string, string>;
className?: string;
@ -21,17 +21,17 @@ export default function render(props: WebComponentProps<EntityDict, "extraFile",
onDownload?: (file: UploadFile<any>) => void;
showUploadList?: boolean;
children?: JSX.Element;
files?: EntityDict["extraFile"]["OpSchema"][];
files?: EntityDict['extraFile']['OpSchema'][];
disableInsert?: boolean;
disableAdd?: boolean;
disableDownload?: boolean;
disableDelete?: boolean;
preview?: boolean;
disablePreview?: boolean;
}, {
onPickByWeb: (files: UploadFile[], callback?: (file: NewUploadFile, status: string) => void) => void;
onDeleteByWeb: (file: UploadFile) => void;
getUrl: (extraFile: EntityDict['extraFile']['OpSchema']) => string;
getFileName: (extraFile: EntityDict['extraFile']['OpSchema']) => string;
eFFormatBytes: (value: number) => string;
formatBytes: (value: number) => string;
}>): import("react/jsx-runtime").JSX.Element;
export {};

View File

@ -21,8 +21,8 @@ function getListType(theme) {
};
return themeMap[theme];
}
const type = "DragableUploadList";
const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const type = 'DraggableUploadList';
const DraggableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const ref = react_1.default.useRef(null);
const index = fileList.indexOf(file);
const [{ isOver, dropClassName }, drop] = (0, react_dnd_1.useDrop)({
@ -34,7 +34,9 @@ const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
}
return {
isOver: monitor.isOver(),
dropClassName: dragIndex < index ? " drop-over-downward" : " drop-over-upward",
dropClassName: dragIndex < index
? ' drop-over-downward'
: ' drop-over-upward',
};
},
drop: (item) => {
@ -49,11 +51,11 @@ const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
}),
});
drop(drag(ref));
return ((0, jsx_runtime_1.jsx)("div", { ref: ref, className: `ant-upload-draggable-list-item ${isOver ? dropClassName : ""}`, style: { cursor: "move", height: "100%" }, children: originNode }));
return ((0, jsx_runtime_1.jsx)("div", { ref: ref, className: `ant-upload-draggable-list-item ${isOver ? dropClassName : ''}`, style: { cursor: 'move', height: '100%' }, children: originNode }));
};
function render(props) {
const { accept = "image/*", maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = "image", tips, beforeUpload, disabled, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files, disableInsert = false, disableAdd = false, disableDownload = false, disableDelete = false, preview = true, } = props.data;
const { onPickByWeb, onDeleteByWeb, updateItem, t, getFileName, getUrl, eFFormatBytes } = props.methods;
const { accept = 'image/*', maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = 'image', tips, beforeUpload, disabled, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files, disableInsert = false, disableAdd = false, disableDownload = false, disableDelete = false, disablePreview = false, } = props.data;
const { onPickByWeb, onDeleteByWeb, updateItem, t, getFileName, getUrl, formatBytes, } = props.methods;
const [newFiles, setNewFiles] = (0, react_1.useState)([]);
const [newUploadFiles, setNewUploadFiles] = (0, react_1.useState)([]);
const listType = getListType(theme);
@ -114,7 +116,7 @@ function render(props) {
if (children) {
return children;
}
if (listType === "picture-card") {
if (listType === 'picture-card') {
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(icons_1.PlusOutlined, {}), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: 8 }, children: "\u8BF7\u9009\u62E9\u56FE\u7247" })] }));
}
return (0, jsx_runtime_1.jsx)(antd_1.Button, { type: "default", children: "\u9009\u62E9\u6587\u4EF6" });
@ -134,7 +136,10 @@ function render(props) {
sort = newFiles[hoverIndex].sort + 100;
}
else {
sort = (newFiles[hoverIndex].sort + newFiles[hoverIndex + 1].sort) / 2;
sort =
(newFiles[hoverIndex].sort +
newFiles[hoverIndex + 1].sort) /
2;
}
}
else {
@ -142,35 +147,38 @@ function render(props) {
sort = newFiles[hoverIndex].sort / 2;
}
else {
sort = (newFiles[hoverIndex].sort + newFiles[hoverIndex - 1].sort) / 2;
sort =
(newFiles[hoverIndex].sort +
newFiles[hoverIndex - 1].sort) /
2;
}
}
if (checkLimit(sort)) {
alert("当前的sort值为:" + sort);
alert('当前的sort值为:' + sort);
return;
}
updateItem({ sort }, dragRow.id);
}, [newFiles]);
return ((0, jsx_runtime_1.jsxs)(antd_1.Space, { direction: "vertical", className: web_module_less_1.default["oak-upload"], style: { width: "100%" }, children: [(0, jsx_runtime_1.jsx)(react_dnd_1.DndProvider, { backend: utils_2.isPc ? react_dnd_html5_backend_1.HTML5Backend : react_dnd_touch_backend_1.TouchBackend, children: (0, jsx_runtime_1.jsx)(antd_1.Upload, { className: (0, classnames_1.default)(web_module_less_1.default["oak-upload__upload"], className), style: style, disabled: disabled, directory: directory, showUploadList: showUploadList
return ((0, jsx_runtime_1.jsxs)(antd_1.Space, { direction: "vertical", className: web_module_less_1.default['oak-upload'], style: { width: '100%' }, children: [(0, jsx_runtime_1.jsx)(react_dnd_1.DndProvider, { backend: utils_2.isPc ? react_dnd_html5_backend_1.HTML5Backend : react_dnd_touch_backend_1.TouchBackend, children: (0, jsx_runtime_1.jsx)(antd_1.Upload, { className: (0, classnames_1.default)(web_module_less_1.default['oak-upload__upload'], className), style: style, disabled: disabled, directory: directory, showUploadList: showUploadList
? {
showPreviewIcon: preview,
showPreviewIcon: !disablePreview,
showRemoveIcon: !disableDelete,
showDownloadIcon: !disableDownload,
}
: false, beforeUpload: async (file) => {
if (typeof beforeUpload === "function") {
if (typeof beforeUpload === 'function') {
const result = await beforeUpload(file);
if (result) {
return false;
}
}
return false;
}, multiple: multiple, maxCount: maxNumber, accept: accept, listType: listType, fileList: theme === "custom"
}, multiple: multiple, maxCount: maxNumber, accept: accept, listType: listType, fileList: theme === 'custom'
? []
: newFiles?.map((ele) => extraFileToUploadFile(ele)), onChange: ({ file, fileList, event }) => {
// id不存在就是file对象
if (!file.id) {
if (theme !== "custom") {
if (theme !== 'custom') {
onPickByWeb([(0, utils_1.file2Obj)(file)]);
}
else {
@ -178,54 +186,54 @@ function render(props) {
}
}
}, onRemove: onDeleteByWeb, onPreview: onPreview, onDownload: onDownload, itemRender: (originNode, currentFile, currentFileList) => {
return ((0, jsx_runtime_1.jsx)(DragableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && !disableAdd ? getUploadButton() : null }) }), tips && (0, jsx_runtime_1.jsx)("small", { className: web_module_less_1.default["oak-upload__tips"], children: tips }), theme === "custom" && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(antd_1.Table, { dataSource: newUploadFiles || [], rowKey: "id", columns: [
return ((0, jsx_runtime_1.jsx)(DraggableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && !disableAdd ? getUploadButton() : null }) }), tips && ((0, jsx_runtime_1.jsx)("small", { className: web_module_less_1.default['oak-upload__tips'], children: tips })), theme === 'custom' && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(antd_1.Table, { dataSource: newUploadFiles || [], rowKey: "id", columns: [
{
align: "center",
dataIndex: "tableIndex",
title: "#",
align: 'center',
dataIndex: 'tableIndex',
title: '#',
render: (value, record, index) => index + 1,
width: 50,
},
{
dataIndex: "name",
title: "文件名",
dataIndex: 'name',
title: '文件名',
},
{
dataIndex: "size",
title: "文件大小",
dataIndex: 'size',
title: '文件大小',
render: (value, record, index) => {
return eFFormatBytes(value);
return formatBytes(value);
},
},
{
dataIndex: "status",
title: "状态",
dataIndex: 'status',
title: '状态',
render: (value, record, index) => {
switch (value) {
case "success":
return (0, jsx_runtime_1.jsx)(antd_1.Tag, { color: "success", children: t("success") });
case "uploading":
return (0, jsx_runtime_1.jsx)(antd_1.Tag, { color: "processing", children: t("uploading") });
case 'success':
return ((0, jsx_runtime_1.jsx)(antd_1.Tag, { color: "success", children: t('success') }));
case 'uploading':
return ((0, jsx_runtime_1.jsx)(antd_1.Tag, { color: "processing", children: t('uploading') }));
default:
return (0, jsx_runtime_1.jsx)(antd_1.Tag, { color: "warning", children: t("waiting") });
return ((0, jsx_runtime_1.jsx)(antd_1.Tag, { color: "warning", children: t('waiting') }));
}
},
},
{
dataIndex: "op",
dataIndex: 'op',
width: 300,
title: "操作",
align: "center",
title: '操作',
align: 'center',
render: (value, record, index) => {
// 只处理state的文件 这时候可以直接删除
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: !record.id && ((0, jsx_runtime_1.jsx)(antd_1.Button, { type: "link", onClick: () => {
customDelete(index);
}, children: "\u5220\u9664" })) }));
},
fixed: "right",
fixed: 'right',
},
] }), (0, jsx_runtime_1.jsx)("div", { style: { display: "flex", justifyContent: "flex-end" }, children: (0, jsx_runtime_1.jsxs)(antd_1.Space, { children: [(0, jsx_runtime_1.jsx)(antd_1.Button, { danger: true, type: "default", onClick: () => setNewUploadFiles([]), children: "\u6E05\u7A7A" }), (0, jsx_runtime_1.jsx)(antd_1.Button, { type: "primary", onClick: () => {
] }), (0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', justifyContent: 'flex-end' }, children: (0, jsx_runtime_1.jsxs)(antd_1.Space, { children: [(0, jsx_runtime_1.jsx)(antd_1.Button, { danger: true, type: "default", onClick: () => setNewUploadFiles([]), children: "\u6E05\u7A7A" }), (0, jsx_runtime_1.jsx)(antd_1.Button, { type: "primary", onClick: () => {
onPickByWeb(newUploadFiles, (file, status) => {
setNewUploadFilesByStatus(file, status);
});

View File

@ -0,0 +1,16 @@
import { EntityDict } from '../../../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { ReactComponentProps } from 'oak-frontend-base/lib/types/Page';
type ImgMode = 'scaleToFill' | 'aspectFit' | 'aspectFill' | 'widthFix' | "heightFix" | 'top' | 'bottom' | 'left' | 'right' | 'center' | 'top left' | 'top right' | 'bottom left' | 'bottom right';
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
mode: ImgMode;
size: number;
disablePreview: boolean;
disableDownload: boolean;
tag1: string;
tag2: string;
entity: keyof ED2;
entityId: string;
style: string;
}>) => React.ReactElement;
export default _default;

View File

@ -0,0 +1,141 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
;
exports.default = OakComponent({
entity: 'extraFile',
isList: true,
projection: {
id: 1,
tag1: 1,
tag2: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
fileType: 1,
sort: 1,
isBridge: 1,
uploadState: 1,
},
features: ['extraFile2'],
formData({ data, features }) {
let files = data?.sort((ele1, ele2) => ele1.sort - ele2.sort);
if (this.props.tag1) {
files = files?.filter((ele) => ele?.tag1 === this.props.tag1);
}
if (this.props.tag2) {
files = files?.filter((ele) => ele?.tag2 === this.props.tag2);
}
const files2 = files.map((ele) => {
const url = features.extraFile2.getUrl(ele);
const thumbUrl = features.extraFile2.getUrl(ele, this.props.style);
const fileName = features.extraFile2.getFileName(ele);
return {
url,
thumbUrl,
fileName,
...ele,
};
});
return {
files: files2,
};
},
data: {
// 根据 size 不同,计算的图片显示大小不同
itemSizePercentage: '',
},
wechatMp: {
externalClasses: ['oak-class', 'oak-item-class'],
},
filters: [
{
filter() {
const { tag1, tag2 } = this.props;
const filter1 = {};
if (tag1) {
Object.assign(filter1, { tag1 });
}
if (tag2) {
Object.assign(filter1, { tag2 });
}
return filter1;
},
},
],
properties: {
mode: 'aspectFit',
size: 3,
disablePreview: false,
disableDownload: false,
tag1: '',
tag2: '',
entity: '',
entityId: '',
style: '',
},
methods: {
/**
* 获取组件内部节点位置信息单个
* @param component 组件实例
* @param selector {String} css选择器
* @returns boundingClientRect() 回调函数的值
*/
async getNodeRectFromComponent(component, selector) {
return await new Promise((resolve) => {
component
.createSelectorQuery()
.select(selector)
.boundingClientRect((res) => {
resolve(res);
})
.exec();
});
},
/**
// * px 转 rpx
// * @param px 像素值
// */
px2rpx(px) {
const windowWidth = wx.getSystemInfoSync().windowWidth;
return (750 / windowWidth) * px;
},
async onPreviewByMp(event) {
const files = this.state.files;
const { index } = event.currentTarget.dataset;
const imageUrl = files[index].url;
const urls = files?.filter((ele) => !!ele).map((ele) => ele.url);
// 预览图片
if (!this.props.disablePreview) {
const result = await wx.previewImage({
urls: urls,
current: imageUrl,
});
}
},
},
listeners: {
async size(prev, next) {
if (process.env.OAK_PLATFORM === 'wechatMp') {
const size = next.size;
if (!size) {
this.setState({ itemSizePercentage: '' });
return;
}
// 获取 .file-list__container 容器宽度
const res = 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,
});
}
},
},
});

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,61 @@
@import "../../../config/styles/mp/index.less";
@import "../../../config/styles/mp/mixins.less";
.file-list__container {
position: relative;
display: flex;
flex-wrap: wrap;
}
.file-list__item {
position: relative;
width: 220rpx;
padding-bottom: 220rpx;
height: 0;
}
// size 不同时,对应的图片间距设置
// size 仅支持 1-10
each(range(2, 10), {
@valuePlusOne : @value+1;
.file-list__item--@{value}:nth-of-type(n+@{valuePlusOne}) {
margin-top : 20rpx;
}
.file-list__item--@{value}:not(:nth-of-type(@{value}n+1)) {
margin-left : 20rpx;
}
}) // 当 size 为 null每行会显示 3 张图片
.file-list__item--null:nth-of-type(n+4) {
margin-top: 20rpx;
}
.file-list__item--null:not(:nth-of-type(3n+1)) {
margin-left: 20rpx;
}
.file-list__image {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 1rpx solid #eee;
border-radius: 4rpx;
}
.file-list__item--selected {
width: 100%;
height: 100%;
z-index: 10;
background-color: #000;
filter: Alpha(Opacity=50);
opacity: 0.5;
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}

View File

@ -0,0 +1,9 @@
<view class="file-list__container oak-class">
<block wx:for="{{files}}" wx:key="index">
<block wx:if="{{item}}">
<view class="file-list__item file-list__item--{{size}} oak-item-class" style="{{itemSizePercentage?'width:'+itemSizePercentage+'padding-bottom:'+itemSizePercentage:'xxx'}}">
<image data-index="{{index}}" bind:tap="onPreviewByMp" src="{{item.thumbUrl}}" mode="{{mode}}" class="file-list__image"/>
</view>
</block>
</block>
</view>

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,3 @@
.container {
display: flex;
}

View File

@ -0,0 +1,18 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
type ExtraFile = EntityDict['extraFile']['OpSchema'];
interface EnhancedExtraFile extends ExtraFile {
url: string;
thumbUrl: string;
fileFullName: string;
}
export default function render(props: WebComponentProps<EntityDict, 'extraFile', true, {
files: EnhancedExtraFile[];
style?: Record<string, string>;
className?: string;
onDownload?: (file: EnhancedExtraFile) => void;
showUploadList?: boolean;
disableDownload?: boolean;
disablePreview?: boolean;
}, {}>): import("react/jsx-runtime").JSX.Element;
export {};

View File

@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const antd_mobile_1 = require("antd-mobile");
function render(props) {
const { style, className, onDownload, files = [], disableDownload = false, disablePreview = false, } = props.data;
const { t } = props.methods;
const [visible, setVisible] = (0, react_1.useState)(false);
const imageViewerMultiRef = (0, react_1.useRef)(null);
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(antd_mobile_1.Space, { children: files?.map((ele, index) => ((0, jsx_runtime_1.jsx)(antd_mobile_1.Image, { src: ele.thumbUrl, width: 100, height: 100, fit: "contain", onClick: !disablePreview ? () => {
setVisible(true);
imageViewerMultiRef.current.swipeTo(index);
} : undefined }))) }), (0, jsx_runtime_1.jsx)(antd_mobile_1.ImageViewer.Multi, { ref: imageViewerMultiRef, images: files?.map((ele) => ele.url) || [], visible: visible, onClose: () => {
setVisible(false);
} })] }));
}
exports.default = render;

View File

@ -0,0 +1,3 @@
.container {
display: flex;
}

View File

@ -0,0 +1,18 @@
import { WebComponentProps } from "oak-frontend-base";
import { EntityDict } from "../../../oak-app-domain";
type ExtraFile = EntityDict['extraFile']['OpSchema'];
interface EnhancedExtraFile extends ExtraFile {
url: string;
thumbUrl: string;
fileFullName: string;
}
export default function render(props: WebComponentProps<EntityDict, 'extraFile', true, {
files: EnhancedExtraFile[];
style?: Record<string, string>;
className?: string;
onDownload?: (file: EnhancedExtraFile) => void;
showUploadList?: boolean;
disableDownload?: boolean;
disablePreview?: boolean;
}, {}>): import("react/jsx-runtime").JSX.Element;
export {};

View File

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const antd_1 = require("antd");
;
function render(props) {
const { style, className, onDownload, files = [], disableDownload = false, disablePreview = false, } = props.data;
const { t } = props.methods;
return ((0, jsx_runtime_1.jsx)(antd_1.Image.PreviewGroup, { preview: {
onChange: (current, prev) => { },
}, children: (0, jsx_runtime_1.jsx)(antd_1.Space, { children: files?.map((ele) => ((0, jsx_runtime_1.jsx)(antd_1.Image, { width: 120, src: ele.thumbUrl, preview: !disablePreview
? {
src: ele.url,
}
: true, fallback: "data:image/png;base64,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" }))) }) }));
}
exports.default = render;

View File

@ -6,13 +6,12 @@ type ExtraFile = EntityDict['extraFile']['OpSchema'];
export interface EnhancedExtraFile extends ExtraFile {
url: string;
thumbUrl: string;
filename: string;
fileName: string;
fileState?: FileState;
percentage?: number;
}
type SourceType = 'album' | 'camera';
export type Theme = 'file' | 'image' | 'image-flow' | 'custom';
type FileType = 'all' | 'video' | 'image' | 'file';
type ImgMode = 'scaleToFill' | 'aspectFit' | 'aspectFill' | 'widthFix' | "heightFix" | 'top' | 'bottom' | 'left' | 'right' | 'center' | 'top left' | 'top right' | 'bottom left' | 'bottom right';
declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends keyof ED2>(props: ReactComponentProps<ED2, T2, true, {
bucket: string;
@ -20,15 +19,15 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
autoUpload: boolean;
maxNumber: number;
extension: string[];
fileType: FileType;
selectCount: number;
sourceType: SourceType[];
mediaType: ('image' | 'video')[];
mode: ImgMode;
size: number;
showUploadList: boolean;
showUploadProgress: boolean;
accept: string;
preview: boolean;
disablePreview: boolean;
disableDelete: boolean;
disableAdd: boolean;
disableDownload: boolean;
@ -40,7 +39,6 @@ declare const _default: <ED2 extends EntityDict & BaseEntityDict, T2 extends key
entity: keyof ED2;
entityId: string;
theme: Theme;
showUploadProgress: boolean;
children?: React.ReactNode;
}>) => React.ReactElement;
export default _default;

View File

@ -28,7 +28,7 @@ exports.default = OakComponent({
itemSizePercentage: '',
},
wechatMp: {
externalClasses: ['oak-class', 'oak-item-class'],
externalClasses: ['oak-class', 'oak-item-class', 'oak-item-add-class'],
},
filters: [
{
@ -51,32 +51,25 @@ exports.default = OakComponent({
autoUpload: false,
maxNumber: 20,
extension: [],
fileType: 'all',
selectCount: 1,
sourceType: ['album', 'camera'],
mediaType: ['image'],
// 图片显示模式
mode: 'aspectFit',
// 每行可显示的个数
size: 3,
showUploadList: true,
showUploadProgress: false,
accept: 'image/*',
// 图片是否可预览
preview: true,
// 图片是否可删除
disablePreview: false,
disableDelete: false,
// 上传按钮隐藏
disableAdd: false,
// 下按按钮隐藏
disableDownload: false,
type: 'file',
type: 'image',
origin: 'qiniu',
tag1: '',
tag2: '',
entity: '',
entityId: '',
theme: 'image',
showUploadProgress: false,
},
listeners: {
maxNumber(prev, next) {
@ -106,22 +99,29 @@ exports.default = OakComponent({
},
features: ['extraFile2'],
formData({ data, features }) {
const files = data.map(ele => {
let files = data?.sort((ele1, ele2) => ele1.sort - ele2.sort);
if (this.props.tag1) {
files = files?.filter((ele) => ele?.tag1 === this.props.tag1);
}
if (this.props.tag2) {
files = files?.filter((ele) => ele?.tag2 === this.props.tag2);
}
const files2 = files.map((ele) => {
const url = features.extraFile2.getUrl(ele);
const thumbUrl = features.extraFile2.getUrl(ele, 'thumbnail');
const fileState = features.extraFile2.getFileState(ele.id);
const filename = features.extraFile2.getFileName(ele);
const fileName = features.extraFile2.getFileName(ele);
return {
url,
thumbUrl,
filename,
fileName,
fileState: fileState?.state,
percentage: fileState?.percentage,
...ele,
};
});
return {
files,
files: files2,
};
},
methods: {
@ -130,16 +130,17 @@ exports.default = OakComponent({
this.features.extraFile2.removeLocalFiles([file.id]);
},
addExtraFileInner(options, file) {
const { type, origin, tag1, tag2, entity, entityId, bucket } = this.props;
const { type, origin = 'qiniu', // 默认qiniu
tag1, tag2, entity, entityId, bucket, } = this.props;
const { name, fileType, size } = options;
const extension = name.substring(name.lastIndexOf('.') + 1);
const filename = name.substring(0, name.lastIndexOf('.'));
const { files } = this.state;
const sort = files.length * 10000;
let bucket2 = bucket;
if (!bucket2) {
if (origin === 'qiniu' && !bucket2) {
const context = this.features.cache.begin();
const { config } = (0, getContextConfig_1.getConfig)(context, 'Cos', 'qiniu');
const { config } = (0, getContextConfig_1.getConfig)(context, 'Cos', origin);
this.features.cache.commit();
const { defaultBucket } = config;
bucket2 = defaultBucket;
@ -171,6 +172,124 @@ exports.default = OakComponent({
fileType: type,
size,
}, file);
}
}
},
// 小程序端
async chooseMediaByMp() {
//图片和视频使用
const { selectCount, mediaType, sourceType } = this.props;
try {
const { errMsg, tempFiles } = await wx.chooseMedia({
count: selectCount,
mediaType,
sourceType,
});
if (errMsg !== 'chooseMedia:ok') {
this.triggerEvent('onError', {
level: 'warning',
msg: errMsg,
});
}
else {
tempFiles.map((tempExtraFile) => {
const { tempFilePath, thumbTempFilePath, fileType, size, } = tempExtraFile;
const filePath = tempFilePath || thumbTempFilePath;
const fileFullName = filePath.match(/[^/]+(?!.*\/)/g)[0];
this.addExtraFileInner({
name: fileFullName,
fileType,
size,
}, filePath);
});
}
}
catch (err) {
if (err.errMsg !== 'chooseMedia:fail cancel') {
this.triggerEvent('onError', {
level: 'error',
msg: err.errMsg,
});
}
}
},
async chooseMessageFileByMp() {
const { selectCount, extension } = this.props;
try {
const { errMsg, tempFiles } = await wx.chooseMessageFile({
count: selectCount,
type: 'all',
extension,
});
if (errMsg !== 'chooseMessageFile:ok') {
this.triggerEvent('onError', {
level: 'warning',
msg: errMsg,
});
}
else {
tempFiles.map((tempExtraFile) => {
const { path, type, size, name } = tempExtraFile;
this.addExtraFileInner({
name,
fileType: type,
size,
}, path);
});
}
}
catch (err) {
if (err.errMsg !== 'chooseMessageFile:fail cancel') {
this.triggerEvent('onError', {
level: 'error',
msg: err.errMsg,
});
}
}
},
async addFileByMp(evt) {
const { type } = this.props;
//小程序 根据type类型调用api
if (['image', 'video'].includes(type)) {
this.chooseMediaByMp();
}
else {
this.chooseMessageFileByMp();
}
},
onRemoveByMp(event) {
const { value } = event.currentTarget.dataset;
this.onRemove(value);
},
async onPreviewByMp(event) {
const files = this.state.files;
const { index } = event.currentTarget.dataset;
const imageUrl = files[index].url;
const urls = files?.filter((ele) => !!ele).map((ele) => ele.url);
const detail = {
all: files,
index,
urls,
current: imageUrl,
};
// 预览图片
if (!this.props.disablePreview) {
const result = await wx.previewImage({
urls: urls,
current: imageUrl,
});
this.triggerEvent('onPreview', detail);
}
},
//检查排序是否超过上限
checkSort(sort) {
const reg = /^\d+\.(?:9+)$/;
if (reg.test(sort.toString())) {
this.setMessage({
type: 'warning',
content: this.t('dragSort'),
});
return false;
}
return true;
},
},
});

View File

@ -0,0 +1,152 @@
@import "../../../config/styles/mp/index.less";
@import "../../../config/styles/mp/mixins.less";
.file-list__container {
position: relative;
display: flex;
flex-wrap: wrap;
}
.file-list__item {
position: relative;
width: 220rpx;
padding-bottom: 220rpx;
height: 0;
}
// size 不同时,对应的图片间距设置
// size 仅支持 1-10
each(range(2, 10), {
@valuePlusOne : @value+1;
.file-list__item--@{value}:nth-of-type(n+@{valuePlusOne}) {
margin-top : 20rpx;
}
.file-list__item--@{value}:not(:nth-of-type(@{value}n+1)) {
margin-left : 20rpx;
}
}) // 当 size 为 null每行会显示 3 张图片
.file-list__item--null:nth-of-type(n+4) {
margin-top: 20rpx;
}
.file-list__item--null:not(:nth-of-type(3n+1)) {
margin-left: 20rpx;
}
.file-list__image {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 1rpx solid #eee;
border-radius: 4rpx;
}
.file-list__item--selected {
width: 100%;
height: 100%;
z-index: 10;
background-color: #000;
filter: Alpha(Opacity=50);
opacity: 0.5;
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
.file-list__remove {
position: absolute;
right: 10rpx;
top: 10rpx;
height: 40rpx;
width: 40rpx;
border-radius: 50%;
background: rgb(0 0 0 / 40%);
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.file-list__item--add {
border: 1rpx solid #eee;
border-radius: 4rpx;
background-color: white;
}
.file-list__image--add {
visibility: hidden;
position: absolute;
width: 50%;
height: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
align-items: center;
justify-content: center;
display: flex;
}
.file-list__item-slot-wrapper {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.file-list__item-slot-wrapper:empty+.file-list__image--add {
visibility: visible;
}
.file-list-flow__container {
position: relative;
display: flex;
flex-direction: column;
}
.file-list-flow__item {
display: flex;
flex-direction: row;
align-items: center;
margin: 10rpx 10rpx 10rpx 0;
}
.file-list-flow__item--name {
display: flex;
flex-direction: row;
fleX: 1;
font-size: 28rpx;
}
.file-list-flow__item--btns {
display: flex;
flex-direction: row;
}
.file-list-flow__download {
width: 48rpx;
height: 48rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.file-list-flow__remove {
width: 48rpx;
height: 48rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

View File

@ -0,0 +1,47 @@
<block wx:if="{{ type === 'image' }}">
<view class="file-list__container oak-class">
<block wx:for="{{files}}" wx:key="index">
<block wx:if="{{item}}">
<view class="file-list__item file-list__item--{{size}} oak-item-class" style="{{itemSizePercentage?'width:'+itemSizePercentage+'padding-bottom:'+itemSizePercentage:'xxx'}}">
<image data-index="{{index}}" bind:tap="onPreviewByMp" src="{{item.url}}" mode="{{mode}}" class="file-list__image"/>
<view wx:if="{{!disableDelete}}" mut-bind:tap="onRemoveByMp" class="file-list__remove" data-value="{{item}}">
<l-icon name="close" color="#ffffff" size="18" />
</view>
</view>
</block>
</block>
<view class="file-list__item file-list__item--add file-list__item--{{size}} oak-item-add-class" style="{{itemSizePercentage?'width:'+itemSizePercentage+'padding-bottom:'+itemSizePercentage:''}}" wx:if="{{!disableInsert && !disableAdd}}" bind:tap="addFileByMp">
<view class="file-list__item-slot-wrapper">
<slot />
</view>
<view class="file-list__image--add">
<l-icon name="add" size="80" />
</view>
</view>
</view>
</block>
<block wx:else >
<view class="file-list-flow__container oak-class">
<view class="file-list-flow__item--add oak-item-add-class" wx:if="{{!disableInsert && !disableAdd}}">
<l-button bind:lintap="addFileByMp" plain="{{true}}" type="default">{{ t('chooseFile') }}</l-button>
</view>
<block wx:for="{{files}}" wx:key="index">
<block wx:if="{{item}}">
<view class="file-list-flow__item oak-item-class">
<view class="file-list-flow__item--name" mut-bind:tap="onOpenByMp" data-value="{{item}}">
{{ item.fileName }}
</view>
<view class="file-list-flow__item--btns">
<!-- <view wx:if="{{!disableDownload}}" mut-bind:tap="onDownloadByMp" class="file-list-flow__download" data-value="{{item}}">
<l-icon name="download" size="36" />
</view> -->
<view wx:if="{{!disableDelete}}" mut-bind:tap="onRemoveByMp" class="file-list-flow__remove" data-value="{{item}}">
<l-icon name="delete" size="36" />
</view>
<view>
</view>
</block>
</block>
</view>
</block>

View File

@ -1,4 +1,5 @@
{
"choosePicture": "请选择图片",
"chooseFile": "请选择文件"
"chooseFile": "请选择文件",
"dragSort": "当前拖拽排序值超过上限范围"
}

View File

@ -10,7 +10,7 @@ export default function render(props: WebComponentProps<EntityDict, 'extraFile',
draggable?: boolean;
theme?: Theme;
tips?: string;
beforeUpload?: (file: File) => Promise<boolean>;
beforeUpload?: (file: File) => Promise<boolean> | boolean;
style?: Record<string, string>;
className?: string;
directory?: boolean;
@ -21,8 +21,9 @@ export default function render(props: WebComponentProps<EntityDict, 'extraFile',
disableInsert?: boolean;
disableDownload?: boolean;
disableDelete?: boolean;
preview?: boolean;
disablePreview?: boolean;
}, {
onRemove: (file: UploadFile) => void;
addFileByWeb: (file: UploadFile) => void;
checkSort: (sort: number) => boolean;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -20,8 +20,8 @@ function getListType(theme) {
};
return themeMap[theme];
}
const type = "DragableUploadList";
const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const type = "DraggableUploadList";
const DraggableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
const ref = react_1.default.useRef(null);
const index = fileList.indexOf(file);
const [{ isOver, dropClassName }, drop] = (0, react_dnd_1.useDrop)({
@ -51,14 +51,14 @@ const DragableUploadListItem = ({ originNode, moveRow, file, fileList, }) => {
return ((0, jsx_runtime_1.jsx)("div", { ref: ref, className: `ant-upload-draggable-list-item ${isOver ? dropClassName : ""}`, style: { cursor: "move", height: "100%" }, children: originNode }));
};
function render(props) {
const { accept = "image/*", maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = "image", tips, beforeUpload, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files = [], disableInsert = false, disableDownload = false, disableDelete = false, preview = true, } = props.data;
const { t, onRemove, addFileByWeb } = props.methods;
const { accept = 'image/*', maxNumber = 20, multiple = maxNumber !== 1, draggable = false, theme = 'image', tips, beforeUpload, style, className, directory = false, onPreview, onDownload, children, showUploadList = true, files = [], disableInsert = false, disableDownload = false, disableDelete = false, disablePreview = false, } = props.data;
const { t, updateItem, onRemove, addFileByWeb, checkSort } = props.methods;
const listType = getListType(theme);
const getUploadButton = () => {
if (children) {
return children;
}
if (listType === "picture-card") {
if (listType === 'picture-card') {
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(icons_1.PlusOutlined, {}), (0, jsx_runtime_1.jsx)("div", { style: { marginTop: 8 }, children: t('choosePicture') })] }));
}
return (0, jsx_runtime_1.jsx)(antd_1.Button, { type: "default", children: t('chooseFile') });
@ -110,23 +110,53 @@ function render(props) {
return {
...file,
status,
name: file.filename,
name: file.fileName,
uid: file.id,
size: file.size,
fileName: file.fileName,
};
});
};
const moveRow = (0, react_1.useCallback)((dragIndex, hoverIndex) => {
console.log('dragIndex', dragIndex, 'hoverIndex', hoverIndex);
const dragRow = files[dragIndex];
let sort;
if (hoverIndex === dragIndex) {
return;
}
else if (hoverIndex > dragIndex) {
if (hoverIndex === files.length - 1) {
sort = files[hoverIndex].sort + 100;
}
else {
sort =
(files[hoverIndex].sort +
files[hoverIndex + 1].sort) /
2;
}
}
else {
if (hoverIndex === 0) {
sort = files[hoverIndex].sort / 2;
}
else {
sort =
(files[hoverIndex].sort +
files[hoverIndex - 1].sort) /
2;
}
}
if (checkSort(sort)) {
updateItem({ sort }, dragRow.id);
}
}, [files]);
return ((0, jsx_runtime_1.jsxs)(antd_1.Space, { direction: "vertical", className: web_module_less_1.default["oak-upload"], style: { width: "100%" }, children: [(0, jsx_runtime_1.jsx)(react_dnd_1.DndProvider, { backend: utils_1.isPc ? react_dnd_html5_backend_1.HTML5Backend : react_dnd_touch_backend_1.TouchBackend, children: (0, jsx_runtime_1.jsx)(antd_1.Upload, { className: (0, classnames_1.default)(web_module_less_1.default["oak-upload__upload"], className), style: style, directory: directory, showUploadList: showUploadList
return ((0, jsx_runtime_1.jsxs)(antd_1.Space, { direction: "vertical", className: web_module_less_1.default['oak-upload'], style: { width: '100%' }, children: [(0, jsx_runtime_1.jsx)(react_dnd_1.DndProvider, { backend: utils_1.isPc ? react_dnd_html5_backend_1.HTML5Backend : react_dnd_touch_backend_1.TouchBackend, children: (0, jsx_runtime_1.jsx)(antd_1.Upload, { className: (0, classnames_1.default)(web_module_less_1.default['oak-upload__upload'], className), style: style, directory: directory, showUploadList: showUploadList
? {
showPreviewIcon: preview,
showPreviewIcon: !disablePreview,
showRemoveIcon: !disableDelete,
showDownloadIcon: !disableDownload,
}
: false, beforeUpload: async (file) => {
if (typeof beforeUpload === "function") {
if (typeof beforeUpload === 'function') {
const result = await beforeUpload(file);
if (result) {
return false;
@ -138,7 +168,9 @@ function render(props) {
addFileByWeb(file);
}
}, onRemove: onRemove, onPreview: onPreview, onDownload: onDownload, itemRender: (originNode, currentFile, currentFileList) => {
return ((0, jsx_runtime_1.jsx)(DragableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && files.length < maxNumber ? getUploadButton() : null }) }), tips && (0, jsx_runtime_1.jsx)("small", { className: web_module_less_1.default["oak-upload__tips"], children: tips })] }));
return ((0, jsx_runtime_1.jsx)(DraggableUploadListItem, { originNode: originNode, file: currentFile, fileList: currentFileList, moveRow: moveRow }));
}, children: !disableInsert && files.length < maxNumber
? getUploadButton()
: null }) }), tips && ((0, jsx_runtime_1.jsx)("small", { className: web_module_less_1.default['oak-upload__tips'], children: tips }))] }));
}
exports.default = render;

View File

@ -8,6 +8,7 @@ exports.default = OakComponent({
entity: 1,
entityId: 1,
lmts: 1,
openId: 1,
user: {
id: 1,
name: 1,
@ -139,7 +140,7 @@ exports.default = OakComponent({
}
},
getName() {
const { user, entity } = this.state;
const { user, entity, openId } = this.state;
const { entityFilter } = this.props;
if (entityFilter) {
const userName = user?.name;
@ -152,6 +153,9 @@ exports.default = OakComponent({
if (userMobile) {
return '用户' + userMobile;
}
if (openId) {
return '微信用户' + openId;
}
return userNickname;
}
else {

View File

@ -8,6 +8,7 @@ export default function render(props: WebComponentProps<EntityDict, 'session', f
selectedId: string;
onSelect: (id: string) => void;
name: string;
lmts: number;
}, {
getName: () => string;
getAvatarUrl: () => string;

View File

@ -8,22 +8,21 @@ const classnames_1 = tslib_1.__importDefault(require("classnames"));
const web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
function render(props) {
const { methods, data } = props;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], name, } = data;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], name, lmts, } = data;
const { t, getName, getAvatarUrl } = methods;
const sessiontMessage = sessiontMessages && sessiontMessages[0];
const createAt = sessiontMessage?.$$createAt$$;
const type = sessiontMessage?.type;
const text = sessiontMessage?.text;
const today = (0, dayjs_1.default)().startOf('day').valueOf();
const createAt2 = createAt && (0, dayjs_1.default)(createAt).startOf('day').valueOf();
const createAt2 = lmts && (0, dayjs_1.default)(lmts).startOf('day').valueOf();
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(web_module_less_1.default.cell, {
[web_module_less_1.default.cell_selected]: id === selectedId,
}), onClick: () => {
onSelect(id);
}, children: [(0, jsx_runtime_1.jsx)(antd_1.Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: (0, jsx_runtime_1.jsx)(antd_1.Image, { className: web_module_less_1.default.avatar, src: getAvatarUrl(), preview: false }) }), (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.inner, children: [(0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.top, children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.title, children: name || getName() }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.date, children: sessiontMessage &&
}, children: [(0, jsx_runtime_1.jsx)(antd_1.Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: (0, jsx_runtime_1.jsx)(antd_1.Image, { className: web_module_less_1.default.avatar, src: getAvatarUrl(), preview: false }) }), (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.inner, children: [(0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.top, children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.title, children: name || getName() }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.date, children: lmts &&
(today === createAt2
? (0, dayjs_1.default)(createAt).format('HH:mm')
: (0, dayjs_1.default)(createAt).format('YYYY-MM-DD')) })] }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.message, children: type &&
? (0, dayjs_1.default)(lmts).format('HH:mm')
: (0, dayjs_1.default)(lmts).format('YYYY-MM-DD')) })] }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.message, children: type &&
(type === 'text'
? `${text}`
: `[${t(`sessiontMessage:v.type.${type}`)}消息]`) })] })] }));

View File

@ -2,5 +2,7 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
sessionId: string;
isEntity: boolean;
entityDisplay: (data: any) => any[];
entityProjection: any;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -95,9 +95,12 @@ exports.default = OakComponent({
properties: {
sessionId: '',
isEntity: false,
entityDisplay: (data) => [],
entityProjection: {}, // user端指示需要取哪些entity的属性来显示entityDisplay
},
methods: {
getSession(sessionId) {
const { entityProjection } = this.props;
const [session] = this.features.cache.get('session', {
data: {
id: 1,
@ -134,6 +137,7 @@ exports.default = OakComponent({
},
},
},
...entityProjection,
},
filter: {
id: sessionId
@ -154,7 +158,7 @@ exports.default = OakComponent({
},
getName() {
const { session, entity } = this.state;
const { isEntity } = this.props;
const { isEntity, entityDisplay } = this.props;
if (isEntity) {
const userName = session?.user?.name;
const userNickname = session?.user?.name || session?.user?.nickname;
@ -169,6 +173,10 @@ exports.default = OakComponent({
return userNickname;
}
else {
if (entityDisplay && session) {
const sessions = entityDisplay([session]);
return sessions[0]?.name;
}
return '未知';
}
},

View File

@ -2,7 +2,7 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "session", true, {
entity: string;
entityFilter: any;
entityDisplay: (data: any) => "";
entityDisplay: (data: any) => any[];
entityProjection: any;
sessionId: string;
dialog: boolean;

View File

@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("../../../config/constants");
exports.default = OakComponent({
entity: 'session',
projection() {
@ -8,6 +9,8 @@ exports.default = OakComponent({
id: 1,
entity: 1,
entityId: 1,
lmts: 1,
openId: 1,
userId: 1,
user: {
id: 1,
@ -85,8 +88,9 @@ exports.default = OakComponent({
// const unReadLength = wechatSessions?.filter(
// (ele) => ele.isRead
// )
//排序待框架实现
return {
sessions,
sessions: sessions?.sort((a, b) => b.lmts - a.lmts),
};
},
lifetimes: {
@ -109,6 +113,22 @@ exports.default = OakComponent({
this.setSelectedSessionId(sessionId);
}
},
async ready() {
const { entityFilter } = this.props;
const userId = this.features.token.getUserId();
await this.subData([
{
entity: 'session',
filter: entityFilter ? { ...entityFilter } : { userId },
id: `${constants_1.DATA_SUBSCRIBER_KEYS.sessionList}`,
}
], () => { console.log(123); });
},
detached() {
this.unSubData([
`${constants_1.DATA_SUBSCRIBER_KEYS.sessionList}`
]);
},
},
data: {
unReadLength: 0,
@ -117,7 +137,7 @@ exports.default = OakComponent({
properties: {
entity: '',
entityFilter: undefined,
entityDisplay: (data) => '',
entityDisplay: (data) => [],
entityProjection: {},
sessionId: '',
dialog: false,

View File

@ -6,6 +6,8 @@ export default function Render(props: WebComponentProps<EntityDict, 'session', f
className: string;
dialog: boolean;
entityFilter: object;
entityDisplay: (data: any) => any[];
entityProjection: object;
}, {
setSelectedSessionId: (conversationId: string) => void;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -11,7 +11,7 @@ function Render(props) {
const { data, methods } = props;
const { sessions, selectedSessionId, oakFullpath,
// unReadConversation = 0,
entityFilter, dialog = false, className, } = data;
entityFilter, dialog = false, className, entityDisplay, entityProjection, } = data;
const { setSelectedSessionId } = methods;
return ((0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.container, children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(web_module_less_1.default.bothContainer, className, {
[web_module_less_1.default.dialogContainer]: dialog,
@ -23,7 +23,7 @@ function Render(props) {
: '' }, session.id));
}) })] }), selectedSessionId && ((0, jsx_runtime_1.jsx)(list_1.default, { sessionId: selectedSessionId,
// isCombine={true}
isEntity: entityFilter ? true : false, isUser: entityFilter ? false : true, oakAutoUnmount: true, oakPath: oakFullpath
isEntity: entityFilter ? true : false, isUser: entityFilter ? false : true, oakAutoUnmount: true, entityDisplay: entityDisplay, entityProjection: entityProjection, oakPath: oakFullpath
? `$$sessionMessage/list`
: undefined }))] }) }));
}

View File

@ -1,5 +1,4 @@
"use strict";
// import { Schema as ExtraFile } from '../../../
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = OakComponent({
entity: 'sessionMessage',
@ -93,13 +92,12 @@ exports.default = OakComponent({
userAvatar: this.features.extraFile.getUrl(session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]),
};
// if (type === 'image') {
// const extraFile$entity =
// wechatMessage?.extraFile$entity as ExtraFile[];
// Object.assign(newWechatMessage, {
// picUrl: features.extraFile.getUrl(extraFile$entity[0]),
// });
// }
if (type === 'image') {
const extraFile$entity = sessionMessage?.extraFile$entity;
Object.assign(newSessionMessage, {
picUrl: features.extraFile.getUrl(extraFile$entity && extraFile$entity[0]),
});
}
return newSessionMessage;
},
properties: {

View File

@ -7,5 +7,7 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
dialog: boolean;
entity: string;
entityId: string;
entityDisplay: (data: any) => any[];
entityProjection: any;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -2,6 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
const uuid_1 = require("oak-domain/lib/utils/uuid");
const constants_1 = require("../../../config/constants");
const getContextConfig_1 = require("../../../utils/getContextConfig");
exports.default = OakComponent({
entity: 'sessionMessage',
projection: {
@ -10,6 +11,7 @@ exports.default = OakComponent({
type: 1,
userId: 1,
wechatUserId: 1,
applicationId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
@ -45,40 +47,18 @@ exports.default = OakComponent({
lifetimes: {
async ready() {
const { sessionId } = this.props;
await this.subData([
this.subData([
{
entity: 'sessionMessage',
filter: {
sessionId: sessionId,
},
id: `${constants_1.DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`,
}
], async () => { await this.pageScroll('comment'); });
// const userId = this.features.token.getUserId(true);
// const applicationId = this.features.application.getApplicationId();
// if (!sessionId) {
// const entity = 'application';
// const entityId = applicationId;
// const type = 'web';
// const { result: newSessionId } = await this.features.cache.exec('createSession', { type, entity, entityId });
// this.setState({
// newSessionId,
// })
// }
// if (!userId) {
// this.redirectTo(
// {
// url: '/login',
// backUrl: encodeURIComponent(window.location.href),
// },
// undefined,
// true
// );
// return;
// }
// (this as any).timer = setInterval(() => {
// this.refresh();
// }, 2000);
},
], async () => {
await this.pageScroll('comment');
});
this.createItem();
this.getConversationInfo();
},
detached() {
@ -87,34 +67,42 @@ exports.default = OakComponent({
}
const { sessionId } = this.props;
this.unSubData([
`${constants_1.DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`
`${constants_1.DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`,
]);
},
},
listeners: {
num(prev, next) {
if (prev.num !== next.num) {
if (next.num > 0 && next.num <= 20) {
this.pageScroll('comment');
}
this.pageScroll('comment');
}
},
sessionId(prev, next) {
if (this.state.oakFullpath) {
if (prev.sessionId !== next.sessionId) {
if (next.sessionId) {
const { sessionMessageId } = this.state;
this.getConversationInfo();
// 如果sessionId变了需要重新刷新下
this.refresh();
this.removeItem(sessionMessageId);
this.setState({
text: '',
});
this.createItem();
this.pageScroll('comment');
}
}
}
},
},
formData({ data: sessionMessageList = [], features }) {
const sessionMessageType = sessionMessageList?.find((ele) => ele.$$createAt$$ === 1)?.type;
this.getUserLastMessage();
return {
sessionMessageList,
num: sessionMessageList?.length,
sessionMessageType,
};
},
properties: {
@ -124,6 +112,8 @@ exports.default = OakComponent({
dialog: false,
entity: '',
entityId: '',
entityDisplay: (data) => [],
entityProjection: {}, // user端指示需要取哪些entity的属性来显示entityDisplay
},
filters: [
{
@ -131,9 +121,6 @@ exports.default = OakComponent({
const { sessionId } = this.props;
return {
sessionId,
// type: {
// $exists: true,
// },
};
},
},
@ -155,10 +142,49 @@ exports.default = OakComponent({
newSessionId: '',
},
methods: {
getUserLastMessage() {
const { sessionId } = this.props;
const [lastMessage] = this.features.cache.get('sessionMessage', {
data: {
id: 1,
sessionId: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
applicationId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
filter: {
sessionId,
aaoe: false,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
count: 1,
});
const isWeChat = !!lastMessage?.wechatUserId;
console.log(lastMessage);
this.setState({ isWeChat });
},
setContent(text) {
const { sessionMessageId } = this.state;
console.log(sessionMessageId);
this.setState({
text,
});
this.updateItem({
text,
type: 'text',
}, sessionMessageId);
},
setButtonHidden(isHidden) {
this.setState({
@ -224,8 +250,24 @@ exports.default = OakComponent({
const doc = window.document.getElementById(id);
setTimeout(() => doc.scrollTo(0, 10000), 500);
},
async createItem() {
const { text, wechatUserId } = this.state;
const { sessionId, isEntity } = this.props;
const userId = this.features.token.getUserId();
const applicationId = this.features.application.getApplicationId();
const sessionMessageId = this.addItem({
applicationId,
userId,
wechatUserId,
sessionId: sessionId,
aaoe: isEntity,
});
this.setState({
sessionMessageId,
});
},
async createMessage() {
const { text, wechatUserId, newSessionId } = this.state;
const { text, wechatUserId, newSessionId, sessionMessageId } = this.state;
const { sessionId, isEntity } = this.props;
const userId = this.features.token.getUserId();
const applicationId = this.features.application.getApplicationId();
@ -236,67 +278,83 @@ exports.default = OakComponent({
});
return;
}
this.addItem({
applicationId,
text,
userId,
wechatUserId,
sessionId: sessionId || newSessionId,
type: 'text',
// this.addItem({
// applicationId,
// text,
// userId,
// wechatUserId,
// sessionId: sessionId || newSessionId,
// type: 'text',
// createTime: Date.now(),
// aaoe: isEntity,
// } as EntityDict['sessionMessage']['CreateSingle']['data']);
this.updateItem({
createTime: Date.now(),
aaoe: isEntity,
});
}, sessionMessageId);
await this.execute(undefined, false);
this.setState({
text: '',
});
this.pageScroll('comment');
this.createItem();
},
async customUpload(file) {
const { sessionId } = this.props;
const { sessionId, isEntity } = this.props;
// TS 语法
// file 即选中的文件
const { name, size, type, originFileObj } = file;
const applicationId = this.features.application.getApplicationId();
const extension = name.substring(name.lastIndexOf('.') + 1);
const filename = name.substring(0, name.lastIndexOf('.'));
let bucket2 = '';
if (!bucket2) {
const context = this.features.cache.begin();
const { config } = (0, getContextConfig_1.getConfig)(context, 'Cos', 'qiniu');
this.features.cache.commit();
const { defaultBucket } = config;
bucket2 = defaultBucket;
}
const extraFile = {
extra1: originFileObj,
applicationId,
bucket: bucket2,
origin: 'qiniu',
type: 'image',
tag1: 'image',
objectId: (0, uuid_1.generateNewId)(),
filename,
fileType: type,
size,
extension,
entity: 'sessionMessage',
bucket: '',
id: (0, uuid_1.generateNewId)(),
};
// try {
// // 自己实现上传,并得到图片 url alt href
// const { url, bucket } = await this.features.extraFile.upload(
// extraFile
// );
// extraFile.bucket = bucket;
// extraFile.extra1 = null;
// const userId = this.features.token.getUserId();
// this.addItem({
// id: generateNewId(),
// sessionId,
// type: 'image',
// extraFile$entity: [
// {
// id: generateNewId(),
// action: 'create',
// data: extraFile,
// },
// ],
// } as EntityDict['sessionMessage']['CreateSingle']['data']);
// await this.execute(undefined, false);
// } catch (err) {
// throw err;
// }
try {
// await this.features.extraFile.upload(
// extraFile,
// originFileObj
// );
const userId = this.features.token.getUserId();
this.addItem({
id: (0, uuid_1.generateNewId)(),
applicationId,
sessionId,
createTime: Date.now(),
aaoe: isEntity,
type: 'image',
extraFile$entity: [
{
id: (0, uuid_1.generateNewId)(),
action: 'create',
data: extraFile,
},
],
});
this.features.extraFile2.addLocalFile(extraFile?.id, originFileObj);
await this.execute(undefined, false);
this.features.extraFile2.upload(extraFile?.id);
}
catch (err) {
throw err;
}
},
},
});

View File

@ -14,6 +14,11 @@ export default function Render(props: WebComponentProps<EntityDict, 'sessionMess
isEntity: boolean;
isUser: boolean;
employerId: string;
sessionMessageType: string;
sessionMessageId: string;
entityDisplay: (data: any) => any[];
entityProjection: object;
isWeChat: boolean;
}, {
setButtonHidden: (isHidden: boolean) => void;
customUpload: (file: customFile) => void;

Some files were not shown because too many files have changed in this diff Show More