mirror of
https://github.com/xiaoyiweb/YiAi.git
synced 2026-02-13 18:04:27 +08:00
初始化
This commit is contained in:
18
chat/src/utils/crypto/index.ts
Normal file
18
chat/src/utils/crypto/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
|
||||
const CryptoSecret = '__CRYPTO_SECRET__'
|
||||
|
||||
export function enCrypto(data: any) {
|
||||
const str = JSON.stringify(data)
|
||||
return CryptoJS.AES.encrypt(str, CryptoSecret).toString()
|
||||
}
|
||||
|
||||
export function deCrypto(data: string) {
|
||||
const bytes = CryptoJS.AES.decrypt(data, CryptoSecret)
|
||||
const str = bytes.toString(CryptoJS.enc.Utf8)
|
||||
|
||||
if (str)
|
||||
return JSON.parse(str)
|
||||
|
||||
return null
|
||||
}
|
||||
59
chat/src/utils/format/index.ts
Normal file
59
chat/src/utils/format/index.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 转义 HTML 字符
|
||||
* @param source
|
||||
*/
|
||||
export function encodeHTML(source: string) {
|
||||
return source
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为代码块
|
||||
* @param text
|
||||
*/
|
||||
export function includeCode(text: string | null | undefined) {
|
||||
const regexp = /^(?:\s{4}|\t).+/gm
|
||||
return !!(text?.includes(' = ') || text?.match(regexp))
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制文本
|
||||
* @param options
|
||||
*/
|
||||
export function copyText(options: { text: string; origin?: boolean }) {
|
||||
const props = { origin: true, ...options }
|
||||
|
||||
let input: HTMLInputElement | HTMLTextAreaElement
|
||||
|
||||
if (props.origin)
|
||||
input = document.createElement('textarea')
|
||||
else
|
||||
input = document.createElement('input')
|
||||
|
||||
input.setAttribute('readonly', 'readonly')
|
||||
input.value = props.text
|
||||
document.body.appendChild(input)
|
||||
input.select()
|
||||
if (document.execCommand('copy'))
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(input)
|
||||
}
|
||||
|
||||
export function utcToShanghaiTime(utcTime: string, format: string): string {
|
||||
const date = new Date(utcTime)
|
||||
const shanghaiTime = date.getTime() + 8 * 60 * 60 * 1000
|
||||
const shanghaiDate = new Date(shanghaiTime)
|
||||
|
||||
let result = format.replace('YYYY', shanghaiDate.getFullYear().toString())
|
||||
result = result.replace('MM', (`0${shanghaiDate.getMonth() + 1}`).slice(-2))
|
||||
result = result.replace('DD', (`0${shanghaiDate.getDate()}`).slice(-2))
|
||||
result = result.replace('hh', (`0${shanghaiDate.getHours()}`).slice(-2))
|
||||
result = result.replace('mm', (`0${shanghaiDate.getMinutes()}`).slice(-2))
|
||||
result = result.replace('ss', (`0${shanghaiDate.getSeconds()}`).slice(-2))
|
||||
|
||||
return result
|
||||
}
|
||||
12
chat/src/utils/functions/date.ts
Normal file
12
chat/src/utils/functions/date.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export function formatDate(dateString: string, format: string): string {
|
||||
const date = new Date(dateString)
|
||||
const year = date.getFullYear()
|
||||
const month = (`0${date.getMonth() + 1}`).slice(-2)
|
||||
const day = (`0${date.getDate()}`).slice(-2)
|
||||
|
||||
format = format.replace('yyyy', year.toString())
|
||||
format = format.replace('MM', month)
|
||||
format = format.replace('dd', day)
|
||||
|
||||
return format
|
||||
}
|
||||
18
chat/src/utils/functions/debounce.ts
Normal file
18
chat/src/utils/functions/debounce.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
type CallbackFunc<T extends unknown[]> = (...args: T) => void
|
||||
|
||||
export function debounce<T extends unknown[]>(
|
||||
func: CallbackFunc<T>,
|
||||
wait: number,
|
||||
): (...args: T) => void {
|
||||
let timeoutId: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
return (...args: T) => {
|
||||
const later = () => {
|
||||
clearTimeout(timeoutId)
|
||||
func(...args)
|
||||
}
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = setTimeout(later, wait)
|
||||
}
|
||||
}
|
||||
7
chat/src/utils/functions/index.ts
Normal file
7
chat/src/utils/functions/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function getCurrentDate() {
|
||||
const date = new Date()
|
||||
const day = date.getDate()
|
||||
const month = date.getMonth() + 1
|
||||
const year = date.getFullYear()
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
17
chat/src/utils/functions/throttle.ts
Normal file
17
chat/src/utils/functions/throttle.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
type ThrottledFunction<T extends any[]> = (...args: T) => void
|
||||
|
||||
export function throttle<T extends any[]>(func: ThrottledFunction<T>, delay: number): ThrottledFunction<T> {
|
||||
let timeoutId: ReturnType<typeof setTimeout> | null
|
||||
let lastArgs: T
|
||||
|
||||
return function throttled(...args: T) {
|
||||
lastArgs = args
|
||||
|
||||
if (!timeoutId) {
|
||||
timeoutId = setTimeout(() => {
|
||||
func.apply(this, lastArgs)
|
||||
timeoutId = null
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
55
chat/src/utils/is/index.ts
Normal file
55
chat/src/utils/is/index.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
export function isNumber<T extends number>(value: T | unknown): value is number {
|
||||
return Object.prototype.toString.call(value) === '[object Number]'
|
||||
}
|
||||
|
||||
export function isString<T extends string>(value: T | unknown): value is string {
|
||||
return Object.prototype.toString.call(value) === '[object String]'
|
||||
}
|
||||
|
||||
export function isBoolean<T extends boolean>(value: T | unknown): value is boolean {
|
||||
return Object.prototype.toString.call(value) === '[object Boolean]'
|
||||
}
|
||||
|
||||
export function isNull<T extends null>(value: T | unknown): value is null {
|
||||
return Object.prototype.toString.call(value) === '[object Null]'
|
||||
}
|
||||
|
||||
export function isUndefined<T extends undefined>(value: T | unknown): value is undefined {
|
||||
return Object.prototype.toString.call(value) === '[object Undefined]'
|
||||
}
|
||||
|
||||
export function isObject<T extends object>(value: T | unknown): value is object {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
}
|
||||
|
||||
export function isArray<T extends any[]>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object Array]'
|
||||
}
|
||||
|
||||
export function isFunction<T extends (...args: any[]) => any | void | never>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object Function]'
|
||||
}
|
||||
|
||||
export function isDate<T extends Date>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object Date]'
|
||||
}
|
||||
|
||||
export function isRegExp<T extends RegExp>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object RegExp]'
|
||||
}
|
||||
|
||||
export function isPromise<T extends Promise<any>>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object Promise]'
|
||||
}
|
||||
|
||||
export function isSet<T extends Set<any>>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object Set]'
|
||||
}
|
||||
|
||||
export function isMap<T extends Map<any, any>>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object Map]'
|
||||
}
|
||||
|
||||
export function isFile<T extends File>(value: T | unknown): value is T {
|
||||
return Object.prototype.toString.call(value) === '[object File]'
|
||||
}
|
||||
59
chat/src/utils/motion/index.ts
Normal file
59
chat/src/utils/motion/index.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { h, defineComponent, withDirectives, resolveDirective } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Motion",
|
||||
props: {
|
||||
delay:{
|
||||
type: Number,
|
||||
default: 50
|
||||
},
|
||||
y:{
|
||||
type: Number,
|
||||
default: 50
|
||||
},
|
||||
opacity:{
|
||||
type: Number,
|
||||
default: 0.5
|
||||
},
|
||||
scale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
duration:{
|
||||
type: Number,
|
||||
default: 350
|
||||
}
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
// 使用 setup 函数的参数来访问 props 和 slots
|
||||
return () => {
|
||||
const motion = resolveDirective("motion");
|
||||
return withDirectives(
|
||||
h(
|
||||
"div",
|
||||
{},
|
||||
{
|
||||
default: () => [slots.default?.()]
|
||||
}
|
||||
),
|
||||
[
|
||||
[
|
||||
motion,
|
||||
{
|
||||
initial: { opacity: props.opacity, y: props.y, scale: props.scale },
|
||||
enter: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
transition : {
|
||||
delay: props.delay,
|
||||
duration: props.duration
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
);
|
||||
};
|
||||
}
|
||||
});
|
||||
37
chat/src/utils/request/axios.ts
Normal file
37
chat/src/utils/request/axios.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import axios, { type AxiosResponse } from 'axios'
|
||||
import { useAuthStore, useGlobalStore } from '@/store'
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_GLOB_API_URL,
|
||||
timeout: 2400 * 1000,
|
||||
})
|
||||
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = useAuthStore().token
|
||||
const fingerprint = useGlobalStore()?.fingerprint
|
||||
const currentDomain = window.location.origin;
|
||||
config.headers['X-Website-Domain'] = currentDomain;
|
||||
fingerprint && (config.headers.Fingerprint = fingerprint)
|
||||
if (token)
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error.response)
|
||||
},
|
||||
)
|
||||
|
||||
service.interceptors.response.use(
|
||||
(response: AxiosResponse): AxiosResponse => {
|
||||
if ([200, 201].includes(response.status))
|
||||
return response
|
||||
|
||||
throw new Error(response.status.toString())
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
export default service
|
||||
113
chat/src/utils/request/index.ts
Normal file
113
chat/src/utils/request/index.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { AxiosProgressEvent, AxiosResponse, GenericAbortSignal } from 'axios'
|
||||
import request from './axios'
|
||||
import { useAuthStore } from '@/store'
|
||||
|
||||
export interface HttpOption {
|
||||
url: string
|
||||
data?: any
|
||||
method?: string
|
||||
headers?: any
|
||||
onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void
|
||||
signal?: GenericAbortSignal
|
||||
beforeRequest?: () => void
|
||||
afterRequest?: () => void
|
||||
}
|
||||
|
||||
export interface Response<T = any> {
|
||||
data: T
|
||||
message: string | null
|
||||
status: string
|
||||
}
|
||||
|
||||
let last401ErrorTimestamp = 0
|
||||
const homePagePath = ['/chatlog/chatList', '/group/query']
|
||||
|
||||
function hasWhitePath(path: string) {
|
||||
if (!path)
|
||||
return false
|
||||
return homePagePath.some(item => path.includes(item))
|
||||
}
|
||||
|
||||
function http<T = any>(
|
||||
{ url, data, method, headers, onDownloadProgress, signal, beforeRequest, afterRequest }: HttpOption,
|
||||
) {
|
||||
const successHandler = (res: AxiosResponse<Response<T>>) => {
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const { code } = res.data
|
||||
|
||||
if ((code >= 200 && code < 300) || !code)
|
||||
return res.data
|
||||
|
||||
if (code === 401) {
|
||||
authStore.removeToken()
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
return Promise.reject(res.data)
|
||||
}
|
||||
|
||||
const failHandler = (error: Response<Error>) => {
|
||||
const authStore = useAuthStore()
|
||||
let data = ''
|
||||
error.response?.data && (data = error.response.data)
|
||||
afterRequest?.()
|
||||
const status = error?.response?.status
|
||||
|
||||
if (status === 401) {
|
||||
authStore.removeToken()
|
||||
if (!hasWhitePath(error?.request?.responseURL)) {
|
||||
authStore.loadInit && authStore.setLoginDialog(true)
|
||||
const message = error.response.data?.message || '请先登录后再进行使用!'
|
||||
Date.now() - last401ErrorTimestamp > 3000 && window.$message.error(message)
|
||||
}
|
||||
last401ErrorTimestamp = Date.now()
|
||||
}
|
||||
else {
|
||||
if (data && !data?.success)
|
||||
window.$message.error(data?.message || '请求接口错误!')
|
||||
}
|
||||
throw new Error(error.response?.data?.message || error || 'Error')
|
||||
}
|
||||
|
||||
beforeRequest?.()
|
||||
|
||||
method = method || 'GET'
|
||||
|
||||
const params = Object.assign(typeof data === 'function' ? data() : data ?? {}, {})
|
||||
|
||||
return method === 'GET'
|
||||
? request.get(url, { params, signal, onDownloadProgress }).then(successHandler, failHandler)
|
||||
: request.post(url, params, { headers, signal, onDownloadProgress }).then(successHandler, failHandler)
|
||||
}
|
||||
|
||||
export function get<T = any>(
|
||||
{ url, data, method = 'GET', onDownloadProgress, signal, beforeRequest, afterRequest }: HttpOption,
|
||||
): Promise<Response<T>> {
|
||||
return http<T>({
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
onDownloadProgress,
|
||||
signal,
|
||||
beforeRequest,
|
||||
afterRequest,
|
||||
})
|
||||
}
|
||||
|
||||
export function post<T = any>(
|
||||
{ url, data, method = 'POST', headers, onDownloadProgress, signal, beforeRequest, afterRequest }: HttpOption,
|
||||
): Promise<Response<T>> {
|
||||
return http<T>({
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
headers,
|
||||
onDownloadProgress,
|
||||
signal,
|
||||
beforeRequest,
|
||||
afterRequest,
|
||||
})
|
||||
}
|
||||
|
||||
export default post
|
||||
1
chat/src/utils/storage/index.ts
Normal file
1
chat/src/utils/storage/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './local'
|
||||
70
chat/src/utils/storage/local.ts
Normal file
70
chat/src/utils/storage/local.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { deCrypto, enCrypto } from '../crypto'
|
||||
|
||||
interface StorageData<T = any> {
|
||||
data: T
|
||||
expire: number | null
|
||||
}
|
||||
|
||||
export function createLocalStorage(options?: { expire?: number | null; crypto?: boolean }) {
|
||||
const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7
|
||||
|
||||
const { expire, crypto } = Object.assign(
|
||||
{
|
||||
expire: DEFAULT_CACHE_TIME,
|
||||
crypto: true,
|
||||
},
|
||||
options,
|
||||
)
|
||||
|
||||
function set<T = any>(key: string, data: T) {
|
||||
const storageData: StorageData<T> = {
|
||||
data,
|
||||
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
|
||||
}
|
||||
|
||||
const json = crypto ? enCrypto(storageData) : JSON.stringify(storageData)
|
||||
window.localStorage.setItem(key, json)
|
||||
}
|
||||
|
||||
function get(key: string) {
|
||||
const json = window.localStorage.getItem(key)
|
||||
if (json) {
|
||||
let storageData: StorageData | null = null
|
||||
|
||||
try {
|
||||
storageData = crypto ? deCrypto(json) : JSON.parse(json)
|
||||
}
|
||||
catch {
|
||||
// Prevent failure
|
||||
}
|
||||
|
||||
if (storageData) {
|
||||
const { data, expire } = storageData
|
||||
if (expire === null || expire >= Date.now())
|
||||
return data
|
||||
}
|
||||
|
||||
remove(key)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function remove(key: string) {
|
||||
window.localStorage.removeItem(key)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
window.localStorage.clear()
|
||||
}
|
||||
|
||||
return {
|
||||
set,
|
||||
get,
|
||||
remove,
|
||||
clear,
|
||||
}
|
||||
}
|
||||
|
||||
export const ls = createLocalStorage()
|
||||
|
||||
export const ss = createLocalStorage({ expire: null, crypto: false })
|
||||
Reference in New Issue
Block a user