UNPKG

fastlion-amis

Version:

一种MIS页面生成工具

588 lines (545 loc) 22 kB
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; }; // 高级查询部分