提交 11e1237f 编写于 作者: Mosher's avatar Mosher

update:新增表格导出支持

上级 c87ae67c
...@@ -86,6 +86,9 @@ export class AppSysAction { ...@@ -86,6 +86,9 @@ export class AppSysAction {
case 'ToggleFilter': case 'ToggleFilter':
this.toggleFilter(params); this.toggleFilter(params);
break; break;
case 'ExportExcel':
this.exportExcel(params);
break;
default: default:
App.getNotificationService().info({ App.getNotificationService().info({
message: '提示', message: '提示',
...@@ -359,4 +362,20 @@ export class AppSysAction { ...@@ -359,4 +362,20 @@ export class AppSysAction {
actionEnvironment.state.expandSearchForm = !actionEnvironment.state.expandSearchForm; actionEnvironment.state.expandSearchForm = !actionEnvironment.state.expandSearchForm;
} }
} }
/**
* 导出
*
* @param params 界面行为参数对象
* @return {*}
*/
public static async exportExcel(params: IUIActionParams) {
const { actionEnvironment } = params;
// 视图里获取多数据部件
if (actionEnvironment.xDataControl && hasFunction(actionEnvironment.xDataControl, "exportExcel")) {
await actionEnvironment.xDataControl.exportExcel();
} else if (isExist(actionEnvironment.exportExcel)) {
await actionEnvironment.exportExcel();
}
}
} }
...@@ -43,6 +43,13 @@ export interface MainControlState extends ControlStateBase { ...@@ -43,6 +43,13 @@ export interface MainControlState extends ControlStateBase {
*/ */
appDeCodeName: string; appDeCodeName: string;
/**
* @description 应用实体逻辑名称
* @type {string}
* @memberof MainControlState
*/
appDeLogicName: string;
/** /**
* @description 应用实体主键属性codeName * @description 应用实体主键属性codeName
* @type {string} * @type {string}
......
...@@ -8,6 +8,13 @@ import { IParam, MainControlState } from '@core'; ...@@ -8,6 +8,13 @@ import { IParam, MainControlState } from '@core';
*/ */
export interface MDControlState extends MainControlState { export interface MDControlState extends MainControlState {
/**
* @description 导出项
* @type {IParam[]}
* @memberof MDControlState
*/
exportItems?: IParam[];
/** /**
* @description 多数据部件数据 * @description 多数据部件数据
* @type {IParam[]} * @type {IParam[]}
......
import { MDControlState, MainControl, deepCopy, IActionParam, IParam, UIBase, isExistAndNotEmpty, UIUtil } from '@core'; import { MDControlState, MainControl, deepCopy, IActionParam, IParam, UIBase, isExistAndNotEmpty, UIUtil, ExportExcel, translateCodeList2Text } from '@core';
import { Modal } from 'ant-design-vue'; import { Modal } from 'ant-design-vue';
/** /**
...@@ -393,6 +393,155 @@ export class MDControl extends MainControl { ...@@ -393,6 +393,155 @@ export class MDControl extends MainControl {
return refresh; return refresh;
} }
/**
* @description 导出
* @protected
* @param {*} [opt={}]
* @memberof MDControl
*/
protected async exportExcel(opt: any = {}) { }
/**
* @description 获取导出项
* @protected
* @return {*} {IParam[]}
* @memberof MDControl
*/
protected getExportItems(): IParam[] {
return this.state.exportItems || [];
}
private getExportHeader(exportItems: IParam[]): string[] {
const headers: string[] = [];
exportItems.forEach((item: IParam) => {
headers.push(item.label);
});
return headers;
}
/**
* @description 翻译导出数据
* @private
* @param {IParam[]} datas
* @param {IParam[]} exportItems
* @return {*}
* @memberof MDControl
*/
private async formatExcelData(datas: IParam[], exportItems: IParam[]) {
const { context, viewParams } = this.state;
const codeListService = App.getCodeListService();
const codeListColumn: Map<string, IParam[]> = new Map();
// 获取代码表
for (const item of exportItems) {
if (item.codeListTag && !codeListColumn.has(`${item.field},${item.codeListTag}`)) {
const codeListItems = await codeListService.getCodeListItems({
tag: item.codeListTag,
context: context,
viewParams: viewParams
});
codeListColumn.set(`${item.field},${item.codeListTag}`, codeListItems);
}
}
const items: IParam[] = [];
if (codeListColumn.size > 0) {
datas.forEach((data: IParam) => {
const temp = deepCopy(data.$DO);
codeListColumn.forEach((codeListItems: IParam[], key: string) => {
const values = key.split(',');
if (values.length === 2) {
Object.assign(temp, { [values[0]]: translateCodeList2Text(values[1], temp[values[0]], codeListItems) });
}
});
items.push(temp);
})
}
return items.map((item: IParam) => exportItems.map((j: IParam) => item[j.field]));
}
/**
* @description 执行导出
* @private
* @param {IParam[]} [_data=[]]
* @memberof MDControl
*/
private async doExport(_data: IParam[] = []) {
const { appDeLogicName } = this.state;
const exportItems = this.getExportItems();
if (exportItems && exportItems.length > 0) {
const tHeader: string[] = this.getExportHeader(exportItems);
const data = await this.formatExcelData(_data, exportItems);
const excel = await ExportExcel.getInstance().exportExcel();
excel.export_json_to_excel({
header: tHeader,
data,
filename: `${appDeLogicName}表`,
authWidth: true,
bookType: "xlsx"
});
}
}
/**
* @description 使用导出功能模块
* @return {*}
* @memberof MDControl
*/
public useExportExcel() {
const exportExcel = async (opt: IParam = {}) => {
const {
items,
mdCtrlPaging,
mdCtrlSort,
controlService,
context,
viewParams,
controlAction,
showBusyIndicator
} = this.state;
let tempViewParams = deepCopy(viewParams ? viewParams : {});
// 最大行
if (Object.is(opt.type, 'maxRowCount')) {
Object.assign(tempViewParams, { page: 0, size: opt.maxRowCount ? opt.maxRowCount : 1000 });
// } else if (Object.is(opt.type, 'activatedPage')) {
} else {
// 当前激活页
const { current, pageSize } = mdCtrlPaging;
Object.assign(tempViewParams, { page: current - 1, size: pageSize });
this.doExport(items);
return;
}
// 远程获取
const { noSort, minorSortDir, minorSortPSDEF } = mdCtrlSort;
if (!noSort && minorSortDir && minorSortPSDEF) {
Object.assign(tempViewParams, { sort: `${minorSortPSDEF},${minorSortDir}` });
}
const arg: any = {};
Object.assign(arg, tempViewParams);
this.emit('ctrlEvent', { tag: this.props.name, action: 'beforeload', data: arg });
let tempContext = deepCopy(context ? context : {});
try {
const response = await controlService.search(tempContext, arg, {
action: controlAction.fetchAction,
isLoading: showBusyIndicator
});
if (!response || response.status !== 200) {
App.getNotificationService().warning({
message: '导出获取数据集失败',
description: response.message
});
}
this.doExport(response.data);
} catch (error: any) {
App.getNotificationService().error({
message: '导出数据失败',
description: error?.data
});
}
}
this.exportExcel = exportExcel;
return exportExcel;
}
/** /**
* 处理数据状态变化(逻辑数据+UI) * 处理数据状态变化(逻辑数据+UI)
* *
...@@ -484,6 +633,7 @@ export class MDControl extends MainControl { ...@@ -484,6 +633,7 @@ export class MDControl extends MainControl {
remove: this.useRemove(), remove: this.useRemove(),
newRow: this.useNewRow(), newRow: this.useNewRow(),
refresh: this.useRefresh(), refresh: this.useRefresh(),
exportExcel: this.useExportExcel()
}; };
} }
} }
import { AppCodeListConfig } from '@/app/config';
import { IParam } from '@core';
import { clone } from 'ramda'; import { clone } from 'ramda';
/** /**
...@@ -385,3 +387,63 @@ export const styleObj2Str: Function = (style: any) => { ...@@ -385,3 +387,63 @@ export const styleObj2Str: Function = (style: any) => {
} }
return s; return s;
}; };
/**
* 获取选中代码表项
* @param codeListTag
* @param value
* @param codeListItems
* @returns
*/
const getSelectCodeListItems: Function = (codeListTag: string, value: any, codeListItems: IParam[], valueSeparator: string = ',') => {
const codeList = AppCodeListConfig[codeListTag];
const _valueSeparator = codeList.valueSeparator || valueSeparator;
// 值的集合
let values: any[] = [];
// 选中代码表项的集合
const selectedItems: any[] = [];
if(codeList.orMode == 'NUM'){
codeListItems.forEach((_item: any, index: number)=>{
const nValue = parseInt((value as any), 10);
if((parseInt(_item.value, 10) & nValue) > 0){
selectedItems.push(deepCopy(_item));
}
});
} else {
// 数值直接赋值
if (typeof value === 'number'){
values = [value];
} else {
values = [...value.toString().split(_valueSeparator)];
}
values.forEach((v: any)=>{
let selected = codeListItems.find((_item:any)=> _item.value == v);
if (selected) {
selectedItems.push(selected);
} else {
selectedItems.push({ text: v });
}
})
}
return selectedItems;
}
/**
* 翻译代码表
* @param codeListTag 代码表标识
* @param value 值
* @param codeListItems 代码表项
* @param textSeparator 值分隔符
* @returns
*/
export const translateCodeList2Text: Function = (codeListTag: string, value: any, codeListItems: IParam[] = [], textSeparator: string = '、'): string => {
let text: string = '';
const items = getSelectCodeListItems(codeListTag, value, codeListItems);
items.forEach((item: any, index: number) => {
if (index !== 0) {
text += textSeparator;
}
text += item.text;
});
return isExistAndNotEmpty(text) ? text : '';
}
...@@ -26,6 +26,7 @@ export const ctrlState = { ...@@ -26,6 +26,7 @@ export const ctrlState = {
selectColumnWidth: {{#if (neq ctrl.aggMode 'NONE')}}100{{else}}50{{/if}}, selectColumnWidth: {{#if (neq ctrl.aggMode 'NONE')}}100{{else}}50{{/if}},
appEntityCodeName: '{{ctrl.appEntity.codeName}}', appEntityCodeName: '{{ctrl.appEntity.codeName}}',
appDeCodeName:'{{ctrl.appEntity.codeName}}', appDeCodeName:'{{ctrl.appEntity.codeName}}',
appDeLogicName: '{{ctrl.appEntity.logicName}}',
appDeKeyFieldName: '{{#if ctrl.appEntity.keyPSAppDEField}}{{ctrl.appEntity.keyPSAppDEField.codeName}}{{/if}}', appDeKeyFieldName: '{{#if ctrl.appEntity.keyPSAppDEField}}{{ctrl.appEntity.keyPSAppDEField.codeName}}{{/if}}',
appDeMajorFieldName: '{{#if ctrl.appEntity.majorPSAppDEField}}{{ctrl.appEntity.majorPSAppDEField.codeName}}{{/if}}', appDeMajorFieldName: '{{#if ctrl.appEntity.majorPSAppDEField}}{{ctrl.appEntity.majorPSAppDEField.codeName}}{{/if}}',
controlService: new GridService<ControlVO>(ControlVO, new {{pascalCase ctrl.psAppDataEntity.codeName}}Service() ), controlService: new GridService<ControlVO>(ControlVO, new {{pascalCase ctrl.psAppDataEntity.codeName}}Service() ),
...@@ -53,6 +54,22 @@ export const ctrlState = { ...@@ -53,6 +54,22 @@ export const ctrlState = {
{{/if}} {{/if}}
{{/each}} {{/each}}
], ],
{{#if (and ctrl.psDEDataExport ctrl.psDEDataExport.psDEDataExportItems)}}
// 数据导出
exportItems: [
{{#each ctrl.psDEDataExport.psDEDataExportItems as | exportItem |}}
{
field: '{{lowerCase exportItem.psAppDEField.codeName}}',
{{#if exportItem.psCodeList}}
codeListTag: '{{exportItem.psCodeList.codeListTag}}',
{{/if}}
label: '{{exportItem.caption}}',
lanResTag: '{{#if (and exportItem.capPSLanguageRes exportItem.capPSLanguageRes.lanResTag)}}{{exportItem.capPSLanguageRes}}{{/if}}',
show: true
}{{#unless @last}},{{/unless}}
{{/each}}
],
{{/if}}
items: [], items: [],
selectedRowKeys: [], selectedRowKeys: [],
// 多数据部件分组 // 多数据部件分组
......
...@@ -39,7 +39,7 @@ interface CtrlEmit { ...@@ -39,7 +39,7 @@ interface CtrlEmit {
const emit = defineEmits<CtrlEmit>(); const emit = defineEmits<CtrlEmit>();
// 安装功能模块,提供状态和能力 // 安装功能模块,提供状态和能力
const { name, state, useCustom, onEditorEvent, onToolbarEvent, onActionColEvent, newRow, remove, save, load, refresh, getData } = new GridControl(ctrlState, props, emit).moduleInstall(); const { name, state, useCustom, onEditorEvent, onToolbarEvent, onActionColEvent, newRow, remove, save, load, refresh, getData, exportExcel } = new GridControl(ctrlState, props, emit).moduleInstall();
const { useScrollOption, useRowKey, useRowClassName, useCustomRow, useRowSelectionOption, onResizeColumn, onGridChange, useExpandedRowKeys, onExpandedRowsChange } = useCustom; const { useScrollOption, useRowKey, useRowClassName, useCustomRow, useRowSelectionOption, onResizeColumn, onGridChange, useExpandedRowKeys, onExpandedRowsChange } = useCustom;
{{#if ctrl.batchToolBarItems}} {{#if ctrl.batchToolBarItems}}
const renderBatchToolbar = (total: number, range: IParam[]) => { const renderBatchToolbar = (total: number, range: IParam[]) => {
...@@ -59,7 +59,7 @@ const renderBatchToolbar = (total: number, range: IParam[]) => { ...@@ -59,7 +59,7 @@ const renderBatchToolbar = (total: number, range: IParam[]) => {
{{/if}} {{/if}}
// 暴露内部状态及能力 // 暴露内部状态及能力
defineExpose({ name, state, newRow, remove, save, load, refresh, getData }); defineExpose({ name, state, newRow, remove, save, load, refresh, getData, exportExcel });
</script> </script>
<template> <template>
<a-form name="{{ctrl.name}}" class="app-grid-form" > <a-form name="{{ctrl.name}}" class="app-grid-form" >
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册