diff --git a/CHANGELOG.md b/CHANGELOG.md index 351ce85b..b6b11434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### v1.3.19 + +* 增加项目文档记录wiki + + ### v1.3.18 * 增加全局接口搜索功能 diff --git a/client/components/TimeLine/TimeLine.js b/client/components/TimeLine/TimeLine.js index 53081f89..4e8e1463 100644 --- a/client/components/TimeLine/TimeLine.js +++ b/client/components/TimeLine/TimeLine.js @@ -1,41 +1,41 @@ -import React, { PureComponent as Component } from 'react' -import { Timeline, Spin, Row, Col, Tag, Avatar, Button, Modal, AutoComplete } from 'antd' -import PropTypes from 'prop-types' -import { connect } from 'react-redux' +import React, { PureComponent as Component } from 'react'; +import { Timeline, Spin, Row, Col, Tag, Avatar, Button, Modal, AutoComplete } from 'antd'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; import { formatTime } from '../../common.js'; -import showDiffMsg from '../../../common/diff-view.js' +import showDiffMsg from '../../../common/diff-view.js'; import variable from '../../constants/variable'; -import { Link } from 'react-router-dom' -import { fetchNewsData, fetchMoreNews } from '../../reducer/modules/news.js' -import { fetchInterfaceList } from '../../reducer/modules/interface.js' +import { Link } from 'react-router-dom'; +import { fetchNewsData, fetchMoreNews } from '../../reducer/modules/news.js'; +import { fetchInterfaceList } from '../../reducer/modules/interface.js'; import ErrMsg from '../ErrMsg/ErrMsg.js'; -const jsondiffpatch = require('jsondiffpatch/public/build/jsondiffpatch-full.js') +const jsondiffpatch = require('jsondiffpatch/public/build/jsondiffpatch-full.js'); const formattersHtml = require('jsondiffpatch/public/build/jsondiffpatch-formatters.js').html; -import 'jsondiffpatch/public/formatters-styles/annotated.css' -import 'jsondiffpatch/public/formatters-styles/html.css' +import 'jsondiffpatch/public/formatters-styles/annotated.css'; +import 'jsondiffpatch/public/formatters-styles/html.css'; -import './TimeLine.scss' +import './TimeLine.scss'; const Option = AutoComplete.Option; -const AddDiffView = (props) => { +const AddDiffView = props => { const { title, content, className } = props; if (!content) { return null; } - return
-

{title}

-
-
-} + return ( +
+

{title}

+
+
+ ); +}; AddDiffView.propTypes = { title: PropTypes.string, content: PropTypes.string, className: PropTypes.string -} - - +}; function timeago(timestamp) { let minutes, hours, days, seconds, mouth, year; @@ -52,47 +52,45 @@ function timeago(timestamp) { mouth = 0; } if (seconds > 86400) { - days = parseInt(seconds / (86400)); + days = parseInt(seconds / 86400); } else { days = 0; } if (seconds > 3600) { - hours = parseInt(seconds / (3600)); + hours = parseInt(seconds / 3600); } else { hours = 0; } minutes = parseInt(seconds / 60); if (year > 0) { - return year + "年前"; + return year + '年前'; } else if (mouth > 0 && year <= 0) { - return mouth + "月前"; + return mouth + '月前'; } else if (days > 0 && mouth <= 0) { - return days + "天前"; + return days + '天前'; } else if (days <= 0 && hours > 0) { - return hours + "小时前"; + return hours + '小时前'; } else if (hours <= 0 && minutes > 0) { - return minutes + "分钟前"; + return minutes + '分钟前'; } else if (minutes <= 0 && seconds > 0) { if (seconds < 30) { - return "刚刚"; + return '刚刚'; } else { - return seconds + "秒前"; + return seconds + '秒前'; } - } else { - return "刚刚"; + return '刚刚'; } } // timeago(new Date().getTime() - 40); @connect( - state => { return { newsData: state.news.newsData, curpage: state.news.curpage, curUid: state.user.uid - } + }; }, { fetchNewsData: fetchNewsData, @@ -100,7 +98,6 @@ function timeago(timestamp) { fetchInterfaceList } ) - class TimeTree extends Component { static propTypes = { newsData: PropTypes.object, @@ -113,33 +110,39 @@ class TimeTree extends Component { curUid: PropTypes.number, type: PropTypes.string, fetchInterfaceList: PropTypes.func - } + }; constructor(props) { super(props); this.state = { - bidden: "", + bidden: '', loading: false, visible: false, curDiffData: {}, apiList: [] - } + }; this.curInterfaceId = ''; } - getMore() { const that = this; if (this.props.curpage <= this.props.newsData.total) { - this.setState({ loading: true }); - this.props.fetchMoreNews(this.props.typeid, this.props.type, this.props.curpage + 1, 10, this.curInterfaceId).then(function () { - that.setState({ loading: false }); - if (that.props.newsData.total === that.props.curpage) { - that.setState({ bidden: "logbidden" }) - } - }) + this.props + .fetchMoreNews( + this.props.typeid, + this.props.type, + this.props.curpage + 1, + 10, + this.curInterfaceId + ) + .then(function() { + that.setState({ loading: false }); + if (that.props.newsData.total === that.props.curpage) { + that.setState({ bidden: 'logbidden' }); + } + }); } } @@ -147,89 +150,116 @@ class TimeTree extends Component { this.setState({ visible: false }); - } + }; componentWillMount() { - this.props.fetchNewsData(this.props.typeid, this.props.type, 1, 10) + this.props.fetchNewsData(this.props.typeid, this.props.type, 1, 10); if (this.props.type === 'project') { - this.getApiList() + this.getApiList(); } } - openDiff = (data) => { + openDiff = data => { this.setState({ curDiffData: data, visible: true }); - } + }; async getApiList() { - let result = await this.props.fetchInterfaceList({project_id: this.props.typeid, limit: 'all'}); + let result = await this.props.fetchInterfaceList({ + project_id: this.props.typeid, + limit: 'all' + }); this.setState({ apiList: result.payload.data.data.list - }) + }); } - handleSelectApi = (interfaceId) => { + handleSelectApi = interfaceId => { this.curInterfaceId = interfaceId; - this.props.fetchNewsData(this.props.typeid, this.props.type, 1, 10, interfaceId) - } + this.props.fetchNewsData(this.props.typeid, this.props.type, 1, 10, interfaceId); + }; render() { let data = this.props.newsData ? this.props.newsData.list : []; const curDiffData = this.state.curDiffData; let logType = { - project: "项目", - group: "分组", - interface: "接口", - interface_col: "接口集", - user: "用户", - other: "其他" + project: '项目', + group: '分组', + interface: '接口', + interface_col: '接口集', + user: '用户', + other: '其他' }; - - - const children = this.state.apiList.map((item) => { + const children = this.state.apiList.map(item => { let methodColor = variable.METHOD_COLOR[item.method ? item.method.toLowerCase() : 'get']; - return ; + return ( + + ); }); children.unshift( - - ) + + ); + if (data && data.length) { data = data.map((item, i) => { let interfaceDiff = false; - if (item.data && typeof item.data === 'object' && item.data.interface_id) { + // 去掉了 && item.data.interface_id + if (item.data && typeof item.data === 'object') { interfaceDiff = true; - } - return (} key={i}> -
- {timeago(item.add_time)} - {/*{item.username}*/} - {logType[item.type]}动态 - {formatTime(item.add_time)} -
- -
{interfaceDiff && - - }
-
); + return ( + + + + } + key={i} + > +
+ {timeago(item.add_time)} + {/*{item.username}*/} + {logType[item.type]}动态 + {formatTime(item.add_time)} +
+ +
+ {interfaceDiff && } +
+
+ ); }); } else { - data = ""; + data = ''; } - let pending = this.props.newsData.total <= this.props.curpage ? 以上为全部内容 : 查看更多; + let pending = + this.props.newsData.total <= this.props.curpage ? ( + 以上为全部内容 + ) : ( + + 查看更多 + + ); if (this.state.loading) { - pending = + pending = ; } let diffView = showDiffMsg(jsondiffpatch, formattersHtml, curDiffData); - - return (
@@ -243,14 +273,19 @@ class TimeTree extends Component { 注: 绿色代表新增内容,红色代表删除内容
{diffView.map((item, index) => { - return + return ( + + ); })} - {diffView.length === 0 && - - } + {diffView.length === 0 && }
- {this.props.type === 'project' && + {this.props.type === 'project' && ( 选择查询的 Api: @@ -258,10 +293,14 @@ class TimeTree extends Component { onSelect={this.handleSelectApi} style={{ width: '100%' }} placeholder="Select Api" - optionLabelProp="path" + optionLabelProp="title" filterOption={(inputValue, options) => { + console.log(options); if (options.props.value == '') return true; - if (options.props.path.indexOf(inputValue) !== -1 || options.props.title.indexOf(inputValue) !== -1) { + if ( + options.props.path.indexOf(inputValue) !== -1 || + options.props.title.indexOf(inputValue) !== -1 + ) { return true; } return false; @@ -270,13 +309,18 @@ class TimeTree extends Component { {children} - - } - {data ? {data} : } + )} + {data ? ( + + {data} + + ) : ( + + )}
- ) + ); } } -export default TimeTree +export default TimeTree; diff --git a/common/diff-view.js b/common/diff-view.js index e6ca138f..d95898c3 100644 --- a/common/diff-view.js +++ b/common/diff-view.js @@ -66,7 +66,17 @@ module.exports = function (jsondiffpatch, formattersHtml, curDiffData) { if (curDiffData && typeof curDiffData === 'object' && curDiffData.current) { - const { current, old } = curDiffData; + const { current, old, type } = curDiffData; + // wiki 信息的diff 输出 + if(type === 'wiki') { + if (current != old) { + diffView.push({ + title: 'wiki更新', + content: diffText(old, current) + }) + } + return diffView = diffView.filter(item => item.content) + } if (current.path != old.path) { diffView.push({ title: 'Api 路径', diff --git a/common/utils.js b/common/utils.js index bd9b23ca..5407b054 100644 --- a/common/utils.js +++ b/common/utils.js @@ -169,4 +169,5 @@ exports.json_format= function(json){ }catch(e){ return json; } -} \ No newline at end of file +} + diff --git a/exts/yapi-plugin-advanced-mock/server.js b/exts/yapi-plugin-advanced-mock/server.js index 733c8708..d8a357fa 100644 --- a/exts/yapi-plugin-advanced-mock/server.js +++ b/exts/yapi-plugin-advanced-mock/server.js @@ -49,7 +49,7 @@ module.exports = function(){ interface_id: interfaceId, ip_enable: true, ip: ip - }).select('_id params'); + }).select('_id params'); let matchList = []; listWithIp.forEach(item=>{ let params = item.params; diff --git a/exts/yapi-plugin-wiki/WikiPage/index.js b/exts/yapi-plugin-wiki/WikiPage/index.js index a90c8ae7..ca992e33 100644 --- a/exts/yapi-plugin-wiki/WikiPage/index.js +++ b/exts/yapi-plugin-wiki/WikiPage/index.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { Button, message, Checkbox } from 'antd'; -import { connect } from 'react-redux' +import { connect } from 'react-redux'; import axios from 'axios'; import PropTypes from 'prop-types'; import './index.scss'; @@ -11,7 +11,8 @@ require('tui-editor/dist/tui-editor-contents.css'); // editor content require('highlight.js/styles/github.css'); // code block highlight // require('./editor.css'); var Editor = require('tui-editor'); -import { formatDate } from '../util.js'; +import { timeago } from '../util.js'; +import { Link } from 'react-router-dom'; @connect( state => { @@ -69,7 +70,8 @@ class WikiPage extends Component { desc: data.desc, markdown: data.markdown, username: data.username, - editorTime: formatDate(data.up_time * 1000) + uid: data.uid, + editorTime: timeago(data.up_time) }); } } else { @@ -101,16 +103,18 @@ class WikiPage extends Component { }; // 邮件通知 - onEmailNotice = (e) => { + onEmailNotice = e => { this.setState({ notice: e.target.checked - }) - - } + }); + }; render() { - const { isEditor, username, editorTime, notice } = this.state; - const editorEable = this.props.projectMsg.role === 'admin' || this.props.projectMsg.role === 'owner' || this.props.projectMsg.role === 'dev' + const { isEditor, username, editorTime, notice, uid } = this.state; + const editorEable = + this.props.projectMsg.role === 'admin' || + this.props.projectMsg.role === 'owner' || + this.props.projectMsg.role === 'dev'; return (
@@ -124,15 +128,24 @@ class WikiPage extends Component { - - 通知相关人员 + + + 通知相关人员 +
)}
{!isEditor && username && (
- 由{username}修改于{editorTime} + {/* 由 {username} */} + + {/* */} + {username} + + 修改于 {editorTime}
)}
diff --git a/exts/yapi-plugin-wiki/client.js b/exts/yapi-plugin-wiki/client.js index 4a01abf8..48d0bda9 100644 --- a/exts/yapi-plugin-wiki/client.js +++ b/exts/yapi-plugin-wiki/client.js @@ -3,7 +3,7 @@ import WikiPage from './WikiPage/index' module.exports = function(){ this.bindHook('sub_nav', function(app){ app.wiki = { - name: 'wiki', + name: 'Wiki', path: '/project/:id/wiki', component: WikiPage } diff --git a/exts/yapi-plugin-wiki/controller.js b/exts/yapi-plugin-wiki/controller.js index 4324dd47..46490a62 100644 --- a/exts/yapi-plugin-wiki/controller.js +++ b/exts/yapi-plugin-wiki/controller.js @@ -5,10 +5,10 @@ const projectModel = require('models/project.js'); const jsondiffpatch = require('jsondiffpatch'); const formattersHtml = jsondiffpatch.formatters.html; const yapi = require('yapi.js'); -const util = require('./util.js'); -const fs = require('fs-extra') +// const util = require('./util.js'); +const fs = require('fs-extra'); const path = require('path'); - +const showDiffMsg = require('../../common/diff-view.js'); class wikiController extends baseController { constructor(ctx) { super(ctx); @@ -68,12 +68,15 @@ class wikiController extends baseController { let notice = params.email_notice; delete params.email_notice; + const username = this.getUsername(); + const uid = this.getUid(); // 如果当前数据库里面没有数据 let result = await this.Model.get(params.project_id) if(!result) { let data = Object.assign(params, { - username: this.getUsername(), + username, + uid, add_time: yapi.commons.time(), up_time: yapi.commons.time() }); @@ -84,42 +87,57 @@ class wikiController extends baseController { // console.log('result', result); let data = Object.assign(params, { - username: this.getUsername(), + username, + uid, up_time: yapi.commons.time() }); let upRes = await this.Model.up(result._id, data); ctx.body = yapi.commons.resReturn(upRes) + let logData = { + type: 'wiki', + project_id: params.project_id, + current: params.desc, + old: result ? result.toObject().desc : '' + } + let wikiUrl = `http://${ctx.request.host}/project/${params.project_id}/wiki` + if(notice) { - let logData = { - project_id: params.project_id, - current: params.desc, - old: result ? result.toObject().desc : '' - } - let diffView = util.showDiffMsg(jsondiffpatch, formattersHtml, logData); + let diffView = showDiffMsg(jsondiffpatch, formattersHtml, logData); let annotatedCss = fs.readFileSync(path.resolve(yapi.WEBROOT, 'node_modules/jsondiffpatch/public/formatters-styles/annotated.css'), 'utf8'); let htmlCss = fs.readFileSync(path.resolve(yapi.WEBROOT, 'node_modules/jsondiffpatch/public/formatters-styles/html.css'), 'utf8'); let project = await this.projectModel.getBaseInfo(params.project_id); - let wikiUrl = `http://${ctx.request.host}/project/${params.project_id}/wiki` + yapi.commons.sendNotice(params.project_id, { - title: `${this.getUsername()} 更新了wiki说明`, + title: `${username} 更新了wiki说明`, content: ` + -

${this.getUsername()}更新了wiki

-

修改用户: ${this.getUsername()}

+

${username}更新了wiki说明

+

修改用户: ${username}

修改项目: ${project.name}

详细改动日志: ${this.diffHTML(diffView)}

` }) } + + // 保存修改日志信息 + yapi.commons.saveLog({ + content: `${username} 更新了 wiki 的信息`, + type: 'project', + uid, + username: username, + typeid: params.project_id, + data: logData + }); // let upRes = await this.Model.get(result._id) return 1; } catch (err) { diff --git a/exts/yapi-plugin-wiki/server.js b/exts/yapi-plugin-wiki/server.js index 63463134..6c7bdcc7 100644 --- a/exts/yapi-plugin-wiki/server.js +++ b/exts/yapi-plugin-wiki/server.js @@ -16,6 +16,7 @@ module.exports = function () { this.bindHook('add_router', function (addRouter) { addRouter({ + // 获取wiki信息 controller: controller, method: 'get', path: 'wiki_desc/get', @@ -23,24 +24,12 @@ module.exports = function () { }) addRouter({ + // 更新wiki信息 controller: controller, method: 'post', path: 'wiki_desc/up', action: 'uplodaWikiDesc' }) - // addRouter({ - // controller: controller, - // method: 'get', - // path: 'statismock/get_system_status', - // action: 'getSystemStatus' - // }) - // addRouter({ - // controller: controller, - // method: 'get', - // path: 'statismock/group_data_statis', - // action: 'groupDataStatis' - // }) - }) }; \ No newline at end of file diff --git a/exts/yapi-plugin-wiki/util.js b/exts/yapi-plugin-wiki/util.js index 82912640..5e8b34d5 100644 --- a/exts/yapi-plugin-wiki/util.js +++ b/exts/yapi-plugin-wiki/util.js @@ -28,37 +28,51 @@ const convert2Decimal = num => (num > 9 ? num : `0${num}`) // const json5_parse = require('../client/common.js').json5_parse; - - -exports.showDiffMsg = (jsondiffpatch, formattersHtml, curDiffData) => { - - const diffText = (left, right) => { - left = left || ''; - right = right || ''; - if (left == right) { - return null; - } - var delta = jsondiffpatch.diff(left, right); - return formattersHtml.format(delta, left) +exports.timeago =(timestamp) => { + let minutes, hours, days, seconds, mouth, year; + const timeNow = parseInt(new Date().getTime() / 1000); + seconds = timeNow - timestamp; + if (seconds > 86400 * 30 * 12) { + year = parseInt(seconds / (86400 * 30 * 12)); + } else { + year = 0; } - - - let diffView = []; - - - if (curDiffData && typeof curDiffData === 'object' && curDiffData.current) { - const { current, old } = curDiffData; - if (current != old) { - diffView.push({ - title: 'wiki更新', - content: diffText(old, current) - }) - } - + if (seconds > 86400 * 30) { + mouth = parseInt(seconds / (86400 * 30)); + } else { + mouth = 0; } - - - return diffView = diffView.filter(item => item.content) - + if (seconds > 86400) { + days = parseInt(seconds / (86400)); + } else { + days = 0; + } + if (seconds > 3600) { + hours = parseInt(seconds / (3600)); + } else { + hours = 0; + } + minutes = parseInt(seconds / 60); + if (year > 0) { + return year + "年前"; + } else if (mouth > 0 && year <= 0) { + return mouth + "月前"; + } else if (days > 0 && mouth <= 0) { + return days + "天前"; + } else if (days <= 0 && hours > 0) { + return hours + "小时前"; + } else if (hours <= 0 && minutes > 0) { + return minutes + "分钟前"; + } else if (minutes <= 0 && seconds > 0) { + if (seconds < 30) { + return "刚刚"; + } else { + return seconds + "秒前"; + } + } else { + return "刚刚"; + } } + + diff --git a/exts/yapi-plugin-wiki/wikiModel.js b/exts/yapi-plugin-wiki/wikiModel.js index 6c39a181..965043b4 100644 --- a/exts/yapi-plugin-wiki/wikiModel.js +++ b/exts/yapi-plugin-wiki/wikiModel.js @@ -10,6 +10,7 @@ class statisMockModel extends baseModel { return { project_id: { type: Number, required: true }, username: String, + uid: Number, desc: String, markdown: String, add_time: Number, diff --git a/server/controllers/interfaceCol.js b/server/controllers/interfaceCol.js index 87bd8094..6ef696ba 100755 --- a/server/controllers/interfaceCol.js +++ b/server/controllers/interfaceCol.js @@ -672,7 +672,7 @@ class interfaceColController extends baseController { let result = await this.colModel.up(id, params); let username = this.getUsername(); yapi.commons.saveLog({ - content: `${username} 更新了接口集 ${colData.name} 的信息`, + content: `${username} 更新了测试集合 ${colData.name} 的信息`, type: 'project', uid: this.getUid(), username: username, diff --git a/server/controllers/project.js b/server/controllers/project.js index 37cdfd1c..31734c83 100755 --- a/server/controllers/project.js +++ b/server/controllers/project.js @@ -908,9 +908,10 @@ class projectController extends baseController { return (ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空')); } - if ((await this.checkAuth(project_id, 'project', 'edit')) !== true) { - return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限')); - } + // 去掉权限判断 + // if ((await this.checkAuth(project_id, 'project', 'edit')) !== true) { + // return (ctx.body = yapi.commons.resReturn(null, 405, '没有权限')); + // } let env = await this.Model.getByEnv(project_id); // console.log('project', projectData)