This commit is contained in:
caishi 2021-07-12 10:44:11 +08:00
commit 27883febe1
50 changed files with 9549 additions and 0 deletions

16
.editorconfig Executable file
View File

@ -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

20
.gitignore vendored Normal file
View File

@ -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

8
.prettierignore Normal file
View File

@ -0,0 +1,8 @@
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test

11
.prettierrc Normal file
View File

@ -0,0 +1,11 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}

23
.umirc.ts Normal file
View File

@ -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
}
});

15
README.md Normal file
View File

@ -0,0 +1,15 @@
# umi project
## Getting Started
Install dependencies,
```bash
$ yarn
```
Start the dev server,
```bash
$ yarn start
```

0
mock/.gitkeep Normal file
View File

39
package.json Normal file
View File

@ -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"
}
}

2
src/app.less Normal file
View File

@ -0,0 +1,2 @@
@import './styles/iconfont/iconfont.css';
@import './styles/base.less';

12
src/app.tsx Normal file
View File

@ -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)
},
},
}

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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)

BIN
src/images/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

10
src/layouts/Index.less Normal file
View File

@ -0,0 +1,10 @@
div[id~='root']{
height: 100%;
}
.layoutMain{
position: relative;
min-height: 100%;
}
.layoutMainbox{
padding:70px 0px 485px;
}

67
src/layouts/Index.tsx Normal file
View File

@ -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);

View File

@ -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);
}

View File

@ -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;

70
src/models/user/index.ts Normal file
View File

@ -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;

31
src/pages/document.ejs Normal file
View File

@ -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>

5
src/pages/index.less Normal file
View File

@ -0,0 +1,5 @@
.slickBox {
}
.boxwidth{
padding:20px 0px;
}

66
src/pages/index.tsx Normal file
View File

@ -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)

View File

View File

@ -0,0 +1,8 @@
import React from 'react';
import styles from './index.less';
export default (()=>{
return(
<div></div>
)
})

8
src/service/common.ts Normal file
View File

@ -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
})
}

7
src/service/global.ts Normal file
View File

@ -0,0 +1,7 @@
import Fetch from '@/utils/fetch';
export async function getSetting() {
return Fetch('/api/setting.json',{
method:"Get"
})
}

View File

@ -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);
}

14
src/service/user.ts Normal file
View File

@ -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'
});
}

324
src/styles/base.less Normal file
View File

@ -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;
}

View File

@ -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.

194
src/styles/mixin.less Executable file
View File

@ -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;
}
//通用背景图片按照topleft,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;
}

16
src/utils/env.ts Normal file
View File

@ -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]

238
src/utils/fetch.ts Normal file
View File

@ -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' })
}

25
tsconfig.json Normal file
View File

@ -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"
]
}

11
typings.d.ts vendored Normal file
View File

@ -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
}