From 67a6f3faabfc0bd9660ef79a4dc05431741e8bcf Mon Sep 17 00:00:00 2001 From: HFO4 <912394456@qq.com> Date: Thu, 27 Feb 2020 12:53:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=83=E7=89=9B=E5=AD=98=E5=82=A8=E7=AD=96?= =?UTF-8?q?=E7=95=A5=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/component/Admin/Common/DomainInput.js | 12 + src/component/Admin/Dialogs/AddPolicy.js | 5 + src/component/Admin/Policy/AddPolicy.js | 2 + src/component/Admin/Policy/Guid/QiniuGuide.js | 972 ++++++++++++++++++ src/untils/index.js | 9 + 5 files changed, 1000 insertions(+) create mode 100644 src/component/Admin/Policy/Guid/QiniuGuide.js diff --git a/src/component/Admin/Common/DomainInput.js b/src/component/Admin/Common/DomainInput.js index ea34a9f..90c248d 100644 --- a/src/component/Admin/Common/DomainInput.js +++ b/src/component/Admin/Common/DomainInput.js @@ -7,10 +7,12 @@ import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; import {useDispatch} from "react-redux"; import {toggleSnackbar} from "../../../actions"; +import FormHelperText from "@material-ui/core/FormHelperText"; export default function DomainInput({onChange,value,required,label}){ const [domain,setDomain] = useState(""); const [protocol,setProtocol] = useState("https://"); + const [error,setError] = useState(); useState(()=>{ if (value.startsWith("https://")){ @@ -22,12 +24,21 @@ export default function DomainInput({onChange,value,required,label}){ } },[value]); + useEffect(()=>{ + if(protocol === "http://" && window.location.protocol === "https:"){ + setError("您当前站点启用了 HTTPS ,此处选择 HTTP 可能会导致无法连接。") + }else{ + setError("") + } + },[protocol]) + return ( {label} { setDomain(e.target.value); @@ -59,6 +70,7 @@ export default function DomainInput({onChange,value,required,label}){ } /> + {error !== "" && {error}} ) } \ No newline at end of file diff --git a/src/component/Admin/Dialogs/AddPolicy.js b/src/component/Admin/Dialogs/AddPolicy.js index 45f3c3f..e47c666 100644 --- a/src/component/Admin/Dialogs/AddPolicy.js +++ b/src/component/Admin/Dialogs/AddPolicy.js @@ -47,22 +47,27 @@ const policies = [ { name:"七牛", img:"qiniu.png", + path:"/admin/policy/add/qiniu", }, { name:"阿里云 OSS", img:"oss.png", + path:"/admin/policy/add/soo", }, { name:"又拍云", img:"upyun.png", + path:"/admin/policy/add/upyun", }, { name:"腾讯云 COS", img:"upyun.png", + path:"/admin/policy/add/cos", }, { name:"OneDrive", img:"onedrive.png", + path:"/admin/policy/add/onedrive", }, ]; diff --git a/src/component/Admin/Policy/AddPolicy.js b/src/component/Admin/Policy/AddPolicy.js index d6cfd9e..d0faa4f 100644 --- a/src/component/Admin/Policy/AddPolicy.js +++ b/src/component/Admin/Policy/AddPolicy.js @@ -4,6 +4,7 @@ import Paper from "@material-ui/core/Paper"; import {useParams} from "react-router"; import LocalGuide from "./Guid/LocalGuide"; import RemoteGuide from "./Guid/RemoteGuide"; +import QiniuGuide from "./Guid/QiniuGuide"; const useStyles = makeStyles(theme => ({ root: { @@ -29,6 +30,7 @@ export default function AddPolicyParent( ) { {type==="local"&&} {type==="remote"&&} + {type==="qiniu"&&} ); diff --git a/src/component/Admin/Policy/Guid/QiniuGuide.js b/src/component/Admin/Policy/Guid/QiniuGuide.js new file mode 100644 index 0000000..2f985c6 --- /dev/null +++ b/src/component/Admin/Policy/Guid/QiniuGuide.js @@ -0,0 +1,972 @@ +import { lighten, makeStyles } from "@material-ui/core/styles"; +import React, { useCallback, useEffect, useState } from "react"; +import Stepper from "@material-ui/core/Stepper"; +import StepLabel from "@material-ui/core/StepLabel"; +import Step from "@material-ui/core/Step"; +import Typography from "@material-ui/core/Typography"; +import { useDispatch } from "react-redux"; +import { changeSubTitle, toggleSnackbar } from "../../../../actions"; +import Link from "@material-ui/core/Link"; +import FormControl from "@material-ui/core/FormControl"; +import InputLabel from "@material-ui/core/InputLabel"; +import Input from "@material-ui/core/Input"; +import RadioGroup from "@material-ui/core/RadioGroup"; +import FormControlLabel from "@material-ui/core/FormControlLabel"; +import Radio from "@material-ui/core/Radio"; +import Collapse from "@material-ui/core/Collapse"; +import Button from "@material-ui/core/Button"; +import API from "../../../../middleware/Api"; +import MagicVar from "../../Dialogs/MagicVar"; +import DomainInput from "../../Common/DomainInput"; +import SizeInput from "../../Common/SizeInput"; +import { useHistory } from "react-router"; +import Alert from "@material-ui/lab/Alert"; +import {getNumber, randomStr} from "../../../../untils"; + +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) + } +})); + +const steps = [ + { + title: "存储空间", + optional: false + }, + { + title: "上传路径", + optional: false + }, + { + title: "直链设置", + optional: false + }, + { + title: "上传限制", + optional: false + }, + { + title: "完成", + optional: false + } +]; + +export default function RemoteGuide() { + 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({ + Type: "qiniu", + Name: "", + SecretKey: "", + AccessKey: "", + BaseURL: "", + IsPrivate: "true", + DirNameRule: "uploads/{year}/{month}/{day}", + AutoRename: "true", + FileNameRule: "{randomkey8}_{originname}", + IsOriginLinkEnable: "false", + MaxSize: "0", + OptionsSerialized: { + file_type: "", + mimetype:"", + } + }); + + 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 testSlave = () => { + setLoading(true); + + // 测试路径是否可用 + API.post("/admin/policy/test/slave", { + server: policy.Server, + secret: policy.SecretKey + }) + .then(response => { + ToggleSnackbar("top", "right", "通信正常", "success"); + }) + .catch(error => { + ToggleSnackbar("top", "right", error.message, "error"); + }) + .finally(() => { + setLoading(false); + }); + }; + + const submitPolicy = e => { + e.preventDefault(); + setLoading(true); + + let policyCopy = { ...policy }; + policyCopy.OptionsSerialized = { ...policyCopy.OptionsSerialized }; + + // 类型转换 + 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", "存储策略已添加", "success"); + setActiveStep(5); + }) + .catch(error => { + ToggleSnackbar("top", "right", error.message, "error"); + }) + .finally(() => { + setLoading(false); + }); + + setLoading(false); + }; + + return ( +
+ 添加七牛存储策略 + + {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
+
+
+ + 在使用七牛存储策略前,请确保您在 参数设置 - 站点信息 + - 站点URL 中填写的 地址与实际相符,并且 + 能够被外网正常访问。 + +
+
+ +
+
+
1
+
+
+ + 前往 + + 七牛控制面板 + + 创建对象存储资源。 + +
+
+ +
+
+
2
+
+
+ + 在下方填写您在七牛创建存储空间时指定的“存储空间名称”: + +
+ + + 存储空间名称 + + + +
+
+
+ +
+
+
3
+
+
+ + 在下方选择您创建的空间类型,推荐选择“私有空间”以获得更高的安全性,私有空间无法开启“获取直链”功能。 + +
+ + + + } + label="私有" + /> + + } + label="公有" + /> + + +
+
+
+ +
+
+
4
+
+
+ + 填写您为存储空间绑定的 CDN 加速域名。 + +
+ +
+
+
+ +
+
+
5
+
+
+ + 在七牛控制面板进入 个人中心 - + 密钥管理,在下方填写获得到的 AK、SK。 + +
+ + + AK + + + +
+
+ + + SK + + + +
+
+
+ +
+ +
+
+ )} + + {activeStep === 1 && ( +
{ + e.preventDefault(); + setActiveStep(2); + }} + > +
+
+
1
+
+
+ + 请在下方输入文件的存储目录路径,可以为绝对路径或相对路径(相对于 + 从机的 + Cloudreve)。路径中可以使用魔法变量,文件在上传时会自动替换这些变量为相应值; + 可用魔法变量可参考{" "} + setMagicVar("path")} + > + 路径魔法变量列表 + {" "} + 。 + +
+ + + 存储目录 + + + +
+
+
+ +
+
+
2
+
+
+ + 是否需要对存储的物理文件进行重命名?此处的重命名不会影响最终呈现给用户的 + 文件名。文件名也可使用魔法变量, + 可用魔法变量可参考{" "} + 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 && ( +
{ + e.preventDefault(); + setActiveStep(4); + }} + > +
+
+
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"} +
+
+
+ + 输入允许上传的文件扩展名,多个请以半角逗号 , + 隔开 + +
+ + + 扩展名列表 + + + +
+
+
+
+ +
+
+
+ {getNumber(3,[ + policy.MaxSize !== "0", + policy.OptionsSerialized.file_type !== "", + ])} +
+
+
+ + 是否限制上传文件 MimeType? + + +
+ + { + if (e.target.value === "true") { + setPolicy({ + ...policy, + OptionsSerialized: { + ...policy.OptionsSerialized, + mimetype: + "image/*" + } + }); + } else { + setPolicy({ + ...policy, + OptionsSerialized: { + ...policy.OptionsSerialized, + mimetype: "" + } + }); + } + }} + row + > + + } + label="限制" + /> + + } + label="不限制" + /> + + +
+
+
+ + +
+
+
+ {getNumber(4,[ + policy.MaxSize !== "0", + policy.OptionsSerialized.file_type !== "", + ])} +
+
+
+ + 输入允许上传的 MimeType,多个请以半角逗号 , + 隔开。七牛服务器会侦测文件内容以判断 MimeType,再用判断值跟指定值进行匹配,匹配成功则允许上传 + +
+ + + MimeType 列表 + + + +
+
+
+
+ +
+ {" "} + +
+
+ )} + + {activeStep === 4 && ( +
+
+
+
+ + 最后一步,为此存储策略命名: + +
+ + + 存储策略名 + + + +
+
+
+
+ {" "} + +
+
+ )} + + {activeStep === 5 && ( + <> +
+ 存储策略已添加! + + 要使用此存储策略,请到用户组管理页面,为相应用户组绑定此存储策略。 + +
+
+ +
+ + )} + + setMagicVar("")} + /> + setMagicVar("")} + /> +
+ ); +} diff --git a/src/untils/index.js b/src/untils/index.js index f039b8e..9f6c7ec 100644 --- a/src/untils/index.js +++ b/src/untils/index.js @@ -179,4 +179,13 @@ export function randomStr(length) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; +} + +export function getNumber(base,conditions){ + conditions.forEach(v=>{ + if(v){ + base++ + } + }) + return base } \ No newline at end of file