180 lines
6.9 KiB
Vue
180 lines
6.9 KiB
Vue
<template>
|
|
<n-modal :show="show" @mask-click="handleClose">
|
|
<n-card class="w-200 max-w-1200px" :title="t('home.Data set config')">
|
|
<n-form :model="model" :rules="rules" ref="formRef" label-placement="left" label-width="auto" :disabled="submitLoading">
|
|
<n-grid :cols="24" :x-gap="24">
|
|
<n-form-item-gi :span="12" :label="t('home.Data set name')" path="name">
|
|
<n-input v-model:value="model.name" />
|
|
</n-form-item-gi>
|
|
<n-form-item-gi :span="12" :label="t('home.Data set group')">
|
|
<n-cascader v-model:value="model.groupId" expand-trigger="hover" :options="groupOptions"
|
|
check-strategy="all" show-path filterable clearable label-field="name" value-field="id" />
|
|
</n-form-item-gi>
|
|
<n-form-item-gi :span="12" :label="t('home.Data set type')">
|
|
<n-select v-model:value="model.type" :options="setTypes" />
|
|
</n-form-item-gi>
|
|
|
|
<template v-if="model.type === 'API'">
|
|
<n-form-item-gi :span="12" :label="t('home.Method')">
|
|
<n-select v-model:value="model.type" :options="[
|
|
{ label: 'GET', value: 'GET' },
|
|
{ label: 'POST', value: 'POST' },
|
|
]" />
|
|
</n-form-item-gi>
|
|
<n-form-item-gi :span="24" :label="t('home.API interface')">
|
|
<n-input v-model:value="model.api" type="textarea" />
|
|
</n-form-item-gi>
|
|
</template>
|
|
|
|
<template v-else-if="model.type === 'SQL'">
|
|
<n-form-item-gi :span="12" :label="t('home.Data sources')">
|
|
<n-select v-model:value="model.dataSource" :options="dataSourceOptions" />
|
|
</n-form-item-gi>
|
|
<n-form-item-gi :span="24" :label="`SQL(${t('home.Query only')})`">
|
|
<SQLEditor v-model:value="model.sql as string" />
|
|
</n-form-item-gi>
|
|
<n-form-item-gi :span="24" label=" ">
|
|
<n-blockquote>
|
|
{{ t('home.Parameter is passed as ') }}
|
|
'${id}' ,
|
|
{{ t('home.For example:') }}
|
|
SELECT * FROM table WHERE id='${id}'
|
|
</n-blockquote>
|
|
</n-form-item-gi>
|
|
</template>
|
|
|
|
<template v-else-if="model.type === 'JSON'">
|
|
<n-form-item-gi :span="24" label="JSON">
|
|
<JSONEditor v-model:value="model.json as string" />
|
|
</n-form-item-gi>
|
|
</template>
|
|
|
|
<n-gi :span="24">
|
|
<div class="flex justify-end mt-4">
|
|
<n-button :disabled="submitLoading" @click="handleClose" class="mr-2">{{ t("other.Cancel") }}</n-button>
|
|
<n-button type="primary" :loading="submitLoading" @click="saveDataSet">{{ t("other.Ok") }}</n-button>
|
|
</div>
|
|
</n-gi>
|
|
</n-grid>
|
|
</n-form>
|
|
</n-card>
|
|
</n-modal>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, watch, useTemplateRef } from "vue";
|
|
import type { FormInst } from 'naive-ui'
|
|
import { t } from "@/language";
|
|
import { DataSetPayload, fetchCreateDataSet, fetchUpdateDataSet } from "@/http/api/dataSet";
|
|
import { fetchDataSetGroupTree } from "@/http/api/dataSetGroup";
|
|
import { fetchDataSourceList } from "@/http/api/dataSource";
|
|
import SQLEditor from "@/components/code/SQLEditor.vue";
|
|
import JSONEditor from "@/components/code/JSONEditor.vue";
|
|
|
|
const props = withDefaults(defineProps<{
|
|
show: boolean,
|
|
model: IDataSet.Item
|
|
}>(), {
|
|
show: false,
|
|
model: () => ({
|
|
id: '',
|
|
groupId: "",
|
|
name: '',
|
|
type: 'SQL',
|
|
})
|
|
})
|
|
const emits = defineEmits(["update:show", "refresh"]);
|
|
|
|
const formRef = useTemplateRef<FormInst>("formRef");
|
|
const rules = {
|
|
name: { required: true, message: t("prompt.Please enter a name for the dataset"), trigger: 'blur' }
|
|
};
|
|
const groupOptions = ref<IDataSet.IGroup[]>([]);
|
|
const setTypes = [
|
|
{ label: 'API', value: 'API' },
|
|
{ label: 'SQL', value: 'SQL' },
|
|
{ label: 'JSON', value: 'JSON' },
|
|
];
|
|
const dataSourceOptions = ref<{ label: string; value: IDataSource.Item["id"] }[]>([]);
|
|
const submitLoading = ref(false);
|
|
|
|
watch(() => props.show, (show) => {
|
|
if (!show) {
|
|
return;
|
|
}
|
|
loadOptions();
|
|
});
|
|
|
|
watch(() => props.model.type, (nextType, oldType) => {
|
|
if (!nextType || nextType === oldType) {
|
|
return;
|
|
}
|
|
if (nextType !== "API") {
|
|
props.model.method = undefined;
|
|
props.model.api = "";
|
|
} else if (!props.model.method) {
|
|
props.model.method = "GET";
|
|
}
|
|
if (nextType !== "SQL") {
|
|
props.model.dataSource = "";
|
|
props.model.sql = "";
|
|
}
|
|
if (nextType !== "JSON") {
|
|
props.model.json = "";
|
|
}
|
|
});
|
|
|
|
async function loadOptions() {
|
|
const [groupRes, dataSourceRes] = await Promise.all([
|
|
fetchDataSetGroupTree(),
|
|
fetchDataSourceList()
|
|
]);
|
|
groupOptions.value = groupRes.data || [];
|
|
dataSourceOptions.value = (dataSourceRes.data || []).map(item => ({
|
|
label: item.name,
|
|
value: item.id
|
|
}));
|
|
}
|
|
|
|
function handleClose() {
|
|
emits("update:show", false);
|
|
}
|
|
|
|
function saveDataSet(e: MouseEvent) {
|
|
e.preventDefault()
|
|
|
|
formRef.value?.validate(async (errors) => {
|
|
if (!errors) {
|
|
submitLoading.value = true;
|
|
const payload: DataSetPayload = {
|
|
id: props.model.id || undefined,
|
|
name: props.model.name?.trim() || "",
|
|
groupId: props.model.groupId,
|
|
type: props.model.type
|
|
};
|
|
|
|
if (props.model.type === "API") {
|
|
payload.method = props.model.method;
|
|
payload.api = props.model.api?.trim();
|
|
} else if (props.model.type === "SQL") {
|
|
payload.dataSourceId = props.model.dataSource;
|
|
payload.sql = props.model.sql?.trim();
|
|
} else if (props.model.type === "JSON") {
|
|
payload.json = props.model.json;
|
|
}
|
|
|
|
const res = props.model.id ? await fetchUpdateDataSet(payload) : await fetchCreateDataSet(payload);
|
|
submitLoading.value = false;
|
|
if (res.error) {
|
|
return;
|
|
}
|
|
window.$message?.success(props.model.id ? t("prompt.Success to update") : t("prompt.Saved successfully!"));
|
|
|
|
// 刷新父页面表格
|
|
emits("refresh");
|
|
|
|
handleClose();
|
|
}
|
|
})
|
|
}
|
|
</script> |