Commit 4b82338e authored by nano's avatar nano

init

parents
# 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
{
"parser": "babel-eslint",
"extends": "airbnb",
"rules": {
"generator-star-spacing": [0],
"consistent-return": [0],
"react/forbid-prop-types": [0],
"react/jsx-filename-extension": [1, { "extensions": [".js"] }],
"global-require": [1],
"import/prefer-default-export": [0],
"react/jsx-no-bind": [0],
"react/prop-types": [0],
"react/prefer-stateless-function": [0],
"no-else-return": [0],
"no-restricted-syntax": [0],
"import/no-extraneous-dependencies": [0],
"no-use-before-define": [0],
"jsx-a11y/no-static-element-interactions": [0],
"no-nested-ternary": [0],
"arrow-body-style": [0],
"import/extensions": [0],
"no-bitwise": [0],
"no-cond-assign": [0],
"import/no-unresolved": [0],
"require-yield": [1]
},
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
}
}
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
# production
/dist
# misc
.DS_Store
npm-debug.log*
{
"entry": "src/index.js",
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr",
"transform-runtime",
["import", { "libraryName": "antd", "style": "css" }]
]
},
"production": {
"extraBabelPlugins": [
"transform-runtime",
["import", { "libraryName": "antd", "style": "css" }]
]
}
}
}
export default {
};
Warning: Permanently added 'poi.mycard.moe,101.37.76.207' (ECDSA) to the list of known hosts.
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
Attaching: [tmux____1]
{
"author": "ZUN",
"homepage": "http://www.myacg.cc",
"locales": [
"actions": {
"win32": {
"main": {
"execute": "Game.exe",
"args": [],
"env": {}
}
},
"darwin": {
"main": {
"execute": "Game.exe",
"args": [],
"open": "wine",
"env": {
"LANG": "zh_CN.UTF-8"
}
}
}
},
"version": {
"win32": "1.54e-1",
"darwin": "1.54e-1"
},
"news": [],
"conference": "oz",
"icon": "https://r.my-card.in/downloads/assets/ozns/Icon%2016x16.png",
"cover": "https://r.my-card.in/downloads/assets/ozns/MyCard%20logo%20NS.png",
"background": "https://r.my-card.in/downloads/assets/ozns/MyCard%20Background%20NS.jpg"
}
\ No newline at end of file
{
"en": {
"Apps" : "Apps"
},
"zh": {
"Apps" : "应用"
}
}
\ No newline at end of file
{
"private": true,
"scripts": {
"start": "roadhog server",
"build": "roadhog build",
"lint": "eslint --ext .js src test",
"precommit": "npm run lint"
},
"engines": {
"install-node": "6.9.2"
},
"dependencies": {
"antd": "^2.7.4",
"babel-runtime": "^6.9.2",
"dva": "^1.2.1",
"react": "^15.4.0",
"react-dom": "^15.4.0"
},
"devDependencies": {
"babel-eslint": "^7.1.1",
"babel-plugin-dva-hmr": "^0.3.2",
"babel-plugin-import": "^1.1.1",
"babel-plugin-transform-runtime": "^6.9.0",
"eslint": "^3.12.2",
"eslint-config-airbnb": "^13.0.0",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.8.0",
"expect": "^1.20.2",
"husky": "^0.12.0",
"redbox-react": "^1.3.2",
"roadhog": "^0.5.2"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dva Demo</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div id="root"></div>
<script src="index.js"></script>
</body>
</html>
import React from 'react';
import styles from './Create.css';
import { Button, Modal, Form, Input, Radio, Select, Spin } from 'antd';
const FormItem = Form.Item;
class Create extends React.Component {
handleSubmit = (e) => {
const {onSubmit} = this.props
e.preventDefault();
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
onSubmit(values)
this.props.form.resetFields()
}
});
}
handleSelectChange = (value) => {
}
render() {
const { visible, onCancel, form, isLoading } = this.props;
const { getFieldDecorator } = form;
return (
<Modal
visible={visible}
title="创建一个新的应用"
okText="提交"
onCancel={onCancel}
onOk={this.handleSubmit}>
<Spin spinning={isLoading} delay={100} tip="提交中...">
<Form vertical onSubmit={this.handleSubmit}>
<FormItem label="应用 ID (创建应用后无法修改)">
{getFieldDecorator('id', {
rules: [{ required: true, message: '请输入应用ID' }],
})(
<Input />
)}
</FormItem>
<FormItem label="应用昵称">
{getFieldDecorator('name', {
rules: [{ required: true, message: '请输入应用昵称' }],
})(
<Input />
)}
</FormItem>
<FormItem
label="主要语言"
wrapperCol={{ span: 8 }}>
{getFieldDecorator('locale', {
rules: [{ required: true, message: '请至少选择一门主要语言' }],
onChange: this.handleSelectChange,
})(
<Select>
<Select.Option value="zh-CN">zh-CN</Select.Option>
<Select.Option value="zh-TW">zh-TW</Select.Option>
<Select.Option value="en-US">en-US</Select.Option>
<Select.Option value="ja-JP">ja-JP</Select.Option>
</Select>
)}
</FormItem>
</Form>
</Spin>
</Modal>
);
}
}
const WrappedCreate = Form.create()(Create)
export default WrappedCreate;
import React from 'react';
import styles from './Items.css';
function Items() {
return (
<div className={styles.normal}>
Component: Items
</div>
);
}
export default Items;
import React from 'react';
import styles from './Nav.less';
import { Layout, Menu, Icon, Breadcrumb } from 'antd';
import {Link} from 'dva/router'
import { FormattedMessage } from 'react-intl'
const { Header, Sider, Content, Footer } = Layout;
const SubMenu = Menu.SubMenu
function Nav({ collapsed, mode, dispatch }) {
return (
<Sider
collapsible
collapsed={collapsed}
onCollapse={() => dispatch({ type: 'Common/collapsed' })}>
<div className={styles.logo} />
<Menu theme="dark" mode={mode} defaultSelectedKeys={['0']}>
<Menu.Item key="0">
<Link to="/apps">
<Icon type="windows-o" />
<span className="nav-next">
<FormattedMessage id="Apps"/>
</span>
</Link>
</Menu.Item>
</Menu>
</Sider>
);
}
export default Nav;
.nav {
min-height: 500px;
}
.trigger {
font-size: 18px;
line-height: 64px;
padding: 0 16px;
cursor: pointer;
transition: color .3s;
}
.trigger:hover {
color: #108ee9;
}
.logo {
height: 32px;
background: #333;
border-radius: 6px;
margin: 16px;
}
:global {
.ant-layout-sider-collapsed .nav-next {
display: none;
}
.ant-layout-sider-collapsed .ant-menu-submenu-vertical > .ant-menu-submenu-title:after {
display: none;
}
.ant-layout-sider-collapsed .anticon {
font-size: 16px;
margin-left: 8px;
}
}
\ No newline at end of file
import React from 'react';
const Example = () => {
return (
<div>
Example
</div>
);
};
Example.propTypes = {
};
export default Example;
export default {
apiRoot: 'http://localhost:8001'
}
\ No newline at end of file
html, body, :global(#root) {
height: 100%;
}
\ No newline at end of file
import ReactDOM from 'react-dom';
import dva from 'dva';
import './index.css';
import { IntlProvider, addLocaleData } from 'react-intl';
// 1. Initialize
const app = dva();
app.model(require("./models/Apps"));
app.model(require("./models/Common"));
app.model(require("./models/App"));
// 2. Plugins
// app.use({});
// 3. Model
// app.model(require('./models/example'));
// 4. Router
app.router(require('./router'));
// 5. Start
import en from 'react-intl/locale-data/en'
import zh from 'react-intl/locale-data/zh'
import localeData from '../i18n.json'
addLocaleData([...en, ...zh])
const language = navigator.language || (navigator.languages && navigator.languages[0]) || navigator.userLanguage;
const languageWithoutRegionCode = language.toLowerCase().split(/[_-]+/)[0];
const messages = localeData[languageWithoutRegionCode] || localeData[language] || localeData.zh;
const App = app.start()
ReactDOM.render(
<IntlProvider locale={ language } messages={ messages }>
<App />
</IntlProvider>,
document.getElementById("root")
)
import { create } from '../services/Apps'
export default {
namespace: 'App',
state: {
isSubmit: false,
isCreate: false,
id: null,
name: null,
locale: null
},
reducers: {
onCreate(state, action) {
return {
...state,
isCreate: true
}
},
SubmitRequest(state, action) {
return {
...state,
...action.payload,
isSubmit: true,
}
},
SubmitSuccess(state, action){
return {
...state,
isSubmit: false,
isCreate: false
}
},
onCancel(state, action) {
return {
...state,
isCreate: false,
isSubmit: false
}
},
reset(state, action) {
return {
...state,
isSubmit: false,
isCreate: false,
id: null,
name: null,
locale: null
}
}
},
effects: {
*submit({ payload }, { call, put }){
yield put({ type: 'SubmitRequest', payload })
const params = {
id: payload.id,
name: {
[payload.locale]: payload.name
}
}
const req = yield call(create, params)
if(req.data) {
yield put({ type: 'SubmitSuccess' })
yield put({ type: 'reset' })
// TODO: 成功提示
}
// TODO: 错误处理
}
},
subscriptions: {},
};
import { fetch } from '../services/Apps'
export default {
namespace: 'Apps',
state: {
list: [],
},
reducers: {
save(state, action) {
return {
...state,
...action.payload
}
},
},
effects: {
*fetch({ payload }, { call, put }) {
const { data } = yield call(fetch, payload)
yield put({ type: 'save', payload: { list: data }})
}
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname, query}) => {
if(pathname === '/apps') {
dispatch({ type: 'fetch', payload: query})
}
})
}
},
};
export default {
namespace: 'Common',
state: {
collapsed: false,
mode: 'inline'
},
reducers: {
collapsed (state) {
const mode = state.collapsed ? 'inline' : 'vertical'
return { ...state, collapsed: !state.collapsed, mode }
}
},
effects: {},
subscriptions: {},
};
export default {
namespace: 'example',
state: {},
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-line
},
},
effects: {
*fetch({ payload }, { call, put }) { // eslint-disable-line
yield put({ type: 'save' });
},
},
reducers: {
save(state, action) {
return { ...state, ...action.payload };
},
},
};
import React from 'react';
import { Router, Route } from 'dva/router';
import IndexPage from './routes/IndexPage';
import Apps from "./routes/Apps.js";
import AppDetail from './routes/AppDetail.js'
import Entry from "./routes/Entry.js";
function RouterConfig({ history }) {
return (
<Router history={history}>
<Route path="/" component={Entry} >
<Route path="apps" component={Apps} />
<Route path="apps/:id" component={AppDetail} />
</Route>
</Router>
);
}
export default RouterConfig;
import React from 'react';
import { connect } from 'dva';
import styles from './AppDetail.less';
import { Form, Input, Icon, Radio, Tag, Tooltip, Button, Select, Tabs } from 'antd'
const FormItem = Form.Item;
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const Option = Select.Option;
const TabPane = Tabs.TabPane;
function AppDetail({ form }) {
const { getFieldDecorator } = form
const formItemLayout = {
labelCol: { span: 5 },
wrapperCol: { span: 24 },
}
return (
<Tabs defaultActiveKey="1" className="app-detail-nav">
<TabPane tab={<span><Icon type="setting" /> 基本信息 </span>} key="1">
<div className={styles.form}>
<Form>
<FormItem {...formItemLayout} label="游戏类别">
{getFieldDecorator('category')(
<RadioGroup>
<RadioButton value="game">game</RadioButton>
<RadioButton value="runtime">runtime</RadioButton>
<RadioButton value="emulator">emulator</RadioButton>
<RadioButton value="module">module</RadioButton>
</RadioGroup>
)}
</FormItem>
<FormItem {...formItemLayout}>
{getFieldDecorator('author', {
})(
<Input addonBefore={<Icon type="user" />} placeholder="开发者" />
)}
</FormItem>
<FormItem
{...formItemLayout}
help="以 http:// 或 https:// 开头,没有可留空">
{getFieldDecorator('homepage', {
})(
<Input addonBefore={<Icon type="home" />} placeholder="网站" />
)}
</FormItem>
<FormItem
{...formItemLayout}
help="游戏类应用通常与 ID 相同,其他类型的应用留空">
{getFieldDecorator('conference', {
})(
<Input addonBefore={<Icon type="message" />} placeholder="聊天室" />
)}
</FormItem>
<FormItem
{...formItemLayout}
help="JSON string[],不会写请联系 zh99998@gmail.com"
>
{getFieldDecorator('tags', {
})(
<Select tags style={{ width: '100%' }} placeholder="标签">
</Select>
)}
</FormItem>
<FormItem {...formItemLayout}>
{getFieldDecorator('locales', {
})(
<Select
multiple
style={{ width: '100%' }}
placeholder="游戏支持的语言"
defaultValue={['a10', 'c12']}>
<Select.Option value="zh-CN">zh-CN</Select.Option>
<Select.Option value="zh-TW">zh-TW</Select.Option>
<Select.Option value="en-US">en-US</Select.Option>
<Select.Option value="ja-JP">ja-JP</Select.Option>
</Select>
)}
</FormItem>
<FormItem {...formItemLayout} >
<div className={styles.wrapSubmit}>
<Button type="primary" htmlType="submit" size="large">提交</Button>
</div>
</FormItem>
</Form>
</div>
</TabPane>
<TabPane tab={<span><Icon type="solution" />应用介绍</span>} key="2">
<div className={styles.form}>
<Tabs type="card" className="app-detail-nav">
<TabPane tab="zh-CN" key="1">
<Form>
<FormItem {...formItemLayout}>
{getFieldDecorator('locale', {
})(
<Input addonBefore={<Icon type="info" />} placeholder="应用名称" />
)}
</FormItem>
<FormItem {...formItemLayout}>
{getFieldDecorator('description', {
})(
<Input type="textarea" placeholder="应用介绍" autosize={{ minRows: 2}}/>
)}
</FormItem>
<FormItem {...formItemLayout}>
{getFieldDecorator('news', {
})(
<Input type="textarea" placeholder="新闻" autosize={{ minRows: 2}} />
)}
</FormItem>
<FormItem {...formItemLayout} >
<div className={styles.wrapSubmit}>
<Button type="primary" htmlType="submit" size="large">提交</Button>
</div>
</FormItem>
</Form>
</TabPane>
<TabPane tab="zh-TW" key="2">
<Form>
<FormItem {...formItemLayout}>
{getFieldDecorator('locale', {
})(
<Input addonBefore={<Icon type="info" />} placeholder="应用名称" />
)}
</FormItem>
</Form>
</TabPane>
</Tabs>
</div>
</TabPane>
<TabPane tab={<span><Icon type="save" />应用管理</span>} key="3">
Tab 2
</TabPane>
</Tabs>
);
}
function mapStateToProps() {
return {};
}
const WrapperAppDetail = Form.create()(AppDetail)
export default connect(mapStateToProps)(WrapperAppDetail);
:global {
.app-detail-nav{
width: 100%;
}
.app-detail-nav .ant-tabs-nav-scroll {
widows: 100%;
display: flex;
justify-content: center;
}
}
.wrapSubmit{
width: 100%;
display: flex;
justify-content: center;
}
.form {
flex: 1;
display: flex;
justify-content: center;
}
\ No newline at end of file
import React from 'react';
import { connect } from 'dva';
import styles from './Apps.less';
import { Link } from 'dva/router';
import { Button, Affix, Icon, Table } from 'antd'
import Create from '../components/App/Create'
const columns = [
{
title: "Id",
dataIndex: 'id',
sorter: (a, b) => a.id - b.id,
render: id => <Link to={`apps/${id}`}>{id}</Link>,
width: '10%',
key:'id'
}, {
title: 'Name',
dataIndex: 'name',
render: name => `${Object.values(name)[0]}`,
width: '10%',
key: 'name'
},{
title: "Created_At",
dataIndex: 'created_at',
sorter: true,
width: '10%',
key:'created_at'
}, {
title: "Updated_at",
dataIndex: 'updated_at',
sorter: true,
width: '10%',
key:'updated_at'
},
]
function Apps({children, dispatch, isCreate, isSubmit, list}) {
const CreateProps = {
visible: isCreate,
isLoading: isSubmit,
onCancel: () => dispatch({ type: 'App/onCancel'}),
onCreate: () => dispatch({ type: 'App/onCreate'}),
onSubmit: (payload) => dispatch({ type: 'App/submit', payload}),
}
const CreateButtonProps = {
onClick: () => dispatch({ type: 'App/onCreate'}),
className: styles.CreateBtn,
shape: "circle",
type: "primary",
size: "large",
}
const TableProps = {
columns,
dataSource: list
}
return (
<div className={styles.normal}>
<Table {...TableProps}/>
<Affix style={{ position: 'absolute', bottom: 50, right: 50}}>
<Button {...CreateButtonProps} >
<Icon type="plus" />
</Button>
</Affix>
<Create {...CreateProps}/>
</div>
);
}
function mapStateToProps(state) {
const {
Apps: { list },
App: { isCreate, isSubmit }
} = state
return {
list,
isCreate,
isSubmit
};
}
export default connect(mapStateToProps)(Apps);
.CreateBtn {
width: 45px !important;
height: 45px !important;
font-size: 22px !important;
}
:global {
.ant-table-pagination {
display: flex;
justify-content: center;
float: none;
}
}
\ No newline at end of file
import React from 'react';
import { connect } from 'dva';
import styles from './All.less';
import { routerRedux } from 'dva/router';
import { Button, Affix, Icon } from 'antd'
import Create from '../../components/App/Create'
class Apps extends React.Component {
render() {
const { dispatch, isCreate, isSubmit } = this.props
const CreateProps = {
visible: isCreate,
isLoading: isSubmit,
onCancel: () => dispatch({ type: 'App/onCancel'}),
onCreate: () => dispatch({ type: 'App/onCreate'}),
onSubmit: (payload) => dispatch({ type: 'App/submit', payload}),
}
const CreateButtonProps = {
onClick: () => dispatch({ type: 'App/onCreate'}),
className: styles.CreateBtn,
shape: "circle",
type: "primary",
size: "large",
}
return (
<div className={styles.normal}>
<Affix style={{ position: 'absolute', bottom: 50, right: 50}}>
<Button {...CreateButtonProps} >
<Icon type="plus" />
</Button>
</Affix>
<Create {...CreateProps}/>
</div>
)
}
}
function mapStateToProps(state) {
const {
App: { isCreate, isSubmit }
} = state
return {
isCreate,
isSubmit
};
}
export default connect(mapStateToProps)(Apps);
.CreateBtn {
width: 45px !important;
height: 45px !important;
font-size: 22px !important;
}
\ No newline at end of file
import React from 'react';
import { connect } from 'dva';
import styles from './Create.css';
import {
Form, Select, InputNumber, Switch, Radio,
Slider, Button, Upload, Icon,
} from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
class Create extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
}
normFile = (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
return (
<Form onSubmit={this.handleSubmit}>
<FormItem
{...formItemLayout}
label="Nation"
>
<span className="ant-form-text">China</span>
</FormItem>
<FormItem
{...formItemLayout}
label="Select"
hasFeedback
>
{getFieldDecorator('select', {
rules: [
{ required: true, message: 'Please select your country!' },
],
})(
<Select placeholder="Please select a country">
<Option value="china">China</Option>
<Option value="use">U.S.A</Option>
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Select[multiple]"
>
{getFieldDecorator('select-multiple', {
rules: [
{ required: true, message: 'Please select your favourite colors!', type: 'array' },
],
})(
<Select multiple placeholder="Please select favourite colors">
<Option value="red">Red</Option>
<Option value="green">Green</Option>
<Option value="blue">Blue</Option>
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="InputNumber"
>
{getFieldDecorator('input-number', { initialValue: 3 })(
<InputNumber min={1} max={10} />
)}
<span className="ant-form-text"> machines</span>
</FormItem>
<FormItem
{...formItemLayout}
label="Switch"
>
{getFieldDecorator('switch', { valuePropName: 'checked' })(
<Switch />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Slider"
>
{getFieldDecorator('slider')(
<Slider marks={{ 0: 'A', 20: 'B', 40: 'C', 60: 'D', 80: 'E', 100: 'F' }} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Radio.Group"
>
{getFieldDecorator('radio-group')(
<RadioGroup>
<Radio value="a">item 1</Radio>
<Radio value="b">item 2</Radio>
<Radio value="c">item 3</Radio>
</RadioGroup>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Radio.Button"
>
{getFieldDecorator('radio-button')(
<RadioGroup>
<RadioButton value="a">item 1</RadioButton>
<RadioButton value="b">item 2</RadioButton>
<RadioButton value="c">item 3</RadioButton>
</RadioGroup>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Upload"
extra="longgggggggggggggggggggggggggggggggggg">
{getFieldDecorator('upload', {
valuePropName: 'fileList',
getValueFromEvent: this.normFile,
})(
<Upload name="logo" action="/upload.do" onChange={this.handleUpload}>
<Button>
<Icon type="upload" /> Click to upload
</Button>
</Upload>
)}
</FormItem>
<FormItem wrapperCol={{ span: 12, offset: 6 }}>
<Button type="primary" htmlType="submit">Submit</Button>
</FormItem>
</Form>
);
}
}
// const Create = () => {
// return (
// <div className={styles.normal}>
// Route Component: Create
// </div>
// );
// }
function mapStateToProps() {
return {};
}
const WrappedCreate = Form.create()(Create)
export default connect(mapStateToProps)(WrappedCreate);
import React from 'react';
import { connect } from 'dva';
import styles from './Entry.less';
import Nav from '../components/Common/Nav'
import {Layout} from 'antd'
function Entry({ children, collapsed, mode, dispatch }) {
const NavProps = {
collapsed,
mode,
dispatch
}
return (
<Layout style={{ flexDirection: 'row', height: '100%'}}>
<Nav {...NavProps}/>
<Layout style={{ minHeight: '400px'}}>
{children}
</Layout>
</Layout>
);
}
function mapStateToProps(state) {
const {
Common: {collapsed, mode}
} = state
return {
collapsed,
mode
};
}
export default connect(mapStateToProps)(Entry);
.normal {
font-family: Georgia, sans-serif;
margin-top: 3em;
text-align: center;
}
.title {
font-size: 2.5rem;
font-weight: normal;
letter-spacing: -1px;
}
.welcome {
height: 328px;
background: url(../assets/yay.jpg) no-repeat center 0;
background-size: 388px 328px;
}
.list {
font-size: 1.2em;
margin-top: 1.8em;
list-style: none;
line-height: 1.5em;
}
.list code {
background: #f7f7f7;
}
import React from 'react';
import { connect } from 'dva';
import styles from './IndexPage.css';
function IndexPage() {
return (
<div className={styles.normal}>
<h1 className={styles.title}>Yay! Welcome to dva!</h1>
<div className={styles.welcome} />
<ul className={styles.list}>
<li>To get started, edit <code>src/index.js</code> and save to reload.</li>
<li><a href="https://github.com/dvajs/dva-docs/blob/master/v1/en-us/getting-started.md">Getting Started</a></li>
</ul>
</div>
);
}
IndexPage.propTypes = {
};
export default connect()(IndexPage);
import request from '../utils/request'
export async function fetch() {
return request(`/apps`)
}
export async function create(params) {
return request(`/apps/${params.id}`, {
method: 'post',
body: JSON.stringify(params)
})
}
\ No newline at end of file
import request from '../utils/request';
export async function query() {
return request('/api/users');
}
import fetch from 'dva/fetch';
import config from '../config'
function parseJSON(response) {
return response.json();
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
/**
* Requests a URL, returning a promise.
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
* @return {object} An object containing either "data" or "err"
*/
export default function request(url, options) {
url = `${config.apiRoot}${url}`
if(options && !options.headers && options.method == 'post') {
options.headers = {
"content-type": "application/json"
}
}
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => ({ data }))
.catch(err => ({ err }));
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment