828 lines
25 KiB
TypeScript
828 lines
25 KiB
TypeScript
import { parse } from 'querystring';
|
||
import moment from 'moment';
|
||
import numeral from 'numeral';
|
||
import ExportJsonExcel from 'js-export-excel';
|
||
import type { RangePickerDateProps } from 'antd/es/date-picker/generatePicker';
|
||
import type { ProColumns } from '@ant-design/pro-table';
|
||
|
||
type RangePickerValue = RangePickerDateProps<moment.Moment>['value']
|
||
|
||
/* eslint no-useless-escape:0 import/prefer-default-export:0 */
|
||
const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
|
||
|
||
export const isUrl = (path: string): boolean => reg.test(path);
|
||
|
||
export const isAntDesignPro = (): boolean => {
|
||
if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') {
|
||
return true;
|
||
}
|
||
return window.location.hostname === 'preview.pro.ant.design';
|
||
};
|
||
|
||
// For the official demo site, it is used to turn off features that are not needed in the real development environment
|
||
export const isAntDesignProOrDev = (): boolean => {
|
||
const { NODE_ENV } = process.env;
|
||
if (NODE_ENV === 'development') {
|
||
return true;
|
||
}
|
||
return isAntDesignPro();
|
||
};
|
||
|
||
export const getPageQuery = () => parse(window.location.href.split('?')[1]);
|
||
|
||
export function getTimeDistance(type: 'today' | 'week' | 'month' | 'year'): RangePickerValue {
|
||
const now = new Date();
|
||
const oneDay = 1000 * 60 * 60 * 24;
|
||
|
||
if (type === 'today') {
|
||
now.setHours(0);
|
||
now.setMinutes(0);
|
||
now.setSeconds(0);
|
||
return [moment(now), moment(now.getTime() + (oneDay - 1000))];
|
||
}
|
||
|
||
if (type === 'week') {
|
||
let day = now.getDay();
|
||
now.setHours(0);
|
||
now.setMinutes(0);
|
||
now.setSeconds(0);
|
||
|
||
if (day === 0) {
|
||
day = 6;
|
||
} else {
|
||
day -= 1;
|
||
}
|
||
|
||
const beginTime = now.getTime() - day * oneDay;
|
||
|
||
return [moment(beginTime), moment(beginTime + (7 * oneDay - 1000))];
|
||
}
|
||
const year = now.getFullYear();
|
||
|
||
if (type === 'month') {
|
||
const month = now.getMonth();
|
||
const nextDate = moment(now).add(1, 'months');
|
||
const nextYear = nextDate.year();
|
||
const nextMonth = nextDate.month();
|
||
|
||
return [
|
||
moment(`${year}-${fixedZero(month + 1)}-01 00:00:00`),
|
||
moment(moment(`${nextYear}-${fixedZero(nextMonth + 1)}-01 00:00:00`).valueOf() - 1000),
|
||
];
|
||
}
|
||
|
||
return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)];
|
||
}
|
||
|
||
export function fixedZero(val: number) {
|
||
return val * 1 < 10 ? `0${val}` : val;
|
||
}
|
||
|
||
// 拆分小数点前后数字
|
||
export const splitAmount = (value: any, fixedType?: string) => {
|
||
const formatType = fixedType || '0,0'
|
||
const stringValue = numeral(value).format(formatType)
|
||
|
||
const [intValue, floatValue] = stringValue.split(".")
|
||
return [intValue, floatValue]
|
||
}
|
||
|
||
// 报表导出excel 无多级表头
|
||
export const exportExcel = async (
|
||
outColumn: ProColumns<any>[],
|
||
reqDetailList: any[],
|
||
fileName?: string,
|
||
) => {
|
||
// 网络请求命名空间
|
||
// const outColumn: ProColumns<any>[] = columns.slice(3); // 需要放在state里边,Table,Columns
|
||
const option: { fileName: string; datas: any[] } = {
|
||
fileName: fileName || '新建文件', // : '收营员报表' + moment().format('YYYYMMDDHHmmss'),
|
||
datas: [],
|
||
};
|
||
if (reqDetailList?.length) {
|
||
const getList = (data = [], index: number) => {
|
||
const wrapData: any = data.map((item: any) => {
|
||
const node = { ...item };
|
||
if (item.children && item.children.length > 0) {
|
||
const childNode = getList(item.children, index)
|
||
return [node, ...childNode.data]
|
||
}
|
||
return node
|
||
});
|
||
return { data: wrapData, index: index + 1 };
|
||
}
|
||
|
||
const data = getList(reqDetailList as [], 0)
|
||
const outList = data.data.flat(data.index + 1)
|
||
option.datas = [
|
||
{
|
||
sheetData: outList.map((item: any, index: number) => {
|
||
const result = {};
|
||
|
||
outColumn.forEach((c: any, i) => {
|
||
if (c.hideInTable) return;
|
||
if (c.dataIndex === 'index') {
|
||
result[c.dataIndex] = index + 1;
|
||
} else if (c.render) {
|
||
result[c.dataIndex] = typeof c.render(item[c.dataIndex], item) === 'object' ?
|
||
item[c.dataIndex] : c.render(item[c.dataIndex], item)
|
||
} else {
|
||
result[c.dataIndex] = item[c.dataIndex] ? item[c.dataIndex] : item[c.dataIndex] === 0 ? 0 : ''
|
||
}
|
||
});
|
||
// if(item.children) {
|
||
// const childrenColums = item.children.map((child, index) => {
|
||
// const res = {};
|
||
// outColumn.forEach((c: any, i) => {
|
||
// if (c.hideInTable) return;
|
||
// if (i !== 0) {
|
||
// res[c.dataIndex] = c.render ? c.render(child[c.dataIndex],item) : child[c.dataIndex] ;
|
||
// } else {
|
||
// res[c.dataIndex] = index + 1;
|
||
// }
|
||
// });
|
||
// return res
|
||
// })
|
||
// console.log(childrenColums)
|
||
// // return {childrenColums}
|
||
|
||
// }
|
||
// console.log('result',result)
|
||
return result;
|
||
}),
|
||
sheetName: 'sheet1', // Excel文件名称
|
||
sheetFilter: outColumn.map((item) => item.dataIndex),
|
||
sheetHeader: outColumn.map((item) => item.title),
|
||
columnWidths: outColumn.map(() => 10),
|
||
},
|
||
];
|
||
|
||
// function warpNode(data) {
|
||
// data.map((item, index) => {
|
||
// const result = {};
|
||
// if(item.children) {
|
||
// }
|
||
// outColumn.forEach((c: any, i) => {
|
||
// if (c.hideInTable) return;
|
||
// if (i !== 0) {
|
||
// result[c.dataIndex] = item[c.dataIndex];
|
||
// } else {
|
||
// result[c.dataIndex] = index + 1;
|
||
// }
|
||
// });
|
||
// return result;
|
||
// })
|
||
// }
|
||
// }
|
||
|
||
const toExcel = new ExportJsonExcel(option);
|
||
toExcel.saveExcel();
|
||
return { message: 'ok' };
|
||
}
|
||
return { message: '没有可导出的数据' };
|
||
};
|
||
|
||
// 合作商户资金到账汇总报表导出的修改
|
||
export const exportExcelReceivedSum = (
|
||
outColumn: ProColumns<any>[],
|
||
reqDetailList: any[],
|
||
fileName?: string,) => {
|
||
const option: { fileName: string; datas: any[] } = {
|
||
fileName: fileName || '新建文件', // : '收营员报表' + moment().format('YYYYMMDDHHmmss'),
|
||
datas: [],
|
||
};
|
||
if (reqDetailList?.length) {
|
||
const getList = (data = [], index: number) => {
|
||
const wrapData: any = data.map((item: any) => {
|
||
const node = { ...item };
|
||
if (item.children && item.children.length > 0) {
|
||
const childNode = getList(item.children, index)
|
||
return [node, ...childNode.data]
|
||
}
|
||
return node
|
||
});
|
||
return { data: wrapData, index: index + 1 };
|
||
}
|
||
|
||
const data = getList(reqDetailList as [], 0)
|
||
const outList = data.data.flat(data.index + 1)
|
||
console.log('outList', outList)
|
||
option.datas = [
|
||
{
|
||
sheetData: outList.map((item: any, index: number) => {
|
||
const result = {};
|
||
// 判断这个对象是否都有值
|
||
outColumn.forEach((c: any, i) => {
|
||
if (c.hideInTable) return;
|
||
if (c.render) {
|
||
result[c.dataIndex] = typeof c.render(item[c.dataIndex], item) === 'object' ?
|
||
item[c.dataIndex] : c.render(item[c.dataIndex], item)
|
||
} else {
|
||
result[c.dataIndex] = item[c.dataIndex] ? item[c.dataIndex] : item[c.dataIndex] === 0 ? 0 : ''
|
||
}
|
||
});
|
||
// if(item.children) {
|
||
// const childrenColums = item.children.map((child, index) => {
|
||
// const res = {};
|
||
// outColumn.forEach((c: any, i) => {
|
||
// if (c.hideInTable) return;
|
||
// if (i !== 0) {
|
||
// res[c.dataIndex] = c.render ? c.render(child[c.dataIndex],item) : child[c.dataIndex] ;
|
||
// } else {
|
||
// res[c.dataIndex] = index + 1;
|
||
// }
|
||
// });
|
||
// return res
|
||
// })
|
||
// // return {childrenColums}
|
||
|
||
// }
|
||
return result;
|
||
}),
|
||
sheetName: 'sheet1', // Excel文件名称
|
||
sheetFilter: outColumn.map((item) => item.dataIndex),
|
||
sheetHeader: outColumn.map((item) => item.title),
|
||
columnWidths: outColumn.map(() => 10),
|
||
},
|
||
];
|
||
console.log('option.datas', option.datas)
|
||
// function warpNode(data) {
|
||
// data.map((item, index) => {
|
||
// const result = {};
|
||
// if(item.children) {
|
||
// }
|
||
// outColumn.forEach((c: any, i) => {
|
||
// if (c.hideInTable) return;
|
||
// if (i !== 0) {
|
||
// result[c.dataIndex] = item[c.dataIndex];
|
||
// } else {
|
||
// result[c.dataIndex] = index + 1;
|
||
// }
|
||
// });
|
||
// return result;
|
||
// })
|
||
// }
|
||
// }
|
||
const toExcel = new ExportJsonExcel(option);
|
||
toExcel.saveExcel();
|
||
return { message: 'ok' };
|
||
}
|
||
return { message: '没有可导出的数据' };
|
||
}
|
||
|
||
// 处理好数据 可作为公共的导出方法
|
||
// outColumn 排除hideInTable和 再设置中隐藏的字段 变成一个数组
|
||
// reqDetailList 无论多少级 转成一层数组用于导出
|
||
// 合作商户资金到账汇总报表导出的修改
|
||
export const exportExcelaccountMonthly = (
|
||
outColumn: ProColumns<any>[],
|
||
reqDetailList: any[],
|
||
fileName?: string,) => {
|
||
const option: { fileName: string; datas: any[] } = {
|
||
fileName: fileName || '新建文件', // : '收营员报表' + moment().format('YYYYMMDDHHmmss'),
|
||
datas: [],
|
||
};
|
||
if (reqDetailList?.length) {
|
||
const data = reqDetailList
|
||
const outList = data.flat(data.index + 1)
|
||
option.datas = [
|
||
{
|
||
sheetData: outList.map((item: any, index: number) => {
|
||
const result = {};
|
||
// 判断这个对象是否都有值
|
||
outColumn.forEach((c: any, i) => {
|
||
if (c.hideInTable) return;
|
||
if (c.render) {
|
||
result[c.dataIndex] = typeof c.render(item[c.dataIndex], item) === 'object' ?
|
||
item[c.dataIndex] : c.render(item[c.dataIndex], item)
|
||
} else {
|
||
result[c.dataIndex] = item[c.dataIndex] ? item[c.dataIndex] : item[c.dataIndex] === 0 ? 0 : ''
|
||
}
|
||
});
|
||
return result;
|
||
}),
|
||
sheetName: 'sheet1', // Excel文件名称
|
||
sheetFilter: outColumn.map((item) => item.dataIndex),
|
||
sheetHeader: outColumn.map((item) => item.title),
|
||
columnWidths: outColumn.map(() => 10),
|
||
},
|
||
];
|
||
const toExcel = new ExportJsonExcel(option);
|
||
toExcel.saveExcel();
|
||
return { message: 'ok' };
|
||
}
|
||
return { message: '没有可导出的数据' };
|
||
}
|
||
|
||
// 打印页面配置内容
|
||
export const printOutBody = (ele: any, content: string) => {
|
||
const dateEle = document.createElement('div');
|
||
const printConent = document.createElement('div');
|
||
if (typeof ele === 'object' && ele.length > 1) {
|
||
ele.forEach(n => {
|
||
if (n) {
|
||
printConent.appendChild(n)
|
||
}
|
||
})
|
||
} else {
|
||
const title = ele?.getElementsByClassName('ant-table-wrapper')[0];
|
||
printConent.appendChild(ele)
|
||
if (title) {
|
||
dateEle.setAttribute('style', 'text-align:right;font-size:20px;margin-bottom: 20px');
|
||
dateEle.innerHTML = content;
|
||
ele.insertBefore(dateEle, title);
|
||
}
|
||
}
|
||
|
||
// dateEle.setAttribute('style', 'text-align:right;font-size:20px;margin-bottom: 20px;');
|
||
// dateEle.innerHTML = content;
|
||
|
||
return printConent;
|
||
};
|
||
|
||
// 打印合同配置的内容
|
||
export const printContract = (ele: any, content: string) => {
|
||
const dateEle = document.createElement('div');
|
||
const printConent = document.createElement('div');
|
||
if (typeof ele === 'object' && ele.length > 1) {
|
||
ele.forEach(n => printConent.appendChild(n))
|
||
} else {
|
||
const title = ele
|
||
printConent.appendChild(ele)
|
||
if (title) {
|
||
dateEle.setAttribute('style', 'text-align:center;font-size:20px;margin-bottom: 20px;');
|
||
dateEle.innerHTML = content;
|
||
ele.insertBefore(dateEle, title);
|
||
}
|
||
}
|
||
return printConent
|
||
}
|
||
|
||
// 打印低代码生成页面配置内容
|
||
// 由于不同页面表单所在区域的dom元素不同 此方法建议只在低代码生成的页面中 做打印功能
|
||
export const printOutInternal = (ele: any, content: string) => {
|
||
// 先创建一个包裹在最外层的dom 再在这里面新建一个dom用来放需要打印的内容
|
||
const dateEle = document.createElement('div');
|
||
const printConent = document.createElement('div');
|
||
// 增加一些样式
|
||
printConent.setAttribute('style', 'width:100%;padding:25px')
|
||
// 顶部内容dom 用于放标题内容
|
||
const top = document.createElement('div');
|
||
// 顶部dom框样式
|
||
top.setAttribute('style', 'width:100%;display:flex;just-content:center;align-items:center;margin-bottom:20px')
|
||
// 找title的文本信息dom拿到值
|
||
const title = ele?.getElementsByClassName('ant-pro-table-list-toolbar-title')[0];
|
||
// 标题的样式
|
||
title.setAttribute('style', 'font-size:20px;margin: 0 auto')
|
||
// 把title的dom放到顶部dom中 顶部dom加入到需要打印内容的dom中 添加的顺序就是显示的顺序
|
||
top.appendChild(title)
|
||
dateEle.appendChild(top)
|
||
// 拿到表格的整体dom
|
||
const body = ele?.getElementsByClassName('ant-table')[0]
|
||
body.setAttribute('style', 'height:auto')
|
||
const colgroup = body.getElementsByTagName('colgroup')[0]
|
||
const colList = colgroup.getElementsByTagName('col')
|
||
for (let i = colList.length - 1; i >= 0; i--) {
|
||
colList[i].remove()
|
||
}
|
||
// 表格数据的dom
|
||
// const listDom = body.getElementsByClassName('ant-table-body')[0]
|
||
// listDom.setAttribute('style', '')
|
||
// 拿到表头
|
||
const th = body.getElementsByTagName('th')
|
||
// 判断表头里面有没有操作列 有操作列的话 每行数据的最后一列要去除
|
||
let isOption = false
|
||
th.forEach((n: any) => {
|
||
if (n.innerHTML === '操作') {
|
||
n.remove()
|
||
isOption = true
|
||
}
|
||
})
|
||
th.forEach((n: any, index: number) => {
|
||
if (index === th.length - 1) {
|
||
n.setAttribute('style', 'width:1px')
|
||
// n.remove()
|
||
}
|
||
// else {
|
||
// n.setAttribute('style',`width:calc((100% - 1px)/${th.length - 1}),text-align:center`)
|
||
// }
|
||
})
|
||
// 拿到表格数据的dom
|
||
const tbody = body.getElementsByClassName('ant-table-tbody')[0]
|
||
const list = tbody.getElementsByTagName('tr')
|
||
// 删除操作列的数据
|
||
if (isOption) {
|
||
list.forEach((n: any, index: number) => {
|
||
const td = n.getElementsByTagName('td')
|
||
const { length } = td
|
||
td[length - 1].remove()
|
||
})
|
||
}
|
||
// 判断是否有传入时间 有时间 显示在表格和头部中间偏右
|
||
if (content) {
|
||
const time = document.createElement('div')
|
||
time.innerText = content
|
||
time.setAttribute('style', 'width:100%;text-align:right')
|
||
dateEle.appendChild(time)
|
||
}
|
||
// 添加处理过的数据 放到打印内容中
|
||
dateEle.appendChild(body)
|
||
printConent.appendChild(dateEle)
|
||
return printConent;
|
||
};
|
||
|
||
// 封装导出的方法 尽量适配报表的全部页面
|
||
export const handlePrint = (ele: any) => {
|
||
const printContent = document.createElement('div');
|
||
|
||
const cloneNode = ele.cloneNode(true)
|
||
const tableContent = cloneNode.getElementsByClassName('ant-card')[0]
|
||
|
||
printContent.appendChild(tableContent)
|
||
return printContent
|
||
}
|
||
|
||
|
||
|
||
// 获取临时查看图片的base4码
|
||
export const getBase64 = async (file: any): Promise<any> => {
|
||
return new Promise((resolve, reject) => {
|
||
const reader = new FileReader();
|
||
reader.readAsDataURL(file);
|
||
reader.onload = () => resolve(reader.result);
|
||
reader.onerror = error => reject(error);
|
||
});
|
||
}
|
||
|
||
|
||
// 打印合作商户合同期结算明细表 有流程进度的特殊情况
|
||
export const printSettlementDetails = (ele: any, content: string) => {
|
||
console.log('ele', ele)
|
||
const dateEle = document.createElement('div');
|
||
const printConent = document.createElement('div');
|
||
if (typeof ele === 'object' && ele.length > 1) {
|
||
ele.forEach(n => printConent.appendChild(n))
|
||
} else {
|
||
const title = ele
|
||
printConent.appendChild(ele)
|
||
if (title) {
|
||
dateEle.setAttribute('style', 'text-align:center;font-size:20px;margin-bottom: 20px;');
|
||
dateEle.innerHTML = content;
|
||
ele.insertBefore(dateEle, title);
|
||
}
|
||
}
|
||
console.log('printConent', printConent)
|
||
return printConent
|
||
}
|
||
|
||
|
||
// 处理高精度问题
|
||
export const handleHighPrecision = (num: number) => {
|
||
// 处理负数情况
|
||
const isNegative = num < 0;
|
||
const newNumber = Number(Math.abs(num).toFixed(2))
|
||
const str: string = newNumber.toString(); // 取绝对值进行处理
|
||
|
||
// 取整数部分
|
||
let integer: string = str.split('.')[0];
|
||
|
||
// 确保整数部分至少两位(前面补 0)
|
||
if (integer.length < 3) {
|
||
integer = integer.padStart(3, '0');
|
||
}
|
||
|
||
// 取最后两位作为小数部分
|
||
const lastTwo: string = integer.substring(integer.length - 2);
|
||
// 取前面的整数部分
|
||
const startStr: string = integer.substring(0, integer.length - 2);
|
||
|
||
// 组合字符串,转换为数字
|
||
const result = parseFloat(`${startStr}.${lastTwo}`);
|
||
|
||
// 如果原数是负数,返回负值
|
||
return isNegative ? -result : result;
|
||
}
|
||
|
||
|
||
// 将多层级树组 按照label value 变为单层的对象
|
||
export const handleGetListObj = (list: any) => {
|
||
let res: any = {};
|
||
|
||
if (!list || list.length === 0) {
|
||
return res;
|
||
}
|
||
|
||
list.forEach((item: any) => {
|
||
if (item.children?.length) {
|
||
const childObj = handleGetListObj(item.children);
|
||
res = { ...res, ...childObj };
|
||
}
|
||
|
||
if (item.value !== undefined && item.label !== undefined) {
|
||
res[item.value] = item.label;
|
||
}
|
||
});
|
||
|
||
return res;
|
||
}
|
||
|
||
// 将多层的columns 按照key value 变为单层对象
|
||
export const handleColumnsToObj = (list: any, parentTitle?: string) => {
|
||
let res: any = {}
|
||
|
||
if (!list || list.length === 0) {
|
||
return res;
|
||
}
|
||
|
||
list.forEach((item: any) => {
|
||
const currentTitle = typeof item.title === 'string' ? item.title : item.aiTitle || '';
|
||
const fullTitle = parentTitle ? `${currentTitle}${parentTitle} ` : currentTitle;
|
||
if (item.children && item.children.length > 0) {
|
||
// 如果有子节点,递归处理子节点,并传入当前拼接后的标题
|
||
const childResults = handleColumnsToObj(item.children, fullTitle);
|
||
res = { ...res, ...childResults };
|
||
} else {
|
||
// 如果没有子节点,添加到结果对象中
|
||
if(item.renderHaveText){
|
||
res[item.renderHaveText] = fullTitle;
|
||
}else if (item.aiDataIndex) {
|
||
res[item.aiDataIndex] = fullTitle;
|
||
}
|
||
}
|
||
})
|
||
|
||
return res;
|
||
}
|
||
|
||
|
||
// 将多层的表格数据 他里面的对象数据 全部解构出来 变层父级key拼上当级key的格式 与原先的父级同级
|
||
export const handleExportListToObj = (data: any) => {
|
||
if (!Array.isArray(data)) return [];
|
||
|
||
const processNode = (node: any) => {
|
||
// 处理当前节点的数据
|
||
const processedNode: any = {};
|
||
|
||
// 处理所有字段
|
||
Object.entries(node).forEach(([key, value]) => {
|
||
// 保留children和ShopINCList结构
|
||
if (key === 'children' || key === 'ShopINCList') {
|
||
return;
|
||
}
|
||
|
||
// 处理对象类型字段
|
||
if (value && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Date)) {
|
||
Object.entries(value).forEach(([innerKey, innerValue]) => {
|
||
processedNode[`${key}${innerKey}`] = innerValue;
|
||
});
|
||
} else {
|
||
processedNode[key] = value;
|
||
}
|
||
});
|
||
|
||
// 处理子节点
|
||
const children = node.children && node.children.length > 0 ? node.children : node.ShopINCList && node.ShopINCList.length > 0 ? node.ShopINCList : [];
|
||
if (children.length > 0) {
|
||
processedNode.children = children.map((child: any) => processNode(child));
|
||
}
|
||
|
||
return processedNode;
|
||
};
|
||
|
||
return data.map(node => processNode(node));
|
||
};
|
||
|
||
|
||
// 有一个对象 key的值为跟表格的每一层对象的key对应 value值为这个key所代表的意思
|
||
export const handleChangeItemKeyToValue = (list: any, keyMapping: Record<string, any>) => {
|
||
if (!Array.isArray(list)) return [];
|
||
|
||
const processNode = (node: any) => {
|
||
const newNode: any = {};
|
||
|
||
// 处理当前节点的所有属性
|
||
Object.entries(node).forEach(([key, value]) => {
|
||
// 特殊处理children数组
|
||
if (key === 'children') {
|
||
const processedChildren = value.map((child: any) => processNode(child));
|
||
if (processedChildren.length > 0) {
|
||
newNode.children = processedChildren;
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 检查是否有映射关系
|
||
if (key in keyMapping) {
|
||
const newKey = keyMapping[key];
|
||
|
||
// 处理值
|
||
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||
// 如果是对象,递归处理
|
||
const processedValue = processNode(value);
|
||
if (Object.keys(processedValue).length > 0) {
|
||
newNode[newKey] = processedValue;
|
||
}
|
||
} else {
|
||
// 普通值直接赋值
|
||
newNode[newKey] = value;
|
||
}
|
||
}
|
||
});
|
||
|
||
return newNode;
|
||
};
|
||
|
||
return list.map(node => processNode(node)).filter(node => Object.keys(node).length > 0);
|
||
};
|
||
|
||
// export const handleChangeItemKeyToValue = (list: any, keyMapping: any) => {
|
||
// if (!Array.isArray(list)) return [];
|
||
|
||
// const processNode = (node: any) => {
|
||
// const newNode: any = {};
|
||
|
||
// // 处理当前节点的所有属性
|
||
// Object.entries(node).forEach(([key, value]: any) => {
|
||
// // 特殊处理children数组
|
||
// if (key === 'children') {
|
||
// newNode.children = value.map((child: any) => processNode(child));
|
||
// return;
|
||
// }
|
||
|
||
// // 检查是否有映射关系
|
||
// const newKey = keyMapping[key] || key;
|
||
|
||
// // 处理值
|
||
// if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||
// // 如果是对象,递归处理
|
||
// newNode[newKey] = processNode(value);
|
||
// } else {
|
||
// // 普通值直接赋值
|
||
// newNode[newKey] = value;
|
||
// }
|
||
// });
|
||
|
||
// return newNode;
|
||
// };
|
||
|
||
// return list.map(node => processNode(node));
|
||
// }
|
||
|
||
|
||
|
||
|
||
// 多层级数组 变为同一级
|
||
export const handleFlattenTree = (treeData: any) => {
|
||
const result: any = [];
|
||
|
||
function traverse(nodes) {
|
||
if (!Array.isArray(nodes)) return;
|
||
|
||
nodes.forEach(node => {
|
||
// 将当前节点加入结果(排除嵌套字段)
|
||
const { children, ShopINCList, ...rest } = node;
|
||
result.push(rest);
|
||
|
||
// 递归处理嵌套节点
|
||
if (children && children.length > 0) traverse(children);
|
||
if (ShopINCList && ShopINCList.length > 0) traverse(ShopINCList);
|
||
});
|
||
}
|
||
|
||
traverse(treeData);
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
|
||
export const findNodeByPath = (treeData: any[], targetPath: string): any | undefined => {
|
||
// 边界检查
|
||
if (!Array.isArray(treeData) || !targetPath) return undefined;
|
||
|
||
for (const node of treeData) {
|
||
// 检查当前节点是否匹配
|
||
if (node.SYSTEMMODULE_URL === targetPath) {
|
||
return node;
|
||
}
|
||
|
||
// 如果有子节点且不是空数组,递归查找
|
||
if (node.SystemModuleList?.length > 0) {
|
||
const found = findNodeByPath(node.SystemModuleList, targetPath);
|
||
if (found) return found;
|
||
}
|
||
}
|
||
|
||
return undefined; // 未找到
|
||
}
|
||
|
||
// 封装一个方法 将传入的树形字段 分别变为 片区层 服务区层 门店层
|
||
export const handleGetSpecifyFormatLevelRes = (data: any) => {
|
||
const result = {
|
||
regions: [], // 片区层(最高级)
|
||
serviceAreas: [], // 服务区层
|
||
shops: [] // 门店层
|
||
};
|
||
|
||
if (!Array.isArray(data)) return result;
|
||
|
||
const cleanItem = (item: any): any => {
|
||
const cleaned: any = {};
|
||
Object.keys(item).forEach(key => {
|
||
const value = item[key];
|
||
// 保留非对象且非数组的字段
|
||
if (typeof value !== 'object' || value === null) {
|
||
cleaned[key] = value;
|
||
}
|
||
});
|
||
return cleaned;
|
||
};
|
||
|
||
// 递归处理每一项
|
||
const processItem = (item: any) => {
|
||
const keys = Object.keys(item);
|
||
const lowerCaseKeys: any = keys.map(key => key.toLowerCase());
|
||
|
||
// 获取字段值(不区分大小写)
|
||
const spRegionTypeId = keys.find(k => k.toLowerCase() === 'spregiontypeid');
|
||
const serverpartId = keys.find(k => k.toLowerCase() === 'serverpartid');
|
||
const serverpartShopId = keys.find(k => k.toLowerCase() === 'serverpartshopid');
|
||
|
||
const hasSPRegionTypeId = spRegionTypeId != null && item[spRegionTypeId] != null;
|
||
const hasServerpartId = serverpartId != null && item[serverpartId] != null;
|
||
const hasServerpartShopId = serverpartShopId != null && item[serverpartShopId] != null;
|
||
|
||
// 严格层级判断
|
||
if (hasServerpartShopId) {
|
||
result.shops.push(cleanItem(item)); // 规则3:只要 ServerpartShopId 有值就是门店层
|
||
} else if (hasSPRegionTypeId && hasServerpartId) {
|
||
result.serviceAreas.push(cleanItem(item)); // 规则2:SPRegionTypeId + ServerpartId(无 ServerpartShopId)
|
||
} else if (hasSPRegionTypeId && !hasServerpartId && !hasServerpartShopId) {
|
||
result.regions.push(cleanItem(item)); // 规则1:仅 SPRegionTypeId
|
||
}
|
||
|
||
// 递归处理子集(children 或 ShopINCList,字段名大小写敏感)
|
||
if (item.children && Array.isArray(item.children)) {
|
||
item.children.forEach(child => processItem(child));
|
||
}
|
||
if (item.ShopINCList && Array.isArray(item.ShopINCList)) {
|
||
item.ShopINCList.forEach(child => processItem(child));
|
||
}
|
||
};
|
||
// 遍历初始数组
|
||
data.forEach(item => processItem(item));
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
|
||
export const checkAndCompleteFields = (targetObj, sourceObj) => {
|
||
// 获取目标对象所有键(转换为小写)
|
||
const targetKeys = Object.keys(targetObj).map(key => key.toLowerCase());
|
||
|
||
// 遍历源对象的所有键
|
||
for (const sourceKey in sourceObj) {
|
||
if (sourceObj.hasOwnProperty(sourceKey)) {
|
||
const lowerSourceKey = sourceKey.toLowerCase();
|
||
|
||
// 检查目标对象是否包含当前键(不区分大小写)
|
||
if (!targetKeys.includes(lowerSourceKey)) {
|
||
// 找到源对象中原始键名(保留原始大小写)
|
||
const originalKey = Object.keys(sourceObj).find(
|
||
key => key.toLowerCase() === lowerSourceKey
|
||
);
|
||
|
||
// 将缺失的字段添加到目标对象
|
||
targetObj[originalKey] = sourceObj[originalKey];
|
||
}
|
||
}
|
||
}
|
||
|
||
return targetObj;
|
||
}
|
||
|
||
|
||
|
||
// 字符串计数 控制跟word一样
|
||
export const countLikeWordAccurate = (text: string) => {
|
||
if (!text) return 0;
|
||
|
||
// 将文本标准化:合并连续空格,去除首尾空格
|
||
const normalizedText = text.replace(/\s+/g, ' ').trim();
|
||
if (!normalizedText) return 0;
|
||
|
||
// 使用Unicode属性转义更准确地匹配中文字符
|
||
const chineseRegex = /(\p{Script=Han}|\p{sc=Hani})/gu;
|
||
const chineseCount = [...normalizedText.matchAll(chineseRegex)].length;
|
||
|
||
// 统计非中文部分
|
||
const nonChineseText = normalizedText.replace(chineseRegex, ' ');
|
||
|
||
// 统计英文单词和数字序列
|
||
const wordCount = nonChineseText.split(/\s+/)
|
||
.filter(word => word.length > 0)
|
||
.length;
|
||
|
||
return chineseCount + wordCount;
|
||
} |