😎1、优化报表开发相关 2、优化表格查询组件

This commit is contained in:
zuohuaijun 2025-07-06 02:39:20 +08:00
parent ed49e27251
commit e554eeca65
8 changed files with 154 additions and 152 deletions

View File

@ -4,7 +4,7 @@
// SqlSugar PostgreSQL // SqlSugar PostgreSQL
// https://www.connectionstrings.com/ // https://www.connectionstrings.com/
"DbConnection": { "DbConnection": {
"EnableConsoleSql": false, // SQL "EnableConsoleSql": true, // SQL
"ConnectionConfigs": [ "ConnectionConfigs": [
{ {
//"ConfigId": "1300000000001", // - //"ConfigId": "1300000000001", // -

View File

@ -36,9 +36,9 @@
<PackageReference Include="IPTools.China" Version="1.6.0" /> <PackageReference Include="IPTools.China" Version="1.6.0" />
<PackageReference Include="IPTools.International" Version="1.6.0" /> <PackageReference Include="IPTools.International" Version="1.6.0" />
<PackageReference Include="log4net" Version="3.1.0" /> <PackageReference Include="log4net" Version="3.1.0" />
<PackageReference Include="Magicodes.IE.Excel" Version="2.7.5.2" /> <PackageReference Include="Magicodes.IE.Excel" Version="2.7.6" />
<PackageReference Include="Magicodes.IE.Pdf" Version="2.7.5.2" /> <PackageReference Include="Magicodes.IE.Pdf" Version="2.7.6" />
<PackageReference Include="Magicodes.IE.Word" Version="2.7.5.2" /> <PackageReference Include="Magicodes.IE.Word" Version="2.7.6" />
<PackageReference Include="MailKit" Version="4.13.0" /> <PackageReference Include="MailKit" Version="4.13.0" />
<PackageReference Include="MiniExcel" Version="1.41.3" /> <PackageReference Include="MiniExcel" Version="1.41.3" />
<PackageReference Include="MiniWord" Version="0.9.2" /> <PackageReference Include="MiniWord" Version="0.9.2" />
@ -56,7 +56,7 @@
<PackageReference Include="SSH.NET" Version="2025.0.0" /> <PackageReference Include="SSH.NET" Version="2025.0.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.6" /> <PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.6" />
<PackageReference Include="System.Net.Http" Version="4.3.4" /> <PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1259" /> <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1273" />
<PackageReference Include="UAParser" Version="3.1.47" /> <PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
<PackageReference Include="microsoft.semantickernel" Version="1.59.0" /> <PackageReference Include="microsoft.semantickernel" Version="1.59.0" />

View File

@ -1,105 +1,106 @@
<template> <template>
<div class="table-search-container" v-if="props.search.length > 0"> <div class="table-search-container" v-if="props.search.length > 0">
<el-form ref="tableSearchRef" :model="state.innerModelValue" label-width="100px" class="table-form"> <el-card shadow="hover" :body-style="{ padding: '5px 5px 0px 5px', display: 'flex', width: '100%', height: '100%', alignItems: 'start' }">
<el-row :gutter="20"> <el-form ref="tableSearchRef" :model="state.innerModelValue" :show-message="false" :inlineMessage="true" label-width="auto" style="flex: 1 1 0%">
<!-- <el-col :xs="12" :sm="8" :md="8" :lg="6" :xl="4" class="mb20"></el-col> --> <el-row :gutter="10">
<el-col :xs="12" :sm="5" :md="5" :lg="6" :xl="4" class="mb20" v-for="(val, key) in search" :key="key" v-show="key < 3 || state.isToggle"> <!-- <el-col :xs="12" :sm="8" :md="8" :lg="6" :xl="4" class="mb5"></el-col> -->
<template v-if="val.type"> <el-col :xs="12" :sm="5" :md="5" :lg="6" :xl="4" class="mb5" v-for="(val, key) in search" :key="key" v-show="key < 3 || state.isToggle">
<el-form-item <template v-if="val.type">
label-width="auto" <el-form-item
:label="val.label" label-width="auto"
:prop="val.prop" :label="val.label"
:rules="[{ required: val.required, message: `${val.label}${t('message.list.required')}`, trigger: val.type === 'input' ? 'blur' : 'change' }]" :prop="val.prop"
> :rules="[{ required: val.required, message: `${val.label}${t('message.list.required')}`, trigger: val.type === 'input' ? 'blur' : 'change' }]"
<el-input
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
:placeholder="val.placeholder"
:clearable="!val.required"
v-if="val.type === 'input'"
@keyup.enter="onSearch(tableSearchRef)"
@change="val.change"
class="w100"
/>
<el-date-picker
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
type="date"
:placeholder="val.placeholder"
:clearable="!val.required"
v-else-if="val.type === 'date'"
@change="val.change"
class="w100"
/>
<el-date-picker
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
type="monthrange"
value-format="YYYY/MM/DD"
:placeholder="val.placeholder"
:clearable="!val.required"
v-else-if="val.type === 'monthrange'"
@change="val.change"
class="w100"
/>
<el-date-picker
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
type="daterange"
value-format="YYYY/MM/DD"
:range-separator="t('message.list.to')"
:start-placeholder="t('message.list.startDate')"
:end-placeholder="t('message.list.endDate')"
:clearable="!val.required"
:shortcuts="shortcuts"
:default-time="defaultTime"
v-else-if="val.type === 'daterange'"
@change="val.change"
class="w100"
/>
<el-select
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
:clearable="!val.required"
:placeholder="val.placeholder"
v-else-if="val.type === 'select'"
@change="val.change"
class="w100"
> >
<el-option v-for="item in val.options" :key="item.value" :label="item.label" :value="item.value"> </el-option> <el-input
</el-select> v-model="state.innerModelValue[val.prop]"
<el-cascader v-bind="val.comProps"
v-else-if="val.type === 'cascader' && val.cascaderData" :placeholder="val.placeholder"
:options="val.cascaderData" :clearable="!val.required"
:clearable="!val.required" v-if="val.type === 'input'"
filterable @keyup.enter="onSearch(tableSearchRef)"
:props="val.cascaderProps ? val.cascaderProps : state.cascaderProps" @change="val.change"
:placeholder="val.placeholder" class="w100"
@change="val.change" />
class="w100" <el-date-picker
v-bind="val.comProps" v-model="state.innerModelValue[val.prop]"
v-model="state.innerModelValue[val.prop]" v-bind="val.comProps"
> type="date"
</el-cascader> :placeholder="val.placeholder"
:clearable="!val.required"
v-else-if="val.type === 'date'"
@change="val.change"
class="w100"
/>
<el-date-picker
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
type="monthrange"
value-format="YYYY/MM/DD"
:placeholder="val.placeholder"
:clearable="!val.required"
v-else-if="val.type === 'monthrange'"
@change="val.change"
class="w100"
/>
<el-date-picker
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
type="daterange"
value-format="YYYY/MM/DD"
:range-separator="t('message.list.to')"
:start-placeholder="t('message.list.startDate')"
:end-placeholder="t('message.list.endDate')"
:clearable="!val.required"
:shortcuts="shortcuts"
:default-time="defaultTime"
v-else-if="val.type === 'daterange'"
@change="val.change"
class="w100"
/>
<el-select
v-model="state.innerModelValue[val.prop]"
v-bind="val.comProps"
:clearable="!val.required"
:placeholder="val.placeholder"
v-else-if="val.type === 'select'"
@change="val.change"
class="w100"
>
<el-option v-for="item in val.options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
<el-cascader
v-else-if="val.type === 'cascader' && val.cascaderData"
:options="val.cascaderData"
:clearable="!val.required"
filterable
:props="val.cascaderProps ? val.cascaderProps : state.cascaderProps"
:placeholder="val.placeholder"
@change="val.change"
class="w100"
v-bind="val.comProps"
v-model="state.innerModelValue[val.prop]"
>
</el-cascader>
</el-form-item>
</template>
</el-col>
<el-col :xs="12" :sm="9" :md="9" :lg="6" :xl="4" class="mb5">
<el-form-item class="table-form-btn" label-width="auto">
<div>
<el-button-group>
<el-button type="primary" icon="ele-Search" @click="onSearch(tableSearchRef)"> {{ t('message.list.query') }} </el-button>
<el-button icon="ele-Refresh" @click="onReset(tableSearchRef)"> {{ t('message.list.reset') }} </el-button>
</el-button-group>
</div>
</el-form-item> </el-form-item>
</template> </el-col>
</el-col> </el-row>
<el-col :xs="12" :sm="9" :md="9" :lg="6" :xl="4" class="mb20"> <el-divider style="margin-top: 5px" v-if="search.length > 3">
<el-form-item class="table-form-btn" label-width="auto"> <el-button :icon="state.isToggle ? 'ele-ArrowUpBold' : 'ele-ArrowDownBold'" class="divider-btn" @click="state.isToggle = !state.isToggle"> </el-button>
<div> </el-divider>
<!-- 使用el-button-group会导致具有type属性的按钮的右边框无法显示 --> </el-form>
<!-- <el-button-group> --> </el-card>
<el-button plain type="primary" icon="ele-Search" @click="onSearch(tableSearchRef)"> {{ t('message.list.query') }} </el-button>
<el-button icon="ele-Refresh" @click="onReset(tableSearchRef)" style="margin-left: 12px"> {{ t('message.list.reset') }} </el-button>
<!-- </el-button-group> -->
</div>
</el-form-item>
</el-col>
</el-row>
<el-divider style="margin-top: 5px" v-if="search.length > 3">
<el-button :icon="state.isToggle ? 'ele-ArrowUpBold' : 'ele-ArrowDownBold'" class="divider-btn" @click="state.isToggle = !state.isToggle"> </el-button>
</el-divider>
</el-form>
</div> </div>
</template> </template>
@ -205,19 +206,19 @@ const shortcuts = [
<style scoped lang="scss"> <style scoped lang="scss">
.table-search-container { .table-search-container {
display: flex; // display: flex;
.table-form { // .table-form {
flex: 1; // flex: 1;
.table-form-btn-toggle { // .table-form-btn-toggle {
white-space: nowrap; // white-space: nowrap;
user-select: none; // user-select: none;
display: flex; // display: flex;
align-items: center; // align-items: center;
color: var(--el-color-primary); // color: var(--el-color-primary);
} // }
} // }
} }
.divider-btn { .divider-btn {

View File

@ -7,7 +7,7 @@
<span> {{ props.title }} </span> <span> {{ props.title }} </span>
</div> </div>
</template> </template>
<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="130" :rules="rules"> <el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto" :rules="rules">
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8" class="mb20"> <el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8" class="mb20">
<el-form-item :label="$t('名称')" prop="name"> <el-form-item :label="$t('名称')" prop="name">
@ -71,8 +71,8 @@
<template #toolbar_buttons> <template #toolbar_buttons>
<el-space> <el-space>
<el-button type="primary" size="small" icon="ele-Plus" @click="() => add(vFieldGrid!, beforeAddField)">{{ $t('新增') }}</el-button> <el-button type="primary" size="small" icon="ele-Plus" @click="() => add(vFieldGrid!, beforeAddField)">{{ $t('新增') }}</el-button>
<el-button size="small" @click="() => insert(vFieldGrid!)">{{ $t('插入') }}</el-button> <el-button size="small" icon="ele-Rank" @click="() => insert(vFieldGrid!)">{{ $t('插入') }}</el-button>
<el-button type="danger" size="small" icon="ele-Minus" plain @click="() => remove(vFieldGrid!)">{{ $t('删除') }}</el-button> <el-button type="danger" size="small" icon="ele-Delete" plain @click="() => remove(vFieldGrid!)">{{ $t('删除') }}</el-button>
</el-space> </el-space>
</template> </template>
<template #toolbar_tools> </template> <template #toolbar_tools> </template>
@ -90,8 +90,8 @@
<template #toolbar_buttons> <template #toolbar_buttons>
<el-space> <el-space>
<el-button type="primary" size="small" icon="ele-Plus" @click="() => add(vParamGrid!)">{{ $t('新增') }}</el-button> <el-button type="primary" size="small" icon="ele-Plus" @click="() => add(vParamGrid!)">{{ $t('新增') }}</el-button>
<el-button size="small" @click="() => insert(vParamGrid!)">{{ $t('插入') }}</el-button> <el-button size="small" icon="ele-Rank" @click="() => insert(vParamGrid!)">{{ $t('插入') }}</el-button>
<el-button type="danger" size="small" icon="ele-Minus" plain @click="() => remove(vParamGrid!)">{{ $t('删除') }}</el-button> <el-button type="danger" size="small" icon="ele-Delete" plain @click="() => remove(vParamGrid!)">{{ $t('删除') }}</el-button>
</el-space> </el-space>
</template> </template>
<template #toolbar_tools> </template> <template #toolbar_tools> </template>
@ -272,20 +272,20 @@ const fieldConfig = reactive({
{ {
id: 'sysReportConfigEditForm_fields', id: 'sysReportConfigEditForm_fields',
columns: [ columns: [
{ type: 'checkbox', width: 36, fixed: 'left' }, { type: 'checkbox', width: 60, fixed: 'left' },
{ field: 'fieldName', title: t('字段名'), width: 200, editRender: { name: 'ElInput', props: { size: 'small' } }, dragSort: true }, { field: 'fieldName', title: t('字段名'), editRender: { name: 'ElInput', props: { size: 'small' } }, dragSort: true },
{ field: 'title', title: t('字段标题'), width: 200, editRender: { name: 'ElInput', props: { size: 'small' } } }, { field: 'title', title: t('字段标题'), editRender: { name: 'ElInput', props: { size: 'small' } } },
{ field: 'isSummary', title: t('是否合计'), width: 90, editRender: { name: 'ElSwitch', props: { size: 'small' } }, slots: { default: 'row_isSummary' } }, { field: 'isSummary', title: t('是否合计'), editRender: { name: 'ElSwitch', props: { size: 'small' } }, slots: { default: 'row_isSummary' } },
{ field: 'visible', title: t('是否显示'), width: 90, editRender: { name: 'ElSwitch', props: { size: 'small' } }, slots: { default: 'row_visible' } }, { field: 'visible', title: t('是否显示'), editRender: { name: 'ElSwitch', props: { size: 'small' } }, slots: { default: 'row_visible' } },
{ field: 'groupTitle', title: t('分组标题'), width: 200, editRender: { name: 'ElInput', props: { size: 'small' } } }, { field: 'groupTitle', title: t('分组标题'), editRender: { name: 'ElInput', props: { size: 'small' } } },
{ field: 'width', title: t('列宽'), width: 80, editRender: { name: 'ElInputNumber', props: { size: 'small', min: 0, controlsPosition: 'right' } } }, { field: 'width', title: t('列宽'), editRender: { name: 'ElInputNumber', props: { size: 'small', min: 0, controlsPosition: 'right' } } },
], ],
}, },
{ {
align: 'left', align: 'left',
columnConfig: { // columnConfig: {
width: 130, // // width: 120, //
}, // },
toolbarConfig: { toolbarConfig: {
refresh: false, refresh: false,
import: false, import: false,
@ -318,7 +318,7 @@ const paramConfig = reactive({
{ {
id: 'sysReportConfigEditForm_param', id: 'sysReportConfigEditForm_param',
columns: [ columns: [
{ type: 'checkbox', width: 36, fixed: 'left' }, { type: 'checkbox', width: 60, fixed: 'left' },
{ field: 'paramName', title: t('参数名'), editRender: { name: 'ElInput', props: { size: 'small' } } }, { field: 'paramName', title: t('参数名'), editRender: { name: 'ElInput', props: { size: 'small' } } },
{ field: 'title', title: t('参数标题'), editRender: { name: 'ElInput', props: { size: 'small' } } }, { field: 'title', title: t('参数标题'), editRender: { name: 'ElInput', props: { size: 'small' } } },
{ {
@ -335,9 +335,9 @@ const paramConfig = reactive({
}, },
{ {
align: 'left', align: 'left',
columnConfig: { // columnConfig: {
width: 130, // // width: 130, //
}, // },
toolbarConfig: { toolbarConfig: {
refresh: false, refresh: false,
import: false, import: false,

View File

@ -1,12 +1,12 @@
<template> <template>
<div class="group-panel" v-loading="state.isLoading"> <div class="group-panel" v-loading="state.isLoading">
<el-button-group class="group-panel-buttonGroup"> <el-button-group class="group-panel-buttonGroup">
<el-button icon="el-icon-circle-plus-outline" size="small" @click="createFormShow">{{ $t('新增分组') }}</el-button> <el-button icon="ele-CirclePlus" size="small" @click="createFormShow">{{ $t('新增分组') }}</el-button>
<el-dropdown split-button @command="handleCommand" size="small" @click="editFormShow"> <el-dropdown split-button @command="handleCommand" size="small" :icon="Delete" @click="editFormShow">
{{ $t('编辑分组') }} {{ $t('编辑分组') }}
<template v-slot:dropdown> <template v-slot:dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="del" :icon="Minus">{{ $t('删除分组') }}</el-dropdown-item> <el-dropdown-item command="del" :icon="Delete">{{ $t('删除分组') }}</el-dropdown-item>
<el-dropdown-item command="refresh" :icon="RefreshRight">{{ $t('刷新分组') }}</el-dropdown-item> <el-dropdown-item command="refresh" :icon="RefreshRight">{{ $t('刷新分组') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
@ -38,7 +38,7 @@
<script setup lang="ts" name="sysReportGroup"> <script setup lang="ts" name="sysReportGroup">
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { ElMessage, ElMessageBox, ElTree } from 'element-plus'; import { ElMessage, ElMessageBox, ElTree } from 'element-plus';
import { Minus, RefreshRight } from '@element-plus/icons-vue'; import { Delete, RefreshRight } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import EditReportGroup from './editReportGroup.vue'; import EditReportGroup from './editReportGroup.vue';

View File

@ -1,12 +1,13 @@
<template> <template>
<div> <div>
<el-card class="full-table" shadow="hover"> <TableSearch ref="tableSearch" :search="state.search" @search="onSearch" v-model="state.queryParams" />
<el-card class="full-table" shadow="hover" style="margin-top: 5px">
<vxe-grid ref="xGrid" v-bind="options" :loading="state.isLoading"> <vxe-grid ref="xGrid" v-bind="options" :loading="state.isLoading">
<template #top> <!-- <template #top>
<TableSearch ref="tableSearch" :search="state.search" @search="onSearch" v-model="state.queryParams" /> </template> -->
</template>
<template #toolbar_buttons> <template #toolbar_buttons>
<el-button @click="handleExport"> {{ $t('导出') }} </el-button> <el-button type="primary" icon="ele-FolderOpened" @click="handleExport"> {{ $t('导出') }} </el-button>
</template> </template>
<template #toolbar_tools> </template> <template #toolbar_tools> </template>
</vxe-grid> </vxe-grid>
@ -54,7 +55,7 @@ const state = reactive({
watch( watch(
() => state.totalInfo, () => state.totalInfo,
(val) => { (val) => {
options.showFooter = Object.keys(state.totalInfo).length > 0; if (state.totalInfo != null) options.showFooter = Object.keys(state.totalInfo).length > 0;
} }
); );
@ -66,7 +67,7 @@ onBeforeMount(() => {
state.layoutConfig = res.data.result!; state.layoutConfig = res.data.result!;
if (state.layoutConfig.fields) { if (state.layoutConfig.fields) {
options.columns!.push({ type: 'seq', width: 50 }); options.columns!.push({ type: 'seq', width: 60, fixed: 'left' });
const columns = state.layoutConfig.fields.map((r) => { const columns = state.layoutConfig.fields.map((r) => {
return convertSysReportFieldToVxeColumn(r); return convertSysReportFieldToVxeColumn(r);
@ -133,7 +134,7 @@ const options = useVxeTable<any>(
// //
proxyConfig: { autoLoad: true, ajax: { query: ({ page, sort }) => handleQueryApi(page, sort) } }, proxyConfig: { autoLoad: true, ajax: { query: ({ page, sort }) => handleQueryApi(page, sort) } },
columnConfig: { columnConfig: {
width: 120, // width: 100, //
}, },
pagerConfig: { enabled: false }, pagerConfig: { enabled: false },
showFooter: false, showFooter: false,

View File

@ -55,7 +55,7 @@
</el-tooltip> </el-tooltip>
<el-button icon="ele-CopyDocument" size="small" text type="primary" @click="copy(row)"> {{ $t('复制') }} </el-button> <el-button icon="ele-CopyDocument" size="small" text type="primary" @click="copy(row)"> {{ $t('复制') }} </el-button>
<el-button icon="ele-ScaleToOriginal" size="small" text type="primary" @click="preview(row)"> {{ $t('预览') }} </el-button> <el-button icon="ele-ScaleToOriginal" size="small" text type="primary" @click="preview(row)"> {{ $t('预览') }} </el-button>
<el-button size="small" text type="primary" @click="publicToMenu(row)"> {{ $t('发布到菜单') }} </el-button> <el-button icon="ele-Position" size="small" text type="primary" @click="publicToMenu(row)"> {{ $t('发布到菜单') }} </el-button>
</template> </template>
</vxe-grid> </vxe-grid>
</el-card> </el-card>
@ -121,13 +121,13 @@ const options = useVxeTable<ReportConfigOutput>(
name: '报表数据源', name: '报表数据源',
columns: [ columns: [
{ field: 'seq', type: 'seq', title: t('序号'), width: 60, fixed: 'left' }, { field: 'seq', type: 'seq', title: t('序号'), width: 60, fixed: 'left' },
{ field: 'name', title: t('名称'), minWidth: 200, showOverflow: 'tooltip' }, { field: 'name', title: t('名称'), showOverflow: 'tooltip' },
{ field: 'dsType', title: t('数据源类型'), minWidth: 100, showOverflow: 'tooltip', slots: { default: 'row_dsType' } }, { field: 'dsType', title: t('数据源类型'), showOverflow: 'tooltip', slots: { default: 'row_dsType' } },
{ field: 'dataSource', title: t('数据源'), showOverflow: 'tooltip', slots: { default: 'row_dataSource' } }, { field: 'dataSource', title: t('数据源'), showOverflow: 'tooltip', slots: { default: 'row_dataSource' } },
{ field: 'groupName', title: t('分组名称'), showOverflow: 'tooltip' }, { field: 'groupName', title: t('分组名称'), showOverflow: 'tooltip' },
{ field: 'record', title: t('修改记录'), width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } }, { field: 'record', title: t('修改记录'), width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } },
{ field: 'buttons', title: t('操作'), fixed: 'right', width: 300, showOverflow: true, slots: { default: 'row_buttons' } }, { field: 'buttons', title: t('操作'), fixed: 'right', width: 320, showOverflow: true, slots: { default: 'row_buttons' } },
], ],
}, },
// vxeGrid()vxe-table // vxeGrid()vxe-table

View File

@ -94,9 +94,9 @@ const options = useVxeTable<SysReportDataSource>(
name: '报表数据源', name: '报表数据源',
columns: [ columns: [
{ field: 'seq', type: 'seq', title: t('序号'), width: 60, fixed: 'left' }, { field: 'seq', type: 'seq', title: t('序号'), width: 60, fixed: 'left' },
{ field: 'name', title: t('名称'), minWidth: 200, showOverflow: 'tooltip' }, { field: 'name', title: t('名称'), showOverflow: 'tooltip' },
{ field: 'dbType', title: t('数据库类型'), minWidth: 100, showOverflow: 'tooltip', slots: { default: 'row_dbType' } }, { field: 'dbType', title: t('数据库类型'), showOverflow: 'tooltip', slots: { default: 'row_dbType' } },
{ field: 'connectionString', title: t('连接字符串'), minWidth: 400, showOverflow: 'tooltip' }, { field: 'connectionString', title: t('连接字符串'), showOverflow: 'tooltip' },
{ field: 'memo', title: t('备注'), showOverflow: 'tooltip' }, { field: 'memo', title: t('备注'), showOverflow: 'tooltip' },
{ field: 'record', title: t('修改记录'), width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } }, { field: 'record', title: t('修改记录'), width: 100, showOverflow: 'tooltip', slots: { default: 'row_record' } },