Add File
This commit is contained in:
787
frontend/src/views/ds/DataTable.vue
Normal file
787
frontend/src/views/ds/DataTable.vue
Normal file
@@ -0,0 +1,787 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, reactive } from 'vue'
|
||||
import { datasourceApi } from '@/api/datasource'
|
||||
import icon_right_outlined from '@/assets/svg/icon_right_outlined.svg'
|
||||
import icon_form_outlined from '@/assets/svg/icon_form_outlined.svg'
|
||||
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
import edit from '@/assets/svg/icon_edit_outlined.svg'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import ParamsForm from './ParamsForm.vue'
|
||||
|
||||
interface Table {
|
||||
name: string
|
||||
host: string
|
||||
port: string
|
||||
username: string
|
||||
password: string
|
||||
database: string
|
||||
extraJdbc: string
|
||||
dbSchema: string
|
||||
filename: string
|
||||
sheets: string
|
||||
mode: string
|
||||
timeout: string
|
||||
configuration: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
info: Table
|
||||
}>(),
|
||||
{
|
||||
info: () => ({
|
||||
name: '-',
|
||||
host: '-',
|
||||
port: '-',
|
||||
username: '-',
|
||||
password: '-',
|
||||
database: '-',
|
||||
extraJdbc: '-',
|
||||
dbSchema: '-',
|
||||
filename: '-',
|
||||
sheets: '-',
|
||||
mode: '-',
|
||||
timeout: '-',
|
||||
configuration: '-',
|
||||
id: 0,
|
||||
}),
|
||||
}
|
||||
)
|
||||
const { t } = useI18n()
|
||||
const paramsFormRef = ref()
|
||||
const tableList = ref([] as any[])
|
||||
const loading = ref(false)
|
||||
const initLoading = ref(false)
|
||||
const keywords = ref('')
|
||||
const tableListWithSearch = computed(() => {
|
||||
if (!keywords.value) return tableList.value
|
||||
return tableList.value.filter((ele) =>
|
||||
ele.table_name.toLowerCase().includes(keywords.value.toLowerCase())
|
||||
)
|
||||
})
|
||||
const total = ref(1000)
|
||||
const showNum = ref(100)
|
||||
const currentTable = ref<any>({})
|
||||
const ds = ref<any>({})
|
||||
const btnSelect = ref('d')
|
||||
|
||||
const pageInfo = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
})
|
||||
|
||||
const handleSizeChange = (val: number) => {
|
||||
pageInfo.currentPage = 1
|
||||
pageInfo.pageSize = val
|
||||
}
|
||||
const handleCurrentChange = (val: number) => {
|
||||
pageInfo.currentPage = val
|
||||
}
|
||||
|
||||
const fieldListComputed = computed(() => {
|
||||
const { currentPage, pageSize } = pageInfo
|
||||
return fieldList.value.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
||||
})
|
||||
|
||||
const init = () => {
|
||||
initLoading.value = true
|
||||
datasourceApi.getDs(props.info.id).then((res) => {
|
||||
ds.value = res
|
||||
fieldList.value = []
|
||||
pageInfo.total = 0
|
||||
pageInfo.currentPage = 1
|
||||
datasourceApi.tableList(props.info.id).then((res) => {
|
||||
tableList.value = res
|
||||
initLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
const tableComment = ref('')
|
||||
const fieldDialog = ref<boolean>(false)
|
||||
const tableDialog = ref<boolean>(false)
|
||||
const fieldComment = ref('')
|
||||
const currentField = ref<any>({})
|
||||
const previewData = ref<any>({})
|
||||
const fieldList = ref<any>([])
|
||||
|
||||
const buildData = () => {
|
||||
return { table: currentTable.value, fields: fieldList.value }
|
||||
}
|
||||
|
||||
const handleSelectTableList = () => {
|
||||
paramsFormRef.value.open(props.info)
|
||||
}
|
||||
|
||||
const clickTable = (table: any) => {
|
||||
loading.value = true
|
||||
currentTable.value = table
|
||||
fieldList.value = []
|
||||
pageInfo.total = 0
|
||||
previewData.value = []
|
||||
datasourceApi
|
||||
.fieldList(table.id)
|
||||
.then((res) => {
|
||||
fieldList.value = res
|
||||
pageInfo.total = res.length
|
||||
pageInfo.currentPage = 1
|
||||
datasourceApi.previewData(props.info.id, buildData()).then((res) => {
|
||||
previewData.value = res
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const closeTable = () => {
|
||||
tableDialog.value = false
|
||||
}
|
||||
const editTable = () => {
|
||||
tableComment.value = currentTable.value.custom_comment
|
||||
tableDialog.value = true
|
||||
}
|
||||
const saveTable = () => {
|
||||
currentTable.value.custom_comment = tableComment.value
|
||||
datasourceApi.saveTable(currentTable.value).then(() => {
|
||||
closeTable()
|
||||
ElMessage({
|
||||
message: t('common.save_success'),
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
const closeField = () => {
|
||||
fieldDialog.value = false
|
||||
}
|
||||
|
||||
const refresh = () => {
|
||||
emits('refresh')
|
||||
datasourceApi.tableList(props.info.id).then((res) => {
|
||||
tableList.value = res
|
||||
if (!currentTable.value.table_name) return
|
||||
const nameArr = tableList.value.map((ele: any) => ele.table_name)
|
||||
if (!nameArr.includes(currentTable.value.table_name)) {
|
||||
currentTable.value = {}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const saveField = () => {
|
||||
currentField.value.custom_comment = fieldComment.value
|
||||
datasourceApi.saveField(currentField.value).then(() => {
|
||||
closeField()
|
||||
ElMessage({
|
||||
message: t('common.save_success'),
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const editField = (row: any) => {
|
||||
currentField.value = row
|
||||
fieldComment.value = currentField.value.custom_comment
|
||||
fieldDialog.value = true
|
||||
}
|
||||
|
||||
const changeStatus = (row: any) => {
|
||||
currentField.value = row
|
||||
datasourceApi.saveField(currentField.value).then(() => {
|
||||
closeField()
|
||||
ElMessage({
|
||||
message: t('common.save_success'),
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const emits = defineEmits(['back', 'refresh'])
|
||||
const back = () => {
|
||||
emits('back')
|
||||
}
|
||||
|
||||
const renderHeader = ({ column }: any) => {
|
||||
//创建一个元素用于存放表头信息
|
||||
const span = document.createElement('span')
|
||||
// 将表头信息渲染到元素上
|
||||
span.innerText = column.label
|
||||
// 在界面中添加该元素
|
||||
document.body.appendChild(span)
|
||||
//获取该元素的宽度(包含内外边距等信息)
|
||||
const spanWidth = span.getBoundingClientRect().width + 20 //渲染后的 div 内左右 padding 都是 10,所以 +20
|
||||
//判断是否小于element的最小宽度,两者取最大值
|
||||
column.minWidth = column.minWidth > spanWidth ? column.minWidth : spanWidth
|
||||
// 计算完成后,删除该元素
|
||||
document.body.removeChild(span)
|
||||
return column.label
|
||||
}
|
||||
|
||||
const btnSelectClick = (val: any) => {
|
||||
btnSelect.value = val
|
||||
loading.value = true
|
||||
|
||||
if (val === 'd') {
|
||||
datasourceApi
|
||||
.fieldList(currentTable.value.id)
|
||||
.then((res) => {
|
||||
fieldList.value = res
|
||||
pageInfo.total = res.length
|
||||
pageInfo.currentPage = 1
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
datasourceApi
|
||||
.previewData(props.info.id, buildData())
|
||||
.then((res) => {
|
||||
previewData.value = res
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="data-table no-padding">
|
||||
<div class="info">
|
||||
<el-button text @click="back">{{ $t('ds.title') }}</el-button>
|
||||
<el-icon size="12">
|
||||
<icon_right_outlined></icon_right_outlined>
|
||||
</el-icon>
|
||||
<div class="name">{{ info.name }}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="side-list">
|
||||
<div class="select-table_top">
|
||||
{{ $t('ds.tables') }}
|
||||
|
||||
<el-tooltip effect="dark" :content="$t('ds.form.choose_tables')" placement="top">
|
||||
<el-icon size="18" @click="handleSelectTableList">
|
||||
<icon_form_outlined></icon_form_outlined>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="keywords"
|
||||
clearable
|
||||
style="width: 232px"
|
||||
:placeholder="$t('datasource.search')"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<icon_searchOutline_outlined class="svg-icon" />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<div v-loading="initLoading" class="list-content">
|
||||
<el-scrollbar v-if="tableListWithSearch.length">
|
||||
<div
|
||||
v-for="ele in tableListWithSearch"
|
||||
:key="ele.table_name"
|
||||
class="model"
|
||||
:class="currentTable.table_name === ele.table_name && 'isActive'"
|
||||
:title="ele.table_name"
|
||||
@click="clickTable(ele)"
|
||||
>
|
||||
<el-icon size="16">
|
||||
<icon_form_outlined></icon_form_outlined>
|
||||
</el-icon>
|
||||
<span class="name">{{ ele.table_name }}</span>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<EmptyBackground
|
||||
v-if="!!keywords && !tableListWithSearch.length"
|
||||
:description="$t('datasource.relevant_content_found')"
|
||||
img-type="tree"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div v-else-if="!initLoading && !tableListWithSearch.length" class="no-data">
|
||||
<div class="no-data-msg">
|
||||
<div>
|
||||
{{ $t('datasource.no_table') }}
|
||||
</div>
|
||||
<el-button type="primary" link @click="handleSelectTableList">
|
||||
{{ $t('datasource.go_add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="currentTable.table_name" v-loading="loading" class="info-table">
|
||||
<div class="table-name">
|
||||
<div class="name">{{ currentTable.table_name }}</div>
|
||||
<div class="notes">
|
||||
{{ $t('about.remark') }}:
|
||||
<span :title="currentTable.custom_comment" class="field-notes">{{
|
||||
currentTable.custom_comment || '-'
|
||||
}}</span>
|
||||
|
||||
<el-tooltip :offset="14" effect="dark" :content="$t('datasource.edit')" placement="top">
|
||||
<el-icon style="margin-left: 8px; cursor: pointer" size="16" @click="editTable">
|
||||
<edit></edit>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-content">
|
||||
<div class="btn-select">
|
||||
<el-button
|
||||
:class="[btnSelect === 'd' && 'is-active']"
|
||||
text
|
||||
@click="btnSelectClick('d')"
|
||||
>
|
||||
{{ t('ds.table_schema') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
:class="[btnSelect === 'q' && 'is-active']"
|
||||
text
|
||||
@click="btnSelectClick('q')"
|
||||
>
|
||||
{{ t('ds.preview') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!loading"
|
||||
class="preview-or-schema"
|
||||
:class="btnSelect === 'q' && 'overflow-preview'"
|
||||
>
|
||||
<div v-if="btnSelect === 'd'" class="table-content_preview">
|
||||
<el-table
|
||||
row-class-name="hover-icon_edit"
|
||||
:data="fieldListComputed"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column
|
||||
prop="field_name"
|
||||
:label="t('datasource.field_name')"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="field_type"
|
||||
:label="t('datasource.field_type')"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="field_comment"
|
||||
:label="t('datasource.field_original_notes')"
|
||||
/>
|
||||
<el-table-column :label="t('datasource.field_notes_1')">
|
||||
<template #default="scope">
|
||||
<div class="field-comment">
|
||||
<span :title="scope.row.custom_comment" class="notes-in_table">{{
|
||||
scope.row.custom_comment
|
||||
}}</span>
|
||||
<el-tooltip
|
||||
:offset="14"
|
||||
effect="dark"
|
||||
:content="$t('datasource.edit')"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="action-btn" size="16" @click="editField(scope.row)">
|
||||
<edit></edit>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('datasource.enabled_status')" width="180">
|
||||
<template #default="scope">
|
||||
<div style="display: flex; align-items: center">
|
||||
<el-switch
|
||||
v-model="scope.row.checked"
|
||||
size="small"
|
||||
@change="changeStatus(scope.row)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-if="fieldList.length && btnSelect === 'd'" class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pageInfo.currentPage"
|
||||
v-model:page-size="pageInfo.pageSize"
|
||||
:page-sizes="[10, 20, 30]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pageInfo.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="btnSelect === 'q'">
|
||||
<div class="preview-num">
|
||||
{{ t('ds.pieces_in_total', { msg: total, ms: showNum }) }}
|
||||
</div>
|
||||
<el-table :data="previewData.data" style="width: 100%">
|
||||
<el-table-column
|
||||
v-for="(c, index) in previewData.fields"
|
||||
:key="index"
|
||||
:prop="c"
|
||||
:label="c"
|
||||
:render-header="renderHeader"
|
||||
/>
|
||||
</el-table>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="tableDialog"
|
||||
:title="t('datasource.table_notes')"
|
||||
width="600"
|
||||
:destroy-on-close="true"
|
||||
:close-on-click-modal="false"
|
||||
modal-class="notes-dialog"
|
||||
@closed="closeTable"
|
||||
>
|
||||
<el-input
|
||||
v-model="tableComment"
|
||||
:placeholder="$t('datasource.please_enter')"
|
||||
:autosize="{ minRows: 3.64, maxRows: 11.095 }"
|
||||
type="textarea"
|
||||
clearable
|
||||
/>
|
||||
<div style="display: flex; justify-content: flex-end; margin-top: 20px">
|
||||
<el-button secondary @click="closeTable">{{ t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="saveTable">{{ t('common.save') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="fieldDialog"
|
||||
:title="t('datasource.field_notes')"
|
||||
width="600"
|
||||
:destroy-on-close="true"
|
||||
:close-on-click-modal="false"
|
||||
modal-class="notes-dialog"
|
||||
@closed="closeField"
|
||||
>
|
||||
<el-input
|
||||
v-model="fieldComment"
|
||||
:placeholder="$t('datasource.please_enter')"
|
||||
:autosize="{ minRows: 3.64, maxRows: 11.095 }"
|
||||
clearable
|
||||
type="textarea"
|
||||
/>
|
||||
<div style="display: flex; justify-content: flex-end; margin-top: 20px">
|
||||
<el-button secondary @click="closeField">{{ t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="saveField">{{ t('common.save') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<ParamsForm ref="paramsFormRef" @refresh="refresh"></ParamsForm>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.data-table {
|
||||
height: 100%;
|
||||
.info {
|
||||
height: 56px;
|
||||
width: 100%;
|
||||
padding-left: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #646a73;
|
||||
border-bottom: 1px solid #1f232926;
|
||||
|
||||
.ed-button {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
color: #646a73;
|
||||
|
||||
&:hover {
|
||||
background: var(--ed-color-primary-1a, #1cba901a);
|
||||
color: var(--ed-color-primary);
|
||||
}
|
||||
&:active {
|
||||
color: var(--ed-color-primary-dark-2);
|
||||
background: var(--ed-color-primary-33, #1cba9033);
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #1f2329;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
height: calc(100% - 56px);
|
||||
position: relative;
|
||||
.side-list {
|
||||
width: 280px;
|
||||
padding: 8px 16px;
|
||||
height: 100%;
|
||||
border-right: 1px solid #1f232926;
|
||||
.select-table_top {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px;
|
||||
font-weight: 500;
|
||||
|
||||
.ed-icon {
|
||||
cursor: pointer;
|
||||
color: var(--ed-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.ed-input {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
height: calc(100% - 100px);
|
||||
.no-result {
|
||||
margin-top: 72px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
color: #646a73;
|
||||
}
|
||||
.model {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 8px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
.name {
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
max-width: 80%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
&:hover {
|
||||
background: #1f23291a;
|
||||
}
|
||||
|
||||
&.isActive {
|
||||
background: var(--ed-color-primary-1a, #1cba901a);
|
||||
color: var(--ed-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
.no-data-msg {
|
||||
display: inline;
|
||||
width: 100%;
|
||||
color: var(--ed-text-color-secondary);
|
||||
font-size: var(--ed-font-size-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
.info-table {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: calc(100% - 280px);
|
||||
height: 100%;
|
||||
.table-name {
|
||||
height: 80px;
|
||||
padding: 16px 0 0 24px;
|
||||
border-bottom: 1px solid #1f232926;
|
||||
|
||||
.name {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.ed-icon {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
margin-top: 4px;
|
||||
margin-left: 8px;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
background-color: #1f23291a;
|
||||
position: absolute;
|
||||
border-radius: 6px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::after {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notes {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #646a73;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.field-notes {
|
||||
display: inline-block;
|
||||
max-width: calc(100% - 75px);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-content {
|
||||
padding: 16px 24px;
|
||||
height: calc(100% - 80px);
|
||||
|
||||
.btn-select {
|
||||
height: 32px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
display: inline-flex;
|
||||
background: #ffffff;
|
||||
align-items: center;
|
||||
border: 1px solid #d0d3d6;
|
||||
border-radius: 4px;
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-or-schema {
|
||||
margin-top: 16px;
|
||||
height: calc(100% - 50px);
|
||||
|
||||
&.overflow-preview {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.table-content_preview {
|
||||
max-height: calc(100% - 50px);
|
||||
overflow-y: auto;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.hover-icon_edit:hover {
|
||||
.ed-icon {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.field-comment {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 24px;
|
||||
.notes-in_table {
|
||||
max-width: 100%;
|
||||
display: -webkit-box;
|
||||
max-height: 66px;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3; /* 限制行数为3 */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ed-icon {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
display: none;
|
||||
color: #646a73;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
background-color: #1f23291a;
|
||||
position: absolute;
|
||||
border-radius: 6px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::after {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.preview-num {
|
||||
margin: 12px 0;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #646a73;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.notes-dialog {
|
||||
.ed-textarea__inner {
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user