Files
login_task_web/src/utils/links.js

148 lines
4.4 KiB
JavaScript
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.

// 链接管理工具函数
// 格式化链接状态
export function formatLinkStatus(status) {
const statusMap = {
'ACTIVE': '启用',
'INACTIVE': '禁用',
'EXPIRED': '已过期'
}
return statusMap[status] || status
}
// 获取链接状态标签类型
export function getLinkStatusType(status) {
const typeMap = {
'ACTIVE': 'success',
'INACTIVE': 'danger',
'EXPIRED': 'warning'
}
return typeMap[status] || 'info'
}
// 检查链接是否过期
export function isLinkExpired(expiredAt) {
if (!expiredAt) return false
return new Date(expiredAt) < new Date()
}
// 计算剩余时间
export function getRemainingTime(expiredAt) {
if (!expiredAt) return null
const now = new Date()
const expired = new Date(expiredAt)
const diff = expired - now
if (diff <= 0) return '已过期'
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
if (days > 0) return `${days}${hours}小时`
if (hours > 0) return `${hours}小时${minutes}分钟`
return `${minutes}分钟`
}
// 生成二维码URL使用在线服务
export function generateQRCodeUrl(data, size = 200) {
return `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(data)}`
}
// 下载图片
export function downloadImage(url, filename) {
const link = document.createElement('a')
link.href = url
link.download = filename
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
// 复制到剪贴板
export async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text)
return true
} catch (error) {
console.error('复制失败:', error)
return false
}
}
// 计算列宽(中文按双字节处理)
function calcWch(val) {
const s = (val ?? '').toString()
let w = 0
for (const ch of s) w += ch.charCodeAt(0) > 255 ? 2 : 1
return Math.min(Math.max(w, 8), 60) // 8~60 字符宽
}
// 简单日期格式化(如果字段是 Date 或 ISO 字符串)
function fmtDate(v) {
const d = v instanceof Date ? v : (typeof v === 'string' && !isNaN(Date.parse(v)) ? new Date(v) : null)
if (!d) return v
const pad = n => (n < 10 ? '0' + n : '' + n)
return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}
// 真实 .xlsx 导出(中文不会乱码)
export function exportToExcel(data, headers, filename = '导出.xlsx', sheetName = 'Sheet1') {
console.log('xlsx导出数据:', data)
// 动态导入 xlsx 库
import('xlsx').then(({ utils: XLSXUtils, writeFile: XLSXWriteFile }) => {
// 1) 规范化数据:按 headers 顺序映射到"显示列名 -> 值"
const headerLabels = headers.map(h => h.label)
const rows = (data || []).map(row => {
const obj = {}
headers.forEach(h => {
let v = row?.[h.key]
// 识别并格式化日期
v = fmtDate(v)
// 复杂对象转字符串
if (v && typeof v === 'object' && !(v instanceof Date)) {
try { v = JSON.stringify(v) } catch { v = String(v) }
}
// 公式注入防护(以 = + - @ 开头的文本加前导单引号)
if (typeof v === 'string' && /^[=+\-@]/.test(v)) v = "'" + v
// null/undefined 转为空串,保留 0/false
if (v === null || v === undefined) v = ''
obj[h.label] = v
})
return obj
})
// 2) 生成工作表
const ws = XLSXUtils.json_to_sheet(rows, { header: headerLabels })
// 3) 列宽:根据表头和数据计算
const cols = headers.map(h => {
const headW = calcWch(h.label)
const dataW = rows.reduce((mx, r) => Math.max(mx, calcWch(r[h.label])), 0)
return { wch: Math.max(headW, dataW) }
})
ws['!cols'] = cols
// 4) 冻结首行、开启筛选
if (ws['!ref']) {
ws['!freeze'] = { xSplit: 0, ySplit: 1 }
ws['!autofilter'] = { ref: ws['!ref'] }
}
// 5) 生成工作簿并下载
const wb = XLSXUtils.book_new()
XLSXUtils.book_append_sheet(wb, ws, sheetName)
const safeName = filename.endsWith('.xlsx') ? filename : `${filename}.xlsx`
XLSXWriteFile(wb, safeName)
}).catch(error => {
console.error('Failed to load xlsx library:', error)
// 可以在这里添加错误提示
})
}