markdown渲染功能
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import mdTemplate from './mdTemplate/mdTemplate.js'
|
import mdTemplate from './mdTemplate/mdTemplate.js'
|
||||||
|
import Services from "./mdTemplate/Services";
|
||||||
|
|
||||||
function exportData(exportDataModule, pid) {
|
function exportData(exportDataModule, pid) {
|
||||||
exportDataModule.markdown = {
|
exportDataModule.markdown = {
|
||||||
@@ -17,7 +18,18 @@ function hander(routers) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = function() {
|
module.exports = function() {
|
||||||
this.bindHook('export_data', exportData);
|
this.bindHook('export_data', exportData);
|
||||||
this.bindHook('sub_setting_nav', hander);
|
this.bindHook('sub_setting_nav', hander);
|
||||||
|
|
||||||
|
|
||||||
|
this.bindHook('interface_tab', function (tabs) {
|
||||||
|
tabs.mdGen = {
|
||||||
|
name: 'Markdown',
|
||||||
|
component: Services
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const baseController = require('controllers/base.js');
|
|||||||
const interfaceModel = require('models/interface.js');
|
const interfaceModel = require('models/interface.js');
|
||||||
const projectModel = require('models/project.js');
|
const projectModel = require('models/project.js');
|
||||||
const interfaceCatModel = require('models/interfaceCat.js');
|
const interfaceCatModel = require('models/interfaceCat.js');
|
||||||
|
const userModel = require("models/user.js");
|
||||||
const yapi = require('yapi.js');
|
const yapi = require('yapi.js');
|
||||||
const uuid = require('uuid');
|
const uuid = require('uuid');
|
||||||
const configModel = require("./configModel");
|
const configModel = require("./configModel");
|
||||||
@@ -15,6 +16,7 @@ class exportMarkdownController extends baseController {
|
|||||||
this.interModel = yapi.getInst(interfaceModel);
|
this.interModel = yapi.getInst(interfaceModel);
|
||||||
this.projectModel = yapi.getInst(projectModel);
|
this.projectModel = yapi.getInst(projectModel);
|
||||||
this.configModel = yapi.getInst(configModel);
|
this.configModel = yapi.getInst(configModel);
|
||||||
|
this.userModel = yapi.getInst(userModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -71,7 +73,6 @@ class exportMarkdownController extends baseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async exportData(ctx) {
|
async exportData(ctx) {
|
||||||
let pid = ctx.request.query.pid;
|
let pid = ctx.request.query.pid;
|
||||||
let status = ctx.request.query.status;
|
let status = ctx.request.query.status;
|
||||||
@@ -80,13 +81,13 @@ class exportMarkdownController extends baseController {
|
|||||||
ctx.body = yapi.commons.resReturn(null, 200, 'pid 不为空');
|
ctx.body = yapi.commons.resReturn(null, 200, 'pid 不为空');
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = await this.configModel.getByProjectId(pid);
|
let templateData = await this.configModel.getByProjectId(pid);
|
||||||
// console.log(result);
|
// console.log(result);
|
||||||
if (!result.is_export_by_interface){
|
if (!templateData.is_export_by_interface) {
|
||||||
console.log("重定向")
|
console.log("重定向")
|
||||||
ctx.status = 302;
|
ctx.status = 302;
|
||||||
ctx.redirect(`/api/plugin/export?type=markdown&pid=${pid}`);
|
ctx.redirect(`/api/plugin/export?type=markdown&pid=${pid}`);
|
||||||
return ;
|
return;
|
||||||
}
|
}
|
||||||
let curProject;
|
let curProject;
|
||||||
try {
|
try {
|
||||||
@@ -96,6 +97,8 @@ class exportMarkdownController extends baseController {
|
|||||||
const list = await this.handleListClass(pid, status);
|
const list = await this.handleListClass(pid, status);
|
||||||
|
|
||||||
let data = this.handleExistId(list);
|
let data = this.handleExistId(list);
|
||||||
|
let userData = await this.userModel.findById(this.getUid());
|
||||||
|
|
||||||
|
|
||||||
// console.log("curProject", curProject)
|
// console.log("curProject", curProject)
|
||||||
// console.log("list", list)
|
// console.log("list", list)
|
||||||
@@ -106,41 +109,19 @@ class exportMarkdownController extends baseController {
|
|||||||
// const tmpPath = fs.mkdtempSync(path.join(os.tmpdir(),uuid.v4()));
|
// const tmpPath = fs.mkdtempSync(path.join(os.tmpdir(),uuid.v4()));
|
||||||
// console.log("tmpPath=", tmpPath)
|
// console.log("tmpPath=", tmpPath)
|
||||||
const zip = JSZip();
|
const zip = JSZip();
|
||||||
let errMsg = [];
|
let allErrMsg = [];
|
||||||
for (let item of data) {
|
for (let item of data) {
|
||||||
for(let interfaceItem of item.list){
|
for (let interfaceItem of item.list) {
|
||||||
const safeVm = new Safeify({
|
let {result, errMsg} = await this.executeJsRender(templateData.template_data, curProject, interfaceItem, item, userData)
|
||||||
timeout: 3000, //超时时间
|
zip.file(`${item.name}/${interfaceItem.title}.md`, result.toString())
|
||||||
asyncTimeout: 10000, //包含异步操作的超时时间
|
if (errMsg){
|
||||||
unrestricted: true,
|
allErrMsg.push(errMsg)
|
||||||
quantity: 4, //沙箱进程数量,默认同 CPU 核数
|
|
||||||
memoryQuota: 500, //沙箱最大能使用的内存(单位 m),默认 500m
|
|
||||||
cpuQuota: 0.5 //沙箱的 cpu 资源配额(百分比),默认 50%
|
|
||||||
});
|
|
||||||
// console.log("curProject", curProject)
|
|
||||||
const vmContext = {
|
|
||||||
projectTmp: JSON.stringify(curProject),
|
|
||||||
interfaceTmp: JSON.stringify(interfaceItem),
|
|
||||||
categoryTmp: JSON.stringify(item)
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
safeVm.preset("const project = JSON.parse(projectTmp);const interface = JSON.parse(interfaceTmp);const category=JSON.parse(categoryTmp)")
|
|
||||||
model = await safeVm.run(result.template_data, vmContext);
|
|
||||||
// fs.writeFileSync(`${tmpPath}/${interfaceItem.title}.md`, model.toString())
|
|
||||||
zip.file(`${item.name}/${interfaceItem.title}.md`, model.toString())
|
|
||||||
safeVm.destroy();
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
errMsg.push({
|
|
||||||
error: e.toString(),
|
|
||||||
context: vmContext
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (errMsg.length){
|
if (allErrMsg.length) {
|
||||||
ctx.body = yapi.commons.resReturn(errMsg, 502, '下载出错');
|
ctx.body = yapi.commons.resReturn(allErrMsg, 502, '下载出错');
|
||||||
return ;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.set('Content-Disposition', `attachment; filename=${encodeURIComponent(curProject.name)}.zip`);
|
ctx.set('Content-Disposition', `attachment; filename=${encodeURIComponent(curProject.name)}.zip`);
|
||||||
@@ -202,6 +183,67 @@ class exportMarkdownController extends baseController {
|
|||||||
let result = await this.configModel.getByProjectId(projectId);
|
let result = await this.configModel.getByProjectId(projectId);
|
||||||
return (ctx.body = yapi.commons.resReturn(result));
|
return (ctx.body = yapi.commons.resReturn(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询配置信息
|
||||||
|
* @param {*} ctx
|
||||||
|
*/
|
||||||
|
async mdGen(ctx) {
|
||||||
|
let interfaceId = ctx.query.interfaceId;
|
||||||
|
let userData = await this.userModel.findById(this.getUid());
|
||||||
|
let interfaceData = await this.interModel.get(interfaceId);
|
||||||
|
if (!interfaceData) {
|
||||||
|
return (ctx.body = yapi.commons.resReturn(null, 200, ''));
|
||||||
|
}
|
||||||
|
let templateData = await this.configModel.getByProjectId(interfaceData.project_id);
|
||||||
|
if (!templateData || !templateData.template_data) {
|
||||||
|
return (ctx.body = yapi.commons.resReturn(null, 200, ''));
|
||||||
|
}
|
||||||
|
let interfaceCat = await this.catModel.get(interfaceData.catid);
|
||||||
|
let project = await this.projectModel.get(interfaceData.project_id);
|
||||||
|
let {result, errMsg} = await this.executeJsRender(templateData.template_data, project, interfaceData, interfaceCat, userData);
|
||||||
|
if (errMsg){
|
||||||
|
ctx.body = yapi.commons.resReturn(errMsg, 502, '渲染出错');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return (ctx.body = yapi.commons.resReturn(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async executeJsRender(template_data, curProject, interfaceItem, categoryItem, useItem) {
|
||||||
|
let errMsg;
|
||||||
|
let result;
|
||||||
|
const safeVm = new Safeify({
|
||||||
|
timeout: 3000, //超时时间
|
||||||
|
asyncTimeout: 10000, //包含异步操作的超时时间
|
||||||
|
unrestricted: true,
|
||||||
|
quantity: 4, //沙箱进程数量,默认同 CPU 核数
|
||||||
|
memoryQuota: 500, //沙箱最大能使用的内存(单位 m),默认 500m
|
||||||
|
cpuQuota: 0.5 //沙箱的 cpu 资源配额(百分比),默认 50%
|
||||||
|
});
|
||||||
|
// console.log("curProject", curProject)
|
||||||
|
const vmContext = {
|
||||||
|
project: JSON.stringify(curProject),
|
||||||
|
interface: JSON.stringify(interfaceItem),
|
||||||
|
category: JSON.stringify(categoryItem),
|
||||||
|
user: JSON.stringify(useItem)
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
safeVm.preset("project = JSON.parse(project);interface = JSON.parse(interface);category=JSON.parse(category);user=JSON.parse(user)")
|
||||||
|
result = await safeVm.run(template_data, vmContext);
|
||||||
|
// fs.writeFileSync(`${tmpPath}/${interfaceItem.title}.md`, model.toString())
|
||||||
|
safeVm.destroy();
|
||||||
|
} catch (e) {
|
||||||
|
errMsg = {
|
||||||
|
error: e.toString(),
|
||||||
|
context: vmContext
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result: result, errMsg}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = exportMarkdownController;
|
module.exports = exportMarkdownController;
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import React, {PureComponent as Component} from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {getToken} from '../../../client/reducer/modules/project.js'
|
||||||
|
import './Services.scss';
|
||||||
|
import {withRouter} from "react-router-dom";
|
||||||
|
import axios from "axios";
|
||||||
|
import {message} from "antd";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
|
@connect(
|
||||||
|
state => {
|
||||||
|
return {
|
||||||
|
token: state.project.token
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getToken
|
||||||
|
}
|
||||||
|
)
|
||||||
|
class MDTemplateServices extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
projectId: PropTypes.number,
|
||||||
|
token: PropTypes.string,
|
||||||
|
getToken: PropTypes.func,
|
||||||
|
match: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.state = {
|
||||||
|
render_data: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.getSyncData();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSyncData() {
|
||||||
|
let interfaceId = this.props.match.params.actionId;
|
||||||
|
let result = await axios.get(`/api/plugin/mdConfig/gen?interfaceId=${interfaceId}`);
|
||||||
|
if (result.data) {
|
||||||
|
this.setState({
|
||||||
|
render_data: result.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async preCopy(code) {
|
||||||
|
copy(code)
|
||||||
|
message.success("复制成功")
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
let render_vide = [];
|
||||||
|
if (this.state.render_data) {
|
||||||
|
render_vide.push(<pre key="md"><span className='btn-pre-copy' onClick={()=>this.preCopy(this.state.render_data.data)}>复制代码</span>{this.state.render_data.data + "\n"}</pre>)
|
||||||
|
|
||||||
|
}
|
||||||
|
console.log(render_vide)
|
||||||
|
return (
|
||||||
|
<div className="project-services">
|
||||||
|
<section className="news-box m-panel">
|
||||||
|
<div className="token">
|
||||||
|
{render_vide}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = withRouter(MDTemplateServices);
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
.project-services {
|
||||||
|
margin: 0;
|
||||||
|
pre {
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pre{
|
||||||
|
position: relative;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
pre .btn-pre-copy{
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
color: hsla(0,0%,54.9%,.8);
|
||||||
|
transition: color .1s;
|
||||||
|
}
|
||||||
@@ -17,6 +17,13 @@ module.exports = function(){
|
|||||||
path: 'mdConfig/get',
|
path: 'mdConfig/get',
|
||||||
action: 'getConfig'
|
action: 'getConfig'
|
||||||
});
|
});
|
||||||
|
// 配置信息
|
||||||
|
addRouter({
|
||||||
|
controller: exportMarkdownController,
|
||||||
|
method: 'get',
|
||||||
|
path: 'mdConfig/gen',
|
||||||
|
action: 'mdGen'
|
||||||
|
});
|
||||||
addRouter({
|
addRouter({
|
||||||
controller: exportMarkdownController,
|
controller: exportMarkdownController,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import './Services.scss';
|
|||||||
import {withRouter} from "react-router-dom";
|
import {withRouter} from "react-router-dom";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {message} from "antd";
|
import {message} from "antd";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
|
||||||
@connect(
|
@connect(
|
||||||
state => {
|
state => {
|
||||||
@@ -47,7 +48,7 @@ class Services extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async preCopy(code) {
|
async preCopy(code) {
|
||||||
await navigator.clipboard.writeText(code)
|
copy(code)
|
||||||
message.success("复制成功")
|
message.success("复制成功")
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
Reference in New Issue
Block a user