fastlion-amis
Version:
一种MIS页面生成工具
588 lines (545 loc) • 22 kB
text/typescript
import { Modal } from "antd"
import { cloneDeep, isNil, isObject } from "lodash"
import moment from 'moment';
import { TranslateFn } from "../../locale";
import { filterDate } from "../../utils/tpl-builtin";
import { advancedRanges, availableRanges } from "../../components/DateRangePicker";
import { advancedShortcuts, availableShortcuts } from "../../components/DatePicker";
import { getMediaIcon, isImg } from "../Lion/utils/utils";
import { createObject, findTree, isMobile } from "../../utils/helper";
import { ActionSchema } from "../Action";
import { Schema } from "../../types";
import getExprProperties from "../../utils/filter-schema";
import { ICRUDStore } from "../../store/crud";
import { IColumn, ITableStore } from "../../store/table";
import { exportXLSXFromCross } from "../../utils/xlsx";
import { getHeadRows } from "../../store/utils/commonTableFunction";
import { filterTpl } from "./types";
// utils/filterUtils.ts (新建工具文件)
// 判断条件是否是个合法空值 如果是 空 的情况 默认是true 如果不是 则判断 是不是 undefined null ''
export const advancefilterValueIsLegalEmptyValue = (item: any) => {
return item.op !== 10 && (isNil(item.values) || item.values === '')
}
// 处理合法的高级查询值
export const dealAdvacedCondition = (advacedArr: { op: number }[]) => {
return advacedArr?.filter((item: any) => {
if (advancefilterValueIsLegalEmptyValue(item)) {
return false
}
return true
}) || []
}
// 获取查询参数的初始值,用于初始化的数据查询
export const getInitParam = (translate: TranslateFn<any>, filter?: obj,) => {
let filterParam = {}
filter?.body.forEach((item: any) => {
if (!isNil(item.value)) {
const key = item.name.split('.')?.[1]
const delimiter = item.delimiter || ','
const format = item.inputFormat || item.format
if (['input-date-range', 'input-datetime-range', 'input-time-range'].includes(item.type)) {
let itemValue = item.value.includes(delimiter) ? item.value.split(delimiter)
.map((val: string) => filterDate(val, undefined, format).format(format)
).join(delimiter) : item.value
if (availableRanges[item.value]) {
const range = availableRanges[item.value];
const now = moment();
const startDate = range.startDate(now.clone()).format(format);
const endDate = range.endDate(now.clone()).format(format);
itemValue = [startDate, endDate].join(delimiter);
} else {
// 通过正则尝试匹配
for (let i = 0, len = advancedRanges.length; i < len; i++) {
let value = advancedRanges[i];
const m = value.regexp.exec(item.value);
if (m) {
const range = value.resolve.apply(item.value, [translate, ...m]);
const now = moment();
const startDate = range.startDate(now.clone()).format(format);
const endDate = range.endDate(now.clone()).format(format);
itemValue = [startDate, endDate].join(delimiter);
}
}
}
filterParam = {
...filterParam,
[key]: itemValue
}
} else if (['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year'].includes(item.type)) {
//实现时间点的解析
let itemValue = item.value.includes(delimiter) ? item.value : filterDate(item.value, undefined, format).format(format);
if (availableShortcuts[item.value]) {
const value = availableShortcuts[item.value];
const now = moment();
itemValue = value.date(now).format(format);
} else {
for (let i = 0, len = advancedShortcuts.length; i < len; i++) {
let value = advancedShortcuts[i];
const m = value.regexp.exec(item.value);
if (m) {
const range = value.resolve.apply(item.value, [translate, ...m]);
const now = moment();
itemValue = range.date(now).format(format);
}
}
}
filterParam = {
...filterParam,
[key]: itemValue
}
} else {
filterParam = {
...filterParam,
[key]: item.value
}
}
}
})
return filterParam
}
// 打开预览组件
export const openImageEnlarge = (data: Array<any>, baseURL: string, onImageEnlarge: any, env?: any) => {
let isNotImg = false;
let list: any = data.map((item: any) => {
isNotImg = !isImg(item.name);
return {
src: isNotImg ? getMediaIcon(item.name) : baseURL + (item.thumbnailAddr || item?.addr),
originalSrc: baseURL + item.previewAddr,
downloadSrc: baseURL + item?.addr,
title: item.name || '',
previewTitle: item.previewName,
previewType: item.previewType,
fileSize: item.size,
isNotImg
};
});
if (isMobile()) {
// if (Shell.hasShell()) {
// if (tools.isAndroid) {
// Shell.previewFile({ urls: list.map((val: any) => { return val.originalSrc }) })
// } else {
// const urls = list.map((attachment: any) => {
// const url = new URL(encodeURI(attachment.originalSrc))
// const search = url.search == '' ? `?fileName=${Date.now() + attachment.title}` : `${url.search}&fileName=${Date.now() + attachment.title}`
// url.search = search
// return url.href
// })
// Shell.previewFile({ urls, current: 0 })
// }
// return
// } else
if (env?.previewImagesMb) {
const urls = list.map((val: any) => { return val.originalSrc })
env.previewImagesMb(urls, 0)
return
}
} else {
onImageEnlarge && onImageEnlarge({
src: list[0].src,
originalSrc: list[0].originalSrc,
index: 0,
list
});
}
}
// 处理高高级查询前缀
export const handlePrefix = (body: obj, advancedQueryFields: string, advancedFilter?: obj) => {
const filtercont: obj = {}
for (const key in body) {
if (key == "advancedFilter" || key == "advancedHeader" || key == "advancedFilterSub") {
if (typeof body[key] == 'object') {
if (Array.isArray(body[key])) {
const content = cloneDeep(body[key]);
let newArr: any[] = [];
const dateLineItem = content.find((item: any) => item.dateLine);
if (content.length && key === 'advancedFilter' && !dateLineItem) {
let filterBody = advancedFilter?.body;
filterBody = Array.isArray(filterBody) ? filterBody : filterBody ? [filterBody] : [];
const filters = filterBody.find((item: any) => item.name === 'advancedFilter')?.body;
let dateList = filters?.filter((filterItem: any) => filterItem.type && ['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year'].includes(filterItem.type));
if (advancedQueryFields) {
dateList = dateList.filter((info: any) => advancedQueryFields.includes(info.name.split('.')?.[1]))
}
if (dateList?.length > 0) {
newArr.push({
caseSensitive: 1,
condition: 1,
dateLine: true,
field: dateList[0].name,
not: false,
op: 7
})
}
}
content.forEach((item: any) => {
const repeatNum = newArr.filter(pItem => pItem.field.includes(item.field)).length
const element = item
element.field = key + "." + item.field + (repeatNum > 0 ? `--${repeatNum}` : '')
newArr.push(element);
})
filtercont[key] = newArr
} else {
const content = cloneDeep(body[key])
const data: obj = {}
for (const item in content) {
data[`${key}.${item}`] = content[item]
}
filtercont[key] = data
}
}
}
}
return filtercont
}
// 处理结构化数据
export const handleSelectStructure = (select: any[]): any[] => {
const newArray: any[] = [];
const pushChildren = (item: any, newArray: any[]) => {
newArray.push(item);
if (item.children && item.children.length > 0) {
item.children.forEach((child: any) => {
pushChildren(child, newArray);
});
}
}
select.forEach((item: any) => {
pushChildren(item, newArray);
});
return newArray;
}
// 表格数据获取统一规范一下
export const getTableRowsData = (crudStore: ICRUDStore, tableStore: ITableStore | null) => {
return tableStore?.rows.map(row => row.data) || crudStore.data.items || []
}
export const getTableSelectedRowsData = (crudStore: ICRUDStore, tableStore: ITableStore | null) => {
return tableStore?.selectedRows.map(row => row.data) || crudStore.selectedItems.concat() || []
}
export const hasBulkActions = (actionGroup: {
headerBulkActions?: ActionSchema[],
footerBulkActions?: ActionSchema[],
itemActions?: ActionSchema[]
}, CRUDStore: ICRUDStore, tableStore: ITableStore | null) => {
const { headerBulkActions, footerBulkActions, itemActions } = actionGroup;
if ((!headerBulkActions || !headerBulkActions.length) &&
(!footerBulkActions || !footerBulkActions.length) &&
(!itemActions || !itemActions.length)
) {
return false;
}
let bulkHeaderBtns: Array<ActionSchema> = [];
let bulkFooterBtns: Array<ActionSchema> = [];
let itemBtns: Array<ActionSchema> = [];
const ctx = CRUDStore.mergedData
if (headerBulkActions && headerBulkActions.length) {
bulkHeaderBtns = headerBulkActions.map(item => ({
...item,
...getExprProperties(item as Schema, ctx)
})).filter(item => !item?.hidden && item?.visible !== false);
}
if (footerBulkActions && footerBulkActions.length) {
bulkFooterBtns = footerBulkActions.map(item => ({
...item,
...getExprProperties(item as Schema, ctx)
})).filter(item => !item?.hidden && item?.visible !== false);
}
const selectedItems = getTableSelectedRowsData(CRUDStore, tableStore)
const itemData = createObject(
CRUDStore.data,
selectedItems.length ? selectedItems[0] : {}
);
if (itemActions && itemActions.length) {
itemBtns = itemActions.map(item => ({
...item,
...getExprProperties(item as Schema, itemData)
})).filter(item => !item?.hidden && item?.visible !== false);
}
return !!(bulkHeaderBtns.length || bulkFooterBtns.length || itemBtns.length);
}
export const filtBoolean = (filt: obj, tableStore: ITableStore | null) => {
return tableStore?.filterColumns?.size > 0 || (filt && Object.keys(filt || {}).length && (filt?.advancedFilter?.length || filt?.advancedFilterSub?.length || Object.keys(filt?.advancedHeader || {}).length) ? true : false);
}
// 展示头部判断
export const headerCanShow = (header: any, filter: any, filtercont: obj, tableStore: ITableStore | null) => {
return !!header || !!filter || filtBoolean(filtercont, tableStore)
}
//移动端处理工具栏按钮中的可批量操作的按钮,加入到headerBulkActions中
export const unitBulkActions = (actionGroup: {
headerToolbar?: any,
headerBulkActions?: ActionSchema[],
headerActions: any
}) => {
const { headerToolbar, headerBulkActions, headerActions } = actionGroup;
const bulkHeaderToolActions = headerToolbar?.filter((item: any) => {
if (isObject(item.api?.data) && Object.keys(item.api.data).includes('SELECTION_IDS')) return true;
return false;
})
const bulkFooterToolActions = headerActions?.filter((item: any) => {
if (isObject(item.api?.data) && Object.keys(item.api.data).includes('SELECTION_IDS')) return true;
return false;
})
if ((!headerBulkActions || headerBulkActions?.length === 0) && (!bulkHeaderToolActions || bulkHeaderToolActions?.length === 0) && (!bulkFooterToolActions || bulkFooterToolActions?.length === 0)) {
return headerBulkActions
} else {
return ([] as Array<any>).concat(headerBulkActions ?? [], bulkHeaderToolActions ?? [], bulkFooterToolActions ?? [])
}
}
/**
*
* @param keepDataFormat 保留格式
* @param isTemplate 导出方式
*/
export const handleExportDefault = (tableStore: ITableStore, aliasTitle: string, keepDataFormat: boolean, exportType: 'column' | 'template', exportRangeAll: boolean, exportFields?: string[],) => {
let tableHeadRows = tableStore!.tableHeadRows.map(row => row.filter(item => item.column.type !== 'lion-upload' && item.name != 'SF_CHECK' && item.name != 'SF_PSEUDO' && item.name !== 'operation'))
let columns = tableStore!.filteredColumns.filter(item => item.type !== 'lion-upload' && item.type !== '__checkme' && item.type != '__pseudoColumn' && item.name !== 'operation')
if (exportType === 'template' && exportFields?.length) {
let exportCols: IColumn[] = [];
const cols = tableStore?.columns;
exportFields.forEach(item => {
const targetItem = cols?.find(col => col.name === item);
if (targetItem) exportCols.push(targetItem)
})
tableHeadRows = getHeadRows(exportCols).map(row => {
return row.filter(item => item.column.type !== 'lion-upload' && item.name != 'SF_CHECK' && item.name != 'SF_PSEUDO' && item.name !== 'operation' && item.name && exportFields.includes(item.name))
})
columns = exportCols.filter(item => item.type !== 'lion-upload' && item.type !== '__checkme' && item.type != '__pseudoColumn' && item.name !== 'operation' && item.name && exportFields.includes(item.name))
}
const excelData = tableStore?.rows.filter(row => exportRangeAll || row.checked).map(row => row.data) ?? []
exportXLSXFromCross(tableHeadRows, columns, excelData, `${aliasTitle?.trim?.() || '导出'}.xlsx`, keepDataFormat)
}
interface filterItem {
field: string;
values: any;
valuesAlia?: any;
op: number;
not?: boolean;
delimiter?: string;
dateLine?: boolean;
}
// 高级查询部分
/**
* 纯函数:计算过滤器模板数据
*/
export const computeFilterTpl = ({
advancedFilter,
advancedQueryFields,
filtercont,
advancedFilterData,
advanceFilterFormState
}: {
advancedFilter: any;
advancedQueryFields?: any;
filtercont: any;
advancedFilterData: Map<string, any>;
advanceFilterFormState?: any;
}): filterTpl[] => {
if (!advancedFilter) return [];
const { body } = advancedFilter;
const filters = Array.isArray(body) ? body : body ? [body] : [];
const { advancedFilter: advancedFilterCont, advancedFilterSub } = filtercont || {};
const allAdvancedFilters = [...(advancedFilterCont || []), ...(advancedFilterSub || [])];
const dateLineItem = allAdvancedFilters.find((filItem: filterItem) => filItem.dateLine);
// 处理主要过滤器逻辑
const filtertpl: filterTpl[] = allAdvancedFilters.reduce((result: filterTpl[], value: filterItem, currentIndex: number) => {
filters.forEach(item => {
if (item.name.includes('advancedFilter')) {
item.body.forEach((items: any) => {
const long = items.name.split('.');
if (long[long.length - 1] === value.field) {
const currentValue = advancedFilterData.get(value.field);
let data = null;
if (currentValue) {
if (typeof value?.values == 'string' && value?.values?.indexOf(value?.delimiter ?? ',') > -1) {
data = value.values.split(value?.delimiter ?? ',').map((name_item: any) => {
if (value.op == 12) {
const newArray = handleSelectStructure(currentValue);
return newArray.find((current: any) => current.value == name_item)?.label;
}
return findTree(currentValue, (current: any) => current.value == name_item)?.label;
});
} else {
data = findTree(currentValue, (current: any) => current.value == value.values)?.label;
}
}
let dateList = item.body.filter((filterItem: any) =>
filterItem.type && ['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year'].includes(filterItem.type)
);
if (advancedQueryFields) {
dateList = dateList.filter((info: any) =>
advancedQueryFields.includes(info.name.split('.')?.[1])
);
}
let cop: filterTpl = {};
// 生成keyName
if (advanceFilterFormState?.filtersArr?.length) {
cop.keyName = advanceFilterFormState.filtersArr[!dateList.length || dateLineItem ? currentIndex : currentIndex + 1]?.field || 'advancedFilter.' + value.field;
} else {
const repeatNum = result.filter((resItem: filterTpl) => resItem.name === 'advancedFilter.' + value.field).length +
(dateList.length && !dateLineItem && dateList[0].name === 'advancedFilter.' + value.field ? 1 : 0);
const keyName = 'advancedFilter.' + value.field + (repeatNum > 0 ? `--${repeatNum}` : '');
cop.keyName = keyName;
}
cop.value = data ? typeof data === 'object' ? data.join(',') : data : value.values;
cop.label = items?.label || items?.placeholder;
cop.name = items.name;
if (value.valuesAlia) {
cop.valuesAlia = value.valuesAlia;
}
// 操作符处理逻辑
cop = processFilterOperator(cop, value);
if (!advancefilterValueIsLegalEmptyValue(value)) {
result.push({ ...cop, advancedFilterIndex: currentIndex });
}
}
});
}
});
return result;
}, []);
// 处理头部过滤器
return processHeaderFilters(filtertpl, filtercont, filters, advancedFilterData);
};
/**
* 纯函数:处理过滤器操作符逻辑
*/
const processFilterOperator = (cop: filterTpl, value: filterItem): filterTpl => {
const newCop = { ...cop };
switch (value.op) {
case 2:
if (newCop.value) {
newCop.value = value.not
? `![${newCop.value}]`
: `[${newCop.value}]`;
}
if (newCop.valuesAlia) {
newCop.valuesAlia = value.not
? `![${newCop.valuesAlia}]`
: `[${newCop.valuesAlia}]`;
}
break;
case 3:
if (newCop.value) {
newCop.value = value.not
? `!(${newCop.value},∞)`
: `(${newCop.value},∞)`;
}
if (newCop.valuesAlia) {
newCop.valuesAlia = value.not
? `!(${newCop.valuesAlia},∞)`
: `(${newCop.valuesAlia},∞)`;
}
break;
case 4:
if (newCop.value) {
newCop.value = value.not
? `![${newCop.value},∞)`
: `[${newCop.value},∞)`;
}
if (newCop.valuesAlia) {
newCop.valuesAlia = value.not
? `![${newCop.valuesAlia},∞)`
: `[${newCop.valuesAlia},∞)`;
}
break;
case 5:
if (newCop.value) {
newCop.value = value.not
? `!(-∞,${newCop.value})`
: `(-∞,${newCop.value})`;
}
if (newCop.valuesAlia) {
newCop.valuesAlia = value.not
? `!(-∞,${newCop.valuesAlia})`
: `(-∞,${newCop.valuesAlia})`;
}
break;
case 6:
if (newCop.value) {
newCop.value = value.not
? `!(-∞,${newCop.value}]`
: `(-∞,${newCop.value}]`;
}
if (newCop.valuesAlia) {
newCop.valuesAlia = value.not
? `!(-∞,${newCop.valuesAlia}]`
: `(-∞,${newCop.valuesAlia}]`;
}
break;
case 7:
if (value.values) {
newCop.value = `[${value.values}]`;
newCop.valuesAlia = `[${value.values}]`;
}
break;
case 9:
if (newCop.value) {
newCop.value = value.not
? `!${newCop.value}`
: `${newCop.value}`;
}
if (newCop.valuesAlia) {
newCop.valuesAlia = value.not
? `!${newCop.valuesAlia}`
: `${newCop.valuesAlia}`;
}
break;
case 10:
newCop.value = value.not
? '[不为空]'
: '[为空]';
break;
case 12:
if (newCop.value) {
newCop.value = value.not
? `!属于标签 ${newCop.value}`
: `属于标签 ${newCop.value}`;
}
if (newCop.valuesAlia) {
newCop.valuesAlia = value.not
? `!属于标签${newCop.valuesAlia}`
: `属于标签${newCop.valuesAlia}`;
}
break;
default:
break;
}
return newCop;
};
/**
* 纯函数:处理头部过滤器
*/
const processHeaderFilters = (filtertpl: filterTpl[], filtercont: any, filters: any[], advancedFilterData: Map<string, any>): filterTpl[] => {
const { advancedHeader } = filtercont || {};
const result = [...filtertpl];
if (advancedHeader && Object.keys(advancedHeader).length) {
Object.keys(advancedHeader).forEach(key => {
filters.forEach(item => {
if (item.name === 'advancedHeader') {
item.body.forEach((items: any) => {
const processItem = (it: any) => {
const long = it.name.split('.');
if (long[long.length - 1] === key) {
const currentValue = advancedFilterData.get(it.name);
let cop: filterTpl = {};
if (currentValue) {
const currentLabel = currentValue.find((opp: any) => opp.value === advancedHeader[key]);
cop.labelName = currentLabel?.label;
}
cop.value = advancedHeader[key];
cop.label = it.label || it.placeholder;
cop.name = it.name;
result.push(cop);
}
};
if (items?.body) {
items.body.forEach(processItem);
} else {
processItem(items);
}
});
}
});
});
}
return result;
};
// 高级查询部分