first commit

This commit is contained in:
2025-10-27 23:13:08 +08:00
commit 476c5e7658
2968 changed files with 49547 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
/**
* Emoji处理工具函数
*/
// 将emoji代码转换为Unicode字符
export function parseEmoji(text) {
// 这里可以添加具体的emoji解析逻辑
// 例如将 :smile: 转换为 😊
return text;
}
// 将Unicode字符转换为emoji代码
export function encodeEmoji(text) {
// 这里可以添加具体的emoji编码逻辑
return text;
}
// 检查文本中是否包含emoji
export function containsEmoji(text) {
// 基本的emoji Unicode范围检查
const emojiRegex = /[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]/gu;
return emojiRegex.test(text);
}
export default {
parseEmoji,
encodeEmoji,
containsEmoji
};
+165
View File
@@ -0,0 +1,165 @@
// 常用emoji表情数据
export const emojis = [
// 笑脸和情感
{ id: 'smile', unicode: '😊', name: '微笑' },
{ id: 'laugh', unicode: '😄', name: '大笑' },
{ id: 'grin', unicode: '😁', name: ' grin' },
{ id: 'tears_of_joy', unicode: '😂', name: '笑哭' },
{ id: 'wink', unicode: '😉', name: '眨眼' },
{ id: 'blush', unicode: '😊', name: '脸红' },
{ id: 'innocent', unicode: '😇', name: '天使' },
{ id: 'heart_eyes', unicode: '😍', name: '花痴' },
{ id: 'kissing_heart', unicode: '😘', name: '飞吻' },
{ id: 'kissing_closed_eyes', unicode: '😚', name: '闭眼亲亲' },
{ id: 'yum', unicode: '😋', name: '好吃' },
{ id: 'stuck_out_tongue_winking_eye', unicode: '😜', name: '吐舌头眨眼' },
{ id: 'sunglasses', unicode: '😎', name: '酷' },
{ id: 'smirk', unicode: '😏', name: '得意' },
{ id: 'expressionless', unicode: '😑', name: '面无表情' },
{ id: 'neutral_face', unicode: '😐', name: '中性' },
// 手势和身体部位
{ id: 'thumbsup', unicode: '👍', name: '赞' },
{ id: 'thumbsdown', unicode: '👎', name: '踩' },
{ id: 'ok_hand', unicode: '👌', name: 'OK' },
{ id: 'fist', unicode: '✊', name: '拳头' },
{ id: 'v', unicode: '✌️', name: '胜利' },
{ id: 'wave', unicode: '👋', name: '挥手' },
{ id: 'clap', unicode: '👏', name: '鼓掌' },
{ id: 'muscle', unicode: '💪', name: '肌肉' },
{ id: 'pray', unicode: '🙏', name: '祈祷' },
// 动物和自然
{ id: 'dog', unicode: '🐶', name: '狗' },
{ id: 'cat', unicode: '🐱', name: '猫' },
{ id: 'pig', unicode: '🐷', name: '猪' },
{ id: 'rabbit', unicode: '🐰', name: '兔子' },
{ id: 'koala', unicode: '🐨', name: '考拉' },
{ id: 'tiger', unicode: '🐯', name: '老虎' },
{ id: 'horse', unicode: '🐴', name: '马' },
{ id: 'cow', unicode: '🐮', name: '牛' },
{ id: 'panda_face', unicode: '🐼', name: '熊猫' },
{ id: 'pig_nose', unicode: '🐽', name: '猪鼻子' },
{ id: 'feet', unicode: '🐾', name: '爪子' },
{ id: 'turtle', unicode: '🐢', name: '乌龟' },
{ id: 'hatching_chick', unicode: '🐣', name: '孵化' },
{ id: 'baby_chick', unicode: '🐤', name: '小鸡' },
{ id: 'hatched_chick', unicode: '🐥', name: '雏鸡' },
{ id: 'bird', unicode: '🐦', name: '鸟' },
// 食物和饮料
{ id: 'grapes', unicode: '🍇', name: '葡萄' },
{ id: 'melon', unicode: '🍈', name: '甜瓜' },
{ id: 'watermelon', unicode: '🍉', name: '西瓜' },
{ id: 'tangerine', unicode: '🍊', name: '橘子' },
{ id: 'lemon', unicode: '🍋', name: '柠檬' },
{ id: 'banana', unicode: '🍌', name: '香蕉' },
{ id: 'pineapple', unicode: '🍍', name: '菠萝' },
{ id: 'apple', unicode: '🍎', name: '苹果' },
{ id: 'green_apple', unicode: '🍏', name: '青苹果' },
{ id: 'cherries', unicode: '🍒', name: '樱桃' },
{ id: 'strawberry', unicode: '🍓', name: '草莓' },
{ id: 'hamburger', unicode: '🍔', name: '汉堡' },
{ id: 'pizza', unicode: '🍕', name: '披萨' },
{ id: 'meat_on_bone', unicode: '🍖', name: '排骨' },
{ id: 'poultry_leg', unicode: '🍗', name: '鸡腿' },
{ id: 'rice_cracker', unicode: '🍘', name: '米饼' },
// 活动和运动
{ id: 'soccer', unicode: '⚽', name: '足球' },
{ id: 'basketball', unicode: '🏀', name: '篮球' },
{ id: 'football', unicode: '🏈', name: '橄榄球' },
{ id: 'baseball', unicode: '⚾', name: '棒球' },
{ id: 'tennis', unicode: '🎾', name: '网球' },
{ id: 'golf', unicode: '⛳', name: '高尔夫' },
{ id: 'ski', unicode: '🎿', name: '滑雪' },
{ id: 'snowboarder', unicode: '🏂', name: '滑雪板' },
{ id: 'swimmer', unicode: '🏊', name: '游泳' },
{ id: 'surfer', unicode: '🏄', name: '冲浪' },
{ id: 'cyclist', unicode: '🚴', name: '骑车' },
{ id: 'runner', unicode: '🏃', name: '跑步' },
{ id: 'dancer', unicode: '💃', name: '跳舞' },
{ id: 'guitar', unicode: '🎸', name: '吉他' },
{ id: 'musical_keyboard', unicode: '🎹', name: '键盘' },
{ id: 'violin', unicode: '🎻', name: '小提琴' },
// 旅行和地点
{ id: 'rocket', unicode: '🚀', name: '火箭' },
{ id: 'helicopter', unicode: '🚁', name: '直升机' },
{ id: 'steam_locomotive', unicode: '🚂', name: '火车头' },
{ id: 'railway_car', unicode: '🚃', name: '车厢' },
{ id: 'bullettrain_side', unicode: '🚄', name: '高铁' },
{ id: 'bullettrain_front', unicode: '🚅', name: '子弹头' },
{ id: 'train2', unicode: '🚆', name: '火车' },
{ id: 'metro', unicode: '🚇', name: '地铁' },
{ id: 'light_rail', unicode: '🚈', name: '轻轨' },
{ id: 'station', unicode: '🚉', name: '车站' },
{ id: 'tram', unicode: '🚊', name: '电车' },
{ id: 'bus', unicode: '🚌', name: '公交车' },
{ id: 'blue_car', unicode: '🚙', name: '汽车' },
{ id: 'car', unicode: '🚗', name: '轿车' },
{ id: 'taxi', unicode: '🚕', name: '出租车' },
{ id: 'truck', unicode: '🚚', name: '卡车' },
// 符号和标志
{ id: 'heart', unicode: '❤️', name: '爱心' },
{ id: 'broken_heart', unicode: '💔', name: '心碎' },
{ id: 'heartpulse', unicode: '💗', name: '心动' },
{ id: 'sparkling_heart', unicode: '💖', name: '闪心' },
{ id: 'cupid', unicode: '💘', name: '丘比特' },
{ id: 'gift_heart', unicode: '💝', name: '礼盒心' },
{ id: 'heart_decoration', unicode: '💟', name: '心装饰' },
{ id: 'purple_heart', unicode: '💜', name: '紫心' },
{ id: 'yellow_heart', unicode: '💛', name: '黄心' },
{ id: 'green_heart', unicode: '💚', name: '绿心' },
{ id: 'blue_heart', unicode: '💙', name: '蓝心' },
{ id: 'star', unicode: '⭐', name: '星星' },
{ id: 'sparkles', unicode: '✨', name: '闪亮' },
{ id: 'zap', unicode: '⚡', name: '闪电' },
{ id: 'fire', unicode: '🔥', name: '火' },
{ id: 'boom', unicode: '💥', name: '爆炸' }
];
// 将emoji按类别分组
export const emojiCategories = [
{
id: 'people',
name: '笑脸和情感',
emojis: emojis.slice(0, 16)
},
{
id: 'hands',
name: '手势和身体',
emojis: emojis.slice(16, 25)
},
{
id: 'animals',
name: '动物和自然',
emojis: emojis.slice(25, 41)
},
{
id: 'food',
name: '食物和饮料',
emojis: emojis.slice(41, 57)
},
{
id: 'activity',
name: '活动和运动',
emojis: emojis.slice(57, 73)
},
{
id: 'travel',
name: '旅行和地点',
emojis: emojis.slice(73, 89)
},
{
id: 'symbols',
name: '符号和标志',
emojis: emojis.slice(89, 105)
}
];
export default {
emojis,
emojiCategories
};
+355
View File
@@ -0,0 +1,355 @@
/**
* 通用工具函数
*/
/**
* 格式化时间
* @param {Date|string|number} date 时间
* @param {string} format 格式 'YYYY-MM-DD HH:mm:ss'
*/
export function formatTime(date, format = 'YYYY-MM-DD HH:mm:ss') {
if (!date) return ''
const d = new Date(date)
if (isNaN(d.getTime())) return ''
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const hours = String(d.getHours()).padStart(2, '0')
const minutes = String(d.getMinutes()).padStart(2, '0')
const seconds = String(d.getSeconds()).padStart(2, '0')
return format
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('mm', minutes)
.replace('ss', seconds)
}
/**
* 格式化相对时间
* @param {Date|string|number} date 时间
*/
export function formatRelativeTime(date) {
if (!date) return ''
const now = new Date()
const target = new Date(date)
const diff = now.getTime() - target.getTime()
const minute = 60 * 1000
const hour = 60 * minute
const day = 24 * hour
const week = 7 * day
const month = 30 * day
if (diff < minute) {
return '刚刚'
} else if (diff < hour) {
return `${Math.floor(diff / minute)}分钟前`
} else if (diff < day) {
return `${Math.floor(diff / hour)}小时前`
} else if (diff < week) {
return `${Math.floor(diff / day)}天前`
} else if (diff < month) {
return `${Math.floor(diff / week)}周前`
} else {
return formatTime(target, 'YYYY-MM-DD')
}
}
/**
* 格式化金额
* @param {number} amount 金额
* @param {string} currency 货币符号
*/
export function formatMoney(amount, currency = '¥') {
if (amount === null || amount === undefined || isNaN(amount)) return '0'
return `${currency}${Number(amount).toLocaleString()}`
}
/**
* 格式化文件大小
* @param {number} bytes 字节数
*/
export function formatFileSize(bytes) {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
/**
* 防抖函数
* @param {Function} func 要防抖的函数
* @param {number} delay 延迟时间
*/
export function debounce(func, delay = 300) {
let timeoutId
return function (...args) {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => func.apply(this, args), delay)
}
}
/**
* 节流函数
* @param {Function} func 要节流的函数
* @param {number} delay 延迟时间
*/
export function throttle(func, delay = 300) {
let lastCall = 0
return function (...args) {
const now = Date.now()
if (now - lastCall >= delay) {
lastCall = now
return func.apply(this, args)
}
}
}
/**
* 深拷贝
* @param {any} obj 要拷贝的对象
*/
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
}
}
/**
* 生成唯一ID
*/
export function generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2)
}
/**
* 验证手机号
* @param {string} phone 手机号
*/
export function validatePhone(phone) {
const reg = /^1[3-9]\d{9}$/
return reg.test(phone)
}
/**
* 验证邮箱
* @param {string} email 邮箱
*/
export function validateEmail(email) {
const reg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return reg.test(email)
}
/**
* 验证身份证号
* @param {string} idCard 身份证号
*/
export function validateIdCard(idCard) {
const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
return reg.test(idCard)
}
/**
* 获取URL参数
* @param {string} name 参数名
* @param {string} url URL地址
*/
export function getUrlParam(name, url = window.location.href) {
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
const r = url.match(reg)
if (r != null) return decodeURIComponent(r[2])
return null
}
/**
* 存储到本地
* @param {string} key 键
* @param {any} value 值
*/
export function setStorage(key, value) {
try {
uni.setStorageSync(key, JSON.stringify(value))
} catch (error) {
console.error('存储失败:', error)
}
}
/**
* 从本地获取
* @param {string} key 键
* @param {any} defaultValue 默认值
*/
export function getStorage(key, defaultValue = null) {
try {
const value = uni.getStorageSync(key)
return value ? JSON.parse(value) : defaultValue
} catch (error) {
console.error('获取存储失败:', error)
return defaultValue
}
}
/**
* 删除本地存储
* @param {string} key 键
*/
export function removeStorage(key) {
try {
uni.removeStorageSync(key)
} catch (error) {
console.error('删除存储失败:', error)
}
}
/**
* 显示加载提示
* @param {string} title 提示文字
*/
export function showLoading(title = '加载中...') {
uni.showLoading({
title,
mask: true
})
}
/**
* 隐藏加载提示
*/
export function hideLoading() {
uni.hideLoading()
}
/**
* 显示成功提示
* @param {string} title 提示文字
*/
export function showSuccess(title) {
uni.showToast({
title,
icon: 'success',
duration: 2000
})
}
/**
* 显示错误提示
* @param {string} title 提示文字
*/
export function showError(title) {
uni.showToast({
title,
icon: 'error',
duration: 2000
})
}
/**
* 显示普通提示
* @param {string} title 提示文字
*/
export function showToast(title) {
uni.showToast({
title,
icon: 'none',
duration: 2000
})
}
/**
* 显示确认对话框
* @param {string} content 内容
* @param {string} title 标题
*/
export function showConfirm(content, title = '提示') {
return new Promise((resolve) => {
uni.showModal({
title,
content,
success: (res) => {
resolve(res.confirm)
}
})
})
}
/**
* 页面跳转
* @param {string} url 页面路径
* @param {object} params 参数
*/
export function navigateTo(url, params = {}) {
const query = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&')
const fullUrl = query ? `${url}?${query}` : url
uni.navigateTo({
url: fullUrl,
fail: (error) => {
console.error('页面跳转失败:', error)
showError('页面跳转失败')
}
})
}
/**
* 页面重定向
* @param {string} url 页面路径
* @param {object} params 参数
*/
export function redirectTo(url, params = {}) {
const query = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&')
const fullUrl = query ? `${url}?${query}` : url
uni.redirectTo({
url: fullUrl,
fail: (error) => {
console.error('页面重定向失败:', error)
showError('页面重定向失败')
}
})
}
/**
* 切换Tab页面
* @param {string} url 页面路径
*/
export function switchTab(url) {
uni.switchTab({
url,
fail: (error) => {
console.error('Tab切换失败:', error)
showError('页面切换失败')
}
})
}
/**
* 返回上一页
* @param {number} delta 返回层数
*/
export function navigateBack(delta = 1) {
uni.navigateBack({
delta,
fail: (error) => {
console.error('返回失败:', error)
showError('返回失败')
}
})
}
+114
View File
@@ -0,0 +1,114 @@
import { useAuthStore } from '../store/authStore.js'
// 需要登录的页面路径
const authRequiredPages = [
'/pages/index/index',
'/pages/profile/profile',
'/pages/function/function',
'/pages/message/message',
'/pages/tasks/index'
]
// 登录页面路径
const loginPage = '/pages/login/index'
// 首页路径
const homePage = '/pages/index/index'
/**
* 检查当前页面是否需要登录
* @param {string} currentPath 当前页面路径
* @returns {boolean} 是否需要登录
*/
export function isAuthRequired(currentPath) {
return authRequiredPages.includes(currentPath)
}
/**
* 路由守卫 - 检查登录状态
* @param {string} toPath 目标页面路径
* @returns {boolean} 是否允许访问
*/
export function checkAuthGuard(toPath) {
const authStore = useAuthStore()
// 如果是登录页面,直接允许访问
if (toPath === loginPage) {
return true
}
// 检查是否需要登录
if (isAuthRequired(toPath)) {
// 检查是否已登录
if (!authStore.isAuthenticated) {
// 跳转到登录页面
uni.reLaunch({
url: loginPage
})
return false
}
}
return true
}
/**
* 初始化路由守卫
*/
export function initRouteGuard() {
// 监听页面跳转
uni.addInterceptor('navigateTo', {
invoke(args) {
const toPath = args.url.split('?')[0] // 移除查询参数
if (!checkAuthGuard(toPath)) {
return false // 阻止跳转
}
}
})
uni.addInterceptor('redirectTo', {
invoke(args) {
const toPath = args.url.split('?')[0]
if (!checkAuthGuard(toPath)) {
return false
}
}
})
uni.addInterceptor('switchTab', {
invoke(args) {
const toPath = args.url.split('?')[0]
if (!checkAuthGuard(toPath)) {
return false
}
}
})
uni.addInterceptor('reLaunch', {
invoke(args) {
const toPath = args.url.split('?')[0]
if (!checkAuthGuard(toPath)) {
return false
}
}
})
}
/**
* 登录成功后跳转
* @param {string} redirectPath 重定向路径,默认为首页
*/
export function redirectAfterLogin(redirectPath = homePage) {
uni.reLaunch({
url: redirectPath
})
}
/**
* 登出后跳转
*/
export function redirectAfterLogout() {
uni.reLaunch({
url: loginPage
})
}
+183
View File
@@ -0,0 +1,183 @@
/**
* 启动画面管理器
*/
// 启动画面配置
export const splashConfig = {
// 最小显示时间(毫秒)
minDisplayTime: 2000,
// 最大显示时间(毫秒)
maxDisplayTime: 5000,
// 是否已显示过启动画面
hasShown: false,
// 启动时间戳
startTime: null
}
/**
* 初始化启动画面
*/
export function initSplash() {
splashConfig.startTime = Date.now()
splashConfig.hasShown = false
}
/**
* 检查是否应该显示启动画面
*/
export function shouldShowSplash() {
// 如果已经显示过,不再显示
if (splashConfig.hasShown) {
return false
}
// 检查是否在冷启动状态
const isColdStart = !getApp().globalData?.isWarmStart
return isColdStart
}
/**
* 标记启动画面已显示
*/
export function markSplashShown() {
splashConfig.hasShown = true
}
/**
* 获取启动画面显示时长
*/
export function getSplashDuration() {
if (!splashConfig.startTime) {
return splashConfig.minDisplayTime
}
const elapsed = Date.now() - splashConfig.startTime
return Math.max(splashConfig.minDisplayTime - elapsed, 500)
}
/**
* 启动画面加载步骤配置
*/
export const loadingSteps = [
{
text: '正在初始化...',
duration: 800,
action: 'init'
},
{
text: '加载用户数据...',
duration: 1000,
action: 'loadUserData'
},
{
text: '同步工作数据...',
duration: 800,
action: 'syncWorkData'
},
{
text: '准备就绪...',
duration: 600,
action: 'ready'
}
]
/**
* 执行启动步骤
*/
export async function executeLoadingStep(step) {
try {
switch (step.action) {
case 'init':
await initializeApp()
break
case 'loadUserData':
await loadUserData()
break
case 'syncWorkData':
await syncWorkData()
break
case 'ready':
await prepareReady()
break
}
return true
} catch (error) {
console.error(`启动步骤 ${step.action} 执行失败:`, error)
return false
}
}
/**
* 初始化应用
*/
async function initializeApp() {
// 模拟初始化过程
await new Promise(resolve => setTimeout(resolve, 200))
// 这里可以添加实际的初始化逻辑
// 例如:检查网络状态、初始化全局配置等
console.log('应用初始化完成')
}
/**
* 加载用户数据
*/
async function loadUserData() {
// 模拟加载用户数据
await new Promise(resolve => setTimeout(resolve, 300))
// 这里可以添加实际的用户数据加载逻辑
// 例如:从本地存储加载用户信息、验证登录状态等
console.log('用户数据加载完成')
}
/**
* 同步工作数据
*/
async function syncWorkData() {
// 模拟同步工作数据
await new Promise(resolve => setTimeout(resolve, 400))
// 这里可以添加实际的工作数据同步逻辑
// 例如:同步待办事项、考勤数据、消息等
console.log('工作数据同步完成')
}
/**
* 准备就绪
*/
async function prepareReady() {
// 模拟准备就绪过程
await new Promise(resolve => setTimeout(resolve, 200))
// 这里可以添加最后的准备逻辑
// 例如:预加载关键数据、设置全局状态等
console.log('应用准备就绪')
}
/**
* 启动画面完成回调
*/
export function onSplashComplete() {
// 标记应用为热启动
if (getApp().globalData) {
getApp().globalData.isWarmStart = true
}
// 标记启动画面已显示
markSplashShown()
console.log('启动画面完成')
}
/**
* 重置启动状态(用于测试)
*/
export function resetSplashState() {
splashConfig.hasShown = false
splashConfig.startTime = null
if (getApp().globalData) {
getApp().globalData.isWarmStart = false
}
}