|
@@ -1,509 +0,0 @@
|
|
|
-<script setup lang="ts">
|
|
|
-import {useVModel} from "@vueuse/core";
|
|
|
-import {nextTick, onMounted, onUnmounted, ref, Ref, unref} from 'vue'
|
|
|
-import type {TDataBaseSqlApi} from "@/ts-type/data-base-type";
|
|
|
-import * as monaco from "monaco-editor";
|
|
|
-import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
|
|
|
-import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
|
|
|
-import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
|
|
|
-import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
|
|
|
-import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
|
|
|
-import XcElOption from "@/components/xiao-chan/xc-el-option/XcElOption.vue";
|
|
|
-import XEUtils from "xe-utils";
|
|
|
-import {publishApi, testSqlApi, updateSqlApi} from "@/api/data-base/sql-api";
|
|
|
-import {FormInstance} from "element-plus";
|
|
|
-import {xcMessage} from "@/utils/xiaochan-element-plus";
|
|
|
-import {copyStrFunc, isDev} from "@/utils/public";
|
|
|
-import {windowSizeStore} from "@/utils/store-public";
|
|
|
-import GenericTokenParser from "@/utils/genergic-token-parser";
|
|
|
-
|
|
|
-// 代码提示
|
|
|
-self.MonacoEnvironment = {
|
|
|
- getWorker(_: string, label: string) {
|
|
|
- if (label === 'json') {
|
|
|
- return JsonWorker();
|
|
|
- }
|
|
|
- if (label === 'css' || label === 'scss' || label === 'less') {
|
|
|
- return CssWorker();
|
|
|
- }
|
|
|
- if (label === 'html' || label === 'handlebars' || label === 'razor') {
|
|
|
- return HtmlWorker();
|
|
|
- }
|
|
|
- if (['typescript', 'javascript'].includes(label)) {
|
|
|
- return TsWorker();
|
|
|
- }
|
|
|
- return EditorWorker();
|
|
|
- },
|
|
|
-}
|
|
|
-
|
|
|
-const props = defineProps({
|
|
|
- modelValue: {
|
|
|
- type: Object,
|
|
|
- default: null
|
|
|
- },
|
|
|
- dataBase: {
|
|
|
- type: Array,
|
|
|
- default: []
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-const urlPrefix = isDev ? `http://172.16.30.61:8706/dataBase/api` : `http://172.16.32.160:8077/dataBase/api`;
|
|
|
-
|
|
|
-const emits = defineEmits(['update:modelValue'])
|
|
|
-const modelValue: Ref<TDataBaseSqlApi> = useVModel(props, 'modelValue', emits) as Ref<TDataBaseSqlApi>
|
|
|
-const sqlEditor = ref<HTMLDivElement>()
|
|
|
-const drawerDialog = ref(false)
|
|
|
-const pageSizeList = [{code: 30, name: '30'}, {code: 50, name: '50'}, {code: 100, name: '100'}]
|
|
|
-
|
|
|
-const testParams = ref({})
|
|
|
-
|
|
|
-let monacoEditor = null
|
|
|
-
|
|
|
-function handleSave() {
|
|
|
- const dataTemp = prepareData()
|
|
|
- console.log(dataTemp)
|
|
|
- updateSqlApi(dataTemp)
|
|
|
-}
|
|
|
-
|
|
|
-const testDialog = ref(false)
|
|
|
-const testFormRef = ref<FormInstance>()
|
|
|
-const testRules = ref({})
|
|
|
-const testResData = ref<{
|
|
|
- code?: string,
|
|
|
- message?: string
|
|
|
- data?: any
|
|
|
-}>({})
|
|
|
-
|
|
|
-function handleDialogOpen() {
|
|
|
- testRules.value = {}
|
|
|
- testParams.value = {}
|
|
|
- modelValue.value.configJson.params.forEach(item => {
|
|
|
- testParams.value[item.key] = item.defaultValue || ''
|
|
|
- if (item.required) {
|
|
|
- testRules.value[item.key] = [{
|
|
|
- required: true,
|
|
|
- message: '此项必填',
|
|
|
- trigger: 'change',
|
|
|
- }]
|
|
|
- }
|
|
|
- })
|
|
|
- if (modelValue.value.configJson.pageInfo.page) {
|
|
|
- testParams.value['currentPage'] = 1
|
|
|
-
|
|
|
- testRules.value['currentPage'] = [{
|
|
|
- required: true,
|
|
|
- message: '此项必填',
|
|
|
- trigger: 'change',
|
|
|
- }]
|
|
|
-
|
|
|
- }
|
|
|
- testDialog.value = true
|
|
|
-}
|
|
|
-
|
|
|
-function prepareData() {
|
|
|
- const data = XEUtils.clone(modelValue.value, true)
|
|
|
- data.config = XEUtils.toJSONString(data.configJson)
|
|
|
- return data
|
|
|
-}
|
|
|
-
|
|
|
-async function handleTest() {
|
|
|
- await testFormRef.value.validate()
|
|
|
-
|
|
|
- const data = prepareData()
|
|
|
- data.params = unref(testParams)
|
|
|
- data.currentDataSource = dataSource.value
|
|
|
-
|
|
|
- testSqlApi(data).then(res => {
|
|
|
- console.log(res)
|
|
|
- testResData.value.code = '200'
|
|
|
- testResData.value.message = '成功'
|
|
|
- testResData.value.data = res
|
|
|
- }).catch((res) => {
|
|
|
- testResData.value.code = '1002'
|
|
|
- testResData.value.message = res
|
|
|
- testResData.value.data = null
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-function handlePublishApi() {
|
|
|
- modelValue.value.enable = modelValue.value.enable === 0 ? 1 : 0
|
|
|
- publishApi(modelValue.value.id, modelValue.value.enable)
|
|
|
-}
|
|
|
-
|
|
|
-function handleAddParams() {
|
|
|
- modelValue.value.configJson.params.push({
|
|
|
- key: '',
|
|
|
- required: false,
|
|
|
- defaultValue: '',
|
|
|
- describe: ''
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-function handleParamsClose(index) {
|
|
|
- modelValue.value.configJson.params.splice(index, 1)
|
|
|
-}
|
|
|
-
|
|
|
-const paramsFormMap = new Map<string, FormInstance>()
|
|
|
-const paramsFormRules = {
|
|
|
- key: [{
|
|
|
- required: true,
|
|
|
- message: '此项必填',
|
|
|
- trigger: 'change',
|
|
|
- }]
|
|
|
-}
|
|
|
-
|
|
|
-function setParamsFormMap(name: string, ref: FormInstance) {
|
|
|
- paramsFormMap.set(name, ref)
|
|
|
-}
|
|
|
-
|
|
|
-async function drawerClose(done: (cancel?: boolean) => void) {
|
|
|
- for (let key of paramsFormMap.keys()) {
|
|
|
- const value = paramsFormMap.get(key)
|
|
|
- if (value == null) break
|
|
|
- try {
|
|
|
- await value.validate();
|
|
|
- } catch (e) {
|
|
|
- xcMessage.error('请求参数中,有必填项不能为空。')
|
|
|
- done(true)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
- done(false)
|
|
|
-}
|
|
|
-
|
|
|
-function copyUrl(url: string) {
|
|
|
- copyStrFunc(url)
|
|
|
-}
|
|
|
-
|
|
|
-function fillingFunc() {
|
|
|
- const addKeys = new Set()
|
|
|
-
|
|
|
- new GenericTokenParser('#{', "}", (content) => {
|
|
|
- addKeys.add(content)
|
|
|
- return ""
|
|
|
- }).parse(modelValue.value.sql)
|
|
|
-
|
|
|
- new GenericTokenParser('${', "}", (content) => {
|
|
|
- addKeys.add(content)
|
|
|
- return ""
|
|
|
- }).parse(modelValue.value.sql)
|
|
|
-
|
|
|
-
|
|
|
- const keys = new Set()
|
|
|
-
|
|
|
-
|
|
|
- modelValue.value.configJson.params.forEach(item => {
|
|
|
- keys.add(item.key)
|
|
|
- })
|
|
|
-
|
|
|
- const result1 = new Set([...addKeys].filter(x => !keys.has(x)));
|
|
|
- const result2 = new Set([...keys].filter(x => !addKeys.has(x)));
|
|
|
-
|
|
|
- XEUtils.remove(modelValue.value.configJson.params, (item) => {
|
|
|
- return result2.has(item.key)
|
|
|
- })
|
|
|
-
|
|
|
- result1.forEach(item => {
|
|
|
- const index = modelValue.value.sql.indexOf(`test="${item}`)
|
|
|
-
|
|
|
- modelValue.value.configJson.params.push({
|
|
|
- key: item,
|
|
|
- required: index === -1,
|
|
|
- describe: '',
|
|
|
- defaultValue: null
|
|
|
- })
|
|
|
- })
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-function processingOpenProperties() {
|
|
|
- fillingFunc()
|
|
|
- drawerDialog.value = true
|
|
|
-}
|
|
|
-
|
|
|
-const dataSource = ref('')
|
|
|
-
|
|
|
-onUnmounted(() => {
|
|
|
- monacoEditor.dispose()
|
|
|
-})
|
|
|
-
|
|
|
-onMounted(async () => {
|
|
|
- await nextTick()
|
|
|
- monacoEditor = monaco.editor.create(sqlEditor.value, {
|
|
|
- value: modelValue.value.sql,
|
|
|
- language: 'sql',
|
|
|
- automaticLayout: true,
|
|
|
- theme: 'vs-dark',
|
|
|
- foldingStrategy: 'indentation',
|
|
|
- formatOnType: true,
|
|
|
- renderLineHighlight: 'all',
|
|
|
- selectOnLineNumbers: true,
|
|
|
- minimap: {
|
|
|
- enabled: false,
|
|
|
- },
|
|
|
- readOnly: false,
|
|
|
- fontSize: 16,
|
|
|
- scrollBeyondLastLine: false,
|
|
|
- overviewRulerBorder: true,
|
|
|
- })
|
|
|
-
|
|
|
- monacoEditor.onDidChangeModelContent((val) => {
|
|
|
- modelValue.value.sql = monacoEditor.getValue();
|
|
|
- })
|
|
|
- dataSource.value = modelValue.value.configJson.dataSources[0]
|
|
|
-})
|
|
|
-</script>
|
|
|
-
|
|
|
-<template>
|
|
|
- <div class="api_pane-container">
|
|
|
- <div class="api_pane-header">
|
|
|
- <span style="font-size: 12px;margin: 0">
|
|
|
- 数据库:
|
|
|
- </span>
|
|
|
- <el-select v-model="modelValue.configJson.dataSources"
|
|
|
- placeholder="请选择"
|
|
|
- size="small"
|
|
|
- multiple
|
|
|
- collapse-tags
|
|
|
- style="width: 160px">
|
|
|
- <el-option v-for="item in props.dataBase" :label="item.name" :value="item.alias"/>
|
|
|
- </el-select>
|
|
|
- <el-divider direction="vertical"/>
|
|
|
- <span class="iconfont icon-baocun" @click="handleSave" title="保存"/>
|
|
|
- <span class="iconfont icon-ceshi" title="测试" @click="handleDialogOpen"></span>
|
|
|
- <el-button
|
|
|
- @click="handlePublishApi"
|
|
|
- :type="modelValue.enable ? 'warning' : 'success'">
|
|
|
- {{ modelValue.enable ? '停用' : '启用' }}
|
|
|
- </el-button>
|
|
|
- <el-divider direction="vertical"/>
|
|
|
- <el-button @click="processingOpenProperties" type="primary">属性</el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="api_pane-main">
|
|
|
- <div ref="sqlEditor" class="editor"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <el-drawer v-model="drawerDialog" title="配置" size="40%" class="api_pane-drawer" :before-close="drawerClose">
|
|
|
- <div class="api_pane-drawer-main">
|
|
|
- <div style="height: 70%; overflow: auto">
|
|
|
- <el-divider style="margin: 12px 0">
|
|
|
- 请求参数
|
|
|
- <el-button-group>
|
|
|
- <el-button text icon="Plus" @click="handleAddParams"/>
|
|
|
- <el-button @click="fillingFunc">填充</el-button>
|
|
|
- </el-button-group>
|
|
|
- </el-divider>
|
|
|
- <div v-for="(item,index) in modelValue.configJson.params" style="padding: 0 40px 0 20px">
|
|
|
- <el-divider style="margin: 10px 0" border-style="dashed" v-if="index !== 0"/>
|
|
|
- <el-form label-width="50px"
|
|
|
- :model="item"
|
|
|
- :rules="paramsFormRules"
|
|
|
- label-position="right"
|
|
|
- :ref="(el) => setParamsFormMap(`form${index}`, el)">
|
|
|
- <el-row>
|
|
|
- <el-col :span="7">
|
|
|
- <el-form-item label="名称" prop="key">
|
|
|
- <el-input v-model.trim="item.key"/>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="7">
|
|
|
- <el-form-item label="必填">
|
|
|
- <el-switch v-model.trim="item.required"/>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="10">
|
|
|
- <el-form-item label="默认值">
|
|
|
- <el-input v-model.trim="item.defaultValue"/>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
-
|
|
|
- <el-row>
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="描述">
|
|
|
- <div style="width: 100%;position: relative">
|
|
|
- <div class="params_close">
|
|
|
- <el-icon :size="18" @click="handleParamsClose(index)">
|
|
|
- <CircleClose/>
|
|
|
- </el-icon>
|
|
|
- </div>
|
|
|
- <el-input v-model.trim="item.describe"/>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div style="flex: 1 ;overflow: auto">
|
|
|
- <div style="padding: 0 20px">
|
|
|
- <el-divider style="margin: 10px 0">其他</el-divider>
|
|
|
- <el-form label-width="70px" label-position="right">
|
|
|
- <el-row :gutter="10">
|
|
|
-
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="去除空格">
|
|
|
- <el-switch v-model="modelValue.configJson.removeSpaces"></el-switch>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="请求方式">
|
|
|
- <el-select v-model="modelValue.requestMapping">
|
|
|
- <xc-el-option :data="[{code: 'GET', name: 'GET'},{code: 'POST', name: 'POST'}]"/>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- <el-col :span="24">
|
|
|
- <el-form-item label="分页">
|
|
|
- <el-switch v-model="modelValue.configJson.pageInfo.page"></el-switch>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- <el-col :span="24" v-if="modelValue.configJson.pageInfo.page">
|
|
|
- <el-form-item label="页大小">
|
|
|
- <el-select v-model="modelValue.configJson.pageInfo.pageSize">
|
|
|
- <xc-el-option :data="pageSizeList"/>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- </el-row>
|
|
|
-
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-drawer>
|
|
|
-
|
|
|
- <el-dialog title="预览" v-model="testDialog" fullscreen>
|
|
|
- <el-descriptions
|
|
|
- class="margin-top"
|
|
|
- border
|
|
|
- :title="modelValue.name"
|
|
|
- :column="3"
|
|
|
- size="small">
|
|
|
- <el-descriptions-item label="地址" :span="3">
|
|
|
- <el-select v-model="dataSource"
|
|
|
- placeholder="请选择"
|
|
|
- size="small"
|
|
|
- style="width: 120px">
|
|
|
- <el-option v-for="item in props.dataBase"
|
|
|
- :label="item.name"
|
|
|
- :disabled="!modelValue.configJson.dataSources.includes(item.alias)"
|
|
|
- :value="item.alias"/>
|
|
|
- </el-select>
|
|
|
- {{ `${urlPrefix}/${dataSource}/${modelValue.id}` }}
|
|
|
- <el-button icon="CopyDocument" circle
|
|
|
- @click="copyUrl(`${urlPrefix}/${dataSource}/${modelValue.id}`)"/>
|
|
|
- </el-descriptions-item>
|
|
|
- <el-descriptions-item label="请求方式">
|
|
|
- {{ modelValue.requestMapping }}
|
|
|
- </el-descriptions-item>
|
|
|
- <el-descriptions-item label="分页">
|
|
|
- {{ modelValue.configJson.pageInfo.page ? `分页,页大小${modelValue.configJson.pageInfo.pageSize}` : '不分页' }}
|
|
|
- </el-descriptions-item>
|
|
|
- </el-descriptions>
|
|
|
-
|
|
|
- <el-divider border-style="dashed">参数</el-divider>
|
|
|
-
|
|
|
- <el-form label-width="100px"
|
|
|
- label-position="right"
|
|
|
- :rules="testRules"
|
|
|
- :model="testParams"
|
|
|
- ref="testFormRef">
|
|
|
- <el-form-item v-for="item in modelValue.configJson.params"
|
|
|
- :label="item.key"
|
|
|
- :prop="item.key">
|
|
|
- <el-input v-model="testParams[item.key]"/>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="页码" prop="currentPage" v-if="modelValue.configJson.pageInfo.page">
|
|
|
- <el-input-number v-model="testParams.currentPage"/>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item>
|
|
|
- <el-button type="primary" @click="handleTest">测试</el-button>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
-
|
|
|
- <el-divider border-style="dashed">结果 {{ modelValue.configJson.pageInfo.page ? '' : '测试环境默认10条' }}
|
|
|
- </el-divider>
|
|
|
-
|
|
|
- <div :style="{height: windowSizeStore.h / 1.8 + 'px'}" style="overflow: auto">
|
|
|
- <JsonViewer :value="testResData"
|
|
|
- style="height: 100%" copyable :expandDepth="3"/>
|
|
|
- </div>
|
|
|
-
|
|
|
-
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
-</template>
|
|
|
-
|
|
|
-<style lang="scss">
|
|
|
-.api_pane-container {
|
|
|
- display: flex;
|
|
|
- height: 100%;
|
|
|
- flex-flow: column nowrap;
|
|
|
-}
|
|
|
-
|
|
|
-.api_pane-header {
|
|
|
- line-height: 20px;
|
|
|
- font-size: 20px;
|
|
|
- padding: 5px 10px;
|
|
|
- box-sizing: border-box;
|
|
|
- border-right: 1px solid #E4E7ED;
|
|
|
- border-left: 1px solid #E4E7ED;
|
|
|
-
|
|
|
- .iconfont {
|
|
|
- cursor: pointer;
|
|
|
- margin: 0 10px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.api_pane-main {
|
|
|
- flex: 1;
|
|
|
- width: 100%;
|
|
|
-
|
|
|
- .editor {
|
|
|
- height: 100%;
|
|
|
- width: 100%;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.api_pane-database {
|
|
|
- padding: 0 10px;
|
|
|
- height: 40px;
|
|
|
-}
|
|
|
-
|
|
|
-.api_pane-drawer {
|
|
|
- .api_pane-drawer-main {
|
|
|
- height: 100%;
|
|
|
- width: 100%;
|
|
|
- overflow: auto;
|
|
|
- display: flex;
|
|
|
- flex-flow: column nowrap;
|
|
|
- }
|
|
|
-
|
|
|
- .el-drawer__header {
|
|
|
- margin-bottom: 10px;
|
|
|
- }
|
|
|
-
|
|
|
- .el-drawer__body {
|
|
|
- padding: 5px;
|
|
|
- }
|
|
|
-
|
|
|
- .params_close {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- right: -30px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- height: 100%;
|
|
|
- cursor: pointer;
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|