提交 5f99a08b authored 作者: vipcxj's avatar vipcxj

补完文档, 文档加载自动化

上级 cd77cb12
...@@ -16375,9 +16375,9 @@ ...@@ -16375,9 +16375,9 @@
"integrity": "sha512-H0nT+KHADICdFgflNZ0A6+EBcExajxY8XM100tKOT5Oidhdo/0bAi26ffBhraEls4FIi8Lm4917tMq8LIWN7Qg==" "integrity": "sha512-H0nT+KHADICdFgflNZ0A6+EBcExajxY8XM100tKOT5Oidhdo/0bAi26ffBhraEls4FIi8Lm4917tMq8LIWN7Qg=="
}, },
"react-async-wrapper": { "react-async-wrapper": {
"version": "0.1.0", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/react-async-wrapper/-/react-async-wrapper-0.1.0.tgz", "resolved": "https://registry.npmjs.org/react-async-wrapper/-/react-async-wrapper-0.1.2.tgz",
"integrity": "sha512-Bd/Azo0X1Qd+KCUUAOi9+H2y7YqX9XV3gJkd5H1uBgA7ZSr/9HIdIj/1VnIuwojLgnOPDHt6aqEBs7mfgIJFHw==", "integrity": "sha512-rUsqvpgVWLZaPnbai6oJu5sQcgpr1lgCCarAuFTzPd6wTlUecotU96+dYCdfVDpibTXwxsnzEAvn3fb2k1UpXA==",
"requires": { "requires": {
"is-promise": "2.1.0" "is-promise": "2.1.0"
} }
...@@ -16647,7 +16647,7 @@ ...@@ -16647,7 +16647,7 @@
"requires": { "requires": {
"hoist-non-react-statics": "2.5.0", "hoist-non-react-statics": "2.5.0",
"invariant": "2.2.4", "invariant": "2.2.4",
"react-async-wrapper": "0.1.0" "react-async-wrapper": "0.1.2"
} }
}, },
"react-router-dom": { "react-router-dom": {
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
"moment": "^2.18.1", "moment": "^2.18.1",
"prop-types": "^15.6.1", "prop-types": "^15.6.1",
"react": "^16.2.0", "react": "^16.2.0",
"react-async-wrapper": "^0.1.0", "react-async-wrapper": "^0.1.2",
"react-dom": "^16.2.0", "react-dom": "^16.2.0",
"react-json-view": "^1.11.4", "react-json-view": "^1.11.4",
"react-markdown": "^3.3.0", "react-markdown": "^3.3.0",
......
...@@ -10,7 +10,7 @@ const App = ({ children }) => { ...@@ -10,7 +10,7 @@ const App = ({ children }) => {
}; };
App.propTypes = { App.propTypes = {
children: PropTypes.element.isRequired, children: PropTypes.oneOfType(PropTypes.element, PropTypes.arrayOf(PropTypes.element)).isRequired,
}; };
export default connect()(App); export default connect()(App);
/* eslint-disable react/no-danger */
import React from 'react';
import PropTypes from 'prop-types';
class MarkDown extends React.Component {
render() {
return (
<div dangerouslySetInnerHTML={{
__html: this.props.markdown,
}}
/>
);
}
}
MarkDown.propTypes = {
markdown: PropTypes.string,
};
MarkDown.defaultProps = {
markdown: '',
};
export default MarkDown;
...@@ -20,34 +20,50 @@ POST ...@@ -20,34 +20,50 @@ POST
``` ```
{ {
type: string, //登录方式 type: string,
data: string, //登录方式对应的登录数据 data: string,
tokenInfo: { //令牌信息 tokenInfo: {
productId: string, //产品ID productId: string,
deviceId: string //设备ID deviceId: string
}, },
authRequest: { //验证请求,可选 authRequest: {
type: string, //验证方式 type: string,
parameters: Map //验证参数 parameters: Map
} }
} }
``` ```
> - *type*: 登录方式, 可选值为`userName`,`email`,分别表示用户名登录和邮箱登录。 - *type* - **string** 登录方式, 可选值为`userName``email`,分别表示用户名登录和邮箱登录。
> - *data*: 登录方式对应的登录数据, `userName`对应的登录数据即为用户名,`email`对应的登录数据即为邮箱地址 - *data* - **string** 登录方式对应的登录数据, `userName`对应的登录数据即为用户名,`email`对应的登录数据即为邮箱地址
> - *tokenInfo*: 登录必备的信息,为权限验证所需。 - *tokenInfo* - **object** 登录必备的信息,为权限验证所需。
> - *productId*: 产品ID,表示要登录的产品。 - *productId* - **string** 产品ID,表示要登录的产品。
> - *deviceId*: 设备ID,一条可以用来唯一标识客户端的字符串,生成规则不限,只要保证唯一性和不变性即可。 - *deviceId* - **string** 设备ID,一条可以用来唯一标识客户端的字符串,生成规则不限,只要保证唯一性和不变性即可。
> - *authRequest*: 验证请求,为了简化接口,登录的同时也可以一起进行验证。 - *authRequest* - **object** 验证请求,为了简化接口,登录的同时也可以一起进行验证。
前提是事先知道对应用户需要用哪种方式进行验证。因为用户所需的验证方式是后台可配置, 前提是事先知道对应用户需要用哪种方式进行验证。因为用户所需的验证方式是后台可配置,
不是一成不变的,所以不建议登录验证同时进行的api调用方式。 不是一成不变的,所以不建议登录验证同时进行的api调用方式。
> - *type*: 验证方式。可选值为`password`,表示密码登录 - *type* - **string** 验证方式。可选值为`password`,表示密码登录
> - *parameters*: 验证参数。`password`对应的验证参数为 - *parameters* - **object** 验证参数。`password`对应的验证参数为
`{ cipher: string }`,表示用户密码。 `{ cipher: string }`,表示用户密码。
- **Content-Type**: - **Content-Type**:
application/json application/json
- *tokenId* - **string** 未加密的原始token字符串,该token在服务器存在内存中,
若超过30分钟没有使用该token,该token将失效。
- *authResponse* - **object** 验证响应,请求体中包含`authRequest`字段时,响应体中才会有此字段。
- *type* - **string** 验证类型,与请求体中`authRequest.type`值相同。
- *status* - **string** 验证状态,可能值为:`authed`,`rejected`,`skipped`等。
`authed`表示验证通过,`rejected`表示验证未通过,`skipped`表示不需要此步验证。
以上3种可能值为所有验证方式共有。其他可能值依赖于各自的验证方式。
- *data* - **any** 验证响应数据。其含义依赖于验证方式。
- *remainedAuthRequirements* - **object** 剩余的验证需求。
- *requirements* - **[object]** 若干个验证需求,逻辑关系为和。
若为空数组,表示所有验证需求均已满足,即全部验证成功。
- *authTypes*: - **[string]** 若干个验证方式,逻辑关系为或,
只要其中一个验证方式验证成功,该验证条件即满足。
- *remainedAuthRequirements* - **object**`authResponse.remainedAuthRequirements`
不同之处在于请求体中不需要包含`authRequest`,该字段也存在。
``` ```
{ {
tokenId: string, tokenId: string,
...@@ -68,21 +84,7 @@ application/json ...@@ -68,21 +84,7 @@ application/json
} }
} }
``` ```
> - *tokenId*: 未加密的原始token字符串,该token在服务器存在内存中,
若超过30分钟没有使用该token,该token将失效。
> - *authResponse*: 验证响应,请求体中包含`authRequest`字段时,响应体中才会有此字段。
- *type*: 验证类型,与请求体中`authRequest.type`值相同。
- *status*: 验证状态,可能值为:`authed`,`rejected`,`skipped`等。
`authed`表示验证通过,`rejected`表示验证未通过,`skipped`表示不需要此步验证。
以上3种可能值为所有验证方式共有。其他可能值依赖于各自的验证方式。
- *data*: 验证响应数据。其含义依赖于验证方式。
- *remainedAuthRequirements*: 剩余的验证需求。
- *requirements*: 若干个验证需求,逻辑关系为和。
若为空数组,表示所有验证需求均已满足,即全部验证成功。
- *authTypes*: 若干个验证方式,逻辑关系为或,
只要其中一个验证方式验证成功,该验证条件即满足。
> - *remainedAuthRequirements*: 同`authResponse.remainedAuthRequirements`。
不同之处在于请求体中不需要包含`authRequest`,该字段也存在。
- **note**: - **note**:
获取后的token,不能直接使用,需要使用公钥进行非对称加密。加密方式如下: 获取后的token,不能直接使用,需要使用公钥进行非对称加密。加密方式如下:
...@@ -121,10 +123,10 @@ application/json ...@@ -121,10 +123,10 @@ application/json
} }
} }
``` ```
- *tkId*: 加密后的令牌 - *tkId* - **string** 加密后的令牌
- *request*: 验证请求 - *request* -**object** 验证请求
- *type*: 验证方式。可选值为`password`,表示密码登录 - *type* - **string** 验证方式。可选值为`password`,表示密码登录
- *parameters*: 验证参数。`password`对应的验证参数为 - *parameters* - **object** 验证参数。`password`对应的验证参数为
`{ cipher: string }`,表示用户密码。 `{ cipher: string }`,表示用户密码。
- **Content-Type**: - **Content-Type**:
...@@ -142,15 +144,15 @@ application/json ...@@ -142,15 +144,15 @@ application/json
} }
} }
``` ```
- *type*: 验证类型,与请求体中`authRequest.type`值相同。 - *type* - **string** 验证类型,与请求体中`authRequest.type`值相同。
- *status*: 验证状态,可能值为:`authed`,`rejected`,`skipped`等。 - *status* - **string** 验证状态,可能值为:`authed`,`rejected`,`skipped`等。
`authed`表示验证通过,`rejected`表示验证未通过,`skipped`表示不需要此步验证。 `authed`表示验证通过,`rejected`表示验证未通过,`skipped`表示不需要此步验证。
以上3种可能值为所有验证方式共有。其他可能值依赖于各自的验证方式。 以上3种可能值为所有验证方式共有。其他可能值依赖于各自的验证方式。
- *data*: 验证响应数据。其含义依赖于验证方式。 - *data* - **any** 验证响应数据。其含义依赖于验证方式。
- *remainedAuthRequirements*: 剩余的验证需求。 - *remainedAuthRequirements* - **[object]** 剩余的验证需求。
- *requirements*: 若干个验证需求,逻辑关系为和。 - *requirements* - **[object]** 若干个验证需求,逻辑关系为和。
若为空数组,表示所有验证需求均已满足,即全部验证成功。 若为空数组,表示所有验证需求均已满足,即全部验证成功。
- *authTypes*: 若干个验证方式,逻辑关系为或, - *authTypes* - **[string]** 若干个验证方式,逻辑关系为或,
只要其中一个验证方式验证成功,该验证条件即满足。 只要其中一个验证方式验证成功,该验证条件即满足。
## 登出 ## 登出
...@@ -163,8 +165,9 @@ POST ...@@ -163,8 +165,9 @@ POST
- **Accept**: - **Accept**:
application/json application/json
`empty` (只包含前置说明中提到的token,即`{ token: string }`, 之后不再重复说明。) - `empty` - 只包含前置说明中提到的token,即`{ token: string }`, 之后不再重复说明。
- **Content-Type**: - **Content-Type**:
application/json application/json
`null` (并不是真正的空,仅仅是如前置说明中提到那样,`data`字段为`null`, 之后不再重复说明。)
`null` - 并不是真正的空,仅仅是如前置说明中提到那样,`data`字段为`null`, 之后不再重复说明。
.markdown {
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
width: 100%;
color:#444;
font-family:Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif;
font-size:12px;
line-height:1.5em;
padding:1em;
background:#fefefe;
a{ color: #0645ad; text-decoration:none;}
a:visited{ color: #0b0080; }
a:hover{ color: #06e; }
a:active{ color:#faa700; }
a:focus{ outline: thin dotted; }
a:hover, a:active{ outline: 0; }
::-moz-selection{background:rgba(255,255,0,0.3);color:#000}
::selection{background:rgba(255,255,0,0.3);color:#000}
a::-moz-selection{background:rgba(255,255,0,0.3);color:#0645ad}
a::selection{background:rgba(255,255,0,0.3);color:#0645ad}
p{
margin:1em 0;
}
img{
max-width:100%;
}
h1,h2,h3,h4,h5,h6{
font-weight:normal;
color:#111;
line-height:1em;
}
h4,h5,h6{ font-weight: bold; }
h1{ font-size:2.5em; }
h2{ font-size:2em; }
h3{ font-size:1.5em; }
h4{ font-size:1.2em; }
h5{ font-size:1em; }
h6{ font-size:0.9em; }
blockquote{
color:#666666;
margin:0;
padding-left: 3em;
border-left: 0.5em #EEE solid;
}
hr { display: block; height: 2px; border: 0; border-top: 1px solid #aaa;border-bottom: 1px solid #eee; margin: 1em 0; padding: 0; }
pre, code, kbd, samp { color: #000; font-family: monospace, monospace; _font-family: 'courier new', monospace; font-size: 0.98em; }
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; }
b, strong { font-weight: bold; }
dfn { font-style: italic; }
ins { background: #ff9; color: #000; text-decoration: none; }
mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; }
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
ul, ol { margin: 1em 0; padding: 0 0 0 2em; }
li p:last-child { margin:0 }
dd { margin: 0 0 0 2em; }
img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; }
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
}
th { border-bottom: 1px solid black; }
td { vertical-align: top; }
@media only screen and (min-width: 480px) {
font-size:14px;
}
@media only screen and (min-width: 768px) {
font-size:16px;
}
@media print {
* { background: transparent !important; color: black !important; filter:none !important; -ms-filter: none !important; }
font-size:12pt; max-width:100%;
a, a:visited { text-decoration: underline; }
hr { height: 1px; border:0; border-bottom:1px solid black; }
a[href]:after { content: " (" attr(href) ")"; }
abbr[title]:after { content: " (" attr(title) ")"; }
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
pre, blockquote { border: 1px solid #999; padding-right: 1em; page-break-inside: avoid; }
tr, img { page-break-inside: avoid; }
img { max-width: 100% !important; }
@page :left { margin: 15mm 20mm 15mm 10mm; }
@page :right { margin: 15mm 10mm 15mm 20mm; }
p, h2, h3 { orphans: 3; widows: 3; }
h2, h3 { page-break-after: avoid; }
}
}
import React from 'react';
import { AsyncComponent } from 'react-async-wrapper';
import ReactMarkdown from 'react-markdown';
export default (match) => {
const linkBase = `${match.url}/dynamic-interface`;
const pathBase = `${match.path}/dynamic-interface`;
return [
['addFamily', '新增两清'],
['updateFamily', '修改两清'],
['removeFamily', '删除两清'],
].map(([name, showName]) => ({
name,
showName,
link: `${linkBase}/${name}`,
path: `${pathBase}/${name}`,
component: props => (
<AsyncComponent asyncComponent={
() => import(`./${name}.md`).then(md => p => (
<div style={{
padding: '1em',
background: '#fafafa',
}}
>
<ReactMarkdown {...p} {...props} className="markdown-body" source={md} />
</div>
))
}
/>
),
}));
};
...@@ -7,6 +7,29 @@ ...@@ -7,6 +7,29 @@
不过一般情况下,进入生产环境配置好的接口不会轻易改动, 不过一般情况下,进入生产环境配置好的接口不会轻易改动,
除非有bug。 除非有bug。
## 验证前置条件
调用动态接口可能需要满足某些状态条件,使用这个api来事先进行检测。
改api如果检测满足前置条件,则没有返回值,如果不满足条件`errorCode`则不为0,
`errorCode`含义依赖于具体配置,另外`message`字段也可能包含错误信息,
`data`字段可能包含特定的错误数据。
- **URL**
/api/interface/user/{name}/invoke/validateState
- *name* - 动态接口的名称,可以认为是动态接口的唯一标识符。
- **Method**:
GET
- **query parameter**
-
- **Content-Type**:
application/json
- `null`
## 调用动态接口
执行动态接口,调用此接口,服务端仍然会进行前置条件验证。
- **URL**: - **URL**:
/api/interface/user/{name}/invoke /api/interface/user/{name}/invoke
- *name* - 动态接口的名称,可以认为是动态接口的唯一标识符。 - *name* - 动态接口的名称,可以认为是动态接口的唯一标识符。
......
...@@ -9,9 +9,7 @@ import mdIndex from './index.md'; ...@@ -9,9 +9,7 @@ import mdIndex from './index.md';
import mdAuth from './auth.md'; import mdAuth from './auth.md';
import mdDomain from './domain.md'; import mdDomain from './domain.md';
import mdDyInt from './dynamic-interface/index.md'; import mdDyInt from './dynamic-interface/index.md';
import mdDyAddFamily from './dynamic-interface/addFamily.md'; import createPages from './dynamic-interface';
import mdDyUpdateFamily from './dynamic-interface/updateFamily.md';
import mdDyRemoveFamily from './dynamic-interface/removeFamily.md';
const md = mdString => props => ( const md = mdString => props => (
<div style={{ <div style={{
...@@ -26,6 +24,7 @@ const md = mdString => props => ( ...@@ -26,6 +24,7 @@ const md = mdString => props => (
class DocMainPage extends React.Component { class DocMainPage extends React.Component {
render() { render() {
const { match } = this.props; const { match } = this.props;
const pages = createPages(match);
return ( return (
<div className={styles.main} ref={(node) => { this.container = node && node.parentElement; }}> <div className={styles.main} ref={(node) => { this.container = node && node.parentElement; }}>
<Affix target={() => this.container}> <Affix target={() => this.container}>
...@@ -42,9 +41,11 @@ class DocMainPage extends React.Component { ...@@ -42,9 +41,11 @@ class DocMainPage extends React.Component {
<li> <li>
<Link to={`${match.url}/dynamic-interface`}>动态接口</Link> <Link to={`${match.url}/dynamic-interface`}>动态接口</Link>
<ul> <ul>
<li><Link to={`${match.url}/dynamic-interface/addFamily`}>新增两清</Link></li> {
<li><Link to={`${match.url}/dynamic-interface/updateFamily`}>更新两清</Link></li> pages.map(page => (
<li><Link to={`${match.url}/dynamic-interface/removeFamily`}>删除两清</Link></li> <li key={page.name}><Link to={page.link}>{ page.showName }</Link></li>
))
}
</ul> </ul>
</li> </li>
</ul> </ul>
...@@ -55,15 +56,11 @@ class DocMainPage extends React.Component { ...@@ -55,15 +56,11 @@ class DocMainPage extends React.Component {
<Route path={`${match.path}/auth`} component={md(mdAuth)} /> <Route path={`${match.path}/auth`} component={md(mdAuth)} />
<Route path={`${match.path}/domain`} component={md(mdDomain)} /> <Route path={`${match.path}/domain`} component={md(mdDomain)} />
<Route path={`${match.path}/dynamic-interface`} exact component={md(mdDyInt)} /> <Route path={`${match.path}/dynamic-interface`} exact component={md(mdDyInt)} />
<Route path={`${match.path}/dynamic-interface/addFamily`} component={md(mdDyAddFamily)} /> {
<Route path={`${match.path}/dynamic-interface/updateFamily`} component={md(mdDyUpdateFamily)} /> pages.map(page => (
<Route path={`${match.path}/dynamic-interface/removeFamily`} component={md(mdDyRemoveFamily)} /> <Route key={page.name} path={page.path} component={page.component} />
<Route path={`${match.path}/dynamic-interface/addHouse`} component={md(mdDyAddFamily)} /> ))
<Route path={`${match.path}/dynamic-interface/updateHouse`} component={md(mdDyAddFamily)} /> }
<Route path={`${match.path}/dynamic-interface/removeHouse`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/addPeople`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/updatePeople`} component={md(mdDyAddFamily)} />
<Route path={`${match.path}/dynamic-interface/removePeople`} component={md(mdDyAddFamily)} />
</Switch> </Switch>
</div> </div>
</div> </div>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论