Files
SQLBot/frontend/src/views/system/embedded/iframe.vue
T

1398 lines
38 KiB
Python

<script lang="ts" setup>
import { ref, computed, reactive, nextTick } from 'vue'
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
import icon_close_outlined from '@/assets/svg/operate/ope-close.svg'
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
import icon_database_colorful from '@/assets/embedded/icon_database_colorful.png'
import icon_web_site_colorful from '@/assets/embedded/icon_web-site_colorful.png'
import floating_window from '@/assets/embedded/window.png'
import full_window from '@/assets/embedded/Card.png'
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
import icon_delete from '@/assets/svg/icon_delete.svg'
import icon_copy_outlined from '@/assets/embedded/icon_copy_outlined.svg'
import { useClipboard } from '@vueuse/core'
import SetUi from './SetUi.vue'
import Card from './Card.vue'
import { workspaceList } from '@/api/workspace'
import DsCard from './DsCard.vue'
import { getList, updateAssistant, saveAssistant, delOne, dsApi } from '@/api/embedded'
import { useI18n } from 'vue-i18n'
import { cloneDeep } from 'lodash-es'
defineProps({
btnSelect: {
type: String,
default: '',
},
})
const emits = defineEmits(['btnSelectChange'])
const { t } = useI18n()
const { copy } = useClipboard({ legacy: true })
const keywords = ref('')
const activeStep = ref(0)
const ruleConfigvVisible = ref(false)
const drawerConfigvVisible = ref(false)
const advancedApplication = ref(false)
const editRule = ref(0)
const embeddedFormRef = ref()
const dsFormRef = ref()
const urlFormRef = ref()
const certificateFormRef = ref()
const dialogTitle = ref('')
const drawerTitle = ref('')
const activeMode = ref('full')
const embeddedList = ref<any[]>([])
const systemCredentials = ['localStorage', 'custom', 'cookie', 'sessionStorage']
const credentials = ['header', 'cookie', 'param']
const workspaces = ref<any[]>([])
const defaultEmbedded = {
id: '',
name: '',
type: 0,
description: '',
domain: '',
}
const currentEmbedded = reactive<any>(cloneDeep(defaultEmbedded))
const isCreate = ref(false)
const defaultForm = {
oid: 1,
private_list: [] as any,
}
const dsForm = reactive(cloneDeep(defaultForm))
const defaultCertificateForm = {
id: '',
type: '',
source: '',
target: '',
target_key: '',
target_val: '',
}
const certificateForm = reactive(cloneDeep(defaultCertificateForm))
const defaultUrlForm = {
endpoint: '',
encrypt: true,
aes_key: '',
aes_iv: '',
certificate: [] as any,
}
const urlForm = reactive(cloneDeep(defaultUrlForm))
const dsListOptions = ref<any[]>([])
const embeddedListWithSearch = computed(() => {
if (!keywords.value) return embeddedList.value
return embeddedList.value.filter((ele) =>
ele.name.toLowerCase().includes(keywords.value.toLowerCase())
)
})
const userTypeList = [
{
name: t('embedded.basic_application'),
img: icon_database_colorful,
tip: t('embedded.support_is_required'),
value: 0,
},
{
name: t('embedded.advanced_application'),
img: icon_web_site_colorful,
tip: t('embedded.data_permissions_etc'),
value: 1,
},
]
const initWorkspace = () => {
workspaceList().then((res) => {
workspaces.value = res
})
}
const handleAddEmbedded = (val: any) => {
Object.assign(currentEmbedded, cloneDeep(defaultEmbedded))
currentEmbedded.type = val
if (val === 0) {
handleBaseEmbedded(null)
} else {
handleAdvancedEmbedded(null)
}
}
const wsChanged = (val: any) => {
dsForm.private_list = []
dsForm.oid = val
getDsList(true)
}
const getDsList = (change: boolean = false) => {
dsApi(dsForm.oid).then((res: any) => {
dsListOptions.value = res || []
if (change || !currentEmbedded.id) {
dsForm.private_list = dsListOptions.value.map((ele) => ele.id)
}
})
}
const handleBaseEmbedded = (row: any) => {
advancedApplication.value = false
initWorkspace()
if (row) {
Object.assign(dsForm, JSON.parse(row.configuration))
}
getDsList(false)
ruleConfigvVisible.value = true
dialogTitle.value = row?.id
? t('embedded.edit_basic_applications')
: t('embedded.create_basic_application')
}
const handleAdvancedEmbedded = (row: any) => {
advancedApplication.value = true
if (row) {
Object.assign(urlForm, cloneDeep(JSON.parse(row.configuration)))
}
ruleConfigvVisible.value = true
dialogTitle.value = row?.id
? t('embedded.edit_advanced_applications')
: t('embedded.creating_advanced_applications')
}
const beforeClose = () => {
ruleConfigvVisible.value = false
activeStep.value = 0
isCreate.value = false
Object.assign(currentEmbedded, cloneDeep(defaultEmbedded))
Object.assign(dsForm, cloneDeep(defaultForm))
Object.assign(urlForm, cloneDeep(defaultUrlForm))
if (embeddedFormRef.value) {
embeddedFormRef.value.clearValidate()
}
if (dsFormRef.value) {
dsFormRef.value.clearValidate()
}
if (urlFormRef.value) {
urlFormRef.value.clearValidate()
}
}
const handleActive = (row: any) => {
console.info('row', row)
}
const handlePrivate = (row: any) => {
dsForm.private_list.push(row.id)
}
const handlePublic = (row: any) => {
dsForm.private_list = dsForm.private_list.filter((ele: any) => ele !== row.id)
}
const searchLoading = ref(false)
const handleSearch = () => {
searchLoading.value = true
getList()
.then((res: any) => {
embeddedList.value = res || []
})
.finally(() => {
searchLoading.value = false
})
}
handleSearch()
const handleEditRule = (row: any) => {
Object.assign(currentEmbedded, cloneDeep(row))
delete currentEmbedded.configuration
if (row.type === 0) {
handleBaseEmbedded(row)
} else {
handleAdvancedEmbedded(row)
}
}
// const deleteRuleHandler = (row: any) => {
// ElMessageBox.confirm(t('permission.rule_rule_1', { msg: row.name }), {
// confirmButtonType: 'danger',
// confirmButtonText: t('dashboard.delete'),
// cancelButtonText: t('common.cancel'),
// customClass: 'confirm-no_icon',
// autofocus: false,
// }).then(() => {
// currentEmbedded.permissions = currentEmbedded.permissions.filter(
// (ele: any) => ele.id !== row.id
// )
// })
// }
const deleteHandler = (row: any) => {
ElMessageBox.confirm(t('embedded.delete', { msg: row.name }), {
confirmButtonType: 'danger',
confirmButtonText: t('dashboard.delete'),
cancelButtonText: t('common.cancel'),
customClass: 'confirm-no_icon',
autofocus: false,
}).then(() => {
delOne(row.id).then(() => {
ElMessage({
type: 'success',
message: t('dashboard.delete_success'),
})
handleSearch()
})
})
}
const setUiRef = ref()
const handleSetUi = (row: any) => {
setUiRef.value.open(row)
}
const rules = {
name: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('embedded.basic_information'),
trigger: 'blur',
},
],
domain: [
{
required: true,
message:
t('datasource.please_enter') + t('common.empty') + t('embedded.cross_domain_settings'),
trigger: 'blur',
},
{
pattern: /^(https?:\/\/)?([\w-]+\.)*[\w-]+(:\d+)?$/,
message: t('embedded.origin_format_error'),
trigger: 'blur',
},
],
}
const dsRules = {
oid: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('user.workspace'),
trigger: 'change',
},
],
}
const urlRules = {
endpoint: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('embedded.interface_url'),
trigger: 'blur',
},
],
certificate: [
{
required: true,
message:
t('datasource.Please_select') + t('common.empty') + t('embedded.system_credential_type'),
trigger: 'change',
},
],
}
const certificateRules = {
type: [
{
required: true,
message:
t('datasource.Please_select') + t('common.empty') + t('embedded.system_credential_type'),
trigger: 'change',
},
],
source: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('embedded.credential_name'),
trigger: 'blur',
},
],
target: [
{
required: true,
message:
t('datasource.Please_select') +
t('common.empty') +
t('embedded.target_credential_location'),
trigger: 'change',
},
],
target_key: [
{
required: true,
message:
t('datasource.please_enter') + t('common.empty') + t('embedded.target_credential_name'),
trigger: 'blur',
},
],
}
const preview = () => {
activeStep.value = 0
}
const next = () => {
embeddedFormRef.value.validate((res: any) => {
if (res) {
activeStep.value = 1
}
})
}
const saveEmbedded = () => {
const req = currentEmbedded.id ? updateAssistant : saveAssistant
const formRef = currentEmbedded.type === 1 ? urlFormRef : dsFormRef
formRef.value.validate((res: any) => {
if (res) {
const obj = { ...currentEmbedded }
if (currentEmbedded.type === 0) {
obj.configuration = JSON.stringify(dsForm)
} else {
obj.configuration = JSON.stringify(urlForm)
}
if (!currentEmbedded.id) {
delete obj.id
}
req(obj).then(() => {
ElMessage({
type: 'success',
message: t('common.save_success'),
})
beforeClose()
handleSearch()
})
}
})
}
const dialogVisible = ref(false)
const scriptElement = ref('')
const jsCodeElement = ref('')
const jsCodeElementFull = ref('')
const handleEmbedded = (row: any) => {
dialogVisible.value = true
const { origin, pathname } = window.location
scriptElement.value = `g-#script
async
defer
id="sqlbot-assistant-float-script-${row.id}"
src="${origin + pathname}assistant.js?id=${row.id}"k-*g-#/scriptk-*`
.replaceAll('g-#', '<')
.replaceAll('k-*', '>')
jsCodeElement.value = `(function(){
const script = document.createElement('script');
script.defer = true;
script.async = true;
script.src = "${origin + pathname}assistant.js?id=${row.id}";
script.id = "sqlbot-assistant-float-script-${row.id}";
document.head.appendChild(script);
})()`
jsCodeElementFull.value = `(function(){
const script = document.createElement('script');
script.defer = true;
script.async = true;
script.src = "${origin + pathname}xpack_static/sqlbot-embedded-dynamic.umd.js";
document.head.appendChild(script);
})()
sqlbot_embedded_handler.mounted('.copilot', {
"embeddedId": "${row.id}",
"online": true
})`
}
const copyJsCode = () => {
copy(jsCodeElement.value)
.then(function () {
ElMessage.success(t('embedded.copy_successful'))
})
.catch(function () {
ElMessage.error(t('embedded.copy_successful'))
})
}
const copyJsCodeFull = () => {
copy(jsCodeElementFull.value)
.then(function () {
ElMessage.success(t('embedded.copy_successful'))
})
.catch(function () {
ElMessage.error(t('embedded.copy_successful'))
})
}
const copyCode = () => {
copy(scriptElement.value)
.then(function () {
ElMessage.success(t('embedded.copy_successful'))
})
.catch(function () {
ElMessage.error(t('embedded.copy_successful'))
})
}
const certificateBeforeClose = () => {
drawerConfigvVisible.value = false
Object.assign(certificateForm, cloneDeep(defaultCertificateForm))
certificateFormRef.value.clearValidate()
}
const initCertificate = (row: any) => {
drawerTitle.value = t('embedded.add_interface_credentials')
if (row) {
Object.assign(certificateForm, cloneDeep(row))
drawerTitle.value = t('embedded.edit_interface_credentials')
} else {
Object.assign(certificateForm, cloneDeep(defaultCertificateForm))
}
drawerConfigvVisible.value = true
nextTick(() => {
certificateFormRef.value.clearValidate()
})
}
const handleCredentialsDel = (row: any) => {
urlForm.certificate = urlForm.certificate.filter((ele: any) => ele.id !== row.id)
}
const saveHandler = () => {
certificateFormRef.value.validate((res: any) => {
if (res) {
if (certificateForm.id) {
for (const key in urlForm.certificate) {
if (Object.prototype.hasOwnProperty.call(urlForm.certificate, key)) {
if (urlForm.certificate[key].id === certificateForm.id) {
Object.assign(urlForm.certificate[key], cloneDeep(certificateForm))
}
}
}
} else {
urlForm.certificate.push({ ...cloneDeep(certificateForm), id: +new Date() })
}
ElMessage({
type: 'success',
message: t('common.save_success'),
})
certificateBeforeClose()
}
})
}
</script>
<template>
<div v-loading="searchLoading" class="embedded-index no-padding">
<div class="tool-left">
<div class="btn-select">
<el-button
:class="[btnSelect === 'd' && 'is-active']"
text
@click="emits('btnSelectChange', 'd')"
>
{{ t('embedded.embedded_assistant') }}
</el-button>
<el-button
:class="[btnSelect === 'q' && 'is-active']"
text
@click="emits('btnSelectChange', 'q')"
>
{{ t('embedded.embedded_page') }}
</el-button>
</div>
<div>
<el-input
v-model="keywords"
style="width: 240px; margin-right: 12px"
:placeholder="$t('dashboard.search')"
clearable
>
<template #prefix>
<el-icon>
<icon_searchOutline_outlined />
</el-icon>
</template>
</el-input>
<el-popover popper-class="system-embedded_user" placement="bottom-end">
<template #reference>
<el-button type="primary">
<template #icon>
<icon_add_outlined></icon_add_outlined>
</template>
{{ $t('embedded.create_application') }}
</el-button>
</template>
<div class="popover">
<div class="popover-content">
<div
v-for="ele in userTypeList"
:key="ele.name"
class="popover-item"
@click="handleAddEmbedded(ele.value)"
>
<img :src="ele.img" style="margin-top: 5px" width="32px" height="32px" />
<div class="embedded">
<div class="name">{{ ele.name }}</div>
<div class="tip">{{ ele.tip }}</div>
</div>
</div>
</div>
</div>
</el-popover>
</div>
</div>
<EmptyBackground
v-if="!!keywords && !embeddedListWithSearch.length"
:description="$t('datasource.relevant_content_found')"
img-type="tree"
class="ed-empty_pd0"
/>
<div v-else class="card-content">
<el-row :gutter="16" class="w-full">
<el-col
v-for="ele in embeddedListWithSearch"
:key="ele.id"
:xs="24"
:sm="12"
:md="12"
:lg="8"
:xl="6"
class="mb-16"
>
<Card
:id="ele.id"
:key="ele.id"
:name="ele.name"
:is-base="ele.type === 0"
:description="ele.description"
@embedded="handleEmbedded(ele)"
@edit="handleEditRule(ele)"
@del="deleteHandler(ele)"
@ui="handleSetUi(ele)"
></Card>
</el-col>
</el-row>
</div>
<template v-if="!keywords && !embeddedListWithSearch.length && !searchLoading">
<EmptyBackground
class="ed-empty_custom"
:description="$t('embedded.no_application')"
img-type="noneWhite"
/>
<div style="text-align: center; margin-top: -10px">
<el-popover popper-class="system-embedded_user" placement="bottom">
<template #reference>
<el-button type="primary">
<template #icon>
<icon_add_outlined></icon_add_outlined>
</template>
{{ $t('embedded.create_application') }}
</el-button>
</template>
<div class="popover">
<div class="popover-content">
<div
v-for="ele in userTypeList"
:key="ele.name"
class="popover-item"
@click="handleAddEmbedded(ele.value)"
>
<img :src="ele.img" style="margin-top: 5px" width="32px" height="32px" />
<div class="embedded">
<div class="name">{{ ele.name }}</div>
<div class="tip">{{ ele.tip }}</div>
</div>
</div>
</div>
</div>
</el-popover>
</div>
</template>
<el-drawer
v-model="ruleConfigvVisible"
:close-on-click-modal="false"
size="calc(100% - 100px)"
modal-class="embedded-drawer-fullscreen"
direction="btt"
:before-close="beforeClose"
:show-close="false"
>
<template #header="{ close }">
<span style="white-space: nowrap">{{ dialogTitle }}</span>
<div v-if="editRule !== 2" class="flex-center" style="width: 100%">
<el-steps custom style="max-width: 500px; flex: 1" :active="activeStep" align-center>
<el-step>
<template #title> {{ $t('embedded.basic_information') }} </template>
</el-step>
<el-step>
<template #title>
{{
currentEmbedded.type === 1
? $t('embedded.configure_interface')
: $t('embedded.set_data_source')
}}
</template>
</el-step>
</el-steps>
</div>
<el-icon style="cursor: pointer" @click="close">
<icon_close_outlined></icon_close_outlined>
</el-icon>
</template>
<div v-if="activeStep === 0" class="drawer-content">
<div class="title">
{{ $t('embedded.basic_information') }}
</div>
<el-form
ref="embeddedFormRef"
:model="currentEmbedded"
label-width="180px"
label-position="top"
:rules="rules"
class="form-content_error"
@submit.prevent
>
<el-form-item prop="name" :label="t('embedded.application_name')">
<el-input
v-model="currentEmbedded.name"
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + $t('embedded.application_name')
"
clearable
maxlength="50"
autocomplete="off"
/>
</el-form-item>
<el-form-item prop="description" :label="t('embedded.application_description')">
<el-input
v-model="currentEmbedded.description"
:rows="3"
type="textarea"
maxlength="200"
show-word-limit
clearable
:placeholder="$t('datasource.please_enter')"
autocomplete="off"
/>
</el-form-item>
<el-form-item prop="domain" :label="t('embedded.cross_domain_settings')">
<el-input
v-model="currentEmbedded.domain"
clearable
:placeholder="$t('embedded.third_party_address')"
autocomplete="off"
/>
</el-form-item>
</el-form>
</div>
<div v-if="activeStep === 1 && advancedApplication" class="drawer-content">
<div class="title">
{{ $t('embedded.configure_interface') }}
</div>
<el-form
ref="urlFormRef"
:model="urlForm"
label-width="180px"
label-position="top"
:rules="urlRules"
class="form-content_error"
@submit.prevent
>
<el-form-item prop="endpoint" :label="t('embedded.interface_url')">
<el-input
v-model="urlForm.endpoint"
clearable
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + $t('embedded.interface_url')
"
autocomplete="off"
/>
</el-form-item>
<el-form-item prop="AES" class="custom-require">
<template #label>
<span class="custom-require_danger">{{ t('embedded.aes_enable') }}</span>
</template>
<el-switch v-model="urlForm.encrypt" />
<span class="aes-encrypt-tips">{{ t('embedded.aes_enable_tips') }}</span>
</el-form-item>
<el-form-item v-if="urlForm.encrypt" prop="aes_key" label="AES Key">
<el-input
v-model="urlForm.aes_key"
clearable
type="password"
show-password
:placeholder="
$t('datasource.please_enter') +
$t('common.empty') +
' 32 ' +
$t('embedded.bit') +
' AES Key'
"
autocomplete="off"
/>
</el-form-item>
<el-form-item v-if="urlForm.encrypt" prop="aes_iv" label="AES IV">
<el-input
v-model="urlForm.aes_iv"
clearable
:placeholder="
$t('datasource.please_enter') +
$t('common.empty') +
' 16 ' +
$t('embedded.bit') +
' AES IV'
"
autocomplete="off"
/>
</el-form-item>
<el-form-item class="certificate-table_form" prop="type">
<template #label>
<div class="title-content">
<span class="title-form">{{ t('embedded.interface_credentials') }}</span>
<span class="add btn" @click="initCertificate(null)">
<el-icon size="16">
<icon_add_outlined></icon_add_outlined>
</el-icon>
{{ t('model.add') }}
</span>
</div>
</template>
<div
class="table-content"
:class="!!urlForm.certificate.length && 'no-credentials_yet'"
>
<el-table
:empty-text="$t('embedded.no_credentials_yet')"
:data="urlForm.certificate"
style="width: 100%"
>
<el-table-column prop="source" :label="t('embedded.credential_name')" width="180" />
<el-table-column
prop="type"
:label="t('embedded.system_credential_type')"
width="180"
/>
<el-table-column
prop="target_key"
:label="t('embedded.target_credential_name')"
width="180"
/>
<el-table-column prop="target" :label="t('embedded.target_credential_location')" />
<el-table-column
fixed="right"
width="80"
class-name="operation-column_text"
:label="$t('ds.actions')"
>
<template #default="scope">
<el-button text type="primary" @click="initCertificate(scope.row)">
<el-icon size="16">
<icon_edit_outlined></icon_edit_outlined>
</el-icon>
</el-button>
<el-button text type="primary" @click="handleCredentialsDel(scope.row)">
<el-icon size="16">
<icon_delete></icon_delete>
</el-icon>
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-form-item>
</el-form>
</div>
<div v-if="activeStep === 1 && !advancedApplication" class="drawer-content">
<div class="title">
{{ $t('embedded.set_data_source') }}
</div>
<el-form
ref="dsFormRef"
:model="dsForm"
label-width="180px"
label-position="top"
:rules="dsRules"
class="form-content_error"
@submit.prevent
>
<el-form-item prop="oid" :label="t('user.workspace')">
<el-select
v-model="dsForm.oid"
filterable
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + $t('user.workspace')
"
@change="wsChanged"
>
<el-option
v-for="item in workspaces"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item class="private-list_form">
<template #label>
<div class="private-list">
{{ t('embedded.set_data_source') }}
<span :title="$t('embedded.open_the_query')" class="open-the_query ellipsis"
>{{ $t('embedded.open_the_query') }}
</span>
</div>
</template>
<div class="card-ds_content">
<DsCard
v-for="(ele, index) in dsListOptions"
:id="ele.id"
:key="ele.id"
:class="[0, 1].includes(index) && 'no-margin_top'"
:name="ele.name"
:type="ele.type"
:type-name="ele.type_name"
:description="ele.description"
:is-private="dsForm.private_list.includes(ele.id)"
:num="ele.num"
@active="handleActive(ele)"
@private="handlePrivate(ele)"
@public="handlePublic(ele)"
></DsCard>
</div>
</el-form-item>
</el-form>
</div>
<template #footer>
<el-button secondary @click="beforeClose"> {{ $t('common.cancel') }} </el-button>
<el-button v-if="activeStep === 1 && editRule !== 2" secondary @click="preview">
{{ t('ds.previous') }}
</el-button>
<el-button v-if="activeStep === 0 && editRule !== 2" type="primary" @click="next">
{{ t('common.next') }}
</el-button>
<el-button v-if="activeStep === 1" type="primary" @click="saveEmbedded">
{{ $t('common.save') }}
</el-button>
</template>
</el-drawer>
</div>
<el-dialog
v-model="dialogVisible"
:title="$t('embedded.embed_third_party')"
width="600"
modal-class="embed-third_party"
>
<div class="floating-window">
<div class="mode">
<div
class="floating"
:class="activeMode === 'full' && 'active'"
@click="activeMode = 'full'"
>
<div class="title">{{ $t('professional.full_screen_mode') }}</div>
<img :src="full_window" width="180px" height="120px" alt="" />
</div>
<div
class="floating"
:class="activeMode === 'floating' && 'active'"
@click="activeMode = 'floating'"
>
<div class="title">{{ $t('embedded.floating_window_mode') }}</div>
<img :src="floating_window" width="180px" height="120px" alt="" />
</div>
</div>
<div v-if="activeMode === 'floating'" class="code-bg">
<div class="code">
<div class="copy">
{{ $t('embedded.code_to_embed') }}
<el-tooltip :offset="12" effect="dark" :content="t('datasource.copy')" placement="top">
<el-icon size="16" @click="copyCode">
<icon_copy_outlined></icon_copy_outlined>
</el-icon>
</el-tooltip>
</div>
<div class="script">
{{ scriptElement }}
</div>
</div>
<div class="line"></div>
<div class="code">
<div class="copy">
{{ $t('professional.code_for_debugging') }}
<el-tooltip :offset="12" effect="dark" :content="t('datasource.copy')" placement="top">
<el-icon size="16" @click="copyJsCode">
<icon_copy_outlined></icon_copy_outlined>
</el-icon>
</el-tooltip>
</div>
<div class="script">
{{ jsCodeElement }}
</div>
</div>
</div>
<div v-else class="code-bg">
<div class="code">
<div class="copy">
{{ $t('embedded.code_to_embed') }}
<el-tooltip :offset="12" effect="dark" :content="t('datasource.copy')" placement="top">
<el-icon size="16" @click="copyJsCodeFull">
<icon_copy_outlined></icon_copy_outlined>
</el-icon>
</el-tooltip>
</div>
<div class="script">
{{ jsCodeElementFull }}
</div>
</div>
</div>
</div>
</el-dialog>
<el-drawer
v-model="drawerConfigvVisible"
:title="drawerTitle"
modal-class="certificate-form_drawer"
direction="rtl"
size="600px"
:before-close="certificateBeforeClose"
>
<el-form
ref="certificateFormRef"
:model="certificateForm"
label-width="180px"
label-position="top"
:rules="certificateRules"
class="form-content_error"
@submit.prevent
>
<el-form-item prop="source" :label="t('embedded.credential_name')">
<el-input
v-model="certificateForm.source"
clearable
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + $t('embedded.credential_name')
"
autocomplete="off"
/>
</el-form-item>
<el-form-item prop="type" :label="t('embedded.system_credential_type')">
<el-select
v-model="certificateForm.type"
:placeholder="
$t('datasource.Please_select') +
$t('common.empty') +
$t('embedded.system_credential_type')
"
>
<el-option v-for="item in systemCredentials" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item prop="target_key" :label="t('embedded.target_credential_name')">
<el-input
v-model="certificateForm.target_key"
clearable
:placeholder="
$t('datasource.please_enter') +
$t('common.empty') +
$t('embedded.target_credential_name')
"
autocomplete="off"
/>
</el-form-item>
<el-form-item prop="target" :label="t('embedded.target_credential_location')">
<el-select
v-model="certificateForm.target"
:placeholder="
$t('datasource.Please_select') +
$t('common.empty') +
$t('embedded.target_credential_location')
"
>
<el-option v-for="item in credentials" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item prop="target_val" :label="t('embedded.target_credential')">
<el-input
v-model="certificateForm.target_val"
clearable
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + $t('embedded.target_credential')
"
autocomplete="off"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button secondary @click="certificateBeforeClose">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="saveHandler">
{{ $t('common.save') }}
</el-button>
</div>
</template>
</el-drawer>
<SetUi ref="setUiRef" @refresh="handleSearch"></SetUi>
</template>
<style lang="less" scoped>
.embedded-index {
height: 100%;
padding: 16px 0 16px 0;
.ed-empty_custom {
padding-top: 200px;
padding-bottom: 0;
height: auto;
}
.tool-left {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
padding: 0 24px 0 24px;
.title {
font-weight: 500;
font-size: 20px;
line-height: 28px;
}
.btn-select {
height: 32px;
padding-left: 4px;
padding-right: 4px;
display: inline-flex;
background: #ffffff;
align-items: center;
border: 1px solid #d9dcdf;
border-radius: 6px;
.is-active {
background: var(--ed-color-primary-1a, #1cba901a);
}
.ed-button:not(.is-active) {
color: #1f2329;
}
.ed-button.is-text {
height: 24px;
width: auto;
padding: 0 8px;
line-height: 24px;
}
.ed-button + .ed-button {
margin-left: 4px;
}
}
}
.card-content {
max-height: calc(100% - 40px);
overflow-y: auto;
padding: 0 8px 0 24px;
.w-full {
width: 100%;
}
.mb-16 {
margin-bottom: 16px;
}
}
}
</style>
<style lang="less">
.embedded-drawer-fullscreen {
.title {
font-weight: 500;
font-size: 16px;
line-height: 24px;
margin-top: 8px;
margin-bottom: 16px;
}
.private-list_form {
.ed-form-item__label:after {
display: none;
}
}
.private-list {
display: flex;
align-items: center;
.open-the_query {
color: #ff8800;
margin-left: 4px;
max-width: 650px;
}
}
.card-ds_content {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
.card {
width: 392px;
&:nth-child(even) {
margin-right: 0;
}
}
.no-margin_top {
margin-top: 0;
}
}
.drawer-content {
width: 800px;
margin: 0 auto;
height: 100%;
padding-bottom: 24px;
overflow-y: auto;
.ed-form-item {
&:last-child {
margin-bottom: 0;
}
.aes-encrypt-tips {
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #ff8800;
margin-left: 8px;
}
}
}
.certificate-table_form {
.ed-form-item__label:after {
display: none;
}
.title-content {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.ed-form-item__label {
width: 100%;
padding-right: 0;
}
.title-form::after {
color: var(--ed-color-danger);
content: '*';
margin-left: 2px;
}
.btn {
height: 26px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 4px;
border-radius: 6px;
cursor: pointer;
&:hover {
background-color: #1f23291a;
}
}
}
.table-content {
width: 100%;
max-height: calc(100vh - 390px);
overflow-y: auto;
border: 1px solid #dee0e3;
border-radius: 6px;
border-top: none;
.operation-column_text {
.ed-button {
color: #646a73;
height: 24px;
}
.ed-button:not(.is-disabled):hover {
background: #1f23291a;
}
.ed-button + .ed-button {
margin-left: 4px;
}
}
.ed-table__empty-text {
padding-top: 0;
}
&.no-credentials_yet {
border-bottom: none;
}
}
}
.system-embedded_user.system-embedded_user {
padding: 0;
width: 282px !important;
box-shadow: 0px 4px 8px 0px #1f23291a;
border: 1px solid #dee0e3;
.popover {
.popover-content {
padding: 4px;
position: relative;
}
.popover-item {
min-height: 98px;
display: flex;
padding-left: 8px;
padding-right: 8px;
position: relative;
border-radius: 4px;
cursor: pointer;
padding-top: 8px;
&:hover {
background: #1f23291a;
}
&:nth-child(2) {
margin: 9px 0 0 0;
}
.embedded {
font-weight: 400;
margin-left: 8px;
.name {
font-size: 14px;
line-height: 22px;
}
.tip {
color: #8f959e;
font-family: PingFang SC;
font-size: 12px;
line-height: 20px;
}
}
}
}
}
.embed-third_party {
.floating-window {
width: 552px;
.mode {
display: flex;
align-items: center;
justify-content: space-between;
}
.code-bg {
background: #f5f6f7;
border-radius: 6px;
overflow: hidden;
margin-top: 16px;
}
.floating {
padding: 16px;
padding-bottom: 0;
border-radius: 6px;
border: 1px solid #dee0e3;
cursor: pointer;
width: 268px;
height: 182px;
display: flex;
align-items: center;
flex-direction: column;
.title {
font-weight: 500;
font-size: 14px;
line-height: 22px;
margin-bottom: 8px;
}
&.active {
background: var(--ed-color-primary-1a, #1cba901a);
border-color: var(--ed-color-primary, #1cba90);
}
}
.line {
background-color: #1f232926;
width: calc(100% - 32px);
height: 1px;
margin-left: 16px;
}
.code {
padding: 16px;
.copy {
display: flex;
align-items: center;
justify-content: space-between;
font-weight: 500;
font-size: 14px;
line-height: 22px;
.ed-icon {
cursor: pointer;
position: relative;
&:hover {
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #1f23291a;
width: 24px;
height: 24px;
border-radius: 6px;
}
}
}
}
.script {
font-weight: 400;
font-size: 14px;
line-height: 22px;
}
}
}
}
</style>