first
This commit is contained in:
147
src/utils/common.ts
Normal file
147
src/utils/common.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import type { App } from 'vue'
|
||||
import { adminBaseRoutePath } from '@/router/static'
|
||||
import router from '@/router/index'
|
||||
import { trimStart } from 'lodash-es'
|
||||
import * as elIcons from '@element-plus/icons-vue'
|
||||
import Icon from '@/components/icon/index.vue'
|
||||
|
||||
export function registerIcons(app: App) {
|
||||
/*
|
||||
* 全局注册 Icon
|
||||
* 使用方式: <Icon name="name" size="size" color="color" />
|
||||
* 详见<待完善>
|
||||
*/
|
||||
app.component('Icon', Icon)
|
||||
|
||||
/*
|
||||
* 全局注册element Plus的icon
|
||||
*/
|
||||
const icons = elIcons as any
|
||||
for (const i in icons) {
|
||||
app.component(`el-icon-${icons[i].name}`, icons[i])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否在后台应用内
|
||||
* @param path 不传递则通过当前路由 path 检查
|
||||
*/
|
||||
export const isAdminApp = (path = '') => {
|
||||
const regex = new RegExp(`^${adminBaseRoutePath}`)
|
||||
if (path) {
|
||||
return regex.test(path)
|
||||
}
|
||||
if (regex.test(getCurrentRoutePath())) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由 path
|
||||
*/
|
||||
export const getCurrentRoutePath = () => {
|
||||
let path = router.currentRoute.value.path
|
||||
if (path == '/') path = trimStart(window.location.hash, '#')
|
||||
if (path.indexOf('?') !== -1) path = path.replace(/\?.*/, '')
|
||||
return path
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源完整地址
|
||||
* @param relativeUrl 资源相对地址
|
||||
* @param domain 指定域名
|
||||
*/
|
||||
export const fullUrl = (relativeUrl: string, domain = '') => {
|
||||
return domain + '/api/system-boot/image/toStream?bgImage=' + relativeUrl
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是外部链接
|
||||
* @param path
|
||||
*/
|
||||
export function isExternal(path: string): boolean {
|
||||
return /^(https?|ftp|mailto|tel):/.test(path)
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局防抖
|
||||
* 与 _.debounce 不同的是,间隔期间如果再次传递不同的函数,两个函数也只会执行一次
|
||||
* @param fn 执行函数
|
||||
* @param ms 间隔毫秒数
|
||||
*/
|
||||
export const debounce = (fn: Function, ms: number) => {
|
||||
return (...args: any[]) => {
|
||||
if (window.lazy) {
|
||||
clearTimeout(window.lazy)
|
||||
}
|
||||
window.lazy = window.setTimeout(() => {
|
||||
fn(...args)
|
||||
}, ms)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串补位
|
||||
*/
|
||||
const padStart = (str: string, maxLength: number, fillString = ' ') => {
|
||||
if (str.length >= maxLength) return str
|
||||
|
||||
const fillLength = maxLength - str.length
|
||||
let times = Math.ceil(fillLength / fillString.length)
|
||||
while ((times >>= 1)) {
|
||||
fillString += fillString
|
||||
if (times === 1) {
|
||||
fillString += fillString
|
||||
}
|
||||
}
|
||||
return fillString.slice(0, fillLength) + str
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间戳
|
||||
* @param dateTime 时间戳
|
||||
* @param fmt 格式化方式,默认:yyyy-mm-dd hh:MM:ss
|
||||
*/
|
||||
export const timeFormat = (dateTime: string | number | null = null, fmt = 'yyyy-mm-dd hh:MM:ss') => {
|
||||
if (dateTime == 'none') return '-'
|
||||
if (!dateTime) dateTime = Number(new Date())
|
||||
if (dateTime.toString().length === 10) {
|
||||
dateTime = +dateTime * 1000
|
||||
}
|
||||
|
||||
const date = new Date(dateTime)
|
||||
let ret
|
||||
const opt: anyObj = {
|
||||
'y+': date.getFullYear().toString(), // 年
|
||||
'm+': (date.getMonth() + 1).toString(), // 月
|
||||
'd+': date.getDate().toString(), // 日
|
||||
'h+': date.getHours().toString(), // 时
|
||||
'M+': date.getMinutes().toString(), // 分
|
||||
's+': date.getSeconds().toString() // 秒
|
||||
}
|
||||
for (const k in opt) {
|
||||
ret = new RegExp('(' + k + ')').exec(fmt)
|
||||
if (ret) {
|
||||
fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : padStart(opt[k], ret[1].length, '0'))
|
||||
}
|
||||
}
|
||||
return fmt
|
||||
}
|
||||
|
||||
/**
|
||||
* el-form 密码正则校验 密码需要包含特殊字符字母数字,长度为8-16
|
||||
*/
|
||||
export const validatePwd = (rule: any, value: string, callback: any) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入密码'))
|
||||
} else {
|
||||
const reg = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@#$%^&+=!])(?=.*[a-zA-Z0-9])[A-Za-z\d@#$%^&+=!]{8,16}$/
|
||||
if (!reg.test(value)) {
|
||||
callback(new Error('密码需要包含特殊字符字母数字,长度为8-16'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
33
src/utils/horizontalScroll.ts
Normal file
33
src/utils/horizontalScroll.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 横向滚动条
|
||||
*/
|
||||
export default class horizontalScroll {
|
||||
private el: HTMLElement
|
||||
|
||||
constructor(nativeElement: HTMLElement) {
|
||||
this.el = nativeElement
|
||||
this.handleWheelEvent()
|
||||
}
|
||||
|
||||
handleWheelEvent() {
|
||||
let wheel = ''
|
||||
|
||||
if ('onmousewheel' in this.el) {
|
||||
wheel = 'mousewheel'
|
||||
} else if ('onwheel' in this.el) {
|
||||
wheel = 'wheel'
|
||||
} else if ('attachEvent' in window) {
|
||||
wheel = 'onmousewheel'
|
||||
} else {
|
||||
wheel = 'DOMMouseScroll'
|
||||
}
|
||||
this.el['addEventListener'](wheel, this.scroll, { passive: true })
|
||||
}
|
||||
|
||||
scroll = (event: any) => {
|
||||
if (this.el.clientWidth >= this.el.scrollWidth) {
|
||||
return
|
||||
}
|
||||
this.el.scrollLeft += event.deltaY ? event.deltaY : event.detail && event.detail !== 0 ? event.detail : -event.wheelDelta
|
||||
}
|
||||
}
|
||||
85
src/utils/iconfont.ts
Normal file
85
src/utils/iconfont.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { nextTick } from 'vue'
|
||||
import * as elIcons from '@element-plus/icons-vue'
|
||||
import { getUrl } from '@/utils/request'
|
||||
|
||||
/*
|
||||
* 获取element plus 自带的图标
|
||||
*/
|
||||
export function getElementPlusIconfontNames() {
|
||||
return new Promise<string[]>((resolve, reject) => {
|
||||
nextTick(() => {
|
||||
const iconfonts = []
|
||||
const icons = elIcons as any
|
||||
for (const i in icons) {
|
||||
iconfonts.push(`el-icon-${icons[i].name}`)
|
||||
}
|
||||
if (iconfonts.length > 0) {
|
||||
resolve(iconfonts)
|
||||
} else {
|
||||
reject('No ElementPlus Icons')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取Vite开发服务/编译后的样式表内容
|
||||
* @param devID style 标签的 viteDevId,只开发服务有
|
||||
*/
|
||||
function getStylesFromVite(devId: string) {
|
||||
const sheets = []
|
||||
const styles: StyleSheetList = document.styleSheets
|
||||
if (import.meta.env.MODE == 'production') {
|
||||
const url = getUrl()
|
||||
for (const key in styles) {
|
||||
if (styles[key].href && styles[key].href?.indexOf(url) === 0) {
|
||||
sheets.push(styles[key])
|
||||
}
|
||||
}
|
||||
return sheets
|
||||
}
|
||||
for (const key in styles) {
|
||||
const ownerNode = styles[key].ownerNode as HTMLMapElement
|
||||
if (ownerNode && ownerNode.dataset?.viteDevId && ownerNode.dataset.viteDevId!.indexOf(devId) > -1) {
|
||||
sheets.push(styles[key])
|
||||
}
|
||||
}
|
||||
return sheets
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 获取 Awesome-Iconfont 的 name 列表
|
||||
*/
|
||||
export function getAwesomeIconfontNames() {
|
||||
return new Promise<string[]>((resolve, reject) => {
|
||||
nextTick(() => {
|
||||
const iconfonts = []
|
||||
const sheets = getStylesFromVite('all.css')
|
||||
console.log(sheets)
|
||||
for (const key in sheets) {
|
||||
const rules: any = sheets[key].cssRules
|
||||
for (const k in rules) {
|
||||
if (!rules[k].selectorText || rules[k].selectorText.indexOf('.fa-') !== 0) {
|
||||
continue
|
||||
}
|
||||
if (/^\.fa-(.*)::before$/g.test(rules[k].selectorText)) {
|
||||
if (rules[k].selectorText.indexOf(', ') > -1) {
|
||||
const iconNames = rules[k].selectorText.split(', ')
|
||||
iconfonts.push(`${iconNames[0].substring(1, iconNames[0].length).replace(/\:\:before/gi, '')}`)
|
||||
} else {
|
||||
iconfonts.push(`${rules[k].selectorText.substring(1, rules[k].selectorText.length).replace(/\:\:before/gi, '')}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iconfonts.length > 0) {
|
||||
resolve(iconfonts)
|
||||
} else {
|
||||
reject('没有样式表')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
41
src/utils/layout.ts
Normal file
41
src/utils/layout.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
import { useConfig } from '@/stores/config'
|
||||
|
||||
/**
|
||||
* main高度
|
||||
* @param extra main高度额外减去的px数,可以实现隐藏原有的滚动条
|
||||
* @returns CSSProperties
|
||||
*/
|
||||
export function mainHeight(extra = 0,divided =1): CSSProperties {
|
||||
let height = extra
|
||||
const adminLayoutMainExtraHeight: anyObj = {
|
||||
Default: 60,
|
||||
Classic: 105,
|
||||
Streamline: 60
|
||||
}
|
||||
const config = useConfig()
|
||||
const navTabs = useNavTabs()
|
||||
if (!navTabs.state.tabFullScreen) {
|
||||
height += adminLayoutMainExtraHeight[config.layout.layoutMode]
|
||||
}
|
||||
|
||||
return {
|
||||
height: 'calc((100vh - ' + height.toString() + 'px) / '+ divided+')'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置导航栏宽度
|
||||
* @returns
|
||||
*/
|
||||
export function setNavTabsWidth() {
|
||||
const navTabs = document.querySelector('.nav-tabs') as HTMLElement
|
||||
if (!navTabs) {
|
||||
return
|
||||
}
|
||||
const navBar = document.querySelector('.nav-bar') as HTMLElement
|
||||
const navMenus = document.querySelector('.nav-menus') as HTMLElement
|
||||
const minWidth = navBar.offsetWidth - (navMenus.offsetWidth + 20)
|
||||
// navTabs.style.width = minWidth.toString() + 'px'
|
||||
}
|
||||
34
src/utils/loading.ts
Normal file
34
src/utils/loading.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { nextTick } from 'vue'
|
||||
import '@/styles/loading.scss'
|
||||
|
||||
export const loading = {
|
||||
show: () => {
|
||||
const bodys: Element = document.body
|
||||
const div = document.createElement('div')
|
||||
div.className = 'block-loading'
|
||||
div.innerHTML = `
|
||||
<div class="block-loading-box">
|
||||
<div class="block-loading-box-warp">
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
<div class="block-loading-box-item"></div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
bodys.insertBefore(div, bodys.childNodes[0])
|
||||
},
|
||||
hide: () => {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const el = document.querySelector('.block-loading')
|
||||
el && el.parentNode?.removeChild(el)
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
}
|
||||
104
src/utils/pageBubble.ts
Normal file
104
src/utils/pageBubble.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
// 页面气泡效果
|
||||
|
||||
const bubble: {
|
||||
width: number
|
||||
height: number
|
||||
bubbleEl: any
|
||||
canvas: any
|
||||
ctx: any
|
||||
circles: any[]
|
||||
animate: boolean
|
||||
requestId: any
|
||||
} = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
bubbleEl: null,
|
||||
canvas: null,
|
||||
ctx: {},
|
||||
circles: [],
|
||||
animate: true,
|
||||
requestId: null,
|
||||
}
|
||||
|
||||
export const init = function (): void {
|
||||
bubble.width = window.innerWidth
|
||||
bubble.height = window.innerHeight
|
||||
|
||||
bubble.bubbleEl = document.getElementById('bubble')
|
||||
bubble.bubbleEl.style.height = bubble.height + 'px'
|
||||
|
||||
bubble.canvas = document.getElementById('bubble-canvas')
|
||||
bubble.canvas.width = bubble.width
|
||||
bubble.canvas.height = bubble.height
|
||||
bubble.ctx = bubble.canvas.getContext('2d')
|
||||
|
||||
// create particles
|
||||
bubble.circles = []
|
||||
for (let x = 0; x < bubble.width * 0.5; x++) {
|
||||
const c = new Circle()
|
||||
bubble.circles.push(c)
|
||||
}
|
||||
animate()
|
||||
addListeners()
|
||||
}
|
||||
|
||||
function scrollCheck() {
|
||||
bubble.animate = document.body.scrollTop > bubble.height ? false : true
|
||||
}
|
||||
|
||||
function resize() {
|
||||
bubble.width = window.innerWidth
|
||||
bubble.height = window.innerHeight
|
||||
bubble.bubbleEl.style.height = bubble.height + 'px'
|
||||
bubble.canvas.width = bubble.width
|
||||
bubble.canvas.height = bubble.height
|
||||
}
|
||||
|
||||
function animate() {
|
||||
if (bubble.animate) {
|
||||
bubble.ctx.clearRect(0, 0, bubble.width, bubble.height)
|
||||
for (const i in bubble.circles) {
|
||||
bubble.circles[i].draw()
|
||||
}
|
||||
}
|
||||
bubble.requestId = requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
class Circle {
|
||||
pos: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
alpha: number
|
||||
scale: number
|
||||
velocity: number
|
||||
draw: () => void
|
||||
constructor() {
|
||||
this.pos = {
|
||||
x: Math.random() * bubble.width,
|
||||
y: bubble.height + Math.random() * 100,
|
||||
}
|
||||
this.alpha = 0.1 + Math.random() * 0.3
|
||||
this.scale = 0.1 + Math.random() * 0.3
|
||||
this.velocity = Math.random()
|
||||
this.draw = function () {
|
||||
this.pos.y -= this.velocity
|
||||
this.alpha -= 0.0005
|
||||
bubble.ctx.beginPath()
|
||||
bubble.ctx.arc(this.pos.x, this.pos.y, this.scale * 10, 0, 2 * Math.PI, false)
|
||||
bubble.ctx.fillStyle = 'rgba(255,255,255,' + this.alpha + ')'
|
||||
bubble.ctx.fill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addListeners() {
|
||||
window.addEventListener('scroll', scrollCheck)
|
||||
window.addEventListener('resize', resize)
|
||||
}
|
||||
|
||||
export function removeListeners() {
|
||||
window.removeEventListener('scroll', scrollCheck)
|
||||
window.removeEventListener('resize', resize)
|
||||
cancelAnimationFrame(bubble.requestId)
|
||||
}
|
||||
22
src/utils/pageShade.ts
Normal file
22
src/utils/pageShade.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
|
||||
/*
|
||||
* 显示页面遮罩
|
||||
*/
|
||||
export const showShade = function (className = 'shade', closeCallBack: Function): void {
|
||||
const containerEl = document.querySelector('.layout-container') as HTMLElement
|
||||
const shadeDiv = document.createElement('div')
|
||||
shadeDiv.setAttribute('class', 'ba-layout-shade ' + className)
|
||||
containerEl.appendChild(shadeDiv)
|
||||
useEventListener(shadeDiv, 'click', () => closeShade(closeCallBack))
|
||||
}
|
||||
|
||||
/*
|
||||
* 隐藏页面遮罩
|
||||
*/
|
||||
export const closeShade = function (closeCallBack: Function = () => {}): void {
|
||||
const shadeEl = document.querySelector('.ba-layout-shade') as HTMLElement
|
||||
shadeEl && shadeEl.remove()
|
||||
|
||||
closeCallBack()
|
||||
}
|
||||
57
src/utils/random.ts
Normal file
57
src/utils/random.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
const hexList: string[] = []
|
||||
for (let i = 0; i <= 15; i++) {
|
||||
hexList[i] = i.toString(16)
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机数
|
||||
* @param min 最小值
|
||||
* @param max 最大值
|
||||
* @returns 生成的随机数
|
||||
*/
|
||||
export function randomNum(min: number, max: number) {
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
return parseInt((Math.random() * min + 1).toString(), 10)
|
||||
break
|
||||
case 2:
|
||||
return parseInt((Math.random() * (max - min + 1) + min).toString(), 10)
|
||||
break
|
||||
default:
|
||||
return 0
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成全球唯一标识
|
||||
* @returns uuid
|
||||
*/
|
||||
export function uuid(): string {
|
||||
let uuid = ''
|
||||
for (let i = 1; i <= 36; i++) {
|
||||
if (i === 9 || i === 14 || i === 19 || i === 24) {
|
||||
uuid += '-'
|
||||
} else if (i === 15) {
|
||||
uuid += 4
|
||||
} else if (i === 20) {
|
||||
uuid += hexList[(Math.random() * 4) | 8]
|
||||
} else {
|
||||
uuid += hexList[(Math.random() * 16) | 0]
|
||||
}
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一标识
|
||||
* @param prefix 前缀
|
||||
* @returns 唯一标识
|
||||
*/
|
||||
export function shortUuid(prefix = ''): string {
|
||||
const time = Date.now()
|
||||
const random = Math.floor(Math.random() * 1000000000)
|
||||
if (!window.unique) window.unique = 0
|
||||
window.unique++
|
||||
return prefix + '_' + random + window.unique + String(time)
|
||||
}
|
||||
240
src/utils/request.ts
Normal file
240
src/utils/request.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import type { AxiosRequestConfig, Method } from 'axios'
|
||||
import axios from 'axios'
|
||||
import { ElLoading, ElNotification, type LoadingOptions } from 'element-plus'
|
||||
import { refreshToken } from '@/api/user-boot/user'
|
||||
import router from '@/router/index'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
|
||||
window.requests = []
|
||||
window.tokenRefreshing = false
|
||||
const pendingMap = new Map()
|
||||
const loadingInstance: LoadingInstance = {
|
||||
target: null,
|
||||
count: 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据运行环境获取基础请求URL
|
||||
*/
|
||||
export const getUrl = (): string => {
|
||||
return '/api'
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建`Axios`
|
||||
* 默认开启`reductDataFormat(简洁响应)`,返回类型为`ApiPromise`
|
||||
* 关闭`reductDataFormat`,返回类型则为`AxiosPromise`
|
||||
*/
|
||||
function createAxios<Data = any, T = ApiPromise<Data>>(
|
||||
axiosConfig: AxiosRequestConfig,
|
||||
options: Options = {},
|
||||
loading: LoadingOptions = {}
|
||||
): T {
|
||||
const adminInfo = useAdminInfo()
|
||||
|
||||
const Axios = axios.create({
|
||||
baseURL: getUrl(),
|
||||
timeout: 1000 * 60 * 5,
|
||||
headers: {},
|
||||
responseType: 'json'
|
||||
})
|
||||
|
||||
options = Object.assign(
|
||||
{
|
||||
CancelDuplicateRequest: true, // 是否开启取消重复请求, 默认为 true
|
||||
loading: false, // 是否开启loading层效果, 默认为false
|
||||
reductDataFormat: true, // 是否开启简洁的数据结构响应, 默认为true
|
||||
showErrorMessage: true, // 是否开启接口错误信息展示,默认为true
|
||||
showCodeMessage: true, // 是否开启code不为1时的信息提示, 默认为true
|
||||
showSuccessMessage: false, // 是否开启code为1时的信息提示, 默认为false
|
||||
anotherToken: '' // 当前请求使用另外的用户token
|
||||
},
|
||||
options
|
||||
)
|
||||
|
||||
// 请求拦截
|
||||
Axios.interceptors.request.use(
|
||||
config => {
|
||||
removePending(config)
|
||||
options.CancelDuplicateRequest && addPending(config)
|
||||
// 创建loading实例
|
||||
if (options.loading) {
|
||||
loadingInstance.count++
|
||||
if (loadingInstance.count === 1) {
|
||||
loadingInstance.target = ElLoading.service(loading)
|
||||
}
|
||||
}
|
||||
// 自动携带token
|
||||
if (config.headers) {
|
||||
const token = adminInfo.getToken()
|
||||
if (token) {
|
||||
;(config.headers as anyObj).Authorization = token
|
||||
} else {
|
||||
config.headers.Authorization = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截
|
||||
Axios.interceptors.response.use(
|
||||
response => {
|
||||
removePending(response.config)
|
||||
options.loading && closeLoading(options) // 关闭loading
|
||||
if (
|
||||
response.data.code === 'A0000' ||
|
||||
response.data.type === 'application/json' ||
|
||||
response.data.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
) {
|
||||
return options.reductDataFormat ? response.data : response
|
||||
} else if (response.data.code == 'A0202') {
|
||||
if (!window.tokenRefreshing) {
|
||||
window.tokenRefreshing = true
|
||||
return refreshToken()
|
||||
.then(res => {
|
||||
adminInfo.setToken(res.data.token, 'auth')
|
||||
response.headers.Authorization = `${res.data.token}`
|
||||
window.requests.forEach(cb => cb(res.data.token))
|
||||
window.requests = []
|
||||
return Axios(response.config)
|
||||
})
|
||||
.catch(err => {
|
||||
adminInfo.removeToken()
|
||||
router.push({ name: 'login' })
|
||||
return Promise.reject(err)
|
||||
})
|
||||
.finally(() => {
|
||||
window.tokenRefreshing = false
|
||||
})
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
// 用函数形式将 resolve 存入,等待刷新后再执行
|
||||
window.requests.push((token: string) => {
|
||||
response.headers.Authorization = `${token}`
|
||||
resolve(Axios(response.config))
|
||||
})
|
||||
})
|
||||
}
|
||||
} else if (response.data.code == 'A0024') {
|
||||
// 登录失效
|
||||
ElNotification({
|
||||
type: 'error',
|
||||
message: response.data.message
|
||||
})
|
||||
adminInfo.removeToken()
|
||||
router.push({ name: 'login' })
|
||||
return Promise.reject(response.data)
|
||||
} else {
|
||||
if (options.showCodeMessage) {
|
||||
ElNotification({
|
||||
type: 'error',
|
||||
message: response.data.message || '未知错误'
|
||||
})
|
||||
}
|
||||
return Promise.reject(response.data)
|
||||
}
|
||||
},
|
||||
error => {
|
||||
error.config && removePending(error.config)
|
||||
options.loading && closeLoading(options) // 关闭loading
|
||||
return Promise.reject(error) // 错误继续返回给到具体页面
|
||||
}
|
||||
)
|
||||
return Axios(axiosConfig) as T
|
||||
}
|
||||
|
||||
export default createAxios
|
||||
|
||||
/**
|
||||
* 关闭Loading层实例
|
||||
*/
|
||||
function closeLoading(options: Options) {
|
||||
if (options.loading && loadingInstance.count > 0) loadingInstance.count--
|
||||
if (loadingInstance.count === 0) {
|
||||
loadingInstance.target.close()
|
||||
loadingInstance.target = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 储存每个请求的唯一cancel回调, 以此为标识
|
||||
*/
|
||||
function addPending(config: AxiosRequestConfig) {
|
||||
const pendingKey = getPendingKey(config)
|
||||
config.cancelToken =
|
||||
config.cancelToken ||
|
||||
new axios.CancelToken(cancel => {
|
||||
if (!pendingMap.has(pendingKey)) {
|
||||
pendingMap.set(pendingKey, cancel)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除重复的请求
|
||||
*/
|
||||
function removePending(config: AxiosRequestConfig) {
|
||||
const pendingKey = getPendingKey(config)
|
||||
if (pendingMap.has(pendingKey)) {
|
||||
const cancelToken = pendingMap.get(pendingKey)
|
||||
cancelToken(pendingKey)
|
||||
pendingMap.delete(pendingKey)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成每个请求的唯一key
|
||||
*/
|
||||
function getPendingKey(config: AxiosRequestConfig) {
|
||||
let { data } = config
|
||||
const { url, method, params, headers } = config
|
||||
if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
|
||||
return [
|
||||
url,
|
||||
method,
|
||||
headers && (headers as anyObj).Authorization ? (headers as anyObj).Authorization : '',
|
||||
headers && (headers as anyObj)['ba-user-token'] ? (headers as anyObj)['ba-user-token'] : '',
|
||||
JSON.stringify(params),
|
||||
JSON.stringify(data)
|
||||
].join('&')
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据请求方法组装请求数据/参数
|
||||
*/
|
||||
export function requestPayload(method: Method, data: anyObj) {
|
||||
if (method == 'GET') {
|
||||
return {
|
||||
params: data
|
||||
}
|
||||
} else if (method == 'POST') {
|
||||
return {
|
||||
data: data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface LoadingInstance {
|
||||
target: any
|
||||
count: number
|
||||
}
|
||||
|
||||
interface Options {
|
||||
// 是否开启取消重复请求, 默认为 true
|
||||
CancelDuplicateRequest?: boolean
|
||||
// 是否开启loading层效果, 默认为false
|
||||
loading?: boolean
|
||||
// 是否开启简洁的数据结构响应, 默认为true
|
||||
reductDataFormat?: boolean
|
||||
// 是否开启code不为A0000时的信息提示, 默认为true
|
||||
showCodeMessage?: boolean
|
||||
// 是否开启code为0时的信息提示, 默认为false
|
||||
showSuccessMessage?: boolean
|
||||
// 当前请求使用另外的用户token
|
||||
anotherToken?: string
|
||||
}
|
||||
296
src/utils/router.ts
Normal file
296
src/utils/router.ts
Normal file
@@ -0,0 +1,296 @@
|
||||
import router from '@/router/index'
|
||||
import { isNavigationFailure, NavigationFailureType } from 'vue-router'
|
||||
import type { RouteRecordRaw, RouteLocationRaw } from 'vue-router'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import { useConfig } from '@/stores/config'
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
import { closeShade } from '@/utils/pageShade'
|
||||
import { adminBaseRoute } from '@/router/static'
|
||||
import { compact, isEmpty, reverse } from 'lodash-es'
|
||||
import { isAdminApp } from '@/utils/common'
|
||||
import { log } from 'console'
|
||||
|
||||
/**
|
||||
* 导航失败有错误消息的路由push
|
||||
* @param to — 导航位置,同 router.push
|
||||
*/
|
||||
export const routePush = async (to: RouteLocationRaw) => {
|
||||
try {
|
||||
const failure = await router.push(to)
|
||||
if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
|
||||
ElNotification({
|
||||
message: 'utils.Navigation failed, navigation guard intercepted!',
|
||||
type: 'error'
|
||||
})
|
||||
} else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {
|
||||
// ElNotification({
|
||||
// message: '已在目标页',
|
||||
// type: 'warning'
|
||||
// })
|
||||
}
|
||||
} catch (error) {
|
||||
ElNotification({
|
||||
message: '导航失败,路由无效',
|
||||
type: 'error'
|
||||
})
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取第一个菜单
|
||||
*/
|
||||
export const getFirstRoute = (routes: RouteRecordRaw[], menuType = 'tab'): false | RouteRecordRaw => {
|
||||
const routerPaths: string[] = []
|
||||
const routers = router.getRoutes()
|
||||
routers.forEach(item => {
|
||||
if (item.path) routerPaths.push(item.path)
|
||||
})
|
||||
let find: boolean | RouteRecordRaw = false
|
||||
for (const key in routes) {
|
||||
if (
|
||||
routes[key].meta?.type == 'menu' &&
|
||||
routes[key].meta?.menu_type == menuType &&
|
||||
routerPaths.indexOf(routes[key].path) !== -1
|
||||
) {
|
||||
return routes[key]
|
||||
} else if (routes[key].children && routes[key].children?.length) {
|
||||
find = getFirstRoute(routes[key].children!)
|
||||
if (find) return find
|
||||
}
|
||||
}
|
||||
return find
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开侧边菜单
|
||||
* @param menu 菜单数据
|
||||
*/
|
||||
export const onClickMenu = (menu: RouteRecordRaw) => {
|
||||
switch (menu.meta?.menu_type) {
|
||||
case 'iframe':
|
||||
case 'tab':
|
||||
routePush({ path: menu.path })
|
||||
break
|
||||
case 'link':
|
||||
window.open(menu.path, '_blank')
|
||||
break
|
||||
|
||||
default:
|
||||
ElNotification({
|
||||
message: 'utils.Navigation failed, the menu type is unrecognized!',
|
||||
type: 'error'
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
const config = useConfig()
|
||||
if (config.layout.shrink) {
|
||||
closeShade(() => {
|
||||
config.setLayout('menuCollapse', true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理后台的路由
|
||||
*/
|
||||
export const handleAdminRoute = (routes: any) => {
|
||||
const viewsComponent = import.meta.glob('/src/views/**/*.vue')
|
||||
addRouteAll(viewsComponent, routes, adminBaseRoute.name as string)
|
||||
const menuAdminBaseRoute = (adminBaseRoute.path as string) + '/'
|
||||
// 更新stores中的路由菜单数据
|
||||
const navTabs = useNavTabs()
|
||||
navTabs.setTabsViewRoutes(handleMenuRule(routes, menuAdminBaseRoute))
|
||||
navTabs.fillAuthNode(handleAuthNode(routes, menuAdminBaseRoute))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单的paths
|
||||
*/
|
||||
export const getMenuPaths = (menus: RouteRecordRaw[]): string[] => {
|
||||
let menuPaths: string[] = []
|
||||
menus.forEach(item => {
|
||||
menuPaths.push(item.path)
|
||||
if (item.children && item.children.length > 0) {
|
||||
menuPaths = menuPaths.concat(getMenuPaths(item.children))
|
||||
}
|
||||
})
|
||||
return menuPaths
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台的菜单处理
|
||||
*/
|
||||
const handleMenuRule = (routes: any, pathPrefix = '/', type = ['menu', 'menu_dir']) => {
|
||||
const menuRule: RouteRecordRaw[] = []
|
||||
for (const key in routes) {
|
||||
if (routes[key].extend == 'add_rules_only') {
|
||||
continue
|
||||
}
|
||||
if (!type.includes(routes[key].type)) {
|
||||
continue
|
||||
}
|
||||
if (routes[key].type == 'menu_dir' && routes[key].children && !routes[key].children.length) {
|
||||
continue
|
||||
}
|
||||
if (
|
||||
['route', 'menu', 'nav_user_menu', 'nav'].includes(routes[key].type) &&
|
||||
((routes[key].menu_type == 'tab' && !routes[key].component) ||
|
||||
(['link', 'iframe'].includes(routes[key].menu_type) && !routes[key].url))
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const currentPath = ['link', 'iframe'].includes(routes[key].menu_type)
|
||||
? routes[key].url
|
||||
: pathPrefix + routes[key].path
|
||||
let children: RouteRecordRaw[] = []
|
||||
if (routes[key].children && routes[key].children.length > 0) {
|
||||
children = handleMenuRule(routes[key].children, pathPrefix, type)
|
||||
}
|
||||
menuRule.push({
|
||||
path: currentPath,
|
||||
name: routes[key].name,
|
||||
component: routes[key].component,
|
||||
meta: {
|
||||
id: routes[key].id,
|
||||
title: routes[key].title,
|
||||
icon: routes[key].icon,
|
||||
keepalive: routes[key].keepalive,
|
||||
menu_type: routes[key].menu_type,
|
||||
type: routes[key].type
|
||||
},
|
||||
children: children
|
||||
})
|
||||
}
|
||||
return menuRule
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理权限节点
|
||||
* @param routes 路由数据
|
||||
* @param prefix 节点前缀
|
||||
* @returns 组装好的权限节点
|
||||
*/
|
||||
const handleAuthNode = (routes: any, prefix = '/') => {
|
||||
const authNode: Map<string, string[]> = new Map([])
|
||||
assembleAuthNode(routes, authNode, prefix, prefix)
|
||||
return authNode
|
||||
}
|
||||
const assembleAuthNode = (routes: any, authNode: Map<string, string[]>, prefix = '/', parent = '/') => {
|
||||
const authNodeTemp = []
|
||||
for (const key in routes) {
|
||||
if (routes[key].type == 'button') authNodeTemp.push(prefix + routes[key].name)
|
||||
if (routes[key].children && routes[key].children.length > 0) {
|
||||
assembleAuthNode(routes[key].children, authNode, prefix, prefix + routes[key].name)
|
||||
}
|
||||
}
|
||||
if (authNodeTemp && authNodeTemp.length > 0) {
|
||||
authNode.set(parent, authNodeTemp)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态添加路由-带子路由
|
||||
* @param viewsComponent
|
||||
* @param routes
|
||||
* @param parentName
|
||||
* @param analyticRelation 根据 name 从已注册路由分析父级路由
|
||||
*/
|
||||
export const addRouteAll = (
|
||||
viewsComponent: Record<string, any>,
|
||||
routes: any,
|
||||
parentName: string,
|
||||
analyticRelation = false
|
||||
) => {
|
||||
for (const idx in routes) {
|
||||
if (routes[idx].extend == 'add_menu_only') {
|
||||
continue
|
||||
}
|
||||
if (
|
||||
(routes[idx].menu_type == 'tab' && viewsComponent[routes[idx].component]) ||
|
||||
routes[idx].menu_type == 'iframe'
|
||||
) {
|
||||
addRouteItem(viewsComponent, routes[idx], parentName, analyticRelation)
|
||||
}
|
||||
|
||||
if (routes[idx].children && routes[idx].children.length > 0) {
|
||||
addRouteAll(viewsComponent, routes[idx].children, parentName, analyticRelation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态添加路由
|
||||
* @param viewsComponent
|
||||
* @param route
|
||||
* @param parentName
|
||||
* @param analyticRelation 根据 name 从已注册路由分析父级路由
|
||||
*/
|
||||
export const addRouteItem = (
|
||||
viewsComponent: Record<string, any>,
|
||||
route: any,
|
||||
parentName: string,
|
||||
analyticRelation: boolean
|
||||
) => {
|
||||
let path = '',
|
||||
component
|
||||
if (route.menu_type == 'iframe') {
|
||||
path = (isAdminApp() ? adminBaseRoute.path : '') + '/iframe/' + encodeURIComponent(route.url)
|
||||
component = () => import('@/layouts/common/router-view/iframe.vue')
|
||||
} else {
|
||||
path = parentName ? route.path : '/' + route.path
|
||||
component = viewsComponent[route.component]
|
||||
}
|
||||
|
||||
if (route.menu_type == 'tab' && analyticRelation) {
|
||||
const parentNames = getParentNames(route.name)
|
||||
if (parentNames.length) {
|
||||
for (const key in parentNames) {
|
||||
if (router.hasRoute(parentNames[key])) {
|
||||
parentName = parentNames[key]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const routeBaseInfo: RouteRecordRaw = {
|
||||
path: path,
|
||||
name: route.name,
|
||||
component: component,
|
||||
meta: {
|
||||
...route,
|
||||
title: route.title,
|
||||
extend: route.extend,
|
||||
icon: route.icon,
|
||||
keepalive: route.keepalive,
|
||||
menu_type: route.menu_type,
|
||||
type: route.type,
|
||||
url: route.url,
|
||||
addtab: true
|
||||
}
|
||||
}
|
||||
if (parentName) {
|
||||
router.addRoute(parentName, routeBaseInfo)
|
||||
} else {
|
||||
router.addRoute(routeBaseInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据name字符串,获取父级name组合的数组
|
||||
* @param name
|
||||
*/
|
||||
const getParentNames = (name: string) => {
|
||||
const names = compact(name.split('/'))
|
||||
const tempNames = []
|
||||
const parentNames = []
|
||||
for (const key in names) {
|
||||
tempNames.push(names[key])
|
||||
if (parseInt(key) != names.length - 1) {
|
||||
parentNames.push(tempNames.join('/'))
|
||||
}
|
||||
}
|
||||
return reverse(parentNames)
|
||||
}
|
||||
42
src/utils/setTheme.ts
Normal file
42
src/utils/setTheme.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { onMounted, watch } from 'vue'
|
||||
|
||||
import { useElementPlusTheme } from 'use-element-plus-theme'
|
||||
import { useConfig } from '@/stores/config'
|
||||
|
||||
const useSetTheme = () => {
|
||||
const configStore = useConfig()
|
||||
const elementPlusTheme = useElementPlusTheme(configStore.getColorVal('elementUiPrimary'))
|
||||
const updateTheme = () => {
|
||||
const root = document.documentElement
|
||||
root.style.setProperty('--vxe-table-header-background-color', configStore.getColorVal('tableHeaderBackground'))
|
||||
root.style.setProperty('--vxe-table-header-font-color', configStore.getColorVal('tableHeaderColor'))
|
||||
root.style.setProperty('--vxe-table-row-current-background-color', configStore.getColorVal('tableCurrent'))
|
||||
root.style.setProperty('--vxe-table-row-hover-background-color', configStore.getColorVal('tableCurrent'))
|
||||
root.style.setProperty(
|
||||
'--vxe-table-row-hover-current-background-color',
|
||||
configStore.getColorVal('tableCurrent')
|
||||
)
|
||||
root.style.setProperty(
|
||||
'--vxe-table-row-hover-striped-background-color',
|
||||
configStore.getColorVal('tableCurrent')
|
||||
)
|
||||
}
|
||||
onMounted(updateTheme)
|
||||
watch(
|
||||
() => configStore.getColorVal('elementUiPrimary'),
|
||||
() => {
|
||||
elementPlusTheme.changeTheme(configStore.getColorVal('elementUiPrimary'))
|
||||
}
|
||||
)
|
||||
watch(
|
||||
[
|
||||
() => configStore.getColorVal('tableHeaderBackground'),
|
||||
() => configStore.getColorVal('tableHeaderColor'),
|
||||
() => configStore.getColorVal('tableCurrent')
|
||||
],
|
||||
() => {
|
||||
updateTheme()
|
||||
}
|
||||
)
|
||||
}
|
||||
export default useSetTheme
|
||||
45
src/utils/storage.ts
Normal file
45
src/utils/storage.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* window.localStorage
|
||||
* @method set 设置
|
||||
* @method get 获取
|
||||
* @method remove 移除
|
||||
* @method clear 移除全部
|
||||
*/
|
||||
export const Local = {
|
||||
set(key: string, val: any) {
|
||||
window.localStorage.setItem(key, JSON.stringify(val))
|
||||
},
|
||||
get(key: string) {
|
||||
const json: any = window.localStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
},
|
||||
remove(key: string) {
|
||||
window.localStorage.removeItem(key)
|
||||
},
|
||||
clear() {
|
||||
window.localStorage.clear()
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* window.sessionStorage
|
||||
* @method set 设置会话缓存
|
||||
* @method get 获取会话缓存
|
||||
* @method remove 移除会话缓存
|
||||
* @method clear 移除全部会话缓存
|
||||
*/
|
||||
export const Session = {
|
||||
set(key: string, val: any) {
|
||||
window.sessionStorage.setItem(key, JSON.stringify(val))
|
||||
},
|
||||
get(key: string) {
|
||||
const json: any = window.sessionStorage.getItem(key)
|
||||
return JSON.parse(json)
|
||||
},
|
||||
remove(key: string) {
|
||||
window.sessionStorage.removeItem(key)
|
||||
},
|
||||
clear() {
|
||||
window.sessionStorage.clear()
|
||||
},
|
||||
}
|
||||
166
src/utils/tableStore.ts
Normal file
166
src/utils/tableStore.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { reactive } from 'vue'
|
||||
import createAxios from '@/utils/request'
|
||||
import { requestPayload } from '@/utils/request'
|
||||
import { Method } from 'axios'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
interface TableStoreParams {
|
||||
url: string
|
||||
pk?: string
|
||||
column: TableColumn[]
|
||||
params?: anyObj
|
||||
method?: Method
|
||||
isWebPaging?: boolean // 是否前端分页
|
||||
showPage?: boolean
|
||||
publicHeight?: number
|
||||
resetCallback?: () => void
|
||||
loadCallback?: () => void
|
||||
beforeSearchFun?: () => void
|
||||
}
|
||||
|
||||
export default class TableStore {
|
||||
public url
|
||||
public pk
|
||||
public method: Method
|
||||
public initData: any = null
|
||||
public isWebPaging = false
|
||||
public showPage = true
|
||||
public table: CnTable = reactive({
|
||||
ref: null,
|
||||
selection: [],
|
||||
data: [],
|
||||
webPagingData: [],
|
||||
total: 0,
|
||||
params: {
|
||||
pageNum: 1,
|
||||
pageSize: 20
|
||||
},
|
||||
loading: true,
|
||||
column: [],
|
||||
loadCallback: null,
|
||||
resetCallback: null,
|
||||
beforeSearchFun: null,
|
||||
height: mainHeight(20 + (this.showPage ? 58 : 0)).height as string,
|
||||
publicHeight: 0
|
||||
})
|
||||
|
||||
constructor(public options: TableStoreParams) {
|
||||
this.url = options.url
|
||||
this.pk = options.pk || 'id'
|
||||
this.isWebPaging = options.isWebPaging || false
|
||||
this.method = options.method || 'GET'
|
||||
this.table.column = options.column
|
||||
this.showPage = options.showPage !== false
|
||||
this.table.publicHeight = options.publicHeight || 0
|
||||
this.table.resetCallback = options.resetCallback || null
|
||||
this.table.loadCallback = options.loadCallback || null
|
||||
this.table.beforeSearchFun = options.beforeSearchFun || null
|
||||
Object.assign(this.table.params, options.params)
|
||||
}
|
||||
|
||||
index() {
|
||||
this.table.data = []
|
||||
this.table.loading = true
|
||||
// 重置用的数据数据
|
||||
if (!this.initData) {
|
||||
this.initData = JSON.parse(JSON.stringify(this.table.params))
|
||||
}
|
||||
createAxios(
|
||||
Object.assign(
|
||||
{
|
||||
url: this.url,
|
||||
method: this.method
|
||||
},
|
||||
requestPayload(this.method, this.table.params)
|
||||
)
|
||||
).then((res: any) => {
|
||||
this.table.data = res.data.records || res.data
|
||||
this.table.total = res.data.total || res.data.length || 0
|
||||
if (this.isWebPaging) {
|
||||
this.table.webPagingData = window.XEUtils.chunk(this.table.data, this.table.params.pageSize)
|
||||
this.table.data = this.table.webPagingData[this.table.params.pageNum - 1]
|
||||
}
|
||||
this.table.loadCallback && this.table.loadCallback()
|
||||
this.table.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格内的事件统一响应
|
||||
* @param event 事件:selection-change=选中项改变,page-size-change=每页数量改变,current-page-change=翻页
|
||||
* @param data 携带数据
|
||||
*/
|
||||
onTableAction = (event: string, data: anyObj) => {
|
||||
const actionFun = new Map([
|
||||
[
|
||||
'search',
|
||||
() => {
|
||||
this.table.beforeSearchFun && this.table.beforeSearchFun()
|
||||
this.table.params.pageNum = 1
|
||||
this.index()
|
||||
}
|
||||
],
|
||||
[
|
||||
'reset',
|
||||
() => {
|
||||
delete this.initData.pageSize
|
||||
console.log(this.table.params)
|
||||
console.log(this.initData)
|
||||
Object.assign(this.table.params, this.initData)
|
||||
this.index()
|
||||
this.table.resetCallback && this.table.resetCallback()
|
||||
}
|
||||
],
|
||||
[
|
||||
'selection-change',
|
||||
() => {
|
||||
this.table.selection = data as TableRow[]
|
||||
}
|
||||
],
|
||||
[
|
||||
'page-size-change',
|
||||
() => {
|
||||
this.table.params.pageSize = data.size
|
||||
this.table.params.pageNum = 1
|
||||
|
||||
if (this.isWebPaging) {
|
||||
this.table.webPagingData = window.XEUtils.chunk(
|
||||
window.XEUtils.flatten(this.table.webPagingData),
|
||||
this.table.params.pageSize
|
||||
)
|
||||
this.table.data = this.table.webPagingData[this.table.params.pageNum - 1]
|
||||
} else {
|
||||
this.index()
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'current-page-change',
|
||||
() => {
|
||||
this.table.params.pageNum = data.page
|
||||
if (this.isWebPaging) {
|
||||
this.table.data = []
|
||||
requestAnimationFrame(() => {
|
||||
this.table.data = this.table.webPagingData[data.page - 1]
|
||||
})
|
||||
} else {
|
||||
this.index()
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'field-change',
|
||||
() => {
|
||||
console.warn('field-change')
|
||||
}
|
||||
],
|
||||
[
|
||||
'default',
|
||||
() => {
|
||||
console.warn('No action defined')
|
||||
}
|
||||
]
|
||||
])
|
||||
const action = actionFun.get(event) || actionFun.get('default')
|
||||
action!.call(this)
|
||||
}
|
||||
}
|
||||
13
src/utils/useCurrentInstance.ts
Normal file
13
src/utils/useCurrentInstance.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { getCurrentInstance } from 'vue'
|
||||
import type { ComponentInternalInstance } from 'vue'
|
||||
|
||||
export default function useCurrentInstance() {
|
||||
if (!getCurrentInstance()) {
|
||||
throw new Error('useCurrentInstance() can only be used inside setup() or functional components!')
|
||||
}
|
||||
const { appContext } = getCurrentInstance() as ComponentInternalInstance
|
||||
const proxy = appContext.config.globalProperties
|
||||
return {
|
||||
proxy,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user