feat: 修改S3配置的类型,并实现系统管理页面中S3相关的账号和cos配置
This commit is contained in:
parent
6ce0cf80aa
commit
88482b96c1
|
|
@ -11,6 +11,140 @@ import {
|
|||
LocalCloudConfig,
|
||||
} from '../../../../types/Config';
|
||||
|
||||
function S3Account(props: {
|
||||
accounts: LocalCloudConfig[];
|
||||
setValue: (path: string, value: any) => void;
|
||||
removeItem: (path: string, index: number) => void;
|
||||
addItem: (path: string, index: number) => void;
|
||||
}) {
|
||||
const { accounts, setValue, removeItem, addItem } = props;
|
||||
return (
|
||||
<Col flex="auto">
|
||||
<Divider orientation="left" className={Styles.title}>
|
||||
S3配置
|
||||
</Divider>
|
||||
<Tabs
|
||||
tabPosition={'top'}
|
||||
size={'middle'}
|
||||
type="editable-card"
|
||||
hideAdd={!(accounts.length > 0)}
|
||||
onEdit={(targetKey: any, action: 'add' | 'remove') => {
|
||||
if (action === 'add') {
|
||||
addItem('', accounts.length);
|
||||
} else {
|
||||
removeItem('', parseInt(targetKey, 10));
|
||||
}
|
||||
}}
|
||||
items={
|
||||
accounts.length > 0
|
||||
? accounts.map((ele, idx) => ({
|
||||
key: `${idx}`,
|
||||
label: `帐号${idx + 1}`,
|
||||
children: (
|
||||
<Form
|
||||
colon={false}
|
||||
labelAlign="left"
|
||||
layout="vertical"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<Form.Item
|
||||
label="accessKey"
|
||||
//name="accessKey"
|
||||
>
|
||||
<>
|
||||
<Input
|
||||
placeholder="请输入accessKey"
|
||||
type="text"
|
||||
value={ele.accessKey}
|
||||
onChange={(e) =>
|
||||
setValue(
|
||||
`${idx}.accessKey`,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="secretKey"
|
||||
//name="secretKey"
|
||||
>
|
||||
<>
|
||||
<Input
|
||||
placeholder="请输入secretKey"
|
||||
type="text"
|
||||
value={ele.secretKey}
|
||||
onChange={(e) =>
|
||||
setValue(
|
||||
`${idx}.secretKey`,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
</Form.Item>
|
||||
|
||||
|
||||
</Form>
|
||||
),
|
||||
}))
|
||||
: [
|
||||
{
|
||||
label: '新建帐号',
|
||||
key: '0',
|
||||
children: (
|
||||
<Form
|
||||
colon={true}
|
||||
labelAlign="left"
|
||||
layout="vertical"
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
<Form.Item
|
||||
label="accessKey"
|
||||
// name="accessKey"
|
||||
>
|
||||
<>
|
||||
<Input
|
||||
placeholder="请输入accessKey"
|
||||
type="text"
|
||||
value=""
|
||||
onChange={(e) =>
|
||||
setValue(
|
||||
`0.accessKey`,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="secretKey"
|
||||
// name="secretKey"
|
||||
>
|
||||
<>
|
||||
<Input
|
||||
placeholder="请输入secretKey"
|
||||
type="text"
|
||||
value=""
|
||||
onChange={(e) =>
|
||||
setValue(
|
||||
`0.secretKey`,
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
></Tabs>
|
||||
</Col>
|
||||
);
|
||||
}
|
||||
|
||||
function LocalAccount(props: {
|
||||
accounts: LocalCloudConfig[];
|
||||
setValue: (path: string, value: any) => void;
|
||||
|
|
@ -1035,7 +1169,7 @@ export default function Account(props: {
|
|||
removeItem: (path: string, index: number) => void;
|
||||
}) {
|
||||
const { account, setValue, removeItem } = props;
|
||||
const { tencent, qiniu, ali, amap, ctyun, local } = account;
|
||||
const { tencent, qiniu, ali, amap, ctyun, local, s3 } = account;
|
||||
return (
|
||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||
<Row>
|
||||
|
|
@ -1073,6 +1207,12 @@ export default function Account(props: {
|
|||
removeItem={(path, index) => removeItem(`local`, index)}
|
||||
addItem={(path, index) => setValue(`local.${index}`, {})}
|
||||
/>
|
||||
<S3Account
|
||||
accounts={s3 || []}
|
||||
setValue={(path, value) => setValue(`s3.${path}`, value)}
|
||||
removeItem={(path, index) => removeItem(`s3`, index)}
|
||||
addItem={(path, index) => setValue(`s3.${index}`, {})}
|
||||
/>
|
||||
<AmapAccount
|
||||
accounts={amap || []}
|
||||
setValue={(path, value) => setValue(`amap.${path}`, value)}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -94,13 +94,12 @@ export type S3Zone =
|
|||
// S3/Minio 配置类型
|
||||
export type S3CosConfig = {
|
||||
accessKey: string;
|
||||
secretKey: string; // S3 需要 secretKey
|
||||
endpoint?: string; // 自定义端点(Minio 必需,AWS S3 可选)
|
||||
buckets: {
|
||||
zone?: S3Zone; // S3 区域 (某些 S3 兼容服务可能不需要)
|
||||
name: string; // 桶名称
|
||||
domain: string; // 访问域名
|
||||
protocol: Protocol | Protocol[];
|
||||
endpoint?: string; // 自定义端点(Minio 必需,AWS S3 可选)
|
||||
pathStyle?: boolean; // 是否使用路径风格 URL(Minio 常用)
|
||||
}[];
|
||||
defaultBucket: string; // 默认上传桶
|
||||
|
|
|
|||
|
|
@ -4,24 +4,36 @@ import { CosBackend } from '../../types/Cos';
|
|||
import S3 from './s3';
|
||||
import { OpSchema } from '../../oak-app-domain/ExtraFile/Schema';
|
||||
|
||||
import { S3CosConfig } from '../../types/Config';
|
||||
import { S3CosConfig, S3Zone } from '../../types/Config';
|
||||
import { S3Instance, S3SDK } from 'oak-external-sdk';
|
||||
import { OakExternalException } from 'oak-domain/lib/types/Exception';
|
||||
|
||||
export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
||||
private getConfigAndInstance(
|
||||
application: EntityDict['application']['Schema']
|
||||
application: EntityDict['application']['Schema'],
|
||||
bucket: string | null | undefined
|
||||
) {
|
||||
const { config, account } = this.getConfig(application);
|
||||
const { config, account, endpoint, defaultBucket } = this.getConfig(application);
|
||||
|
||||
const realBucket = bucket || defaultBucket;
|
||||
assert(realBucket, '没有指定上传桶,且配置中也没有默认上传桶');
|
||||
|
||||
// 在配置中找名称匹配的桶
|
||||
const { buckets } = config as S3CosConfig;
|
||||
let bucketConfig = bucket
|
||||
? buckets.find((ele) => ele.name === realBucket)
|
||||
: buckets[0];
|
||||
|
||||
const instance = S3SDK.getInstance(
|
||||
account.accessKey,
|
||||
account.secretKey,
|
||||
config.buckets[0]?.endpoint, // 使用第一个 bucket 的 endpoint 作为默认
|
||||
config.buckets[0]?.zone
|
||||
endpoint,
|
||||
bucketConfig?.zone || 'us-east-1' as S3Zone
|
||||
);
|
||||
return {
|
||||
config,
|
||||
instance,
|
||||
endpoint,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -31,8 +43,7 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
|||
) {
|
||||
const { bucket } = extraFile;
|
||||
const key = this.formKey(extraFile);
|
||||
const { instance, config: s3CosConfig } =
|
||||
this.getConfigAndInstance(application);
|
||||
const { instance, config: s3CosConfig, endpoint } = this.getConfigAndInstance(application, bucket);
|
||||
|
||||
const { buckets } = s3CosConfig as S3CosConfig;
|
||||
let bucket2 = bucket;
|
||||
|
|
@ -48,7 +59,7 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
|||
const uploadInfo = await (instance as S3Instance).getUploadInfo(
|
||||
bucket2,
|
||||
key,
|
||||
b.endpoint,
|
||||
endpoint,
|
||||
b.pathStyle
|
||||
);
|
||||
|
||||
|
|
@ -65,9 +76,10 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
|||
application: EntityDict['application']['Schema'],
|
||||
extraFile: OpSchema
|
||||
) {
|
||||
const { bucket } = extraFile;
|
||||
const key = this.formKey(extraFile);
|
||||
const { instance, config: s3CosConfig } =
|
||||
this.getConfigAndInstance(application);
|
||||
const { instance, config: s3CosConfig, endpoint } =
|
||||
this.getConfigAndInstance(application, bucket);
|
||||
|
||||
const b = (s3CosConfig as S3CosConfig).buckets.find(
|
||||
(ele) => ele.name === extraFile.bucket
|
||||
|
|
@ -81,7 +93,7 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
|||
const result = await (instance as S3Instance).isExistObject(
|
||||
extraFile.bucket!,
|
||||
key,
|
||||
b.endpoint,
|
||||
endpoint,
|
||||
b.pathStyle
|
||||
);
|
||||
|
||||
|
|
@ -95,9 +107,10 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
|||
application: EntityDict['application']['Schema'],
|
||||
extraFile: OpSchema
|
||||
) {
|
||||
const { bucket } = extraFile
|
||||
const key = this.formKey(extraFile);
|
||||
const { instance, config: s3CosConfig } =
|
||||
this.getConfigAndInstance(application);
|
||||
const { instance, config: s3CosConfig, endpoint } =
|
||||
this.getConfigAndInstance(application, bucket);
|
||||
|
||||
const b = (s3CosConfig as S3CosConfig).buckets.find(
|
||||
(ele) => ele.name === extraFile.bucket
|
||||
|
|
@ -111,7 +124,7 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
|||
await (instance as S3Instance).removeFile(
|
||||
extraFile.bucket!,
|
||||
key,
|
||||
b.endpoint,
|
||||
endpoint,
|
||||
b.pathStyle
|
||||
);
|
||||
} catch (err: any) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export default class S3 implements Cos<EntityDict> {
|
|||
const { config } = system!;
|
||||
const s3Config = config.Cos?.s3;
|
||||
assert(s3Config);
|
||||
const { accessKey } = s3Config;
|
||||
const { accessKey, endpoint, defaultBucket } = s3Config;
|
||||
const account = config.Account?.s3?.find(
|
||||
(ele) => ele.accessKey === accessKey
|
||||
);
|
||||
|
|
@ -28,6 +28,8 @@ export default class S3 implements Cos<EntityDict> {
|
|||
return {
|
||||
config: s3Config,
|
||||
account,
|
||||
endpoint,
|
||||
defaultBucket,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +92,7 @@ export default class S3 implements Cos<EntityDict> {
|
|||
extraFile: Partial<EntityDict['extraFile']['OpSchema']>,
|
||||
style?: string
|
||||
) {
|
||||
const { config: s3CosConfig } = this.getConfig(application);
|
||||
const { config: s3CosConfig, endpoint } = this.getConfig(application);
|
||||
|
||||
if (s3CosConfig) {
|
||||
let bucket = (
|
||||
|
|
@ -98,7 +100,7 @@ export default class S3 implements Cos<EntityDict> {
|
|||
).find((ele) => ele.name === extraFile.bucket!);
|
||||
|
||||
if (bucket) {
|
||||
const { domain, protocol, endpoint, pathStyle } = bucket;
|
||||
const { domain, protocol, pathStyle } = bucket;
|
||||
let protocol2 = protocol;
|
||||
if (protocol instanceof Array) {
|
||||
const index = (protocol as Protocol[]).includes('https:')
|
||||
|
|
|
|||
Loading…
Reference in New Issue