个人建站+身份认证

This commit is contained in:
谢思 2023-08-22 09:55:48 +08:00
parent 955a62e3a0
commit 602d4a748a
9 changed files with 495 additions and 16 deletions

View File

@ -70,6 +70,10 @@ const Mysite = Loadable({
loader: () => import("./website/mySiteList"),
loading: Loading,
});
const CreateSite = Loadable({
loader: () => import("./website/createSite"),
loading: Loading,
});
function Index(props){
const { current_user,mygetHelmetapi , checkIfLogin } = props;
@ -78,7 +82,6 @@ function Index(props){
const [ avatarVisible , setAvatarVisible ] = useState(false);
const [active, setActive] = useState(1);
console.log('active', active);
useEffect(()=>{
if(checkIfLogin() === false){
@ -87,7 +90,7 @@ function Index(props){
},[])
useEffect(()=>{
console.log('pathname', pathname, ["/settings/profile"].indexOf(pathname));
const pattern = /^\/settings\/installbot\/\d+$/;
if(["/settings/profile"].indexOf(pathname) !== -1){
setActive(1);
}else if(["/settings/emails", "/settings/phone", "/settings/password", "/settings/cancel"].indexOf(pathname) !== -1){
@ -100,11 +103,11 @@ function Index(props){
setActive(5);
}else if(["/settings/CLA"].indexOf(pathname) !== -1){
setActive(6);
}else if(["/settings/mybot"].indexOf(pathname) !== -1){
}else if(["/settings/mybot", "/settings/mybot/new"].indexOf(pathname) !== -1){
setActive(7);
}else if(["/settings/installbot"].indexOf(pathname) !== -1){
}else if(["/settings/installbot"].indexOf(pathname) !== -1 || pattern.test(pathname)){
setActive(8);
}else if(["/settings/mysite"].indexOf(pathname) !== -1){
}else if(["/settings/mysite", "/settings/mysite/create"].indexOf(pathname) !== -1){
setActive(9);
}
}, [pathname])
@ -262,6 +265,13 @@ function Index(props){
<Disposition {...props} {...p}/>
)}
></Route>
{/* 创建站点 */}
<Route
path="/settings/mysite/create"
render={(p) => (
<CreateSite {...props} {...p}/>
)}
></Route>
{/* 个人建站 */}
<Route
path="/settings/mysite"

View File

@ -0,0 +1,177 @@
import React, { useState, useEffect, Fragment } from "react";
import { Button, message, Form, Input, Select } from "antd";
import "./index.scss";
import "../../users/Material/Index.scss";
import axios from "axios";
import { AlignCenter, AlignTop } from "../../Component/layout";
import { Link } from "react-router-dom";
const { TextArea } = Input;
function CreateSite(props) {
const { current_user, history, form } = props;
const { getFieldDecorator, validateFieldsAndScroll, setFieldsValue } = form;
const [tag, setTag] = useState(undefined);
const [language, setLanguage] = useState(undefined);
const [themes, setThemes] = useState([]);
const [theme, setTheme] = useState(undefined);
useEffect(() => {
document.title = "创建站点";
}, []);
useEffect(()=>{
axios.get(`/site_pages/themes.json`, {params: {language_frame: language === 1 ? "jekyll" : language === 2 ? "hexo" : "hugo"}}).then(res=>{
if(res && res.status === 200){
setThemes(res.data.themes);
setTheme(res.data.themes[0])
}
})
}, [language])
useEffect(()=>{
if(theme && theme.clone_url && theme && theme.clone_url.indexOf("/") > -1){
let arr = theme && theme.clone_url.split("/");
let first = arr[arr.length-1];
if(first.indexOf(".") > -1){
let second = first.split('.')[0];
if(!second)return;
setFieldsValue({
repository_name:second,
name:second
})
}else{
setFieldsValue({
repository_name:first
})
}
}
}, [theme])
function submit(e) {
e.preventDefault();
validateFieldsAndScroll((err, values) => {
if (!err) {
axios.post(`/projects/page_migrate.json`,{
...values,
clone_addr: theme && theme.clone_url,
theme: theme && theme.name,
user_id: current_user.user_id
}).then(res=>{
if(res && res.status === 200){
message.success("新建成功");
history.push(`/settings/mysite`);
}
})
}
});
}
return (
<Fragment>
<div className="mySites_head mb30"><Link to={`/settings/mysite`} className="font-16">我的站点 / </Link><span>新建站点</span></div>
<Form
form={form}
name="register"
className="createSiteForm"
scrollToFirstError
layout="horizontal"
labelCol={{ span: 3 }}
wrapperCol={{ span: 16 }}
onSubmit={submit}
>
<Form.Item name="站点名称" label="站点名称">
{getFieldDecorator("site_name", {
rules: [{ required: true, message: "请输入站点名称" }],
})(<Input placeholder="请输入站点名称" />)}
</Form.Item>
<Form.Item
name="站点标识"
label="站点标识"
className="Create-Form-biaoshi"
>
{getFieldDecorator("identifier", {
rules: [{ required: true, message: "请输入站点标识" }],
})(
<Input
onChange={(e) => {
setTag(e.target.value);
}}
placeholder="请输入站点标识"
/>
)}
<span>
http://{current_user.login}.kingchan.cn/{tag}
</span>
</Form.Item>
<Form.Item name="建站工具" label="建站工具">
{getFieldDecorator("language_frame", {initialValue: 0})(
<Select style={{ width: 100 }} onChange={(value)=>{setLanguage(value)}}>
<Select.Option value={0}>hugo</Select.Option>
<Select.Option value={1}>jekyll</Select.Option>
<Select.Option value={2}>hexo</Select.Option>
</Select>
)}
</Form.Item>
<Form.Item name="主题选择" label="主题选择">
<AlignTop>
{themes && themes.map(item=>{
const {imgage_url, name, clone_url} = item;
return <div className="mr20 themeBox" onClick={()=>{setTheme(item)}}>
<i className={`iconfont icon-wancheng ${theme && theme.clone_url === clone_url ? 'active' : ''}`}></i>
<img src={imgage_url} alt="" width="125px"/>
<p>{name}</p>
</div>
})}
</AlignTop>
</Form.Item>
<AlignCenter style={{marginLeft: '58px'}}>
<Form.Item name="拥有者" label="拥有者" style={{width: '260px'}} labelCol={{span: 6}}>
<Input
placeholder={current_user.username}
disabled
/>
</Form.Item>
{/* <span className="mb20 font-18">/</span> */}
<Form.Item
name="项目名称"
label="项目名称"
// 0.87
style={{flex: '0.83'}}
labelCol={{span: 4}}
>
{getFieldDecorator("name", {
rules: [{ required: true, message: "请输入项目名称" }],
})(
<Input placeholder="请输入项目名称"/>
)}
</Form.Item>
</AlignCenter>
<Form.Item name="项目标识" label="项目标识">
{getFieldDecorator("repository_name", {
rules: [{ required: true, message: "请输入项目标识" }],
})(
<Input placeholder="请输入项目标识"/>
)}
</Form.Item>
<Form.Item name="项目简介" label="项目简介">
{getFieldDecorator("description", {})(
<TextArea rows={4} />
)}
</Form.Item>
<Form.Item style={{marginLeft: '123px'}} className="mt40">
<Button type="primary" htmlType="submit" className="mr20">
创建站点
</Button>
<Button
onClick={() => {
history.push("/settings/mysite");
}}
>
取消
</Button>
</Form.Item>
</Form>
</Fragment>
);
}
export default Form.create()(CreateSite);

View File

@ -1,8 +1,30 @@
.default_head{
.mySites_head{
height: 65px;
line-height: 64px;
border-bottom: 1px solid rgba(224, 230, 245, 1);
color:#151d40;
font-size:17px;
padding-bottom:20px;
}
.createSiteForm{
.themeBox{
text-align: center;
position: relative;
cursor: pointer;
}
.icon-wancheng{
position: absolute;
right: 4px;
top: -7px;
color: #e5e3e0;
&.active{
color: #ffa13a;
}
}
}
.siteBox{
padding: 15px 0;
border-bottom: 1px dashed #e0e6f5;
.siteName{
color: $primary-color;
}
}

View File

@ -1,16 +1,70 @@
import React, { useState, useEffect, Fragment } from "react";
import { Button, Icon, message, Modal } from "antd";
import { Button, Spin } from "antd";
import './index.scss';
import '../../users/Material/Index.scss';
import '../bot/exploit/index.scss'
import axios from "axios";
import Nodata from "../../Nodata";
import { FlexAJ } from "../../Component/layout";
function MySiteList(props){
const {current_user} = props;
const {current_user, history} = props;
const {id_card_verify} = current_user;
const [total, setTotal] = useState(0);
const [pages, setPages] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(()=>{
document.title='我的站点';
}, [])
return <Fragment>
<div className="default_head">我的站点</div>
</Fragment>
useEffect(()=>{
if(id_card_verify){
setLoading(true);
//
axios.get(`/site_pages.json`).then(res=>{
if(res && res.status === 200){
const {total_count, pages} = res.data;
setPages(pages);
setTotal(total_count);
}
setLoading(false);
})
}
}, [id_card_verify])
return <Spin spinning={loading}>
<FlexAJ className="mySites_head">
<span>我的站点</span>
{id_card_verify && <Button type="primary" onClick={()=>{history.push(`/settings/mysite/create`)}}>新建站点</Button>}
</FlexAJ>
{/* 未通过实名认证 */}
{!id_card_verify && <Fragment>
<div className="tipsBox font-15 mt30">您尚未通过实名认证无法使用此服务如需使用请先进行实名认证</div>
<Button type="primary" className="mt20" onClick={()=>{history.push(`/settings/verification`)}}>前往验证</Button>
</Fragment>}
{/* 通过实名认证 */}
{id_card_verify && <Fragment>
{!loading && total === 0 ? <div style={{marginTop: '130px'}}><Nodata _html="暂无数据"/></div> : <div className="mt10">
{pages && pages.map(item=>{
const {owner, repo, url, last_build_at} = item
return <FlexAJ>
<div className="siteBox">
<i className="iconfont icon-cangkuyuyanicon font-16 mr5 color-grey-6"></i>
<a className="font-16 siteName" onClick={()=>{last_build_at && window.open(url)}}>{item.site_name}</a>
<span className={`statusBot ml20 font-12 ${last_build_at ? "public" : "private"}`}>{last_build_at ? "已部署" : "未部署"}</span>
<div className="color-grey-6 mt8">
<span className="">主题</span> {item.theme}
<span className="ml5 mr5 color-grey-ccc">|</span>
建站工具{item.language_frame}
</div>
</div>
<Button className="themeCorBorBut" onClick={()=>{history.push(`/${owner}/${repo}/service/pages`)}}>去仓库</Button>
</FlexAJ>
})}
</div>}
</Fragment>}
</Spin>
}
export default MySiteList;

View File

@ -18,6 +18,11 @@ const Reposyncer = Loadable({
loader: () => import('./reposyncer'),
loading: Loading,
})
//
const Pages = Loadable({
loader: () => import('./pages'),
loading: Loading,
})
function ServerIndex(props){
return(
<div className="panels">
@ -32,6 +37,12 @@ function ServerIndex(props){
() => (<Data {...props}/>)
}
></Route>
{/* 个人建站服务 */}
<Route path="/:owner/:projectsId/service/pages"
render={
() => (<Pages {...props}/>)
}
></Route>
<Route path="/:owner/:projectsId/service"
render={
() => (<List {...props}/>)

View File

@ -64,6 +64,16 @@ function Main(props){
<Link to={`/${owner}/${projectsId}/service/reposyncer`} className="btnhover">查看详情</Link>
</span>
</li> */}
<li>
<span className="servername">
<img src={require('./img/logo.png')} alt=""/>
<a onClick={openDetail}>个人建站服务</a>
</span>
<p className="task-hide-2 serverdesc">支持HugoJekyllHexo静态网站服务</p>
<span className="serverbtn">
<Link to={`/${owner}/${projectsId}/service/pages`} className="btnhover">查看详情</Link>
</span>
</li>
</ul>
</div>
)

View File

@ -0,0 +1,187 @@
import React, { Fragment, useEffect, useState } from 'react';
import { Spin, message, Button, Form, Input, Select, Descriptions } from 'antd';
import axios from 'axios';
import SelectBranch from '../../../forge/Branch/Select';
import './index.scss';
import { Link } from 'react-router-dom';
function Pages(props) {
const {current_user, history, form, projectDetail, defaultBranch} = props;
const { owner , projectsId } = props.match.params;
const {id_card_verify} = current_user;
const { getFieldDecorator, validateFieldsAndScroll } = form;
const [reload, setReload] = useState(undefined);
const [loading, setLoading] = useState(false);
const [pageInfo, setPageInfo] = useState(undefined);
const [tag, setTag] = useState(undefined);
const [branch, setBranch ] = useState(null);
const [building, setBuilding] = useState(false);
const [isBuild, setIsBuild] = useState(false);
const [result, setResult] = useState(undefined);
useEffect(()=>{
//
if(projectDetail){
const { author, name} = projectDetail;
document.title = `个人建站-${author.name}/${name}`;
}
}, [projectDetail])
useEffect(()=>{
if(id_card_verify){
setLoading(true);
//
axios.get(`/site_pages/x.json`, {params:{owner, repo: projectsId}}).then(res=>{
if(res && res.status === 200){
setPageInfo(res.data.data)
}
setLoading(false);
})
}
}, [id_card_verify, reload])
//
function submit(e) {
e.preventDefault();
validateFieldsAndScroll((err, values) => {
if (!err) {
axios.post(`/site_pages.json`,{
...values,
owner,
repo: projectsId
}).then(res=>{
if(res && res.status === 200){
setReload(Math.random());
message.success("创建成功");
}
})
}
});
}
//
function startBuild(){
setBuilding(true);
axios.post(`/site_pages/${pageInfo.id}/build.json`,{
owner,
repo: projectsId,
branch: branch || defaultBranch
}).then(res=>{
if(res && res.data && res.data.status === 0){
setResult(res.data.data);
}else{
message.error((res && res.data && res.data.message) || "部署失败,请稍后重试");
}
setBuilding(false);
})
}
return (
<div className='mb100'>
<div className="servertitle">
<span className="systitle">个人建站服务{!pageInfo && !loading && id_card_verify && ' - 新建站点'}</span>
</div>
{/* 未通过实名认证 */}
{!id_card_verify && <Fragment>
<div className="tipsBox font-15 mt30">您尚未通过实名认证无法使用此服务如需使用请先进行实名认证</div>
<Button type="primary" className="mt20" onClick={()=>{history.push(`/settings/verification`)}}>前往验证</Button>
</Fragment>}
{id_card_verify && <Spin spinning={loading}>
{/* 未开通 */}
{!pageInfo && <Form
form={form}
name="register"
className="mt30"
scrollToFirstError
layout="horizontal"
labelCol={{ span: 2 }}
wrapperCol={{ span: 14 }}
onSubmit={submit}
>
<Form.Item name="站点名称" label="站点名称">
{getFieldDecorator("site_name", {
rules: [{ required: true, message: "请输入站点名称" }],
})(<Input placeholder="请输入站点名称" />)}
</Form.Item>
<Form.Item
name="站点标识"
label="站点标识"
className="Create-Form-biaoshi"
>
{getFieldDecorator("identifier", {
rules: [{ required: true, message: "请输入站点标识" }],
})(
<Input
onChange={(e) => {
setTag(e.target.value);
}}
placeholder="请输入站点标识"
/>
)}
<span>
http://{current_user.login}.kingchan.cn/{tag}
</span>
</Form.Item>
<Form.Item name="建站工具" label="建站工具">
{getFieldDecorator("language_frame", {initialValue: 0})(
<Select style={{ width: 100 }}>
<Select.Option value={0}>hugo</Select.Option>
<Select.Option value={1}>jekyll</Select.Option>
<Select.Option value={2}>hexo</Select.Option>
</Select>
)}
</Form.Item>
<Form.Item style={{marginLeft: '100px'}} className="mt40">
<Button type="primary" htmlType="submit" className="mr20">
创建站点
</Button>
<Button
onClick={() => {
history.push(`/${owner}/${projectsId}/service`);
}}
>
取消
</Button>
</Form.Item>
</Form>}
{/* 已开通 */}
{pageInfo && <div className='mt30'>
<Descriptions title="站点信息">
<Descriptions.Item label="站点名称"><a onClick={()=>{window.open(pageInfo.url)}} className='theme-btn'>{pageInfo.site_name}</a></Descriptions.Item>
<Descriptions.Item label="网站地址">{pageInfo.url}</Descriptions.Item>
<Descriptions.Item label="站点工具">{pageInfo.language_frame}</Descriptions.Item>
<Descriptions.Item label="建站时间">{pageInfo.created_at}</Descriptions.Item>
{pageInfo.last_build_at && <Descriptions.Item label="上次部署时间">{pageInfo.last_build_at}</Descriptions.Item>}
</Descriptions>
{!isBuild && <Button type='primary' style={{width: '135px', height: '34px'}} className='mt20' onClick={()=>{setIsBuild(true)}}>去部署</Button>}
{isBuild && <div>
<div className='mt20 ant-descriptions-title'>部署</div>
<div style={{display: 'inline-flex'}}>
<span>部署分支</span>
<SelectBranch
repo_id={projectDetail && projectDetail.repo_id}
projectsId={projectsId}
branch={branch || defaultBranch}
changeBranch={(params)=>{setBranch(params)}}
owner={owner}
history={props.history}
tagflag={false}
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
></SelectBranch>
<span className='color-grey-6 ml30'>选择您要部署的分支</span>
</div>
<div className='mt20'>
<Button type='primary' loading={building} onClick={startBuild}>确定</Button>
<Button type='primary' ghost onClick={()=>{setIsBuild(false)}} className='ml30'>取消</Button>
</div>
</div>}
</div>}
{result && <div className='mt30'>
<div className='mt20 ant-descriptions-title'>部署结果</div>
<div className='buildResult'>{result.map(item=> <p>{item}</p>)}</div>
</div>}
</Spin>}
</div>
)
}
export default Form.create()(Pages);

View File

@ -0,0 +1,8 @@
.buildResult{
padding: 10px 20px;
background-color: rgb(20, 20, 20);
color: white;
}
.theme-btn{
color: $primary-color;
}

View File

@ -9,7 +9,7 @@ import { getImageUrl } from '../../../common/UrlTool';
export default Form.create()(
forwardRef((props)=>{
const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
const { resetUserInfo , current_user } = props;
const { current_user } = props;
const [loading, setLoading] = useState(false);
const [data, setData] = useState(undefined);
const [reload, setReload] = useState(undefined);
@ -18,7 +18,7 @@ export default Form.create()(
if(current_user && current_user.login){
setLoading(true);
//
axios.get(`http://ng.learnerhub.net/api/identity_verifications.json`).then(res=>{
axios.get(`/identity_verifications.json`).then(res=>{
setLoading(false);
if(res && res.status === 200){
if(res.data && res.data.status === 0){
@ -38,7 +38,7 @@ export default Form.create()(
validateFields((error, values) => {
if (!error) {
if(data){
axios.put(`http://ng.learnerhub.net/api/identity_verifications/${data.id}.json`, values).then(res => {
axios.put(`/identity_verifications/${data.id}.json`, values).then(res => {
if(res && res.status === 200){
message.success("提交成功");
setReload(Math.random());
@ -46,7 +46,7 @@ export default Form.create()(
}).catch((error) => {});
}else{
//
axios.post(`http://ng.learnerhub.net/api/identity_verifications.json`, values).then(res=>{
axios.post(`/identity_verifications.json`, values).then(res=>{
if(res && res.status === 200){
message.success("提交成功");
setReload(Math.random());