mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-26 04:02:47 +00:00
1179 lines
53 KiB
JavaScript
1179 lines
53 KiB
JavaScript
import Button from "@material-ui/core/Button";
|
||
import Collapse from "@material-ui/core/Collapse";
|
||
import FormControl from "@material-ui/core/FormControl";
|
||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||
import Input from "@material-ui/core/Input";
|
||
import InputLabel from "@material-ui/core/InputLabel";
|
||
import Link from "@material-ui/core/Link";
|
||
import MenuItem from "@material-ui/core/MenuItem";
|
||
import Radio from "@material-ui/core/Radio";
|
||
import RadioGroup from "@material-ui/core/RadioGroup";
|
||
import Select from "@material-ui/core/Select";
|
||
import Step from "@material-ui/core/Step";
|
||
import StepLabel from "@material-ui/core/StepLabel";
|
||
import Stepper from "@material-ui/core/Stepper";
|
||
import { lighten, makeStyles } from "@material-ui/core/styles";
|
||
import Typography from "@material-ui/core/Typography";
|
||
import React, { useCallback, useState } from "react";
|
||
import { useDispatch } from "react-redux";
|
||
import { useHistory } from "react-router";
|
||
import { toggleSnackbar } from "../../../../actions";
|
||
import API from "../../../../middleware/Api";
|
||
import { getNumber } from "../../../../utils";
|
||
import DomainInput from "../../Common/DomainInput";
|
||
import SizeInput from "../../Common/SizeInput";
|
||
import MagicVar from "../../Dialogs/MagicVar";
|
||
|
||
const useStyles = makeStyles(theme => ({
|
||
stepContent: {
|
||
padding: "16px 32px 16px 32px"
|
||
},
|
||
form: {
|
||
maxWidth: 400,
|
||
marginTop: 20
|
||
},
|
||
formContainer: {
|
||
[theme.breakpoints.up("md")]: {
|
||
padding: "0px 24px 0 24px"
|
||
}
|
||
},
|
||
subStepContainer: {
|
||
display: "flex",
|
||
marginBottom: 20,
|
||
padding: 10,
|
||
transition: theme.transitions.create("background-color", {
|
||
easing: theme.transitions.easing.sharp,
|
||
duration: theme.transitions.duration.leavingScreen
|
||
}),
|
||
"&:focus-within": {
|
||
backgroundColor: theme.palette.background.default
|
||
}
|
||
},
|
||
stepNumber: {
|
||
width: 20,
|
||
height: 20,
|
||
backgroundColor: lighten(theme.palette.secondary.light, 0.2),
|
||
color: theme.palette.secondary.contrastText,
|
||
textAlign: "center",
|
||
borderRadius: " 50%"
|
||
},
|
||
stepNumberContainer: {
|
||
marginRight: 10
|
||
},
|
||
stepFooter: {
|
||
marginTop: 32
|
||
},
|
||
button: {
|
||
marginRight: theme.spacing(1)
|
||
},
|
||
viewButtonLabel: { textTransform: "none" },
|
||
"@global": {
|
||
code: {
|
||
color: "rgba(0, 0, 0, 0.87)",
|
||
display: "inline-block",
|
||
padding: "2px 6px",
|
||
fontFamily:
|
||
' Consolas, "Liberation Mono", Menlo, Courier, monospace',
|
||
borderRadius: "2px",
|
||
backgroundColor: "rgba(255,229,100,0.1)"
|
||
}
|
||
}
|
||
}));
|
||
|
||
const steps = [
|
||
{
|
||
title: "存储空间",
|
||
optional: false
|
||
},
|
||
{
|
||
title: "上传路径",
|
||
optional: false
|
||
},
|
||
{
|
||
title: "直链设置",
|
||
optional: false
|
||
},
|
||
{
|
||
title: "上传限制",
|
||
optional: false
|
||
},
|
||
{
|
||
title: "跨域策略",
|
||
optional: true
|
||
},
|
||
{
|
||
title: "云函数回调",
|
||
optional: true
|
||
},
|
||
{
|
||
title: "完成",
|
||
optional: false
|
||
}
|
||
];
|
||
|
||
export default function COSGuide(props) {
|
||
const classes = useStyles();
|
||
const history = useHistory();
|
||
|
||
const [activeStep, setActiveStep] = useState(0);
|
||
const [loading, setLoading] = useState(false);
|
||
const [skipped, setSkipped] = React.useState(new Set());
|
||
const [magicVar, setMagicVar] = useState("");
|
||
const [useCDN, setUseCDN] = useState("false");
|
||
const [policy, setPolicy] = useState(
|
||
props.policy
|
||
? props.policy
|
||
: {
|
||
Type: "cos",
|
||
Name: "",
|
||
SecretKey: "",
|
||
AccessKey: "",
|
||
BaseURL: "",
|
||
Server: "",
|
||
IsPrivate: "true",
|
||
DirNameRule: "uploads/{year}/{month}/{day}",
|
||
AutoRename: "true",
|
||
FileNameRule: "{randomkey8}_{originname}",
|
||
IsOriginLinkEnable: "false",
|
||
MaxSize: "0",
|
||
OptionsSerialized: {
|
||
file_type: ""
|
||
}
|
||
}
|
||
);
|
||
const [policyID, setPolicyID] = useState(
|
||
props.policy ? props.policy.ID : 0
|
||
);
|
||
const [region, setRegion] = useState("ap-chengdu");
|
||
|
||
const handleChange = name => event => {
|
||
setPolicy({
|
||
...policy,
|
||
[name]: event.target.value
|
||
});
|
||
};
|
||
|
||
const handleOptionChange = name => event => {
|
||
setPolicy({
|
||
...policy,
|
||
OptionsSerialized: {
|
||
...policy.OptionsSerialized,
|
||
[name]: event.target.value
|
||
}
|
||
});
|
||
};
|
||
|
||
const isStepSkipped = step => {
|
||
return skipped.has(step);
|
||
};
|
||
|
||
const dispatch = useDispatch();
|
||
const ToggleSnackbar = useCallback(
|
||
(vertical, horizontal, msg, color) =>
|
||
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
|
||
[dispatch]
|
||
);
|
||
|
||
const submitPolicy = e => {
|
||
e.preventDefault();
|
||
setLoading(true);
|
||
|
||
const policyCopy = { ...policy };
|
||
policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized };
|
||
|
||
if (useCDN === "false") {
|
||
policyCopy.BaseURL = policy.Server;
|
||
}
|
||
|
||
// 类型转换
|
||
policyCopy.AutoRename = policyCopy.AutoRename === "true";
|
||
policyCopy.IsOriginLinkEnable =
|
||
policyCopy.IsOriginLinkEnable === "true";
|
||
policyCopy.IsPrivate = policyCopy.IsPrivate === "true";
|
||
policyCopy.MaxSize = parseInt(policyCopy.MaxSize);
|
||
policyCopy.OptionsSerialized.file_type = policyCopy.OptionsSerialized.file_type.split(
|
||
","
|
||
);
|
||
if (
|
||
policyCopy.OptionsSerialized.file_type.length === 1 &&
|
||
policyCopy.OptionsSerialized.file_type[0] === ""
|
||
) {
|
||
policyCopy.OptionsSerialized.file_type = [];
|
||
}
|
||
|
||
API.post("/admin/policy", {
|
||
policy: policyCopy
|
||
})
|
||
.then(response => {
|
||
ToggleSnackbar(
|
||
"top",
|
||
"right",
|
||
"存储策略已" + (props.policy ? "保存" : "添加"),
|
||
"success"
|
||
);
|
||
setActiveStep(4);
|
||
setPolicyID(response.data);
|
||
})
|
||
.catch(error => {
|
||
ToggleSnackbar("top", "right", error.message, "error");
|
||
})
|
||
.then(() => {
|
||
setLoading(false);
|
||
});
|
||
|
||
setLoading(false);
|
||
};
|
||
|
||
const createCORS = () => {
|
||
setLoading(true);
|
||
API.post("/admin/policy/cors", {
|
||
id: policyID
|
||
})
|
||
.then(() => {
|
||
ToggleSnackbar("top", "right", "跨域策略已添加", "success");
|
||
setActiveStep(5);
|
||
})
|
||
.catch(error => {
|
||
ToggleSnackbar("top", "right", error.message, "error");
|
||
})
|
||
.then(() => {
|
||
setLoading(false);
|
||
});
|
||
};
|
||
|
||
const creatCallback = () => {
|
||
setLoading(true);
|
||
API.post("/admin/policy/scf", {
|
||
id: policyID,
|
||
region: region
|
||
})
|
||
.then(() => {
|
||
ToggleSnackbar("top", "right", "回调云函数已添加", "success");
|
||
setActiveStep(6);
|
||
})
|
||
.catch(error => {
|
||
ToggleSnackbar("top", "right", error.message, "error");
|
||
})
|
||
.then(() => {
|
||
setLoading(false);
|
||
});
|
||
};
|
||
|
||
return (
|
||
<div>
|
||
<Typography variant={"h6"}>
|
||
{props.policy ? "修改" : "添加"} 腾讯云 COS 存储策略
|
||
</Typography>
|
||
<Stepper activeStep={activeStep}>
|
||
{steps.map((label, index) => {
|
||
const stepProps = {};
|
||
const labelProps = {};
|
||
if (label.optional) {
|
||
labelProps.optional = (
|
||
<Typography variant="caption">可选</Typography>
|
||
);
|
||
}
|
||
if (isStepSkipped(index)) {
|
||
stepProps.completed = false;
|
||
}
|
||
return (
|
||
<Step key={label.title} {...stepProps}>
|
||
<StepLabel {...labelProps}>{label.title}</StepLabel>
|
||
</Step>
|
||
);
|
||
})}
|
||
</Stepper>
|
||
|
||
{activeStep === 0 && (
|
||
<form
|
||
className={classes.stepContent}
|
||
onSubmit={e => {
|
||
e.preventDefault();
|
||
setActiveStep(1);
|
||
}}
|
||
>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>0</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
在使用 腾讯云 COS 储策略前,请确保您在 参数设置
|
||
- 站点信息 - 站点URL 中填写的
|
||
地址与实际相符,并且
|
||
<strong>能够被外网正常访问</strong>。
|
||
</Typography>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>1</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
前往
|
||
<Link
|
||
href={
|
||
"https://console.cloud.tencent.com/cos5"
|
||
}
|
||
target={"_blank"}
|
||
>
|
||
COS 管理控制台
|
||
</Link>
|
||
创建存储桶。
|
||
</Typography>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>2</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
转到所创建存储桶的基础配置页面,将
|
||
<code>空间名称</code>填写在下方:
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor="component-helper">
|
||
空间名称
|
||
</InputLabel>
|
||
<Input
|
||
inputProps={{
|
||
pattern: "[a-z0-9-]+-[0-9]+",
|
||
title:
|
||
"空间名格式不正确, 举例:ccc-1252109809"
|
||
}}
|
||
required
|
||
value={policy.BucketName}
|
||
onChange={handleChange("BucketName")}
|
||
/>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>3</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
在下方选择您创建的空间的访问权限类型,推荐选择
|
||
<code>私有读写</code>
|
||
以获得更高的安全性,私有空间无法开启“获取直链”功能。
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl required component="fieldset">
|
||
<RadioGroup
|
||
required
|
||
value={policy.IsPrivate}
|
||
onChange={handleChange("IsPrivate")}
|
||
row
|
||
>
|
||
<FormControlLabel
|
||
value={"true"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="私有读写"
|
||
/>
|
||
<FormControlLabel
|
||
value={"false"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="公共读私有写"
|
||
/>
|
||
</RadioGroup>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>4</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
转到所创建 Bucket 的基础配置,填写
|
||
<code>基本信息</code>栏目下 给出的{" "}
|
||
<code>访问域名</code>
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<DomainInput
|
||
value={policy.Server}
|
||
onChange={handleChange("Server")}
|
||
required
|
||
label={"访问域名"}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>5</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
是否要使用配套的 腾讯云CDN 加速 COS 访问?
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl required component="fieldset">
|
||
<RadioGroup
|
||
required
|
||
value={useCDN}
|
||
onChange={e => {
|
||
setUseCDN(e.target.value);
|
||
}}
|
||
row
|
||
>
|
||
<FormControlLabel
|
||
value={"true"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="使用"
|
||
/>
|
||
<FormControlLabel
|
||
value={"false"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="不使用"
|
||
/>
|
||
</RadioGroup>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<Collapse in={useCDN === "true"}>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>6</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
前往
|
||
<Link
|
||
href={
|
||
"https://console.cloud.tencent.com/cdn/access/guid"
|
||
}
|
||
target={"_blank"}
|
||
>
|
||
腾讯云 CDN 管理控制台
|
||
</Link>
|
||
创建 CDN 加速域名,并设定源站为刚创建的 COS
|
||
存储桶。在下方填写 CDN
|
||
加速域名,并选择是否使用 HTTPS:
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<DomainInput
|
||
value={policy.BaseURL}
|
||
onChange={handleChange("BaseURL")}
|
||
required={useCDN === "true"}
|
||
label={"CDN 加速域名"}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Collapse>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>
|
||
{getNumber(6, [useCDN === "true"])}
|
||
</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
在腾讯云
|
||
<Link
|
||
href={
|
||
"https://console.cloud.tencent.com/cam/capi"
|
||
}
|
||
target={"_blank"}
|
||
>
|
||
访问密钥
|
||
</Link>
|
||
页面获取
|
||
一对访问密钥,并填写在下方。请确保这对密钥拥有
|
||
COS 和 SCF 服务的访问权限。
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor="component-helper">
|
||
SecretId
|
||
</InputLabel>
|
||
<Input
|
||
required
|
||
inputProps={{
|
||
pattern: "\\S+",
|
||
title: "不能含有空格"
|
||
}}
|
||
value={policy.AccessKey}
|
||
onChange={handleChange("AccessKey")}
|
||
/>
|
||
</FormControl>
|
||
</div>
|
||
<div className={classes.form}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor="component-helper">
|
||
SecretKey
|
||
</InputLabel>
|
||
<Input
|
||
required
|
||
inputProps={{
|
||
pattern: "\\S+",
|
||
title: "不能含有空格"
|
||
}}
|
||
value={policy.SecretKey}
|
||
onChange={handleChange("SecretKey")}
|
||
/>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>
|
||
{getNumber(7, [useCDN === "true"])}
|
||
</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
为此存储策略命名:
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor="component-helper">
|
||
存储策略名
|
||
</InputLabel>
|
||
<Input
|
||
required
|
||
value={policy.Name}
|
||
onChange={handleChange("Name")}
|
||
/>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.stepFooter}>
|
||
<Button
|
||
disabled={loading}
|
||
type={"submit"}
|
||
variant={"contained"}
|
||
color={"primary"}
|
||
>
|
||
下一步
|
||
</Button>
|
||
</div>
|
||
</form>
|
||
)}
|
||
|
||
{activeStep === 1 && (
|
||
<form
|
||
className={classes.stepContental}
|
||
onSubmit={e => {
|
||
e.preventDefault();
|
||
setActiveStep(2);
|
||
}}
|
||
>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>1</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
请在下方输入文件的存储目录路径,可以为绝对路径或相对路径(相对于
|
||
从机的
|
||
Cloudreve)。路径中可以使用魔法变量,文件在上传时会自动替换这些变量为相应值;
|
||
可用魔法变量可参考{" "}
|
||
<Link
|
||
color={"secondary"}
|
||
onClick={e => {
|
||
e.preventDefault();
|
||
setMagicVar("path");
|
||
}}
|
||
>
|
||
路径魔法变量列表
|
||
</Link>{" "}
|
||
。
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor="component-helper">
|
||
存储目录
|
||
</InputLabel>
|
||
<Input
|
||
required
|
||
value={policy.DirNameRule}
|
||
onChange={handleChange("DirNameRule")}
|
||
/>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>2</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
是否需要对存储的物理文件进行重命名?此处的重命名不会影响最终呈现给用户的
|
||
文件名。文件名也可使用魔法变量,
|
||
可用魔法变量可参考{" "}
|
||
<Link
|
||
color={"secondary"}
|
||
onClick={e => {
|
||
e.preventDefault();
|
||
setMagicVar("file");
|
||
}}
|
||
>
|
||
文件名魔法变量列表
|
||
</Link>{" "}
|
||
。
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl required component="fieldset">
|
||
<RadioGroup
|
||
aria-label="gender"
|
||
name="gender1"
|
||
value={policy.AutoRename}
|
||
onChange={handleChange("AutoRename")}
|
||
row
|
||
>
|
||
<FormControlLabel
|
||
value={"true"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="开启重命名"
|
||
/>
|
||
<FormControlLabel
|
||
value={"false"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="不开启"
|
||
/>
|
||
</RadioGroup>
|
||
</FormControl>
|
||
</div>
|
||
|
||
<Collapse in={policy.AutoRename === "true"}>
|
||
<div className={classes.form}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor="component-helper">
|
||
命名规则
|
||
</InputLabel>
|
||
<Input
|
||
required={
|
||
policy.AutoRename === "true"
|
||
}
|
||
value={policy.FileNameRule}
|
||
onChange={handleChange(
|
||
"FileNameRule"
|
||
)}
|
||
/>
|
||
</FormControl>
|
||
</div>
|
||
</Collapse>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.stepFooter}>
|
||
<Button
|
||
color={"default"}
|
||
className={classes.button}
|
||
onClick={() => setActiveStep(0)}
|
||
>
|
||
上一步
|
||
</Button>
|
||
<Button
|
||
disabled={loading}
|
||
type={"submit"}
|
||
variant={"contained"}
|
||
color={"primary"}
|
||
>
|
||
下一步
|
||
</Button>
|
||
</div>
|
||
</form>
|
||
)}
|
||
|
||
{activeStep === 2 && (
|
||
<form
|
||
className={classes.stepContent}
|
||
onSubmit={e => {
|
||
e.preventDefault();
|
||
setActiveStep(3);
|
||
}}
|
||
>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>1</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
是否允许获取文件永久直链?
|
||
<br />
|
||
开启后,用户可以请求获得能直接访问到文件内容的直链,适用于图床应用或自用。
|
||
</Typography>
|
||
|
||
<div className={classes.form}>
|
||
<FormControl required component="fieldset">
|
||
<RadioGroup
|
||
required
|
||
value={policy.IsOriginLinkEnable}
|
||
onChange={e => {
|
||
if (
|
||
policy.IsPrivate === "true" &&
|
||
e.target.value === "true"
|
||
) {
|
||
ToggleSnackbar(
|
||
"top",
|
||
"right",
|
||
"私有空间无法开启此功能",
|
||
"warning"
|
||
);
|
||
return;
|
||
}
|
||
handleChange("IsOriginLinkEnable")(
|
||
e
|
||
);
|
||
}}
|
||
row
|
||
>
|
||
<FormControlLabel
|
||
value={"true"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="允许"
|
||
/>
|
||
<FormControlLabel
|
||
value={"false"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="禁止"
|
||
/>
|
||
</RadioGroup>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={classes.stepFooter}>
|
||
<Button
|
||
color={"default"}
|
||
className={classes.button}
|
||
onClick={() => setActiveStep(1)}
|
||
>
|
||
上一步
|
||
</Button>{" "}
|
||
<Button
|
||
disabled={loading}
|
||
type={"submit"}
|
||
variant={"contained"}
|
||
color={"primary"}
|
||
>
|
||
下一步
|
||
</Button>
|
||
</div>
|
||
</form>
|
||
)}
|
||
|
||
{activeStep === 3 && (
|
||
<form className={classes.stepContent} onSubmit={submitPolicy}>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>1</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
是否限制上传的单文件大小?
|
||
</Typography>
|
||
|
||
<div className={classes.form}>
|
||
<FormControl required component="fieldset">
|
||
<RadioGroup
|
||
required
|
||
value={
|
||
policy.MaxSize === "0"
|
||
? "false"
|
||
: "true"
|
||
}
|
||
onChange={e => {
|
||
if (e.target.value === "true") {
|
||
setPolicy({
|
||
...policy,
|
||
MaxSize: "10485760"
|
||
});
|
||
} else {
|
||
setPolicy({
|
||
...policy,
|
||
MaxSize: "0"
|
||
});
|
||
}
|
||
}}
|
||
row
|
||
>
|
||
<FormControlLabel
|
||
value={"true"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="限制"
|
||
/>
|
||
<FormControlLabel
|
||
value={"false"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="不限制"
|
||
/>
|
||
</RadioGroup>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<Collapse in={policy.MaxSize !== "0"}>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>2</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
输入限制:
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<SizeInput
|
||
value={policy.MaxSize}
|
||
onChange={handleChange("MaxSize")}
|
||
min={0}
|
||
max={9223372036854775807}
|
||
label={"单文件大小限制"}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Collapse>
|
||
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>
|
||
{policy.MaxSize !== "0" ? "3" : "2"}
|
||
</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
是否限制上传文件扩展名?
|
||
</Typography>
|
||
|
||
<div className={classes.form}>
|
||
<FormControl required component="fieldset">
|
||
<RadioGroup
|
||
required
|
||
value={
|
||
policy.OptionsSerialized
|
||
.file_type === ""
|
||
? "false"
|
||
: "true"
|
||
}
|
||
onChange={e => {
|
||
if (e.target.value === "true") {
|
||
setPolicy({
|
||
...policy,
|
||
OptionsSerialized: {
|
||
...policy.OptionsSerialized,
|
||
file_type:
|
||
"jpg,png,mp4,zip,rar"
|
||
}
|
||
});
|
||
} else {
|
||
setPolicy({
|
||
...policy,
|
||
OptionsSerialized: {
|
||
...policy.OptionsSerialized,
|
||
file_type: ""
|
||
}
|
||
});
|
||
}
|
||
}}
|
||
row
|
||
>
|
||
<FormControlLabel
|
||
value={"true"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="限制"
|
||
/>
|
||
<FormControlLabel
|
||
value={"false"}
|
||
control={
|
||
<Radio color={"primary"} />
|
||
}
|
||
label="不限制"
|
||
/>
|
||
</RadioGroup>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<Collapse in={policy.OptionsSerialized.file_type !== ""}>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer}>
|
||
<div className={classes.stepNumber}>
|
||
{policy.MaxSize !== "0" ? "4" : "3"}
|
||
</div>
|
||
</div>
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
输入允许上传的文件扩展名,多个请以半角逗号 ,
|
||
隔开
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor="component-helper">
|
||
扩展名列表
|
||
</InputLabel>
|
||
<Input
|
||
value={
|
||
policy.OptionsSerialized
|
||
.file_type
|
||
}
|
||
onChange={handleOptionChange(
|
||
"file_type"
|
||
)}
|
||
/>
|
||
</FormControl>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Collapse>
|
||
|
||
<div className={classes.stepFooter}>
|
||
<Button
|
||
color={"default"}
|
||
className={classes.button}
|
||
onClick={() => setActiveStep(2)}
|
||
>
|
||
上一步
|
||
</Button>{" "}
|
||
<Button
|
||
disabled={loading}
|
||
type={"submit"}
|
||
variant={"contained"}
|
||
color={"primary"}
|
||
>
|
||
下一步
|
||
</Button>
|
||
</div>
|
||
</form>
|
||
)}
|
||
|
||
{activeStep === 4 && (
|
||
<form className={classes.stepContent}>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer} />
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
COS 存储桶 需要正确配置跨域策略后才能使用 Web
|
||
端上传文件,Cloudreve
|
||
可以帮您自动设置,您也可以参考文档步骤手动设置。如果您已设置过此
|
||
Bucket 的跨域策略,此步骤可以跳过。
|
||
</Typography>
|
||
<div className={classes.form}>
|
||
<Button
|
||
disabled={loading}
|
||
color={"secondary"}
|
||
variant={"contained"}
|
||
className={classes.button}
|
||
onClick={() => createCORS()}
|
||
classes={{ label: classes.viewButtonLabel }}
|
||
>
|
||
让 Cloudreve 帮我设置
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className={classes.stepFooter}>
|
||
<Button
|
||
color={"default"}
|
||
className={classes.button}
|
||
onClick={() => {
|
||
setActiveStep(
|
||
prevActiveStep => prevActiveStep + 1
|
||
);
|
||
setSkipped(prevSkipped => {
|
||
const newSkipped = new Set(
|
||
prevSkipped.values()
|
||
);
|
||
newSkipped.add(activeStep);
|
||
return newSkipped;
|
||
});
|
||
}}
|
||
>
|
||
跳过
|
||
</Button>{" "}
|
||
</div>
|
||
</form>
|
||
)}
|
||
|
||
{activeStep === 5 && (
|
||
<form className={classes.stepContent}>
|
||
<div className={classes.subStepContainer}>
|
||
<div className={classes.stepNumberContainer} />
|
||
<div className={classes.subStepContent}>
|
||
<Typography variant={"body2"}>
|
||
COS 存储桶 客户端直传需要借助腾讯云的
|
||
<Link
|
||
href={
|
||
"https://console.cloud.tencent.com/scf/index?rid=16"
|
||
}
|
||
target={"_blank"}
|
||
>
|
||
云函数
|
||
</Link>
|
||
产品以确保上传回调可控。如果您打算将此存储策略自用,或者分配给可信赖用户组,此步骤可以跳过。
|
||
如果是作为公有使用,请务必创建回调云函数。
|
||
<br />
|
||
<br />
|
||
</Typography>
|
||
<Typography variant={"body2"}>
|
||
Cloudreve 可以尝试帮你自动创建回调云函数,请选择
|
||
COS 存储桶 所在地域后继续。
|
||
创建可能会花费数秒钟,请耐心等待。创建前请确保您的腾讯云账号已开启云函数服务。
|
||
</Typography>
|
||
|
||
<div className={classes.form}>
|
||
<FormControl>
|
||
<InputLabel htmlFor="component-helper">
|
||
存储桶所在地区
|
||
</InputLabel>
|
||
<Select
|
||
value={region}
|
||
onChange={e =>
|
||
setRegion(e.target.value)
|
||
}
|
||
required
|
||
>
|
||
<MenuItem value={"ap-beijing"}>
|
||
华北地区(北京)
|
||
</MenuItem>
|
||
<MenuItem value={"ap-chengdu"}>
|
||
西南地区(成都)
|
||
</MenuItem>
|
||
<MenuItem value={"ap-guangzhou"}>
|
||
华南地区(广州)
|
||
</MenuItem>
|
||
<MenuItem value={"ap-guangzhou-open"}>
|
||
华南地区(广州Open)
|
||
</MenuItem>
|
||
<MenuItem value={"ap-hongkong"}>
|
||
港澳台地区(中国香港)
|
||
</MenuItem>
|
||
<MenuItem value={"ap-mumbai"}>
|
||
亚太南部(孟买)
|
||
</MenuItem>
|
||
<MenuItem value={"ap-shanghai"}>
|
||
华东地区(上海)
|
||
</MenuItem>
|
||
<MenuItem value={"ap-singapore"}>
|
||
亚太东南(新加坡)
|
||
</MenuItem>
|
||
<MenuItem value={"na-siliconvalley"}>
|
||
美国西部(硅谷)
|
||
</MenuItem>
|
||
<MenuItem value={"na-toronto"}>
|
||
北美地区(多伦多)
|
||
</MenuItem>
|
||
</Select>
|
||
</FormControl>
|
||
</div>
|
||
|
||
<div className={classes.form}>
|
||
<Button
|
||
disabled={loading}
|
||
color={"secondary"}
|
||
variant={"contained"}
|
||
className={classes.button}
|
||
onClick={() => creatCallback()}
|
||
classes={{ label: classes.viewButtonLabel }}
|
||
>
|
||
让 Cloudreve 帮我创建
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className={classes.stepFooter}>
|
||
<Button
|
||
color={"default"}
|
||
className={classes.button}
|
||
onClick={() => {
|
||
setActiveStep(
|
||
prevActiveStep => prevActiveStep + 1
|
||
);
|
||
setSkipped(prevSkipped => {
|
||
const newSkipped = new Set(
|
||
prevSkipped.values()
|
||
);
|
||
newSkipped.add(activeStep);
|
||
return newSkipped;
|
||
});
|
||
}}
|
||
>
|
||
跳过
|
||
</Button>{" "}
|
||
</div>
|
||
</form>
|
||
)}
|
||
|
||
{activeStep === 6 && (
|
||
<>
|
||
<form className={classes.stepContent}>
|
||
<Typography>
|
||
存储策略已{props.policy ? "保存" : "添加"}!
|
||
</Typography>
|
||
<Typography variant={"body2"} color={"textSecondary"}>
|
||
要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。
|
||
</Typography>
|
||
</form>
|
||
<div className={classes.stepFooter}>
|
||
<Button
|
||
color={"primary"}
|
||
className={classes.button}
|
||
onClick={() => history.push("/admin/policy")}
|
||
>
|
||
返回存储策略列表
|
||
</Button>
|
||
</div>
|
||
</>
|
||
)}
|
||
|
||
<MagicVar
|
||
open={magicVar === "file"}
|
||
isFile
|
||
onClose={() => setMagicVar("")}
|
||
/>
|
||
<MagicVar
|
||
open={magicVar === "path"}
|
||
onClose={() => setMagicVar("")}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|