Files
Situation-Awareness-Platfor…/src/utils/index.ts

464 lines
13 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 router from '@/router';
import * as CryptoJS from 'crypto-js';
import pick from 'lodash/pick';
import pickBy from 'lodash/pickBy';
import type { createIssueReqType } from '@/api/issue/types';
import type { RepoItemResData } from '@/utils/types';
import DOMPurify from 'dompurify';
import { Message } from 'vue-devui/message';
import qs from 'qs';
/**
* 返回 axios 的 data, 或者 obj 最内层的 data
*/
export const escapeResData = (obj: object) => {
if (!obj) return obj;
if (!Object.prototype.hasOwnProperty.call(obj, 'data')) return obj;
if (obj?.headers?.constructor?.name === 'AxiosHeaders') { return obj?.data; };
return escapeResData(obj?.data);
};
export function getRepoName(): string {
//
return router.currentRoute.value.params.repoName;
};
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string | null}
*/
function parseTime(time: string | number | Date, cFormat?: string) {
if (!time) {
return null;
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
let date;
if (typeof time === 'object') {
date = time;
} else {
if ((typeof time === 'string')) {
if ((/^[0-9]+$/.test(time))) {
time = parseInt(time);
} else {
// support safari
time = time.replace(new RegExp(/-/gm), '/');
}
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000;
}
date = new Date(time);
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
};
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
const value = formatObj[key];
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value]; }
return value.toString().padStart(2, '0');
});
return time_str;
}
export function fileToBlob(file: any) {
// 创建 FileReader 对象
const reader = new FileReader();
return new Promise(resolve => {
// FileReader 添加 load 事件
reader.addEventListener('load', (e) => {
let blob;
if (typeof e.target.result === 'object') {
blob = new Blob([e.target.result]);
} else {
blob = e.target.result;
}
resolve(blob);
});
// FileReader 以 ArrayBuffer 格式 读取 File 对象中数据
reader.readAsArrayBuffer(file);
});
}
// 图片转 base64
export function imageToBase64(file: File) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
export function generateHash(userName: string, salt: string): string {
const hashBytes = CryptoJS.SHA256(userName + salt);
return hashBytes.toString(CryptoJS.enc.Hex);
}
export function getFilePath(hash: string, filetype: string): string {
const chars: string[] = hash.split('');
const sb: string[] = [];
for (const c of chars) {
if (isNaN(Number(c))) {
sb.push(c);
}
}
return `${sb.slice(0, 2).join('')}/${sb.slice(2, 4).join('')}/${hash}.${filetype}`;
}
export function getImageUrl(iam_id?: string, fileType: string = 'png', isAvatar: boolean = true) {
if (!iam_id) {
const accountInfo = JSON.parse(localStorage.getItem('opUserInfo') || '{}');
iam_id = accountInfo.iam_id;
}
if (isAvatar) {
const host = 'https://gitcode-img.obs.cn-south-1.myhuaweicloud.com:443/';
const salt = 'avatar';
const hash = generateHash(iam_id || '', salt);
const path = getFilePath(hash, fileType || 'png');
return host + path + '?time=' + new Date().getTime();
}
}
/**
* 处理issue put 数据
*/
export function formatIssuePutData(data: createIssueReqType) {
const params = pick(data, ['title', 'description', 'confidential', 'discussions', 'assignee', 'assignee_id', 'assignee_ids', 'project_id', 'issue_iid', 'labels', 'milestone_id', 'discussion_locked', 'state_event']);
let { labels } = params;
if (typeof labels === 'object') {
labels = labels.map(item => {
if (typeof item === 'string') {
return item;
} else if (typeof item.name === 'string') {
return item.name;
} else {
return null;
}
});
}
return ({
...params,
labels,
issue_category: '-',
issue_stage: '-',
issue_severity: '-'
});
}
/**
* 提取展示的姓名
*/
export const pickNickName = (author?: any): string => {
return author?.nick_name || author?.nickname || author?.name_cn || author?.name || author?.username || '';
};
/**
* 去除对象中的空值
*/
export function removeEmptyValue(params: object): object {
return pickBy(params, (e) => (e !== undefined && e !== '' && e !== null));
}
/**
* 替换对象中的null为 undefined
*/
export function replaceNull(obj: {[name:string]: any}): any {
for (const k in obj) {
if (obj[k] === null) {
obj[k] = undefined;
}
}
return obj;
}
/**
* 处理多选数据 1.空值 清空select 2.重复项取消 3.未选中的添加
*/
export function formatSelectedData(current: string | object | undefined | null, selectedList: any[], judge: (a: { [name: string]: unknown }, b: { [name: string]: unknown } | unknown) => boolean): object[] {
if (!current) return [];
const index = selectedList.findIndex((item) => {
if (typeof item === 'string') {
return item === current;
} else {
return judge && judge(item, current);
}
});
if (index > -1) {
selectedList.splice(index, 1);
} else {
selectedList.push(current);
}
return selectedList;
}
/**
* 处理引用回复文本
*/
export const formatQuoteReply = (str: string) => {
str = str.trim();
if (!str) return '';
str = str.split('\n').map(e => '>' + e).join('\n') + '\n\n';
return str;
};
/**
* 判断父级元素有没有类名
*/
export function hasClassInParent(target: Element, classNameList: string[]): boolean {
if (target?.parentElement) {
if (classNameList.every(name => target?.classList?.contains(name))) {
return true;
} else {
return hasClassInParent(target?.parentElement, classNameList);
}
} else {
return target ? classNameList.every(name => target?.classList?.contains(name)) : false;
}
}
/**
* 优先展示已经选择的项,已勾选的排在前面
*/
export const sortList = (list: Object[] = [], select: Object[] = []):Object[] => {
list = list.slice(0);
select = select.slice(0);
if (select[0]) {
const sList:any[] = [];
for (let i = 0; i < select.length; i++) {
const index = list.findIndex(e => e.value === select[i]?.value);
if (index > -1) {
const one = list.splice(index, 1)[0];
sList.push(one);
}
}
return sList.concat(list);
} else {
return list;
}
};
/**
* 处理repo数据便于使用repoItem组件
*/
export const repoDataHandler = (data: RepoItemResData[]) => {
return data.filter((item) => {
return !!item && (item.id || item.resource_id);
}).map((item) => {
const langs = (item.main_repository_language || []).filter((lang) => {
return !!lang;
});
return {
id: item.id || item.resource_id || '',
imgSrc: '',
title: item.name || '-',
desc: item.description || '-',
isStar: item.starred || false,
tag: item.visibility || '',
to: `/${item.namespace}`,
web_url: item.web_url,
iconHandleList: [
{ icon: 'icon-dot-status', value: langs.join(',') || '-', type: 'language', iconColor: 'red', label: '', to: '' },
{ icon: 'gt-star', value: item.star_count, label: '', to: '' },
{ icon: 'gt-fork', value: item.forks_count, label: '', to: '' },
{ icon: 'gt-date', value: item.last_activity_at, label: '', to: '' }
]
};
});
};
/**
* 文案关键词高亮
*/
export const highlightWords = (Word: string, title?: string) => {
if (!Word) return xssPurify(title || '');
title = title ? xssPurify(title) : '';
const regexPattern = new RegExp(`(${Word})`, 'gi');
const str = title?.replace(regexPattern, (_, match) => `<span style="color:red">${match}</span>`);
return str;
};
/* 过滤对象中的空属性值
* @param obj
* @returns
*/
export function filterEmptyObj(obj: object) {
const newObj = obj;
for (const key in newObj) { // 删除空属性值
if (Object.prototype.hasOwnProperty.call(newObj, key)) {
if (!newObj[key]) {
delete newObj[key];
}
}
}
return newObj;
}
export const fullscreen = (id: string): void => {
if (document.fullscreenElement || document.webkitCurrentFullScreenElement) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
// 兼容Firefox
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
// 兼容Chrome, Safari and Opera等
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
// 兼容IE/Edge
document.msExitFullscreen();
}
} else {
const dom = document.getElementById(id);
if (dom?.requestFullscreen) {
dom.requestFullscreen();
} else if (dom?.mozRequestFullScreen) {
// 兼容Firefox
dom.mozRequestFullScreen();
} else if (dom?.webkitRequestFullScreen) {
// 兼容Chrome, Safari and Opera等
dom.webkitRequestFullScreen();
} else if (dom?.msRequestFullscreen) {
// 兼容IE/Edge
dom.msRequestFullscreen();
}
}
};
// 对象深层递归合并
export const deepMerge = function(target: object, source: object) {
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (source[key] instanceof Object && key in target && target[key] instanceof Object) {
deepMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
}
return target;
};
// 最长公共子序列(模糊匹配)
export const longestCommonSubsequence = function(str1: string, str2: string) {
const m = str1.length;
const n = str2.length;
const dp = new Array(m + 1);
for (let i = 0; i <= m; i++) {
dp[i] = new Array(n + 1).fill(0);
}
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (str1[i - 1] === str2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
let lcs = '';
let i = m; let j = n;
while (i > 0 && j > 0) {
if (str1[i - 1] === str2[j - 1]) {
lcs = str1[i - 1] + lcs;
i--;
j--;
} else if (dp[i - 1][j] > dp[i][j - 1]) {
i--;
} else {
j--;
}
}
return lcs;
};
export const blurMatch = function(target: string, keywords: string) {
const m = target.length;
const n = keywords.length;
const dp = new Array(m + 1);
for (let i = 0; i <= m; i++) {
dp[i] = new Array(n + 1).fill('');
}
const match = [];
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (target[i - 1] === keywords[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + keywords[j - 1];
if (typeof match[j - 1] === 'undefined') match[j - 1] = i - 1;
} else {
dp[i][j] = dp[i - 1][j].length > dp[i][j - 1].length ? dp[i - 1][j] : dp[i][j - 1];
}
}
}
return match;
};
/**
* xss 过滤
* purify 规则参考https://github.com/cure53/DOMPurify#control-our-allow-lists-and-block-lists
*/
const purifyConfig = { FORBID_TAGS: ['img'] };
export const xssPurify = (str: string) => DOMPurify.sanitize(str, purifyConfig);
export const messageError = ({ error_message, message }) => Message.error(error_message || message);
export const savePageRef = (fullPath:string) => {
// const BASE_URL = (import.meta as any).env.VITE_HOST;
const BASE_URL = window.location.origin + '/openRepoPortal';
const beforeRef = sessionStorage.getItem('ref');
const ref = beforeRef || document.referrer || '';
window.page_ref = ref;
sessionStorage.setItem('ref', BASE_URL + fullPath);
};
/**
* 处理上报header中的地址防止 header size 过大 报错431
* @param href string访问地址
* @returns {string} 访问地址
*/
export const cutParamsInUrl = (href: string) => {
if (!href) return '';
try {
const location = new URL(href);
const query = qs.parse(location.search, { ignoreQueryPrefix: true });
for (const k in query) {
if (typeof query[k] === 'string') {
query[k] = query[k]?.substring(0, 100);
}
}
location.search = qs.stringify(query);
return location.href;
} catch (error) {
console.log(error);
return href;
};
};
/**
* 获取注册来源utm_source(有效时间一小时)
* @returns {string} utm_source
*/
export const getSignUtmSource = () => {
const utm_source_sign = localStorage.getItem('utm_source_sign');
if (utm_source_sign) {
const intervalTime = 1000 * 60 * 60;
const currentTime = Date.now();
const utm_source_sign_time = Number(localStorage.getItem('utm_source_sign_time'));
if (utm_source_sign_time + intervalTime < currentTime) {
// 超过一小时清除utm_source
localStorage.removeItem('utm_source_sign');
localStorage.removeItem('utm_source_sign_time');
return '';
} else {
return JSON.parse(utm_source_sign);
}
}
return '';
};