v1.0.0
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
import moment from 'moment'
|
||||
import { h } from 'vue'
|
||||
import type { NotificationReactive } from 'naive-ui'
|
||||
import { NButton, createDiscreteApi } from 'naive-ui'
|
||||
import { useNoticeStore, useUserStore } from '@/store'
|
||||
import { getInfo as getUserInfo } from '@/api/system/user'
|
||||
import { getListByDisplayType as getListByDisplayTypeApi } from '@/api/notice'
|
||||
|
||||
const noticeStore = useNoticeStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const { notification } = createDiscreteApi(['notification'])
|
||||
|
||||
/**
|
||||
* 生成指定时间格式
|
||||
* @param format 时间格式 默认:'YYYY-MM-DD HH:mm:ss'
|
||||
* @returns string
|
||||
*/
|
||||
export function buildTimeString(format?: string): string {
|
||||
if (!format)
|
||||
format = 'YYYY-MM-DD HH:mm:ss'
|
||||
|
||||
return moment().format(format)
|
||||
}
|
||||
|
||||
export function timeFormat(timeString?: string) {
|
||||
return moment(timeString).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新的公告
|
||||
* @param timeString
|
||||
*/
|
||||
export function noticeCreate(info: Notice.NoticeInfo) {
|
||||
const option: any = {
|
||||
title: info.title,
|
||||
content: info.content,
|
||||
meta: info.createTime ? timeFormat(info.createTime) : '',
|
||||
}
|
||||
|
||||
const btns: any = []
|
||||
|
||||
let n: NotificationReactive
|
||||
// 链接按钮
|
||||
if (info.url !== '') {
|
||||
btns.push(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
type: 'info',
|
||||
onClick: () => {
|
||||
window.open(info.url, '_blank')
|
||||
n.destroy()
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '打开链接',
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
if (info.oneRead === 1) {
|
||||
btns.push(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
text: true,
|
||||
type: 'primary',
|
||||
style: { marginLeft: '20px' },
|
||||
onClick: () => {
|
||||
if (info.id) {
|
||||
if (info.isLogin === 1 && userStore.userInfo.username) {
|
||||
noticeStore.setReadByUsername(userStore.userInfo.username, info.id)
|
||||
console.log('设置用户已读', info.id)
|
||||
}
|
||||
else {
|
||||
noticeStore.setReadByGlobal(info.id)
|
||||
console.log('设置全局已读', info.id)
|
||||
}
|
||||
}
|
||||
n.destroy()
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => '不再提醒',
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
option.action = () => btns
|
||||
n = notification.create(option)
|
||||
}
|
||||
|
||||
export function setTitle(titile: string) {
|
||||
document.title = titile
|
||||
}
|
||||
|
||||
export function getTitle(titile: string) {
|
||||
document.title = titile
|
||||
}
|
||||
|
||||
//
|
||||
export async function updateLocalUserInfo() {
|
||||
const { data } = await getUserInfo<User.Info>()
|
||||
|
||||
userStore.updateUserInfo({ headImage: data.headImage, name: data.name })
|
||||
}
|
||||
|
||||
export async function getNotice(displayType: number | number[]) {
|
||||
let param: number[]
|
||||
if (typeof displayType === 'number')
|
||||
param = [displayType]
|
||||
else
|
||||
param = displayType
|
||||
|
||||
const { data } = await getListByDisplayTypeApi<Common.ListResponse<Notice.NoticeInfo[]>>(param)
|
||||
|
||||
for (let i = 0; i < data.list.length; i++) {
|
||||
const element = data.list[i]
|
||||
if (element.id && !noticeStore.getReadByNoticeId(element.id, userStore.userInfo.username))
|
||||
noticeCreate(element)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取随机码
|
||||
* @param {number} size
|
||||
* @param {array} seed ["a","b"m"c]
|
||||
* @return {string}
|
||||
*/
|
||||
export function randomCode(size: number, seed?: Array<string>) {
|
||||
seed = seed || ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'Q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'2', '3', '4', '5', '6', '7', '8', '9',
|
||||
]// 数组
|
||||
const seedlength = seed.length// 数组长度
|
||||
let createPassword = ''
|
||||
for (let i = 0; i < size; i++) {
|
||||
const j = Math.floor(Math.random() * seedlength)
|
||||
createPassword += seed[j]
|
||||
}
|
||||
return createPassword
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 转义 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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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}`
|
||||
}
|
||||
@@ -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]'
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import axios, { type AxiosResponse } from 'axios'
|
||||
import { useAuthStore } from '@/store'
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_GLOB_API_URL,
|
||||
})
|
||||
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = useAuthStore().token
|
||||
if (token)
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error.response)
|
||||
},
|
||||
)
|
||||
|
||||
service.interceptors.response.use(
|
||||
(response: AxiosResponse): AxiosResponse => {
|
||||
if (response.status === 200)
|
||||
return response
|
||||
|
||||
throw new Error(response.status.toString())
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
export default service
|
||||
@@ -0,0 +1,120 @@
|
||||
import type { AxiosProgressEvent, AxiosResponse, GenericAbortSignal } from 'axios'
|
||||
import { createDiscreteApi } from 'naive-ui'
|
||||
import request from './axios'
|
||||
import { useAuthStore } from '@/store'
|
||||
import { router } from '@/router'
|
||||
|
||||
const { message } = createDiscreteApi(['message'])
|
||||
|
||||
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
|
||||
msg: string
|
||||
code: number
|
||||
}
|
||||
|
||||
function http<T = any>(
|
||||
{ url, data, method, headers, onDownloadProgress, signal, beforeRequest, afterRequest }: HttpOption,
|
||||
) {
|
||||
const authStore = useAuthStore()
|
||||
const successHandler = (res: AxiosResponse<Response<T>>) => {
|
||||
if (res.data.code === 0 || typeof res.data === 'string')
|
||||
return res.data
|
||||
|
||||
if (res.data.code === 1001) {
|
||||
message.warning('登录过期,请重新登录')
|
||||
router.push({ path: '/login' })
|
||||
authStore.removeToken()
|
||||
return res.data
|
||||
}
|
||||
|
||||
if (res.data.code === 1000) {
|
||||
router.push({ path: '/login' })
|
||||
authStore.removeToken()
|
||||
return res.data
|
||||
}
|
||||
|
||||
if (res.data.code === 1005) {
|
||||
message.warning(res.data.msg)
|
||||
return res.data
|
||||
}
|
||||
|
||||
if (res.data.code === -1) {
|
||||
message.warning(res.data.msg)
|
||||
// router.push({ path: '/login' })
|
||||
// authStore.removeToken()
|
||||
return res.data
|
||||
}
|
||||
|
||||
// 验证码相关错误
|
||||
if (res.data.code > 1100 && res.data.code < 1200)
|
||||
return res.data
|
||||
|
||||
return Promise.reject(res.data)
|
||||
}
|
||||
|
||||
const failHandler = (error: Response<Error>) => {
|
||||
afterRequest?.()
|
||||
// message.error('网络错误,请稍后重试', {
|
||||
// duration: 50000,
|
||||
// closable: true,
|
||||
// })
|
||||
throw new Error(error?.msg || 'Error')
|
||||
}
|
||||
|
||||
beforeRequest?.()
|
||||
|
||||
method = method || 'GET'
|
||||
|
||||
const params = Object.assign(typeof data === 'function' ? data() : data ?? {}, {})
|
||||
if (!headers)
|
||||
headers = {}
|
||||
|
||||
headers.token = authStore.token
|
||||
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
|
||||
@@ -0,0 +1 @@
|
||||
export * from './local'
|
||||
@@ -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