v3.3.1 细节补充

This commit is contained in:
ray_wuhao 2023-06-06 15:39:05 +08:00
parent 3a5923ee52
commit 75cd4c5a9f
19 changed files with 347 additions and 104 deletions

2
.gitignore vendored
View File

@ -14,6 +14,8 @@ dist
dist/ dist/
*.local *.local
visualizer.* visualizer.*
components.d.ts
auto-imports.d.ts
# Editor directories and files # Editor directories and files
.idea .idea

View File

@ -1,5 +1,34 @@
# CHANGE LOG # CHANGE LOG
## 3.3.1
### Feats
- 新增 useAppTheme sass 方法
```ts
useAppTheme key 类型: 'dark' | 'light'
```
```scss
// 暗色主题
.demo--dark {
@include useAppTheme('dark') {
color: #ffffff;
}
}
// 明亮主题
.demo--light {
@include useAppTheme('light') {
color: #000000;
}
}
```
- 一些细节优化
- axios 拦截器与 axios instance 进行独立(现在不再 instance.ts 文件中编写拦截器相关逻辑),拦截器逻辑放在 inject 包中
- 一些 bug 修复
## 3.3.0 ## 3.3.0
### 特征 ### 特征

1
components.d.ts vendored
View File

@ -7,7 +7,6 @@ export {}
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
RayTransitionComponent: typeof import('./src/components/RayTransitionComponent/TransitionComponent.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
TransitionComponent: typeof import('./src/components/RayTransitionComponent/TransitionComponent.vue')['default'] TransitionComponent: typeof import('./src/components/RayTransitionComponent/TransitionComponent.vue')['default']

View File

@ -1,7 +1,7 @@
{ {
"name": "ray-template", "name": "ray-template",
"private": false, "private": false,
"version": "3.3.1", "version": "3.3.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@ -0,0 +1,33 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-02
*
* @workspace ray-template
*
* @remark
*/
/** axios 拦截器工具 */
import type { RawAxiosRequestHeaders, AxiosRequestConfig } from 'axios'
import type { RequestHeaderOptions } from '../type'
/**
*
* @param instance axios instance
* @param options axios headers options
*
* @remark `axios`
*/
export const appendRequestHeaders = (
instance: AxiosRequestConfig<unknown>,
options: RequestHeaderOptions[],
) => {
const requestHeaders = instance.headers as RawAxiosRequestHeaders
options.forEach((curr) => {
requestHeaders[curr.key] = curr.value
})
}

View File

@ -2,32 +2,91 @@
* *
* @author Ray <https://github.com/XiaoDaiGua-Ray> * @author Ray <https://github.com/XiaoDaiGua-Ray>
* *
* @date 2023-06-02 * @date 2023-06-05
* *
* @workspace ray-template * @workspace ray-template
* *
* @remark * @remark
*/ */
/** axios 拦截器工具 */
import type { RawAxiosRequestHeaders, AxiosRequestConfig } from 'axios'
import type { RequestHeaderOptions } from '../type'
/** /**
* *
* @param instance axios instance * axios
* @param options axios headers options
* *
* @remark `axios` *
*
*
* create , emmmmmm
*/ */
export const appendRequestHeaders = (
instance: AxiosRequestConfig<unknown>,
options: RequestHeaderOptions[],
) => {
const requestHeaders = instance.headers as RawAxiosRequestHeaders
options.forEach((curr) => { import RequestCanceler from '@/axios/helper/canceler'
requestHeaders[curr.key] = curr.value
}) import type {
RequestInterceptorConfig,
ResponseInterceptorConfig,
ImplementKey,
ImplementQueue,
} from '@/axios/type'
const axiosFetchInstance = {
requestInstance: null as RequestInterceptorConfig | null,
responseInstance: null as ResponseInterceptorConfig | null,
}
const implement: ImplementQueue = {
implementRequestInterceptorArray: [],
implementResponseInterceptorArray: [],
}
export const axiosCanceler = new RequestCanceler()
export const useAxiosInterceptor = () => {
const getImplementKey = (key: ImplementKey) => {
return key === 'requestInstance'
? 'implementRequestInterceptorArray'
: 'implementResponseInterceptorArray'
}
const createRequestAxiosInstance = (instance: RequestInterceptorConfig) => {
axiosFetchInstance['requestInstance'] = instance
}
const createResponseAxiosInstance = (instance: ResponseInterceptorConfig) => {
axiosFetchInstance['responseInstance'] = instance
}
/** 请求前, 执行队列所有方法 */
const beforeAxiosFetch = (key: ImplementKey) => {
const funcArr = implement[getImplementKey(key)]
funcArr?.forEach((curr) => {
if (typeof curr === 'function') {
curr()
}
})
}
/** 设置拦截器队列 */
const setImplementQueue = (func: AnyFunc[], key: ImplementKey) => {
if (func && key) {
implement[getImplementKey(key)] = func
}
}
/** 获取拦截器队列 */
const getImplementQueue = (key: ImplementKey) => {
return implement[getImplementKey(key)]
}
/** 获取请求实例或者响应实例 */
const getAxiosFetchInstance = (key: ImplementKey) => {
return axiosFetchInstance[key]
}
return {
createRequestAxiosInstance,
createResponseAxiosInstance,
beforeAxiosFetch,
setImplementQueue,
getImplementQueue,
getAxiosFetchInstance,
}
} }

View File

@ -0,0 +1,48 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-06
*
* @workspace ray-template
*
* @remark
*/
/** 请求拦截器入口 */
import { useAxiosInterceptor, axiosCanceler } from '@/axios/helper/interceptor'
import { appendRequestHeaders } from '@/axios/helper/axiosCopilot'
import type { RequestInterceptorConfig } from '@/axios/type'
const { getAxiosFetchInstance, setImplementQueue } = useAxiosInterceptor()
/** 注入请求头信息 */
const injectRequestHeaders = () => {
const request = getAxiosFetchInstance(
'requestInstance',
) as RequestInterceptorConfig
appendRequestHeaders(request, [
{
key: 'X-TOKEN',
value: 'token',
},
])
}
/** 注入重复请求拦截器 */
const injectCanceler = () => {
const request = getAxiosFetchInstance(
'requestInstance',
) as RequestInterceptorConfig
axiosCanceler.removePendingRequest(request) // 检查是否存在重复请求, 若存在则取消已发的请求
axiosCanceler.addPendingRequest(request) // 把当前的请求信息添加到 pendingRequest 表中
}
/** 注册请求拦截器 */
export const setupRequestInterceptor = () => {
setImplementQueue([injectRequestHeaders, injectCanceler], 'requestInstance')
}

View File

@ -0,0 +1,32 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-06
*
* @workspace ray-template
*
* @remark
*/
/** 响应拦截器入口 */
import { useAxiosInterceptor, axiosCanceler } from '@/axios/helper/interceptor'
import type { ResponseInterceptorConfig } from '@/axios/type'
const { getAxiosFetchInstance, setImplementQueue } = useAxiosInterceptor()
/** 响应成功后移除缓存请求 url */
const injectResponseCanceler = () => {
const response = getAxiosFetchInstance(
'responseInstance',
) as ResponseInterceptorConfig
axiosCanceler.removePendingRequest(response.config)
}
/** 注册响应拦截器 */
export const setupResponseInterceptor = () => {
setImplementQueue([injectResponseCanceler], 'responseInstance')
}

View File

@ -12,43 +12,30 @@
/** /**
* *
* , * ,
* * , inject
* *
*/ */
import axios from 'axios' import axios from 'axios'
import { getDetermineEnv } from '@use-utils/hook'
import RequestCanceler from './helper/canceler'
import { AXIOS_CONFIG } from '@/appConfig/requestConfig' import { AXIOS_CONFIG } from '@/appConfig/requestConfig'
import { appendRequestHeaders } from './helper/interceptor' import { useAxiosInterceptor, axiosCanceler } from '@/axios/helper/interceptor'
import { setupRequestInterceptor } from '@/axios/inject/requestInject'
import { setupResponseInterceptor } from '@/axios/inject/responseInject'
import type { AxiosInstanceExpand } from './type' import type { AxiosInstanceExpand } from './type'
const canceler = new RequestCanceler()
const server: AxiosInstanceExpand = axios.create(AXIOS_CONFIG) const server: AxiosInstanceExpand = axios.create(AXIOS_CONFIG)
const {
createRequestAxiosInstance,
createResponseAxiosInstance,
beforeAxiosFetch,
} = useAxiosInterceptor()
server.interceptors.request.use( server.interceptors.request.use(
(request) => { (request) => {
const { MODE } = getDetermineEnv() createRequestAxiosInstance(request)
setupRequestInterceptor()
if (MODE === 'development') { beforeAxiosFetch('requestInstance')
// TODO: 开发环境
} else if (MODE === 'production') {
// TODO: 生产环境
} else if (MODE === 'test') {
// TODO: 测试环境
}
appendRequestHeaders(request, [
{
key: 'X-TOKEN',
value: 'token',
},
]) // 自定义请求头
canceler.removePendingRequest(request) // 检查是否存在重复请求, 若存在则取消已发的请求
canceler.addPendingRequest(request) // 把当前的请求信息添加到 pendingRequest 表中
return request return request
}, },
@ -59,14 +46,16 @@ server.interceptors.request.use(
server.interceptors.response.use( server.interceptors.response.use(
(response) => { (response) => {
canceler.removePendingRequest(response.config) createResponseAxiosInstance(response)
setupResponseInterceptor()
beforeAxiosFetch('responseInstance')
const { data } = response const { data } = response
return Promise.resolve(data) return Promise.resolve(data)
}, },
(error) => { (error) => {
canceler.removePendingRequest(error.config || {}) axiosCanceler.removePendingRequest(error.config || {})
return Promise.reject(error) return Promise.reject(error)
}, },

View File

@ -1,9 +1,12 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { import type {
AxiosHeaders, AxiosHeaders,
AxiosRequestConfig, AxiosRequestConfig,
HeadersDefaults, HeadersDefaults,
AxiosDefaults, AxiosDefaults,
Axios, Axios,
InternalAxiosRequestConfig,
AxiosResponse,
} from 'axios' } from 'axios'
export type AxiosHeaderValue = export type AxiosHeaderValue =
@ -20,56 +23,50 @@ export interface RequestHeaderOptions {
} }
export interface AxiosInstanceExpand extends Axios { export interface AxiosInstanceExpand extends Axios {
<T = unknown, D = unknown>(config: AxiosRequestConfig<D>): Promise<T> <T = any, D = any>(config: AxiosRequestConfig<D>): Promise<T>
<T = unknown, D = unknown>( <T = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<T>
url: string,
config?: AxiosRequestConfig<D>,
): Promise<T>
getUri(config?: AxiosRequestConfig): string getUri(config?: AxiosRequestConfig): string
request<R = unknown, D = unknown>(config: AxiosRequestConfig<D>): Promise<R> request<R = any, D = any>(config: AxiosRequestConfig<D>): Promise<R>
get<R = unknown, D = unknown>( get<R = any, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>
delete<R = any, D = any>(
url: string, url: string,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
delete<R = unknown, D = unknown>( head<R = any, D = any>(
url: string, url: string,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
head<R = unknown, D = unknown>( options<R = any, D = any>(
url: string, url: string,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
options<R = unknown, D = unknown>( post<R = any, D = any>(
url: string,
config?: AxiosRequestConfig<D>,
): Promise<R>
post<R = unknown, D = unknown>(
url: string, url: string,
data?: D, data?: D,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
put<R = unknown, D = unknown>( put<R = any, D = any>(
url: string, url: string,
data?: D, data?: D,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
patch<R = unknown, D = unknown>( patch<R = any, D = any>(
url: string, url: string,
data?: D, data?: D,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
postForm<R = unknown, D = unknown>( postForm<R = any, D = any>(
url: string, url: string,
data?: D, data?: D,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
putForm<R = unknown, D = unknown>( putForm<R = any, D = any>(
url: string, url: string,
data?: D, data?: D,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
): Promise<R> ): Promise<R>
patchForm<R = unknown, D = unknown>( patchForm<R = any, D = any>(
url: string, url: string,
data?: D, data?: D,
config?: AxiosRequestConfig<D>, config?: AxiosRequestConfig<D>,
@ -81,3 +78,14 @@ export interface AxiosInstanceExpand extends Axios {
} }
} }
} }
export type RequestInterceptorConfig<T = any> = InternalAxiosRequestConfig<T>
export type ResponseInterceptorConfig<T = any, K = any> = AxiosResponse<T, K>
export type ImplementKey = 'requestInstance' | 'responseInstance'
export interface ImplementQueue {
implementRequestInterceptorArray: AnyFunc[]
implementResponseInterceptorArray: AnyFunc[]
}

View File

@ -58,6 +58,10 @@
& .current-date span { & .current-date span {
font-size: 1.5rem; font-size: 1.5rem;
} }
// & .current-year span {
// font-size: 0.75rem;
// }
} }
} }
} }

View File

@ -9,6 +9,16 @@
* @remark * @remark
*/ */
/**
*
* ,
*
*
* @deprecated
* ,
* , 使
*/
import './index.scss' import './index.scss'
import { NModal, NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui' import { NModal, NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui'
@ -35,19 +45,19 @@ const LockScreen = defineComponent({
const { changeSwitcher } = settingStore const { changeSwitcher } = settingStore
const { logout } = signinStore const { logout } = signinStore
const TIME_FORMAT = 'HH:mm' const HH_MM_FORMAT = 'HH:mm'
const AM_PM_FORMAT = 'A' const AM_PM_FORMAT = 'A'
const YEAR_FORMAT = 'YY-MM-DD' const YY_MM_DD_FORMAT = 'YY年MM月DD日'
const DATE_FORMAT = 'dddd' const DDD_FORMAT = 'ddd'
const state = reactive({ const state = reactive({
lockCondition: { lockCondition: {
pwd: null, pwd: null,
}, },
time: dayjs().format(TIME_FORMAT), HH_MM: dayjs().format(HH_MM_FORMAT),
second: dayjs().locale('en').format(AM_PM_FORMAT), AM_PM: dayjs().locale('en').format(AM_PM_FORMAT),
year: dayjs().format(YEAR_FORMAT), YY_MM_DD: dayjs().format(YY_MM_DD_FORMAT),
date: dayjs().format(DATE_FORMAT), DDD: dayjs().format(DDD_FORMAT),
}) })
const rules = { const rules = {
pwd: { pwd: {
@ -77,12 +87,12 @@ const LockScreen = defineComponent({
} }
const dayInterval = setInterval(() => { const dayInterval = setInterval(() => {
state.time = dayjs().format(TIME_FORMAT) state.HH_MM = dayjs().format(HH_MM_FORMAT)
state.second = dayjs().format(AM_PM_FORMAT) state.AM_PM = dayjs().format(AM_PM_FORMAT)
}, 60_000) }, 60_000)
const yearInterval = setInterval(() => { const yearInterval = setInterval(() => {
state.year = dayjs().format(YEAR_FORMAT) state.YY_MM_DD = dayjs().format(YY_MM_DD_FORMAT)
state.date = dayjs().format(DATE_FORMAT) state.DDD = dayjs().format(DDD_FORMAT)
}, 86_400_000) }, 86_400_000)
const handleBackToSignin = () => { const handleBackToSignin = () => {
@ -190,8 +200,8 @@ const LockScreen = defineComponent({
<div class="lock-screen"> <div class="lock-screen">
<div class="lock-screen__content"> <div class="lock-screen__content">
<div class="lock-screen__content-bg"> <div class="lock-screen__content-bg">
<div class="left">{this.time?.split(':')[0]}</div> <div class="left">{this.HH_MM?.split(':')[0]}</div>
<div class="right">{this.time?.split(':')[1]}</div> <div class="right">{this.HH_MM?.split(':')[1]}</div>
</div> </div>
<div class="lock-screen__content-avatar"> <div class="lock-screen__content-avatar">
<AppAvatar vertical align="center" avatarSize={52} /> <AppAvatar vertical align="center" avatarSize={52} />
@ -233,10 +243,10 @@ const LockScreen = defineComponent({
</div> </div>
<div class="lock-screen__content-date"> <div class="lock-screen__content-date">
<div class="current-date"> <div class="current-date">
{this.time}&nbsp;<span>{this.second}</span> {this.HH_MM}&nbsp;<span>{this.AM_PM}</span>
</div> </div>
<div class="current-year"> <div class="current-year">
{this.year}&nbsp;{this.date} {this.YY_MM_DD}&nbsp;<span>{this.DDD}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -35,11 +35,13 @@
} }
} }
.ray-template--dark { .ray-table__table-size--dark {
& .table-size__dropdown-wrapper { @include useAppTheme("dark") {
& .dropdown-item:hover { & .table-size__dropdown-wrapper {
background-color: var(--ray-theme-primary-fade-color); & .dropdown-item:hover {
color: var(--ray-theme-primary-color); background-color: var(--ray-theme-primary-fade-color);
color: var(--ray-theme-primary-color);
}
} }
} }
} }

View File

@ -92,7 +92,10 @@ const TableSize = defineComponent({
</NPopover> </NPopover>
), ),
default: () => ( default: () => (
<NCard bordered={false} class="ray-table__table-size"> <NCard
bordered={false}
class="ray-table__table-size ray-table__table-size--dark ray-table__table-size--light"
>
<div class="table-size__dropdown"> <div class="table-size__dropdown">
<div class="table-size__dropdown-wrapper"> <div class="table-size__dropdown-wrapper">
{this.sizeOptions.map((curr) => ( {this.sizeOptions.map((curr) => (

View File

@ -67,29 +67,33 @@ $globalSearchWidth: 650px;
} }
} }
.ray-template--dark { .global-seach--dark {
& .global-seach__card { @include useAppTheme("dark") {
background-color: #242424; & .global-seach__card {
background-color: #242424;
& .global-seach__card-content .content-item { & .global-seach__card-content .content-item {
background-color: #2f2f2f; background-color: #2f2f2f;
&:hover { &:hover {
background-color: var(--ray-theme-primary-fade-color); background-color: var(--ray-theme-primary-fade-color);
}
} }
} }
} }
} }
.ray-template--light { .global-seach--light {
& .global-seach__card { @include useAppTheme("light") {
background-color: #f9f9f9; & .global-seach__card {
background-color: #f9f9f9;
& .global-seach__card-content .content-item { & .global-seach__card-content .content-item {
background-color: #ffffff; background-color: #ffffff;
&:hover { &:hover {
background-color: var(--ray-theme-primary-fade-color); background-color: var(--ray-theme-primary-fade-color);
}
} }
} }
} }

View File

@ -139,7 +139,7 @@ const GlobalSeach = defineComponent({
render() { render() {
return ( return (
<NModal v-model:show={this.modelShow} transform-origin="center" show> <NModal v-model:show={this.modelShow} transform-origin="center" show>
<div class="global-seach"> <div class="global-seach global-seach--dark global-seach--light">
<div class="global-seach__wrapper"> <div class="global-seach__wrapper">
<div class="global-seach__card"> <div class="global-seach__card">
<div class="global-seach__card-header"> <div class="global-seach__card-header">

View File

@ -40,3 +40,10 @@
cursor: pointer; cursor: pointer;
} }
} }
// 根据主题切换样式
@mixin useAppTheme($theme) {
body[class="ray-template--#{$theme}"] & {
@content;
}
}

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export {} export {}
import type CryptoJS from 'crypto-js' import type CryptoJS from 'crypto-js'
@ -32,7 +33,7 @@ export global {
declare type CipherParams = CryptoJS.lib.CipherParams declare type CipherParams = CryptoJS.lib.CipherParams
declare type VoidFunc = (...args: unknown[]) => void declare type VoidFunc = (...args: any[]) => void
declare type AnyFunc = (...args: unknown[]) => unknown declare type AnyFunc = (...args: any[]) => any
} }

View File

@ -1,3 +1,16 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-05
*
* @workspace ray-template
*
* @remark
*/
/** vue3 项目里建议直接用 vueuse useStorage 方法 */
/** /**
* *
* @param key key * @param key key