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 (
{props.policy ? "修改" : "添加"} 腾讯云 COS 存储策略 {steps.map((label, index) => { const stepProps = {}; const labelProps = {}; if (label.optional) { labelProps.optional = ( 可选 ); } if (isStepSkipped(index)) { stepProps.completed = false; } return ( {label.title} ); })} {activeStep === 0 && (
{ e.preventDefault(); setActiveStep(1); }} >
0
在使用 腾讯云 COS 储策略前,请确保您在 参数设置 - 站点信息 - 站点URL 中填写的 地址与实际相符,并且 能够被外网正常访问
1
前往 COS 管理控制台 创建存储桶。
2
转到所创建存储桶的基础配置页面,将 空间名称填写在下方:
空间名称
3
在下方选择您创建的空间的访问权限类型,推荐选择 私有读写 以获得更高的安全性,私有空间无法开启“获取直链”功能。
} label="私有读写" /> } label="公共读私有写" />
4
转到所创建 Bucket 的基础配置,填写 基本信息栏目下 给出的{" "} 访问域名
5
是否要使用配套的 腾讯云CDN 加速 COS 访问?
{ setUseCDN(e.target.value); }} row > } label="使用" /> } label="不使用" />
6
前往 腾讯云 CDN 管理控制台 创建 CDN 加速域名,并设定源站为刚创建的 COS 存储桶。在下方填写 CDN 加速域名,并选择是否使用 HTTPS:
{getNumber(6, [useCDN === "true"])}
在腾讯云 访问密钥 页面获取 一对访问密钥,并填写在下方。请确保这对密钥拥有 COS 和 SCF 服务的访问权限。
SecretId
SecretKey
{getNumber(7, [useCDN === "true"])}
为此存储策略命名:
存储策略名
)} {activeStep === 1 && (
{ e.preventDefault(); setActiveStep(2); }} >
1
请在下方输入文件的存储目录路径,可以为绝对路径或相对路径(相对于 从机的 Cloudreve)。路径中可以使用魔法变量,文件在上传时会自动替换这些变量为相应值; 可用魔法变量可参考{" "} { e.preventDefault(); setMagicVar("path"); }} > 路径魔法变量列表 {" "} 。
存储目录
2
是否需要对存储的物理文件进行重命名?此处的重命名不会影响最终呈现给用户的 文件名。文件名也可使用魔法变量, 可用魔法变量可参考{" "} { e.preventDefault(); setMagicVar("file"); }} > 文件名魔法变量列表 {" "} 。
} label="开启重命名" /> } label="不开启" />
命名规则
)} {activeStep === 2 && (
{ e.preventDefault(); setActiveStep(3); }} >
1
是否允许获取文件永久直链?
开启后,用户可以请求获得能直接访问到文件内容的直链,适用于图床应用或自用。
{ if ( policy.IsPrivate === "true" && e.target.value === "true" ) { ToggleSnackbar( "top", "right", "私有空间无法开启此功能", "warning" ); return; } handleChange("IsOriginLinkEnable")( e ); }} row > } label="允许" /> } label="禁止" />
{" "}
)} {activeStep === 3 && (
1
是否限制上传的单文件大小?
{ if (e.target.value === "true") { setPolicy({ ...policy, MaxSize: "10485760" }); } else { setPolicy({ ...policy, MaxSize: "0" }); } }} row > } label="限制" /> } label="不限制" />
2
输入限制:
{policy.MaxSize !== "0" ? "3" : "2"}
是否限制上传文件扩展名?
{ 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 > } label="限制" /> } label="不限制" />
{policy.MaxSize !== "0" ? "4" : "3"}
输入允许上传的文件扩展名,多个请以半角逗号 , 隔开
扩展名列表
{" "}
)} {activeStep === 4 && (
COS 存储桶 需要正确配置跨域策略后才能使用 Web 端上传文件,Cloudreve 可以帮您自动设置,您也可以参考文档步骤手动设置。如果您已设置过此 Bucket 的跨域策略,此步骤可以跳过。
{" "}
)} {activeStep === 5 && (
COS 存储桶 客户端直传需要借助腾讯云的 云函数 产品以确保上传回调可控。如果您打算将此存储策略自用,或者分配给可信赖用户组,此步骤可以跳过。 如果是作为公有使用,请务必创建回调云函数。

Cloudreve 可以尝试帮你自动创建回调云函数,请选择 COS 存储桶 所在地域后继续。 创建可能会花费数秒钟,请耐心等待。创建前请确保您的腾讯云账号已开启云函数服务。
存储桶所在地区
{" "}
)} {activeStep === 6 && ( <>
存储策略已{props.policy ? "保存" : "添加"}! 要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。
)} setMagicVar("")} /> setMagicVar("")} />
); }