Files
dataease/frontend/src/views/dataset/add/AddDB.vue
2023-04-13 22:55:52 +08:00

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>