fork from bc4552c5a8
This commit is contained in:
23
exts/yapi-plugin-statistics/client.js
Normal file
23
exts/yapi-plugin-statistics/client.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Created by gxl.gao on 2017/10/24.
|
||||
*/
|
||||
import StatisticsPage from './statisticsClientPage/index'
|
||||
|
||||
module.exports = function () {
|
||||
this.bindHook('header_menu', function (menu) {
|
||||
menu.statisticsPage = {
|
||||
path: '/statistic',
|
||||
name: '系统信息',
|
||||
icon: 'bar-chart',
|
||||
adminFlag: true
|
||||
}
|
||||
})
|
||||
this.bindHook('app_route', function (app) {
|
||||
app.statisticsPage = {
|
||||
path: '/statistic',
|
||||
component: StatisticsPage
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
176
exts/yapi-plugin-statistics/controller.js
Normal file
176
exts/yapi-plugin-statistics/controller.js
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Created by gxl.gao on 2017/10/24.
|
||||
*/
|
||||
const baseController = require('controllers/base.js');
|
||||
const statisMockModel = require('./statisMockModel.js');
|
||||
const groupModel = require('models/group.js');
|
||||
const projectModel = require('models/project.js');
|
||||
const interfaceModel = require('models/interface.js');
|
||||
const interfaceCaseModel = require('models/interfaceCase.js');
|
||||
|
||||
const yapi = require('yapi.js');
|
||||
const config = require('./index.js');
|
||||
const commons = require('./util.js');
|
||||
const os = require('os');
|
||||
let cpu = require('cpu-load');
|
||||
|
||||
class statisMockController extends baseController {
|
||||
constructor(ctx) {
|
||||
super(ctx);
|
||||
this.Model = yapi.getInst(statisMockModel);
|
||||
this.groupModel = yapi.getInst(groupModel);
|
||||
this.projectModel = yapi.getInst(projectModel);
|
||||
this.interfaceModel = yapi.getInst(interfaceModel);
|
||||
this.interfaceCaseModel = yapi.getInst(interfaceCaseModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有统计总数
|
||||
* @interface statismock/count
|
||||
* @method get
|
||||
* @category statistics
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
*/
|
||||
async getStatisCount(ctx) {
|
||||
try {
|
||||
let groupCount = await this.groupModel.getGroupListCount();
|
||||
let projectCount = await this.projectModel.getProjectListCount();
|
||||
let interfaceCount = await this.interfaceModel.getInterfaceListCount();
|
||||
let interfaceCaseCount = await this.interfaceCaseModel.getInterfaceCaseListCount();
|
||||
|
||||
return (ctx.body = yapi.commons.resReturn({
|
||||
groupCount,
|
||||
projectCount,
|
||||
interfaceCount,
|
||||
interfaceCaseCount
|
||||
}));
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 400, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有mock接口数据信息
|
||||
* @interface statismock/get
|
||||
* @method get
|
||||
* @category statistics
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
*/
|
||||
async getMockDateList(ctx) {
|
||||
try {
|
||||
let mockCount = await this.Model.getTotalCount();
|
||||
let mockDateList = [];
|
||||
|
||||
if (!this.getRole() === 'admin') {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限'));
|
||||
}
|
||||
// 默认时间是30 天为一周期
|
||||
let dateInterval = commons.getDateRange();
|
||||
mockDateList = await this.Model.getDayCount(dateInterval);
|
||||
return (ctx.body = yapi.commons.resReturn({ mockCount, mockDateList }));
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 400, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮箱状态信息
|
||||
* @interface statismock/getSystemStatus
|
||||
* @method get
|
||||
* @category statistics
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
*/
|
||||
async getSystemStatus(ctx) {
|
||||
try {
|
||||
let mail = '';
|
||||
if (yapi.WEBCONFIG.mail && yapi.WEBCONFIG.mail.enable) {
|
||||
mail = await this.checkEmail();
|
||||
// return ctx.body = yapi.commons.resReturn(result);
|
||||
} else {
|
||||
mail = '未配置';
|
||||
}
|
||||
|
||||
let load = (await this.cupLoad()) * 100;
|
||||
|
||||
let systemName = os.platform();
|
||||
let totalmem = commons.transformBytesToGB(os.totalmem());
|
||||
let freemem = commons.transformBytesToGB(os.freemem());
|
||||
let uptime = commons.transformSecondsToDay(os.uptime());
|
||||
|
||||
let data = {
|
||||
mail,
|
||||
systemName,
|
||||
totalmem,
|
||||
freemem,
|
||||
uptime,
|
||||
load: load.toFixed(2)
|
||||
};
|
||||
return (ctx.body = yapi.commons.resReturn(data));
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 400, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
checkEmail() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let result = {};
|
||||
yapi.mail.verify(error => {
|
||||
if (error) {
|
||||
result = '不可用';
|
||||
resolve(result);
|
||||
} else {
|
||||
result = '可用';
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async groupDataStatis(ctx) {
|
||||
try {
|
||||
let groupData = await this.groupModel.list();
|
||||
let result = [];
|
||||
for (let i = 0; i < groupData.length; i++) {
|
||||
let group = groupData[i];
|
||||
let groupId = group._id;
|
||||
const data = {
|
||||
name: group.group_name,
|
||||
interface: 0,
|
||||
mock: 0,
|
||||
project: 0
|
||||
};
|
||||
result.push(data);
|
||||
|
||||
let projectCount = await this.projectModel.listCount(groupId);
|
||||
let projectData = await this.projectModel.list(groupId);
|
||||
let interfaceCount = 0;
|
||||
for (let j = 0; j < projectData.length; j++) {
|
||||
let project = projectData[j];
|
||||
interfaceCount += await this.interfaceModel.listCount({
|
||||
project_id: project._id
|
||||
});
|
||||
}
|
||||
let mockCount = await this.Model.countByGroupId(groupId);
|
||||
data.interface = interfaceCount;
|
||||
data.project = projectCount;
|
||||
data.mock = mockCount;
|
||||
}
|
||||
return (ctx.body = yapi.commons.resReturn(result));
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 400, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
cupLoad() {
|
||||
return new Promise((resolve, reject) => {
|
||||
cpu(1000, function(load) {
|
||||
resolve(load);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = statisMockController;
|
||||
10
exts/yapi-plugin-statistics/index.js
Normal file
10
exts/yapi-plugin-statistics/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Created by gxl.gao on 2017/10/24.
|
||||
*/
|
||||
module.exports = {
|
||||
server: true,
|
||||
client: true,
|
||||
httpCodes: [
|
||||
100,101,102,200,201,202,203,204,205,206,207,208,226,300,301,302,303,304,305,307,308,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,422,423,424,426,428,429,431,500,501,502,503,504,505,506,507,508,510,511
|
||||
]
|
||||
}
|
||||
82
exts/yapi-plugin-statistics/server.js
Normal file
82
exts/yapi-plugin-statistics/server.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Created by gxl.gao on 2017/10/24.
|
||||
*/
|
||||
const yapi = require('yapi.js');
|
||||
const mongoose = require('mongoose');
|
||||
const controller = require('./controller');
|
||||
const statisModel = require('./statisMockModel.js');
|
||||
const commons = require('./util.js');
|
||||
|
||||
module.exports = function() {
|
||||
yapi.connect.then(function() {
|
||||
let Col = mongoose.connection.db.collection('statis_mock');
|
||||
Col.createIndex({
|
||||
interface_id: 1
|
||||
});
|
||||
Col.createIndex({
|
||||
project_id: 1
|
||||
});
|
||||
Col.createIndex({
|
||||
group_id: 1
|
||||
});
|
||||
Col.createIndex({
|
||||
time: 1
|
||||
});
|
||||
Col.createIndex({
|
||||
date: 1
|
||||
});
|
||||
});
|
||||
|
||||
this.bindHook('add_router', function(addRouter) {
|
||||
addRouter({
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'statismock/count',
|
||||
action: 'getStatisCount'
|
||||
});
|
||||
|
||||
addRouter({
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'statismock/get',
|
||||
action: 'getMockDateList'
|
||||
});
|
||||
addRouter({
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'statismock/get_system_status',
|
||||
action: 'getSystemStatus'
|
||||
});
|
||||
addRouter({
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'statismock/group_data_statis',
|
||||
action: 'groupDataStatis'
|
||||
});
|
||||
});
|
||||
|
||||
// MockServer生成mock数据后触发
|
||||
this.bindHook('mock_after', function(context) {
|
||||
let interfaceId = context.interfaceData._id;
|
||||
let projectId = context.projectData._id;
|
||||
let groupId = context.projectData.group_id;
|
||||
//let ip = context.ctx.originalUrl;
|
||||
let ip = yapi.commons.getIp(context.ctx);
|
||||
|
||||
let data = {
|
||||
interface_id: interfaceId,
|
||||
project_id: projectId,
|
||||
group_id: groupId,
|
||||
time: yapi.commons.time(),
|
||||
ip: ip,
|
||||
date: commons.formatYMD(new Date())
|
||||
};
|
||||
let inst = yapi.getInst(statisModel);
|
||||
|
||||
try {
|
||||
inst.save(data).then();
|
||||
} catch (e) {
|
||||
yapi.commons.log('mockStatisError', e);
|
||||
}
|
||||
});
|
||||
};
|
||||
75
exts/yapi-plugin-statistics/statisMockModel.js
Normal file
75
exts/yapi-plugin-statistics/statisMockModel.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Created by gxl.gao on 2017/10/24.
|
||||
*/
|
||||
const yapi = require('yapi.js');
|
||||
const baseModel = require('models/base.js');
|
||||
|
||||
class statisMockModel extends baseModel {
|
||||
getName() {
|
||||
return 'statis_mock';
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
return {
|
||||
interface_id: { type: Number, required: true },
|
||||
project_id: { type: Number, required: true },
|
||||
group_id: { type: Number, required: true },
|
||||
time: Number, //'时间戳'
|
||||
ip: String,
|
||||
date: String
|
||||
};
|
||||
}
|
||||
|
||||
countByGroupId(id){
|
||||
return this.model.countDocuments({
|
||||
group_id: id
|
||||
})
|
||||
}
|
||||
|
||||
save(data) {
|
||||
let m = new this.model(data);
|
||||
return m.save();
|
||||
}
|
||||
|
||||
getTotalCount() {
|
||||
return this.model.countDocuments({});
|
||||
}
|
||||
|
||||
async getDayCount(timeInterval) {
|
||||
let end = timeInterval[1];
|
||||
let start = timeInterval[0];
|
||||
let data = [];
|
||||
const cursor = this.model.aggregate([
|
||||
{
|
||||
$match: {
|
||||
date: { $gt: start, $lte: end }
|
||||
}
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: '$date', //$region is the column name in collection
|
||||
count: { $sum: 1 }
|
||||
}
|
||||
},
|
||||
{
|
||||
$sort: { _id: 1 }
|
||||
}
|
||||
]).cursor({}).exec();
|
||||
await cursor.eachAsync(doc => data.push(doc));
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
list() {
|
||||
return this.model.find({}).select('date').exec();
|
||||
}
|
||||
|
||||
up(id, data) {
|
||||
data.up_time = yapi.commons.time();
|
||||
return this.model.updateOne({
|
||||
_id: id
|
||||
}, data, { runValidators: true });
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = statisMockModel;
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Created by gxl.gao on 2017/10/25.
|
||||
*/
|
||||
import React, { Component } from 'react';
|
||||
// import PropTypes from 'prop-types'
|
||||
import axios from 'axios';
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts';
|
||||
import { Spin } from 'antd';
|
||||
class StatisChart extends Component {
|
||||
static propTypes = {};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showLoading: true,
|
||||
chartDate: {
|
||||
mockCount: 0,
|
||||
mockDateList: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getMockData();
|
||||
}
|
||||
|
||||
// 获取mock 请求次数信息
|
||||
async getMockData() {
|
||||
let result = await axios.get('/api/plugin/statismock/get');
|
||||
if (result.data.errcode === 0) {
|
||||
let mockStatisData = result.data.data;
|
||||
this.setState({
|
||||
showLoading: false,
|
||||
chartDate: { ...mockStatisData }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const width = 1050;
|
||||
const { mockCount, mockDateList } = this.state.chartDate;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Spin spinning={this.state.showLoading}>
|
||||
<div className="statis-chart-content">
|
||||
<h3 className="statis-title">mock 接口访问总数为:{mockCount.toLocaleString()}</h3>
|
||||
<div className="statis-chart">
|
||||
<LineChart
|
||||
width={width}
|
||||
height={300}
|
||||
data={mockDateList}
|
||||
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||
>
|
||||
<XAxis dataKey="_id" />
|
||||
<YAxis />
|
||||
<CartesianGrid strokeDasharray="7 3" />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Line
|
||||
name="mock统计值"
|
||||
type="monotone"
|
||||
dataKey="count"
|
||||
stroke="#8884d8"
|
||||
activeDot={{ r: 8 }}
|
||||
/>
|
||||
</LineChart>
|
||||
</div>
|
||||
<div className="statis-footer">过去3个月mock接口调用情况</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default StatisChart;
|
||||
@@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { Table } from 'antd';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Group',
|
||||
dataIndex: 'name',
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: '项目',
|
||||
dataIndex: 'project',
|
||||
key: 'project'
|
||||
},
|
||||
{
|
||||
title: '接口',
|
||||
dataIndex: 'interface',
|
||||
key: 'interface'
|
||||
},
|
||||
{
|
||||
title: 'mock数据',
|
||||
dataIndex: 'mock',
|
||||
key: 'mock'
|
||||
}
|
||||
];
|
||||
|
||||
const StatisTable = props => {
|
||||
const { dataSource } = props;
|
||||
return (
|
||||
<div className="m-row-table">
|
||||
<h3 className="statis-title">分组数据详情</h3>
|
||||
<Table
|
||||
className="statis-table"
|
||||
pagination={false}
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
StatisTable.propTypes = {
|
||||
dataSource: PropTypes.array
|
||||
};
|
||||
|
||||
export default StatisTable;
|
||||
210
exts/yapi-plugin-statistics/statisticsClientPage/index.js
Normal file
210
exts/yapi-plugin-statistics/statisticsClientPage/index.js
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Created by gxl.gao on 2017/10/25.
|
||||
*/
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import axios from 'axios';
|
||||
import PropTypes from 'prop-types';
|
||||
import './index.scss';
|
||||
// import { withRouter } from 'react-router-dom';
|
||||
import { Row, Col, Tooltip, Icon } from 'antd';
|
||||
import { setBreadcrumb } from 'client/reducer/modules/user';
|
||||
import StatisChart from './StatisChart';
|
||||
import StatisTable from './StatisTable';
|
||||
|
||||
const CountOverview = props => (
|
||||
<Row type="flex" justify="space-start" className="m-row">
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
分组总数
|
||||
<Tooltip placement="rightTop" title="统计yapi中一共开启了多少可见的公共分组">
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">{props.date.groupCount}</h2>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
项目总数
|
||||
<Tooltip placement="rightTop" title="统计yapi中建立的所有项目总数">
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">{props.date.projectCount}</h2>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
接口总数
|
||||
<Tooltip placement="rightTop" title="统计yapi所有项目中的所有接口总数">
|
||||
{/*<a href="javascript:void(0)" className="m-a-help">?</a>*/}
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">{props.date.interfaceCount}</h2>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
测试接口总数
|
||||
<Tooltip placement="rightTop" title="统计yapi所有项目中的所有测试接口总数">
|
||||
{/*<a href="javascript:void(0)" className="m-a-help">?</a>*/}
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">{props.date.interfaceCaseCount}</h2>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
|
||||
CountOverview.propTypes = {
|
||||
date: PropTypes.object
|
||||
};
|
||||
|
||||
const StatusOverview = props => (
|
||||
<Row type="flex" justify="space-start" className="m-row">
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
操作系统类型
|
||||
<Tooltip
|
||||
placement="rightTop"
|
||||
title="操作系统类型,返回值有'darwin', 'freebsd', 'linux', 'sunos' , 'win32'"
|
||||
>
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">{props.data.systemName}</h2>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
cpu负载
|
||||
<Tooltip placement="rightTop" title="cpu的总负载情况">
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">{props.data.load} %</h2>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
系统空闲内存总量 / 内存总量
|
||||
<Tooltip placement="rightTop" title="系统空闲内存总量 / 内存总量">
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">
|
||||
{props.data.freemem} G / {props.data.totalmem} G{' '}
|
||||
</h2>
|
||||
</Col>
|
||||
<Col className="gutter-row" span={6}>
|
||||
<span>
|
||||
邮箱状态
|
||||
<Tooltip placement="rightTop" title="检测配置文件中配置邮箱的状态">
|
||||
<Icon className="m-help" type="question-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<h2 className="gutter-box">{props.data.mail}</h2>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
|
||||
StatusOverview.propTypes = {
|
||||
data: PropTypes.object
|
||||
};
|
||||
|
||||
@connect(
|
||||
null,
|
||||
{
|
||||
setBreadcrumb
|
||||
}
|
||||
)
|
||||
class statisticsPage extends Component {
|
||||
static propTypes = {
|
||||
setBreadcrumb: PropTypes.func
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
count: {
|
||||
groupCount: 0,
|
||||
projectCount: 0,
|
||||
interfaceCount: 0,
|
||||
interfactCaseCount: 0
|
||||
},
|
||||
status: {
|
||||
mail: '',
|
||||
systemName: '',
|
||||
totalmem: '',
|
||||
freemem: '',
|
||||
uptime: ''
|
||||
},
|
||||
dataTotal: []
|
||||
};
|
||||
}
|
||||
|
||||
async UNSAFE_componentWillMount() {
|
||||
this.props.setBreadcrumb([{ name: '系统信息' }]);
|
||||
this.getStatisData();
|
||||
this.getSystemStatusData();
|
||||
this.getGroupData();
|
||||
}
|
||||
|
||||
// 获取统计数据
|
||||
async getStatisData() {
|
||||
let result = await axios.get('/api/plugin/statismock/count');
|
||||
if (result.data.errcode === 0) {
|
||||
let statisData = result.data.data;
|
||||
this.setState({
|
||||
count: { ...statisData }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 获取系统信息
|
||||
|
||||
async getSystemStatusData() {
|
||||
let result = await axios.get('/api/plugin/statismock/get_system_status');
|
||||
if (result.data.errcode === 0) {
|
||||
let statusData = result.data.data;
|
||||
this.setState({
|
||||
status: { ...statusData }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 获取分组详细信息
|
||||
|
||||
async getGroupData() {
|
||||
let result = await axios.get('/api/plugin/statismock/group_data_statis');
|
||||
if (result.data.errcode === 0) {
|
||||
let statusData = result.data.data;
|
||||
statusData.map(item => {
|
||||
return (item['key'] = item.name);
|
||||
});
|
||||
this.setState({
|
||||
dataTotal: statusData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { count, status, dataTotal } = this.state;
|
||||
|
||||
return (
|
||||
<div className="g-statistic">
|
||||
<div className="content">
|
||||
<h2 className="title">系统状况</h2>
|
||||
<div className="system-content">
|
||||
<StatusOverview data={status} />
|
||||
</div>
|
||||
<h2 className="title">数据统计</h2>
|
||||
<div>
|
||||
<CountOverview date={count} />
|
||||
<StatisTable dataSource={dataTotal} />
|
||||
<StatisChart />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default statisticsPage;
|
||||
83
exts/yapi-plugin-statistics/statisticsClientPage/index.scss
Normal file
83
exts/yapi-plugin-statistics/statisticsClientPage/index.scss
Normal file
@@ -0,0 +1,83 @@
|
||||
@import '../../../client/styles/mixin';
|
||||
|
||||
.g-statistic {
|
||||
@include row-width-limit;
|
||||
margin: 0 auto .24rem;
|
||||
margin-top: 24px;
|
||||
min-width: 11.2rem;
|
||||
|
||||
|
||||
.content {
|
||||
-webkit-box-flex: 1;
|
||||
padding: 24px;
|
||||
width:100%;
|
||||
background: #fff;
|
||||
min-height: 5rem;
|
||||
// overflow-x: scroll;
|
||||
}
|
||||
.m-row {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.m-row-table {
|
||||
padding-top: 16px
|
||||
|
||||
}
|
||||
|
||||
.statis-table {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.m-help {
|
||||
margin-left: 5px;
|
||||
border-radius: 12px;
|
||||
color: #2395f1;
|
||||
}
|
||||
|
||||
.gutter-row {
|
||||
padding-left: 24px;
|
||||
border-left: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.gutter-row:first-child {
|
||||
border-left: 0
|
||||
}
|
||||
|
||||
.gutter-box {
|
||||
margin-top: 8px;
|
||||
//margin-bottom: 16px;
|
||||
//margin: 8px 0 16px;
|
||||
}
|
||||
|
||||
.statis-chart-content {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.statis-title{
|
||||
padding: 8px 8px 24px;
|
||||
}
|
||||
|
||||
.statis-chart{
|
||||
margin:0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.statis-footer{
|
||||
margin:16px 0;
|
||||
text-align: center;
|
||||
width: 1050px;
|
||||
}
|
||||
|
||||
.title{
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
margin-bottom: 0.16rem;
|
||||
border-left: 3px solid #2395f1;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.system-content{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
56
exts/yapi-plugin-statistics/test.js
Normal file
56
exts/yapi-plugin-statistics/test.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const fs = require('fs-extra');
|
||||
const yapi = require('../../server/yapi.js');
|
||||
const commons = require('../../server/utils/commons');
|
||||
const dbModule = require('../../server/utils/db.js');
|
||||
const userModel = require('../../server/models/user.js');
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
yapi.commons = commons;
|
||||
yapi.connect = dbModule.connect();
|
||||
|
||||
const convert2Decimal = num => (num > 9 ? num : `0${num}`);
|
||||
const formatYMD = (val, joinStr = '-') => {
|
||||
let date = val;
|
||||
if (typeof val !== 'object') {
|
||||
val = val * 1000;
|
||||
date = new Date(val);
|
||||
}
|
||||
return `${[
|
||||
date.getFullYear(),
|
||||
convert2Decimal(date.getMonth() + 1),
|
||||
convert2Decimal(date.getDate())
|
||||
].join(joinStr)}`;
|
||||
};
|
||||
|
||||
function run() {
|
||||
let time = yapi.commons.time() - 10000000;
|
||||
let data = i => {
|
||||
time = time - yapi.commons.rand(10000, 1000000);
|
||||
return {
|
||||
interface_id: 94,
|
||||
project_id: 25,
|
||||
group_id: 19,
|
||||
time: time,
|
||||
ip: '1.1.1.1',
|
||||
date: formatYMD(time)
|
||||
};
|
||||
};
|
||||
|
||||
yapi.connect
|
||||
.then(function() {
|
||||
let logCol = mongoose.connection.db.collection('statis_mock');
|
||||
let arr = [];
|
||||
for (let i = 0; i < 11; i++) {
|
||||
if (arr.length >= 5) {
|
||||
logCol.insert(arr);
|
||||
arr = [];
|
||||
}
|
||||
arr.push(data(i));
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
throw new Error(err.message);
|
||||
});
|
||||
}
|
||||
|
||||
run();
|
||||
150
exts/yapi-plugin-statistics/util.js
Normal file
150
exts/yapi-plugin-statistics/util.js
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 获取所需要的日期区间点
|
||||
* @param time {Number} Number是ele日期区间选择组件返回的结果
|
||||
* Number是之前时刻距离今天的间隔天数,默认是90天
|
||||
* @param start {String} 日期对象,日期区间的开始点 '2017-01-17 00:00:00'
|
||||
* @param withToday {Boolean} 是否包含今天
|
||||
* @return {Array} ['2017-01-17 00:00:00', '2017-01-20 23:59:59']
|
||||
*/
|
||||
exports.getDateRange = (time = 90, start = false, withToday = true) => {
|
||||
const gapTime = time * 24 * 3600 * 1000;
|
||||
if (!start) {
|
||||
// 没有规定start时间
|
||||
let endTime = getNowMidnightDate().getTime();
|
||||
if (!withToday) {
|
||||
endTime -= 86400000;
|
||||
}
|
||||
return [this.formatYMD(endTime - gapTime), this.formatYMD(endTime - 1000)];
|
||||
}
|
||||
const startTime = dateSpacialWithSafari(start);
|
||||
const endTime = startTime + (gapTime - 1000);
|
||||
return [start, this.formatYMD(endTime)];
|
||||
}
|
||||
|
||||
// 时间
|
||||
const convert2Decimal = num => (num > 9 ? num : `0${num}`)
|
||||
|
||||
/**
|
||||
* 获取距今天之前多少天的所有时间
|
||||
* @param time {Number} Number是ele日期区间选择组件返回的结果
|
||||
* Number是之前时刻距离今天的间隔天数,默认是30天
|
||||
* @return {Array} ['2017-01-17', '2017-01-28', '2017-10-29',...]
|
||||
*/
|
||||
|
||||
exports.getDateInterval = (time = 30) => {
|
||||
// const gapTime = time * 24 * 3600 * 1000;
|
||||
// 今天
|
||||
let endTime = new Date().getTime();
|
||||
let timeList = []
|
||||
for (let i = 0; i < time; i++) {
|
||||
const gapTime = i * 24 * 3600 * 1000;
|
||||
const time = this.formatYMD(endTime - gapTime);
|
||||
timeList.push(time);
|
||||
}
|
||||
return timeList;
|
||||
}
|
||||
|
||||
/**获取2017-10-27 00:00:00 和 2017-10-27 23:59:59的时间戳
|
||||
* @param date {String} "2017-10-27"
|
||||
* @return {Array} [ 1509033600000, 1509119999000 ]
|
||||
*/
|
||||
|
||||
exports.getTimeInterval = (date) => {
|
||||
const startTime = (getNowMidnightDate(date).getTime()-86400000)/1000;
|
||||
const endTime =(getNowMidnightDate(date).getTime()-1000)/1000;
|
||||
return [startTime, endTime];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间午夜0点的日期对象
|
||||
*/
|
||||
const getNowMidnightDate = (time) => {
|
||||
let date;
|
||||
if (time) {
|
||||
date = new Date(time);
|
||||
} else {
|
||||
date = new Date();
|
||||
}
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化 年、月、日、时、分、秒
|
||||
* @param val {Object or String or Number} 日期对象 或是可new Date的对象或时间戳
|
||||
* @return {String} 2017-01-20 20:00:00
|
||||
*/
|
||||
const formatDate = val => {
|
||||
let date = val;
|
||||
if (typeof val !== 'object') {
|
||||
date = new Date(val);
|
||||
}
|
||||
return `${[
|
||||
date.getFullYear(),
|
||||
convert2Decimal(date.getMonth() + 1),
|
||||
convert2Decimal(date.getDate())
|
||||
].join('-')} ${[
|
||||
convert2Decimal(date.getHours()),
|
||||
convert2Decimal(date.getMinutes()),
|
||||
convert2Decimal(date.getSeconds())
|
||||
].join(':')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化年、月、日
|
||||
* @param val {Object or String or Number} 日期对象 或是可new Date的对象或时间戳
|
||||
* @return {String} 2017-01-20
|
||||
*/
|
||||
exports.formatYMD = (val, joinStr = '-') => {
|
||||
let date = val;
|
||||
if (typeof val !== 'object') {
|
||||
date = new Date(val);
|
||||
}
|
||||
return `${[
|
||||
date.getFullYear(),
|
||||
convert2Decimal(date.getMonth() + 1),
|
||||
convert2Decimal(date.getDate())
|
||||
].join(joinStr)}`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取所需的时间差值,
|
||||
* tip:new Date('2017-01-17 00:00:00')在safari下不可用,需进行替换
|
||||
* @param Array ['2017-01-17 00:00:00', '2017-01-20 23:59:59']
|
||||
* @return {Number} 3
|
||||
*/
|
||||
exports.getDayGapFromRange = dateRange => {
|
||||
const startTime = dateSpacialWithSafari(dateRange[0]);
|
||||
const endTime = dateSpacialWithSafari(dateRange[1]);
|
||||
return Math.ceil((endTime - startTime) / 86400000);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dateSpacialWithSafari 格式话safari下通用的格式
|
||||
* @param str {String} 2017-04-19T11:01:19.074+0800 or 2017-10-10 10:10:10
|
||||
* @return {number} date.getTime()
|
||||
*/
|
||||
const dateSpacialWithSafari = str => {
|
||||
if (str.indexOf('T') > -1) {
|
||||
let date;
|
||||
str.replace(/(\d{4})-(\d{2})-(\d{2})\w(\d{2}):(\d{2}):(\d{2})/, (match, p1, p2, p3, p4, p5, p6) => {
|
||||
date = new Date(p1, +p2 - 1, p3, p4, p5, p6);
|
||||
return;
|
||||
})
|
||||
return date.getTime();
|
||||
}
|
||||
return new Date(str.replace(/-/g, '/')).getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将内存单位从字节(b)变成GB
|
||||
*/
|
||||
|
||||
exports.transformBytesToGB = bytes => {
|
||||
return (bytes/1024/1024/1024).toFixed(2)
|
||||
}
|
||||
|
||||
exports.transformSecondsToDay = seconds => {
|
||||
return (seconds/3600/24).toFixed(2)
|
||||
}
|
||||
Reference in New Issue
Block a user