├── .angular-cli.json
├── .editorconfig
├── .gitignore
├── README.md
├── e2e
├── app.e2e-spec.ts
├── app.po.ts
└── tsconfig.e2e.json
├── karma.conf.js
├── package.json
├── protractor.conf.js
├── proxy.conf.json
├── src
├── app
│ ├── apidoc
│ │ ├── api-param
│ │ │ ├── api-param.component.html
│ │ │ ├── api-param.component.scss
│ │ │ └── api-param.component.ts
│ │ ├── apidoc.module.ts
│ │ └── index
│ │ │ ├── index.component.html
│ │ │ ├── index.component.scss
│ │ │ └── index.component.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── auto-intercepter.ts
│ ├── config.ts
│ └── http-service.service.ts
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.scss
├── test.ts
├── tsconfig.app.json
├── tsconfig.spec.json
└── typings.d.ts
├── tsconfig.json
└── tslint.json
/.angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "project": {
4 | "name": "manager"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.app.json",
19 | "testTsconfig": "tsconfig.spec.json",
20 | "prefix": "app",
21 | "styles": [
22 | "styles.scss",
23 | "../node_modules/bootstrap/dist/css/bootstrap.min.css"
24 | ],
25 | "scripts": [
26 | "../node_modules/jquery/dist/jquery.min.js",
27 | "../node_modules/bootstrap/dist/js/bootstrap.min.js"
28 | ],
29 | "environmentSource": "environments/environment.ts",
30 | "environments": {
31 | "dev": "environments/environment.ts",
32 | "prod": "environments/environment.prod.ts"
33 | }
34 | }
35 | ],
36 | "e2e": {
37 | "protractor": {
38 | "config": "./protractor.conf.js"
39 | }
40 | },
41 | "lint": [
42 | {
43 | "project": "src/tsconfig.app.json",
44 | "exclude": "**/node_modules/**"
45 | },
46 | {
47 | "project": "src/tsconfig.spec.json",
48 | "exclude": "**/node_modules/**"
49 | },
50 | {
51 | "project": "e2e/tsconfig.e2e.json",
52 | "exclude": "**/node_modules/**"
53 | }
54 | ],
55 | "test": {
56 | "karma": {
57 | "config": "./karma.conf.js"
58 | }
59 | },
60 | "defaults": {
61 | "styleExt": "scss",
62 | "component": {}
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 |
8 | # dependencies
9 | /node_modules
10 |
11 | # IDEs and editors
12 | /.idea
13 | .project
14 | .classpath
15 | .c9/
16 | *.launch
17 | .settings/
18 | *.sublime-workspace
19 | .idea
20 |
21 | # IDE - VSCode
22 | .vscode/*
23 | !.vscode/settings.json
24 | !.vscode/tasks.json
25 | !.vscode/launch.json
26 | !.vscode/extensions.json
27 |
28 | # misc
29 | /.sass-cache
30 | /connect.lock
31 | /coverage
32 | /libpeerconnection.log
33 | npm-debug.log
34 | testem.log
35 | /typings
36 |
37 | # e2e
38 | /e2e/*.js
39 | /e2e/*.map
40 |
41 | # System Files
42 | .DS_Store
43 | Thumbs.db
44 |
45 | package-lock.json
46 | .gitee
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # apiDoc生成
2 | 前端页面实现 (angular版)
3 | # 简介
4 |
5 | 前后台分离时,api文档自动生成插件的前端页面,采用angular实现。
6 |
7 | ## 开发环境
8 | ```
9 | Angular CLI: 1.7.4
10 | Node: 8.4.0
11 | OS: win32 x64
12 | Angular: 5.2.10
13 | ```
14 |
15 |
16 | # 快速启动
17 | 下载该项目然后`npm install`
18 |
19 | 如果网络受限,请尝试淘宝的镜像
20 | `npm i -g cnpm --registry=https://registry.npm.taobao.org`
21 |
22 | `ng serve`后打开浏览器`localhost:4200`访问即可
23 |
24 | # 动态代理
25 | 启用该代理需要先运行后端程序,后端代码地址:https://github.com/liupeng328/api-doc
26 |
27 | 文件 : proxy.conf.json
28 | ```$xslt
29 | {
30 | "/": {
31 | "target": "http://localhost:8080/",
32 | "secure": false
33 | }
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 |
3 | describe('manager App', () => {
4 | let page: AppPage;
5 |
6 | beforeEach(() => {
7 | page = new AppPage();
8 | });
9 |
10 | it('should display welcome message', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('Welcome to app!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/e2e",
5 | "baseUrl": "./",
6 | "module": "commonjs",
7 | "target": "es5",
8 | "types": [
9 | "jasmine",
10 | "jasminewd2",
11 | "node"
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular/cli'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular/cli/plugins/karma')
14 | ],
15 | client:{
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | reports: [ 'html', 'lcovonly' ],
20 | fixWebpackSourcePaths: true
21 | },
22 | angularCli: {
23 | environment: 'dev'
24 | },
25 | reporters: ['progress', 'kjhtml'],
26 | port: 9876,
27 | colors: true,
28 | logLevel: config.LOG_INFO,
29 | autoWatch: true,
30 | browsers: ['Chrome'],
31 | singleRun: false
32 | });
33 | };
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ApiDoc",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "scripts": {
6 | "start": "ng serve --host 0.0.0.0 --port 4201 --proxy-config proxy.conf.json --open",
7 | "build": "ng build",
8 | "build-prod": "ng build --prod --aot --base-href ./",
9 | "test": "ng test",
10 | "e2e": "ng e2e"
11 | },
12 | "private": true,
13 | "dependencies": {
14 | "@angular/animations": "^5.2.9",
15 | "@angular/common": "^5.2.9",
16 | "@angular/compiler": "^5.2.9",
17 | "@angular/core": "^5.2.9",
18 | "@angular/forms": "^5.2.9",
19 | "@angular/http": "^5.2.9",
20 | "@angular/platform-browser": "^5.2.9",
21 | "@angular/platform-browser-dynamic": "^5.2.9",
22 | "@angular/router": "^5.2.9",
23 | "bootstrap": "^3.3.7",
24 | "classlist.js": "^1.1.20150312",
25 | "core-js": "^2.5.5",
26 | "intl": "^1.2.5",
27 | "jquery": "^3.3.1",
28 | "ng-zorro-antd": "^0.6.15",
29 | "rxjs": "^5.5.10",
30 | "web-animations-js": "^2.3.1",
31 | "zone.js": "^0.8.26"
32 | },
33 | "devDependencies": {
34 | "@angular/cli": "^1.7.4",
35 | "@angular/compiler-cli": "^5.2.9",
36 | "@angular/language-service": "^5.2.9",
37 | "@types/bootstrap": "^4.1.0",
38 | "@types/jasmine": "~2.8.6",
39 | "@types/jasminewd2": "~2.0.3",
40 | "@types/jquery": "^3.3.1",
41 | "@types/node": "~9.6.5",
42 | "codelyzer": "~4.2.1",
43 | "jasmine-core": "~3.1.0",
44 | "jasmine-spec-reporter": "~4.2.1",
45 | "karma": "~2.0.0",
46 | "karma-chrome-launcher": "~2.2.0",
47 | "karma-cli": "~1.0.1",
48 | "karma-coverage-istanbul-reporter": "^1.4.2",
49 | "karma-jasmine": "~1.1.1",
50 | "karma-jasmine-html-reporter": "^1.0.0",
51 | "protractor": "~5.3.1",
52 | "ts-node": "~5.0.1",
53 | "tslint": "~5.9.1",
54 | "typescript": "~2.4.2"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require('jasmine-spec-reporter');
5 |
6 | exports.config = {
7 | allScriptsTimeout: 11000,
8 | specs: [
9 | './e2e/**/*.e2e-spec.ts'
10 | ],
11 | capabilities: {
12 | 'browserName': 'chrome'
13 | },
14 | directConnect: true,
15 | baseUrl: 'http://localhost:4200/',
16 | framework: 'jasmine',
17 | jasmineNodeOpts: {
18 | showColors: true,
19 | defaultTimeoutInterval: 30000,
20 | print: function() {}
21 | },
22 | onPrepare() {
23 | require('ts-node').register({
24 | project: 'e2e/tsconfig.e2e.json'
25 | });
26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/proxy.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "/": {
3 | "target": "http://localhost:8080",
4 | "secure": false
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/app/apidoc/api-param/api-param.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{requestParam.name}} |
9 | {{requestParam.required}} |
10 | {{requestParam.dataType}} |
11 | {{requestParam.defaultValue}} |
12 | {{requestParam.description}} |
13 |
14 |
15 |
16 |
17 |
18 |
19 | {{requestParam.name}} |
20 | {{requestParam.required}} |
21 | {{requestParam.dataType}} |
22 | {{requestParam.defaultValue}} |
23 | {{requestParam.description}} |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/app/apidoc/api-param/api-param.component.scss:
--------------------------------------------------------------------------------
1 | .div-table {
2 | table {
3 | width: 100%;
4 | th {
5 | text-align: left;
6 | padding: 6px;
7 | border: 1px solid rgba(92, 102, 94, 0.06);
8 | width: 15%;
9 | &:last-child {
10 | width: 40%;
11 | }
12 | }
13 | td {
14 | text-align: left;
15 | padding: 6px;
16 | border: 1px solid rgba(92, 102, 94, 0.06);
17 | width: 15%;
18 | &:last-child {
19 | width: 40%;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/app/apidoc/api-param/api-param.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Input} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-api-param',
5 | templateUrl: './api-param.component.html',
6 | styleUrls: ['./api-param.component.scss']
7 | })
8 | export class ApiParamComponent {
9 |
10 | @Input()
11 | params: any;
12 |
13 | @Input()
14 | require: boolean;
15 |
16 | @Input()
17 | index=0;
18 |
19 | constructor() {
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/apidoc/apidoc.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {FormsModule, ReactiveFormsModule} from '@angular/forms';
4 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
5 | import {HttpClientModule} from '@angular/common/http';
6 | import {NgZorroAntdModule} from 'ng-zorro-antd';
7 | import {IndexComponent} from './index/index.component';
8 | import {ApiParamComponent} from './api-param/api-param.component';
9 |
10 | @NgModule({
11 | imports: [
12 | CommonModule,
13 | FormsModule,
14 | HttpClientModule,
15 | ReactiveFormsModule,
16 | BrowserAnimationsModule,
17 | NgZorroAntdModule.forRoot(),
18 | ],
19 | declarations: [IndexComponent, ApiParamComponent],
20 | exports: [IndexComponent]
21 | })
22 | export class InterfaceModule {
23 | }
24 |
--------------------------------------------------------------------------------
/src/app/apidoc/index/index.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 文档功能未开启,请联系管理员。
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{apiInfo.title}} ({{apiInfo.version}})
17 |
18 |
19 |
20 | -
21 | {{i}}. {{modules.name}}
22 |
23 | -
25 | {{moduleItem.name}}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
53 |
54 |
55 |
63 |
64 |
65 |
66 |
67 |
请求参数
68 | (类型:{{apiModule.reqParams.type?apiModule.reqParams.type:'url'}})
69 |
70 |
71 |
100 |
101 |
102 |
103 |
136 |
137 |
138 |
139 |
140 |
示例
141 | (*注意:请在headers中携带cookie或者token令牌,以保证访问安全或权限校验)
142 |
143 |
144 |
156 |
157 |
158 |
159 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 | {{apiInfo.title}} (文档版本: {{apiInfo.version}})
212 |
213 |
215 |
{{apiInfo.description}}
216 |
217 |
218 |
219 |
220 |
221 |
223 |
224 |
225 |
226 |
227 |
--------------------------------------------------------------------------------
/src/app/apidoc/index/index.component.scss:
--------------------------------------------------------------------------------
1 | .api-details {
2 | color: #333333;
3 | min-height: 800px;
4 | padding: 6px;
5 | p {
6 | margin: 6px 0px;
7 | }
8 | .api-details-title {
9 | font-size: 16px;
10 | color: #333333;
11 | font-weight: bold;
12 | padding: 10px 0;
13 | }
14 | .api-panel-title {
15 | p {
16 | padding: 0 8px;
17 | }
18 | }
19 | .api-panel-footer {
20 | background: #ffffff;
21 | font-size: 0.8em;
22 | color: #333333;
23 | pre{
24 | padding: 8px;
25 | }
26 | .jg {
27 | margin-left: 10px;
28 | }
29 | input {
30 | font-weight: 700;
31 | font-size: 1.3em;
32 | color: #000000;
33 | }
34 | }
35 | .gekai {
36 | height: 10px;
37 | width: 30px;
38 | }
39 | }
40 |
41 | .centerLogo {
42 | margin-top: 240px;
43 | background-color: #ffffff;
44 | color: deepskyblue;
45 | font-weight: 600;
46 | font-size: 30px;
47 | text-align: center;
48 | span {
49 | font-size: 13px;
50 | }
51 | }
52 |
53 | :host ::ng-deep nz-layout {
54 | height: 100%;
55 | overflow: scroll;
56 | }
57 |
58 | :host ::ng-deep nz-sider {
59 | height: 100%;
60 | overflow: scroll;
61 | }
62 |
63 | :host ::ng-deep .logo {
64 | background: #333;
65 | border-radius: 6px;
66 | color: white;
67 | font-weight: 600;
68 | height: 64px;
69 | line-height: 64px;
70 | font-size: 22px;
71 | text-align: center;
72 | span {
73 | font-size: 12px;
74 | }
75 | }
76 |
77 | :host ::ng-deep .ant-layout-sider-collapsed .nav-text {
78 | display: none;
79 | }
80 |
81 | :host ::ng-deep .ant-layout-sider-collapsed .ant-menu-submenu-title:after {
82 | display: none;
83 | }
84 |
85 | :host ::ng-deep .ant-layout-sider-collapsed .anticon {
86 | font-size: 16px;
87 | margin-left: 8px;
88 | }
89 |
90 | :host ::ng-deep .trigger {
91 | font-size: 18px;
92 | line-height: 64px;
93 | padding: 0 16px;
94 | cursor: pointer;
95 | transition: color .3s;
96 | }
97 |
98 | :host ::ng-deep .trigger:hover {
99 | color: #108ee9;
100 | }
101 |
102 | :host ::ng-deep .ant-card-body {
103 | padding: 0;
104 | }
105 |
106 | :host ::ng-deep .ant-card-head {
107 | height: 32px;
108 | line-height: 32px;
109 | background: #eee;
110 | }
111 | :host ::ng-deep nz-layout{
112 | overflow: hidden;
113 | }
114 | :host ::ng-deep nz-sider{
115 | overflow-x: hidden;
116 | overflow-y: scroll;
117 | }
118 |
119 | .oinp {
120 | border: none;
121 | outline-style: none;
122 | }
123 |
124 | textarea {
125 | font-weight: 700;
126 | font-size: 0.9em;
127 | color: #108ee9;
128 | }
129 |
130 | .div-table {
131 | table {
132 | width: 100%;
133 | th {
134 | text-align: left;
135 | padding: 6px;
136 | border: 1px solid rgba(92, 102, 94, 0.06);
137 | width: 15%;
138 | &:last-child {
139 | width: 40%;
140 | }
141 | }
142 | td {
143 | text-align: left;
144 | padding: 6px;
145 | border: 1px solid rgba(92, 102, 94, 0.06);
146 | width: 15%;
147 | &:last-child {
148 | width: 40%;
149 | }
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/app/apidoc/index/index.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit} from '@angular/core';
2 | import {ROOT_URL, TYPE} from '../../config';
3 | import {HttpService} from '../../http-service.service';
4 | import {NzMessageService} from 'ng-zorro-antd';
5 |
6 | /**
7 | * 首先声明:该前端代码用了最新的angular版本,语法是最新的
8 | * 但是: 细节处理和算法上非常粗糙,哈哈哈,时间有限,公司急着用,先实现再说吧,后期优化
9 | * 如果你看到某个算法,觉得傻逼,没事,本来应该写一天的功能,我20分钟就实现了,理解下下。 /偷笑 :)
10 | *
11 | */
12 | @Component({
13 | selector: 'app-index',
14 | templateUrl: './index.component.html',
15 | styleUrls: ['./index.component.scss']
16 | })
17 | export class IndexComponent implements OnInit {
18 |
19 | URL = ROOT_URL + "/";
20 | isVisible = false;//加载中弹窗是否显示
21 | show = false;//显示文档
22 |
23 | apiInfo: any; // 文档基本信息
24 | apiModules: any; // 功能模块信息列表
25 | apiModule: any; // 某个功能模块信息
26 | paramType;//请求参数类型
27 |
28 | //示例功能--------构建的数据
29 | method: any; // 请求方法
30 | mapingUrl: string; // 接口地址
31 | apiUrl: string; //请求地址
32 | showRequestParams = true;//是否显示请求参数
33 |
34 | buildeReqParams; //构建的请求参数
35 | buildRespParams; //构建的响应数据
36 |
37 | //演示功能-------请求得到的数据
38 | demoReqParams;//请求参数
39 | demoUrl;//请求url
40 | demoRespParams: any;//请求后得到的数据
41 | showDemoRespParams = false;//是否显示响应数据
42 | ERROR_MSG = '发送错误或异常:造成错误的原因可能是 请求地址错误,服务器无响应或JavaScript跨域错误,具体如下:';
43 | file;
44 | showBlob = false;//是否显示数据流
45 | blobUrl;
46 |
47 |
48 | //上传文件
49 |
50 |
51 | constructor(private http: HttpService,
52 | private messageService: NzMessageService) {
53 | this.URL = ROOT_URL + "/";
54 | }
55 |
56 | ngOnInit() {
57 | scroll(0, 0);
58 | this.getData();
59 | }
60 |
61 | getData() {
62 | this.isVisible = true;
63 | this.http.get(this.URL + '/apidoc/api/' + TYPE).subscribe(
64 | data => {
65 | this.isVisible = false;
66 | if (data && data["info"]) {
67 | this.apiInfo = data['info'];
68 | this.apiModules = data['models'];
69 | } else {
70 | this.show = true;
71 | }
72 | },
73 | error => {
74 | console.error(error);
75 | this.isVisible = false;
76 | this.messageService.error('初始化数据加载失败');
77 | }
78 | );
79 | }
80 |
81 | //获取功能详情
82 | getApiDetail(rootMapping, moduleItem) {
83 | //清空缓存
84 | this.clearCache();
85 | console.log(this.URL + '/apidoc/detail?methodUUID=' + moduleItem.methoduuid);
86 | this.http.get(this.URL + '/apidoc/detail?methodUUID=' + moduleItem.methoduuid).subscribe(
87 | data => {
88 | this.isVisible = false;
89 | this.showApiDetail(rootMapping, data);
90 | },
91 | error => {
92 | this.isVisible = false;
93 | console.error(error);
94 | this.messageService.error('获取功能详情失败');
95 | }
96 | );
97 |
98 | }
99 |
100 | /**
101 | * 清空缓存
102 | */
103 | private clearCache() {
104 | this.isVisible = true;
105 | this.method = null;
106 | this.mapingUrl = "/";
107 | this.apiUrl = null;
108 | this.showRequestParams = true;
109 | this.buildeReqParams = null;
110 | this.buildRespParams = null;
111 | this.demoReqParams = null;
112 | this.demoUrl = null;
113 | this.demoRespParams = null;
114 | this.showDemoRespParams = null;
115 | this.paramType = null;
116 | this.showBlob = false;
117 | }
118 |
119 | // 展示某个功能详情
120 | showApiDetail(rootMapping, module) {
121 | console.log(JSON.stringify(module));
122 | //默认描述为 功能名称
123 | if (!module.description && module.name) {
124 | module.description = module.name;
125 | }
126 | this.apiModule = module;
127 | if (!this.apiModule.reqParams) {
128 | this.apiModule.reqParams = {type: 'url'};//默认为url
129 | }
130 | if (this.apiModule.reqParams.type === 'url' ||
131 | this.apiModule.reqParams.type === 'url_blob' ||
132 | this.apiModule.reqParams.type === 'url_param') {
133 | this.showRequestParams = false;
134 | }
135 | this.method = module.method;
136 | this.paramType = this.apiModule.reqParams.type;
137 | this.apiUrl = rootMapping + this.apiModule.mapping;
138 |
139 |
140 | //组装请求参数 和 响应参数
141 | this.buildRequestParams(module);
142 | }
143 |
144 | //构建请求参数
145 | buildRequestParams(module) {
146 | const type = module.reqParams.type;//请求类型
147 | if (!module.reqParams || !module.respParams) {
148 | return;
149 | }
150 | const reqparams = module.reqParams.params;//请求参数
151 | const respparams = module.respParams.params;//请求参数
152 |
153 | //判断请求类型
154 | if (type === 'url') {
155 | if (this.apiModule && this.apiModule.reqParams && this.apiModule.reqParams.params &&
156 | this.apiModule.reqParams.params.length > 0) {
157 | //拼接参数 以/隔开
158 | let url = this.apiUrl;
159 | for (const param of this.apiModule.reqParams.params) {
160 | // console.log(url);
161 | param.description = param.description ? param.description : '参数';
162 | url = url + "/" + param.description;
163 | }
164 | this.mapingUrl = url;
165 | } else {
166 | this.mapingUrl = this.apiUrl;
167 | }
168 | } else if (type === 'url_param') {
169 | if (this.apiModule && this.apiModule.reqParams && this.apiModule.reqParams.params &&
170 | this.apiModule.reqParams.params.length > 0) {
171 | //拼接参数 以?隔开
172 | let url = this.apiUrl;
173 | let i = 0;
174 | for (const param of this.apiModule.reqParams.params) {
175 | i++;
176 | console.log(url);
177 | param.description = param.description ? param.description : '参数';
178 | if (i === 1) {
179 | url = url + "?" + param.name + "=" + param.description;
180 | } else {
181 | url = url + "&" + param.name + "=" + param.description;
182 | }
183 | }
184 | this.mapingUrl = url;
185 | } else {
186 | this.mapingUrl = this.apiUrl;
187 | }
188 | } else if (type === 'json') {
189 | this.mapingUrl = this.apiUrl;
190 | } else if (type === 'url_blob') {
191 | this.showBlob = true;
192 | this.mapingUrl = this.apiUrl;
193 | this.blobUrl = this.URL + JSON.parse(JSON.stringify(this.mapingUrl));//得到一个拷贝
194 | } else {
195 | this.mapingUrl = this.apiUrl;
196 | }
197 | this.buildeReqParams = this.fromtJSON(this.bulidParams(reqparams, {}));
198 | this.buildRespParams = this.fromtJSON(this.bulidParams(respparams, {}));
199 |
200 | this.demoReqParams = JSON.parse(JSON.stringify(this.buildeReqParams));//得到一个拷贝,给演示功能用 目的:隔断双向绑定
201 | this.demoUrl = this.URL + JSON.parse(JSON.stringify(this.mapingUrl));//得到一个拷贝
202 | if (type === 'form') {
203 | console.log(Object.keys(JSON.parse(this.demoReqParams)));
204 | this.file = Object.keys(JSON.parse(this.demoReqParams))[0];
205 | }
206 | }
207 |
208 | //构建参数
209 | private bulidParams(params, result): any {
210 | if (params) {
211 | for (const value of params) {
212 | if (value.list && value.list.length > 0) {
213 |
214 | //把list递归
215 | if (value.dataType === "object") {//对象
216 | result[value.name] = {};
217 | this.bulidParams(value.list, result[value.name]);
218 | } else if (value.dataType === "array") {//数组
219 | result[value.name] = [{}];
220 | this.bulidParams(value.list, result[value.name][0]);
221 | }
222 |
223 | } else {
224 | //构建拼接参数
225 | if (value.dataType === "array") {
226 | result[value.name] = [];
227 | } else {
228 | //生成模拟数据
229 | let mock: any = "";
230 | if (value.defaultValue) {
231 | mock = value.defaultValue;
232 | } else {
233 | if (value.dataType === "number") {
234 | mock = 0;
235 | }
236 | }
237 | result[value.name] = mock;//赋值为描述
238 | }
239 | }
240 | }
241 | }
242 | return result;
243 | }
244 |
245 |
246 | //发送测试方法
247 | sendTest() {
248 | console.log('请求方式', this.method);
249 | console.log('请求地址', this.demoUrl);
250 | //刷新图片验证码
251 | if (this.showBlob) {
252 | // this.blobUrl = this.blobUrl.substring(0, this.blobUrl.indexOf("?")) + "?" + new Date();
253 | this.blobUrl = this.blobUrl + "?" + new Date();
254 | console.log(this.blobUrl);
255 | }
256 |
257 | switch (this.method) {
258 | case 'get':
259 | this.http.get(this.demoUrl).subscribe(data => this.success(data), error => this.error(error));
260 | break;
261 | case 'post':
262 | this.http.post(this.demoUrl, JSON.parse(this.demoReqParams)).subscribe(data => this.success(data), error => this.error(error));
263 | break;
264 | case 'put':
265 | this.http.put(this.demoUrl, JSON.parse(this.demoReqParams)).subscribe(data => this.success(data), error => this.error(error));
266 | break;
267 | case 'delete':
268 | this.http.delete(this.demoUrl).subscribe(data => this.success(data), error => this.error(error));
269 | break;
270 | }
271 |
272 | }
273 |
274 | /**
275 | * 请求成功调用方法
276 | * @param data 响应数据
277 | */
278 | private success(data) {
279 | //登陆后保存token
280 | if (data && data.data && data.data.token) {
281 | console.log("设置token", data.data.token);
282 | localStorage.setItem("token", data.data.token);
283 | }
284 | this.showDemoRespParams = true;
285 | console.log(data);
286 | this.demoRespParams = this.fromtJSON(data);
287 | }
288 |
289 | /**
290 | * 请求失败调用方法
291 | * @param error
292 | */
293 | private error(error) {
294 | this.showDemoRespParams = true;
295 | console.error(error);
296 | let msg = "";
297 | if (error.status) {
298 | msg = msg + "状态码:" + error.status + "\n";
299 | }
300 | if (error.url) {
301 | msg = msg + "请求路径:" + error.url + "\n";
302 | }
303 | if (error.message) {
304 | msg = msg + "提示信息:" + error.message + "\n";
305 | }
306 | this.demoRespParams = msg + "\n\n" + this.ERROR_MSG + "\n\n" + this.fromtJSON(error);
307 | }
308 |
309 | //格式化json数据
310 | private fromtJSON(json): any {
311 | return JSON.stringify(json, null, 2);
312 | }
313 |
314 | //上传文件
315 | sendfile($event) {
316 | this.http.upload(this.apiUrl, $event, this.file).subscribe(data => this.success(data), error => this.error(error));
317 |
318 | }
319 |
320 | }
321 |
--------------------------------------------------------------------------------
/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvs6/api-doc-angular/cba225aa021d4a0881e72f0ef24d65944ee2aa86/src/app/app.component.css
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | }
10 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import {BrowserModule} from '@angular/platform-browser';
2 | import {NgModule} from '@angular/core';
3 |
4 | import {AppComponent} from './app.component';
5 | import {HttpService} from "./http-service.service";
6 | import {InterfaceModule} from './apidoc/apidoc.module';
7 | import {HTTP_INTERCEPTORS} from "@angular/common/http";
8 | import {AuthInterceptor} from "./auto-intercepter";
9 |
10 | @NgModule({
11 | declarations: [
12 | AppComponent
13 | ],
14 | imports: [
15 | BrowserModule,
16 | InterfaceModule
17 | ],
18 | providers: [
19 | HttpService,
20 | {
21 | provide: HTTP_INTERCEPTORS,
22 | useClass: AuthInterceptor,
23 | multi: true,
24 | },
25 | ],
26 | bootstrap: [AppComponent]
27 | })
28 | export class AppModule {
29 | }
30 |
--------------------------------------------------------------------------------
/src/app/auto-intercepter.ts:
--------------------------------------------------------------------------------
1 | import {Injectable} from '@angular/core';
2 | import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
3 | import {Observable} from 'rxjs/Observable';
4 | import 'rxjs/add/operator/do';
5 |
6 | /**
7 | * @description 拦截器,拦截所有http请求
8 | * 目前实现功能:
9 | * 1.请求的header中增加token
10 | */
11 | @Injectable()
12 | export class AuthInterceptor implements HttpInterceptor {
13 |
14 | //如果需要注入service,使用这种方式,打开注释代码即可
15 | // private httpService: HttpService;
16 | //
17 | // constructor(private injector: Injector) {
18 | // }
19 |
20 | intercept(request: HttpRequest, next: HttpHandler): Observable> {
21 | const token = localStorage.getItem('token');
22 | console.log("走了", token);
23 | if (token) {
24 | const authReq = request.clone({headers: request.headers.set('token', token)});
25 | return next.handle(authReq);
26 | } else {
27 | return next.handle(request);
28 | }
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/src/app/config.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | * 定义网站url根路由
5 | * @type {string}
6 | */
7 | export const ROOT_URL = getUrl();
8 |
9 |
10 | /**
11 | * 获取查询参数,用以区别不同的文档
12 | * @type {string}
13 | */
14 | export const TYPE = getType();
15 |
16 | //获取网站url根路径
17 | function getUrl() {
18 | return window.location.protocol + "//" + window.location.host;//例:http://localhost:4200
19 | }
20 |
21 | //获取查询参数
22 | function getType() {
23 | //获取查询参数
24 | let search = window.location.search;//例: ?type=admin
25 | search = search.substr(search.indexOf("=")+1,search.length);
26 | return search;
27 | }
28 |
--------------------------------------------------------------------------------
/src/app/http-service.service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable} from '@angular/core';
2 | import {HttpClient} from '@angular/common/http';
3 | import 'rxjs/add/operator/retry';
4 | import {ROOT_URL} from './config';
5 | import {Observable} from 'rxjs/Observable';
6 |
7 | /**
8 | * @description 定义全局接口,封装http服务
9 | * 封装angular原生HttpClient类
10 | * @date 2017-9-15
11 | * @author admin
12 | */
13 | @Injectable()
14 | export class HttpService {
15 |
16 | private rootUrl: string = ROOT_URL;
17 |
18 | // 注入httpClient
19 | constructor(private httpClient: HttpClient) {
20 | }
21 |
22 |
23 | /**
24 | * get请求
25 | * @param {string} url
26 | * @return {Observable