各种情况的封装方法
/**
* 获取默认国际化
* 注:
* 1)从本地方缓存取(后期替换从云创取)
* 2)缓存为空,从浏览气取
*
* @return {string}
*/
export const getDefaultLang = (): string => {
let locale = storage.getLocal("lang") || "";
if (!locale) {
locale = window.navigator.language;
if (/(zh|cn)/.test(locale)) {
locale = "zh-CN";
} else {
locale = "en";
}
}
return locale;
};
/**
* 设置标题
*
* @param title
*/
export const setTitle = (title: string): void => {
window.document.title =
window.$swpT(`menu.${title}`) + " | " + VITE_APP_TITLE;
};
/**
* 注册template下国际化翻译
*
* @param key
* @param value
*/
export const $swpT = (key: any = "", value: any = "") => {
return window.$swpT(key, value);
};
/**
* 接收后端数据分割给前端分页
* data 数组 chunkSize 页数
* @param data
* @param chunkSize
*/
export const sliceData = <T>(data: T[], chunkSize: number): T[][] => {
let result: T[][] = [];
for (let i = 0; i < data.length; i += chunkSize) {
result.push(data.slice(i, i + chunkSize));
}
return result;
};
/**
* 查找 tabs 是否在 tabsList 的 key 中,未找到返回默认
*
* @param activeName
* @param tabsList
* @param defTab
* @returns {string}
*/
export const findTabs = (
activeName: LocationQueryValue | LocationQueryValue[],
tabsList: any[],
defTab: string
): string => {
if (!activeName) return defTab;
const isFind = tabsList.find(val => val.key === activeName);
return (isFind && activeName) || defTab;
};
/**
* 文件下载方法
*
* @param href {string}
* @param filename {string}
*/
export const downloadFile = (href: string, filename: string): void => {
if (href && filename) {
const a = document.createElement("a");
a.download = filename; // 指定下载的文件名
a.href = href; // URL对象
a.click(); // 模拟点击
URL.revokeObjectURL(a.href); // 释放URL 对象
}
};
/**
* 必填字段格式化
*
* @param field {string}
* @returns {string}
*/
export const fieldRequired = (field: string = ""): string => {
return window.$swpT("warning.fieldIsRequired", {
field
});
};
/**
* 深拷贝
*
* @param data {any}
* @returns {null|any}
*/
export const deepCopy = (data: any): any | null => {
try {
return JSON.parse(JSON.stringify(data));
} catch (e) {
return null;
}
};
/**
* 转义HTML特殊字符串,防止XSS
*
* @param str
*/
export const htmlEscape = (str: string = "") => {
if (!str) return str;
const codes: any = {
"<script>": "", // 移除script
"</script>": "", // 移除script
"&": "&",
"<": "<",
">": ">",
'"': """, // 注意会丢失json
"'": "'" // 注意会丢失json
};
for (const code in codes) {
str = str.replace(new RegExp(code, "g"), codes[code]);
}
return str;
};
/**
* 引用与非引用值,深拷贝方法
* 注: 支持方法拷贝
*
* @param data {any}
* @returns {any}
*/
export const deepClone = (data: any): any => {
if (typeof data !== "object" || typeof data === "function" || data === null) {
return data;
}
let item: [] | object | any;
if (Array.isArray(data)) {
item = [];
}
if (!Array.isArray(data)) {
item = {};
}
for (const i in data) {
if (Object.prototype.hasOwnProperty.call(data, i)) {
item[i] = deepClone(data[i]);
}
}
return item;
};
/**
* 比对两个对象中的属性值是否相同
*
* @param value any 对象1
* @param other any 对象2
* @param keys {string[]} 需要比对的属性, 为空取对象1的属性
* @returns boolean
*/
export const isSameObject = (
value: any = {},
other: any = {},
keys: string[] = []
) => {
if (isEmpty(value) && isEmpty(other)) return true;
if (keys.length === 0) keys = Object.keys(value);
if (keys.length === 0) return true;
// 查找是否有不同项判断法
const list = keys.find(key => value[key] !== other[key]);
return typeof list === "undefined";
};
/**
* 展开子列
*
* @template {{children: T[]}} T
* @param {T[]} list
* @param {T[][]} allColumns
* @param {T[]} parentList
* @return T[][]
* @description [{name:'a'; children:[{name:'b'}, {name:'c'}]}] ===> [[{name:'a'},{name:'b'}], [{name:'a'},{name:'c'}]]
*/
export function flatTree<T extends { children?: any[] } = any>(
list: T[],
allColumns: T[][] = [],
parentList: T[] = []
) {
if (!list || list.length === 0) {
return allColumns;
}
for (const item of list) {
if (item.children && item.children.length > 0) {
flatTree(item.children, allColumns, [...parentList, item]);
} else {
allColumns.push([...parentList, item]);
}
}
return allColumns;
}
/**
* 列名转可编辑字段[AG]
*
* @param columns {any}
* @returns []
*/
export const columnsToAgSameKeys = (columns: any = []) => {
if (columns.length === 0) return [];
let keys: any[] = [];
columns.forEach(
({checkboxSelection = false, editable = true, field = ""}) => {
if (!checkboxSelection && editable) {
keys.push(field);
}
}
);
return keys;
};
/**
* 用于返回导出对象
*
* @param exportHeader
* @param value
* @param fieldList
* @returns object
*/
const getExportAgExcelObject = (
exportHeader: any[],
value: any,
fieldList: any[]
) => {
let $row: any = {};
exportHeader.forEach(item => {
let existField: any;
const isExist = fieldList?.findIndex(it => {
if (it.originField === item.field) {
existField = it;
return true;
}
});
if (isExist !== -1) {
$row[item.field] = value[existField["replaceField"]];
} else {
if (item.valueFormatter && value) {
$row[item.field] = item.valueFormatter({value: value[item.field]});
} else if (item.cellRenderer && value) {
let afterRender = item.cellRenderer({
value: value[item.field]
});
if (afterRender) {
afterRender = afterRender.match(/>(.+)</)[1];
$row[item.field] = afterRender;
} else {
$row[item.field] = "";
}
} else if (item.cellRendererParams?.render && value) {
let afterRender = item.cellRendererParams.render({
value: value[item.field]
});
afterRender = afterRender.children.reduce(
(prev: string, current: any) => {
if (_.isString(current)) {
prev = prev + current + ",";
} else if (_.isArray(current)) {
prev =
prev +
current
.map(subItem => {
return subItem.children[0].children[0];
})
.join(",");
}
return prev;
},
""
);
if (afterRender[afterRender.length - 1] === ",") {
afterRender = afterRender.slice(0, -1);
}
$row[item.field] = afterRender;
} else {
$row[item.field] = value && value[item.field];
}
}
});
return $row;
};
/**
* 前端导出
*
* ModuleColumn[] 封装导出迁移至 exportModuleColumnExcel
*
* @param {any[]} columnsList
* @param {any[]} data
* @param {string} name
* @returns void
*/
export const exportExcelByData = (
columnsList: any[],
data: any[],
name: string = "未命名"
) => {
// 判断导出数据
if (!columnsList || !data) {
ElMessage.warning($swpT("warning.exportedDataEmpty"));
// throw new Error('导出数据为空');
return;
}
// 计算导出列配置
const filterColumns = columnsList.filter(
column => column.data !== "selection" || column.field !== "_idx"
);
const {headerHeight, columns, mergeConfigs} =
getExportExcelHeaderConfig(filterColumns);
// --------------- 构建Sheet页 ---------------
const workbook = new Exceljs.Workbook();
const worksheet = workbook.addWorksheet(name, {
properties: {
tabColor: {
argb: "FFC0000"
}
}
});
// --------------- 标题设置 ---------------
worksheet.columns = columns;
for (let rowIndex = 0; rowIndex < headerHeight; rowIndex++) {
const headerRow = worksheet.getRow(rowIndex + 1);
headerRow.eachCell({includeEmpty: true}, headerCell => {
headerCell.style = excelHeaderStyle;
});
}
// --------------- 内容设置 ---------------
worksheet.addRows(data);
worksheet.eachRow((row, rowIndex) => {
if (rowIndex <= headerHeight) return;
const style = rowIndex % 2 === 1 ? excelTwoCellStyle : excelCellStyle;
row.eachCell({includeEmpty: true}, cell => {
cell.style = style;
});
});
// --------------- 判断单元格超链接 ---------------
worksheet.eachColumnKey(col => {
const colIndex = col.number;
const column = columns[colIndex - 1].columnConfig;
if (column.type === "link" && typeof column.getHref === "function") {
const getHref = column.getHref;
worksheet.eachRow((row, rowIndex) => {
if (rowIndex <= headerHeight) return;
const cell = row.getCell(colIndex);
if (typeof cell.value === "string" && cell.value) {
cell.value = {
text: cell.value,
hyperlink: formatExportLink(
getHref(cell.value, data[rowIndex - headerHeight - 1])
)
};
cell.style = {...cell.style, font: excelLinkCellStyleFont};
}
});
}
});
// --------------- 判断合并单元格数据 ---------------
for (let colIndex = 0; colIndex < columns.length; colIndex++) {
const column = columns[colIndex].columnConfig;
const mergeCell = column.mergeCell;
if (!mergeCell) {
continue;
}
for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
const currentData = data[rowIndex];
const lastData = data[rowIndex - 1];
if (rowIndex > 0 && mergeCell(currentData, lastData)) {
continue;
}
let count = 1;
while (count) {
const afterData = data[rowIndex + count];
if (afterData && mergeCell(currentData, afterData)) {
count += 1;
} else {
break;
}
}
if (count > 1) {
mergeConfigs.push({
rowIndex: rowIndex + headerHeight,
colIndex,
width: 0,
height: count - 1
});
}
}
}
// --------------- 合并单元格 ---------------
for (const {rowIndex, colIndex, width, height} of mergeConfigs) {
const top = rowIndex + 1;
const left = colIndex + 1;
worksheet.mergeCells([top, left, top + height, left + width]);
}
// --------------- 导出Excel文件流 ---------------
workbook.xlsx.writeBuffer().then(data => {
const blob = new Blob([data], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
});
saveAs(blob, name + ".xlsx");
});
};
/**
* 计算导出Excel表头信息
*
* @template {{children: T[]}} T
* @param {T[]} tableColumns
*/
function getExportExcelHeaderConfig<T extends { children?: any[] } = any>(
tableColumns: T[]
) {
// 平铺树结构数据
const allColumns = flatTree(tableColumns);
// 获取表头高度
const headerHeight = Math.max(...allColumns.map(columns => columns.length));
/** @type {ExcelMergeConfig[]} */
const mergeConfigs: any[] = [];
const columnSet = new Set();
// 判断父节表头横向合并长度
for (let rowIndex = 0; rowIndex < headerHeight; rowIndex++) {
for (let colIndex = 0; colIndex < allColumns.length; colIndex++) {
const columns = allColumns[colIndex];
const column = columns[rowIndex];
if (!column || !column.children || column.children.length === 0) {
continue;
}
if (columnSet.has(column)) {
continue;
}
columnSet.add(column);
mergeConfigs.push({
rowIndex,
colIndex,
width: column.children.length - 1,
height: 0
});
}
}
// 判断Excel表头名称以及数据源绑定字段
const columns = allColumns.map((columnRows: any[], colIndex: number) => {
const columnRowCount = columnRows.length;
const column = columnRows[columnRowCount - 1];
// 判断表头向下合并空余单元格
if (columnRowCount < headerHeight) {
mergeConfigs.push({
rowIndex: columnRowCount - 1,
colIndex,
width: 0,
height: headerHeight - columnRowCount
});
}
return {
header: columnRows.map(
column =>
column.title || column.titleShort || column.headerName || column.name
),
key: column.data || column.key || column.field || column.prop,
width: column.width / 5 || 20,
columnConfig: column
};
});
return {headerHeight, columns, mergeConfigs};
}
/**
* 导出AG表格
*
* @param agInstance
* @param columns
* @param hiddenColumn
* @param selectIndex
* @param name
* @param fieldList 替换列 originField ==》replaceField
* @param isWrap 是否;换行
* @param isComma 是否,换行
* @param isBr 是否<br>换行
* @param rowKey
*/
export const exportAgGridExcel = (
agInstance: any,
columns: any[],
hiddenColumn: any[],
selectIndex: number[],
name: any,
fieldList = [],
isWrap = false,
isComma = false,
isBr = true,
rowKey: string = " _idx"
) => {
let exportHeader = []; // 表头
if (hiddenColumn.length > 0) {
exportHeader = columns.filter(
col => !hiddenColumn.map(val => val.key).includes(col.field)
);
} else {
exportHeader = columns;
}
// 过滤后的数据或全部数据
let filterData: any[] = [];
agInstance.api.forEachNodeAfterFilter((row: any) => {
filterData.push(row.data);
});
let exportData: any[] = []; // 数据
// 勾选数据导出
if (selectIndex.length > 0) {
filterData = agInstance.api
.getModel()
.rootNode.allLeafChildren.map((row: any) => row.data);
selectIndex.forEach(index => {
let item;
if (rowKey === " _idx") {
item = filterData[index];
} else {
item = filterData.find(val => val[rowKey] === index);
}
if (exportHeader.length > 0) {
let $row = getExportAgExcelObject(exportHeader, item, fieldList);
exportData.push($row);
} else {
exportData.push(item);
}
});
exportExcelByData(exportHeader, exportData, name);
return;
}
// 数据列替换
if (exportHeader.length > 0) {
filterData.forEach(value => {
let $row = getExportAgExcelObject(exportHeader, value, fieldList);
exportData.push($row);
});
} else {
exportData = filterData;
}
exportData.forEach(val => {
for (let prop in val) {
if (val[prop] && typeof val[prop] === "string") {
if (val[prop].indexOf(";") !== -1 && isWrap) {
val[prop] = val[prop].replaceAll(";", "\n");
} else if (val[prop].indexOf(",") !== -1 && isComma) {
val[prop] = val[prop].replaceAll(",", "\n");
} else if (val[prop].indexOf("<br/>") !== -1 && isBr) {
val[prop] = val[prop].replaceAll("<br/>", "\n");
} else if (val[prop].indexOf("<br>") !== -1 && isBr) {
val[prop] = val[prop].replaceAll("<br>", "\n");
}
}
}
});
exportExcelByData(exportHeader, exportData, name);
};
// 日期格式化
export const dateFormatFull = (
timestamp: any | number | Date,
str = "-"
) => {
if (timestamp <= 1000000000000) timestamp *= 1000;
if (timestamp <= 0) return "";
const date = new Date(timestamp);
const y = date.getFullYear();
const m = padding(date.getMonth() + 1);
const d = padding(date.getDate());
const hh = padding(date.getHours());
const mm = padding(date.getMinutes());
const ss = padding(date.getSeconds());
return `${[y, m, d].join(str)} ${[hh, mm, ss].join(":")}`;
};
export const padding = (num: string | number | any[] | any, l = 2, str = "0") => {
num += ""; // 转字符
const len = l - num.length;
if (len > 0) {
if (l === 2) {
return `${str}${num}`;
}
for (let i = 0; i < len; i++) {
num = `${str}${num}`;
}
}
return num;
};
/**
* 评审状态枚举值
* @param {string} value
*/
export function formatReviewLabel(value: string) {
if (!value) {
return $swpT("common.reviewed");
}
return {
"pass": $swpT("common.agree"),
"disagree": $swpT("common.disAgree"), // 不同意
"reject": $swpT("common.overrule"), // 驳回
"transfer": $swpT("common.tranFer"), // 转签
"withdraw": $swpT("common.revoke") // 撤回
}[value] || value;
}
/**
* 对象数组去重
* @param {arr} arr
*/
export function uniqueObjArray(arr: []) {
if (arr.length === 0) return [];
const strings = arr.map((item: any) => JSON.stringify(item));
return Array.from(new Set(strings)).map((item: any) => JSON.parse(item));
}
/**
* 实现复制功能 todo 需要验证,与改造
* @param
*/
export async function copyToClipboard(text: string) {
try {
return await navigator.clipboard.writeText(text);
} catch {
const element = document.createElement("textarea");
const previouslyFocusedElement = document.activeElement;
element.value = text;
// Prevent keyboard from showing on mobile
element.setAttribute("readonly", "");
element.style.contain = "strict";
element.style.position = "absolute";
element.style.left = "-9999px";
element.style.fontSize = "12pt"; // Prevent zooming on iOS
const selection = document.getSelection();
const originalRange = selection
? selection.rangeCount > 0 && selection.getRangeAt(0)
: null;
document.body.appendChild(element);
element.select();
// Explicit selection workaround for iOS
element.selectionStart = 0;
element.selectionEnd = text.length;
document.execCommand("copy");
document.body.removeChild(element);
if (originalRange) {
selection!.removeAllRanges(); // originalRange can't be truthy when selection is falsy
selection!.addRange(originalRange);
}
// Get the focus back on the previously focused element, if any
if (previouslyFocusedElement) {
(previouslyFocusedElement as HTMLElement).focus();
}
}
}
/**
* URL地址转下载
* 注:防止被浏览器拦截
*
* @param url 文件地址
* @param filename 文件名,为空裁剪文件地址
*/
export const downloadUrl = (url:any, filename:string) => {
const link = document.createElement("a");
link.href = url;
if (filename) {
link.download = filename;
} else {
const name = url.split("/");
link.download = name[name.length - 1];
}
link.target = "_blank";
link.click();
link.remove();
};
调用:
// 获取表格数据
const getTableData = (pageState: any = undefined) => {
chartLoading.value = true;
getReport({
...queryForm,
...pageState
}).then(({code, biz_content}) => {
if (code === "10000") {
chartLoading.value = false;
list.value = biz_content.page.data || [];
totalCount.value = Number(biz_content.page.totalSize);
sourceData.value = biz_content.reports.map((item: any) => ({
moduleName: item.moduleName,
校验复用率: item.avgCheckReuseRate,
评估复用率: item.avgReviewReuseRate,
评估工时: item.moduleAssessManHourSum,
应用项目数: item.projectCount
}));
getBarData();
}
});
};