<template>
|
<div class="layout-container">
|
<a :href="exportHref" ref="export"></a>
|
<!--开启懒加载2020.12.06 -->
|
<vol-box :on-model-close="closeCustomModel" v-model="viewModel" :height="520" :width="500" :padding="0" :lazy="true"
|
title="设置">
|
<template #content>
|
<custom-column :view-columns="viewColumns"></custom-column>
|
</template>
|
<template #footer>
|
<div style="text-align: center">
|
<el-button type="default" size="small" @click="closeCustomModel"><i class="el-icon-close"></i>取消</el-button>
|
<el-button type="success" size="small" @click="initViewColumns(true)"><i
|
class="el-icon-refresh"></i>重置</el-button>
|
<el-button type="primary" size="small" @click="saveColumnConfig"><i class="el-icon-check"></i>确定</el-button>
|
</div>
|
</template>
|
</vol-box>
|
<ViewGridAudit @auditClick="saveAudit" :option="table" ref="audit">
|
|
</ViewGridAudit>
|
|
<!--导入excel功能-->
|
<!--2020.10.31添加导入前的方法-->
|
<!--开启懒加载2020.12.06 -->
|
<!-- 2022.01.08增加明细表导入判断 -->
|
<vol-box v-if="upload.url" v-model="upload.excel" :height="350" :width="600" :lazy="true"
|
:title="(boxModel ? detailOptions.cnName : table.cnName) + '-导入'">
|
<UploadExcel ref="upload_excel" @importExcelAfter="importExcelAfter" :importExcelBefore="importExcelBefore"
|
:url="upload.url" :template="upload.template"></UploadExcel>
|
</vol-box>
|
<!--头部自定义组件-->
|
<component :is="dynamicComponent.gridHeader" ref="gridHeader" @parentCall="parentCall"></component>
|
<!--主界面查询与table表单布局-->
|
<div class="view-container">
|
<!-- 2020.09.11增加固定查询表单 -->
|
<!--查询条件-->
|
<div class="grid-search">
|
<div :class="[fiexdSearchForm ? 'fiexd-search-box' : 'search-box']" v-show="searchBoxShow">
|
<!-- 2020.09.13增加formFileds拼写错误兼容处理 -->
|
<vol-form ref="searchForm" :load-key="false" style="padding: 0 15px" :label-width="labelWidth"
|
:formRules="searchFormOptions" :formFields="searchFormFields" :select2Count="select2Count">
|
<template #footer>
|
<div v-if="!fiexdSearchForm" class="form-closex">
|
<el-button size="small" type="primary" plain @click="search">
|
<i class="el-icon-search" />查询
|
</el-button>
|
|
<el-button size="small" type="success" plain @click="resetSearch">
|
<i class="el-icon-refresh-right" />重置
|
</el-button>
|
<el-button size="small" plain @click="searchBoxShow = !searchBoxShow">
|
<i class="el-icon-switch-button" />关闭
|
</el-button>
|
</div>
|
</template>
|
</vol-form>
|
<div v-if="fiexdSearchForm" class="fs-line"></div>
|
</div>
|
<div class="view-header">
|
<div class="desc-text">
|
<i class="el-icon-s-grid" />
|
<span>{{ table.cnName }}</span>
|
</div>
|
<div class="notice">
|
<a class="text" v-html="text || extend.text"></a>
|
</div>
|
<!--快速查询字段-->
|
<div class="search-line" v-if="!fiexdSearchForm && !searchBoxShow">
|
<QuickSearch v-if="singleSearch" :searchFormOptions="searchFormOptions" :searchFormFields="searchFormFields"
|
:select2Count="select2Count" :label-width="labelWidth" :queryFields="queryFields"
|
@tiggerPress="quickSearchKeyPress"></QuickSearch>
|
</div>
|
<!--操作按钮组-->
|
<!-- 2020.11.29增加查询界面hidden属性 -->
|
|
<div class="btn-group">
|
<template :key="bIndex" v-for="(btn, bIndex) in buttons.slice(0, maxBtnLength)">
|
<el-dropdown size="small" v-if="btn.data" :split-button="false">
|
<el-button :color="btn.color" :dark="false" :type="btn.type" :plain="btn.plain">
|
{{ btn.name }}<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
<template #dropdown>
|
<el-dropdown-menu>
|
<el-dropdown-item v-for="(item, index) in btn.data" :key="index">
|
<div @click="onClick(item.onClick)">
|
<i :class="item.icon"></i>
|
{{ item.name }}
|
</div>
|
</el-dropdown-item>
|
</el-dropdown-menu>
|
</template>
|
</el-dropdown>
|
<el-button v-else :type="btn.type" size="small" :color="btn.color" :dark="false" :class="btn.class"
|
:plain="btn.plain" v-show="!btn.hidden" @click="onClick(btn.onClick)">
|
<i :class="btn.icon"></i> {{ btn.name }}
|
</el-button>
|
</template>
|
<el-button type="default" style="padding: 0px 10px" size="small" :plain="true" v-if="showCustom"
|
@click="showCustomModel">
|
<i class="el-icon-s-grid"></i>
|
</el-button>
|
<el-dropdown size="small" @click="changeDropdown" v-if="buttons.length > maxBtnLength">
|
<el-button type="primary" plain size="small">
|
更多<i class="el-icon-arrow-down el-icon--right"></i>
|
</el-button>
|
<template #dropdown>
|
<el-dropdown-menu>
|
<el-dropdown-item @click="changeDropdown(item.name)" :name="item.name" v-show="!item.hidden" v-for="(item, dIndex) in buttons.slice(
|
maxBtnLength,
|
buttons.length
|
)" :key="dIndex">
|
<i :class="item.icon"></i> {{ item.name }}</el-dropdown-item>
|
</el-dropdown-menu>
|
</template>
|
</el-dropdown>
|
</div>
|
</div>
|
|
<!-- 分割位置 -->
|
<vol-box v-if="boxInit" v-model="boxModel" :title="boxOptions.title" :width="boxOptions.width"
|
:height="boxOptions.height" :modal="boxOptions.modal" :draggable="boxOptions.draggable" :padding="0"
|
:on-model-close="onGridModelClose" @fullscreen="fullscreen">
|
<!--明细头部自定义组件-->
|
<template #content>
|
<div class="box-com vol-edit-box">
|
<div class="vol-edit-content">
|
<component :is="dynamicComponent.modelHeader" ref="modelHeader" @parentCall="parentCall"></component>
|
<!-- <div v-show="isBoxAudit" class="flow-step">
|
<div v-for="(item, index) in workFlowSteps" :key="index">
|
{{ item.stepName }}
|
</div>
|
</div> -->
|
<div class="item form-item">
|
<vol-form ref="form" :editor="editor" :load-key="false" :label-width="boxOptions.labelWidth"
|
:formRules="editFormOptions" :formFields="editFormFields" :select2Count="select2Count"></vol-form>
|
</div>
|
<!--明细body自定义组件-->
|
<component :is="dynamicComponent.modelBody" ref="modelBody" @parentCall="parentCall"></component>
|
<div v-show="hasDetail" v-if="detail.columns && detail.columns.length > 0"
|
class="grid-detail table-item item">
|
<div class="toolbar">
|
<div class="title form-text">
|
<span>
|
<i class="el-icon-menu" />
|
{{ detail.cnName }}
|
</span>
|
</div>
|
<!--明细表格按钮-->
|
<div class="btns" v-show="!isBoxAudit">
|
<el-button v-for="(btn, bIndex) in detailOptions.buttons" :key="bIndex" :plain="btn.plain"
|
v-show="!(typeof btn.hidden == 'boolean' && btn.hidden)" @click="onClick(btn.onClick)"
|
size="small"><i :class="btn.icon"></i>{{ btn.name }}</el-button>
|
</div>
|
</div>
|
<vol-table ref="detail" @loadBefore="loadInternalDetailTableBefore" @loadAfter="loadDetailTableAfter"
|
@rowChange="detailRowOnChange" @rowClick="detailRowOnClick" :url="detailOptions.url"
|
:load-key="false" :index="true" :tableData="detailOptions.data" :columns="detailOptions.columns"
|
:pagination="detailOptions.pagination" :height="detailOptions.height" :single="detailOptions.single"
|
:pagination-hide="detailOptions.paginationHide" :defaultLoadPage="detailOptions.load"
|
:beginEdit="detailOptions.beginEdit" :endEditBefore="detailOptions.endEditBefore"
|
:endEditAfter="detailOptions.endEditAfter" :double-edit="detailOptions.doubleEdit"
|
:column-index="detailOptions.columnIndex" :ck="detailOptions.ck"
|
:text-inline="detailOptions.textInline" :select2Count="select2Count" :selectable="detailSelectable"
|
:spanMethod="detailSpanMethod"></vol-table>
|
</div>
|
<component :is="dynamicComponent.modelFooter" ref="modelFooter" @parentCall="parentCall"></component>
|
</div>
|
<div class="vol-edit-box-right">
|
<component :is="dynamicComponent.modelRight" ref="modelRight" @parentCall="parentCall"></component>
|
</div>
|
</div>
|
</template>
|
<template #footer>
|
<div style="text-align: center;" v-show="isBoxAudit">
|
<el-button size="small" type="primary" plain @click="onGridModelClose(false)">
|
<i class="el-icon-close">关闭</i>
|
</el-button>
|
<el-button size="small" type="primary" v-show="auditParam.showViewButton"
|
@click="auditParam.model = true">
|
<i class="el-icon-view">审批</i>
|
</el-button>
|
</div>
|
<div v-show="!isBoxAudit">
|
<el-button v-for="(btn, bIndex) in boxButtons" :key="bIndex" :type="btn.type" size="small"
|
:plain="btn.plain" v-show="!(typeof btn.hidden == 'boolean' && btn.hidden)"
|
:disabled="btn.hasOwnProperty('disabled') && !!btn.disabled" @click="onClick(btn.onClick)">
|
<i :class="btn.icon"></i>{{ btn.name }}
|
</el-button>
|
<el-button size="small" type="primary" plain @click="onGridModelClose(false)">
|
<i class="el-icon-close">关闭</i>
|
</el-button>
|
</div>
|
</template>
|
</vol-box>
|
</div>
|
<!--body自定义组件-->
|
<div class="grid-body">
|
<component :is="dynamicComponent.gridBody" ref="gridBody" @parentCall="parentCall"></component>
|
</div>
|
|
<!--table表格-->
|
<div class="grid-container">
|
<!-- 2021.05.02增加树形结构 rowKey -->
|
<vol-table ref="table" :single="single" :rowKey="rowKey" :loadTreeChildren="loadTreeTableChildren"
|
@loadBefore="loadTableBefore" @loadAfter="loadTableAfter" @rowChange="rowOnChange" @rowClick="rowOnClick"
|
@rowDbClick="rowOnDbClick" @selectionChange="selectionOnChange" :tableData="[]" :linkView="linkData"
|
:columns="columns" :pagination="pagination" :height="height" :max-height="tableMaxHeight"
|
:pagination-hide="paginationHide" :url="url" :load-key="false" :defaultLoadPage="load"
|
:double-edit="doubleEdit" :index="doubleEdit" :beginEdit="tableBeginEdit" :endEditBefore="tableEndEditBefore"
|
:column-index="columnIndex" :text-inline="textInline" :ck="ck" :select2Count="select2Count"
|
:selectable="selectable" :spanMethod="spanMethod" :lazy="lazy" :defaultExpandAll="defaultExpandAll"
|
:expandRowKeys="expandRowKeys" :rowParentField="rowParentField"></vol-table>
|
</div>
|
</div>
|
|
<!--footer自定义组件-->
|
<component :is="dynamicComponent.gridFooter" ref="gridFooter" @parentCall="parentCall"></component>
|
</div>
|
</template>
|
|
<script lang="jsx">
|
const _const = {
|
EDIT: 'update',
|
ADD: 'Add',
|
VIEW: 'view',
|
PAGE: 'getPageData',
|
AUDIT: 'audit',
|
DEL: 'del',
|
EXPORT: 'Export', //导出操作返回加密后的路径
|
DOWNLOAD: 'DownLoadFile', //导出文件
|
DOWNLOADTEMPLATE: 'DownLoadTemplate', //下载导入模板
|
IMPORT: 'Import', //导入(导入表的Excel功能)
|
UPLOAD: 'Upload' //上传文件
|
};
|
import Empty from '@/components/basic/Empty.vue';
|
|
import VolTable from '@/components/basic/VolTable.vue';
|
import VolForm from '@/components/basic/VolForm.vue';
|
import {
|
defineAsyncComponent,
|
defineComponent,
|
ref,
|
shallowRef,
|
toRaw
|
} from 'vue';
|
var vueParam = {
|
emits: ['parentCall'],
|
components: {
|
'vol-form': VolForm,
|
'vol-table': VolTable,
|
VolBox: defineAsyncComponent(() => import('@/components/basic/VolBox.vue')),
|
QuickSearch: defineAsyncComponent(() =>
|
import('@/components/basic/QuickSearch.vue')
|
),
|
Audit: defineAsyncComponent(() => import('@/components/basic/Audit.vue')),
|
UploadExcel: defineAsyncComponent(() =>
|
import('@/components/basic/UploadExcel.vue')
|
),
|
'custom-column': defineAsyncComponent(() =>
|
import('./ViewGridCustomColumn.vue')
|
),
|
'vol-header': defineAsyncComponent(() => import('./../VolHeader.vue')),
|
ViewGridAudit: defineAsyncComponent(() => import('./ViewGridAudit.vue'))
|
},
|
props: {},
|
setup(props) {
|
//2021.07.17调整扩展组件组件
|
const dynamicCom = {
|
gridHeader: Empty,
|
gridBody: Empty,
|
gridFooter: Empty,
|
modelHeader: Empty,
|
modelBody: Empty,
|
modelRight: Empty,
|
modelFooter: Empty
|
};
|
//合并扩展组件
|
if (props.extend.components) {
|
for (const key in props.extend.components) {
|
if (props.extend.components[key]) {
|
dynamicCom[key] = toRaw(props.extend.components[key]);
|
}
|
}
|
}
|
const dynamicComponent = shallowRef(dynamicCom);
|
return { dynamicComponent };
|
},
|
data() {
|
return {
|
isBoxAudit: false,
|
formFieldsType: [],
|
workFlowSteps: [],
|
//树形结构的主键字段,如果设置值默认会开启树形table;注意rowKey字段的值必须是唯一(2021.05.02)
|
rowKey: undefined,
|
fiexdSearchForm: false, //2020.09.011是否固定查询表单,true查询表单将固定显示在表单的最上面
|
_inited: false,
|
doubleEdit: false, //2021.03.19是否开启查询界面表格双击编辑
|
single: false, //表是否单选
|
const: _const, //增删改查导入导出等对应的action
|
boxInit: false, //新建或编辑的弹出框初化状态,默认不做初始化,点击新建或编辑才初始化弹出框
|
searchBoxShow: false, //高级查询(界面查询后的下拉框点击触发)
|
singleSearch: {}, //快速查询字段
|
exportHref: '',
|
currentAction: _const.ADD, //当新建或编辑时,记录当前的状态:如当前操作是新建
|
currentRow: {}, //当前编辑或查看数据的行
|
closable: false,
|
boxModel: false, //弹出新建、编辑框
|
width: 700, //弹出框查看表数据结构
|
labelWidth: 100, //高级查询的标签宽度
|
viewModel: false, //查看表结构的弹出框
|
viewColumns: [], //查看表结构的列数据
|
viewColumnsClone: [],
|
showCustom: true, //是否显示自定义配置列按钮2022.05.27
|
// viewData: [], //查看表结构信息
|
maxBtnLength: 8, //界面按钮最多显示的个数,超过的数量都显示在更多中
|
buttons: [], //查询界面按钮 如需要其他操作按钮,可在表对应的.js中添加(如:Sys_User.js中buttons添加其他按钮)
|
splitButtons: [],
|
uploadfiled: [], //上传文件图片的字段
|
boxButtons: [], //弹出框按钮 如需要其他操作按钮,可在表对应的.js中添加
|
dicKeys: [], //当前界面所有的下拉框字典编号及数据源
|
hasKeyField: [], //有字典数据源的字段
|
keyValueType: { _dinit: false },
|
url: '', //界面表查询的数据源的url
|
hasDetail: false, //是否有从表(明细)表格数据
|
initActivated: false,
|
load: true, //是否默认加载表数据
|
activatedLoad: false, //页面触发actived时是否刷新页面数据
|
// summary: false, //查询界面table是否显示合计
|
//需要从远程绑定数据源的字典编号,如果字典数据源的查询结果较多,请在onInit中将字典编号添加进来
|
//只对自定sql有效
|
remoteKeys: [],
|
columnIndex: true, //2020.11.01是否显示行号
|
ck: true, //2020.11.01是否显示checkbox
|
continueAdd: false, //2021.04.11新建时是否可以连续新建操作
|
continueAddName: '保存后继续添加', //2021.04.11按钮名称
|
// detailUrl: "",
|
detailOptions: {
|
paginationHide: false,//是否隐藏明细表分页2023.10.23
|
//弹出框从表(明细)对象
|
//从表配置
|
buttons: [], //弹出框从表表格操作按钮,目前有删除行,添加行,刷新操作,如需要其他操作按钮,可在表对应的.js中添加
|
cnName: '', //从表名称
|
key: '', //从表主键名
|
data: [], //数据源
|
columns: [], //从表列信息
|
edit: true, //明细是否可以编辑
|
single: false, //明细表是否单选
|
load: false, //
|
delKeys: [], //当编辑时删除当前明细的行主键值
|
url: '', //从表加载数据的url
|
pagination: { total: 0, size: 100, sortName: '' }, //从表分页配置数据
|
height: 0, //默认从表高度
|
textInline: true, //明细表行内容显示在一行上,如果需要换行显示,请设置为false
|
doubleEdit: true, //使用双击编辑
|
clickEdit: false, //是否开启点击单元格编辑,点击其他行时结束编辑
|
currentReadonly: false, //当前用户没有编辑或新建权限时,表单只读(可用于判断用户是否有编辑或新建权限)
|
//开启编辑时
|
beginEdit: (row, column, index) => {
|
return true;
|
},
|
//结束编辑前
|
endEditBefore: (row, column, index) => {
|
return true;
|
},
|
//结束编辑后
|
endEditAfter: (row, column, index) => {
|
return true;
|
},
|
columnIndex: false, //2020.11.01明细是否显示行号
|
ck: true //2020.11.01明细是否显示checkbox
|
},
|
auditParam: {
|
//审核对象
|
rows: 0, //当前选中审核的行数
|
model: false, //审核弹出框
|
value: -1, //审核结果
|
status: -1,
|
reason: '', //审核原因
|
height: 500,
|
showViewButton: true,
|
auditHis: [],
|
showAction: false, //是否显示审批操作(当前节点为用户审批时显示)
|
//审核选项(可自行再添加)
|
data: [
|
{ text: '通过', value: 1 },
|
{ text: '拒绝', value: 2 },
|
{ text: '驳回', value: 3 }
|
]
|
},
|
upload: {
|
//导入上传excel对象
|
excel: false, //导入的弹出框是否显示
|
url: '', //导入的路径,如果没有值,则不渲染导入功能
|
template: {
|
//下载模板对象
|
url: '', //下载模板路径
|
fileName: '' //模板下载的中文名
|
},
|
init: false //是否有导入权限,有才渲染导入组件
|
},
|
height: 0, //表高度
|
tableHeight: 0, //查询页面table的高度
|
tableMaxHeight: 0, //查询页面table的最大高度
|
textInline: true, //table内容超出后是否不换行2020.01.16
|
pagination: { total: 0, size: 30, sortName: '' }, //从分页配置数据
|
boxOptions: {
|
title: '', //弹出框显示的标题2022.08.01
|
saveClose: true,
|
labelWidth: 100,
|
height: 0,
|
width: 0,
|
summary: false, //弹出框明细table是否显示合计
|
draggable: false, //2022.09.12弹出框拖动功能
|
modal: true //2022.09.12弹出框背景遮罩层
|
}, //saveClose新建或编辑成功后是否关闭弹出框//弹出框的标签宽度labelWidth
|
editor: {
|
uploadImgUrl: '', //上传路径
|
upload: null //上传方法
|
},
|
numberFields: [],
|
//2022.09.26增加自定义导出文件名
|
downloadFileName: null,
|
select2Count: 2000, //超出500数量显示select2组件
|
paginationHide: false,//是隐藏分页(2023.10.11)
|
queryFields: [],//快捷查询字段2024.01.18增加多个快捷查询字段
|
lazy: true,//树形表格是否默认延迟加载
|
defaultExpandAll: false,//树形表格是否展开所有
|
expandRowKeys: [],//默认展开行的主键值2024.09.03
|
paginationHide: false,//是否隐藏分页
|
rowParentField: "", //树形表格父级id
|
text: ""//界面上标题后显示的文本,可以是html标签
|
};
|
},
|
methods: {},
|
activated() {
|
this.initFlowQuery();
|
//2020.06.25增加activated方法
|
this.onActivated && this.onActivated();
|
if (!this._inited) {
|
this._inited = true;
|
return;
|
}
|
if (this.activatedLoad) {
|
this.refresh();
|
}
|
},
|
mounted() {
|
this.mounted();
|
// this.$refs.searchForm.forEach()
|
},
|
unmounted() {
|
this.destroyed();
|
},
|
created: function () {
|
//合并自定义业务扩展方法
|
Object.assign(this, this.extend.methods);
|
//如果没有指定排序字段,则用主键作为默认排序字段
|
this.pagination.sortName = this.table.sortName || this.table.key;
|
this.initBoxButtons(); //初始化弹出框与明细表格按钮
|
this.initAuditColumn();
|
this.onInit(); //初始化前,如果需要做其他处理在扩展方法中覆盖此方法
|
this.getButtons();
|
//初始化自定义表格列
|
this.initViewColumns();
|
//初始编辑框等数据
|
this.initBoxHeightWidth();
|
this.initDicKeys(); //初始下框数据源
|
this.onInited(); //初始化后,如果需要做其他处理在扩展方法中覆盖此方法
|
},
|
beforeUpdate: function () { },
|
updated: function () { }
|
};
|
|
import props from './props.js';
|
import methods from './methods.jsx';
|
|
//合并属性
|
vueParam.props = Object.assign(vueParam.props, props);
|
//合并方法
|
vueParam.methods = Object.assign(
|
vueParam.methods,
|
methods,
|
props.extend.methods
|
);
|
export default defineComponent(vueParam);
|
</script>
|
<style lang="less" scoped>
|
@import './ViewGrid.less';
|
</style>
|
<style lang="less" scoped>
|
.btn-group ::v-deep(.ivu-select-dropdown) {
|
padding: 0px !important;
|
right: 3px;
|
}
|
|
.btn-group ::v-deep(.ivu-select-dropdown .ivu-dropdown-menu) {
|
min-width: 100px;
|
right: -2px;
|
position: absolute;
|
background: white;
|
width: 130px;
|
border-radius: 5px;
|
border: 1px solid #e7e5e5;
|
}
|
|
.vertical-center-modal ::v-deep(.srcoll-content) {
|
padding: 0;
|
}
|
|
.view-model-content {
|
background: #eee;
|
}
|
|
.grid-detail ::v-deep(.v-table .el-table__header th) {
|
height: 44px;
|
}
|
</style>
|
<style lang="less" scoped>
|
.grid-search {
|
position: relative;
|
|
.search-box {
|
background: #fefefe;
|
margin-top: 33px;
|
border: 1px solid #eae8e8;
|
position: absolute;
|
z-index: 999;
|
left: 15px;
|
right: 15px;
|
padding: 25px 20px;
|
padding-bottom: 0;
|
border-top: 0;
|
box-shadow: 0 7px 18px -12px #bdc0bb;
|
}
|
}
|
</style>
|