This commit is contained in:
ray_wuhao 2023-07-22 23:31:06 +08:00
parent dd757d24a4
commit 01d44d46f3
58 changed files with 805 additions and 198 deletions

View File

@ -1,5 +1,45 @@
# CHANGE LOG
## 4.1.3
### Feats
- 新增切换路由自动取消上一路由所有请求。但是可以通过配置 `useRequest``request` 方法的 `cancelConfig.needCancel` 属性控制是否需要自动取消该请求。该配置默认为 `true`,当配置为 `false` 时,则不会被取消器取消
```ts
import { useRequest, useHookPlusRequest } from '@/axios/index'
// useRequest
const { data, loading, run } = useRequest<{
title: string
}>(
{
url: 'https://jsonplaceholder.typicode.com/todos/1',
method: 'get',
cancelConfig: {
needCancel: true,
},
},
{
manual: true,
},
)
// request
request({
url: 'https://jsonplaceholder.typicode.com/todos/1',
method: 'get',
cancelConfig: {
needCancel: true,
},
})
```
- `localConfig` 新增配置类型保护
- 将原 `AppComponent` 组件包移动至 `app-components` 包中,并且按照其功能拆分为 `sys` `provider`
- 现在将异步注册 `vue-router`
- `RayChart` 组件新增 `macarons` 主题。现在支持便捷的自定义主题,在[主题编辑器](https://echarts.apache.org/zh/theme-builder.html)编辑主题后下载主题json放置于对应主题包中即可被自动注册
## 4.1.2
### Fixes

View File

@ -1,8 +1,8 @@
import { RouterView } from 'vue-router'
import AppNaiveGlobalProvider from '@/components/AppComponents/AppNaiveGlobalProvider/index'
import AppStyleProvider from '@/components/AppComponents/AppStyleProvider/index'
import AppNaiveGlobalProvider from '@/app-components/provider/AppNaiveGlobalProvider/index'
import AppStyleProvider from '@/app-components/provider/AppStyleProvider/index'
import GlobalSpin from '@/spin/index'
import LockScreen from '@/components/AppComponents/AppLockScreen/index'
import LockScreen from '@/app-components/app/AppLockScreen/index'
const App = defineComponent({
name: 'App',

View File

@ -0,0 +1,6 @@
## 描述
该包存放与模板深度绑定的组件:
- app存放与模板数据绑定的组件
- sys存放模板注入类组件

View File

@ -12,14 +12,11 @@
/** 锁屏界面 */
import { NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui'
import AppAvatar from '@/components/AppComponents/AppAvatar/index'
import AppAvatar from '@/app-components/app/AppAvatar/index'
import { useSetting } from '@/store'
import useAppLockScreen from '@/components/AppComponents/AppLockScreen/appLockVar'
import {
rules,
useCondition,
} from '@/components/AppComponents/AppLockScreen/hook'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook'
import type { FormInst, InputInst } from 'naive-ui'

View File

@ -12,15 +12,12 @@
/** 解锁界面 */
import { NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui'
import AppAvatar from '@/components/AppComponents/AppAvatar/index'
import AppAvatar from '@/app-components/app/AppAvatar/index'
import dayjs from 'dayjs'
import { useSetting, useSignin } from '@/store'
import {
rules,
useCondition,
} from '@/components/AppComponents/AppLockScreen/hook'
import useAppLockScreen from '@/components/AppComponents/AppLockScreen/appLockVar'
import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
import type { FormInst, InputInst } from 'naive-ui'

View File

@ -22,7 +22,7 @@ import LockScreen from './components/LockScreen'
import UnlockScreen from './components/UnlockScreen'
import { useSetting } from '@/store'
import useAppLockScreen from '@/components/AppComponents/AppLockScreen/appLockVar'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
const AppLockScreen = defineComponent({
name: 'AppLockScreen',

View File

@ -0,0 +1,40 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-07-21
*
* @workspace ray-template
*
* @remark
*/
/**
*
*
*
*
* beforeRouteUpdate -> cancelAllRequest -> routerUpdate
*/
import { axiosCanceler } from '@/axios/helper/interceptor'
const AppRequestCanceler = defineComponent({
name: 'AppRequestCanceler',
setup() {
onBeforeRouteUpdate(() => {
axiosCanceler.cancelAllRequest()
})
},
render() {
return (
<div
style={{
display: 'none',
}}
></div>
)
},
})
export default AppRequestCanceler

View File

@ -19,7 +19,7 @@ import type { AppLocalesDropdownMixedOption } from '@/locales/type'
* ,
* key naiveLocales ,
*
* , , CurrentAppMessages
* , , AppCurrentAppMessages
*/
export const LOCAL_OPTIONS: AppLocalesDropdownMixedOption[] = [
{

View File

@ -16,7 +16,7 @@
*
*/
import type { AxiosRequestConfig } from 'axios'
import type { AppRawRequestConfig } from '@/axios/type'
export default class RequestCanceler {
pendingRequest: Map<string, AbortController>
@ -25,6 +25,11 @@ export default class RequestCanceler {
this.pendingRequest = new Map<string, AbortController>()
}
/** 是否需要加入取消请求表中 */
isApending(config: AppRawRequestConfig) {
return config.cancelConfig?.needCancel ?? true
}
/**
*
* @param config config
@ -32,7 +37,7 @@ export default class RequestCanceler {
*
* @remark config request key
*/
generateRequestKey(config: AxiosRequestConfig): string {
generateRequestKey(config: AppRawRequestConfig): string {
const { method, url } = config
return [
@ -49,18 +54,20 @@ export default class RequestCanceler {
*
* @remark signal ,
*/
addPendingRequest(config: AxiosRequestConfig) {
const requestKey = this.generateRequestKey(config)
addPendingRequest(config: AppRawRequestConfig) {
if (this.isApending(config)) {
const requestKey = this.generateRequestKey(config)
if (!this.pendingRequest.has(requestKey)) {
const controller = new AbortController()
if (!this.pendingRequest.has(requestKey)) {
const controller = new AbortController()
config.signal = controller.signal
config.signal = controller.signal
this.pendingRequest.set(requestKey, controller)
} else {
// 如果已经有该 key 则重新挂载 signal
config.signal = this.pendingRequest.get(requestKey)?.signal
this.pendingRequest.set(requestKey, controller)
} else {
// 如果已经有该 key 则重新挂载 signal
config.signal = this.pendingRequest.get(requestKey)?.signal
}
}
}
@ -70,7 +77,7 @@ export default class RequestCanceler {
*
* @remark , map generateRequestKey value
*/
removePendingRequest(config: AxiosRequestConfig) {
removePendingRequest(config: AppRawRequestConfig) {
const requestKey = this.generateRequestKey(config)
if (this.pendingRequest.has(requestKey)) {
@ -79,4 +86,11 @@ export default class RequestCanceler {
this.pendingRequest.delete(requestKey)
}
}
/** 取消所有请求 */
cancelAllRequest() {
this.pendingRequest.forEach((curr) => {
curr.abort()
})
}
}

View File

@ -32,7 +32,7 @@ import type {
AxiosFetchInstance,
AxiosFetchError,
} from '@/axios/type'
import type { AnyFunc } from '@/types/modules/utils'
import type { AnyFC } from '@/types/modules/utils'
/** 当前请求的实例 */
const axiosFetchInstance: AxiosFetchInstance = {
@ -77,7 +77,7 @@ export const useAxiosInterceptor = () => {
/** 设置注入方法队列 */
const setImplement = (
key: keyof ImplementQueue | keyof ErrorImplementQueue,
func: AnyFunc[],
func: AnyFC[],
fetchType: FetchType,
) => {
fetchType === 'ok' ? (implement[key] = func) : (errorImplement[key] = func)
@ -87,12 +87,12 @@ export const useAxiosInterceptor = () => {
const getImplement = (
key: keyof ImplementQueue | keyof ErrorImplementQueue,
fetchType: FetchType,
): AnyFunc[] => {
): AnyFC[] => {
return fetchType === 'ok' ? implement[key] : errorImplement[key]
}
/** 队列执行器 */
const implementer = (funcs: AnyFunc[], ...args: any[]) => {
const implementer = (funcs: AnyFC[], ...args: any[]) => {
if (Array.isArray(funcs)) {
funcs?.forEach((curr) => {
if (typeof curr === 'function') {

View File

@ -25,7 +25,7 @@ import useHookPlusRequest from 'vue-hooks-plus/es/useRequest'
import request from '@/axios/instance'
import type { UseRequestOptions } from 'vue-hooks-plus/es/useRequest/types'
import type { AxiosRequestConfig } from 'axios'
import type { AppRawRequestConfig } from '@/axios/type'
/**
*
@ -43,7 +43,7 @@ function useRequest<
HookPlusParams extends unknown[] = unknown[],
HookPlusPlugin = unknown,
>(
fetchOption: AxiosRequestConfig<Response>,
fetchOption: AppRawRequestConfig<Response>,
option?: UseRequestOptions<Response, HookPlusParams, HookPlusPlugin>,
) {
const fc = () => {
@ -52,7 +52,10 @@ function useRequest<
return cb
}
const hooks = useHookPlusRequest(fc, Object.assign({}, option))
const hooks = useHookPlusRequest<Response, HookPlusParams>(
fc,
Object.assign({}, option),
)
return hooks
}

View File

@ -7,7 +7,7 @@ import type {
Axios,
AxiosResponse,
} from 'axios'
import type { AnyFunc } from '@/types/modules/utils'
import type { AnyFC } from '@/types/modules/utils'
export type AxiosHeaderValue =
| AxiosHeaders
@ -22,54 +22,65 @@ export interface RequestHeaderOptions {
value: AxiosHeaderValue
}
export interface AxiosInstanceExpand extends Axios {
<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<T>
<T = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<T>
export interface CancelConfig {
needCancel?: boolean
}
getUri(config?: AxiosRequestConfig): string
request<R = any, D = any>(config: AxiosRequestConfig<D>): Promise<R>
get<R = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>
export interface AppRawRequestConfig<T = any> extends AxiosRequestConfig<T> {
cancelConfig?: CancelConfig
}
export interface AxiosInstanceExpand extends Axios {
<T = any, D = any>(config: AppRawRequestConfig<D>): Promise<T>
<T = any, D = any>(url: string, config?: AppRawRequestConfig<D>): Promise<T>
getUri(config?: AppRawRequestConfig): string
request<R = any, D = any>(config: AppRawRequestConfig<D>): Promise<R>
get<R = any, D = any>(
url: string,
config?: AppRawRequestConfig<D>,
): Promise<R>
delete<R = any, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
head<R = any, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
options<R = any, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
post<R = any, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
put<R = any, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
patch<R = any, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
postForm<R = any, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
putForm<R = any, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
patchForm<R = any, D = any>(
url: string,
data?: D,
config?: AxiosRequestConfig<D>,
config?: AppRawRequestConfig<D>,
): Promise<R>
defaults: Omit<AxiosDefaults, 'headers' | 'cancelToken'> & {
@ -79,18 +90,18 @@ export interface AxiosInstanceExpand extends Axios {
}
}
export type RequestInterceptorConfig<T = any> = AxiosRequestConfig<T>
export type RequestInterceptorConfig<T = any> = AppRawRequestConfig<T>
export type ResponseInterceptorConfig<T = any, K = any> = AxiosResponse<T, K>
export interface ImplementQueue {
implementRequestInterceptorArray: AnyFunc[]
implementResponseInterceptorArray: AnyFunc[]
implementRequestInterceptorArray: AnyFC[]
implementResponseInterceptorArray: AnyFC[]
}
export interface ErrorImplementQueue {
implementRequestInterceptorErrorArray: AnyFunc[]
implementResponseInterceptorErrorArray: AnyFunc[]
implementRequestInterceptorErrorArray: AnyFC[]
implementResponseInterceptorErrorArray: AnyFC[]
}
export type BeforeFetchFunction<

View File

@ -1,9 +0,0 @@
## 描述
> 该组件包存放依赖系统数据的公共组件和与项目绑定的一些组件。
## 约束
- 该组件包仅存放与系统数据有绑定、关联的组件,纯组件或纯 UI 组件应放置于外层包中
- 以 `App` 开头标记组件是系统组件
- 组件应该尽量避免与其他系统组件有关联性

View File

@ -0,0 +1,81 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-07-22
*
* @workspace ray-template
*
* @remark
*/
import type {
ChartThemeRawArray,
ChartThemeRawModules,
LoadingOptions,
} from '@/components/RayChart/type'
/**
*
*
*
*
*
* https://echarts.apache.org/zh/theme-builder.html
*
* 1.
* 2.
* 3. json
* 4. @/components/RayChart/theme json
*/
export const setupChartTheme = () => {
// 获取所有主题
const themeRawModules: Record<string, ChartThemeRawModules> =
import.meta.glob('@/components/RayChart/theme/**/*.json', {
eager: true,
})
const regx = /\/([^/]+)\.json$/
const rawThemes = Object.keys(themeRawModules).reduce((pre, curr) => {
const name = curr.match(regx)?.[1]
if (name) {
pre.push({
name,
theme: themeRawModules[curr].default,
})
return pre
} else {
throw new Error('theme name is not found')
}
}, [] as ChartThemeRawArray[])
return rawThemes
}
/**
*
* @returns LoadingOptions
*
* 便使, ,
*/
export const loadingOptions = (options?: LoadingOptions) =>
Object.assign(
{},
{
text: 'loading',
color: '#c23531',
textColor: '#000',
maskColor: 'rgba(255, 255, 255, 0.9)',
zlevel: 0,
fontSize: 12,
showSpinner: true,
spinnerRadius: 10,
lineWidth: 5,
fontWeight: 'normal',
fontStyle: 'normal',
fontFamily: 'sans-serif',
},
options,
)

View File

@ -40,66 +40,22 @@ import { CanvasRenderer } from 'echarts/renderers' // `echarts` 渲染器
import { useSetting } from '@/store'
import { cloneDeep, throttle } from 'lodash-es'
import { on, off, addStyle, completeSize } from '@/utils/element'
import { on, off, completeSize } from '@/utils/element'
import { call } from '@/utils/vue/index'
import { setupChartTheme, loadingOptions } from './helper'
import type { PropType } from 'vue'
import type { EChartsInstance } from '@/types/modules/component'
import type { AnyFunc, MaybeArray } from '@/types/modules/utils'
import type { AnyFC, MaybeArray } from '@/types/modules/utils'
import type { DebouncedFunc } from 'lodash-es'
export type AutoResize =
| boolean
| {
width: number
height: number
}
export interface LoadingOptions {
text: string // 文本内容
color: string // 颜色
textColor: string // 字体颜色
maskColor: string // 遮罩颜色
zlevel: number // 水平
fontSize: number // 字体大小
showSpinner: boolean // 是否显示旋转动画(`spinner`)
spinnerRadius: number // 旋转动画(`spinner`)的半径
lineWidth: number // 旋转动画(`spinner`)的线宽
fontWeight: string // 字体粗细
fontStyle: string // 字体风格
fontFamily: string // 字体系列
}
export type ChartTheme = 'dark' | '' | object
import type {
LoadingOptions,
AutoResize,
ChartTheme,
} from '@/components/RayChart/type'
export type EChartsExtensionInstallRegisters = typeof CanvasRenderer
/**
*
* @returns LoadingOptions
*
* 便使, ,
*/
export const loadingOptions = (options?: LoadingOptions) =>
Object.assign(
{},
{
text: 'loading',
color: '#c23531',
textColor: '#000',
maskColor: 'rgba(255, 255, 255, 0.9)',
zlevel: 0,
fontSize: 12,
showSpinner: true,
spinnerRadius: 10,
lineWidth: 5,
fontWeight: 'normal',
fontStyle: 'normal',
fontFamily: 'sans-serif',
},
options,
)
const RayChart = defineComponent({
name: 'RayChart',
props: {
@ -229,7 +185,7 @@ const RayChart = defineComponent({
const rayChartRef = ref<HTMLElement>() // `echart` 容器实例
const echartInstanceRef = ref<EChartsInstance>() // `echart` 拷贝实例, 解决直接使用响应式实例带来的问题
let echartInstance: EChartsInstance // `echart` 实例
let resizeThrottle: DebouncedFunc<AnyFunc> // resize 防抖方法实例
let resizeThrottle: DebouncedFunc<AnyFC> // resize 防抖方法实例
const cssVarsRef = computed(() => {
const cssVars = {
@ -294,13 +250,13 @@ const RayChart = defineComponent({
*
* ...
*/
const useMergeOptions = () => {
const combineChartOptions = () => {
let options = cloneDeep(props.options)
const merge = (opts: object) => Object.assign({}, options, opts)
const assign = (opts: object) => Object.assign({}, options, opts)
if (props.showAria) {
options = merge({
options = assign({
aria: {
enabled: true,
decal: {
@ -321,32 +277,28 @@ const RayChart = defineComponent({
*
* 使, `legend`
*/
const renderChart = (theme: ChartTheme) => {
const renderChart = (theme: ChartTheme = 'macarons') => {
/** 获取 dom 容器 */
const element = rayChartRef.value as HTMLElement
/** 获取配置项 */
const options = useMergeOptions()
const options = combineChartOptions()
/** 获取 dom 容器实际宽高 */
const { height, width } = element.getBoundingClientRect()
const { success, error } = props
/** 如果高度为 0, 则以 200px 填充 */
if (height === 0) {
addStyle(element, {
height: '200px',
})
}
/** 如果款度为 0, 则以 200px 填充 */
if (width === 0) {
addStyle(element, {
width: '200px',
})
}
try {
/** 注册主题 */
setupChartTheme().forEach((curr) => {
echarts.registerTheme(curr.name, curr.theme)
})
/** 注册 chart */
echartInstance = echarts.init(element, theme)
echartInstance = echarts.init(element, theme, {
/** 如果款度为 0, 则以 200px 填充 */
width: width === 0 ? 200 : undefined,
/** 如果高度为 0, 则以 200px 填充 */
height: height === 0 ? 200 : undefined,
})
echartInstanceRef.value = echartInstance
/** 设置 options 配置项 */
@ -373,13 +325,13 @@ const RayChart = defineComponent({
*/
const renderThemeChart = (bool?: boolean) => {
if (props.autoChangeTheme) {
bool ? renderChart('dark') : renderChart('')
bool ? renderChart('dark') : renderChart()
return void 0
}
if (!props.theme) {
renderChart('')
renderChart()
}
}
@ -431,9 +383,9 @@ const RayChart = defineComponent({
*
*/
if (props.autoChangeTheme || props.theme) {
themeValue.value ? renderChart('dark') : renderChart('')
themeValue.value ? renderChart('dark') : renderChart()
} else {
renderChart('')
renderChart()
}
},
)
@ -454,7 +406,7 @@ const RayChart = defineComponent({
() => props.watchOptions,
() => {
/** 重新组合 options */
const options = useMergeOptions()
const options = combineChartOptions()
/** 如果 options 发生变动更新 echarts */
echartInstance?.setOption(options)
@ -473,7 +425,7 @@ const RayChart = defineComponent({
if (props.autoChangeTheme) {
renderThemeChart(themeValue.value)
} else {
props.theme ? renderChart('dark') : renderChart('')
props.theme ? renderChart('dark') : renderChart()
}
/** 注册事件 */

View File

@ -0,0 +1,396 @@
{
"color": [
"#2ec7c9",
"#b6a2de",
"#5ab1ef",
"#ffb980",
"#d87a80",
"#8d98b3",
"#e5cf0d",
"#97b552",
"#95706d",
"#dc69aa",
"#07a2a4",
"#9a7fd1",
"#588dd5",
"#f5994e",
"#c05050",
"#59678c",
"#c9ab00",
"#7eb00a",
"#6f5553",
"#c14089"
],
"backgroundColor": "rgba(0,0,0,0)",
"textStyle": {},
"title": {
"textStyle": {
"color": "#008acd"
},
"subtextStyle": {
"color": "#aaaaaa"
}
},
"line": {
"itemStyle": {
"borderWidth": 1
},
"lineStyle": {
"width": 2
},
"symbolSize": 3,
"symbol": "emptyCircle",
"smooth": true
},
"radar": {
"itemStyle": {
"borderWidth": 1
},
"lineStyle": {
"width": 2
},
"symbolSize": 3,
"symbol": "emptyCircle",
"smooth": true
},
"bar": {
"itemStyle": {
"barBorderWidth": 0,
"barBorderColor": "#ccc"
}
},
"pie": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"scatter": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"boxplot": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"parallel": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"sankey": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"funnel": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"gauge": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"candlestick": {
"itemStyle": {
"color": "#d87a80",
"color0": "#2ec7c9",
"borderColor": "#d87a80",
"borderColor0": "#2ec7c9",
"borderWidth": 1
}
},
"graph": {
"itemStyle": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"lineStyle": {
"width": 1,
"color": "#aaa"
},
"symbolSize": 3,
"symbol": "emptyCircle",
"smooth": true,
"color": [
"#2ec7c9",
"#b6a2de",
"#5ab1ef",
"#ffb980",
"#d87a80",
"#8d98b3",
"#e5cf0d",
"#97b552",
"#95706d",
"#dc69aa",
"#07a2a4",
"#9a7fd1",
"#588dd5",
"#f5994e",
"#c05050",
"#59678c",
"#c9ab00",
"#7eb00a",
"#6f5553",
"#c14089"
],
"label": {
"color": "#eee"
}
},
"map": {
"itemStyle": {
"areaColor": "#dddddd",
"borderColor": "#eeeeee",
"borderWidth": 0.5
},
"label": {
"color": "#d87a80"
},
"emphasis": {
"itemStyle": {
"areaColor": "rgba(254,153,78,1)",
"borderColor": "#444",
"borderWidth": 1
},
"label": {
"color": "rgb(100,0,0)"
}
}
},
"geo": {
"itemStyle": {
"areaColor": "#dddddd",
"borderColor": "#eeeeee",
"borderWidth": 0.5
},
"label": {
"color": "#d87a80"
},
"emphasis": {
"itemStyle": {
"areaColor": "rgba(254,153,78,1)",
"borderColor": "#444",
"borderWidth": 1
},
"label": {
"color": "rgb(100,0,0)"
}
}
},
"categoryAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#008acd"
}
},
"axisTick": {
"show": true,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"color": "#333"
},
"splitLine": {
"show": false,
"lineStyle": {
"color": ["#eee"]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
}
}
},
"valueAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#008acd"
}
},
"axisTick": {
"show": true,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"color": "#333"
},
"splitLine": {
"show": true,
"lineStyle": {
"color": ["#eee"]
}
},
"splitArea": {
"show": true,
"areaStyle": {
"color": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
}
}
},
"logAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#008acd"
}
},
"axisTick": {
"show": true,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"color": "#333"
},
"splitLine": {
"show": true,
"lineStyle": {
"color": ["#eee"]
}
},
"splitArea": {
"show": true,
"areaStyle": {
"color": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
}
}
},
"timeAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#008acd"
}
},
"axisTick": {
"show": true,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"color": "#333"
},
"splitLine": {
"show": true,
"lineStyle": {
"color": ["#eee"]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": ["rgba(250,250,250,0.3)", "rgba(200,200,200,0.3)"]
}
}
},
"toolbox": {
"iconStyle": {
"borderColor": "#2ec7c9"
},
"emphasis": {
"iconStyle": {
"borderColor": "#18a4a6"
}
}
},
"legend": {
"textStyle": {
"color": "#333333"
}
},
"tooltip": {
"axisPointer": {
"lineStyle": {
"color": "#008acd",
"width": "1"
},
"crossStyle": {
"color": "#008acd",
"width": "1"
}
}
},
"timeline": {
"lineStyle": {
"color": "#008acd",
"width": 1
},
"itemStyle": {
"color": "#008acd",
"borderWidth": 1
},
"controlStyle": {
"color": "#008acd",
"borderColor": "#008acd",
"borderWidth": 0.5
},
"checkpointStyle": {
"color": "#2ec7c9",
"borderColor": "#2ec7c9"
},
"label": {
"color": "#008acd"
},
"emphasis": {
"itemStyle": {
"color": "#a9334c"
},
"controlStyle": {
"color": "#008acd",
"borderColor": "#008acd",
"borderWidth": 0.5
},
"label": {
"color": "#008acd"
}
}
},
"visualMap": {
"color": ["#5ab1ef", "#e0ffff"]
},
"dataZoom": {
"backgroundColor": "rgba(47,69,84,0)",
"dataBackgroundColor": "#efefff",
"fillerColor": "rgba(182,162,222,0.2)",
"handleColor": "#008acd",
"handleSize": "100%",
"textStyle": {
"color": "#333333"
}
},
"markPoint": {
"label": {
"color": "#eee"
},
"emphasis": {
"label": {
"color": "#eee"
}
}
}
}

View File

@ -0,0 +1,43 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-07-22
*
* @workspace ray-template
*
* @remark
*/
export interface ChartThemeRawModules {
default: Record<string, UnknownObjectKey>
}
export interface ChartThemeRawArray {
name: string
theme: UnknownObjectKey
}
export interface LoadingOptions {
text: string // 文本内容
color: string // 颜色
textColor: string // 字体颜色
maskColor: string // 遮罩颜色
zlevel: number // 水平
fontSize: number // 字体大小
showSpinner: boolean // 是否显示旋转动画(`spinner`)
spinnerRadius: number // 旋转动画(`spinner`)的半径
lineWidth: number // 旋转动画(`spinner`)的线宽
fontWeight: string // 字体粗细
fontStyle: string // 字体风格
fontFamily: string // 字体系列
}
export type AutoResize =
| boolean
| {
width: number
height: number
}
export type ChartTheme = 'dark' | string | object | 'macarons'

View File

@ -72,7 +72,6 @@ const RayCollapseGrid = defineComponent({
collapsed={this.modelCollapsed}
xGap={this.xGap || 12}
yGap={this.yGap || 18}
cols={this.cols}
collapsedRows={this.collapsedRows}
>
{this.$slots.default?.()}

View File

@ -2,7 +2,7 @@ import { gridProps } from 'naive-ui'
import type { PropType } from 'vue'
import type { CollapseToggleText } from './type'
import type { AnyFunc, MaybeArray } from '@/types/modules/utils'
import type { AnyFC, MaybeArray } from '@/types/modules/utils'
export const collapseGridProps = {
value: {

View File

@ -88,6 +88,7 @@ const RayIcon = defineComponent({
call(onClick, e)
}
}
return {
modelColor,
symbolId,

View File

@ -1,6 +1,15 @@
export type DayjsLocal = 'zh-cn' | 'en'
import type { AppCurrentAppMessages } from '@/locales/type'
export interface DayjsLocalMap {
'zh-CN': 'zh-cn'
'en-US': 'en'
type A<T> = {
[K in keyof T & string]: T[K] extends object ? string : never
}
type PickDayjsLocalValue<T> = {
[K in keyof T]: T[K]
}[keyof T]
type DayjsLocalMaps = A<AppCurrentAppMessages>
export type DayjsLocal = PickDayjsLocalValue<DayjsLocalMaps>
export type DayjsLocalMap = Record<keyof AppCurrentAppMessages, DayjsLocal>

View File

@ -27,7 +27,7 @@ import type { DirectiveModules } from '@/directives/type'
export const setupDirectives = (app: App<Element>) => {
// 获取 modules 包下所有的 index.ts 文件
const directiveRawModules: Record<string, DirectiveModules> =
import.meta.glob('./modules/**/index.ts', {
import.meta.glob('@/directives/modules/**/index.ts', {
eager: true,
})
// 将所有的包提取出来(./modules/[file-name]/index.ts)

View File

@ -52,4 +52,5 @@ const copyDirective: CustomDirectiveFC<CopyElement, string> = () => {
},
}
}
export default copyDirective

View File

@ -19,7 +19,7 @@ import { on, off } from '@use-utils/element'
import type { Directive } from 'vue'
import type { DebounceBindingOptions } from './type'
import type { AnyFunc } from '@/types/modules/utils'
import type { AnyFC } from '@/types/modules/utils'
import type { DebouncedFunc } from 'lodash-es'
import type { CustomDirectiveFC } from '@/directives/type'
@ -27,7 +27,7 @@ const debounceDirective: CustomDirectiveFC<
HTMLElement,
DebounceBindingOptions
> = () => {
let debounceFunction: DebouncedFunc<AnyFunc> | null
let debounceFunction: DebouncedFunc<AnyFC> | null
return {
beforeMount: (el, binding) => {

View File

@ -1,8 +1,8 @@
import type { DebounceSettings } from 'lodash-es'
import type { AnyFunc } from '@/types/modules/utils'
import type { AnyFC } from '@/types/modules/utils'
export interface DebounceBindingOptions {
func: AnyFunc
func: AnyFC
trigger: string
wait: number
options: DebounceSettings

View File

@ -42,4 +42,5 @@ const disabledDirective: CustomDirectiveFC<HTMLElement, boolean> = () => {
},
}
}
export default disabledDirective

View File

@ -19,7 +19,7 @@ import { on, off } from '@use-utils/element'
import type { Directive } from 'vue'
import type { ThrottleBindingOptions } from './type'
import type { AnyFunc } from '@/types/modules/utils'
import type { AnyFC } from '@/types/modules/utils'
import type { DebouncedFunc } from 'lodash-es'
import type { CustomDirectiveFC } from '@/directives/type'
@ -27,7 +27,7 @@ const throttleDirective: CustomDirectiveFC<
HTMLElement,
ThrottleBindingOptions
> = () => {
let throttleFunction: DebouncedFunc<AnyFunc> | null
let throttleFunction: DebouncedFunc<AnyFC> | null
return {
beforeMount: (el, binding) => {

View File

@ -1,8 +1,8 @@
import type { ThrottleSettings } from 'lodash-es'
import type { AnyFunc } from '@/types/modules/utils'
import type { AnyFC } from '@/types/modules/utils'
export interface ThrottleBindingOptions {
func: AnyFunc
func: AnyFC
trigger: string
wait: number
options: ThrottleSettings

View File

@ -36,7 +36,7 @@ const PageResult = defineComponent({
{{
...this.$slots,
footer: () => (
<NButton onClick={redirectRouterToDashboard.bind(this, false)}>
<NButton onClick={redirectRouterToDashboard.bind(this, true)}>
</NButton>
),

View File

@ -24,7 +24,7 @@ import TootipIcon from '@/layout/components/SiderBar/components/TooltipIcon/inde
import SettingDrawer from './components/SettingDrawer/index'
import Breadcrumb from './components/Breadcrumb/index'
import GlobalSeach from './components/GlobalSeach/index'
import AppAvatar from '@/components/AppComponents/AppAvatar/index'
import AppAvatar from '@/app-components/app/AppAvatar/index'
import { useSetting } from '@/store'
import { LOCAL_OPTIONS } from '@/appConfig/localConfig'

View File

@ -19,6 +19,7 @@ import './index.scss'
import RayTransitionComponent from '@/components/RayTransitionComponent/index.vue'
import { NSpin } from 'naive-ui'
import AppRequestCanceler from '@/app-components/provider/AppRequestCanceler/index'
import { useSetting } from '@/store'
@ -64,6 +65,7 @@ const ContentWrapper = defineComponent({
size="large"
themeOverrides={this.thmeOverridesSpin}
>
<AppRequestCanceler />
{this.reloadRouteSwitch ? (
<RayTransitionComponent
class="content-wrapper"

View File

@ -21,7 +21,7 @@ import FooterWrapper from '@/layout/default/FooterWrapper'
import { useSetting } from '@/store'
import { LAYOUT_CONTENT_REF } from '@/appConfig/routerConfig'
import { layoutHeaderCssVars } from '@/layout/layoutResize'
import useAppLockScreen from '@/components/AppComponents/AppLockScreen/appLockVar'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
const Layout = defineComponent({
name: 'RLayout',

View File

@ -26,7 +26,7 @@ import type { Recordable } from '@/types/modules/helper'
import type {
AppLocalesModules,
AppLocalesDropdownMixedOption,
CurrentAppMessages,
AppCurrentAppMessages,
I18nModules,
} from '@/locales/type'
@ -73,7 +73,7 @@ export const combineI18nMessages = (langs: I18nModules, prefix: string) => {
export const getAppLocalMessages = async (
LOCAL_OPTIONS: AppLocalesDropdownMixedOption[],
) => {
const message = {} as CurrentAppMessages
const message = {} as AppCurrentAppMessages
for (const curr of LOCAL_OPTIONS) {
const msg: AppLocalesModules = await import(`./lang/${curr.key}.ts`)
@ -132,5 +132,5 @@ export const getAppDefaultLanguage = () => {
SYSTEM_DEFAULT_LOCAL,
)
return language
return language as keyof AppCurrentAppMessages
}

View File

@ -6,7 +6,7 @@ import type {
} from 'naive-ui'
import type { Recordable } from '@/types/modules/helper'
export interface CurrentAppMessages {
export interface AppCurrentAppMessages {
'zh-CN': object
'en-US': object
}

View File

@ -22,7 +22,7 @@ import type { App as AppType } from 'vue'
const setupPlugins = async (inst: AppType<Element>) => {
await setupI18n(inst)
await setupStore(inst)
setupRouter(inst)
await setupRouter(inst)
setupDayjs()
setupDirectives(inst)
}

View File

@ -55,6 +55,7 @@ interface RouteMeta {
keepAlive?: boolean
sameLevel?: boolean
dev?: string | string[]
needCancel?: boolean
}
```

View File

@ -135,5 +135,5 @@ export const redirectRouterToDashboard = (isReplace = true) => {
setStorage('menuKey', path)
isReplace ? push(path) : replace(path)
isReplace ? replace(path) : push(path)
}

View File

@ -10,10 +10,10 @@ import type { RouteRecordRaw, Router } from 'vue-router'
export let router: Router
const createVueRouter = () => {
const createVueRouter = async () => {
return createRouter({
history: createWebHashHistory(),
routes: constantRoutes() as unknown as RouteRecordRaw[],
routes: (await constantRoutes()) as unknown as RouteRecordRaw[],
scrollBehavior: (to) => {
scrollViewToTop(to)
@ -26,8 +26,8 @@ const createVueRouter = () => {
}
// setup router
export const setupRouter = (app: App<Element>) => {
router = createVueRouter()
export const setupRouter = async (app: App<Element>) => {
router = await createVueRouter()
vueRouterRegister(router)
useVueRouter()

View File

@ -5,7 +5,7 @@ import { expandRoutes } from '@/router/helper/expandRoutes'
const { path } = ROOT_ROUTE
export default () => [
export default async () => [
{
path: '/',
name: 'login',

View File

@ -65,9 +65,13 @@ export const useKeepAlive = defineStore(
}
}
/** 获取当前缓存队列 */
const getKeepAliveInclude = () => state.keepAliveInclude
return {
...toRefs(state),
setKeepAliveInclude,
getKeepAliveInclude,
}
},
{

View File

@ -1,7 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type CryptoJS from 'crypto-js'
export type CacheType = 'sessionStorage' | 'localStorage'
export type StorageLike = 'sessionStorage' | 'localStorage'
export type RemoveStorageKey =
| string
| 'all'
| 'all-sessionStorage'
| 'all-localStorage'
export type EventListenerOrEventListenerObject =
| EventListener
@ -39,7 +45,7 @@ export type WordArray = CryptoJS.lib.WordArray
export type CipherParams = CryptoJS.lib.CipherParams
export type AnyFunc = (...args: any[]) => any
export type AnyFC = (...args: any[]) => any
export type AnyVoidFunc = (...args: any[]) => void

View File

@ -11,7 +11,7 @@
/** vue3 项目里建议直接用 vueuse useStorage 方法 */
import type { CacheType } from '@/types/modules/utils'
import type { StorageLike, RemoveStorageKey } from '@/types/modules/utils'
/**
*
@ -21,7 +21,7 @@ import type { CacheType } from '@/types/modules/utils'
function setStorage<T = unknown>(
key: string,
value: T,
type: CacheType = 'sessionStorage',
type: StorageLike = 'sessionStorage',
) {
if (!key) {
console.error('Failed to set stored data: key is empty or undefined')
@ -41,12 +41,16 @@ function setStorage<T = unknown>(
}
/** 重载函数 getStorage */
function getStorage<T>(key: string, storageType: CacheType, defaultValue: T): T
function getStorage<T>(
key: string,
storageType: StorageLike,
defaultValue: T,
): T
/** 重载函数 getStorage */
function getStorage<T>(
key: string,
storageType?: CacheType,
storageType?: StorageLike,
defaultValue?: T,
): T | null
@ -57,7 +61,7 @@ function getStorage<T>(
*/
function getStorage<T>(
key: string,
storageType: CacheType = 'sessionStorage',
storageType: StorageLike = 'sessionStorage',
defaultValue?: T,
): T | null {
try {
@ -88,8 +92,8 @@ function getStorage<T>(
* - all-localStorage: 删除所有 localStorage
*/
function removeStorage(
key: string | 'all' | 'all-sessionStorage' | 'all-localStorage',
type: CacheType = 'sessionStorage',
key: RemoveStorageKey,
type: StorageLike = 'sessionStorage',
) {
switch (key) {
case 'all':

View File

@ -32,7 +32,7 @@ import currency from 'currency.js'
import { cloneDeep } from 'lodash-es'
import type { Options } from 'currency.js'
import type { AnyFunc } from '@/types/modules/utils'
import type { AnyFC } from '@/types/modules/utils'
export type CurrencyArguments = string | number | currency
@ -49,7 +49,7 @@ export type OriginalValueType = 'string' | 'number'
const basic = (
valueOptions: CurrencyArguments[],
dividend: CurrencyArguments,
cb: AnyFunc,
cb: AnyFC,
) => {
if (!valueOptions?.length) {
return 0

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { AnyFunc, MaybeArray } from '@/types/modules/utils'
import type { AnyFC, MaybeArray } from '@/types/modules/utils'
function call(funcs: MaybeArray<() => void>): void
@ -26,7 +26,7 @@ function call<A1, A2, A3, A4>(
a4: A4,
): void
function call<A extends any[]>(funcs: AnyFunc[] | AnyFunc, ...args: A) {
function call<A extends any[]>(funcs: AnyFC[] | AnyFC, ...args: A) {
if (Array.isArray(funcs)) {
funcs.forEach((func) => (call as any)(func, ...args))
} else {

View File

@ -21,6 +21,7 @@ const Axios = defineComponent({
run: throttleDemoRun,
} = useHookPlusRequest(getTypicode, {
throttleWait: 1000,
manual: true,
})
const {
data: debounceDemoValue,
@ -28,6 +29,7 @@ const Axios = defineComponent({
run: debounceDemoRun,
} = useHookPlusRequest(getTypicode, {
debounceWait: 1000,
manual: true,
})
const {
data: weatherDemoValue,
@ -35,6 +37,7 @@ const Axios = defineComponent({
run: weatherDemoRun,
} = useHookPlusRequest(getWeather, {
throttleWait: 1000,
manual: true,
})
const {
data: demoData,
@ -46,6 +49,9 @@ const Axios = defineComponent({
{
url: 'https://jsonplaceholder.typicode.com/todos/1',
method: 'get',
cancelConfig: {
needCancel: true,
},
},
{
manual: true,

View File

@ -10,7 +10,7 @@ import {
NH6,
} from 'naive-ui'
import RayIcon from '@/components/RayIcon/index'
import RayLink from '@/components/RayLink/index'
import RayLink from '@/app-components/app/RayLink/index'
const Dashboard = defineComponent({
name: 'RDashboard',

View File

@ -35,6 +35,15 @@ const Echart = defineComponent({
color: 'rgba(180, 180, 180, 0.2)',
},
},
{
name: '数量',
data: [12, 220, 250, 180, 20, 10, 190],
type: 'bar',
showBackground: true,
backgroundStyle: {
color: 'rgba(180, 180, 180, 0.2)',
},
},
],
}
const basePieOptions = {

View File

@ -16,7 +16,7 @@ import Register from './components/Register/index'
import QRCodeSignin from './components/QRCodeSignin/index'
import SSOSignin from './components/SSOSignin/index'
import RayIcon from '@/components/RayIcon'
import RayLink from '@/components/RayLink/index'
import RayLink from '@/app-components/app/RayLink/index'
import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index'
import { useSetting } from '@/store'

View File

@ -27,16 +27,10 @@
},
"suppressImplicitAnyIndexErrors": true,
"typeRoots": ["./src/types/app.d.ts", "./src/types/global.d.ts"],
"types": [
"@intlify/unplugin-vue-i18n/messages",
"naive-ui/volar",
"vite/client",
"./src/types/global.d.ts"
],
"types": ["vite/client"],
"ignoreDeprecations": "5.0"
},
"include": [
"./src/types/global.d.ts",
"vite.config.ts",
"vite-plugin/index.ts",
"vite-plugin/type.ts",
@ -45,7 +39,6 @@
"vite-env.d.ts",
"components.d.ts",
"auto-imports.d.ts",
"src/**/*",
"./src/types/app.d.ts"
"src/**/*"
]
}