cloud-JG/src/utils/format.ts
ylj20011123 d94b67182e update
2025-06-18 19:23:17 +08:00

534 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import ProTable from '@ant-design/pro-table'
import numeral from 'numeral'
import './printBox.less'
import { CurrentUser } from 'umi'
import session from './session'
import moment from 'moment'
import { synchroBehaviorRecord } from '@/services/user'
export type TreeSelectModel = {
value: number | string,
id: number | string,
title: string,
pId: number | string,
disabled?: boolean
}
export type TreeNodeDto = {
node: any;
children: TreeNodeDto[];
}
/**
* @description: [{node:{},chidlren:[]}] => [{...node,children}]
* @param {any} node 需要拼接的父节点
* @param {any} chidlren 需要遍历的平级节点 合并节点中的
* @return {*} 返回[node:{...,children:[]}]
*/
export function wrapTreeNode(data: TreeNodeDto[]) {
const wrapData: any = data.map((item: TreeNodeDto) => {
const node = { ...item.node };
if (item.children && item.children.length > 0) {
node.children = wrapTreeNode(item.children);
}
return node
});
return wrapData;
}
export function formatTreeForProTable(data: TreeNodeDto[]) {
const wrapData = wrapTreeNode(data);
return {
data: wrapData,
current: 1,
pageSize: 100,
total: 100,
success: true,
};
}
export function tableList(list: any) {
return {
data: list.List || [],
current: list.PageIndex || 1,
pageSize: list.pageSize || 10,
total: list.TotalCount || 0,
otherData: list?.OtherData || '',
success: true,
};
}
/**
* @description:生产的数据仅提供 treeSelect组件treeDataSimpleMode模式使用的 数据,
* @param fields 需要转化的数据,
* @param treeKeys fields 与 TreeSelectModel 数据键值 如 fields as EnumItem ,treeKeys: { title: 'fieldEnumName', value: 'id', id:'id', pId:'parentId' }
* @returns TreeSelectModel[]
*/
export const getTreeSelectOption = async (treeKeys: TreeSelectModel, fields: any[]) => {
const option: TreeSelectModel[] = []
const { value, title, pId, id } = treeKeys
fields.forEach(async (item: any) => {
option.push({ value: item[value], title: item[title], pId: item[pId], id: item[id] })
if (item.children) {
const children: TreeSelectModel[] = await getTreeSelectOption(treeKeys, item.children)
option.push(...children)
}
})
return option
}
// 转换数据为option格式数据
export function formateOptions(list: [], rules: { name: string; value: string; other?: string }) {
// let options: { label: string; value: number | string; other?: string | number }[] = [];
const { name, value, other } = rules;
if (list && other) {
return list.map((n) => {
return {
label: n[name],
value: n[value],
other: n[other],
};
});
} if (list) {
return list.map((n) => {
return {
label: n[name],
value: n[value],
};
});
}
return [];
}
// 转换options数据value类型为 number
export function formateField(list: { label: string; value: string | number }[]) {
const valueNumber: { label: string; value: number }[] = [];
list.map((n: any) => {
if (!isNaN(Number(n.value))) {
valueNumber.push({
label: n.label,
value: numeral(n.value).value(),
});
}
});
return valueNumber.length > 0 ? valueNumber : list;
}
// 转换树节点的value类型为string
export function formateTreeField(list: TreeNodeDto[]) {
const valueNumber: any[] = list.map((item: TreeNodeDto) => {
const node = { label: item.node.label, value: item.node.value.toString(), type: item.node.type, ico: item.node.ico };
if (item.children && item.children.length > 0) {
node.children = formateTreeField(item.children);
}
return node
});
return valueNumber.length > 0 ? valueNumber : list;
}
// 把图片格式转化为 ui框架需要的数据格式
export const transferImg = (orgIamges: any[]) => {
const newImages = orgIamges.map((n: any) => {
if (typeof n === 'object') {
return {
uid: n.ImageId, // 注意这个uid一定不能少否则上传失败
name: n.ImageName,
status: 'done',
url: n.ImageUrl, // url 是展示在页面上的绝对链接
imgUrl: n.ImagePath,
}
}
const [name] = [...n.split("/")].reverse()
return {
uid: new Date().getTime(), // 注意这个uid一定不能少否则上传失败
name,
status: 'done',
url: n, // url 是展示在页面上的绝对链接
imgUrl: n,
}
})
return newImages
}
// 合计方法
export const handleGetSumRow = (data: any[], fieldList: string[], sumTitle: string, avgFiled?: string) => {
// data 表格数据 fieldList 要算合计的字段 sumTitle 显示合计两个字的字段 avgFiled 要算均值的字段(这个字段也必须在算合计的字段里面)
if (data && data.length > 0) {
if (data.length >= 2) {
const res: any = {}
if (fieldList && fieldList.length > 0) {
fieldList.forEach((item: any) => {
res[item] = 0
})
}
data.forEach((item: any) => {
if (res) {
for (const key in res) {
if (item[key]) {
res[key] += item[key]
}
}
}
})
if (avgFiled) {
res[avgFiled] = Number((res[avgFiled] / data.length).toFixed(2))
}
console.log('res', res);
res[sumTitle] = "合计"
data.unshift(res)
return data
}
// 一个片区的时候 判断是不是一个服务区 一个服务区的话 就单单显示一个服务区就好
if (data && data.length === 1) {
const obj: any = data[0]
if (obj.children && obj.children.length === 1) {
return obj.children
}
return data
}
return data
}
return []
}
// 自定义打印的内容的打印方法
export const handleNewPrint = (printName: string, title: string, neckBox?: any, styles?: any, tableDom?: any, footer?: any) => {
// printName 打印出来文件的名称
// title 打印内容的标题
// neckBox 标题下面可能会要求的打印的内容 数组 {label,value}格式 样式已写死
// styles 获取页面的样式
// tableDom 要打印显示的表格 直接dom元素拿进来(处理好的)
// footer 打印内容底部的自定义样式 需求不一样 样式也不一样 外面写好样式和标签直接传入
const printWindow = window.open('', '_blank', 'width=1400,height=800');
if (printWindow) {
printWindow.document.open();
printWindow.document.write(`
<html>
<head>
<title>${printName || ''}</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
position: relative;
overflow: hidden;
}
${styles}
.handlePrintBox{
width: 100%;
height: 100%;
position: relative;
z-index: 0;
box-sizing: border-box;
padding: 20px 0 0 0;
}
.handlePrintBox .custom-header {
font-size: 24px;
text-align: center;
margin-bottom: 20px;
font-weight: 600;
}
.handlePrintBox .neckBox{
width: 100%;
box-sizing: border-box;
padding: 12px 12px 12px 20px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.handlePrintBox .neckBox .neckBoxItem{
width: calc(100% / 3);
display: flex;
align-items: center;
box-sizing: border-box;
padding-left: 5%;
}
.handlePrintBox .neckBox .bigNeckBoxItem{
width: calc((100% / 3) * 2);
display: flex;
align-items: center;
box-sizing: border-box;
padding-left: 5%;
}
.handlePrintBox .neckBox .bigNeckBoxItem .itemLabel{
font-size: 14px;
font-weight: 600;
margin-right: 2px;
}
.handlePrintBox .neckBox .bigNeckBoxItem .itemValue{
font-size: 12px;
}
.handlePrintBox .neckBox .neckBoxItem .itemLabel{
font-size: 14px;
font-weight: 600;
margin-right: 2px;
}
.handlePrintBox .neckBox .neckBoxItem .itemValue{
font-size: 12px;
}
.handlePrintBox .tableBox{
width: 100%;
box-sizing: border-box;
padding: 12px;
display: flex;
justify-content: center;
border-collapse: separate;
border-spacing: 0;
}
.handlePrintBox .tableBox .ant-table-thead tr th{
border: 2px solid #000;
}
.handlePrintBox .tableBox .ant-table-tbody tr td{
border: 2px solid #000;
}
.handlePrintBox .tableBox .ant-table-summary tr td{
border: 2px solid #000;
}
.handlePrintBox .tableUnit{
width: 100%;
display: flex;
justify-content: flex-end;
box-sizing: border-box;
font-size: 14px;
}
.handlePrintBox .tableUnit .tableRight{
width: calc(100% / 3);
font-size: 14px;
box-sizing: border-box;
padding-left: 5%;
}
.pro-table {
width: 100%;
border-collapse: collapse;
}
.pro-table th, .pro-table td {
border: 1px solid #ddd;
padding: 8px;
}
.pro-table th {
background-color: #f2f2f2;
text-align: left;
}
/* 水印样式 */
.watermark {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: grid;
grid-template-rows: repeat(4, 1fr); /* 水平行数 */
grid-template-columns: repeat(4, 1fr); /* 垂直列数 */
opacity: 0.2;
pointer-events: none;
z-index: 1;
overflow: hidden;
}
.watermark span {
display: flex;
justify-content: center;
align-items: center;
transform: rotate(-45deg); /* 水印旋转 */
font-size: 14px;
color: rgba(0, 0, 0); /* 半透明水印 */
user-select: none;
}
</style>
</head>
<body>
<div class="handlePrintBox">
<div class="custom-header">${title}</div>
<div class="neckBox">
${neckBox && neckBox.length > 0
? neckBox
.map((item: any) => {
return `<div class="${item.label === '门店名称' ? 'bigNeckBoxItem' : 'neckBoxItem'}">
<span class="itemLabel">${item.label ? item.label + '' : ''}</span>
<span class="itemValue">${item.value}</span>
</div>`;
})
.join('') // 连接成单一字符串,避免逗号
: ''}
</div>
<div class="tableUnit">
<div class="tableRight">单位:元</div>
</div>
<div class="tableBox">
${tableDom}
</div>
<div>
${footer}
</div>
</div>
<div class="watermark">
${Array(16) // 5x5 网格的水印内容
.fill('<span>安徽省驿达高速公路服务区经营管理有限公司</span>')
.join('')}
</div>
</body>
</html>
`)
printWindow.document.close();
printWindow.print();
// 使用定时器检测打印窗口是否关闭
const closeCheckInterval = setInterval(() => {
if (printWindow.closed) {
clearInterval(closeCheckInterval);
}
}, 500);
// 监听窗口焦点事件,若打印窗口失去焦点,关闭窗口
printWindow.onfocus = () => {
printWindow.close();
clearInterval(closeCheckInterval);
};
printWindow.onafterprint = () => printWindow.close();
}
}
// 打印图片
export const handlePrintImg = (url: any) => {
const printWindow = window.open('', '_blank', 'width=1400,height=800');
if (printWindow) {
printWindow.document.open();
printWindow.document.close();
printWindow.document.write(`
<html>
<head>
<style>
</style>
<body>
<div style="width:100%;height:100%;display:flex;justify-content: center;">
<img style="max-width:100%;max-height:100%" src=${url}>
</div>
</body>
</head>
</html>
`)
printWindow.print();
// 使用定时器检测打印窗口是否关闭
const closeCheckInterval = setInterval(() => {
if (printWindow.closed) {
clearInterval(closeCheckInterval);
}
}, 500);
printWindow.onfocus = () => {
printWindow.close();
clearInterval(closeCheckInterval);
};
printWindow.onafterprint = () => printWindow.close();
}
}
// 记录每一个按钮的 调用了的方法
export const handleSetPublicLog = (obj: any) => {
// desc 一个数组 入参内容说明 startTime 开始时间 endTime 结束时间 时间戳格式 buttonType 1 为点击了查询按钮
const currentUser: CurrentUser = session.get('currentUser');
let nowMenu = session.get("currentMenu")
let basicInfo = session.get("basicInfo")
let systemBasin = session.get("systemBasin")
let browserVersion = session.get("browserVersion")
if (obj.desc && obj.desc.length > 0) {
obj.desc.forEach((item: any) => {
item.url = 'https://api.eshangtech.com' + item.url
})
}
const req: any = {
USER_ID: currentUser.ID,
USER_NAME: currentUser.Name,
BEHAVIORRECORD_TYPE: "2000", // 1000 浏览页面 2000 行为记录
BEHAVIORRECORD_EXPLAIN: `在页面${nowMenu.name}${obj.buttonType === 1 ? '点击了查询按钮' : ''}`, // 操作行为说明
BEHAVIORRECORD_ROUT: nowMenu.pathname,
BEHAVIORRECORD_ROUTNAME: nowMenu.name,
REQUEST_INFO: JSON.stringify(obj.desc),// 存的是一个JSON 存完整点的内容 在什么页面点击了什么 调用了什么接口 入参是什么 多个接口的时候是数组格式
// BEHAVIORRECORD_DESC: obj.desc, // 入参
BEHAVIORRECORD_TIME: moment(new Date(obj.startTime)).format('YYYY-MM-DD HH:mm:ss'),
BEHAVIORRECORD_LEAVETIME: moment(new Date(obj.endTime)).format('YYYY-MM-DD HH:mm:ss'),
BEHAVIORRECORD_DURATION: (obj.endTime - obj.startTime) / 1000,
OWNERUNIT_ID: currentUser.OwnerUnitId,
OWNERUNIT_NAME: currentUser.OwnerUnitName,
BUSINESSMAN_ID: currentUser.BusinessManID,
BUSINESSMAN_NAME: currentUser.BusinessManName,
SOURCE_PLATFORM: '驿商云平台',
USER_LOGINIP: basicInfo.ip,
USER_LOGINPLACE: `${basicInfo.country}${basicInfo.prov}${basicInfo.city}${basicInfo.district}`,
BROWSER_VERSION: browserVersion,
OPERATING_SYSTEM: systemBasin
}
console.log('reqreqreqreqreq', req);
synchroBehaviorRecord(req)
}
// 将一个对象的key值变为 中文字
export const handleChangeKeyTo = async (params: any, keyObj: any) => {
// params 需要变的对象 keyObj 中文内容
let newObj: any = {}
for (let key in params) {
newObj[keyObj[key]] = params[key]
}
return newObj
}
// 传入秒 返回时分
export const secondsToHuman = (seconds: number) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const parts = [];
if (hours > 0) parts.push(`${hours}小时`);
if (minutes > 0) parts.push(`${minutes}分钟`);
return parts.join('') || '0分钟';
}
// 封装一个只要传入操作事项的就可以记录日志
export const handleSetlogSave = async (str: string) => {
const currentUser = session.get('currentUser')
const basicInfo = session.get('basicInfo')
const browserVersion = session.get('browserVersion')
const systemBasin = session.get('systemBasin')
synchroBehaviorRecord({
USER_ID: currentUser?.ID,
USER_NAME: currentUser?.Name,
BEHAVIORRECORD_TYPE: "2000",
BEHAVIORRECORD_EXPLAIN: str,
OWNERUNIT_ID: currentUser?.OwnerUnitId,
OWNERUNIT_NAME: currentUser?.OwnerUnitName,
BUSINESSMAN_ID: currentUser?.BUSINESSMAN_ID,
BUSINESSMAN_NAME: currentUser?.BUSINESSMAN_NAME,
SOURCE_PLATFORM: "出行平台",
USER_LOGINIP: basicInfo?.ip,
USER_LOGINPLACE: `${basicInfo?.prov}${basicInfo?.city}${basicInfo?.district}`,
BROWSER_VERSION: browserVersion,
OPERATING_SYSTEM: systemBasin
})
}