import dayjs from 'dayjs'; import { kebabCase } from 'lodash-es'; import { t } from '@/i18n'; import { fileContentTypeRegExp, TimeScaleType } from '@/constants'; import { fetchWithTimeout } from './fetch'; import type { SorterResult } from 'ant-design-vue/es/table/interface'; import type { GlobalToken } from 'ant-design-vue/es/theme'; import type { ApiResponse, PageSorts } from '@/types'; export const request = async (url: string, init: RequestInit = {}, timeout?: number): Promise => { const headers: HeadersInit = {}; if (typeof init?.body === 'string') { headers['Content-Type'] = 'application/json;charset=UTF-8'; } // const { token, saveToken, resetToken } = useUserInfoStore(); // const { resetDevInfo } = useDeviceInfoStore(); // if (token) { // Object.assign(headers, { // [TOKEN_KEY]: token, // }); // } headers['Authorization'] = 'Bearer ' + import.meta.env.VITE_TEMP_TOKEN; Object.assign(headers, init?.headers); const res = await fetchWithTimeout( import.meta.env.VITE_BASE_API + url, { ...init, headers, }, timeout, ); if (res.status === 401) { // removeToken(); // resetToken(); // resetDevInfo(); // location.replace('/login'); throw new Error(t('common.reLogin')); } if (!res.ok || res.status !== 200) { const json = await res.json(); const errMsg: string = json.msg || json.error || ''; throw new Error(`HTTP Error: ${res.status} ${errMsg}`); } // if (res.url.includes('/Uboxlogin')) { // const token = res.headers.get(TOKEN_KEY); // if (token) { // setToken(token); // saveToken(token); // } // } const contentType = res.headers.get('content-type'); const isBlob = fileContentTypeRegExp.test(contentType || ''); if (isBlob) { return (await res.blob()) as T; } const json: ApiResponse = await res.json(); const { data, code, msg } = json; if (code !== 0) { throw new Error(msg); } if (data === null || data === undefined) { throw new Error(t('common.emptyData')); } return data; }; export const translateNavigation = (title?: string) => { return title ? t('navigation.' + title) : ''; }; /** * 根据 Antd 当前主题的 token 生成 css var */ export const generateThemeCSSVar = (token: GlobalToken, prefix: string): string => { const cssVar = Object.entries(token) .filter(([key]) => { return /^(color|line|link|motion|border|margin|font(?!fam)|padding(?!con)|screen((?!min|max).)*$|boxShadow(?!pop|dra|tab|car))/i.test( key, ); }) .map(([key, value]) => { return `--${prefix}-${kebabCase(key)}:${value}${/(size|width|radius|margin|screen|padding)/gi.test(key) ? 'px' : ''}`; }); cssVar.push(...getColorGradientCSSVar(token.colorPrimary, `${prefix}-color-primary`)); return `:root{${cssVar.join(';')}}`; }; /** * 根据十六进制值颜色生成透明度为 5%~95% 对应颜色的 css var */ export const getColorGradientCSSVar = (color: string, prefix: string): string[] => { const rgb = hexToRgb(color); if (!rgb) { return []; } const cssVar: string[] = []; const { r, g, b } = rgb; cssVar.push(`--${prefix}-rgb:${r}, ${g}, ${b}`); for (let i = 5; i <= 95; i += 5) { cssVar.push(`--${prefix}-opacity-${i}:rgba(${r}, ${g}, ${b}, ${i / 100})`); } return cssVar; }; export const hexToRgb = (hex: string): { r: number; g: number; b: number } | null => { const cleanedHex = hex.replace(/^#/, ''); if (cleanedHex.length !== 3 && cleanedHex.length !== 6) { console.error('Invalid hex color value'); return null; } let extendedHex = cleanedHex; // 将 3 位十六进制扩展为 6 位(例如 #abc -> #aabbcc) if (cleanedHex.length === 3) { extendedHex = cleanedHex .split('') .map((char) => char + char) .join(''); } const r = parseInt(extendedHex.slice(0, 2), 16); const g = parseInt(extendedHex.slice(2, 4), 16); const b = parseInt(extendedHex.slice(4, 6), 16); return { r, g, b }; }; export const addUnit = (val: number, unit: string = 'px'): string => { return val + unit; }; export const waitTime = async (time: number = 100) => { await new Promise((resolve) => { setTimeout(resolve, time); }); }; export const downloadBlob = (blob: Blob, name: string) => { const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = name; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); }; /** * 根据表格排序配置生成分页查询时的字段排序数组 * @param sorter 表格进行排序的字段数组 */ export const getTablePageSorts = (sorter: SorterResult | SorterResult[]): PageSorts[] => { let sorts: SorterResult[]; if (Array.isArray(sorter)) { sorts = sorter; } else { sorts = [sorter]; } sorts = sorts.filter((item) => item.field !== undefined && item.order !== undefined); if (sorts.length) { return sorts.map((item) => ({ column: item.field as string, asc: item.order === 'ascend', })); } return [ { column: 'id', asc: true, }, ]; }; export const formatTimeByScale = (time: string, scale?: TimeScaleType) => { switch (scale) { case TimeScaleType.Hour: return dayjs(time).format('HH:mm'); case TimeScaleType.Day: return dayjs(time).format('MM-DD'); case TimeScaleType.Month: return dayjs(time).format('YYYY-MM'); default: return dayjs(time).format('YYYY-MM-DD HH:mm:ss'); } }; export const timeSorter = (a: string, b: string) => dayjs(a).unix() - dayjs(b).unix(); export const getEChartsColors = (count: number) => { switch (count) { case 0: return []; case 1: return ['#32BAC0']; case 2: return ['#32BAC0', '#5B8FF9']; case 3: return ['#32BAC0', '#5B8FF9', '#5D7092']; case 4: return ['#32BAC0', '#5B8FF9', '#5D7092', '#F6BD16']; case 5: return ['#32BAC0', '#5B8FF9', '#5D7092', '#F6BD16', '#E86452']; case 6: return ['#32BAC0', '#5B8FF9', '#5D7092', '#F6BD16', '#FF9845', '#E86452']; case 7: return ['#32BAC0', '#5B8FF9', '#6DC8EC', '#5D7092', '#F6BD16', '#FF9845', '#E86452']; case 8: return ['#32BAC0', '#5B8FF9', '#6DC8EC', '#5D7092', '#F3DD13', '#F6BD16', '#FF9845', '#E86452']; case 9: return ['#32BAC0', '#5B8FF9', '#6DC8EC', '#5D7092', '#7E93B2', '#F3DD13', '#F6BD16', '#FF9845', '#E86452']; default: return [ '#32BAC0', '#5AD8A6', '#5B8FF9', '#6DC8EC', '#5D7092', '#7E93B2', '#F3DD13', '#F6BD16', '#FF9845', '#E86452', ]; } };