本来是想使用一下Monaco Editor 做个在线json-schema转ts。
后端接口文档提供了json-schema数据直接转成ts就可以不用写了。
json-schema数据转ts有现成的npm,但是json-schema-to-typescript
插件是在node下的。
其实我就想使用他的compile,只想通过浏览器就好了,找了现有的在线json-schema转ts,转换后调整一下可以用
Online JSONSchema to TypeScript Converter
所以改写成转换数据工具
提供转的方法和要转换的数据最终输出想要的数据,可能觉得麻烦,没必要,但是我觉得积少成多,经常处理多了就是通用
例如1
平时产品提供文字,要转成下拉框数据
'数据1,数据2,数据3,数据4' 转成[{ "label": "数据1", "value": "item" }, { "label": "数据2", "value": "item" }, { "label": "数据3", "value": "item" }, { "label": "数据4", "value": "item" }]
特别数据多的时候感觉有点麻烦就可以用上
例如2
菜单前端通过vscode 连数据库,然后前端去维护的,每次在开发环境可以一个一个弹框添加没啥问题,问题到其他环境还要一个一个加太麻烦了,直接根据菜单特征生成sql
路由文件路径:default/rule/release/manual/
路由名称:manualRelease
路由路径:/default/rule/release/manual/:rule_id
菜单名称:mmm
上级id:29
[
{
"cname": "'mmm'",
"path": "'/default/rule/release/manual/:rule_id'",
"component": "'default/rule/release/manual/'",
"name": "'manualRelease'",
"pid": 29
}
]
输出
INSERT INTO`menu`(`pid`, `name`, `cname`, `image`, `description`, `path`, `component`, `order_no`, `created_at`, `updated_at`, `deleted_at`)VALUES(29, 'manualRelease', 'ccc', '', '', '/default/rule/release/manual/:rule_id', 'default/rule/release/manual/',0, '2024-05-23 18:15:11', '2024-05-23 18:15:11', '1000-01-01 00:00:00')
所以就写了个这么个东西
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/loader.js"></script>
<script>
require.config({
paths: {
vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/',
},
});
window.MonacoEnvironment = {
getWorkerUrl: function (workerId, label) {
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
self.MonacoEnvironment = {
baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/'
};
importScripts('https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/base/worker/workerMain.js');`)}`;
},
};
require(['vs/editor/editor.main'], function () {
});
</script>
</head>
<style>
#app {
display: flex;
flex-direction: column;
height: 100vh;
}
.editor-wrapper {
flex: 1;
display: flex;
flex-wrap: wrap;
}
#monaco-editor-wrapper,
#monaco-editor-towrapper {
flex: 1;
height: 50%;
width: 50%;
}
#monaco-editor-fun {
width: 100%;
height: 30%;
}
#select-tag {
display: flex;
flex-wrap: wrap;
margin-top: 10px;
}
.list-item {
border: 1px solid #FFE0EB;
padding: 4px 10px;
margin: 0 10px 10px 0;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.list-item-active {
background: #FFE0EB;
}
.button-wrapper {
width: 100%;
}
button {
background: transparent;
border: 1px solid #FFE0EB;
}
</style>
<body>
<div id="app">
<div>
<input id="input-value" type="text" placeholder="请输入字符串" />
<button id="add-button">添加转换方法</button>
<div id="select-tag">
</div>
</div>
<div class="editor-wrapper">
<div id="monaco-editor-fun"></div>
<div class="button-wrapper">
<button id="transform-button">转换</button>
</div>
<div id="monaco-editor-wrapper"></div>
<div id="monaco-editor-towrapper"></div>
</div>
</div>
<script>
let mapValue = [{
key: 'stringToSelect',
name: ',字符串转select数据',
value: '地铁,公交,外卖,快递,其他',
fun: function transformData(value) {
let arr = []
value.split(",").forEach((item) => {
arr.push({ label: item, value: 'item' })
})
return arr
}
}, {
key: 'arraryToSelect',
name: '二维数组转select数据',
value: [['subway', '地铁'], ['bus', '公交']],
fun: function transformData(value) {
let arr = []
value.forEach((item) => {
arr.push({ label: item[1], value: item[0] })
})
return arr
}
}, {
key: 'routermenu',
name: '提供路由基本信息生成添加菜单sql',
value: [{
cname: "'ccc'",
path: "'/default/rule/release/manual/:rule_id'",
component: "'default/rule/release/manual/'",
name: "'manualRelease'",
pid: 29
}],
fun: function transformData(value) {
let getCurDate = () => {
let now = new Date();
let month = now.getMonth() + 1; // 注意月份是从0开始的,所以加1
let day = now.getDate();
let hour = now.getHours();
let minute = now.getMinutes();
let second = now.getSeconds();
// 如果需要两位数表示,可以填充前导0
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute : minute;
second = second < 10 ? '0' + second : second;
return `${now.getFullYear()}-${month}-${day} ${hour}:${minute}:${second}`
}
let formatSql = (dat) => {
const {
id,
pid = "''",
name,
cname,
image = "''",
description = "''",
path,
component,
order_no = 0,
created_at = "'" + getCurDate() + "'",
updated_at = "'" + getCurDate() + "'",
deleted_at = "'1000-01-01 00:00:00'" } = dat
return `(${pid},${name},${cname},${image},${description},${path},${component},${order_no},${created_at},${updated_at},${deleted_at})`
}
let getSql = (arr) => {
let str = ''
arr.forEach((item, index) => {
str += formatSql(item) + (index !== arr.length - 1 ? ',' : '')
})
let a = "INSERT INTO" +
" `menu` (" +
"`pid`, `name`, `cname`, `image`, `description`, `path`, `component`, `order_no`, `created_at`, `updated_at`, `deleted_at`" +
")" +
"VALUES";
return a + str
}
return getSql(value)
}
}]
// 初始tag列表
let initDom = false
// 当前tag选中
let curAct = 'stringToSelect'
let editorInstance = null
let toInstance = null
let toInstanceFun = null
// 初始编辑器实例
const initEditorInstance = () => {
if (!editorInstance) {
editorInstance = initEditor('monaco-editor-wrapper')
}
if (!toInstance) {
toInstance = initEditor('monaco-editor-towrapper', { language: 'javascript' })
}
if (!toInstanceFun) {
toInstanceFun = initEditor('monaco-editor-fun', { language: 'javascript' })
}
reLayout()
}
// 重新渲染编辑器
const reLayout = () => {
if (editorInstance) {
editorInstance.layout();
}
if (toInstance) {
toInstance.layout();
}
if (toInstanceFun) {
toInstanceFun.layout();
}
}
window.onload = function () {
initEditorInstance()
setViewModel({ funV: mapValue[0].fun, original: mapValue[0].value, modified: `` })
transformFun()
// 转换点击
document.getElementById('transform-button').addEventListener('click', function () {
transformFun()
})
// 新增tag
document.getElementById('add-button').addEventListener('click', function () {
let nameVal = document.getElementById('input-value').value
if (nameVal) {
let isExist = mapValue.find(item => item.name === nameVal)
if (isExist) {
alert('该转换名已存在')
return
}
transformFun().then((re) => {
let value = editorInstance.getValue()
let funVal = toInstanceFun.getValue()
let addItemObj = {
key: 'custom-' + Math.random().toString(36).substring(2, 15),
name: nameVal || '自定义' + mapValue.length,
value: JSON.parse(value),
fun: funVal
}
mapValue.push(addItemObj)
addItem(addItemObj, document.querySelector('#select-tag'))
})
} else {
alert('请输入转换名')
}
})
forData("select-tag", mapValue)
}
const initEditor = (id, config = {}) => {
return window.monaco.editor.create(document.getElementById(id), {
theme: 'vs', // 编辑器主题:vs, hc-black, or vs-dark
autoIndent: true, // 自动缩进
originalEditable: true,
language: 'json',
formatOnType: true, // 在输入后自动格式化
formatOnPaste: true, // 在粘贴后自动格式化
wordWrap: 'on',
diffCodeLens: false,
...config
});
}
// 设置变化值
const setViewModel = ({ funV, original, modified }) => {
let tpmFunV = typeof funV === 'string' ? funV : `${funV}`
funV && tpmFunV && (toInstanceFun.setValue(tpmFunV))
original && editorInstance.setValue(JSON.stringify(original));
modified && toInstance.setValue(modified)
setTimeout(() => {
toInstanceFun.getAction('editor.action.formatDocument').run();
toInstance.getAction('editor.action.formatDocument').run();
editorInstance.getAction('editor.action.formatDocument').run();
}, 300)
}
// 转换
const transformFun = function () {
var value = editorInstance.getValue();
let funVal = toInstanceFun.getValue()
return new Promise((resolve, reject) => {
try {
if (!funVal) return reject('函数不能为空')
eval(funVal)
if (typeof transformData !== 'function') return reject('函数不能为空')
let dat = transformData(JSON.parse(value))
setViewModel({ modified: typeof dat === "string" ? dat : JSON.stringify(dat) })
resolve('转换成功')
} catch (error) {
console.error(error)
return reject(error)
}
})
}
const forData = (id, data) => {
let listId = document.querySelector('#' + id)
for (let i = 0; i < listId.childNodes.length; i++) {
listId.childNodes[i].remove()
}
if (!initDom) {
listId.addEventListener('click', (e) => {
if (e.target.getAttribute('class') !== 'list-item') return
setTagAct(e.target, listId)
let curTag = mapValue.find((item) => { return item.key === e.target.getAttribute('data-key') })
setViewModel({ funV: curTag.fun, original: curTag.value, modified: `` })
transformFun()
})
}
initDom = true
// 添加子元素
for (let i = 0; i < data.length; i++) {
addItem(data[i], listId)
}
}
// 设置tag选中
const setTagAct = (target, dom) => {
dom.childNodes.forEach(item => {
item.classList.remove('list-item-active')
})
let key = target.getAttribute('data-key')
target.classList.add('list-item-active');
curAct = key
}
// 新增tag
const addItem = (obj, listId) => {
let option = document.createElement('div');
option.setAttribute('class', 'list-item');
if (obj.key === curAct) {
option.setAttribute('class', 'list-item list-item-active');
}
option.setAttribute('data-key', obj.key);
option.innerText = obj.name;
listId.appendChild(option);
}
window.addEventListener('resize', () => {
reLayout()
});
</script>
</body>
</html>
也不知道对你们有没有帮助,就先放着吧