Commit 15c4b1c3 authored by nano's avatar nano

awesome

parent 4b82338e
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
"dependencies": { "dependencies": {
"antd": "^2.7.4", "antd": "^2.7.4",
"babel-runtime": "^6.9.2", "babel-runtime": "^6.9.2",
"crypto": "^0.0.3",
"dva": "^1.2.1", "dva": "^1.2.1",
"qs": "^6.4.0",
"react": "^15.4.0", "react": "^15.4.0",
"react-dom": "^15.4.0" "react-dom": "^15.4.0",
"react-intl": "^2.2.3",
"uuid": "^3.0.1"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^7.1.1", "babel-eslint": "^7.1.1",
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dva Demo</title> <title>Dva Demo</title>
<link rel="stylesheet" href="index.css" /> <link rel="stylesheet" href="index.css" />
<base href="/">
</head> </head>
<body> <body>
......
...@@ -20,7 +20,7 @@ class Create extends React.Component { ...@@ -20,7 +20,7 @@ class Create extends React.Component {
} }
handleSelectChange = (value) => { handleSelectChange = (value) => {
} }
render() { render() {
......
import React from 'react';
import styles from './Items.css';
function Items() {
return (
<div className={styles.normal}>
Component: Items
</div>
);
}
export default Items;
import { Table, Input, Popconfirm } from 'antd';
class EditableCell extends React.Component {
state = {
value: this.props.value,
editable: this.props.editable || false,
}
componentWillReceiveProps(nextProps) {
if (nextProps.editable !== this.state.editable) {
this.setState({ editable: nextProps.editable });
if (nextProps.editable) {
this.cacheValue = this.state.value;
}
}
if (nextProps.status && nextProps.status !== this.props.status) {
if (nextProps.status === 'save') {
this.props.onChange(this.state.value);
} else if (nextProps.status === 'cancel') {
this.setState({ value: this.cacheValue });
this.props.onChange(this.cacheValue);
}
}
}
shouldComponentUpdate(nextProps, nextState) {
return nextProps.editable !== this.state.editable ||
nextState.value !== this.state.value;
}
handleChange(e) {
const value = e.target.value;
this.setState({ value });
}
render() {
const { value, editable } = this.state;
return (
<div>
{
editable ?
<div>
<Input
value={value}
onChange={e => this.handleChange(e)}
/>
</div>
:
<div className="editable-row-text">
{value.toString() || ' '}
</div>
}
</div>
);
}
}
export default EditableCell
\ No newline at end of file
export default { export default {
apiRoot: 'http://localhost:8001' apiRoot: 'http://localhost:8001',
imgRoot: 'http://node:7888',
returnSSO: 'http://localhost:8000/loginCallback',
SSOProvider: 'https://ygobbs.com/session/sso_provider'
// SSOProvider: 'http://localhost:8081'
} }
\ No newline at end of file
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { browserHistory } from 'dva/router'
import dva from 'dva'; import dva from 'dva';
import './index.css'; import './index.less';
import { IntlProvider, addLocaleData } from 'react-intl'; import { IntlProvider, addLocaleData } from 'react-intl';
// 1. Initialize // 1. Initialize
const app = dva(); const app = dva({
history: browserHistory
});
app.model(require("./models/Apps")); app.model(require("./models/Apps"));
app.model(require("./models/user"));
app.model(require("./models/Common")); app.model(require("./models/Common"));
app.model(require("./models/App")); app.model(require("./models/App"));
......
html, body, :global(#root) { html, body, :global(#root) {
height: 100%; height: 100%;
} }
\ No newline at end of file
import { fetch } from '../services/Apps' import { fetch, update } from '../services/Apps'
import * as crypto from 'crypto'
import config from '../config'
export default { export default {
namespace: 'Apps', namespace: 'Apps',
state: { state: {
list: [], apps: {},
}, },
reducers: { reducers: {
save(state, action) { save(state, action) {
...@@ -16,14 +19,44 @@ export default { ...@@ -16,14 +19,44 @@ export default {
effects: { effects: {
*fetch({ payload }, { call, put }) { *fetch({ payload }, { call, put }) {
const { data } = yield call(fetch, payload) const { data } = yield call(fetch, payload)
yield put({ type: 'save', payload: { list: data }})
let apps = {}
if(data && data.length > 0) {
data.map(app => {
apps[app["id"]] = app
})
}
yield put({ type: 'save', payload: { apps } })
},
*update({ payload }, {call, put}){
const { data } = yield call(update, payload)
if (data) {
yield put({ type: 'success'})
} else {
yield put({ type: 'faile' })
}
} }
}, },
subscriptions: { subscriptions: {
setup({ dispatch, history }) { setup({ dispatch, history }) {
return history.listen(({ pathname, query}) => { return history.listen(({ pathname, query}) => {
if(pathname === '/apps') {
if(/^apps/.test(pathname)) {
dispatch({ type: 'fetch', payload: query}) dispatch({ type: 'fetch', payload: query})
} else if(pathname === '/login'){
let params = new URLSearchParams()
params.set('return_sso_url', config.returnSSO)
let payload = Buffer.from(params.toString()).toString('base64')
let url = new URL(config.SSOProvider)
params = url['searchParams'];
params.set('sso', payload);
params.set('sig', crypto.createHmac('sha256', 'zsZv6LXHDwwtUAGa').update(payload).digest('hex'))
window.location.href=url
} }
}) })
} }
......
export default {
namespace: 'user',
state: {
},
reducers: {
change(state, action){
return {
...state, ...action.payload
}
}
},
effects: {},
subscriptions: {},
};
...@@ -4,14 +4,19 @@ import IndexPage from './routes/IndexPage'; ...@@ -4,14 +4,19 @@ import IndexPage from './routes/IndexPage';
import Apps from "./routes/Apps.js"; import Apps from "./routes/Apps.js";
import AppDetail from './routes/AppDetail.js' import AppDetail from './routes/AppDetail.js'
import Entry from "./routes/Entry.js"; import Entry from "./routes/Entry.js";
import LoginCallback from "./routes/LoginCallback.js";
function RouterConfig({ history }) { function RouterConfig({ history }) {
return ( return (
<Router history={history}> <Router history={history}>
<Route path="/" component={Entry} > <Route path="/" component={Entry} >
<Route path="apps" component={Apps} /> <Route path="apps" component={Apps} />
<Route path="apps/:id" component={AppDetail} /> <Route path="apps/:id" component={AppDetail} />
</Route> </Route>
<Route path="/loginCallback" component={LoginCallback} />
<Route path="*" component={() => <div>404</div>}/>
</Router> </Router>
); );
} }
......
This diff is collapsed.
:global { :global {
.app-detail-nav{ .app-detail-nav{
width: 100%; }
.ant-card {
margin: 2vh 0;
} }
.app-detail-nav .ant-tabs-nav-scroll { .app-detail-nav .ant-tabs-nav-scroll {
widows: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.ant-upload-select-picture-card i {
font-size: 28px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
font-size: 12px;
color: #666;
}
} }
.wrapSubmit{ .wrapSubmit{
width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.form { .form {
flex: 1; align-content: center;
padding: 0 5vw;
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import { connect } from 'dva'; import { connect } from 'dva';
import styles from './Apps.less'; import styles from './Apps.less';
import { Link } from 'dva/router'; import { Link } from 'dva/router';
import { Button, Affix, Icon, Table } from 'antd' import { Button, Affix, Icon, Table, Tag } from 'antd'
import Create from '../components/App/Create' import Create from '../components/App/Create'
...@@ -17,15 +17,28 @@ const columns = [ ...@@ -17,15 +17,28 @@ const columns = [
}, { }, {
title: 'Name', title: 'Name',
dataIndex: 'name', dataIndex: 'name',
render: name => `${Object.values(name)[0]}`, render: name => name && name["zh-CN"],
width: '10%', width: '10%',
key: 'name' key: 'name'
},{ },{
title: "Created_At", title: "author",
dataIndex: 'created_at', dataIndex: 'author',
width: '10%',
},{
title: "category",
dataIndex: 'category',
width: '10%',
},{
title: "homepage",
dataIndex: 'homepage',
render: homepage => <a href={homepage} target="_blank">{homepage}</a>,
width: '10%',
},{
title: "released_at",
dataIndex: 'released_at',
sorter: true, sorter: true,
width: '10%', width: '10%',
key:'created_at' key:'released_at'
}, { }, {
title: "Updated_at", title: "Updated_at",
dataIndex: 'updated_at', dataIndex: 'updated_at',
...@@ -35,7 +48,7 @@ const columns = [ ...@@ -35,7 +48,7 @@ const columns = [
}, },
] ]
function Apps({children, dispatch, isCreate, isSubmit, list}) { function Apps({children, dispatch, isCreate, isSubmit, apps}) {
const CreateProps = { const CreateProps = {
visible: isCreate, visible: isCreate,
...@@ -55,11 +68,10 @@ function Apps({children, dispatch, isCreate, isSubmit, list}) { ...@@ -55,11 +68,10 @@ function Apps({children, dispatch, isCreate, isSubmit, list}) {
const TableProps = { const TableProps = {
columns, columns,
dataSource: list dataSource: Object.values(apps)
} }
return ( return (
<div className={styles.normal}> <div className={styles.normal}>
...@@ -78,11 +90,11 @@ function Apps({children, dispatch, isCreate, isSubmit, list}) { ...@@ -78,11 +90,11 @@ function Apps({children, dispatch, isCreate, isSubmit, list}) {
function mapStateToProps(state) { function mapStateToProps(state) {
const { const {
Apps: { list }, Apps: { apps },
App: { isCreate, isSubmit } App: { isCreate, isSubmit }
} = state } = state
return { return {
list, apps,
isCreate, isCreate,
isSubmit isSubmit
}; };
......
...@@ -2,6 +2,8 @@ import React from 'react'; ...@@ -2,6 +2,8 @@ import React from 'react';
import { connect } from 'dva'; import { connect } from 'dva';
import styles from './Entry.less'; import styles from './Entry.less';
import Nav from '../components/Common/Nav' import Nav from '../components/Common/Nav'
import { Router, Route, browserHistory } from 'dva/router';
import {Layout} from 'antd' import {Layout} from 'antd'
...@@ -14,12 +16,12 @@ function Entry({ children, collapsed, mode, dispatch }) { ...@@ -14,12 +16,12 @@ function Entry({ children, collapsed, mode, dispatch }) {
} }
return ( return (
<Layout style={{ flexDirection: 'row', height: '100%'}}> <Layout style={{ flexDirection: 'row', minHeight: '100%'}}>
<Nav {...NavProps}/> <Nav {...NavProps}/>
<Layout style={{ minHeight: '400px'}}> <Layout style={{ minHeight: '400px'}}>
{children} {children}
</Layout>
</Layout> </Layout>
</Layout>
); );
} }
......
import React from 'react';
import { connect } from 'dva';
import styles from './LoginCallback.css';
class LoginCallback extends React.Component{
componentDidMount() {
const { location: { query: { sso }}, dispatch } = this.props
console.log(this.props)
const data = toObject(new URLSearchParams(Buffer.from(sso, 'base64').toString()))
if (data) {
dispatch({type: "user/change", payload:{ data }})
localStorage.setItem("user", JSON.stringify(data))
}
}
render(){
const {dispatch, location} = this.props
return (
<div className={styles.normal}>
</div>
)
}
}
function LoginCallback({ }) {
return (
<div className={styles.normal}>
{JSON.stringify(data)}
</div>
);
}
function mapStateToProps({ }) {
return {
};
}
function toObject(entries){
let result = {};
for (let [key, value] of entries) {
result[key] = value;
}
return result;
}
export default connect(mapStateToProps)(LoginCallback);
...@@ -6,7 +6,14 @@ export async function fetch() { ...@@ -6,7 +6,14 @@ export async function fetch() {
export async function create(params) { export async function create(params) {
return request(`/apps/${params.id}`, { return request(`/apps/${params.id}`, {
method: 'post', method: 'POST',
body: JSON.stringify(params)
})
}
export async function update(params) {
return request(`/apps/${params.id}`, {
method: 'PATCH',
body: JSON.stringify(params) body: JSON.stringify(params)
}) })
} }
\ No newline at end of file
...@@ -24,7 +24,7 @@ function checkStatus(response) { ...@@ -24,7 +24,7 @@ function checkStatus(response) {
*/ */
export default function request(url, options) { export default function request(url, options) {
url = `${config.apiRoot}${url}` url = `${config.apiRoot}${url}`
if(options && !options.headers && options.method == 'post') { if(options && !options.headers && (options.method == 'POST' || options.method == 'PATCH')) {
options.headers = { options.headers = {
"content-type": "application/json" "content-type": "application/json"
} }
......
...@@ -1444,6 +1444,10 @@ crypto-browserify@3.3.0: ...@@ -1444,6 +1444,10 @@ crypto-browserify@3.3.0:
ripemd160 "0.2.0" ripemd160 "0.2.0"
sha.js "2.2.6" sha.js "2.2.6"
crypto@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/crypto/-/crypto-0.0.3.tgz#470a81b86be4c5ee17acc8207a1f5315ae20dbb0"
css-animation@1.x, css-animation@^1.2.5, css-animation@^1.3.0: css-animation@1.x, css-animation@^1.2.5, css-animation@^1.3.0:
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.3.2.tgz#df515820ef5903733ad2db0999403b3037b8b880" resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.3.2.tgz#df515820ef5903733ad2db0999403b3037b8b880"
...@@ -2701,7 +2705,27 @@ interpret@^1.0.0: ...@@ -2701,7 +2705,27 @@ interpret@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1: intl-format-cache@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.0.5.tgz#b484cefcb9353f374f25de389a3ceea1af18d7c9"
intl-messageformat-parser@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.2.0.tgz#5906b7f953ab7470e0dc8549097b648b991892ff"
intl-messageformat@1.3.0, intl-messageformat@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-1.3.0.tgz#f7d926aded7a3ab19b2dc601efd54e99a4bd4eae"
dependencies:
intl-messageformat-parser "1.2.0"
intl-relativeformat@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-1.3.0.tgz#893dc7076fccd380cf091a2300c380fa57ace45b"
dependencies:
intl-messageformat "1.3.0"
invariant@^2.0.0, invariant@^2.1.1, invariant@^2.2.0, invariant@^2.2.1:
version "2.2.2" version "2.2.2"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
dependencies: dependencies:
...@@ -4102,6 +4126,10 @@ qs@6.3.1, qs@~6.3.0: ...@@ -4102,6 +4126,10 @@ qs@6.3.1, qs@~6.3.0:
version "6.3.1" version "6.3.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.1.tgz#918c0b3bcd36679772baf135b1acb4c1651ed79d" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.1.tgz#918c0b3bcd36679772baf135b1acb4c1651ed79d"
qs@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
query-string@^3.0.0: query-string@^3.0.0:
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-3.0.3.tgz#ae2e14b4d05071d4e9b9eb4873c35b0dcd42e638" resolved "https://registry.yarnpkg.com/query-string/-/query-string-3.0.3.tgz#ae2e14b4d05071d4e9b9eb4873c35b0dcd42e638"
...@@ -4459,6 +4487,15 @@ react-hammerjs@~0.5.0: ...@@ -4459,6 +4487,15 @@ react-hammerjs@~0.5.0:
dependencies: dependencies:
hammerjs "^2.0.8" hammerjs "^2.0.8"
react-intl@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.2.3.tgz#8eebb03cddc38b337ed22fab78037ab53a594270"
dependencies:
intl-format-cache "^2.0.5"
intl-messageformat "^1.3.0"
intl-relativeformat "^1.3.0"
invariant "^2.1.1"
react-lazy-load@^3.0.10: react-lazy-load@^3.0.10:
version "3.0.11" version "3.0.11"
resolved "https://registry.yarnpkg.com/react-lazy-load/-/react-lazy-load-3.0.11.tgz#1d27e4e1f6dc77daaf9236db707aaf2bbbfabafe" resolved "https://registry.yarnpkg.com/react-lazy-load/-/react-lazy-load-3.0.11.tgz#1d27e4e1f6dc77daaf9236db707aaf2bbbfabafe"
...@@ -5371,7 +5408,7 @@ uuid@^2.0.2: ...@@ -5371,7 +5408,7 @@ uuid@^2.0.2:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
uuid@^3.0.0: uuid@^3.0.0, uuid@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
......
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