
功能特性: - JWT用户认证系统 - 日报CRUD管理 - 三级权限控制 - 多维度搜索过滤 - 统计分析功能 - 评论互动系统 - 响应式Cool Admin界面 - 暗色主题支持 技术栈: - 后端:Django 4.2.7 + DRF + SimpleJWT - 前端:Vue 3 + Element Plus + Pinia - 数据库:SQLite/PostgreSQL - 部署:Docker + Nginx 包含内容: - 完整的后端API代码 - 现代化前端界面 - 数据库迁移文件 - 部署脚本和文档 - 演示页面和测试工具
232 lines
5.2 KiB
JavaScript
232 lines
5.2 KiB
JavaScript
import dayjs from 'dayjs'
|
|
import 'dayjs/locale/zh-cn'
|
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
|
|
|
// 配置dayjs
|
|
dayjs.locale('zh-cn')
|
|
dayjs.extend(relativeTime)
|
|
|
|
/**
|
|
* 格式化日期
|
|
* @param {string|Date} date 日期
|
|
* @param {string} format 格式
|
|
* @returns {string}
|
|
*/
|
|
export function formatDate(date, format = 'YYYY-MM-DD') {
|
|
if (!date) return ''
|
|
return dayjs(date).format(format)
|
|
}
|
|
|
|
/**
|
|
* 格式化日期时间
|
|
* @param {string|Date} datetime 日期时间
|
|
* @param {string} format 格式
|
|
* @returns {string}
|
|
*/
|
|
export function formatDateTime(datetime, format = 'YYYY-MM-DD HH:mm:ss') {
|
|
if (!datetime) return ''
|
|
return dayjs(datetime).format(format)
|
|
}
|
|
|
|
/**
|
|
* 相对时间
|
|
* @param {string|Date} date 日期
|
|
* @returns {string}
|
|
*/
|
|
export function fromNow(date) {
|
|
if (!date) return ''
|
|
return dayjs(date).fromNow()
|
|
}
|
|
|
|
/**
|
|
* 获取今天的日期
|
|
* @param {string} format 格式
|
|
* @returns {string}
|
|
*/
|
|
export function getToday(format = 'YYYY-MM-DD') {
|
|
return dayjs().format(format)
|
|
}
|
|
|
|
/**
|
|
* 获取本周的开始和结束日期
|
|
* @returns {object}
|
|
*/
|
|
export function getThisWeek() {
|
|
const today = dayjs()
|
|
const startOfWeek = today.startOf('week')
|
|
const endOfWeek = today.endOf('week')
|
|
|
|
return {
|
|
start: startOfWeek.format('YYYY-MM-DD'),
|
|
end: endOfWeek.format('YYYY-MM-DD')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取本月的开始和结束日期
|
|
* @returns {object}
|
|
*/
|
|
export function getThisMonth() {
|
|
const today = dayjs()
|
|
const startOfMonth = today.startOf('month')
|
|
const endOfMonth = today.endOf('month')
|
|
|
|
return {
|
|
start: startOfMonth.format('YYYY-MM-DD'),
|
|
end: endOfMonth.format('YYYY-MM-DD')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 截取文本
|
|
* @param {string} text 文本
|
|
* @param {number} length 长度
|
|
* @param {string} suffix 后缀
|
|
* @returns {string}
|
|
*/
|
|
export function truncateText(text, length = 50, suffix = '...') {
|
|
if (!text) return ''
|
|
if (text.length <= length) return text
|
|
return text.substring(0, length) + suffix
|
|
}
|
|
|
|
/**
|
|
* 防抖函数
|
|
* @param {Function} func 函数
|
|
* @param {number} wait 等待时间
|
|
* @returns {Function}
|
|
*/
|
|
export function debounce(func, wait) {
|
|
let timeout
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout)
|
|
func(...args)
|
|
}
|
|
clearTimeout(timeout)
|
|
timeout = setTimeout(later, wait)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 节流函数
|
|
* @param {Function} func 函数
|
|
* @param {number} limit 限制时间
|
|
* @returns {Function}
|
|
*/
|
|
export function throttle(func, limit) {
|
|
let inThrottle
|
|
return function executedFunction(...args) {
|
|
if (!inThrottle) {
|
|
func.apply(this, args)
|
|
inThrottle = true
|
|
setTimeout(() => (inThrottle = false), limit)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 深拷贝
|
|
* @param {any} obj 对象
|
|
* @returns {any}
|
|
*/
|
|
export function deepClone(obj) {
|
|
if (obj === null || typeof obj !== 'object') return obj
|
|
if (obj instanceof Date) return new Date(obj.getTime())
|
|
if (obj instanceof Array) return obj.map(item => deepClone(item))
|
|
if (typeof obj === 'object') {
|
|
const clonedObj = {}
|
|
for (const key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
clonedObj[key] = deepClone(obj[key])
|
|
}
|
|
}
|
|
return clonedObj
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成随机字符串
|
|
* @param {number} length 长度
|
|
* @returns {string}
|
|
*/
|
|
export function generateRandomString(length = 8) {
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
let result = ''
|
|
for (let i = 0; i < length; i++) {
|
|
result += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
}
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* 下载文件
|
|
* @param {Blob} blob 文件blob
|
|
* @param {string} filename 文件名
|
|
*/
|
|
export function downloadFile(blob, filename) {
|
|
const url = window.URL.createObjectURL(blob)
|
|
const link = document.createElement('a')
|
|
link.href = url
|
|
link.download = filename
|
|
document.body.appendChild(link)
|
|
link.click()
|
|
document.body.removeChild(link)
|
|
window.URL.revokeObjectURL(url)
|
|
}
|
|
|
|
/**
|
|
* 验证邮箱
|
|
* @param {string} email 邮箱
|
|
* @returns {boolean}
|
|
*/
|
|
export function validateEmail(email) {
|
|
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
return re.test(email)
|
|
}
|
|
|
|
/**
|
|
* 验证手机号
|
|
* @param {string} phone 手机号
|
|
* @returns {boolean}
|
|
*/
|
|
export function validatePhone(phone) {
|
|
const re = /^1[3-9]\d{9}$/
|
|
return re.test(phone)
|
|
}
|
|
|
|
/**
|
|
* 获取文件大小文本
|
|
* @param {number} size 文件大小(字节)
|
|
* @returns {string}
|
|
*/
|
|
export function getFileSizeText(size) {
|
|
if (size < 1024) return size + ' B'
|
|
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB'
|
|
if (size < 1024 * 1024 * 1024) return (size / (1024 * 1024)).toFixed(2) + ' MB'
|
|
return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB'
|
|
}
|
|
|
|
/**
|
|
* 获取用户角色文本
|
|
* @param {object} user 用户对象
|
|
* @returns {string}
|
|
*/
|
|
export function getUserRoleText(user) {
|
|
if (!user) return '游客'
|
|
if (user.is_superuser) return '超级管理员'
|
|
if (user.is_staff) return '管理员'
|
|
return '普通用户'
|
|
}
|
|
|
|
/**
|
|
* 获取用户全名
|
|
* @param {object} user 用户对象
|
|
* @returns {string}
|
|
*/
|
|
export function getUserFullName(user) {
|
|
if (!user) return ''
|
|
const fullName = `${user.first_name || ''} ${user.last_name || ''}`.trim()
|
|
return fullName || user.username
|
|
}
|