feat: 修改S3配置的类型,并实现系统管理页面中S3相关的账号和cos配置
This commit is contained in:
parent
6ce0cf80aa
commit
88482b96c1
|
|
@ -11,6 +11,140 @@ import {
|
||||||
LocalCloudConfig,
|
LocalCloudConfig,
|
||||||
} from '../../../../types/Config';
|
} 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: {
|
function LocalAccount(props: {
|
||||||
accounts: LocalCloudConfig[];
|
accounts: LocalCloudConfig[];
|
||||||
setValue: (path: string, value: any) => void;
|
setValue: (path: string, value: any) => void;
|
||||||
|
|
@ -1035,7 +1169,7 @@ export default function Account(props: {
|
||||||
removeItem: (path: string, index: number) => void;
|
removeItem: (path: string, index: number) => void;
|
||||||
}) {
|
}) {
|
||||||
const { account, setValue, removeItem } = props;
|
const { account, setValue, removeItem } = props;
|
||||||
const { tencent, qiniu, ali, amap, ctyun, local } = account;
|
const { tencent, qiniu, ali, amap, ctyun, local, s3 } = account;
|
||||||
return (
|
return (
|
||||||
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
|
||||||
<Row>
|
<Row>
|
||||||
|
|
@ -1073,6 +1207,12 @@ export default function Account(props: {
|
||||||
removeItem={(path, index) => removeItem(`local`, index)}
|
removeItem={(path, index) => removeItem(`local`, index)}
|
||||||
addItem={(path, index) => setValue(`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
|
<AmapAccount
|
||||||
accounts={amap || []}
|
accounts={amap || []}
|
||||||
setValue={(path, value) => setValue(`amap.${path}`, value)}
|
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 配置类型
|
// S3/Minio 配置类型
|
||||||
export type S3CosConfig = {
|
export type S3CosConfig = {
|
||||||
accessKey: string;
|
accessKey: string;
|
||||||
secretKey: string; // S3 需要 secretKey
|
endpoint?: string; // 自定义端点(Minio 必需,AWS S3 可选)
|
||||||
buckets: {
|
buckets: {
|
||||||
zone?: S3Zone; // S3 区域 (某些 S3 兼容服务可能不需要)
|
zone?: S3Zone; // S3 区域 (某些 S3 兼容服务可能不需要)
|
||||||
name: string; // 桶名称
|
name: string; // 桶名称
|
||||||
domain: string; // 访问域名
|
domain: string; // 访问域名
|
||||||
protocol: Protocol | Protocol[];
|
protocol: Protocol | Protocol[];
|
||||||
endpoint?: string; // 自定义端点(Minio 必需,AWS S3 可选)
|
|
||||||
pathStyle?: boolean; // 是否使用路径风格 URL(Minio 常用)
|
pathStyle?: boolean; // 是否使用路径风格 URL(Minio 常用)
|
||||||
}[];
|
}[];
|
||||||
defaultBucket: string; // 默认上传桶
|
defaultBucket: string; // 默认上传桶
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,36 @@ import { CosBackend } from '../../types/Cos';
|
||||||
import S3 from './s3';
|
import S3 from './s3';
|
||||||
import { OpSchema } from '../../oak-app-domain/ExtraFile/Schema';
|
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 { S3Instance, S3SDK } from 'oak-external-sdk';
|
||||||
import { OakExternalException } from 'oak-domain/lib/types/Exception';
|
import { OakExternalException } from 'oak-domain/lib/types/Exception';
|
||||||
|
|
||||||
export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
||||||
private getConfigAndInstance(
|
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(
|
const instance = S3SDK.getInstance(
|
||||||
account.accessKey,
|
account.accessKey,
|
||||||
account.secretKey,
|
account.secretKey,
|
||||||
config.buckets[0]?.endpoint, // 使用第一个 bucket 的 endpoint 作为默认
|
endpoint,
|
||||||
config.buckets[0]?.zone
|
bucketConfig?.zone || 'us-east-1' as S3Zone
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
config,
|
config,
|
||||||
instance,
|
instance,
|
||||||
|
endpoint,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,8 +43,7 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
||||||
) {
|
) {
|
||||||
const { bucket } = extraFile;
|
const { bucket } = extraFile;
|
||||||
const key = this.formKey(extraFile);
|
const key = this.formKey(extraFile);
|
||||||
const { instance, config: s3CosConfig } =
|
const { instance, config: s3CosConfig, endpoint } = this.getConfigAndInstance(application, bucket);
|
||||||
this.getConfigAndInstance(application);
|
|
||||||
|
|
||||||
const { buckets } = s3CosConfig as S3CosConfig;
|
const { buckets } = s3CosConfig as S3CosConfig;
|
||||||
let bucket2 = bucket;
|
let bucket2 = bucket;
|
||||||
|
|
@ -48,7 +59,7 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
||||||
const uploadInfo = await (instance as S3Instance).getUploadInfo(
|
const uploadInfo = await (instance as S3Instance).getUploadInfo(
|
||||||
bucket2,
|
bucket2,
|
||||||
key,
|
key,
|
||||||
b.endpoint,
|
endpoint,
|
||||||
b.pathStyle
|
b.pathStyle
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -65,9 +76,10 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
||||||
application: EntityDict['application']['Schema'],
|
application: EntityDict['application']['Schema'],
|
||||||
extraFile: OpSchema
|
extraFile: OpSchema
|
||||||
) {
|
) {
|
||||||
|
const { bucket } = extraFile;
|
||||||
const key = this.formKey(extraFile);
|
const key = this.formKey(extraFile);
|
||||||
const { instance, config: s3CosConfig } =
|
const { instance, config: s3CosConfig, endpoint } =
|
||||||
this.getConfigAndInstance(application);
|
this.getConfigAndInstance(application, bucket);
|
||||||
|
|
||||||
const b = (s3CosConfig as S3CosConfig).buckets.find(
|
const b = (s3CosConfig as S3CosConfig).buckets.find(
|
||||||
(ele) => ele.name === extraFile.bucket
|
(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(
|
const result = await (instance as S3Instance).isExistObject(
|
||||||
extraFile.bucket!,
|
extraFile.bucket!,
|
||||||
key,
|
key,
|
||||||
b.endpoint,
|
endpoint,
|
||||||
b.pathStyle
|
b.pathStyle
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -95,9 +107,10 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
||||||
application: EntityDict['application']['Schema'],
|
application: EntityDict['application']['Schema'],
|
||||||
extraFile: OpSchema
|
extraFile: OpSchema
|
||||||
) {
|
) {
|
||||||
|
const { bucket } = extraFile
|
||||||
const key = this.formKey(extraFile);
|
const key = this.formKey(extraFile);
|
||||||
const { instance, config: s3CosConfig } =
|
const { instance, config: s3CosConfig, endpoint } =
|
||||||
this.getConfigAndInstance(application);
|
this.getConfigAndInstance(application, bucket);
|
||||||
|
|
||||||
const b = (s3CosConfig as S3CosConfig).buckets.find(
|
const b = (s3CosConfig as S3CosConfig).buckets.find(
|
||||||
(ele) => ele.name === extraFile.bucket
|
(ele) => ele.name === extraFile.bucket
|
||||||
|
|
@ -111,7 +124,7 @@ export default class S3Backend extends S3 implements CosBackend<EntityDict> {
|
||||||
await (instance as S3Instance).removeFile(
|
await (instance as S3Instance).removeFile(
|
||||||
extraFile.bucket!,
|
extraFile.bucket!,
|
||||||
key,
|
key,
|
||||||
b.endpoint,
|
endpoint,
|
||||||
b.pathStyle
|
b.pathStyle
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export default class S3 implements Cos<EntityDict> {
|
||||||
const { config } = system!;
|
const { config } = system!;
|
||||||
const s3Config = config.Cos?.s3;
|
const s3Config = config.Cos?.s3;
|
||||||
assert(s3Config);
|
assert(s3Config);
|
||||||
const { accessKey } = s3Config;
|
const { accessKey, endpoint, defaultBucket } = s3Config;
|
||||||
const account = config.Account?.s3?.find(
|
const account = config.Account?.s3?.find(
|
||||||
(ele) => ele.accessKey === accessKey
|
(ele) => ele.accessKey === accessKey
|
||||||
);
|
);
|
||||||
|
|
@ -28,6 +28,8 @@ export default class S3 implements Cos<EntityDict> {
|
||||||
return {
|
return {
|
||||||
config: s3Config,
|
config: s3Config,
|
||||||
account,
|
account,
|
||||||
|
endpoint,
|
||||||
|
defaultBucket,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +92,7 @@ export default class S3 implements Cos<EntityDict> {
|
||||||
extraFile: Partial<EntityDict['extraFile']['OpSchema']>,
|
extraFile: Partial<EntityDict['extraFile']['OpSchema']>,
|
||||||
style?: string
|
style?: string
|
||||||
) {
|
) {
|
||||||
const { config: s3CosConfig } = this.getConfig(application);
|
const { config: s3CosConfig, endpoint } = this.getConfig(application);
|
||||||
|
|
||||||
if (s3CosConfig) {
|
if (s3CosConfig) {
|
||||||
let bucket = (
|
let bucket = (
|
||||||
|
|
@ -98,7 +100,7 @@ export default class S3 implements Cos<EntityDict> {
|
||||||
).find((ele) => ele.name === extraFile.bucket!);
|
).find((ele) => ele.name === extraFile.bucket!);
|
||||||
|
|
||||||
if (bucket) {
|
if (bucket) {
|
||||||
const { domain, protocol, endpoint, pathStyle } = bucket;
|
const { domain, protocol, pathStyle } = bucket;
|
||||||
let protocol2 = protocol;
|
let protocol2 = protocol;
|
||||||
if (protocol instanceof Array) {
|
if (protocol instanceof Array) {
|
||||||
const index = (protocol as Protocol[]).includes('https:')
|
const index = (protocol as Protocol[]).includes('https:')
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue