mirror of
https://github.com/dataease/dataease.git
synced 2026-05-19 18:29:37 +08:00
662 lines
16 KiB
Vue
662 lines
16 KiB
Vue
<template>
|
|
<div
|
|
v-loading="loading"
|
|
class="dataset-db"
|
|
@mouseup="mouseupDrag"
|
|
>
|
|
<p
|
|
v-show="!showLeft"
|
|
class="arrow-right"
|
|
@click="showLeft = true"
|
|
>
|
|
<i class="el-icon-d-arrow-right"/>
|
|
</p>
|
|
<div
|
|
v-show="showLeft"
|
|
:style="{ left: LeftWidth + 'px' }"
|
|
class="drag-left"
|
|
@mousedown="mousedownDrag"
|
|
/>
|
|
<div
|
|
v-show="showLeft"
|
|
class="table-list"
|
|
:style="{ width: LeftWidth + 'px' }"
|
|
>
|
|
<p class="select-ds">
|
|
{{ $t('deDataset.select_data_source') }}
|
|
<i
|
|
class="el-icon-d-arrow-left"
|
|
@click="showLeft = false"
|
|
/>
|
|
</p>
|
|
<el-select
|
|
v-model="dataSource"
|
|
class="ds-list"
|
|
filterable
|
|
popper-class="db-multiple-select-pop"
|
|
:placeholder="$t('dataset.pls_slc_data_source')"
|
|
size="small"
|
|
>
|
|
<el-option
|
|
v-for="item in options"
|
|
:key="item.id"
|
|
:label="item.name"
|
|
:value="item.id"
|
|
/>
|
|
</el-select>
|
|
<p class="select-ds">{{ $t('datasource.data_table') }}</p>
|
|
<el-input
|
|
v-model="searchTable"
|
|
size="small"
|
|
class="search"
|
|
:placeholder="$t('deDataset.by_table_name')"
|
|
prefix-icon="el-icon-search"
|
|
clearable
|
|
/>
|
|
<div
|
|
v-if="!tableData.length && searchTable !== ''"
|
|
class="el-empty"
|
|
>
|
|
<div
|
|
class="el-empty__description"
|
|
style="margin-top: 80px;color: #5e6d82;"
|
|
>
|
|
没有找到相关内容
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-else
|
|
v-loading="dsLoading"
|
|
class="table-checkbox-list"
|
|
>
|
|
<el-checkbox-group
|
|
v-model="checkTableList"
|
|
size="small"
|
|
>
|
|
<el-tooltip
|
|
v-for="t in tableData"
|
|
:key="t.name"
|
|
:disabled="t.enableCheck"
|
|
effect="dark"
|
|
:content="$t('dataset.table_already_add_to') + ': ' + t.datasetPath"
|
|
placement="right"
|
|
>
|
|
<div
|
|
:class="[
|
|
{ active: activeName === t.name, 'not-allow': !t.enableCheck }
|
|
]"
|
|
class="item"
|
|
:title="t.name"
|
|
@click="setActiveName(t)"
|
|
>
|
|
<svg-icon
|
|
v-if="!t.enableCheck"
|
|
icon-class="Checkbox"
|
|
style="margin-right: 8px"
|
|
/>
|
|
<el-checkbox
|
|
v-else
|
|
:label="t.name"
|
|
:disabled="!t.enableCheck"
|
|
/>
|
|
<span class="label">{{ showTableNameWithComment(t) }}</span>
|
|
<span
|
|
v-if="t.nameExist"
|
|
class="error-name-exist"
|
|
>
|
|
<svg-icon
|
|
icon-class="exclamationmark"
|
|
class="ds-icon-scene"
|
|
/>
|
|
</span>
|
|
</div>
|
|
</el-tooltip>
|
|
</el-checkbox-group>
|
|
</div>
|
|
</div>
|
|
<div class="table-detail">
|
|
<div class="top-table-detail">
|
|
<el-select
|
|
v-model="mode"
|
|
filterable
|
|
:placeholder="$t('dataset.connect_mode')"
|
|
size="small"
|
|
>
|
|
<el-option
|
|
:label="$t('dataset.direct_connect')"
|
|
value="0"
|
|
/>
|
|
<el-option
|
|
v-if="engineMode !== 'simple'"
|
|
:label="$t('dataset.sync_data')"
|
|
value="1"
|
|
:disabled="disabledSync"
|
|
/>
|
|
</el-select>
|
|
<el-select
|
|
v-if="mode === '1'"
|
|
v-model="syncType"
|
|
filterable
|
|
:placeholder="$t('dataset.connect_mode')"
|
|
size="small"
|
|
>
|
|
<el-option
|
|
:label="$t('dataset.sync_now')"
|
|
value="sync_now"
|
|
/>
|
|
<el-option
|
|
:label="$t('dataset.sync_latter')"
|
|
value="sync_latter"
|
|
/>
|
|
</el-select>
|
|
</div>
|
|
<el-empty
|
|
v-if="!dataSource"
|
|
style="padding-top: 160px"
|
|
size="125"
|
|
:description="$t('dataset.pls_slc_data_source')"
|
|
:image="noSelectTable"
|
|
/>
|
|
<template v-else-if="activeName">
|
|
<div class="dataset">
|
|
<span class="name">{{ $t('dataset.name') }}</span>
|
|
<el-input
|
|
v-model="activeTable.datasetName"
|
|
size="small"
|
|
clearable
|
|
@change="validateName"
|
|
/>
|
|
<div
|
|
v-if="activeTable.nameExist"
|
|
style="left: 107px; top: 52px"
|
|
class="el-form-item__error"
|
|
>
|
|
{{ $t('deDataset.already_exists') }}
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-loading="tableLoading"
|
|
class="data"
|
|
>
|
|
<span class="result-num">{{
|
|
`${$t('dataset.preview_show')} 1000 ${$t('dataset.preview_item')}`
|
|
}}</span>
|
|
<div class="table-grid">
|
|
<ux-grid
|
|
ref="plxTable"
|
|
size="mini"
|
|
style="width: 100%"
|
|
:height="height"
|
|
:checkbox-config="{ highlight: true }"
|
|
:width-resize="true"
|
|
>
|
|
<ux-table-column
|
|
v-for="field in fields"
|
|
:key="field.fieldName"
|
|
min-width="200px"
|
|
:field="field.fieldName"
|
|
:title="field.remarks"
|
|
:resizable="true"
|
|
/>
|
|
</ux-grid>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<el-empty
|
|
v-else-if="avilibelTable"
|
|
style="padding-top: 160px"
|
|
size="125"
|
|
:description="$t('deDataset.is_currently_available')"
|
|
:image="noAvilibelTableImg"
|
|
/>
|
|
<el-empty
|
|
v-else-if="!activeName"
|
|
style="padding-top: 160px"
|
|
size="125"
|
|
:description="$t('deDataset.left_to_edit')"
|
|
:image="noSelectTable"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { isKettleRunning, listDatasource, post } from '@/api/dataset/dataset'
|
|
import { dbPreview, engineMode } from '@/api/system/engine'
|
|
import msgCfm from '@/components/msgCfm/index'
|
|
import cancelMix from './cancelMix'
|
|
|
|
import { pySort } from './util'
|
|
import { updateCacheTree } from '@/components/canvas/utils/utils'
|
|
|
|
export default {
|
|
name: 'AddDB',
|
|
mixins: [msgCfm, cancelMix],
|
|
props: {
|
|
param: {
|
|
type: Object,
|
|
default: null
|
|
},
|
|
nameList: {
|
|
type: Array,
|
|
default: () => []
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
showLeft: true,
|
|
LeftWidth: 240,
|
|
tableLoading: false,
|
|
loading: false,
|
|
height: 400,
|
|
fields: [],
|
|
fieldsData: [],
|
|
searchTable: '',
|
|
options: [],
|
|
dataSource: '',
|
|
dsLoading: false,
|
|
tables: [],
|
|
checkTableList: [],
|
|
mode: '0',
|
|
syncType: 'sync_now',
|
|
tableData: [],
|
|
kettleRunning: false,
|
|
selectedDatasource: {},
|
|
engineMode: 'local',
|
|
disabledSync: true,
|
|
avilibelTable: false,
|
|
noAvilibelTableImg: require('@/assets/None.png'),
|
|
noSelectTable: require('@/assets/None_Select_ds.png'),
|
|
activeTable: {},
|
|
activeName: ''
|
|
}
|
|
},
|
|
computed: {
|
|
checkDatasetName() {
|
|
return this.tables
|
|
.filter((ele, index) => {
|
|
return this.checkTableList.includes(ele.name)
|
|
})
|
|
.map((ele) => ele.datasetName)
|
|
}
|
|
},
|
|
watch: {
|
|
checkTableList(val) {
|
|
this.validateName()
|
|
this.$emit('setTableNum', val.length)
|
|
},
|
|
dataSource(val) {
|
|
if (val) {
|
|
this.dsLoading = true
|
|
this.checkTableList = []
|
|
this.activeName = ''
|
|
this.activeTable = {}
|
|
const dsName = this.options.find((ele) => ele.id === val).name
|
|
post('/datasource/getTables/' + val, {}).then((response) => {
|
|
this.tables = response.data
|
|
this.tables.forEach((ele) => {
|
|
this.$set(ele, 'datasetName', dsName + '_' + ele.name)
|
|
this.$set(ele, 'nameExist', false)
|
|
})
|
|
this.tableData = [...this.tables]
|
|
this.avilibelTable = !this.tableData.some((ele) => ele.enableCheck)
|
|
}).finally(() => {
|
|
this.dsLoading = false
|
|
})
|
|
for (let i = 0; i < this.options.length; i++) {
|
|
if (this.options[i].id === val) {
|
|
this.selectedDatasource = this.options[i]
|
|
this.mode = '0'
|
|
if (
|
|
this.engineMode === 'simple' ||
|
|
!this.kettleRunning ||
|
|
this.selectedDatasource.calculationMode === 'DIRECT'
|
|
) {
|
|
this.disabledSync = true
|
|
} else {
|
|
this.disabledSync = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
searchTable(val) {
|
|
this.activeName = ''
|
|
if (val && val !== '') {
|
|
this.tableData = [...this.tables.filter((ele) => {
|
|
return ele.name
|
|
.toLocaleLowerCase()
|
|
.includes(val.toLocaleLowerCase())
|
|
})]
|
|
} else {
|
|
this.tableData = [...this.tables]
|
|
}
|
|
}
|
|
},
|
|
beforeDestroy() {
|
|
window.removeEventListener('resize', this.calHeight)
|
|
},
|
|
mounted() {
|
|
this.initDataSource()
|
|
window.addEventListener('resize', this.calHeight)
|
|
this.calHeight()
|
|
},
|
|
activated() {
|
|
this.initDataSource()
|
|
},
|
|
created() {
|
|
this.kettleState()
|
|
engineMode().then((res) => {
|
|
this.engineMode = res.data
|
|
})
|
|
},
|
|
methods: {
|
|
mousedownDrag() {
|
|
document
|
|
.querySelector('.dataset-db')
|
|
.addEventListener('mousemove', this.calculateHeight)
|
|
},
|
|
mouseupDrag() {
|
|
document
|
|
.querySelector('.dataset-db')
|
|
.removeEventListener('mousemove', this.calculateHeight)
|
|
},
|
|
calculateHeight(e) {
|
|
if (e.pageX < 240) {
|
|
this.LeftWidth = 240
|
|
return
|
|
}
|
|
if (e.pageX > 500) {
|
|
this.LeftWidth = 500
|
|
return
|
|
}
|
|
this.LeftWidth = e.pageX
|
|
},
|
|
nameExistValidator(ele) {
|
|
ele.nameExist =
|
|
this.nameList
|
|
.concat(this.checkDatasetName)
|
|
.filter((name) => name === ele.datasetName)
|
|
.length > 1
|
|
},
|
|
validateName() {
|
|
this.tables.forEach((ele, index) => {
|
|
if (this.checkTableList.includes(ele.name)) {
|
|
this.nameExistValidator(ele)
|
|
} else {
|
|
ele.nameExist = false
|
|
}
|
|
})
|
|
},
|
|
dbPreview(data) {
|
|
this.tableLoading = true
|
|
dbPreview(data)
|
|
.then((res) => {
|
|
const { fields, data } = res.data
|
|
this.fields = fields
|
|
this.fieldsData = data
|
|
this.$refs.plxTable.reloadData(data)
|
|
})
|
|
.finally(() => {
|
|
this.tableLoading = false
|
|
})
|
|
},
|
|
calHeight() {
|
|
const that = this
|
|
setTimeout(function() {
|
|
const currentHeight = document.documentElement.clientHeight
|
|
that.height = currentHeight - 56 - 64 - 75 - 32 - 24 - 16 - 10
|
|
}, 10)
|
|
},
|
|
setActiveName({ name, datasourceId, enableCheck }) {
|
|
if (!enableCheck) return
|
|
this.activeName = name
|
|
this.activeTable = this.tableData.find((ele) => ele.name === this.activeName) || {}
|
|
this.dbPreview({
|
|
dataSourceId: datasourceId,
|
|
info: JSON.stringify({ table: name })
|
|
})
|
|
},
|
|
initDataSource() {
|
|
listDatasource().then((response) => {
|
|
this.options = pySort(response.data.filter((item) => item.type !== 'api'))
|
|
})
|
|
},
|
|
kettleState() {
|
|
isKettleRunning().then((res) => {
|
|
this.kettleRunning = res.data
|
|
})
|
|
},
|
|
showTableNameWithComment(t) {
|
|
if (t.remark) {
|
|
return `${t.name}(${t.remark})`
|
|
} else {
|
|
return `${t.name}`
|
|
}
|
|
},
|
|
save() {
|
|
if (this.tableData.some((ele) => ele.nameExist)) {
|
|
this.openMessageSuccess('deDataset.cannot_be_duplicate', 'error')
|
|
return
|
|
}
|
|
if (this.loading) return
|
|
this.loading = true
|
|
const sceneId = this.param.id
|
|
const dataSourceId = this.dataSource
|
|
const tables = []
|
|
const mode = this.mode
|
|
const syncType = this.syncType
|
|
this.checkTableList.forEach((name) => {
|
|
const datasetName = this.tables.find(
|
|
(ele) => ele.name === name
|
|
).datasetName
|
|
tables.push({
|
|
name: datasetName,
|
|
sceneId: sceneId,
|
|
dataSourceId: dataSourceId,
|
|
type: 'db',
|
|
syncType: syncType,
|
|
mode: parseInt(mode),
|
|
info: JSON.stringify({ table: name })
|
|
})
|
|
})
|
|
post('/dataset/table/batchAdd', tables)
|
|
.then((response) => {
|
|
this.openMessageSuccess('deDataset.set_saved_successfully')
|
|
updateCacheTree('batchNew', 'dataset-tree', response.data, JSON.parse(localStorage.getItem('dataset-tree')))
|
|
this.cancel(response.data)
|
|
})
|
|
.finally(() => {
|
|
this.loading = false
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.dataset-db {
|
|
display: flex;
|
|
height: 100%;
|
|
position: relative;
|
|
width: 100%;
|
|
|
|
.drag-left {
|
|
position: absolute;
|
|
height: calc(100vh - 56px);
|
|
width: 2px;
|
|
top: 0;
|
|
z-index: 5;
|
|
cursor: col-resize;
|
|
}
|
|
|
|
.arrow-right {
|
|
position: absolute;
|
|
top: 15px;
|
|
z-index: 2;
|
|
cursor: pointer;
|
|
margin: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
left: 0;
|
|
height: 24px;
|
|
width: 20px;
|
|
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
|
|
border: 1px solid var(--deCardStrokeColor, #dee0e3);
|
|
border-top-right-radius: 13px;
|
|
border-bottom-right-radius: 13px;
|
|
}
|
|
|
|
.table-list {
|
|
p {
|
|
margin: 0;
|
|
}
|
|
|
|
height: 100%;
|
|
width: 240px;
|
|
padding: 16px 12px;
|
|
font-family: PingFang SC;
|
|
border-right: 1px solid rgba(31, 35, 41, 0.15);
|
|
|
|
.select-ds {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
color: var(--deTextPrimary, #1f2329);
|
|
|
|
i {
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
color: var(--deTextPlaceholder, #8f959e);
|
|
}
|
|
}
|
|
|
|
.search {
|
|
margin: 12px 0;
|
|
}
|
|
|
|
.ds-list {
|
|
margin: 12px 0 24px 0;
|
|
width: 100%;
|
|
}
|
|
|
|
.table-checkbox-list {
|
|
height: calc(100% - 190px);
|
|
overflow-y: auto;
|
|
|
|
.item {
|
|
height: 40px;
|
|
width: 100%;
|
|
border-radius: 4px;
|
|
display: flex;
|
|
align-items: center;
|
|
box-sizing: border-box;
|
|
padding: 12px;
|
|
font-family: PingFang SC;
|
|
font-size: 14px;
|
|
font-weight: 400;
|
|
color: var(--deTextPrimary, #1f2329);
|
|
position: relative;
|
|
|
|
&:hover {
|
|
background: rgba(31, 35, 41, 0.1);
|
|
}
|
|
|
|
&.active {
|
|
background-color: var(--deWhiteHover, #e0eaff);
|
|
color: var(--primary, #3370ff);
|
|
}
|
|
|
|
::v-deep.el-checkbox__label {
|
|
display: none;
|
|
}
|
|
|
|
::v-deep.el-checkbox {
|
|
margin-right: 8px;
|
|
}
|
|
|
|
.label {
|
|
width: 85%;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.error-name-exist {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 10px;
|
|
}
|
|
}
|
|
|
|
.not-allow {
|
|
cursor: not-allowed;
|
|
color: var(--deTextDisable, #bbbfc4);
|
|
}
|
|
}
|
|
}
|
|
|
|
.table-detail {
|
|
font-family: PingFang SC;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
|
|
.top-table-detail {
|
|
height: 64px;
|
|
width: 100%;
|
|
padding: 16px 24px;
|
|
background: #f5f6f7;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.el-select {
|
|
width: 120px;
|
|
margin-right: 12px;
|
|
}
|
|
}
|
|
|
|
.dataset {
|
|
padding: 21px 24px;
|
|
width: 100%;
|
|
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
|
|
display: flex;
|
|
align-items: center;
|
|
position: relative;
|
|
|
|
.name {
|
|
font-size: 14px;
|
|
font-weight: 400;
|
|
color: var(--deTextPrimary, #1f2329);
|
|
}
|
|
|
|
.el-input {
|
|
width: 420px;
|
|
margin-left: 12px;
|
|
}
|
|
}
|
|
|
|
.data {
|
|
padding: 16px 25px;
|
|
overflow: auto;
|
|
height: calc(100% - 140px);
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
|
|
.result-num {
|
|
font-weight: 400;
|
|
display: inline-block;
|
|
font-family: PingFang SC;
|
|
color: var(--deTextSecondary, #646a73);
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.table-grid {
|
|
width: 100%;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|