init
This commit is contained in:
commit
27883febe1
|
@ -0,0 +1,16 @@
|
|||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
|
@ -0,0 +1,20 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/npm-debug.log*
|
||||
/yarn-error.log
|
||||
/yarn.lock
|
||||
/package-lock.json
|
||||
|
||||
# production
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
# umi
|
||||
/src/.umi
|
||||
/src/.umi-production
|
||||
/src/.umi-test
|
||||
/.env.local
|
|
@ -0,0 +1,8 @@
|
|||
**/*.md
|
||||
**/*.svg
|
||||
**/*.ejs
|
||||
**/*.html
|
||||
package.json
|
||||
.umi
|
||||
.umi-production
|
||||
.umi-test
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 80,
|
||||
"overrides": [
|
||||
{
|
||||
"files": ".prettierrc",
|
||||
"options": { "parser": "json" }
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { defineConfig } from 'umi';
|
||||
|
||||
export default defineConfig({
|
||||
nodeModulesTransform: {
|
||||
type: 'all',
|
||||
},
|
||||
hash: true,
|
||||
title:"forge",
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
component: '@/layouts/index' ,
|
||||
routes:[
|
||||
{ path:"/",exact:true,component:"@/pages/users/index" },
|
||||
{ path:'/projects',exact:true,component:"@/pages/index" }
|
||||
]
|
||||
},
|
||||
],
|
||||
locale:{
|
||||
default:"zh-CN",
|
||||
antd:true
|
||||
}
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
# umi project
|
||||
|
||||
## Getting Started
|
||||
|
||||
Install dependencies,
|
||||
|
||||
```bash
|
||||
$ yarn
|
||||
```
|
||||
|
||||
Start the dev server,
|
||||
|
||||
```bash
|
||||
$ yarn start
|
||||
```
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"local": "cross-env API_ENV=local umi dev",
|
||||
"start": "cross-env API_ENV=dev umi dev",
|
||||
"build": "cross-env API_ENV=build umi build",
|
||||
"postinstall": "umi generate tmp",
|
||||
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
||||
"test": "umi-test",
|
||||
"test:coverage": "umi-test --coverage"
|
||||
},
|
||||
"gitHooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,less,md,json}": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.ts?(x)": [
|
||||
"prettier --parser=typescript --write"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/pro-layout": "^5.0.12",
|
||||
"@umijs/preset-react": "1.x",
|
||||
"@umijs/test": "^3.2.16",
|
||||
"lint-staged": "^10.0.7",
|
||||
"prettier": "^1.19.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-slick": "^0.28.1",
|
||||
"umi": "^3.2.16",
|
||||
"yorkie": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-slick": "^0.23.4",
|
||||
"cross-env": "^7.0.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
@import './styles/iconfont/iconfont.css';
|
||||
@import './styles/base.less';
|
|
@ -0,0 +1,12 @@
|
|||
import { message } from 'antd';
|
||||
import moment from 'moment';
|
||||
moment.locale('ZH-cn');
|
||||
import './app.less';
|
||||
|
||||
export const dva = {
|
||||
config: {
|
||||
onError(e: Error) {
|
||||
message.error(e.message, 3)
|
||||
},
|
||||
},
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
.newFooter{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: #323232;
|
||||
clear: both;
|
||||
min-width: 1200px;
|
||||
z-index: 8;
|
||||
left: 0;
|
||||
div[class~='footerInfos']{
|
||||
display: flex;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
justify-content: space-around;
|
||||
padding: 60px 0;
|
||||
ul {
|
||||
padding: 0 40px;
|
||||
box-sizing: border-box;
|
||||
max-width: 25%;
|
||||
text-align: left;
|
||||
li:first-child {
|
||||
font-size: 17px;
|
||||
}
|
||||
li {
|
||||
color: #fff;
|
||||
font-weight: 300;
|
||||
list-style: none;
|
||||
line-height: 28px;
|
||||
a,span {
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p[class~='footerCopy']{
|
||||
color: #bbb;
|
||||
border-top: 1px solid #4e4e4e;
|
||||
padding: 10px 0;
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
a {
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
import React , {FC} from 'react';
|
||||
import styles from './index.less';
|
||||
import {
|
||||
ConnectProps ,
|
||||
Dispatch ,
|
||||
connect,
|
||||
GlobalSettingModelState,
|
||||
Loading
|
||||
} from 'umi';
|
||||
|
||||
interface FooterProps extends Partial<ConnectProps>{
|
||||
loading:Loading,
|
||||
globalSetting:GlobalSettingModelState,
|
||||
dispatch:Dispatch
|
||||
}
|
||||
|
||||
const FootCompontent:FC<FooterProps> = ({
|
||||
globalSetting,
|
||||
loading,
|
||||
dispatch
|
||||
}) =>{
|
||||
return(
|
||||
<div className={styles.newFooter} dangerouslySetInnerHTML={{ __html:globalSetting.setting?.footer}}></div>
|
||||
)
|
||||
}
|
||||
export default connect(
|
||||
({globalSetting, loading}:{globalSetting:GlobalSettingModelState,loading:Loading})=>({
|
||||
globalSetting
|
||||
})
|
||||
)(FootCompontent);
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import React , {FC, useEffect} from 'react';
|
||||
import {
|
||||
history
|
||||
} from 'umi';
|
||||
import { Form , Modal , Input , Radio , Button , notification } from 'antd';
|
||||
import { applyProject } from '@/service/common';
|
||||
import styles from './index.less';
|
||||
|
||||
interface PageProps{
|
||||
visible:boolean,
|
||||
onCancel:()=>void
|
||||
}
|
||||
|
||||
const JoinProjectModel: FC<PageProps>=({
|
||||
visible,
|
||||
onCancel
|
||||
})=>{
|
||||
const [ form ] = Form.useForm();
|
||||
|
||||
const finishFunc=async (values:any)=>{
|
||||
const res = await applyProject(values);
|
||||
if(res.status){
|
||||
notification.open({message:"提示",description:res.message});
|
||||
}
|
||||
}
|
||||
|
||||
function clearBox(){
|
||||
form.setFieldsValue({});
|
||||
onCancel();
|
||||
}
|
||||
|
||||
return(
|
||||
<Modal
|
||||
title="加入项目"
|
||||
width="480px"
|
||||
visible={visible}
|
||||
centered={true}
|
||||
footer={null}
|
||||
className={styles.joinProjectModal}
|
||||
>
|
||||
<Form
|
||||
labelCol={{span:6}}
|
||||
wrapperCol={{ span : 18}}
|
||||
onFinish={finishFunc}
|
||||
>
|
||||
<Form.Item
|
||||
label="项目邀请码"
|
||||
name="code"
|
||||
rules={[{required:true,message:"请输入项目邀请码"}]}
|
||||
>
|
||||
<Input placeholder="请输入项目邀请码" autoComplete="off" maxLength={6}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="选择角色"
|
||||
name="role"
|
||||
rules={[{required:true,message:"请选择角色"}]}
|
||||
initialValue={"developer"}
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value={"manager"}>管理员</Radio>
|
||||
<Radio value={"developer"}>开发者</Radio>
|
||||
<Radio value={"reporter"}>报告者</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<div className={styles.modelBtn}>
|
||||
<Button size={"middle"} className="mr20" onClick={clearBox}>取消</Button>
|
||||
<Button htmlType="submit" type={"primary"} size={"middle"}>保存</Button>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default JoinProjectModel;
|
|
@ -0,0 +1,34 @@
|
|||
.joinMenu{
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 0px 10px #e6e6e6;
|
||||
padding:5px 0px;
|
||||
border-radius: 2px;
|
||||
div[class~='ant-row']{
|
||||
min-width: 120px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
width: 100%;
|
||||
&:hover{
|
||||
a{color: #4cacff;}
|
||||
}
|
||||
a{
|
||||
color: #333;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.joinProjectModal{
|
||||
div[class~='ant-modal-body']{
|
||||
padding:0px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
div[class~="ant-row"]{
|
||||
padding:0px 20px;
|
||||
}
|
||||
}
|
||||
.modelBtn{
|
||||
text-align: right;
|
||||
border-top: 1px solid #eee;
|
||||
padding:15px 20px;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import React , { FC, useState } from 'react';
|
||||
import { Dropdown , Col , Row } from 'antd';
|
||||
import {
|
||||
Link
|
||||
}from 'umi';
|
||||
import styles from './index.less';
|
||||
|
||||
import {
|
||||
connect,
|
||||
Dispatch,
|
||||
UserModelState,
|
||||
GlobalSettingModelState,
|
||||
Loading,
|
||||
history,
|
||||
ConnectProps
|
||||
} from 'umi';
|
||||
import JoinProjectModel from './JoinProjectModel';
|
||||
|
||||
interface PageProps extends Partial<ConnectProps>{
|
||||
user:UserModelState,
|
||||
globalSetting:GlobalSettingModelState,
|
||||
loading:boolean,
|
||||
dispatch:Dispatch
|
||||
}
|
||||
|
||||
const Join: FC<PageProps>=({
|
||||
user,
|
||||
globalSetting,
|
||||
loading,
|
||||
dispatch
|
||||
})=>{
|
||||
const [ joinProjectVisible , setJoinProjectVisible ] = useState(false);
|
||||
|
||||
|
||||
const RenderJoin =
|
||||
<Col>
|
||||
<Row><Link to={``}>新建镜像项目</Link></Row>
|
||||
<Row><Link to={``}>新建托管项目</Link></Row>
|
||||
<Row><Link to={``}>新建组织</Link></Row>
|
||||
<Row><a onClick={()=>setJoinProjectVisible(true)}>加入项目</a></Row>
|
||||
</Col>
|
||||
|
||||
return(
|
||||
<section>
|
||||
<Dropdown overlay={<div className={styles.joinMenu}>{RenderJoin}</div>} placement={"bottomRight"}>
|
||||
<i className="iconfont icon-tianjiafangda font18 c-g-6 pr15 pl15"></i>
|
||||
</Dropdown>
|
||||
<JoinProjectModel visible={joinProjectVisible} onCancel={()=>setJoinProjectVisible(false)}/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
export default connect(
|
||||
({
|
||||
user,
|
||||
globalSetting,
|
||||
loading
|
||||
}:{
|
||||
user:UserModelState,
|
||||
globalSetting:GlobalSettingModelState,
|
||||
loading:Loading
|
||||
})=>({
|
||||
user,
|
||||
globalSetting,
|
||||
loading:loading.models.index
|
||||
})
|
||||
)(Join)
|
|
@ -0,0 +1,20 @@
|
|||
.unlogin{
|
||||
a{
|
||||
padding:0px 10px;
|
||||
position: relative;
|
||||
color: #333;
|
||||
&:first-child::after{
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
margin-top: -7px;
|
||||
top: 50%;
|
||||
width: 1px;
|
||||
background-color: #999;
|
||||
right: 0px;
|
||||
}
|
||||
&:last-child{
|
||||
padding-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import React , { FC , useEffect , useState } from 'react';
|
||||
import styles from './index.less';
|
||||
import {
|
||||
connect,
|
||||
ConnectProps,
|
||||
UserModelState,
|
||||
Dispatch,
|
||||
} from 'umi';
|
||||
|
||||
interface PageProps extends Partial<ConnectProps> {
|
||||
user: UserModelState;
|
||||
dispatch: Dispatch;
|
||||
}
|
||||
|
||||
const User: FC<PageProps> = ({
|
||||
user
|
||||
})=>{
|
||||
return(
|
||||
<div>
|
||||
{
|
||||
user?.userInfo?.login ? "已登录":
|
||||
<span className={styles.unlogin}>
|
||||
<a>登录</a>
|
||||
<a>注册</a>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default connect(
|
||||
({
|
||||
user,
|
||||
}: {
|
||||
user: UserModelState
|
||||
}) => ({
|
||||
user,
|
||||
}),
|
||||
)(User)
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
.header{
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 0px 14px #e6e6e6;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.headbox{
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
section{
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
a[class~='headlogo']{
|
||||
margin-bottom: 0px;
|
||||
img{
|
||||
width: 45px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.headUl{
|
||||
display: flex;
|
||||
margin-bottom: 0px;
|
||||
padding:0px;
|
||||
padding-left: 50px;
|
||||
li{
|
||||
list-style-type: none;
|
||||
a{
|
||||
display: block;
|
||||
padding-right:40px;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.operateBox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
div[class~='flexAlignC']{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
import React ,{ FC , useEffect, useState } from 'react';
|
||||
import styles from './index.less';
|
||||
import {
|
||||
UserModelState ,
|
||||
ConnectProps ,
|
||||
Dispatch ,
|
||||
connect,
|
||||
GlobalSettingModelState,
|
||||
Link,
|
||||
useHistory
|
||||
} from 'umi';
|
||||
import { Layout , Input } from 'antd';
|
||||
import ENV from '@/utils/env';
|
||||
import Join from './components/Join';
|
||||
import User from './components/User';
|
||||
const { Search } = Input;
|
||||
|
||||
interface HeadProps extends Partial<ConnectProps>{
|
||||
user:UserModelState,
|
||||
globalSetting:GlobalSettingModelState,
|
||||
dispatch:Dispatch
|
||||
}
|
||||
|
||||
const HeadComponents:FC<HeadProps> = ({
|
||||
user,
|
||||
globalSetting,
|
||||
dispatch
|
||||
}) =>{
|
||||
const history = useHistory();
|
||||
const [ openSearch ,setOpenSearch ] = useState(false);
|
||||
|
||||
const SearchInput = () => {
|
||||
if (openSearch) {
|
||||
return (
|
||||
<div className={"flexAlignC"}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
setOpenSearch(false)
|
||||
}, 300)
|
||||
}}
|
||||
>
|
||||
<Search placeholder="请输入搜索关键字"
|
||||
style={{width:"260px"}}
|
||||
onSearch={onGlobalSearch}
|
||||
autoFocus={true}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="iconfont icon-sousuo font18 c-g-6 ml15 mr15" onClick={() => {
|
||||
setOpenSearch(true)
|
||||
}} />
|
||||
)
|
||||
}
|
||||
}
|
||||
function onGlobalSearch(value: string) {
|
||||
history.push('/search?value=' + value);
|
||||
}
|
||||
return(
|
||||
<Layout className={styles.header}>
|
||||
<div className={styles.headbox}>
|
||||
<section>
|
||||
{
|
||||
globalSetting?.setting?.tab_logo_url &&
|
||||
<Link to={''} className={"headlogo"}>
|
||||
<img src={`${ENV.IMG_SERVER}/${globalSetting?.setting?.tab_logo_url}`} />
|
||||
</Link>
|
||||
}
|
||||
<ul className={styles.headUl}>
|
||||
{
|
||||
globalSetting?.setting?.navbar.map(function(
|
||||
i:{hidden:boolean,link:string,name:string},
|
||||
k:number
|
||||
){
|
||||
if(!i.hidden){
|
||||
return(
|
||||
<li key={k}><a href={i.link}>{i.name}</a></li>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</section>
|
||||
<div className={styles.operateBox}>
|
||||
<SearchInput />
|
||||
{
|
||||
user?.userInfo?.login && <Join />
|
||||
}
|
||||
{
|
||||
globalSetting?.setting?.common?.notice &&
|
||||
<i className="iconfont icon-xiaoxilingdang pl15 pr15 pointer"></i>
|
||||
}
|
||||
<User/>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
export default connect(
|
||||
({
|
||||
user,
|
||||
globalSetting
|
||||
}:{
|
||||
user:UserModelState,
|
||||
globalSetting:GlobalSettingModelState
|
||||
})=>({
|
||||
user,
|
||||
globalSetting
|
||||
})
|
||||
)(HeadComponents)
|
|
@ -0,0 +1,53 @@
|
|||
.listbox{
|
||||
display: flex;
|
||||
}
|
||||
.boxItem{
|
||||
width:208px;
|
||||
margin-right: 30px;
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #eee;
|
||||
div[class~='mainInfo']{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 160px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
img{
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
span[class~="name"]{
|
||||
margin-top: 12px;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
span[class~="author"]{
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
div[class~="baseInfo"]{
|
||||
padding: 18px 15px;
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import React , { FC , useEffect , useState } from 'react';
|
||||
import {
|
||||
connect,
|
||||
ProjectHomeState,
|
||||
Dispatch
|
||||
}
|
||||
from 'umi';
|
||||
import styles from './index.less';
|
||||
import ENV from '@/utils/env';
|
||||
|
||||
interface PageProps{
|
||||
projectHome:ProjectHomeState,
|
||||
dispatch:Dispatch
|
||||
}
|
||||
|
||||
const Recommand:FC<PageProps>=({
|
||||
projectHome,
|
||||
dispatch
|
||||
})=>{
|
||||
|
||||
useEffect(()=>{
|
||||
dispatch({
|
||||
type:"projectHome/getRecommandList",
|
||||
payload:{}
|
||||
})
|
||||
},[projectHome.name])
|
||||
|
||||
if(projectHome.recommandList && projectHome.recommandList.length> 0){
|
||||
return(
|
||||
<div className={styles.listbox}>
|
||||
{
|
||||
projectHome?.recommandList?.map(function(
|
||||
v:{name:string,identifier:string,visits:number,category:any,author:any},
|
||||
k:number
|
||||
){
|
||||
return(
|
||||
<div className={styles.boxItem} key={k}>
|
||||
<div className="mainInfo">
|
||||
<img src={`${ENV.IMG_SERVER}/${v.author?.image_url}`} alt=""/>
|
||||
<span className="name">{v.name}</span>
|
||||
<span className="author">{v.author?.name}</span>
|
||||
</div>
|
||||
<div className="baseInfo">
|
||||
<span>
|
||||
<i className="iconfont icon-dianjiliang font12 mr3"></i>{v.visits}
|
||||
</span>
|
||||
<span>{v.category?.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}else{
|
||||
return <></>
|
||||
}
|
||||
}
|
||||
export default connect(
|
||||
({projectHome}:{projectHome:ProjectHomeState})=>({projectHome}))(Recommand)
|
|
@ -0,0 +1,36 @@
|
|||
import React , { FC } from 'react';
|
||||
import { Modal } from 'antd';
|
||||
import { connect, Dispatch , UserModelState , Loading } from 'umi';
|
||||
|
||||
|
||||
export interface LoginBoxProps{
|
||||
user:UserModelState
|
||||
loading:boolean
|
||||
dispatch:Dispatch
|
||||
}
|
||||
|
||||
const LoginBoxComponent: FC<LoginBoxProps> = ({
|
||||
user,
|
||||
loading,
|
||||
dispatch
|
||||
})=>{
|
||||
return (
|
||||
<Modal
|
||||
centered
|
||||
title="登录"
|
||||
>
|
||||
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default connect(
|
||||
({
|
||||
user,loading
|
||||
}:{
|
||||
user:UserModelState
|
||||
loading:Loading
|
||||
}) => ({
|
||||
user,
|
||||
loading:loading.models.index
|
||||
})
|
||||
)(LoginBoxComponent)
|
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
|
@ -0,0 +1,10 @@
|
|||
div[id~='root']{
|
||||
height: 100%;
|
||||
}
|
||||
.layoutMain{
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
.layoutMainbox{
|
||||
padding:70px 0px 485px;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
import React , { FC , useEffect } from 'react';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import zhCN from 'antd/es/locale/zh_CN';
|
||||
import { Loading ,
|
||||
connect ,
|
||||
GlobalSettingModelState ,
|
||||
Dispatch,
|
||||
UserModelState
|
||||
} from 'umi';
|
||||
import Header from '@/components/Header';
|
||||
import Footer from '@/components/Footer';
|
||||
import styles from './index.less';
|
||||
|
||||
interface PageProps{
|
||||
loading:Loading,
|
||||
globalSetting:GlobalSettingModelState,
|
||||
dispatch:Dispatch,
|
||||
location:any,
|
||||
user:UserModelState
|
||||
}
|
||||
const IndexLayout:FC<PageProps> = ({
|
||||
children,
|
||||
loading,
|
||||
globalSetting,
|
||||
user,
|
||||
dispatch,
|
||||
location,
|
||||
...props
|
||||
})=>{
|
||||
useEffect(()=>{
|
||||
dispatch({
|
||||
type:"globalSetting/getGlobalSetting",
|
||||
payload:{}
|
||||
})
|
||||
},[globalSetting.name])
|
||||
|
||||
useEffect(()=>{
|
||||
dispatch({
|
||||
type:"user/getUserInfo",
|
||||
payload:{}
|
||||
})
|
||||
},[user.name])
|
||||
|
||||
|
||||
return(
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<div className={styles.layoutMain}>
|
||||
<Header />
|
||||
<div className={styles.layoutMainbox}>
|
||||
{children}
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
)
|
||||
};
|
||||
|
||||
export default connect(
|
||||
(({globalSetting,loading,user}:{
|
||||
globalSetting:GlobalSettingModelState,
|
||||
loading:Loading,
|
||||
user:UserModelState
|
||||
})=>({
|
||||
globalSetting,loading,user
|
||||
})
|
||||
)
|
||||
)(IndexLayout);
|
|
@ -0,0 +1,62 @@
|
|||
import { Effect , Reducer , Subscription } from 'umi';
|
||||
import { getSetting } from '@/service/global';
|
||||
import ENV from '@/utils/env';
|
||||
|
||||
export interface GlobalSettingModelState{
|
||||
name:string,
|
||||
loading:boolean,
|
||||
setting?:any,
|
||||
}
|
||||
|
||||
export interface GlobalSettingModelType{
|
||||
namespace:"globalSetting";
|
||||
state:GlobalSettingModelState;
|
||||
effects:{
|
||||
getGlobalSetting:Effect
|
||||
},
|
||||
reducers:{
|
||||
save:Reducer<GlobalSettingModelState>
|
||||
};
|
||||
subscriptions: { setup: Subscription };
|
||||
}
|
||||
|
||||
const GlobalSettingModel:GlobalSettingModelType={
|
||||
namespace:"globalSetting",
|
||||
state:{
|
||||
name:"全局配置",
|
||||
loading:true,
|
||||
},
|
||||
effects:{
|
||||
*getGlobalSetting({payload},{call,put}){
|
||||
const response = yield call(getSetting,payload);
|
||||
handleDynamicFavicon(response);
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: { ...response },
|
||||
});
|
||||
}
|
||||
},
|
||||
reducers:{
|
||||
save(state,action){
|
||||
return{
|
||||
...state,
|
||||
...action.payload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export default GlobalSettingModel;
|
||||
|
||||
const handleDynamicFavicon = (response: any = {}) => {
|
||||
response.setting?.tab_logo_url
|
||||
const link = document.createElement('link');
|
||||
const oldLink = document.getElementById('dynamic-favicon');
|
||||
link.id = 'dynamic-favicon';
|
||||
link.rel = 'shortcut icon';
|
||||
link.href = response.setting?.tab_logo_url ?
|
||||
`${ENV.IMG_SERVER}/${response.setting?.tab_logo_url}` :
|
||||
`${ENV.IMG_SERVER}/react/build/./favicon.ico`;
|
||||
|
||||
oldLink && document.head.removeChild(oldLink);
|
||||
document.head.appendChild(link);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import { Effect , Reducer , Subscription } from 'umi';
|
||||
import { getProjectList , getRecommand } from '@/service/projectHome';
|
||||
|
||||
export interface ProjectHomeState{
|
||||
name:string,
|
||||
projectList?:any,
|
||||
recommandList?:any
|
||||
}
|
||||
|
||||
export interface ProjectHomeType{
|
||||
namespace:"projectHome",
|
||||
state:ProjectHomeState,
|
||||
effects:{
|
||||
getProjectList:Effect,
|
||||
getRecommandList:Effect
|
||||
},
|
||||
reducers:{
|
||||
save:Reducer<ProjectHomeState>
|
||||
},
|
||||
subscriptions:{setup:Subscription}
|
||||
}
|
||||
|
||||
const ProjectHomeModel:ProjectHomeType = {
|
||||
namespace:"projectHome",
|
||||
state:{
|
||||
name:"项目列表",
|
||||
projectList:{}
|
||||
},
|
||||
effects:{
|
||||
*getProjectList({payload},{call,put}){
|
||||
const { ...params } = payload;
|
||||
const response = yield call(getProjectList,params);
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: { projectList: response },
|
||||
});
|
||||
},
|
||||
*getRecommandList({payload},{call,put}){
|
||||
const response = yield call(getRecommand,payload);
|
||||
yield put({
|
||||
type:"save",
|
||||
payload:{ recommandList : response}
|
||||
})
|
||||
}
|
||||
},
|
||||
reducers:{
|
||||
save(state, action) {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
}
|
||||
},
|
||||
},
|
||||
subscriptions:{
|
||||
setup({ dispatch, history }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
export default ProjectHomeModel;
|
|
@ -0,0 +1,70 @@
|
|||
import { Effect , Reducer , Subscription } from 'umi';
|
||||
import { loginIn , getUserInfo } from '@/service/user';
|
||||
|
||||
export interface UserModelState{
|
||||
name:string,
|
||||
showLoginModal:boolean,
|
||||
loading:boolean,
|
||||
userInfo?:any
|
||||
}
|
||||
|
||||
export interface UserModelType{
|
||||
namespace:"user",
|
||||
state:UserModelState,
|
||||
effects:{
|
||||
loginIn:Effect
|
||||
showLoginBox:Effect
|
||||
getUserInfo:Effect
|
||||
},
|
||||
reducers:{
|
||||
save:Reducer<UserModelState>
|
||||
},
|
||||
subscriptions: { setup: Subscription };
|
||||
}
|
||||
|
||||
const UserModel:UserModelType = {
|
||||
namespace:"user",
|
||||
state:{
|
||||
name:'用户信息',
|
||||
showLoginModal:false,
|
||||
loading:true,
|
||||
userInfo:{}
|
||||
},
|
||||
effects:{
|
||||
*loginIn({payload},{call,put}){
|
||||
const { to , ...params } = payload;
|
||||
const response = yield call(loginIn,params);
|
||||
if(!response.status){
|
||||
try{
|
||||
location.reload();
|
||||
}catch(e){}
|
||||
}
|
||||
},
|
||||
*showLoginBox({payload},{call,put}){
|
||||
yield put({
|
||||
type:"save",
|
||||
payload:{ showLoginBox:payload.showLoginBox }
|
||||
})
|
||||
},
|
||||
*getUserInfo({payload},{call,put}){
|
||||
const response = yield call(getUserInfo,payload);
|
||||
yield put({
|
||||
type: 'save',
|
||||
payload: { userInfo:{...response} },
|
||||
});
|
||||
}
|
||||
},
|
||||
reducers:{
|
||||
save(state, action) {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
}
|
||||
},
|
||||
},
|
||||
subscriptions:{
|
||||
setup({ dispatch, history }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
export default UserModel;
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="notranslate" translate="no">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="Cache-Control" content="max-age=604800" />
|
||||
<meta content="always" name="referrer">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" />
|
||||
<meta http-equiv="Cache-Control" content="no-transform" />
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="viewport" content="width=1226">
|
||||
<title>确实让创建更美好</title>
|
||||
<meta name="keywords" content="trustie,trustieforge,forge,确实让创建更美好,协同开发平台">
|
||||
<meta name="google" content="notranslate" />
|
||||
<meta http-equiv="Content-language" content="en">
|
||||
<meta name="description" content="持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动">
|
||||
<script>
|
||||
window.ENV = '<%- process.env.API_ENV %>';
|
||||
if(window.ENV !== 'dev'){
|
||||
console.log = new Function;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root">
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,5 @@
|
|||
.slickBox {
|
||||
}
|
||||
.boxwidth{
|
||||
padding:20px 0px;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import React , { FC , useEffect, useState } from 'react';
|
||||
// import Slick from 'react-slick';
|
||||
import styles from './index.less';
|
||||
import { Loading ,
|
||||
connect ,
|
||||
Dispatch,
|
||||
ProjectHomeState
|
||||
} from 'umi';
|
||||
import Recommand from '@/components/Recommand';
|
||||
import banner from '@/images/banner.jpg';
|
||||
|
||||
const setting={
|
||||
dots: true,
|
||||
infinite: true,
|
||||
speed: 500,
|
||||
slidesToShow: 5,
|
||||
slidesToScroll: 5,
|
||||
autoplay:false,
|
||||
arrows:false,
|
||||
adaptiveHeight:true
|
||||
}
|
||||
|
||||
interface PageProps{
|
||||
loading:Loading,
|
||||
projectHome:ProjectHomeState,
|
||||
dispatch:Dispatch,
|
||||
location:any
|
||||
}
|
||||
|
||||
const limit = 15;
|
||||
const Projectlist:FC<PageProps>=({
|
||||
loading,
|
||||
projectHome,
|
||||
dispatch,
|
||||
})=>{
|
||||
const [ page , setPage ] = useState(1);
|
||||
const [ total , setTotal ] = useState(0);
|
||||
|
||||
useEffect(()=>{
|
||||
dispatch({
|
||||
type:"projectHome/getProjectList",
|
||||
payload:{page,limit}
|
||||
})
|
||||
},[page])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<img src={banner} width="100%"/>
|
||||
<div className={`${styles.boxwidth} boxWidth`}>
|
||||
<Recommand />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
({
|
||||
projectHome,
|
||||
loading
|
||||
}:{
|
||||
projectHome:ProjectHomeState,
|
||||
loading:Loading
|
||||
})=>({
|
||||
projectHome,
|
||||
loading:loading.models.index
|
||||
})
|
||||
)(Projectlist)
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react';
|
||||
import styles from './index.less';
|
||||
|
||||
export default (()=>{
|
||||
return(
|
||||
<div>用户个人中心首页</div>
|
||||
)
|
||||
})
|
|
@ -0,0 +1,8 @@
|
|||
import Fetch from '@/utils/fetch';
|
||||
|
||||
export async function applyProject(params:any) {
|
||||
return Fetch('/api/applied_projects.json',{
|
||||
method:"post",
|
||||
body:params
|
||||
})
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import Fetch from '@/utils/fetch';
|
||||
|
||||
export async function getSetting() {
|
||||
return Fetch('/api/setting.json',{
|
||||
method:"Get"
|
||||
})
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
import Fetch , { get } from '@/utils/fetch';
|
||||
|
||||
|
||||
export async function getProjectList(params: any) {
|
||||
return get('/api/projects.json' , params );
|
||||
}
|
||||
// 项目类型
|
||||
export async function getGroupTypeList(params: any) {
|
||||
return Fetch('/api/projects/group_type_list.json', {
|
||||
method: 'get',
|
||||
body: params ,
|
||||
});
|
||||
}
|
||||
// 项目类别
|
||||
export async function getGroupList(params: any) {
|
||||
return Fetch('/api/project_categories/group_list.json', {
|
||||
method: 'get',
|
||||
body: params ,
|
||||
});
|
||||
}
|
||||
// 项目语言
|
||||
export async function getLanguages(params: any) {
|
||||
return Fetch('/api/project_languages.json', {
|
||||
method: 'get',
|
||||
body: params ,
|
||||
});
|
||||
}
|
||||
// 推荐项目列表
|
||||
export async function getRecommand(params: any) {
|
||||
return get('/api/projects/recommend.json', params);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import Fetch from '@/utils/fetch';
|
||||
|
||||
export async function loginIn(params: any) {
|
||||
return Fetch('/api/accounts/login.json', {
|
||||
method: 'post',
|
||||
body: { ...params },
|
||||
});
|
||||
}
|
||||
|
||||
export async function getUserInfo() {
|
||||
return Fetch('/api/users/get_user_info.json', {
|
||||
method: 'Get'
|
||||
});
|
||||
}
|
|
@ -0,0 +1,324 @@
|
|||
@import './mixin.less';
|
||||
|
||||
[class^='icon-'],
|
||||
[class*=' icon-'] {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.font12 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.font13 {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.font14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.font15 {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.font16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.font17 {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.font18 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.font19 {
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
.font20 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.font22 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.font24 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.font28 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.font40 {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.font50 {
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
|
||||
.mt0 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.mt3 {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.mt5 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.mt6 {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.mt8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.mt10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mt12 {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.mt15 {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.mt17 {
|
||||
margin-top: 17px;
|
||||
}
|
||||
|
||||
.mt20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.mt25 {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.mt30 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.mt35 {
|
||||
margin-top: 35px;
|
||||
}
|
||||
|
||||
.mt40 {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.mt60 {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.mt75 {
|
||||
margin-top: 75px;
|
||||
}
|
||||
|
||||
.mt80 {
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.mt100 {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
.ml0 {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.ml2 {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.ml5 {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.ml8 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.ml15 {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.ml20 {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.ml25 {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.ml30 {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.ml35 {
|
||||
margin-left: 35px;
|
||||
}
|
||||
|
||||
.ml40 {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.ml50 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.ml60 {
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
.ml100 {
|
||||
margin-left: 100px;
|
||||
}
|
||||
|
||||
.mr0 {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.mr1 {
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.mr3 {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.mr5 {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.mr8 {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mr10 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mr15 {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.mr20 {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.mr25 {
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.mr30 {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.mr32 {
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.mr40 {
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.mr50 {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
.mb0 {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.mb5 {
|
||||
margin-bottom: 5px !important;
|
||||
}
|
||||
|
||||
.mb10 {
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.mb16 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mb20 {
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
|
||||
.mb25 {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.mb30 {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.mb50 {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.mb60 {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.mb80 {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
|
||||
.mb100 {
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.mtb20 {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pl15{
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.pr15{
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.c-g-6{
|
||||
color: @grey-666;
|
||||
}
|
||||
.c-g-9{
|
||||
color: @grey-999;
|
||||
}
|
||||
.c-g-c{
|
||||
color: @grey-ccc;
|
||||
}
|
||||
.c-g-e{
|
||||
color: @grey-eee;
|
||||
}
|
||||
.c-g-3{
|
||||
color: @grey-333;
|
||||
}
|
||||
|
||||
.pointer{
|
||||
cursor: pointer;
|
||||
}
|
||||
.boxWidth{
|
||||
width: 1200px;
|
||||
margin:0px auto;
|
||||
}
|
|
@ -0,0 +1,539 @@
|
|||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,194 @@
|
|||
@primary: #4cacff;
|
||||
@light-primary: #1890ff;
|
||||
@red: #fb3226;
|
||||
@violet: #5e5fb9;
|
||||
@transparent-primary: rgba(255, 104, 133, 0.1);
|
||||
@light-black: #666666;
|
||||
@light-grey: #999;
|
||||
@light-text: #828383;
|
||||
@pink: #cc317c;
|
||||
@green: #028d01;
|
||||
@green-29b: #29bd8b;
|
||||
@green-2ab: #2abd8c;
|
||||
@light-green: #50dbad;
|
||||
@green-13b: #13bf6f;
|
||||
@cyan: #006b75;
|
||||
@grey-ede: #ededed;
|
||||
// @light-green: #7ad58b;
|
||||
@light-orange: #e99695;
|
||||
@light-blue-purple: #5e5fb9;
|
||||
@light-blue: #84b6eb;
|
||||
|
||||
@sky-blue: #f4faff;
|
||||
@cyan-blue: #18d0e7;
|
||||
@brilliant-blue: #aed5ff;
|
||||
@light-pink: #fc2b6a;
|
||||
@orange: #ff6800;
|
||||
|
||||
@purple-8C1: #8c18ff;
|
||||
|
||||
@orange-ff9: #ff954c;
|
||||
@orange-ff7: #ff7500;
|
||||
|
||||
@red-ee4: #ee4a1f;
|
||||
|
||||
@blue-4ca: #4cacff;
|
||||
|
||||
@grey-4b4: #4b4b4b;
|
||||
@grey-eee: #eee;
|
||||
@grey-bcb: #bcbcbc;
|
||||
@grey-eae: #eaeaea;
|
||||
@grey-ccc: #ccc;
|
||||
@grey-333: #333;
|
||||
@grey-666: #666;
|
||||
@grey-888: #888;
|
||||
@grey-999: #999;
|
||||
@grey-9b9: #9b9b9b;
|
||||
@grey-747A7F: #747a7f;
|
||||
@grey-7c7: #7c7c7c;
|
||||
|
||||
@yellow: #fed218;
|
||||
@yellow-feb: #feb300;
|
||||
@white: #fff;
|
||||
@black: black;
|
||||
@black-333: #333;
|
||||
@black-111: #111111;
|
||||
@rem: 100;
|
||||
|
||||
@center-width: 1200px;
|
||||
@head-height: 52px;
|
||||
@right-width: 868px;
|
||||
|
||||
.basefix() {
|
||||
&:before,
|
||||
&:after {
|
||||
content: ' ';
|
||||
display: table;
|
||||
}
|
||||
&:after {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
.inline-block-fix() {
|
||||
font-size: 0;
|
||||
*word-spacing: -1px;
|
||||
}
|
||||
|
||||
.inline-block() {
|
||||
display: inline-block;
|
||||
letter-spacing: normal;
|
||||
word-spacing: normal;
|
||||
}
|
||||
.blur($blur) {
|
||||
-webkit-filter: blur($blur); /* Chrome, Opera */
|
||||
-moz-filter: blur($blur);
|
||||
-ms-filter: blur($blur);
|
||||
filter: blur($blur);
|
||||
}
|
||||
//背景图片
|
||||
.background_image(@url; @repeat;@left:0;@top:0) {
|
||||
background: url(@url) @repeat @left @top;
|
||||
}
|
||||
|
||||
.background_size(@width; @height) {
|
||||
background-size: @width @height;
|
||||
-webkit-background-size: @width @height;
|
||||
}
|
||||
|
||||
//通用背景图片(按照top,left,no-repeat)
|
||||
.background_common_image(@url;@width;@height) {
|
||||
.background_image(@url;no-repeat;0, 0);
|
||||
.background_size(@width; @height);
|
||||
}
|
||||
|
||||
.flex_box_container() {
|
||||
display: box;
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
}
|
||||
// flex水平垂直居中对齐
|
||||
.flex_box_center {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
-webkit-justify-content: center;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
box-align: center;
|
||||
}
|
||||
// flex两端对齐
|
||||
.flex_space_between {
|
||||
justify-content: space-between;
|
||||
-webkit-box-pack: justify;
|
||||
}
|
||||
// flex垂直对齐
|
||||
.flex_box_vertical_center {
|
||||
align-items: center;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
box-align: center;
|
||||
}
|
||||
.flex_box_center_end {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
-webkit-justify-content: flex-end;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-webkit-box-pack: end;
|
||||
box-align: center;
|
||||
box-pack: end;
|
||||
}
|
||||
|
||||
.flex_box_column {
|
||||
flex-direction: column;
|
||||
-webkit-flex-direction: column;
|
||||
-webkit-box-orient: block-axis;
|
||||
box-orient: block-axis;
|
||||
}
|
||||
|
||||
.box_flex(@index) {
|
||||
-webkit-box-flex: @index;
|
||||
-moz-box-flex: @index;
|
||||
-webkit-flex: @index;
|
||||
-ms-flex: @index;
|
||||
flex: @index;
|
||||
}
|
||||
|
||||
.size($width, $height) {
|
||||
width: $width + px;
|
||||
height: $height + px;
|
||||
}
|
||||
|
||||
.box_sizing() {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ellipsis() {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.multi_ellipsis(@line) {
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: @line;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.font($color) {
|
||||
color: $color;
|
||||
}
|
||||
|
||||
.opacity($opa) {
|
||||
opacity: $opa;
|
||||
}
|
||||
|
||||
.border-radius($radius) {
|
||||
border-radius: $radius;
|
||||
-webkit-border-radius: $radius;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
export interface ConfigProps {
|
||||
[key: string]: {
|
||||
API_SERVER: any,
|
||||
IMG_SERVER: any
|
||||
}
|
||||
}
|
||||
|
||||
const GlobalConfig: ConfigProps = {
|
||||
dev:{
|
||||
API_SERVER:"https://testforgeplus.trustie.net",
|
||||
IMG_SERVER: 'https://testforgeplus.trustie.net',
|
||||
}
|
||||
}
|
||||
export default GlobalConfig[window.ENV]
|
|
@ -0,0 +1,238 @@
|
|||
const { fetch } = require('dva');
|
||||
import ENV from './env';
|
||||
import { notification } from 'antd'
|
||||
import hash from 'hash.js'
|
||||
import { getDvaApp, history } from 'umi'
|
||||
let modalConfirm: any;
|
||||
|
||||
interface Response {
|
||||
status: number
|
||||
statusText: string
|
||||
json: any
|
||||
message: string
|
||||
}
|
||||
interface Params {
|
||||
[key: string]: any
|
||||
}
|
||||
const checkStatus = (response: Response) => {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return response
|
||||
}
|
||||
const errortext = response.statusText;
|
||||
let text
|
||||
var resJson = response.json()
|
||||
|
||||
resJson.then((resolve: any, reject: any) => {
|
||||
text = resolve.message
|
||||
notification.error({
|
||||
style: { wordBreak: 'break-all' },
|
||||
// duration: null,
|
||||
message:
|
||||
resolve.message || `请求错误 ${response.status}: ${response.message}`,
|
||||
description: resolve.message ? '' : errortext,
|
||||
})
|
||||
})
|
||||
|
||||
const error: any = new Error(errortext)
|
||||
error.name = response.status
|
||||
error.response = response
|
||||
throw {
|
||||
data: response,
|
||||
code: response.status,
|
||||
message: text || errortext,
|
||||
}
|
||||
}
|
||||
|
||||
const cachedSave = (response: any, hashcode: any) => {
|
||||
const contentType = response.headers.get('Content-Type')
|
||||
if (contentType && contentType.match(/application\/json/i)) {
|
||||
response
|
||||
.clone()
|
||||
.text()
|
||||
.then(() => {
|
||||
// sessionStorage.setItem(hashcode, content)
|
||||
// sessionStorage.setItem(`${hashcode}:timestamp`, Date.now())
|
||||
})
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
export const parseParams = (param: Params) => {
|
||||
param = param || {};
|
||||
// param.domain = window.location.host
|
||||
let paramStr = ''
|
||||
for (let key in param) {
|
||||
if (typeof param[key] === 'object') {
|
||||
if (Array.isArray(param[key])) {
|
||||
param[key].forEach((element: string, k: number) => {
|
||||
paramStr += '&' + key + `[]=` + element
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// if ((param[key]) || param[key] === 0)
|
||||
paramStr += '&' + key + '=' + param[key]
|
||||
}
|
||||
}
|
||||
return paramStr.substr(1)
|
||||
}
|
||||
|
||||
export default function request(url: string, option: any, flag?: boolean) {
|
||||
!option.method ? (option.method = 'get') : ''
|
||||
option.method = option.method.toUpperCase()
|
||||
option.mode = 'cors'
|
||||
const options = {
|
||||
...option,
|
||||
}
|
||||
// options.domain = window.location.host
|
||||
const fingerprint = url + (options.body ? JSON.stringify(options.body) : '')
|
||||
const hashcode = hash
|
||||
.sha256()
|
||||
.update(fingerprint)
|
||||
.digest('hex')
|
||||
|
||||
const defaultOptions = {
|
||||
credentials: 'include',
|
||||
withCredentials: true,
|
||||
}
|
||||
|
||||
let newOptions = { ...defaultOptions, ...options }
|
||||
if (
|
||||
newOptions.method === 'POST' ||
|
||||
newOptions.method === 'PUT' ||
|
||||
newOptions.method === 'PATCH' ||
|
||||
newOptions.method === 'DELETE'
|
||||
) {
|
||||
if (!flag) {
|
||||
newOptions.headers = {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
...newOptions.headers,
|
||||
}
|
||||
newOptions.body = JSON.stringify(options.body)
|
||||
} else {
|
||||
newOptions.headers = {
|
||||
...newOptions.headers,
|
||||
}
|
||||
newOptions.body = options.body
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (newOptions.method == 'GET') {
|
||||
newOptions.headers = {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
...newOptions.headers,
|
||||
}
|
||||
url += '?' + parseParams(options.params)
|
||||
}
|
||||
|
||||
const expirys = options.expirys && 60
|
||||
/**
|
||||
* @description: 枚举出请求数据格式类型
|
||||
* @param {type} 枚举类型
|
||||
* @return:
|
||||
*/
|
||||
enum ContentType {
|
||||
json = 'application/json;charset=UTF-8',
|
||||
form = 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
}
|
||||
/**
|
||||
* @description: 枚举request请求的method方法
|
||||
* @param {type} 枚举类型
|
||||
* @return:
|
||||
*/
|
||||
enum HttpMethod {
|
||||
get = 'GET',
|
||||
post = 'POST',
|
||||
}
|
||||
/**
|
||||
* @description: 声明请求头header的类型
|
||||
* @param {type}
|
||||
* @return:
|
||||
*/
|
||||
interface IHeader {
|
||||
Accept?: string
|
||||
'Content-Type': string
|
||||
[propName: string]: any
|
||||
}
|
||||
/**
|
||||
* @description: 声明fetch请求参数配置
|
||||
* @param {type}
|
||||
* @return:
|
||||
*/
|
||||
interface IReqConfig {
|
||||
method?: string
|
||||
credentials?: string
|
||||
headers?: IHeader
|
||||
body?: any
|
||||
}
|
||||
interface IHttp {
|
||||
getFetch<R, P = {}>(
|
||||
url: string,
|
||||
params?: P,
|
||||
options?: RequestInit,
|
||||
): Promise<R>
|
||||
postFetch<R, P = {}>(url: string, params?: P): Promise<R>
|
||||
}
|
||||
return fetch(ENV.API_SERVER + url, newOptions)
|
||||
.then(checkStatus)
|
||||
.then((response: any) => cachedSave(response, hashcode))
|
||||
.then(async (response: any) => {
|
||||
if (response.status === 204) {
|
||||
return response.text()
|
||||
}
|
||||
const d = await response.json()
|
||||
return d
|
||||
})
|
||||
.catch((e: any) => {
|
||||
try {
|
||||
const status = e.code
|
||||
if (status === 401) {
|
||||
getDvaApp()._store.dispatch({
|
||||
type: 'user/showPopLogin',
|
||||
payload: {
|
||||
showPopLogin: true,
|
||||
showClosable: true
|
||||
}
|
||||
})
|
||||
}
|
||||
return e
|
||||
} catch (e) { }
|
||||
})
|
||||
}
|
||||
|
||||
let historyFlag = false
|
||||
let errorFlag = false
|
||||
|
||||
export function get(url: string, params?: Object) {
|
||||
return request(url, {
|
||||
method: 'Get',
|
||||
params: params || {},
|
||||
})
|
||||
}
|
||||
export function getqq(url: string, params?: Object) {
|
||||
return request(`/${url}`, {
|
||||
method: 'Get',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
export function post(url: string, params?: Object) {
|
||||
return request(`/api/${url}`, {
|
||||
method: 'Post',
|
||||
body: { ...params },
|
||||
})
|
||||
}
|
||||
|
||||
export function put(url: string, params?: Object) {
|
||||
return request(`/api/${url}`, {
|
||||
method: 'Put',
|
||||
body: { ...params },
|
||||
})
|
||||
}
|
||||
|
||||
export function del(url: string) {
|
||||
return request(`/api/${url}`, { method: 'delete' })
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": "./",
|
||||
"strict": true,
|
||||
"paths": {
|
||||
"@/*": ["src/*"],
|
||||
"@@/*": ["src/.umi/*"]
|
||||
},
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": [
|
||||
"mock/**/*",
|
||||
"src/**/*",
|
||||
"config/**/*",
|
||||
".umirc.ts",
|
||||
"typings.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
declare module '*.css';
|
||||
declare module '*.less';
|
||||
declare module "*.png";
|
||||
declare module "*.jpg";
|
||||
declare module "*.gif";
|
||||
|
||||
declare module '*.svg' {
|
||||
export function ReactComponent(props: React.SVGProps<SVGSVGElement>): React.ReactElement
|
||||
const url: string
|
||||
export default url
|
||||
}
|
Loading…
Reference in New Issue