fork from bc4552c5a8
This commit is contained in:
12
exts/yapi-plugin-wiki/client.js
Normal file
12
exts/yapi-plugin-wiki/client.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import WikiPage from './wikiPage/index';
|
||||
// const WikiPage = require('./wikiPage/index')
|
||||
|
||||
module.exports = function() {
|
||||
this.bindHook('sub_nav', function(app) {
|
||||
app.wiki = {
|
||||
name: 'Wiki',
|
||||
path: '/project/:id/wiki',
|
||||
component: WikiPage
|
||||
};
|
||||
});
|
||||
};
|
||||
234
exts/yapi-plugin-wiki/controller.js
Normal file
234
exts/yapi-plugin-wiki/controller.js
Normal file
@@ -0,0 +1,234 @@
|
||||
const baseController = require('controllers/base.js');
|
||||
const wikiModel = require('./wikiModel.js');
|
||||
const projectModel = require('models/project.js');
|
||||
const userModel = require('models/user.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 path = require('path');
|
||||
const showDiffMsg = require('../../common/diff-view.js');
|
||||
class wikiController extends baseController {
|
||||
constructor(ctx) {
|
||||
super(ctx);
|
||||
this.Model = yapi.getInst(wikiModel);
|
||||
this.projectModel = yapi.getInst(projectModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取wiki信息
|
||||
* @interface wiki_desc/get
|
||||
* @method get
|
||||
* @category statistics
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
*/
|
||||
async getWikiDesc(ctx) {
|
||||
try {
|
||||
let project_id = ctx.request.query.project_id;
|
||||
if (!project_id) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空'));
|
||||
}
|
||||
let result = await this.Model.get(project_id);
|
||||
return (ctx.body = yapi.commons.resReturn(result));
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 400, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存wiki信息
|
||||
* @interface wiki_desc/get
|
||||
* @method get
|
||||
* @category statistics
|
||||
* @foldnumber 10
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
async uplodaWikiDesc(ctx) {
|
||||
try {
|
||||
let params = ctx.request.body;
|
||||
params = yapi.commons.handleParams(params, {
|
||||
project_id: 'number',
|
||||
desc: 'string',
|
||||
markdown: 'string'
|
||||
});
|
||||
|
||||
if (!params.project_id) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空'));
|
||||
}
|
||||
if (!this.$tokenAuth) {
|
||||
let auth = await this.checkAuth(params.project_id, 'project', 'edit');
|
||||
if (!auth) {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限'));
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
uid,
|
||||
add_time: yapi.commons.time(),
|
||||
up_time: yapi.commons.time()
|
||||
});
|
||||
|
||||
let res = await this.Model.save(data);
|
||||
ctx.body = yapi.commons.resReturn(res);
|
||||
} else {
|
||||
let data = Object.assign(params, {
|
||||
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 = `${ctx.request.origin}/project/${params.project_id}/wiki`;
|
||||
|
||||
if (notice) {
|
||||
let diffView = showDiffMsg(jsondiffpatch, formattersHtml, logData);
|
||||
|
||||
let annotatedCss = fs.readFileSync(
|
||||
path.resolve(
|
||||
yapi.WEBROOT,
|
||||
'node_modules/jsondiffpatch/dist/formatters-styles/annotated.css'
|
||||
),
|
||||
'utf8'
|
||||
);
|
||||
let htmlCss = fs.readFileSync(
|
||||
path.resolve(yapi.WEBROOT, 'node_modules/jsondiffpatch/dist/formatters-styles/html.css'),
|
||||
'utf8'
|
||||
);
|
||||
let project = await this.projectModel.getBaseInfo(params.project_id);
|
||||
|
||||
yapi.commons.sendNotice(params.project_id, {
|
||||
title: `${username} 更新了wiki说明`,
|
||||
content: `<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
${annotatedCss}
|
||||
${htmlCss}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><h3>${username}更新了wiki说明</h3>
|
||||
<p>修改用户: ${username}</p>
|
||||
<p>修改项目: <a href="${wikiUrl}">${project.name}</a></p>
|
||||
<p>详细改动日志: ${this.diffHTML(diffView)}</p></div>
|
||||
</body>
|
||||
</html>`
|
||||
});
|
||||
}
|
||||
|
||||
// 保存修改日志信息
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${uid}">${username}</a> 更新了 <a href="${wikiUrl}">wiki</a> 的信息`,
|
||||
type: 'project',
|
||||
uid,
|
||||
username: username,
|
||||
typeid: params.project_id,
|
||||
data: logData
|
||||
});
|
||||
return 1;
|
||||
} catch (err) {
|
||||
ctx.body = yapi.commons.resReturn(null, 400, err.message);
|
||||
}
|
||||
}
|
||||
diffHTML(html) {
|
||||
if (html.length === 0) {
|
||||
return `<span style="color: #555">没有改动,该操作未改动wiki数据</span>`;
|
||||
}
|
||||
|
||||
return html.map(item => {
|
||||
return `<div>
|
||||
<h4 class="title">${item.title}</h4>
|
||||
<div>${item.content}</div>
|
||||
</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
// 处理编辑冲突
|
||||
async wikiConflict(ctx) {
|
||||
try {
|
||||
let result;
|
||||
ctx.websocket.on('message', async message => {
|
||||
let id = parseInt(ctx.query.id, 10);
|
||||
if (!id) {
|
||||
return ctx.websocket.send('id 参数有误');
|
||||
}
|
||||
result = await this.Model.get(id);
|
||||
let data = await this.websocketMsgMap(message, result);
|
||||
if (data) {
|
||||
ctx.websocket.send(JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
ctx.websocket.on('close', async () => {});
|
||||
} catch (err) {
|
||||
yapi.commons.log(err, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
websocketMsgMap(msg, result) {
|
||||
const map = {
|
||||
start: this.startFunc.bind(this),
|
||||
end: this.endFunc.bind(this),
|
||||
editor: this.editorFunc.bind(this)
|
||||
};
|
||||
|
||||
return map[msg](result);
|
||||
}
|
||||
|
||||
// socket 开始链接
|
||||
async startFunc(result) {
|
||||
if (result && result.edit_uid === this.getUid()) {
|
||||
await this.Model.upEditUid(result._id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// socket 结束链接
|
||||
async endFunc(result) {
|
||||
if (result) {
|
||||
await this.Model.upEditUid(result._id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// 正在编辑
|
||||
async editorFunc(result) {
|
||||
let userInst, userinfo, data;
|
||||
if (result && result.edit_uid !== 0 && result.edit_uid !== this.getUid()) {
|
||||
userInst = yapi.getInst(userModel);
|
||||
userinfo = await userInst.findById(result.edit_uid);
|
||||
data = {
|
||||
errno: result.edit_uid,
|
||||
data: { uid: result.edit_uid, username: userinfo.username }
|
||||
};
|
||||
} else {
|
||||
if (result) {
|
||||
await this.Model.upEditUid(result._id, this.getUid());
|
||||
}
|
||||
data = {
|
||||
errno: 0,
|
||||
data: result
|
||||
};
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = wikiController;
|
||||
64
exts/yapi-plugin-wiki/index.js
Normal file
64
exts/yapi-plugin-wiki/index.js
Normal file
@@ -0,0 +1,64 @@
|
||||
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
|
||||
]
|
||||
};
|
||||
39
exts/yapi-plugin-wiki/server.js
Normal file
39
exts/yapi-plugin-wiki/server.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const yapi = require('yapi.js');
|
||||
const mongoose = require('mongoose');
|
||||
const controller = require('./controller');
|
||||
|
||||
module.exports = function() {
|
||||
yapi.connect.then(function() {
|
||||
let Col = mongoose.connection.db.collection('wiki');
|
||||
Col.createIndex({
|
||||
project_id: 1
|
||||
});
|
||||
});
|
||||
|
||||
this.bindHook('add_router', function(addRouter) {
|
||||
addRouter({
|
||||
// 获取wiki信息
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'wiki_desc/get',
|
||||
action: 'getWikiDesc'
|
||||
});
|
||||
|
||||
addRouter({
|
||||
// 更新wiki信息
|
||||
controller: controller,
|
||||
method: 'post',
|
||||
path: 'wiki_desc/up',
|
||||
action: 'uplodaWikiDesc'
|
||||
});
|
||||
});
|
||||
|
||||
this.bindHook('add_ws_router', function(wsRouter) {
|
||||
wsRouter({
|
||||
controller: controller,
|
||||
method: 'get',
|
||||
path: 'wiki_desc/solve_conflict',
|
||||
action: 'wikiConflict'
|
||||
});
|
||||
});
|
||||
};
|
||||
25
exts/yapi-plugin-wiki/util.js
Normal file
25
exts/yapi-plugin-wiki/util.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// 时间
|
||||
const convert2Decimal = num => (num > 9 ? num : `0${num}`);
|
||||
|
||||
/**
|
||||
* 格式化 年、月、日、时、分、秒
|
||||
* @param val {Object or String or Number} 日期对象 或是可new Date的对象或时间戳
|
||||
* @return {String} 2017-01-20 20:00:00
|
||||
*/
|
||||
exports.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(':')}`;
|
||||
};
|
||||
|
||||
// const json5_parse = require('../client/common.js').json5_parse;
|
||||
56
exts/yapi-plugin-wiki/wikiModel.js
Normal file
56
exts/yapi-plugin-wiki/wikiModel.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const yapi = require('yapi.js');
|
||||
const baseModel = require('models/base.js');
|
||||
|
||||
class statisMockModel extends baseModel {
|
||||
getName() {
|
||||
return 'wiki';
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
return {
|
||||
project_id: { type: Number, required: true },
|
||||
username: String,
|
||||
uid: { type: Number, required: true },
|
||||
edit_uid: { type: Number, default: 0 },
|
||||
desc: String,
|
||||
markdown: String,
|
||||
add_time: Number,
|
||||
up_time: Number
|
||||
};
|
||||
}
|
||||
|
||||
save(data) {
|
||||
let m = new this.model(data);
|
||||
return m.save();
|
||||
}
|
||||
|
||||
get(project_id) {
|
||||
return this.model
|
||||
.findOne({
|
||||
project_id: project_id
|
||||
})
|
||||
.exec();
|
||||
}
|
||||
|
||||
up(id, data) {
|
||||
return this.model.update(
|
||||
{
|
||||
_id: id
|
||||
},
|
||||
data,
|
||||
{ runValidators: true }
|
||||
);
|
||||
}
|
||||
|
||||
upEditUid(id, uid) {
|
||||
return this.model.update(
|
||||
{
|
||||
_id: id
|
||||
},
|
||||
{ edit_uid: uid },
|
||||
{ runValidators: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = statisMockModel;
|
||||
67
exts/yapi-plugin-wiki/wikiPage/Editor.js
Normal file
67
exts/yapi-plugin-wiki/wikiPage/Editor.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Checkbox } from 'antd';
|
||||
import Editor from 'common/tui-editor/dist/tui-editor-Editor-all.min.js';
|
||||
require('common/tui-editor/dist/tui-editor.min.css'); // editor ui
|
||||
require('common/tui-editor/dist/tui-editor-contents.min.css'); // editor content
|
||||
class WikiEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
isConflict: PropTypes.bool,
|
||||
onUpload: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
notice: PropTypes.bool,
|
||||
onEmailNotice: PropTypes.func,
|
||||
desc: PropTypes.string
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.editor = new Editor({
|
||||
el: document.querySelector('#desc'),
|
||||
initialEditType: 'wysiwyg',
|
||||
height: '500px',
|
||||
initialValue: this.props.desc
|
||||
});
|
||||
}
|
||||
|
||||
onUpload = () => {
|
||||
let desc = this.editor.getHtml();
|
||||
let markdown = this.editor.getMarkdown();
|
||||
this.props.onUpload(desc, markdown);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isConflict, onCancel, notice, onEmailNotice } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
id="desc"
|
||||
className="wiki-editor"
|
||||
style={{ display: !isConflict ? 'block' : 'none' }}
|
||||
/>
|
||||
<div className="wiki-title wiki-up">
|
||||
<Button
|
||||
icon="upload"
|
||||
type="primary"
|
||||
className="upload-btn"
|
||||
disabled={isConflict}
|
||||
onClick={this.onUpload}
|
||||
>
|
||||
更新
|
||||
</Button>
|
||||
<Button onClick={onCancel} className="upload-btn">
|
||||
取消
|
||||
</Button>
|
||||
<Checkbox checked={notice} onChange={onEmailNotice}>
|
||||
通知相关人员
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WikiEditor;
|
||||
41
exts/yapi-plugin-wiki/wikiPage/View.js
Normal file
41
exts/yapi-plugin-wiki/wikiPage/View.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const WikiView = props => {
|
||||
const { editorEable, onEditor, uid, username, editorTime, desc } = props;
|
||||
return (
|
||||
<div className="wiki-view-content">
|
||||
<div className="wiki-title">
|
||||
<Button icon="edit" onClick={onEditor} disabled={!editorEable}>
|
||||
编辑
|
||||
</Button>
|
||||
{username && (
|
||||
<div className="wiki-user">
|
||||
由{' '}
|
||||
<Link className="user-name" to={`/user/profile/${uid || 11}`}>
|
||||
{username}
|
||||
</Link>{' '}
|
||||
修改于 {editorTime}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="tui-editor-contents"
|
||||
dangerouslySetInnerHTML={{ __html: desc }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
WikiView.propTypes = {
|
||||
editorEable: PropTypes.bool,
|
||||
onEditor: PropTypes.func,
|
||||
uid: PropTypes.number,
|
||||
username: PropTypes.string,
|
||||
editorTime: PropTypes.string,
|
||||
desc: PropTypes.string
|
||||
};
|
||||
|
||||
export default WikiView;
|
||||
255
exts/yapi-plugin-wiki/wikiPage/index.js
Normal file
255
exts/yapi-plugin-wiki/wikiPage/index.js
Normal file
@@ -0,0 +1,255 @@
|
||||
import React, { Component } from 'react';
|
||||
import { message } from 'antd';
|
||||
import { connect } from 'react-redux';
|
||||
import axios from 'axios';
|
||||
import PropTypes from 'prop-types';
|
||||
import './index.scss';
|
||||
import { timeago } from '../../../common/utils';
|
||||
import { Link } from 'react-router-dom';
|
||||
import WikiView from './View.js';
|
||||
import WikiEditor from './Editor.js';
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
projectMsg: state.project.currProject
|
||||
};
|
||||
},
|
||||
{}
|
||||
)
|
||||
class WikiPage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isEditor: false,
|
||||
isUpload: true,
|
||||
desc: '',
|
||||
markdown: '',
|
||||
notice: props.projectMsg.switch_notice,
|
||||
status: 'INIT',
|
||||
editUid: '',
|
||||
editName: '',
|
||||
curdata: null
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
projectMsg: PropTypes.object
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
const currProjectId = this.props.match.params.id;
|
||||
await this.handleData({ project_id: currProjectId });
|
||||
this.handleConflict();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// willUnmount
|
||||
try {
|
||||
if (this.state.status === 'CLOSE') {
|
||||
this.WebSocket.send('end');
|
||||
this.WebSocket.close();
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// 结束编辑websocket
|
||||
endWebSocket = () => {
|
||||
try {
|
||||
if (this.state.status === 'CLOSE') {
|
||||
const sendEnd = () => {
|
||||
this.WebSocket.send('end');
|
||||
};
|
||||
this.handleWebsocketAccidentClose(sendEnd);
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// 处理多人编辑冲突问题
|
||||
handleConflict = () => {
|
||||
// console.log(location)
|
||||
let domain = location.hostname + (location.port !== '' ? ':' + location.port : '');
|
||||
let s;
|
||||
//因后端 node 仅支持 ws, 暂不支持 wss
|
||||
let wsProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
s = new WebSocket(
|
||||
wsProtocol +
|
||||
'://' +
|
||||
domain +
|
||||
'/api/ws_plugin/wiki_desc/solve_conflict?id=' +
|
||||
this.props.match.params.id
|
||||
);
|
||||
s.onopen = () => {
|
||||
this.WebSocket = s;
|
||||
s.send('start');
|
||||
};
|
||||
|
||||
s.onmessage = e => {
|
||||
let result = JSON.parse(e.data);
|
||||
if (result.errno === 0) {
|
||||
// 更新
|
||||
if (result.data) {
|
||||
this.setState({
|
||||
// curdata: result.data,
|
||||
desc: result.data.desc,
|
||||
username: result.data.username,
|
||||
uid: result.data.uid,
|
||||
editorTime: timeago(result.data.up_time)
|
||||
});
|
||||
}
|
||||
// 新建
|
||||
this.setState({
|
||||
isEditor: !this.state.isEditor,
|
||||
status: 'CLOSE'
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
editUid: result.data.uid,
|
||||
editName: result.data.username,
|
||||
status: 'EDITOR'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
s.onerror = () => {
|
||||
this.setState({
|
||||
status: 'CLOSE'
|
||||
});
|
||||
console.warn('websocket 连接失败,将导致多人编辑同一个接口冲突。');
|
||||
};
|
||||
};
|
||||
|
||||
// 点击编辑按钮 发送 websocket 获取数据
|
||||
onEditor = () => {
|
||||
// this.WebSocket.send('editor');
|
||||
const sendEditor = () => {
|
||||
this.WebSocket.send('editor');
|
||||
};
|
||||
this.handleWebsocketAccidentClose(sendEditor, status => {
|
||||
// 如果websocket 启动不成功用户依旧可以对wiki 进行编辑
|
||||
if (!status) {
|
||||
this.setState({
|
||||
isEditor: !this.state.isEditor
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 处理websocket 意外断开问题
|
||||
handleWebsocketAccidentClose = (fn, callback) => {
|
||||
// websocket 是否启动
|
||||
if (this.WebSocket) {
|
||||
// websocket 断开
|
||||
if (this.WebSocket.readyState !== 1) {
|
||||
message.error('websocket 链接失败,请重新刷新页面');
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
callback(true);
|
||||
} else {
|
||||
callback(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
handleData = async params => {
|
||||
let result = await axios.get('/api/plugin/wiki_desc/get', { params });
|
||||
if (result.data.errcode === 0) {
|
||||
const data = result.data.data;
|
||||
if (data) {
|
||||
this.setState({
|
||||
desc: data.desc,
|
||||
markdown: data.markdown,
|
||||
username: data.username,
|
||||
uid: data.uid,
|
||||
editorTime: timeago(data.up_time)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
message.error(`请求数据失败: ${result.data.errmsg}`);
|
||||
}
|
||||
};
|
||||
|
||||
// 数据上传
|
||||
onUpload = async (desc, markdown) => {
|
||||
const currProjectId = this.props.match.params.id;
|
||||
let option = {
|
||||
project_id: currProjectId,
|
||||
desc,
|
||||
markdown,
|
||||
email_notice: this.state.notice
|
||||
};
|
||||
let result = await axios.post('/api/plugin/wiki_desc/up', option);
|
||||
if (result.data.errcode === 0) {
|
||||
await this.handleData({ project_id: currProjectId });
|
||||
this.setState({ isEditor: false });
|
||||
} else {
|
||||
message.error(`更新失败: ${result.data.errmsg}`);
|
||||
}
|
||||
this.endWebSocket();
|
||||
// this.WebSocket.send('end');
|
||||
};
|
||||
// 取消编辑
|
||||
onCancel = () => {
|
||||
this.setState({ isEditor: false });
|
||||
this.endWebSocket();
|
||||
};
|
||||
|
||||
// 邮件通知
|
||||
onEmailNotice = e => {
|
||||
this.setState({
|
||||
notice: e.target.checked
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isEditor, username, editorTime, notice, uid, status, editUid, editName } = this.state;
|
||||
const editorEable =
|
||||
this.props.projectMsg.role === 'admin' ||
|
||||
this.props.projectMsg.role === 'owner' ||
|
||||
this.props.projectMsg.role === 'dev';
|
||||
const isConflict = status === 'EDITOR';
|
||||
|
||||
return (
|
||||
<div className="g-row">
|
||||
<div className="m-panel wiki-content">
|
||||
<div className="wiki-content">
|
||||
{isConflict && (
|
||||
<div className="wiki-conflict">
|
||||
<Link to={`/user/profile/${editUid || uid}`}>
|
||||
<b>{editName || username}</b>
|
||||
</Link>
|
||||
<span>正在编辑该wiki,请稍后再试...</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!isEditor ? (
|
||||
<WikiView
|
||||
editorEable={editorEable}
|
||||
onEditor={this.onEditor}
|
||||
uid={uid}
|
||||
username={username}
|
||||
editorTime={editorTime}
|
||||
desc={this.state.desc}
|
||||
/>
|
||||
) : (
|
||||
<WikiEditor
|
||||
isConflict={isConflict}
|
||||
onUpload={this.onUpload}
|
||||
onCancel={this.onCancel}
|
||||
notice={notice}
|
||||
onEmailNotice={this.onEmailNotice}
|
||||
desc={this.state.desc}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WikiPage;
|
||||
27
exts/yapi-plugin-wiki/wikiPage/index.scss
Normal file
27
exts/yapi-plugin-wiki/wikiPage/index.scss
Normal file
@@ -0,0 +1,27 @@
|
||||
.wiki-content {
|
||||
.wiki-user {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.wiki-editor {
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.upload-btn {
|
||||
margin-right: 16px;
|
||||
}
|
||||
.wiki-conflict {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.wiki-up {
|
||||
text-align: right;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.wiki-title {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user