diff --git a/src/plugins/dayjs.ts b/src/plugins/dayjs.ts new file mode 100644 index 0000000..3551381 --- /dev/null +++ b/src/plugins/dayjs.ts @@ -0,0 +1,12 @@ +import 'dayjs/locale/zh-cn'; + +import dayjs from 'dayjs'; +import localeData from 'dayjs/plugin/localeData'; +import weekday from 'dayjs/plugin/weekday'; + +dayjs.extend(weekday); +dayjs.extend(localeData); + +dayjs.locale('zh-cn'); + +export default dayjs; diff --git a/src/types/router/Route.ts b/src/types/router/Route.ts new file mode 100644 index 0000000..c718c54 --- /dev/null +++ b/src/types/router/Route.ts @@ -0,0 +1,29 @@ +import type { RouteComponent } from 'vue-router'; + +/** + * @description 完整子路由的`meta`配置表 + */ +interface CustomizeRouteMeta { + title: string; + subtitle: string; + transition: string; +} + +/** + * @description 整体路由配置表(包括完整子路由) + */ +interface RouteConfigsTable { + /** 路由地址 `必填` */ + path: string; + /** 路由名字(保持唯一)`可选` */ + name?: string; + /** `Layout`组件 `可选` */ + component?: RouteComponent; + /** 路由重定向 `可选` */ + redirect?: string; + meta?: CustomizeRouteMeta; + /** 子路由配置项 */ + children?: Array; +} + +export { RouteConfigsTable }; diff --git a/src/utils/chart.ts b/src/utils/chart.ts new file mode 100644 index 0000000..b8969c9 --- /dev/null +++ b/src/utils/chart.ts @@ -0,0 +1,24 @@ +import { useEventListener } from '@vueuse/core'; +import type { EChartsType } from 'echarts'; + +/** 通用重置图表样式 */ +export const debounceChart = (myChart: EChartsType) => { + useEventListener( + window, + 'resize', + () => { + myChart.resize(); + }, + 500 + ); +}; + +/** 数字格式化 */ +export const formatter = (number) => { + const numbers = number.toString().split('').reverse(); + const segs = []; + + while (numbers.length) segs.push(numbers.splice(0, 3).join('')); + + return segs.join(',').split('').reverse().join(''); +}; diff --git a/src/utils/copy.ts b/src/utils/copy.ts new file mode 100644 index 0000000..03c2dd2 --- /dev/null +++ b/src/utils/copy.ts @@ -0,0 +1,24 @@ +/** + * 复制到剪切板 + * @param text 文本内容 + */ +export const copy = (text: string) => { + const textarea = document.createElement('textarea'); + textarea.value = text; + textarea.style.position = 'fixed'; + document.body.appendChild(textarea); + textarea.select(); + + try { + const success = document.execCommand('copy'); + if (success) { + (window as any as any).$message.success('复制成功!'); + } else { + (window as any).$message.success('复制失败!'); + } + } catch (err: any) { + (window as any).$message.success('复制失败!请手动复制'); + } finally { + document.body.removeChild(textarea); + } +}; diff --git a/src/utils/file.ts b/src/utils/file.ts new file mode 100644 index 0000000..8ed1faa --- /dev/null +++ b/src/utils/file.ts @@ -0,0 +1,45 @@ +export function downloadTextAsFile(text: string, filename: string) { + // 直接创建 File 对象(比 Blob 更高级) + const file = new File([text], filename, { type: 'text/plain' }); + + // 创建下载链接 + const url = URL.createObjectURL(file); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + + // 触发下载 + document.body.appendChild(a); + a.click(); + + // 清理 + requestIdleCallback(() => { + document.body.removeChild(a); + URL.revokeObjectURL(a.href); + }); +} + +export const downloadBlob = (response: any) => { + try { + // 从响应头获取文件名 + const contentDisposition = response.headers['content-disposition']; + let fileName = 'download.zip'; + if (contentDisposition) { + const fileNameMatch = contentDisposition.match(/filename="?(.+)"?/); + if (fileNameMatch && fileNameMatch[1]) { + fileName = fileNameMatch[1]; + } + } + + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', fileName); + document.body.appendChild(link); + link.click(); + link.remove(); + window.URL.revokeObjectURL(url); + } catch (error) { + console.error(error); + } +}; diff --git a/src/utils/regexp/regexpBackground.ts b/src/utils/regexp/regexpBackground.ts new file mode 100644 index 0000000..85e053b --- /dev/null +++ b/src/utils/regexp/regexpBackground.ts @@ -0,0 +1,29 @@ +/** 判断是否是CSS颜色 */ +function isCSSColor(str) { + // 匹配十六进制颜色(如 #fff, #ffffff) + const hexColor = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/; + + // 匹配RGB/RGBA颜色(如 rgb(255, 255, 255), rgba(255, 255, 255, 0.5)) + const rgbColor = /^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(,\s*[\d\.]+)?\s*\)$/; + + // 匹配HSL/HSLA颜色(如 hsl(120, 100%, 50%), hsla(120, 100%, 50%, 0.5)) + const hslColor = /^hsla?\(\s*\d{1,3}\s*,\s*\d{1,3}%\s*,\s*\d{1,3}%\s*(,\s*[\d\.]+)?\s*\)$/; + + // 匹配预定义颜色名称(如 red, blue, green) + const namedColor = /^[a-zA-Z]+$/; + + return hexColor.test(str) || rgbColor.test(str) || hslColor.test(str) || namedColor.test(str); +} + +/** 判断是否是相对路径或绝对路径 */ +function isPath(str) { + // 匹配相对路径(如 ./path, ../path, path/to/file) + const relativePath = /^\.{0,2}\/[^\/].*$/; + + // 匹配绝对路径(如 /path/to/file, C:\path\to\file) + const absolutePath = /^(?:\/|[A-Za-z]:\\).*$/; + + return relativePath.test(str) || absolutePath.test(str); +} + +export { isCSSColor, isPath };