v4.1.9部分细节补充

This commit is contained in:
XiaoDaiGua-Ray 2023-09-08 15:13:36 +08:00
parent 689813f1a0
commit 6acc80f18a
43 changed files with 98 additions and 110 deletions

View File

@ -10,6 +10,8 @@
- 移除 qrcode.vue 依赖
- 更新 vue-hooks-plus 版本至 v1.8.2
- 移除 office 功能集成
- 统一包命名方式
- 更改 v-copy 实现细节(使用方式不变)
### Fixes

View File

@ -12,14 +12,16 @@
## ✨ 特性
- **最新技术栈**:使用 Vue3.x/vite4.x 等前端前沿技术开发
- **最新技术栈**:使用 vue3.x/vite4.x/pinia 等前端前沿技术开发
- **TypeScript**:应用程序级 JavaScript 的语言
- **主题**:可配置的主题
- **国际化**:内置完善的国际化方案
- **Mock 数据**:内置 Mock 数据方案
- **权限**:内置完善的动态路由权限生成方案
- **组件**:二次封装了多个常用的组件
- **Axios 请求**:二次封装 axios 库
- **Axios 请求**:二次封装 axios 库,支持:取消、防抖、自动重复取消等功能
- **缓存**:任意深度页面缓存
- **SVG**:内置 svg icon 解决方案
## 🪄 预览地址
@ -37,7 +39,7 @@
## 🪴 准备
- [node](http://nodejs.org/) 和 [git](https://git-scm.com/) -项目开发环境
- [Node](http://nodejs.org/) 和 [git](https://git-scm.com/) - 项目开发环境
- [Vite](https://vitejs.dev/) - 熟悉 vite 特性
- [Vue3](https://v3.vuejs.org/) - 熟悉 Vue 基础语法
- [TypeScript](https://www.typescriptlang.org/) - 熟悉 TypeScript 基本语法
@ -63,73 +65,33 @@ git clone https://gh.yka.moe/https://github.com/XiaoDaiGua-Ray/ray-template.git
### 拉取依赖
```sh
# pnpm
pnpm
```
```sh
# npm
npm install
```
### 启动项目
```sh
# pnpm
pnpm dev
```
```sh
# npm
npm run dev
```
### 项目打包
```sh
# pnpm
pnpm build
```
```sh
# npm
npm run build
```
### 预览项目
```sh
# pnpm
pnpm preview
```
```sh
# npm
npm run preview
```
### 体积分析
```sh
# pnpm
pnpm report
```
```sh
# npm
npm run report
```
## 🪴 项目活动
![Alt](https://repobeats.axiom.co/api/embed/fab6071297ab281913a42f07a2779b488cfd62b8.svg 'Repobeats analytics image')
@ -150,4 +112,4 @@ npm run report
## 📄 证书
[MIT License](https://github.com/XiaoDaiGua-Ray/ray-template/blob/main/LICENSE) © 2022-PRESENT [Ray](https://github.com/XiaoDaiGua-Ray/ray-template)
[MIT License](https://github.com/XiaoDaiGua-Ray/ray-template/blob/main/LICENSE) © 2022-PRESENT [Ray](https://github.com/XiaoDaiGua-Ray)

4
cfg.ts
View File

@ -43,8 +43,8 @@ import {
buildOptions,
mixinCSSPlugin,
} from './vite-plugin/index'
import { APP_THEME } from './src/appConfig/designConfig'
import { PRE_LOADING_CONFIG, SIDE_BAR_LOGO } from './src/appConfig/appConfig'
import { APP_THEME } from './src/app-config/designConfig'
import { PRE_LOADING_CONFIG, SIDE_BAR_LOGO } from './src/app-config/appConfig'
import type { AppConfigExport } from '@/types/modules/cfg'

View File

@ -22,7 +22,7 @@ import './index.scss'
import { NAvatar, NSpace } from 'naive-ui'
import { avatarProps, spaceProps } from 'naive-ui'
import { APP_CATCH_KEY } from '@/appConfig/appConfig'
import { APP_CATCH_KEY } from '@/app-config/appConfig'
import { getStorage } from '@/utils/cache'
import type { PropType } from 'vue'

View File

@ -31,9 +31,9 @@ import {
import { useSetting } from '@/store'
import { naiveLocales } from '@/locales/helper'
const GlobalProvider = defineComponent({
export default defineComponent({
name: 'GlobalProvider',
setup() {
setup(_, { expose }) {
const settingStore = useSetting()
const modelPrimaryColorOverride = computed(
@ -54,6 +54,7 @@ const GlobalProvider = defineComponent({
configProviderProps: computed(() => ({
theme: modelThemeValue.value,
})),
notificationProviderProps: {},
},
)
@ -62,6 +63,8 @@ const GlobalProvider = defineComponent({
window.$loadingBar = loadingBar // 注入 `loadingBar`
window.$notification = notification // 注入 `notification`
expose()
return {
modelPrimaryColorOverride,
modelThemeValue,
@ -90,5 +93,3 @@ const GlobalProvider = defineComponent({
)
},
})
export default GlobalProvider

View File

@ -19,12 +19,14 @@
import { axiosCanceler } from '@/axios/helper/interceptor'
const AppRequestCanceler = defineComponent({
name: 'AppRequestCanceler',
setup() {
const AppRequestCancelerProvider = defineComponent({
name: 'AppRequestCancelerProvider',
setup(_, { expose }) {
onBeforeRouteUpdate(() => {
axiosCanceler.cancelAllRequest()
})
expose()
},
render() {
return (
@ -37,4 +39,4 @@ const AppRequestCanceler = defineComponent({
},
})
export default AppRequestCanceler
export default AppRequestCancelerProvider

View File

@ -20,7 +20,7 @@ import type { SettingState } from '@/store/modules/setting/type'
const AppStyleProvider = defineComponent({
name: 'AppStyleProvider',
setup() {
setup(_, { expose }) {
const settingStore = useSetting()
const { themeValue } = storeToRefs(settingStore)
@ -97,6 +97,8 @@ const AppStyleProvider = defineComponent({
immediate: true,
},
)
expose()
},
render() {
return <div class="app-style-provider"></div>

View File

@ -20,7 +20,7 @@
import { useAxiosInterceptor, axiosCanceler } from '@/axios/helper/interceptor'
import { appendRequestHeaders } from '@/axios/helper/axiosCopilot'
import { APP_CATCH_KEY } from '@/appConfig/appConfig'
import { APP_CATCH_KEY } from '@/app-config/appConfig'
import { getStorage } from '@/utils/cache'
import type {

View File

@ -17,7 +17,7 @@
*/
import axios from 'axios'
import { AXIOS_CONFIG } from '@/appConfig/requestConfig'
import { AXIOS_CONFIG } from '@/app-config/requestConfig'
import { useAxiosInterceptor, axiosCanceler } from '@/axios/helper/interceptor'
import {
setupResponseInterceptor,

View File

@ -46,7 +46,7 @@ import { cloneDeep, throttle } from 'lodash-es'
import { on, off, completeSize } from '@/utils/element'
import { call } from '@/utils/vue/index'
import { setupChartTheme, loadingOptions } from './helper'
import { APP_THEME } from '@/appConfig/designConfig'
import { APP_THEME } from '@/app-config/designConfig'
import type { PropType } from 'vue'
import type { AnyFC, MaybeArray } from '@/types/modules/utils'

View File

@ -19,11 +19,9 @@ import { AwesomeQR } from 'awesome-qr'
import { isValueType, downloadBase64File } from '@use-utils/hook'
import { call } from '@/utils/vue/index'
import type { QRCodeRenderResponse } from './type'
import type { QRCodeRenderResponse, GIFBuffer } from './type'
const readGIFAsArrayBuffer = (
url: string,
): Promise<string | ArrayBuffer | null> => {
const readGIFAsArrayBuffer = (url: string): Promise<GIFBuffer> => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
@ -50,7 +48,7 @@ const readGIFAsArrayBuffer = (
})
}
const RayQRcode = defineComponent({
export default defineComponent({
name: 'RayQRcode',
props,
setup(props, ctx) {
@ -60,7 +58,7 @@ const RayQRcode = defineComponent({
const spinOverrides = {
opacitySpinning: '0.1',
}
let gifBuffer: string | ArrayBuffer | null
let gifBuffer: GIFBuffer
const getGIFImageByURL = async () => {
const { gifBackgroundURL } = props
@ -77,7 +75,7 @@ const RayQRcode = defineComponent({
}
const renderQRCode = () => {
const { gifBackgroundURL, gifBackground, ...ops } = props
const { gifBackground, ...ops } = props
new AwesomeQR({
...ops,
@ -149,6 +147,7 @@ const RayQRcode = defineComponent({
<NSpin
show={this.status === 'loading'}
themeOverrides={this.spinOverrides}
description={this.loadingDescription}
>
<img src={this.qrcodeURL as string | undefined} />
</NSpin>
@ -184,5 +183,3 @@ const RayQRcode = defineComponent({
)
},
})
export default RayQRcode

View File

@ -15,6 +15,15 @@ import type { MaybeArray } from '@/types/modules/utils'
import type { Options } from 'awesome-qr'
const props = {
loadingDescription: {
/**
*
* Loading status description label
*
* @default undefined
*/
type: String,
},
watchText: {
/**
*

View File

@ -24,3 +24,5 @@ export type QRCodeInst = {
*/
downloadQRCode: (fileName?: string) => void
}
export type GIFBuffer = string | ArrayBuffer | null

View File

@ -24,7 +24,7 @@
</template>
<script lang="ts" setup>
import { useKeepAlive } from '@/store'
import { APP_KEEP_ALIVE } from '@/appConfig/appConfig'
import { APP_KEEP_ALIVE } from '@/app-config/appConfig'
import type { PropType } from 'vue'

View File

@ -10,7 +10,7 @@
*/
import dayjs from 'dayjs'
import { DEFAULT_DAYJS_LOCAL, DAYJS_LOCAL_MAP } from '@/appConfig/localConfig'
import { DEFAULT_DAYJS_LOCAL, DAYJS_LOCAL_MAP } from '@/app-config/localConfig'
import 'dayjs/locale/zh-cn'
import type { DayjsLocal } from './type'

View File

@ -20,31 +20,36 @@ import type { CopyElement } from './type'
import type { CustomDirectiveFC } from '@/directives/type'
const copyDirective: CustomDirectiveFC<CopyElement, string> = () => {
let clipboard: ClipboardJS | null
return {
mounted: (el, { value }) => {
clipboard = new ClipboardJS(el, {
const clipboard = new ClipboardJS(el, {
text: () => value,
})
clipboard?.on('success', () => {
clipboard.on('success', () => {
window.$message.success('复制成功')
})
clipboard?.on('error', () => {
clipboard.on('error', () => {
window.$message.error('复制失败')
})
},
updated: (el, { value }) => {
/** 其实这块代码写的挺蠢的, 但是我目前不知道怎么去优化, 阿巴阿巴阿巴 */
clipboard = new ClipboardJS(el, {
text: () => value,
})
},
beforeUnmount: () => {
clipboard?.destroy()
clipboard = null
el.$$clipboard = clipboard
},
updated: (el, { value, oldValue }) => {
if (value !== oldValue) {
el.$$clipboard?.destroy()
el.$$clipboard = new ClipboardJS(el, {
text: () => value,
})
}
},
beforeUnmount: (el: CopyElement) => {
if (el.$$clipboard) {
el.$$clipboard?.destroy()
el.$$clipboard = null
}
},
}
}

View File

@ -1,3 +1,6 @@
import type ClipboardJS from 'clipboard'
export interface CopyElement extends Element, UnknownObjectKey {
$value: string
$$clipboard: ClipboardJS | null
}

View File

@ -13,7 +13,7 @@ import { NMenu, NLayoutSider } from 'naive-ui'
import SiderBarLogo from './components/SiderBarLogo/index'
import { useMenu } from '@/store'
import { APP_MENU_CONFIG } from '@/appConfig/appConfig'
import { APP_MENU_CONFIG } from '@/app-config/appConfig'
import type { MenuInst } from 'naive-ui'
import type { NaiveMenuOptions } from '@/types/modules/component'

View File

@ -32,7 +32,7 @@ import { useMenu, useSetting } from '@/store'
import { uuid } from '@/utils/hook'
import { hasClass } from '@/utils/element'
import { redirectRouterToDashboard } from '@/router/helper/routerCopilot'
import { ROOT_ROUTE } from '@/appConfig/appConfig'
import { ROOT_ROUTE } from '@/app-config/appConfig'
import { queryElements } from '@use-utils/element'
import type { MenuOption, ScrollbarInst } from 'naive-ui'

View File

@ -13,7 +13,7 @@ import {
} from 'naive-ui'
import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index'
import { APP_THEME } from '@/appConfig/designConfig'
import { APP_THEME } from '@/app-config/designConfig'
import { useSetting } from '@/store'
import { useI18n } from '@/locales/useI18n'

View File

@ -28,7 +28,7 @@ import GlobalSeach from './components/GlobalSeach/index'
import AppAvatar from '@/app-components/app/AppAvatar/index'
import { useSetting } from '@/store'
import { LOCAL_OPTIONS } from '@/appConfig/localConfig'
import { LOCAL_OPTIONS } from '@/app-config/localConfig'
import { useAvatarOptions, avatarDropdownClick } from './hook'
import screenfull from 'screenfull'
import { useI18n } from '@/locales/useI18n'

View File

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

View File

@ -19,7 +19,7 @@ import HeaderWrapper from './default/HeaderWrapper'
import FeatureWrapper from './default/FeatureWrapper'
import { useSetting } from '@/store'
import { LAYOUT_CONTENT_REF } from '@/appConfig/routerConfig'
import { LAYOUT_CONTENT_REF } from '@/app-config/routerConfig'
import { layoutHeaderCssVars } from '@/layout/layoutResize'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'

View File

@ -19,8 +19,8 @@
import { set } from 'lodash-es'
import { zhCN, dateZhCN } from 'naive-ui' // 导入 `naive ui` 中文包
import { getStorage } from '@use-utils/cache'
import { SYSTEM_DEFAULT_LOCAL } from '@/appConfig/localConfig'
import { APP_CATCH_KEY } from '@/appConfig/appConfig'
import { SYSTEM_DEFAULT_LOCAL } from '@/app-config/localConfig'
import { APP_CATCH_KEY } from '@/app-config/appConfig'
import type { Recordable } from '@/types/modules/helper'
import type {

View File

@ -24,7 +24,7 @@
*/
import { createI18n } from 'vue-i18n'
import { LOCAL_OPTIONS } from '@/appConfig/localConfig'
import { LOCAL_OPTIONS } from '@/app-config/localConfig'
import { getAppDefaultLanguage, getAppLocalMessages } from '@/locales/helper'
import type { App } from 'vue'

View File

@ -1,6 +1,6 @@
{
"Register": "注册",
"Signin": "登",
"Signin": "登",
"QRCodeSignin": "扫码登陆",
"NamePlaceholder": "请输入用户名",
"PasswordPlaceholder": "请输入密码",

View File

@ -18,7 +18,7 @@
* router routerCopilot
*/
import { LAYOUT_CONTENT_REF } from '@/appConfig/routerConfig'
import { LAYOUT_CONTENT_REF } from '@/app-config/routerConfig'
import type { RouteLocationNormalized } from 'vue-router'
import type { AppRouteRecordRaw, RouteModules } from '@/router/type'

View File

@ -21,9 +21,9 @@
*/
import { getStorage } from '@/utils/cache'
import { APP_CATCH_KEY, ROOT_ROUTE } from '@/appConfig/appConfig'
import { APP_CATCH_KEY, ROOT_ROUTE } from '@/app-config/appConfig'
import { redirectRouterToDashboard } from '@/router/helper/routerCopilot'
import { WHITE_ROUTES } from '@/appConfig/routerConfig'
import { WHITE_ROUTES } from '@/app-config/routerConfig'
import { validRole } from '@/router/helper/routerCopilot'
import { isValueType } from '@/utils/hook'

View File

@ -10,10 +10,10 @@
*/
import { permissionRouter } from './permission'
import { SETUP_ROUTER_ACTION, SUPER_ADMIN } from '@/appConfig/routerConfig'
import { SETUP_ROUTER_ACTION, SUPER_ADMIN } from '@/app-config/routerConfig'
import { useSignin } from '@/store'
import { useVueRouter } from '@/router/helper/useVueRouter'
import { ROOT_ROUTE } from '@/appConfig/appConfig'
import { ROOT_ROUTE } from '@/app-config/appConfig'
import { setStorage } from '@/utils/cache'
import { getAppEnvironment } from '@/utils/hook'

View File

@ -1,6 +1,6 @@
import Layout from '@/layout/index'
import { getAppRawRoutes } from './routeModules'
import { ROOT_ROUTE } from '@/appConfig/appConfig'
import { ROOT_ROUTE } from '@/app-config/appConfig'
import { expandRoutes } from '@/router/helper/expandRoutes'
export default async () => [

View File

@ -25,11 +25,14 @@ export { useKeepAlive } from './modules/keep-alive/index'
import type { App } from 'vue'
/** 设置并且注册 pinia */
/**
*
* pinia
* pinia setup 使
*/
export const setupStore = async (app: App<Element>) => {
const store = createPinia()
app.use(store)
store.use(piniaPluginPersistedstate)
}

View File

@ -18,7 +18,7 @@
* APP_KEEP_ALIVE
*/
import { APP_KEEP_ALIVE } from '@/appConfig/appConfig'
import { APP_KEEP_ALIVE } from '@/app-config/appConfig'
import type { KeepAliveStoreState } from './type'
import type { AppMenuOption } from '@/types/modules/app'

View File

@ -11,7 +11,7 @@
/** 本方法感谢 <https://yunkuangao.me/> 的支持 */
import { APP_MENU_CONFIG, ROOT_ROUTE } from '@/appConfig/appConfig'
import { APP_MENU_CONFIG, ROOT_ROUTE } from '@/app-config/appConfig'
import RayIcon from '@/components/RayIcon/index'
import { isValueType } from '@/utils/hook'
import { getStorage, setStorage } from '@/utils/cache'

View File

@ -3,7 +3,7 @@ import { setStorage } from '@use-utils/cache'
import { set } from 'lodash-es'
import { addClass, removeClass, colorToRgba } from '@/utils/element'
import { useI18n } from '@/locales/useI18n'
import { APP_THEME } from '@/appConfig/designConfig'
import { APP_THEME } from '@/app-config/designConfig'
import { useDayjs } from '@/dayjs/index'
import type { ConditionalPick } from '@/types/modules/helper'

View File

@ -1,5 +1,5 @@
import { isValueType } from '@use-utils/hook'
import { APP_REGEX } from '@/appConfig/regexConfig'
import { APP_REGEX } from '@/app-config/regexConfig'
import type {
EventListenerOrEventListenerObject,

View File

@ -4,7 +4,7 @@ import { setStorage } from '@/utils/cache'
import { setSpin } from '@/spin'
import { useSignin } from '@/store'
import { useI18n } from '@/locales/useI18n'
import { APP_CATCH_KEY, ROOT_ROUTE } from '@/appConfig/appConfig'
import { APP_CATCH_KEY, ROOT_ROUTE } from '@/app-config/appConfig'
import { useVueRouter } from '@/router/helper/useVueRouter'
import type { FormInst } from 'naive-ui'

View File

@ -20,7 +20,7 @@ import RayLink from '@/app-components/app/RayLink/index'
import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index'
import { useSetting } from '@/store'
import { LOCAL_OPTIONS } from '@/appConfig/localConfig'
import { LOCAL_OPTIONS } from '@/app-config/localConfig'
import { useI18n } from '@/locales/useI18n'
const Login = defineComponent({