feat: add file upload in chat usage

pull/199/merge
moonrailgun 2 months ago
parent e92c28bcd4
commit 52f70c89d5

@ -272,6 +272,6 @@ export {
applyDefaultFallbackGroupPermission,
} from './utils/role-helper';
export { uploadFile } from './utils/upload-helper';
export type { UploadFileResult } from './utils/upload-helper';
export type { UploadFileResult, UploadFileUsage } from './utils/upload-helper';
export { parseUrlStr } from './utils/url-helper';
export { sleep } from './utils/utils';

@ -5,7 +5,10 @@ import { getGlobalConfig } from '../model/config';
import { showErrorToasts } from '../manager/ui';
import filesize from 'filesize';
export type UploadFileUsage = 'chat' | 'group' | 'user' | 'unknown';
interface UploadFileOptions {
usage?: UploadFileUsage;
onProgress?: (percent: number, progressEvent: unknown) => void;
}
export interface UploadFileResult {
@ -23,6 +26,7 @@ export async function uploadFile(
): Promise<UploadFileResult> {
const form = new FormData();
form.append('file', file);
form.append('usage', options.usage ?? 'unknown');
const uploadFileLimit = getGlobalConfig().uploadFileLimit;
if (file.size > uploadFileLimit) {

@ -39,7 +39,9 @@ export function uploadMessageImage(image: File): Promise<{
}%(${originImageSize} -> ${compressedImageSize})`
);
}
const fileInfo = await uploadFile(uploadImage);
const fileInfo = await uploadFile(uploadImage, {
usage: 'chat',
});
const imageRemoteUrl = fileInfo.url;
resolve({
@ -62,7 +64,9 @@ export async function uploadMessageFile(file: File): Promise<{
name: string;
url: string;
}> {
const fileInfo = await uploadFile(file);
const fileInfo = await uploadFile(file, {
usage: 'chat',
});
return {
name: file.name || fileInfo.etag,

@ -1,13 +1,19 @@
import { blobUrlToFile } from '@/utils/file-helper';
import clsx from 'clsx';
import React, { PropsWithChildren, useState } from 'react';
import { uploadFile, UploadFileResult, useAsyncRequest } from 'tailchat-shared';
import {
uploadFile,
UploadFileResult,
UploadFileUsage,
useAsyncRequest,
} from 'tailchat-shared';
import { ImagePicker } from './ImagePicker';
interface ImageUploaderProps extends PropsWithChildren {
circle?: boolean;
aspect?: number;
className?: string;
usage?: UploadFileUsage;
onUploadSuccess: (fileInfo: UploadFileResult) => void;
}
@ -20,6 +26,7 @@ export const ImageUploader: React.FC<ImageUploaderProps> = React.memo(
const file = await blobUrlToFile(blobUrl);
const fileInfo = await uploadFile(file, {
usage: props.usage,
onProgress(percent) {
const uploadProgress = Number((percent * 100).toFixed());
console.log(`进度:${uploadProgress}`);

@ -92,6 +92,7 @@ export const GroupConfig: React.FC<{
<>
<ImageUploader
aspect={16 / 9}
usage="group"
onUploadSuccess={(fileInfo: UploadFileResult) => {
handleModifyConfig('groupBackgroundImage', fileInfo.url);
}}

@ -65,6 +65,7 @@ export const GroupSummary: React.FC<{
<div className="w-1/3 mobile:w-full mobile:text-center">
<AvatarUploader
circle={true}
usage="group"
onUploadSuccess={handleGroupAvatarChange}
>
<Avatar size={128} name={groupInfo.name} src={groupInfo.avatar} />

@ -95,6 +95,7 @@ export const SettingsAccount: React.FC = React.memo(() => {
<div className="w-1/3 mobile:w-full">
<AvatarUploader
circle={true}
usage="user"
onUploadSuccess={handleUserAvatarChange}
>
<Avatar size={128} src={userInfo.avatar} name={userInfo.nickname} />

@ -163,6 +163,11 @@ export const fileFields = [
width: 140,
},
}),
createTextField('usage', {
list: {
width: 100,
},
}),
createFileSizeField('size', {
list: {
width: 120,
@ -170,12 +175,17 @@ export const fileFields = [
},
}),
createTextField('metaData.content-type'),
createTextField('etag'),
createTextField('etag', {
list: {
width: 300,
},
}),
createUserField('userId', {
reference: 'users',
displayField: 'nickname',
list: {
width: 80,
width: 200,
ellipsis: true,
},
}),
createDateTimeField('createdAt', {

@ -58,6 +58,7 @@ export const zhTranslation = {
objectName: '对象存储名',
url: '文件路径',
size: '文件大小',
usage: '使用场景',
'metaData.content-type': '文件类型',
userId: '存储用户',
createdAt: '创建时间',

@ -51,7 +51,7 @@ export const FileList: React.FC = React.memo(() => {
]}
tableProps={{
scroll: {
x: 1200,
x: 1600,
},
}}
fields={fileFields}

@ -61,6 +61,7 @@ export const SystemConfig: React.FC = React.memo(() => {
if (file) {
const formdata = new FormData();
formdata.append('file', file);
formdata.append('usage', 'server');
const { data } = await request.put('/file/upload', formdata, {
headers: {

@ -56,6 +56,15 @@ export class File extends TimeStamps implements Base {
@prop()
metaData: object;
/**
*
* for example: chat, group, user
*/
@prop({
default: 'unknown',
})
usage: string;
}
export type FileDocument = DocumentType<File>;

@ -112,6 +112,7 @@ class FileService extends TcService {
ctx: TcContext<
{},
{
$multipart: any;
$params: any;
filename: any;
}
@ -129,6 +130,7 @@ class FileService extends TcService {
}
const originFilename = String(ctx.meta.filename);
const usage = _.get(ctx, 'meta.$multipart.usage', 'unknown');
const stream = ctx.params as NodeJS.ReadableStream;
(stream as any).on('error', (err) => {
@ -142,7 +144,8 @@ class FileService extends TcService {
const { etag, objectName, url } = await this.saveFileStream(
ctx,
originFilename,
stream
stream,
usage
);
resolve({
@ -211,7 +214,8 @@ class FileService extends TcService {
async saveFileStream(
ctx: TcContext,
filename: string,
fileStream: NodeJS.ReadableStream
fileStream: NodeJS.ReadableStream,
usage = 'unknown'
): Promise<{ etag: string; url: string; objectName: string }> {
const span = ctx.startSpan('file.saveFileStream');
const ext = path.extname(filename);
@ -234,7 +238,8 @@ class FileService extends TcService {
ctx,
tmpObjectName,
etag,
ext
ext,
usage
);
span.finish();
@ -253,7 +258,8 @@ class FileService extends TcService {
ctx: TcContext,
tmpObjectName: string,
etag: string,
ext: string
ext: string,
usage = 'unknown'
): Promise<{
url: string;
objectName: string;
@ -299,6 +305,7 @@ class FileService extends TcService {
url,
size: stat.size,
metaData: stat.metaData,
usage,
},
{
upsert: true,

Loading…
Cancel
Save