refactor: 数据源插件优化

This commit is contained in:
junjun 2024-07-19 10:19:27 +08:00
parent 3d9903b0f2
commit 36e93a9cf6
5 changed files with 139 additions and 699 deletions

View File

@ -141,7 +141,7 @@ const initForm = type => {
form.value.type = type
setTimeout(() => {
dsForm.value.clearValidate()
dsForm?.value?.clearValidate()
}, 0)
}

View File

@ -1,629 +0,0 @@
<script lang="ts" setup>
import { ref, reactive, toRefs, watch } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import type { FormInstance, FormRules } from 'element-plus-secondary'
import { cloneDeep } from 'lodash-es'
import type { Configuration, ApiConfiguration, SyncSetting } from './option'
import { Base64 } from 'js-base64'
import { ElMessage } from 'element-plus-secondary'
const { t } = useI18n()
const prop = defineProps({
form: {
required: false,
default() {
return reactive<{
id: number
name: string
desc: string
type: string
syncSetting?: SyncSetting
configuration?: Configuration
apiConfiguration?: ApiConfiguration[]
paramsConfiguration?: ApiConfiguration[]
}>({
id: 0,
name: '',
desc: '',
type: 'API',
apiConfiguration: []
})
},
type: Object
},
activeStep: {
required: false,
default: 1,
type: Number
}
})
const { form, activeStep } = toRefs(prop)
const state = reactive({
itemRef: []
})
const schemas = ref([])
const dsForm = ref<FormInstance>()
const defaultRule = {
name: [
{
required: true,
message: t('datasource.input_name'),
trigger: 'blur'
},
{
min: 2,
max: 64,
message: t('datasource.input_limit_2_25', [2, 64]),
trigger: 'blur'
}
]
}
const rule = ref<FormRules>(cloneDeep(defaultRule))
const api_table_title = ref('')
const editApiItem = ref()
const defaultApiItem = {
name: '',
deTableName: '',
url: '',
type: '',
serialNumber: 0,
method: 'GET',
request: {
headers: [{}],
arguments: [],
body: {
type: '',
raw: '',
kvs: []
},
authManager: {
verification: '',
username: '',
password: ''
}
},
fields: []
}
const initForm = type => {
form.value.configuration = {
dataBase: '',
jdbcUrl: '',
urlType: 'hostName',
extraParams: '',
username: '',
password: '',
host: '',
authMethod: '',
port: '',
initialPoolSize: 5,
minPoolSize: 5,
maxPoolSize: 5,
queryTimeout: 30
}
schemas.value = []
rule.value = cloneDeep(defaultRule)
setRules()
form.value.type = type
setTimeout(() => {
dsForm.value.clearValidate()
}, 0)
}
const setRules = () => {
const configRules = {
'configuration.jdbcUrl': [
{
required: true,
message: t('datasource.please_input_jdbc_url'),
trigger: 'blur'
}
],
'configuration.dataBase': [
{
required: true,
message: t('datasource.please_input_data_base'),
trigger: 'blur'
}
],
'configuration.authMethod': [
{
required: true,
message: t('datasource.please_select_oracle_type'),
trigger: 'blur'
}
],
'configuration.username': [
{
required: true,
message: t('datasource.please_input_user_name'),
trigger: 'blur'
}
],
'configuration.password': [
{
required: true,
message: t('datasource.please_input_password'),
trigger: 'blur'
}
],
'configuration.host': [
{
required: true,
message: t('datasource._ip_address'),
trigger: 'blur'
}
],
'configuration.extraParams': [
{
required: false,
message: t('datasource.please_input_url'),
trigger: 'blur'
}
],
'configuration.port': [
{
required: true,
message: t('datasource.please_input_port'),
trigger: 'blur'
}
],
'configuration.initialPoolSize': [
{
required: true,
message: t('common.inputText') + t('datasource.initial_pool_size'),
trigger: 'blur'
}
],
'configuration.minPoolSize': [
{
required: true,
message: t('common.inputText') + t('datasource.min_pool_size'),
trigger: 'blur'
}
],
'configuration.maxPoolSize': [
{
required: true,
message: t('common.inputText') + t('datasource.max_pool_size'),
trigger: 'blur'
}
],
'configuration.queryTimeout': [
{
required: true,
message: t('common.inputText') + t('datasource.query_timeout'),
trigger: 'blur'
}
]
}
if (['oracle', 'sqlServer', 'pg', 'redshift', 'db2'].includes(form.value.type)) {
configRules['configuration.schema'] = [
{
required: true,
message: t('datasource.please_choose_schema'),
trigger: 'blur'
}
]
}
if (form.value.type === 'oracle') {
configRules['configuration.connectionType'] = [
{
required: true,
message: t('datasource.connection_mode'),
trigger: 'change'
}
]
}
rule.value = { ...cloneDeep(configRules), ...cloneDeep(defaultRule) }
}
watch(
() => form.value.type,
val => {
if (val !== 'API') {
rule.value = cloneDeep(defaultRule)
setRules()
}
},
{
immediate: true
}
)
const activeName = ref('table')
const showPriority = ref(false)
const submitForm = () => {
dsForm.value.clearValidate()
return dsForm.value.validate
}
const clearForm = () => {
return dsForm.value.clearValidate()
}
const resetForm = () => {
dsForm.value.resetFields()
}
const showSchema = ref(false)
const validatorSchema = () => {
dsForm.value.validateField('configuration.schema')
}
const activeParamsName = ref('')
const activeParamsID = ref(0)
const setActiveName = val => {
gridData.value = val.fields
activeParamsName.value = val.name
activeParamsName.value = val.serialNumber
}
const gridData = ref([])
defineExpose({
submitForm,
resetForm,
initForm,
clearForm
})
</script>
<template>
<div class="editor-detail">
<div class="detail-inner create-dialog">
<el-form
ref="dsForm"
:model="form"
:rules="rule"
label-width="180px"
label-position="top"
require-asterisk-position="right"
>
<el-form-item
:label="t('auth.datasource') + t('chart.name')"
prop="name"
v-show="activeStep !== 2"
>
<el-input
v-model="form.name"
autocomplete="off"
:placeholder="t('datasource.input_name')"
/>
</el-form-item>
<el-form-item :label="t('common.description')" v-show="activeStep !== 2">
<el-input
class="description-text"
type="textarea"
:placeholder="t('common.inputText')"
v-model="form.description"
:row="10"
:maxlength="50"
show-word-limit
/>
</el-form-item>
<el-form-item
:label="t('datasource.host')"
prop="configuration.host"
v-if="form.configuration.urlType !== 'jdbcUrl'"
>
<el-input
v-model="form.configuration.host"
:placeholder="t('datasource._ip_address')"
autocomplete="off"
/>
</el-form-item>
<el-form-item
:label="t('datasource.port')"
prop="configuration.port"
v-if="form.configuration.urlType !== 'jdbcUrl'"
>
<el-input-number
v-model="form.configuration.port"
autocomplete="off"
step-strictly
class="text-left"
:min="0"
:placeholder="t('common.inputText') + t('datasource.port')"
controls-position="right"
type="number"
/>
</el-form-item>
<el-form-item
:label="t('datasource.data_base')"
prop="configuration.dataBase"
v-if="form.configuration.urlType !== 'jdbcUrl'"
>
<el-input
v-model="form.configuration.dataBase"
:placeholder="t('datasource.please_input_data_base')"
autocomplete="off"
/>
</el-form-item>
<el-form-item :label="t('datasource.user_name')" v-if="form.type !== 'presto'">
<el-input
:placeholder="t('common.inputText') + t('datasource.user_name')"
v-model="form.configuration.username"
autocomplete="off"
/>
</el-form-item>
<el-form-item :label="t('datasource.password')" v-if="form.type !== 'presto'">
<CustomPassword
:placeholder="t('common.inputText') + t('datasource.password')"
show-password
type="password"
v-model="form.configuration.password"
/>
</el-form-item>
<el-form-item
:label="t('datasource.extra_params')"
v-if="form.configuration.urlType !== 'jdbcUrl'"
>
<el-input
:placeholder="t('common.inputText') + t('datasource.extra_params')"
v-model="form.configuration.extraParams"
autocomplete="off"
/>
</el-form-item>
<span
v-if="!['es', 'api'].includes(form.type)"
class="de-expand"
@click="showPriority = !showPriority"
>{{ t('datasource.priority') }}
<el-icon>
<Icon :name="showPriority ? 'icon_down_outlined' : 'icon_down_outlined-1'"></Icon>
</el-icon>
</span>
<template v-if="showPriority">
<el-row :gutter="24" class="mb16">
<el-col :span="12">
<el-form-item
:label="t('datasource.initial_pool_size')"
prop="configuration.initialPoolSize"
>
<el-input-number
v-model="form.configuration.initialPoolSize"
controls-position="right"
autocomplete="off"
:placeholder="t('common.inputText') + t('datasource.initial_pool_size')"
type="number"
:min="0"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="t('datasource.min_pool_size')" prop="configuration.minPoolSize">
<el-input-number
v-model="form.configuration.minPoolSize"
controls-position="right"
autocomplete="off"
:placeholder="t('common.inputText') + t('datasource.min_pool_size')"
type="number"
:min="0"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :label="t('datasource.max_pool_size')" prop="configuration.maxPoolSize">
<el-input-number
v-model="form.configuration.maxPoolSize"
controls-position="right"
autocomplete="off"
:placeholder="t('common.inputText') + t('datasource.max_pool_size')"
type="number"
:min="0"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
:label="`${t('datasource.query_timeout')}(${t('common.second')})`"
prop="configuration.queryTimeout"
>
<el-input-number
v-model="form.configuration.queryTimeout"
controls-position="right"
autocomplete="off"
:placeholder="t('common.inputText') + t('datasource.query_timeout')"
type="number"
:min="0"
/>
</el-form-item>
</el-col>
</el-row>
</template>
</el-form>
</div>
</div>
</template>
<style lang="less" scoped>
.editor-detail {
width: 100%;
display: flex;
justify-content: center;
.ed-radio {
height: 22px;
}
.mb16 {
:deep(.ed-form-item) {
margin-bottom: 16px;
}
}
.execute-rate-cont {
border-radius: 4px;
margin-top: -8px;
}
.de-select {
width: 100%;
}
.ed-input-number {
width: 100%;
}
:deep(.is-controls-right > span) {
background: #fff;
}
.de-expand {
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
font-size: 14px;
font-weight: 400;
line-height: 22px;
color: var(--ed-color-primary);
cursor: pointer;
display: inline-flex;
align-items: center;
.ed-icon {
margin-left: 4px;
}
}
:deep(.ed-date-editor.ed-input) {
.ed-input__wrapper {
width: 100%;
}
width: 100%;
}
.simple-cron {
height: 32px;
.ed-select,
.ed-input-number {
width: 140px;
margin: 0 8px;
}
}
.detail-inner {
width: 800px;
padding-top: 8px;
.description-text {
:deep(.ed-textarea__inner) {
height: 92px;
}
}
.base-info {
margin: 24px 0 16px 0;
}
.left-api_params {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
border: 1px solid #bbbfc4;
width: 300px;
padding: 16px;
.name-copy {
display: none;
line-height: 24px;
margin-left: 4px;
}
.list-item_primary:hover {
.name-copy {
display: inline;
}
.label {
width: 74% !important;
}
}
}
.right-api_params {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border: 1px solid #bbbfc4;
border-left: none;
width: calc(100% - 200px);
}
.table-info-mr {
margin: 28px 0 12px 0;
.api-tabs {
:deep(.ed-tabs__nav-wrap::after) {
display: none;
}
}
}
.info-update {
height: 22px;
width: 100%;
display: flex;
align-items: center;
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px;
justify-content: center;
.update-info-line {
width: 208px;
height: 1px;
background: #bcbdbf;
margin: 0 8px;
}
.info-text,
.update-text {
padding-left: 16px;
position: relative;
color: #1f2329;
font-weight: 400;
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
font-size: 14px;
font-style: normal;
line-height: 22px;
&::before {
width: 8px;
height: 8px;
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
border: 1px solid var(--ed-color-primary);
border-radius: 50%;
}
&.active {
font-weight: 500;
}
&.active::before {
border: none;
background: var(--ed-color-primary);
}
}
}
.detail-operate {
text-align: right;
padding: 8px 0;
}
.flex-space {
display: flex;
align-items: center;
}
}
}
</style>

View File

@ -29,6 +29,8 @@ export interface Param {
id?: string
name?: string
creator?: string
isPlugin?: boolean
staticMap?: any
}
export interface Field {

View File

@ -6,7 +6,6 @@ import type { DsType } from './DsTypeList.vue'
import DsTypeList from './DsTypeList.vue'
import { useI18n } from '@/hooks/web/useI18n'
import EditorDetail from './EditorDetail.vue'
import EditorDetailPlugin from './EditorDetailPlugin.vue'
import ExcelDetail from './ExcelDetail.vue'
import { save, update, validate, latestUse, isShowFinishPage, checkRepeat } from '@/api/datasource'
import { Base64 } from 'js-base64'
@ -41,6 +40,8 @@ interface Form {
apiConfiguration?: ApiConfiguration[]
paramsConfiguration?: ApiConfiguration[]
syncSetting?: SyncSetting
isPlugin?: boolean
staticMap?: any
}
const { t } = useI18n()
@ -66,6 +67,7 @@ state.datasourceTree = typeList.map(ele => {
const activeStep = ref(0)
const detail = ref()
const xpack = ref()
const excel = ref()
const latestUseTypes = ref([])
const currentType = ref<DsType>('OLTP')
@ -79,7 +81,11 @@ const selectDsType = (type: string) => {
activeStep.value = 1
activeApiStep.value = 1
nextTick(() => {
detail.value.initForm(type)
detail?.value?.initForm(type) ||
xpack?.value?.invokeMethod({
methodName: 'initForm',
args: type
})
if (!dsTree.value) return
currentTypeList.value
.map(ele => ele.dbList)
@ -142,6 +148,7 @@ const getDatasourceTypes = () => {
}
getDatasourceTypes()
const pluginIndex = ref('')
const pluginDs = ref([])
const loadDsPlugin = data => {
pluginDs.value = data
@ -166,7 +173,11 @@ const getPluginStatic = type => {
const arr = pluginDs.value.filter(ele => {
return ele.type === type
})
return arr && arr.length > 0 ? arr[0].staticMap?.index : null
return pluginIndex.value
? pluginIndex.value
: arr && arr.length > 0
? arr[0].staticMap?.index
: null
}
const getLatestUseTypes = () => {
@ -280,6 +291,23 @@ const prev = () => {
activeStep.value = activeStep.value - 1
}
const handleSubmit = param => {
const validateFrom = param.validate
if (param.eventName === 'saveDs') {
validateFrom(val => {
if (val) {
doSaveDs(param.args)
}
})
} else {
validateFrom(val => {
if (val) {
doValidateDs(param.args)
}
})
}
}
const validateDS = () => {
const request = JSON.parse(JSON.stringify(form)) as unknown as Omit<
Form,
@ -302,9 +330,22 @@ const validateDS = () => {
} else {
request.configuration = Base64.encode(JSON.stringify(request.configuration))
}
const validateFrom = detail.value.submitForm()
if (isPlugin.value) {
xpack?.value?.invokeMethod({
methodName: 'submitForm',
args: [{ eventName: 'validateDs', args: request }]
})
} else {
const validateFrom = detail?.value?.submitForm()
validateFrom(val => {
if (val) {
doValidateDs(request)
}
})
}
}
const doValidateDs = request => {
validate(request).then(res => {
if (res.data.type === 'API') {
let error = 0
@ -328,8 +369,6 @@ const validateDS = () => {
ElMessage.success(t('datasource.validate_success'))
}
})
}
})
}
const typeTitle = computed(() => {
@ -404,10 +443,24 @@ const saveDS = () => {
} else {
request.configuration = Base64.encode(JSON.stringify(request.configuration))
}
const validate = detail.value.submitForm()
if (isPlugin.value) {
xpack?.value?.invokeMethod({
methodName: 'submitForm',
args: [{ eventName: 'saveDs', args: request }]
})
} else {
const validate = detail?.value?.submitForm()
request.apiConfiguration = ''
validate(val => {
if (val) {
doSaveDs(request)
}
})
}
}
const doSaveDs = request => {
if (editDs.value && form.id) {
let options = {
confirmButtonType: 'danger',
@ -457,8 +510,6 @@ const saveDS = () => {
} else {
creatDsFolder.value.createInit('datasource', { id: pid.value, request }, '', form.name)
}
}
})
}
const defaultForm = {
@ -503,6 +554,9 @@ watch(
)
const init = (nodeInfo: Form | Param, id?: string, res?: object) => {
isPlugin.value = nodeInfo?.isPlugin
pluginIndex.value = isPlugin.value ? nodeInfo?.staticMap?.index : null
editDs.value = !!nodeInfo
showFinishPage.value = false
@ -543,7 +597,11 @@ const init = (nodeInfo: Form | Param, id?: string, res?: object) => {
})
}
nextTick(() => {
detail.value.clearForm()
detail?.value?.clearForm()
xpack?.value?.invokeMethod({
methodName: 'clearForm',
args: []
})
})
})
}
@ -711,10 +769,11 @@ defineExpose({
></editor-detail>
<plugin-component
:jsname="getPluginStatic(currentDsType)"
ref="detail"
ref="xpack"
:form="form"
:editDs="editDs"
:active-step="activeApiStep"
@submitForm="handleSubmit"
v-if="
activeStep !== 0 && currentDsType && currentDsType !== 'Excel' && visible && isPlugin
"

View File

@ -306,6 +306,9 @@ const showErrorInfo = info => {
const pluginDs = ref([])
const loadDsPlugin = data => {
pluginDs.value = data
pluginDs.value.forEach(ele => {
typeMap[ele.type] = ele.name
})
}
const getDsIcon = data => {
if (pluginDs?.value.length === 0) return null
@ -606,6 +609,9 @@ const editDatasource = (editType?: number) => {
nodeInfo.editType = editType
}
return getById(nodeInfo.id).then(res => {
let arr = pluginDs.value.filter(ele => {
return ele.type == res.data.type
})
let {
name,
createBy,
@ -648,7 +654,9 @@ const editDatasource = (editType?: number) => {
syncSetting,
apiConfiguration: apiConfigurationStr,
paramsConfiguration: paramsStr,
lastSyncTime
lastSyncTime,
isPlugin: arr && arr.length > 0,
staticMap: arr[0]?.staticMap
})
datasourceEditor.value.init(datasource)
})