Commit 8e5147ef 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 {
};
{
"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.8.2",
"babel-runtime": "^6.9.2",
"dva": "^1.2.1",
"react": "^15.4.0",
"react-dom": "^15.4.0",
"react-intl": "^2.2.3"
},
"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';
const Example = () => {
return (
<div>
Example
</div>
);
};
Example.propTypes = {
};
export default Example;
import React from 'react';
import styles from './Haha.css';
function Haha() {
return (
<div className={styles.normal}>
Component: Haha
</div>
);
}
export default Haha;
export default {
apiRoot: 'http://localhost:8081',
}
\ No newline at end of file
html, body, :global(#root) {
height: 100%;
}
import dva from 'dva';
import ReactDOM from 'react-dom';
import { browserHistory } from 'dva/router'
import './index.css';
import { IntlProvider, addLocaleData } from 'react-intl';
// 1. Initialize
const app = dva({
history: browserHistory
});
app.model(require("./models/user"));
app.model(require("./models/auth"));
app.model(require("./models/haha"));
// app.model(require("./models/login"));
app.model(require("./models/common"));
// 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 { login, forgot, register, reset } from '../services/auth'
import { message } from 'antd'
export default {
namespace: 'auth',
state: {
isSubmit: false,
register:{}
},
reducers: {
change(state, action) {
return {
...state, ...action.payload
}
}
},
effects: {
*login({ payload }, { call, put }) {
const {data} = yield call(login, payload)
if(data){
yield put({ type: 'loginSuccess'})
message.info(data["message"])
} else {
yield put({ type: 'loginFail'})
message.error("登陆失败")
}
},
*forgot({ payload }, { call, put }) {
const { data } = yield call(forgot, payload)
if(data)
{
yield put({ type: 'forgotSuccess'})
message.info(data["message"])
}else {
yield put({ type: 'forgotFail' })
message.error("邮件发送失败")
}
},
*register({ payload }, { call, put }) {
const { data } = yield call(register, payload)
if(data) {
yield put({ type: 'change', payload: { register: data}})
}
// if(data){
// yield put({ type: 'registerSuccess' })
// message.info(data["message"])
// }
},
*reset({ payload }, { call, put }) {
const { data } = yield call(reset, payload)
if(data)
{
yield put({ type: 'resetSuccess' })
message.info(data["message"])
}else{
yield put({ type: 'resetFail' })
message.error("重置失败")
}
},
},
subscriptions: {},
};
export default {
namespace: 'common',
state: {
},
reducers: {
},
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 };
},
},
};
export default {
namespace: 'haha',
state: {
text: '123213213'
},
reducers: {
change(state, action) {
return {
...state, ...action.payload
}
}
},
effects: {},
subscriptions: {},
};
export default {
namespace: 'user',
state: {
},
reducers: {},
effects: {
},
subscriptions: {},
};
import React from 'react';
import { Router, Route, Redirect } from 'dva/router';
import IndexPage from './routes/IndexPage';
import Login from "./routes/Login.js";
import Forgot from "./routes/Forgot.js";
import Register from "./routes/Register.js";
import Reset from "./routes/Reset.js";
import Profiles from "./routes/Profiles.js";
function RouterConfig({ history }) {
return (
<Router history={history}>
<Redirect from="/" to="/login"/>
<Route path="/">
<Route path="/login" component={Login} />
<Route path="/forgot" component={Forgot} />
<Route path="/register" component={Register} />
<Route path="/reset" component={Reset} />
<Route path="/profiles" component={Profiles} />
</Route>
</Router>
);
}
export default RouterConfig;
import React from 'react';
import { connect } from 'dva';
import { Link } from 'dva/router'
import styles from './Login.less';
import { Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 14 },
},
};
class Login extends React.Component {
onSubmitLogin = (e) => {
const { form, dispatch, params: { id }} = this.props
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
const {email} = values
dispatch({type: "auth/forgot", payload: {emailOrUsername: email}})
}
});
}
render() {
const { getFieldDecorator, dispatch } = this.props.form;
return (
<div style={{ display: 'flex', justifyContent:'center', alignItems: 'center', height: '100%'}}>
<Form onSubmit={this.onSubmitLogin} className="login-form">
<FormItem>
{getFieldDecorator('email', {
rules: [{ required: true, message: 'Please input your email!' }],
})(
<Input prefix={<Icon type="user" style={{ fontSize: 13 }} />} placeholder="email" />
)}
</FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
Send
</Button>
Or <Link to="/login">Sign In</Link>
</Form>
</div>
)
}
}
function mapStateToProps() {
return {};
}
const WrapperLogin = Form.create()(Login)
export default connect(mapStateToProps)(WrapperLogin);
.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 React from 'react';
import { connect } from 'dva';
import { Link } from 'dva/router'
import styles from './Login.less';
import { Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 14 },
},
};
class Login extends React.Component {
onSubmitLogin = (e) => {
const { form, dispatch, params: { id }} = this.props
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
const {username, password} = values
dispatch({type: "auth/login", payload: {emailOrUsername: username, password}})
}
});
}
render() {
const { getFieldDecorator, dispatch } = this.props.form;
return (
<div style={{ display: 'flex', justifyContent:'center', alignItems: 'center', height: '100%'}}>
<Form onSubmit={this.onSubmitLogin} className="login-form">
<FormItem>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input prefix={<Icon type="user" style={{ fontSize: 13 }} />} placeholder="Username" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ fontSize: 13 }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox>Remember me</Checkbox>
)}
<Link to="/forgot" className="login-form-forgot">Forgot password</Link>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
Or <Link to="/register">register now!</Link>
</FormItem>
</Form>
</div>
)
}
}
function mapStateToProps() {
return {};
}
const WrapperLogin = Form.create()(Login)
export default connect(mapStateToProps)(WrapperLogin);
:global {
.login-form {
max-width: 300px;
}
.login-form-forgot {
float: right;
}
.login-form-button {
width: 100%;
}
}
.normal {
}
import React from 'react';
import { connect } from 'dva';
import styles from './Profiles.css';
function Profiles({ dispatch, text }) {
return (
<div className={styles.normal} onClick={() => dispatch({type: 'haha/change', payload: { text: Math.random() }})}>
Route Component: {text}
</div>
);
}
function mapStateToProps(state) {
const {
haha: {text}
} = state
return {
text
};
}
export default connect(mapStateToProps)(Profiles);
import React from 'react';
import { connect } from 'dva';
import { Link } from 'dva/router'
import styles from './Login.less';
import { Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 14 },
},
};
class Login extends React.Component {
onSubmitLogin = (e) => {
const { form, dispatch, isSubmit, params: { id }} = this.props
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
const {email, username, nickname, password, confirm} = values
dispatch({type: "auth/register", payload: {email, username, nickname, password, password2: confirm, submit: isSubmit}})
}
});
}
checkPassword = (rule, value, callback) => {
const form = this.props.form;
if (value && value !== form.getFieldValue('password')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
}
checkConfirm = (rule, value, callback) => {
const form = this.props.form;
if (value) {
form.validateFields(['confirm'], { force: true });
}
callback();
}
checkUsername = (rule, value, callback) => {
const { form, dispatch } = this.props
callback();
}
checkEmail= (rule, value, callback) => {
const form = this.props.form;
if (value && value !== form.getFieldValue('password')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
}
render() {
const { getFieldDecorator, dispatch } = this.props.form;
return (
<div style={{ display: 'flex', justifyContent:'center', alignItems: 'center', height: '100%'}}>
<Form onSubmit={this.onSubmitLogin} className="login-form">
<FormItem hasFeedback >
{getFieldDecorator('email', {
rules: [{ required: true, message: 'Please input your email!' }],
}, {
validator: this.checkEmail
})(
<Input placeholder="Email" />
)}
</FormItem>
<FormItem hasFeedback >
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
}, {
validator: this.checkUsername
})(
<Input placeholder="Username" />
)}
</FormItem>
<FormItem hasFeedback >
{getFieldDecorator('nickname', {
rules: [{ required: true, message: 'Please input your nickname!' }],
})(
<Input placeholder="nickname[optional]" />
)}
</FormItem>
<FormItem hasFeedback >
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
}, {
validator: this.checkConfirm
})(
<Input prefix={<Icon type="lock" style={{ fontSize: 13 }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem hasFeedback >
{getFieldDecorator('confirm', {
rules: [{
required: true, message: 'Please confirm your password!',
}, {
validator: this.checkPassword,
}],
})(
<Input type="password" onBlur={this.handleConfirmBlur} placeholder="Password Again" />
)}
</FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
Register
</Button>
Or <Link to="/login">Sign in!</Link>
</Form>
</div>
)
}
}
function mapStateToProps(state) {
const {
auth: { isSubmit, register }
} = state
return {
isSubmit,
register
};
}
const WrapperLogin = Form.create()(Login)
export default connect(mapStateToProps)(WrapperLogin);
import React from 'react';
import { connect } from 'dva';
import { Link } from 'dva/router'
import styles from './Login.less';
import { Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 14 },
},
};
class Reset extends React.Component {
onSubmitReset = (e) => {
const { form, dispatch, location: { query: { key, user_id }}} = this.props
e && e.preventDefault();
form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
const {password} = values
console.log(this.props)
dispatch({type: "auth/reset", payload: { password, key, user_id}})
}
});
}
checkPassword = (rule, value, callback) => {
const form = this.props.form;
if (value && value !== form.getFieldValue('password')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
}
checkConfirm = (rule, value, callback) => {
const form = this.props.form;
if (value) {
form.validateFields(['confirm'], { force: true });
}
callback();
}
render() {
const { getFieldDecorator, dispatch } = this.props.form;
return (
<div style={{ display: 'flex', justifyContent:'center', alignItems: 'center', height: '100%'}}>
<Form onSubmit={this.onSubmitReset} className="login-form">
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
}, {
validator: this.checkConfirm
})(
<Input prefix={<Icon type="lock" style={{ fontSize: 13 }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('confirm', {
rules: [{
required: true, message: 'Please confirm your password!',
}, {
validator: this.checkPassword,
}],
})(
<Input type="password" onBlur={this.handleConfirmBlur} placeholder="Password Again" />
)}
</FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
Submit
</Button>
</Form>
</div>
)
}
}
function mapStateToProps(state, props) {
return {};
}
const WrapperReset = Form.create()(Reset)
export default connect(mapStateToProps)(WrapperReset);
import request from '../utils/request';
import config from '../config'
export async function login(params) {
return request(`/sign_in.php`, {
method: 'POST',
body: JSON.stringify(params)
})
}
export async function forgot(params) {
return request(`/forgot_password.php`, {
method: 'POST',
body: JSON.stringify(params)
})
}
export async function register(params) {
return request(`/sign_up.php`, {
method: 'POST',
body: JSON.stringify(params)
})
}
export async function reset(params) {
return request(`/reset_password.php`, {
method: 'POST',
body: JSON.stringify(params)
})
}
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.method == 'PATCH')) {
options.headers = {
"content-type": "application/json"
}
}
console.log(options)
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
.then(data => ({ data }))
.catch(err => ({ err }));
}
This diff is collapsed.
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