diff --git a/build.bat b/build.bat index 7fd3febe9f43817ff5a76776abc60e2b7d1357d7..2f7d9715456d2eeeac7c157866063c14e4fef329 100755 --- a/build.bat +++ b/build.bat @@ -4,7 +4,7 @@ set dist_dir=dist set app_name=torna -set version="1.14.5" +set version="1.15.0" set build_folder=%app_name%-%version% diff --git a/build.sh b/build.sh index 1e424b71e325cbb61707e907cee4a8313a8601df..2c482a8196a1f09f128a1815631466cae766711d 100644 --- a/build.sh +++ b/build.sh @@ -6,7 +6,7 @@ dist_dir="dist" # 执行文件名称 app_name="torna" -version="1.14.5" +version="1.15.0" build_folder="${app_name}-${version}" diff --git a/changelog.md b/changelog.md index 53ed17b0ab6de29caa9f0efcd57cdde67cf5b15f..28e77b4d9a8b09b74597f6a9bf5969fa1e53bd1d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,16 @@ # 更新日志 +## 1.15.0 + +- 【新增】新增分享配置时可选调试环境 [pr](https://gitee.com/durcframework/torna/pulls/28) +- 【新增】接口文档编辑和查看描述以及备注的地方使用富文本编辑器 [pr](https://gitee.com/durcframework/torna/pulls/32) +- 【新增】调试页面新增自定义修改请求类型或者参数 [#I545M6](https://gitee.com/durcframework/torna/issues/I545M6) +- 【优化】推送失败打印具体文档信息 +- 【优化】代理调试新增对https的支持 [pr](https://gitee.com/durcframework/torna/pulls/30) +- 【修复】postman上传get请求类型失败 [pr](https://gitee.com/durcframework/torna/pulls/31) +- 【修复】编辑文档响应参数的时候敲回车会报错 [#I57TQ3](https://gitee.com/durcframework/torna/issues/I57TQ3) +- 【修复】用户为空间成员,非项目成员;浏览模式下访问公开项目显示以上异常 [#I57UMS](https://gitee.com/durcframework/torna/issues/I57UMS) + ## 1.14.5 - 【修复】修复导出和query参数展示bug diff --git a/front/src/components/DocExportDialog/index.vue b/front/src/components/DocExportDialog/index.vue index 3e3867781688cc3e3b7546d464ce8f0f2099f70c..0e22c02ed97285b87a2b69316fce6f4ab9ea3482 100644 --- a/front/src/components/DocExportDialog/index.vue +++ b/front/src/components/DocExportDialog/index.vue @@ -23,6 +23,7 @@ html markdown + word @@ -52,7 +53,8 @@ const EXPORT_STYLE = { } const EXPORT_TYPE = { HTML: 'html', - MARKDOWN: 'md' + MARKDOWN: 'md', + WORD: 'word' } export default { components: { DocTree }, @@ -113,6 +115,13 @@ export default { ExportUtil.exportMarkdownMultiPages(docInfoList) } break + case EXPORT_TYPE.WORD: + if (style === EXPORT_STYLE.ALL_IN_ONE) { + ExportUtil.exportWordAllInOne(docInfoList) + } else { + ExportUtil.exportWordMultiPages(docInfoList) + } + break default: } } diff --git a/front/src/utils/convert-word.js b/front/src/utils/convert-word.js new file mode 100644 index 0000000000000000000000000000000000000000..17646dc9923413f8c1504ddf71cc4d0f8945e5ca --- /dev/null +++ b/front/src/utils/convert-word.js @@ -0,0 +1,213 @@ +import { + convert_tree, + create_response_example, + get_effective_url, + get_style_config, init_docInfo, + StringBuilder +} from '@/utils/common' +import { isDubbo, isHttp, isShowRequestExample } from '@/utils/convert-common' +import { Enums } from '@/utils/enums' + +export const word_wrapper = ` + + + + + + + Print + {body}` + +const WordUtil = { + toWordByData(docInfoList, title) { + // title = title || $ts('document') + const treeData = convert_tree(docInfoList, '') + const content = new StringBuilder() + const appendHtml = (doc_info) => { + init_docInfo(doc_info) + content.append(WordUtil.toWord(doc_info)) + } + treeData.forEach(docInfo => { + const children = docInfo.children + if (children && children.length > 0) { + // 一级标题 + content.append(`

${docInfo.name}

`) + children.forEach(child => { + appendHtml(child) + }) + } else { + appendHtml(docInfo) + } + }) + return content.toString() + }, + toWord(docInfo) { + const sb = new StringBuilder() + sb.append(`

${docInfo.name}

`) + const appendCode = (str) => { + sb.append('') + sb.append(`\n
\n${str}\n
\n`) + sb.append('
') + } + // 维护人 + docInfo.author && sb.append(`

${$ts('maintainer')}:${docInfo.author}

`) + // URL + if (isHttp(docInfo)) { + sb.append(`

URL

`) + const debugEnvs = docInfo.debugEnvs || [] + if (debugEnvs.length > 0) { + const ul = new StringBuilder('') + sb.append(ul.toString()) + } else { + sb.append(`${docInfo.httpMethod} ${docInfo.url}`) + } + } else if (isDubbo(docInfo)) { + sb.append(`

${$ts('method')}:${docInfo.url}

`) + } + // 描述 + sb.append(`

${$ts('description')}:${docInfo.description}

`) + + isHttp(docInfo) && sb.append(`

ContentType:${docInfo.contentType}

`) + + if (isHttp(docInfo)) { + if (docInfo.pathParams && docInfo.pathParams.length > 0) { + sb.append(`

${$ts('pathVariable')}

`) + sb.append(createTable(docInfo.pathParams, Enums.PARAM_STYLE.path)) + } + if (docInfo.headerParams && docInfo.headerParams.length > 0) { + sb.append(`

${$ts('requestHeader')}

`) + sb.append(createTable(docInfo.headerParams, Enums.PARAM_STYLE.header)) + } + } + sb.append(`

${$ts('requestParams')}

`) + if (docInfo.queryParams && docInfo.queryParams.length > 0) { + sb.append('
Query Parameter
') + sb.append(createTable(docInfo.queryParams, Enums.PARAM_STYLE.request)) + } + if (docInfo.requestParams && docInfo.requestParams.length > 0) { + sb.append('
Body Parameter
') + sb.append(createTable(docInfo.requestParams, Enums.PARAM_STYLE.request)) + } + if (isShowRequestExample(docInfo)) { + sb.append(`

${$ts('requestExample')}

`) + const requestExample = create_response_example(docInfo.requestParams) + appendCode(JSON.stringify(requestExample, null, 4)) + } + sb.append(`

${$ts('responseParam')}

`) + sb.append(createTable(docInfo.responseParams, Enums.PARAM_STYLE.response)) + + if (isHttp(docInfo)) { + sb.append(`

${$ts('responseExample')}

`) + const responseExample = create_response_example(docInfo.responseParams) + appendCode(JSON.stringify(responseExample, null, 4)) + } + + sb.append(`

${$ts('errorCode')}

`) + sb.append(createTable(docInfo.errorCodeParams, Enums.PARAM_STYLE.code)) + return sb.toString() + } +} + +function createTable(params, style) { + if (!params || params.length === 0) { + return $ts('empty') + } + const rowConfig = get_style_config()[style + ''] + if (!rowConfig) { + return '' + } + const headers = rowConfig.map(config => config.label) + const headerContent = `\n${createHeader(headers)}` + const trContent = `\n${createBody(params, rowConfig)}` + const tableContent = [ + '\n', + headerContent, + trContent, + '\n
' + ] + return tableContent.join('') +} + +function createHeader(tds) { + const thHtml = [] + tds.forEach(content => { + thHtml.push(thWrapper(content)) + }) + return `\n${thHtml.join('')}\n` +} + +const thWrapper = (content) => { + return `${content}\n` +} + +function createBody(params, rowConfig, prefix = '', level = 1) { + let rows = [] + for (const param of params) { + const tds = [] + for (const config of rowConfig) { + let value = param[config.prop] + if (config.prop === 'required') { + value = value ? $ts('yes') : $ts('no') + } + tds.push(value) + } + rows.push(createBodyTr(tds, prefix, level)) + if (param.children && param.children.length > 0) { + const childrenRows = createBody(param.children, rowConfig, '└ ', level + 1) + rows = rows.concat(childrenRows) + } + } + return rows.join('\n') +} + +function createBodyTr(tds, prefix, level) { + if (level > 1) { + const padding = [] + console.log('level:', level) + console.log('cishu :', Math.pow(level, 2)) + for (let i = 1; i < level; i++) { + padding.push(' ') + } + prefix = padding.join('') + prefix + } + const tdHtml = [] + tds.forEach((content, index) => { + if (index === 0) { + content = prefix + content + } + tdHtml.push(tdWrapper(content)) + }) + return `\n${tdHtml.join('')}\n` +} + +const tdWrapper = (content) => { + return `${content}\n` +} +export default WordUtil diff --git a/front/src/utils/export.js b/front/src/utils/export.js index 45ab92ed73d1fa8c47c128ca5ff5a95c532dfca6..6596a78704c732d4c85651e957a1565b09724b4a 100644 --- a/front/src/utils/export.js +++ b/front/src/utils/export.js @@ -1,6 +1,7 @@ import JSZip from 'jszip' import HtmlUtil from '@/utils/convert-html' import MarkdownUtil from '@/utils/convert-markdown' +import WordUtil, { word_wrapper } from '@/utils/convert-word' import { convert_tree, download_text, format_string, init_docInfo } from '@/utils/common' import { saveAs } from 'file-saver' @@ -141,6 +142,21 @@ const ExportUtil = { }) }) }, + /** + * 导出一个页面为word + * @param docInfo + */ + exportWordSinglePage(docInfo) { + export_single_page(docInfo, docInfo => { + return `${docInfo.name}-${new Date().getTime()}.doc` + }, docInfo => { + const content = WordUtil.toWord(docInfo) + return format_string(word_wrapper, { + title: docInfo.name, + body: content + }) + }) + }, /** * 导出全部markdown为单页 * @param docInfoList docInfoList @@ -158,6 +174,32 @@ const ExportUtil = { return `${docInfo.name}.md` }, MarkdownUtil.toMarkdown) }, + /** + * 导出全部 word 为单页 + * @param docInfoList docInfoList + */ + exportWordAllInOne(docInfoList) { + const content = WordUtil.toWordByData(docInfoList) + const html = format_string(word_wrapper, { + body: content + }) + download_text(`export-${new Date().getTime()}.doc`, html) + }, + /** + * 导出全部 word 为多页 + * @param docInfoList docInfoList + */ + exportWordMultiPages(docInfoList) { + do_export_multi_docs(docInfoList, docInfo => { + return `${docInfo.name}.doc` + }, docInfo => { + const content = WordUtil.toWord(docInfo) + return format_string(word_wrapper, { + title: docInfo.name, + body: content + }) + }) + }, /** * 导出全部Html为单页 * @param docInfoList docInfoList diff --git a/front/src/utils/global.js b/front/src/utils/global.js index d71eb254d151690216ef1e88af2594b75f661580..ef752252455996c7cf8d7b00b093f673405413bd 100644 --- a/front/src/utils/global.js +++ b/front/src/utils/global.js @@ -18,7 +18,7 @@ import { Enums } from './enums' import { add_init } from './init' // eslint-disable-next-line -const VERSION="1.14.5" +const VERSION="1.15.0" const SPACE_ID_KEY = 'torna.spaceid' const PROJECT_ID_KEY = 'torna.projectid' const TORNA_FROM = 'torna.from' diff --git a/front/src/utils/i18n/languages/en-us.js b/front/src/utils/i18n/languages/en-us.js index 7b6e4a86f3ad0ca69364a2bef57a84d3442dfbc1..dec3c33ef20b184c7661bf51277ae8f89acd17b0 100644 --- a/front/src/utils/i18n/languages/en-us.js +++ b/front/src/utils/i18n/languages/en-us.js @@ -288,6 +288,7 @@ const MAPPING = { 'clickSubscribe': 'Click Subscribe', 'exportMarkdown': 'As markdown', 'exportHtml': 'As html', + 'exportWord': 'As word', 'createdOn': 'Created on', 'lastModifiedBy': 'last modified on', 'noHeader': 'No header', diff --git a/front/src/utils/i18n/languages/zh-cn.js b/front/src/utils/i18n/languages/zh-cn.js index 1d23c6bdc3e149d95f180d79bde81b54353973bc..4d5e90c782f0898318eecb0787ad0cb157282957 100644 --- a/front/src/utils/i18n/languages/zh-cn.js +++ b/front/src/utils/i18n/languages/zh-cn.js @@ -289,6 +289,7 @@ const MAPPING = { 'clickSubscribe': '点击关注', 'exportMarkdown': '导出markdown', 'exportHtml': '导出html', + 'exportWord': '导出word', 'createdOn': '创建于', 'lastModifiedBy': '最后修改于', 'noHeader': '无Header', diff --git a/front/src/views/doc/DocView/index.vue b/front/src/views/doc/DocView/index.vue index 3fb1b04a99073623a458fb866687854651ed289c..67c73f196e9826a1314fe60a83bd40b32bd9f551 100644 --- a/front/src/views/doc/DocView/index.vue +++ b/front/src/views/doc/DocView/index.vue @@ -20,6 +20,7 @@ {{ $ts('exportMarkdown') }} {{ $ts('exportHtml') }} + {{ $ts('exportWord') }} @@ -330,6 +331,9 @@ export default { onExportHtml() { ExportUtil.exportHtmlSinglePage(this.docInfo) }, + onExportWord() { + ExportUtil.exportWordSinglePage(this.docInfo) + }, onSubscribe() { if (!this.isSubscribe) { this.post('/user/subscribe/doc/subscribe', { sourceId: this.docInfo.id }, resp => { diff --git a/front/src/views/doc/DubboView/index.vue b/front/src/views/doc/DubboView/index.vue index 60914fa3384cea2a8f00c2c2f21f340a435b315c..bfb8c4ca0d2ab8b8594ac24c787ec4b11ee9ca95 100644 --- a/front/src/views/doc/DubboView/index.vue +++ b/front/src/views/doc/DubboView/index.vue @@ -19,6 +19,7 @@ {{ $ts('exportMarkdown') }} {{ $ts('exportHtml') }} + {{ $ts('exportWord') }} @@ -178,6 +179,9 @@ export default { onExportHtml() { ExportUtil.exportHtmlSinglePage(this.docInfo) }, + onExportWord() { + ExportUtil.exportWordSinglePage(this.docInfo) + }, onSubscribe() { if (!this.isSubscribe) { this.post('/user/subscribe/doc/subscribe', { sourceId: this.docInfo.id }, resp => { diff --git a/pom.xml b/pom.xml index 8d29df9b4efd164170dfbe92cd0d3e4fe987a2f0..6287f884bb6f87a77a749edbba79a3abed1be17f 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ - 1.14.5 + 1.15.0 1.8 diff --git a/release.sh b/release.sh index b8d5019f3d354d7b731ccad242b91e0063558221..fd2e6ff1cb7373b0e39de85adaaeb1ffac70d568 100644 --- a/release.sh +++ b/release.sh @@ -6,7 +6,7 @@ dist_dir="dist" # 执行文件名称 app_name="torna" -version="1.14.5" +version="1.15.0" build_folder="${app_name}-${version}"