This commit is contained in:
ray_wuhao 2023-06-28 16:01:58 +08:00
parent 5daa7d67a4
commit 6498898a43
67 changed files with 303 additions and 539 deletions

1
.yarnrc.yml Normal file
View File

@ -0,0 +1 @@
nodeLinker: node-modules

View File

@ -1,5 +1,23 @@
# CHANGE LOG # CHANGE LOG
## 4.0.0
### Feats
- 重构 types 包设计,现在的类型包更加清晰
- 重构 utils 包设计,该包下的所有 hook 提供了更加友好的类型提示
- RayIframe 组件新增 lazy 属性
- 新增 v-disabled 指令
- demo 页面展示优化
### Fixes
- 修复一些已知的 bug
### 补充
> 这次花了一点时间,将模板进行重新梳理,进行了一些很大的破坏性更新改动。核心重点是 types 包与 utils 包的重大更新。不过只是做了初步的一些大方向的更新,后续的细节更新还在继续。。。
## 3.3.7 ## 3.3.7
### Feats ### Feats

View File

@ -8,6 +8,8 @@ import { get } from 'lodash-es'
import { useSetting } from '@/store' import { useSetting } from '@/store'
import { addClass, removeClass, addStyle, colorToRgba } from '@/utils/element' import { addClass, removeClass, addStyle, colorToRgba } from '@/utils/element'
import type { SettingState } from '@/store/modules/setting/type'
const App = defineComponent({ const App = defineComponent({
name: 'App', name: 'App',
setup() { setup() {
@ -22,12 +24,15 @@ const App = defineComponent({
} = __APP_CFG__ // 默认主题色 } = __APP_CFG__ // 默认主题色
const body = document.body const body = document.body
const primaryColorOverride = getCache('piniaSettingStore', 'localStorage') const primaryColorOverride = getCache<SettingState>(
'piniaSettingStore',
'localStorage',
)
const _p = get( const _p = get(
primaryColorOverride, primaryColorOverride,
'primaryColorOverride.common.primaryColor', 'primaryColorOverride.common.primaryColor',
) )
const _fp = colorToRgba(_p, 0.3) const _fp = colorToRgba(_p || primaryColor, 0.3)
/** 设置全局主题色 css 变量 */ /** 设置全局主题色 css 变量 */
body.style.setProperty('--ray-theme-primary-color', _p || primaryColor) body.style.setProperty('--ray-theme-primary-color', _p || primaryColor)

View File

@ -15,8 +15,11 @@ import type {
LayoutSideBarLogo, LayoutSideBarLogo,
PreloadingConfig, PreloadingConfig,
RootRoute, RootRoute,
} from '@/types/cfg' } from '@/types/modules/cfg'
import type { MenuCollapsedConfig, AppKeepAlive } from '@/types/appConfig' import type {
MenuCollapsedConfig,
AppKeepAlive,
} from '@/types/modules/appConfig'
/** /**
* *

View File

@ -11,7 +11,7 @@
/** 系统颜色风格配置入口 */ /** 系统颜色风格配置入口 */
import type { AppPrimaryColor } from '@/types/cfg' import type { AppPrimaryColor } from '@/types/modules/cfg'
import type { GlobalThemeOverrides } from 'naive-ui' import type { GlobalThemeOverrides } from 'naive-ui'
/** /**

View File

@ -24,6 +24,8 @@
import useRequest from '@/axios/instance' import useRequest from '@/axios/instance'
import type { AxiosResponseBody } from '@/types/modules/axios'
interface AxiosTestResponse extends UnknownObjectKey { interface AxiosTestResponse extends UnknownObjectKey {
data: UnknownObjectKey[] data: UnknownObjectKey[]
city?: string city?: string

View File

@ -30,6 +30,7 @@ import type {
ErrorImplementQueue, ErrorImplementQueue,
FetchType, FetchType,
} from '@/axios/type' } from '@/axios/type'
import type { AnyFunc } from '@/types/modules/utils'
/** 当前请求的实例 */ /** 当前请求的实例 */
const axiosFetchInstance = { const axiosFetchInstance = {

View File

@ -39,7 +39,7 @@ const { setImplement } = useAxiosInterceptor()
* request instance , * request instance ,
*/ */
const requestHeaderToken = (ins: RequestInterceptorConfig, mode: string) => { const requestHeaderToken = (ins: RequestInterceptorConfig, mode: string) => {
const token = getCache(APP_CATCH_KEY.token) const token = getCache<string>(APP_CATCH_KEY.token)
if (ins.url) { if (ins.url) {
// TODO: 根据 url 不同是否设置 token // TODO: 根据 url 不同是否设置 token

View File

@ -8,6 +8,7 @@ import type {
InternalAxiosRequestConfig, InternalAxiosRequestConfig,
AxiosResponse, AxiosResponse,
} from 'axios' } from 'axios'
import type { AnyFunc } from '@/types/modules/utils'
export type AxiosHeaderValue = export type AxiosHeaderValue =
| AxiosHeaders | AxiosHeaders

View File

@ -27,6 +27,7 @@ import { getCache } from '@/utils/cache'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import type { AvatarProps, SpaceProps } from 'naive-ui' import type { AvatarProps, SpaceProps } from 'naive-ui'
import type { SigninCallback } from '@/store/modules/signin/type'
const AppAvatar = defineComponent({ const AppAvatar = defineComponent({
name: 'AppAvatar', name: 'AppAvatar',
@ -47,7 +48,7 @@ const AppAvatar = defineComponent({
}, },
}, },
setup(props) { setup(props) {
const signin = getCache(APP_CATCH_KEY.signin) const signin = getCache<SigninCallback>(APP_CATCH_KEY.signin)
const cssVars = computed(() => { const cssVars = computed(() => {
const vars = { const vars = {
'--app-avatar-cursor': props.cursor, '--app-avatar-cursor': props.cursor,
@ -73,12 +74,12 @@ const AppAvatar = defineComponent({
<NAvatar <NAvatar
// eslint-disable-next-line prettier/prettier, @typescript-eslint/no-explicit-any // eslint-disable-next-line prettier/prettier, @typescript-eslint/no-explicit-any
{...(this.$props as any)} {...(this.$props as any)}
src={this.signin.avatar} src={this.signin?.avatar}
objectFit="cover" objectFit="cover"
round round
size={this.avatarSize} size={this.avatarSize}
/> />
<div class="app-avatar__name">{this.signin.name}</div> <div class="app-avatar__name">{this.signin?.name}</div>
</NSpace> </NSpace>
) )
}, },

View File

@ -43,6 +43,8 @@ import { cloneDeep, debounce } from 'lodash-es'
import { on, off, addStyle, completeSize } from '@/utils/element' import { on, off, addStyle, completeSize } from '@/utils/element'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import type { EChartsInstance } from '@/types/modules/component'
import type { AnyFunc } from '@/types/modules/utils'
export type AutoResize = export type AutoResize =
| boolean | boolean

View File

@ -93,6 +93,11 @@ const RayIframe = defineComponent({
type: Object as PropType<SpinProps>, type: Object as PropType<SpinProps>,
default: () => ({}), default: () => ({}),
}, },
lazy: {
/** 是否延迟加载 iframe */
type: Boolean,
default: true,
},
}, },
setup(props, { expose }) { setup(props, { expose }) {
const cssVars = computed(() => { const cssVars = computed(() => {
@ -160,6 +165,9 @@ const RayIframe = defineComponent({
allow={this.allow} allow={this.allow}
name={this.name} name={this.name}
title={this.title} title={this.title}
{...{
loading: this.lazy ? 'lazy' : null,
}}
></iframe> ></iframe>
), ),
}} }}

View File

@ -15,6 +15,7 @@ import { NPopover, NCard } from 'naive-ui'
import RayIcon from '@/components/RayIcon/index' import RayIcon from '@/components/RayIcon/index'
import type { TableSettingProvider } from '@/components/RayTable/src/type' import type { TableSettingProvider } from '@/components/RayTable/src/type'
import type { ComponentSize } from '@/types/modules/component'
const TableSize = defineComponent({ const TableSize = defineComponent({
name: 'TableSize', name: 'TableSize',

View File

@ -52,6 +52,7 @@ import type { WritableComputedRef } from 'vue'
import type { DropdownOption } from 'naive-ui' import type { DropdownOption } from 'naive-ui'
import type { ExportExcelHeader } from '@use-utils/xlsx' import type { ExportExcelHeader } from '@use-utils/xlsx'
import type { DataTableInst } from 'naive-ui' import type { DataTableInst } from 'naive-ui'
import type { ComponentSize } from '@/types/modules/component'
const RayTable = defineComponent({ const RayTable = defineComponent({
name: 'RayTable', name: 'RayTable',
@ -60,8 +61,8 @@ const RayTable = defineComponent({
setup(props, { emit, expose }) { setup(props, { emit, expose }) {
const rayTableInstance = ref<DataTableInst>() const rayTableInstance = ref<DataTableInst>()
const tableUUID = uuid() // 表格 id, 用于打印表格 const tableUUID = uuid(16) // 表格 id, 用于打印表格
const rayTableUUID = uuid() // RayTable id, 用于全屏表格 const rayTableUUID = uuid(16) // RayTable id, 用于全屏表格
const modelRightClickMenu = computed(() => props.rightClickMenu) const modelRightClickMenu = computed(() => props.rightClickMenu)
const modelColumns = computed({ const modelColumns = computed({
get: () => props.columns, get: () => props.columns,

View File

@ -7,6 +7,7 @@ import type {
DataTableInst, DataTableInst,
} from 'naive-ui' } from 'naive-ui'
import type { ComputedRef, WritableComputedRef, VNode } from 'vue' import type { ComputedRef, WritableComputedRef, VNode } from 'vue'
import type { ComponentSize } from '@/types/modules/component'
export interface ActionOptions extends DataTableBaseColumn { export interface ActionOptions extends DataTableBaseColumn {
leftFixedActivated?: boolean // 向左固定 leftFixedActivated?: boolean // 向左固定

View File

@ -19,6 +19,7 @@ import { on, off } from '@use-utils/element'
import type { Directive } from 'vue' import type { Directive } from 'vue'
import type { DebounceBindingOptions } from './type' import type { DebounceBindingOptions } from './type'
import type { AnyFunc } from '@/types/modules/utils'
let debounceFunction: AnyFunc | null let debounceFunction: AnyFunc | null

View File

@ -1,4 +1,5 @@
import type { DebounceSettings } from 'lodash-es' import type { DebounceSettings } from 'lodash-es'
import type { AnyFunc } from '@/types/modules/utils'
export interface DebounceBindingOptions { export interface DebounceBindingOptions {
func: AnyFunc func: AnyFunc

View File

@ -19,6 +19,7 @@ import { on, off } from '@use-utils/element'
import type { Directive } from 'vue' import type { Directive } from 'vue'
import type { ThrottleBindingOptions } from './type' import type { ThrottleBindingOptions } from './type'
import type { AnyFunc } from '@/types/modules/utils'
let throttleFunction: AnyFunc | null let throttleFunction: AnyFunc | null

View File

@ -1,4 +1,5 @@
import type { ThrottleSettings } from 'lodash-es' import type { ThrottleSettings } from 'lodash-es'
import type { AnyFunc } from '@/types/modules/utils'
export interface ThrottleBindingOptions { export interface ThrottleBindingOptions {
func: AnyFunc func: AnyFunc

View File

@ -1,3 +1,6 @@
<svg t="1669090001868" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7911" width="200" height="200"> <svg t="1669090001868" class="icon" viewBox="0 0 1024 1024" version="1.1"
<path d="M918.954667 880.896c-0.618667-1.322667-154.688-334.378667-177.194667-382.421333-135.402667-288.917333-174.976-369.642667-196.821333-391.957334a31.829333 31.829333 0 0 0-13.013334-12.138666 32 32 0 0 0-42.944 14.293333L109.909333 865.706667a32 32 0 0 0 57.216 28.672l99.349334-198.421334h496.725333a49853.44 49853.44 0 0 1 97.536 211.605334 32.021333 32.021333 0 0 0 58.218667-26.666667zM521.002667 187.626667c39.850667 76.650667 126.698667 260.117333 212.458666 444.330666H298.517333L521.002667 187.626667z" fill="currentColor" p-id="7912"></path> xmlns="http://www.w3.org/2000/svg" p-id="7911" width="200" height="200">
<path
d="M918.954667 880.896c-0.618667-1.322667-154.688-334.378667-177.194667-382.421333-135.402667-288.917333-174.976-369.642667-196.821333-391.957334a31.829333 31.829333 0 0 0-13.013334-12.138666 32 32 0 0 0-42.944 14.293333L109.909333 865.706667a32 32 0 0 0 57.216 28.672l99.349334-198.421334h496.725333a49853.44 49853.44 0 0 1 97.536 211.605334 32.021333 32.021333 0 0 0 58.218667-26.666667zM521.002667 187.626667c39.850667 76.650667 126.698667 260.117333 212.458666 444.330666H298.517333L521.002667 187.626667z"
fill="currentColor" p-id="7912"></path>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 722 B

View File

@ -8,6 +8,7 @@ import { MENU_COLLAPSED_CONFIG, MENU_ACCORDION } from '@/appConfig/appConfig'
import { useVueRouter } from '@/router/helper/useVueRouter' import { useVueRouter } from '@/router/helper/useVueRouter'
import type { MenuInst } from 'naive-ui' import type { MenuInst } from 'naive-ui'
import type { NaiveMenuOptions } from '@/types/modules/component'
const LayoutMenu = defineComponent({ const LayoutMenu = defineComponent({
name: 'LayoutMenu', name: 'LayoutMenu',

View File

@ -34,8 +34,6 @@ $menuTagWrapperWidth: 76px;
& .menu-tag__right-setting { & .menu-tag__right-setting {
width: 28px; width: 28px;
height: 20px; height: 20px;
// display: inline-flex;
// align-items: center;
} }
} }
} }

View File

@ -36,6 +36,7 @@ import { ROOT_ROUTE } from '@/appConfig/appConfig'
import { getElement } from '@use-utils/element' import { getElement } from '@use-utils/element'
import type { MenuOption, ScrollbarInst } from 'naive-ui' import type { MenuOption, ScrollbarInst } from 'naive-ui'
import type { MenuTagOptions } from '@/types/modules/app'
const MenuTag = defineComponent({ const MenuTag = defineComponent({
name: 'MenuTag', name: 'MenuTag',
@ -148,7 +149,7 @@ const MenuTag = defineComponent({
disabled: false, disabled: false,
}, },
]) ])
const scrollBarUUID = uuid() const scrollBarUUID = uuid(16)
const actionMap = { const actionMap = {
reloadCurrentPage: () => { reloadCurrentPage: () => {
changeSwitcher(false, 'reloadRouteSwitch') changeSwitcher(false, 'reloadRouteSwitch')
@ -380,7 +381,9 @@ const MenuTag = defineComponent({
/** 动态更新 menu tag 所在位置 */ /** 动态更新 menu tag 所在位置 */
const positionMenuTag = () => { const positionMenuTag = () => {
nextTick().then(() => { nextTick().then(() => {
const tags = getElement(`attr:${MENU_TAG_DATA}="${menuKey.value}"`) const tags = getElement<HTMLElement>(
`attr:${MENU_TAG_DATA}="${menuKey.value}"`,
)
if (tags?.length) { if (tags?.length) {
const [menuTag] = tags const [menuTag] = tags
@ -505,9 +508,9 @@ const MenuTag = defineComponent({
[this.MENU_TAG_DATA]: curr.path, [this.MENU_TAG_DATA]: curr.path,
}} }}
> >
{typeof curr.label === 'function' {typeof curr.label === 'string'
? curr.label() ? curr.label
: curr.label} : curr.label?.()}
</NTag> </NTag>
))} ))}
</NSpace> </NSpace>

View File

@ -21,6 +21,7 @@ import { validMenuItemShow } from '@/router/helper/routerCopilot'
import type { MenuOption } from 'naive-ui' import type { MenuOption } from 'naive-ui'
import type { AppRouteMeta } from '@/router/type' import type { AppRouteMeta } from '@/router/type'
import type { AppMenuOption } from '@/types/modules/app'
const GlobalSeach = defineComponent({ const GlobalSeach = defineComponent({
name: 'GlobalSeach', name: 'GlobalSeach',
@ -49,7 +50,7 @@ const GlobalSeach = defineComponent({
const modelMenuOptions = computed(() => menuStore.options) const modelMenuOptions = computed(() => menuStore.options)
const state = reactive({ const state = reactive({
searchValue: null, searchValue: null,
searchOptions: [] as IMenuOptions[], searchOptions: [] as AppMenuOption[],
}) })
const tiptextOptions = [ const tiptextOptions = [
@ -76,9 +77,9 @@ const GlobalSeach = defineComponent({
/** 根据输入值模糊检索菜单 */ /** 根据输入值模糊检索菜单 */
const handleSearchMenuOptions = (value: string) => { const handleSearchMenuOptions = (value: string) => {
const arr: IMenuOptions[] = [] const arr: AppMenuOption[] = []
const filterArr = (options: IMenuOptions[]) => { const filterArr = (options: AppMenuOption[]) => {
options.forEach((curr) => { options.forEach((curr) => {
if (curr.children?.length) { if (curr.children?.length) {
filterArr(curr.children) filterArr(curr.children)

View File

@ -16,6 +16,7 @@ import { useSetting } from '@/store'
import { useI18n } from '@/locales/useI18n' import { useI18n } from '@/locales/useI18n'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import type { Placement } from '@/types/modules/component'
const SettingDrawer = defineComponent({ const SettingDrawer = defineComponent({
name: 'SettingDrawer', name: 'SettingDrawer',
@ -25,7 +26,7 @@ const SettingDrawer = defineComponent({
default: false, default: false,
}, },
placement: { placement: {
type: String as PropType<NaiveDrawerPlacement>, type: String as PropType<Placement>,
default: 'right', default: 'right',
}, },
width: { width: {

View File

@ -29,12 +29,11 @@ import AppAvatar from '@/components/AppComponents/AppAvatar/index'
import { useSetting } from '@/store' import { useSetting } from '@/store'
import { LOCAL_OPTIONS } from '@/appConfig/localConfig' import { LOCAL_OPTIONS } from '@/appConfig/localConfig'
import { useAvatarOptions, avatarDropdownClick } from './hook' import { useAvatarOptions, avatarDropdownClick } from './hook'
import { getCache } from '@/utils/cache'
import screenfull from 'screenfull' import screenfull from 'screenfull'
import { useI18n } from '@/locales/useI18n' import { useI18n } from '@/locales/useI18n'
import { APP_CATCH_KEY } from '@/appConfig/appConfig'
import type { IconEventMapOptions, IconEventMap } from './type' import type { IconEventMapOptions, IconEventMap } from './type'
import type { SigninCallback } from '@/store/modules/signin/type'
const SiderBar = defineComponent({ const SiderBar = defineComponent({
name: 'SiderBar', name: 'SiderBar',
@ -46,7 +45,6 @@ const SiderBar = defineComponent({
const { drawerPlacement, breadcrumbSwitch } = storeToRefs(settingStore) const { drawerPlacement, breadcrumbSwitch } = storeToRefs(settingStore)
const showSettings = ref(false) const showSettings = ref(false)
const signin = getCache(APP_CATCH_KEY.signin)
const spaceItemStyle = { const spaceItemStyle = {
display: 'flex', display: 'flex',
} }
@ -131,7 +129,6 @@ const SiderBar = defineComponent({
handleIconClick, handleIconClick,
showSettings, showSettings,
updateLocale, updateLocale,
signin,
spaceItemStyle, spaceItemStyle,
drawerPlacement, drawerPlacement,
breadcrumbSwitch, breadcrumbSwitch,

View File

@ -22,7 +22,7 @@ import { getCache } from '@use-utils/cache'
import { SYSTEM_DEFAULT_LOCAL } from '@/appConfig/localConfig' import { SYSTEM_DEFAULT_LOCAL } from '@/appConfig/localConfig'
import { APP_CATCH_KEY } from '@/appConfig/appConfig' import { APP_CATCH_KEY } from '@/appConfig/appConfig'
import type { Recordable } from '@/types/type-utils' import type { Recordable } from '@/types/modules/helper'
import type { import type {
AppLocalesModules, AppLocalesModules,
AppLocalesDropdownMixedOption, AppLocalesDropdownMixedOption,
@ -126,10 +126,12 @@ export const naiveLocales = (key: string) => {
* @remak , `main.ts` , `i18n` * @remak , `main.ts` , `i18n`
*/ */
export const getDefaultLocal = () => { export const getDefaultLocal = () => {
const catchLanguage = getCache(APP_CATCH_KEY.localeLanguage, 'localStorage') const catchLanguage = getCache<string>(
APP_CATCH_KEY.localeLanguage,
'localStorage',
)
const locale: string = const locale = catchLanguage ? catchLanguage : SYSTEM_DEFAULT_LOCAL
catchLanguage !== 'no' ? catchLanguage : SYSTEM_DEFAULT_LOCAL
return locale return locale
} }

View File

@ -31,16 +31,17 @@ import type {
NavigationGuardNext, NavigationGuardNext,
RouteLocationNormalized, RouteLocationNormalized,
} from 'vue-router' } from 'vue-router'
import type { AppMenuOption } from '@/types/modules/app'
export const permissionRouter = (router: Router) => { export const permissionRouter = (router: Router) => {
const { beforeEach } = router const { beforeEach } = router
beforeEach((to, from, next) => { beforeEach((to, from, next) => {
const token = getCache(APP_CATCH_KEY.token) const token = getCache<string>(APP_CATCH_KEY.token)
const route = getCache('menuKey') const route = getCache<string>('menuKey') || ROOT_ROUTE.path
if (token !== 'no') { if (token !== null) {
if (validMenuItemShow(to as unknown as IMenuOptions)) { if (validMenuItemShow(to as unknown as AppMenuOption)) {
if (to.path === '/' || from.path === '/login') { if (to.path === '/' || from.path === '/login') {
if (route !== 'no') { if (route !== 'no') {
next(route) next(route)

View File

@ -24,6 +24,7 @@ import { setCache } from '@/utils/cache'
import type { Router } from 'vue-router' import type { Router } from 'vue-router'
import type { AppRouteMeta } from '@/router/type' import type { AppRouteMeta } from '@/router/type'
import type { AppMenuOption } from '@/types/modules/app'
/** /**
* *
@ -64,7 +65,7 @@ export const validRole = (meta: AppRouteMeta) => {
* *
* , 使 validRole * , 使 validRole
*/ */
export const validMenuItemShow = (option: IMenuOptions) => { export const validMenuItemShow = (option: AppMenuOption) => {
const { meta, name } = option const { meta, name } = option
const hidden = const hidden =
meta?.hidden === undefined || meta?.hidden === false ? false : meta?.hidden meta?.hidden === undefined || meta?.hidden === false ? false : meta?.hidden

View File

@ -8,8 +8,8 @@ const directive: AppRouteRecordRaw = {
component: () => import('@/views/directive/index'), component: () => import('@/views/directive/index'),
meta: { meta: {
i18nKey: t('menu.Directive'), i18nKey: t('menu.Directive'),
icon: 'rely', icon: 'other',
order: 3, order: 2,
}, },
} }

View File

@ -7,7 +7,7 @@ const iframe: AppRouteRecordRaw = {
name: 'IframeDemo', name: 'IframeDemo',
component: () => import('@/views/iframe/index'), component: () => import('@/views/iframe/index'),
meta: { meta: {
icon: 'rely', icon: 'other',
order: 2, order: 2,
noLocalTitle: 'iframe', noLocalTitle: 'iframe',
}, },

View File

@ -10,7 +10,7 @@ const multiMenu: AppRouteRecordRaw = {
component: LAYOUT, component: LAYOUT,
meta: { meta: {
i18nKey: t('menu.MultiMenu'), i18nKey: t('menu.MultiMenu'),
icon: 'table', icon: 'other',
order: 4, order: 4,
}, },
children: [ children: [

View File

@ -8,7 +8,7 @@ const precision: AppRouteRecordRaw = {
component: () => import('@/views/precision/index'), component: () => import('@/views/precision/index'),
meta: { meta: {
i18nKey: t('menu.CalculatePrecision'), i18nKey: t('menu.CalculatePrecision'),
icon: 'rely', icon: 'other',
order: 2, order: 2,
}, },
} }

View File

@ -8,7 +8,7 @@ const table: AppRouteRecordRaw = {
component: () => import('@/views/table/index'), component: () => import('@/views/table/index'),
meta: { meta: {
i18nKey: t('menu.Table'), i18nKey: t('menu.Table'),
icon: 'table', icon: 'other',
order: 2, order: 2,
}, },
} }

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { RouteRecordRaw } from 'vue-router' import type { RouteRecordRaw } from 'vue-router'
import type { Recordable } from '@/types/type-utils' import type { Recordable } from '@/types/modules/helper'
import type { DefineComponent, VNode } from 'vue' import type { DefineComponent, VNode } from 'vue'
export type Component<T = any> = export type Component<T = any> =

View File

@ -21,6 +21,7 @@
import { APP_KEEP_ALIVE } from '@/appConfig/appConfig' import { APP_KEEP_ALIVE } from '@/appConfig/appConfig'
import type { KeepAliveStoreState } from './type' import type { KeepAliveStoreState } from './type'
import type { AppMenuOption } from '@/types/modules/app'
export const useKeepAlive = defineStore( export const useKeepAlive = defineStore(
'keepAlive', 'keepAlive',
@ -40,7 +41,7 @@ export const useKeepAlive = defineStore(
* @remark , * @remark ,
* @remark , * @remark ,
*/ */
const setKeepAliveInclude = (option: IMenuOptions) => { const setKeepAliveInclude = (option: AppMenuOption) => {
const length = getCurrentKeepAliveLength() const length = getCurrentKeepAliveLength()
const { const {
name, name,

View File

@ -13,10 +13,15 @@
import { MENU_COLLAPSED_CONFIG, ROOT_ROUTE } from '@/appConfig/appConfig' import { MENU_COLLAPSED_CONFIG, ROOT_ROUTE } from '@/appConfig/appConfig'
import RayIcon from '@/components/RayIcon/index' import RayIcon from '@/components/RayIcon/index'
import { validteValueType } from '@/utils/hook' import { isValueType } from '@/utils/hook'
import { getCache, setCache } from '@/utils/cache' import { getCache, setCache } from '@/utils/cache'
import type { VNode } from 'vue' import type { VNode } from 'vue'
import type {
AppMenuOption,
MenuTagOptions,
AppMenuKey,
} from '@/types/modules/app'
/** /**
* *
@ -27,7 +32,7 @@ import type { VNode } from 'vue'
* @remark * @remark
*/ */
const check = ( const check = (
node: IMenuOptions, node: AppMenuOption,
key: string | number, key: string | number,
value: string | number, value: string | number,
) => { ) => {
@ -43,11 +48,11 @@ const check = (
* @remark * @remark
*/ */
const process = ( const process = (
options: IMenuOptions, options: AppMenuOption,
key: string | number, key: string | number,
value: string | number, value: string | number,
) => { ) => {
const temp: IMenuOptions[] = [] const temp: AppMenuOption[] = []
// 检查当前节点是否匹配值 // 检查当前节点是否匹配值
if (check(options, key, value)) { if (check(options, key, value)) {
@ -79,7 +84,7 @@ const process = (
* @param value * @param value
*/ */
export const parse = ( export const parse = (
options: IMenuOptions[], options: AppMenuOption[],
key: string | number, key: string | number,
value: string | number, value: string | number,
) => { ) => {
@ -105,8 +110,8 @@ export const parse = (
* @remark * @remark
*/ */
export const matchMenuOption = ( export const matchMenuOption = (
item: IMenuOptions, item: AppMenuOption,
key: MenuKey, key: AppMenuKey,
menuTagOptions: MenuTagOptions[], menuTagOptions: MenuTagOptions[],
) => { ) => {
if (item.path !== key) { if (item.path !== key) {
@ -125,7 +130,7 @@ export const matchMenuOption = (
* @remark * @remark
* @remark sideBarLogo.title * @remark sideBarLogo.title
*/ */
export const updateDocumentTitle = (option: IMenuOptions) => { export const updateDocumentTitle = (option: AppMenuOption) => {
const { breadcrumbLabel } = option const { breadcrumbLabel } = option
const { const {
layout: { sideBarLogo }, layout: { sideBarLogo },
@ -135,14 +140,14 @@ export const updateDocumentTitle = (option: IMenuOptions) => {
document.title = breadcrumbLabel + ' - ' + spliceTitle document.title = breadcrumbLabel + ' - ' + spliceTitle
} }
export const hasMenuIcon = (option: IMenuOptions) => { export const hasMenuIcon = (option: AppMenuOption) => {
const { meta } = option const { meta } = option
if (!meta.icon) { if (!meta.icon) {
return return
} }
if (validteValueType(meta.icon, 'Object')) { if (isValueType<object>(meta.icon, 'Object')) {
return () => meta.icon return () => meta.icon
} }
@ -161,8 +166,10 @@ export const hasMenuIcon = (option: IMenuOptions) => {
/** 获取缓存的 menu key, 如果未获取到则使用 ROOTROUTE path 当作默认激活路由菜单 */ /** 获取缓存的 menu key, 如果未获取到则使用 ROOTROUTE path 当作默认激活路由菜单 */
export const getCatchMenuKey = () => { export const getCatchMenuKey = () => {
const { path: rootPath } = ROOT_ROUTE const { path: rootPath } = ROOT_ROUTE
const cacheMenuKey: MenuKey = const cacheMenuKey =
getCache('menuKey') === 'no' ? rootPath : getCache('menuKey') getCache<AppMenuKey>('menuKey') === null
? rootPath
: getCache<AppMenuKey>('menuKey')
return cacheMenuKey return cacheMenuKey
} }

View File

@ -40,6 +40,7 @@ import { useVueRouter } from '@/router/helper/useVueRouter'
import type { MenuOption } from 'naive-ui' import type { MenuOption } from 'naive-ui'
import type { AppRouteMeta } from '@/router/type' import type { AppRouteMeta } from '@/router/type'
import type { AppMenuOption, MenuTagOptions } from '@/types/modules/app'
export const useMenu = defineStore( export const useMenu = defineStore(
'menu', 'menu',
@ -51,10 +52,10 @@ export const useMenu = defineStore(
const menuState = reactive({ const menuState = reactive({
menuKey: getCatchMenuKey(), // 当前菜单 `key` menuKey: getCatchMenuKey(), // 当前菜单 `key`
options: [] as IMenuOptions[], // 菜单列表 options: [] as AppMenuOption[], // 菜单列表
collapsed: false, // 是否折叠菜单 collapsed: false, // 是否折叠菜单
menuTagOptions: [] as MenuTagOptions[], // tag 标签菜单 menuTagOptions: [] as MenuTagOptions[], // tag 标签菜单
breadcrumbOptions: [] as IMenuOptions[], // 面包屑菜单 breadcrumbOptions: [] as AppMenuOption[], // 面包屑菜单
}) })
/** /**
@ -65,7 +66,7 @@ export const useMenu = defineStore(
* @remark * @remark
*/ */
const getCompleteRoutePath = ( const getCompleteRoutePath = (
options: IMenuOptions[], options: AppMenuOption[],
key: string | number, key: string | number,
) => { ) => {
const ops = parse(options, 'key', key) const ops = parse(options, 'key', key)
@ -94,8 +95,8 @@ export const useMenu = defineStore(
menuState.menuKey, menuState.menuKey,
menuState.menuTagOptions, menuState.menuTagOptions,
) )
updateDocumentTitle(item as unknown as IMenuOptions) updateDocumentTitle(item as unknown as AppMenuOption)
setKeepAliveInclude(item as unknown as IMenuOptions) setKeepAliveInclude(item as unknown as AppMenuOption)
menuState.breadcrumbOptions = parse(menuState.options, 'key', key) // 获取面包屑 menuState.breadcrumbOptions = parse(menuState.options, 'key', key) // 获取面包屑
@ -168,7 +169,7 @@ export const useMenu = defineStore(
* @remark , * @remark ,
*/ */
const setupAppRoutes = () => { const setupAppRoutes = () => {
const resolveOption = (option: IMenuOptions) => { const resolveOption = (option: AppMenuOption) => {
const { meta } = option const { meta } = option
/** 设置 label, i18nKey 优先级最高 */ /** 设置 label, i18nKey 优先级最高 */
@ -184,9 +185,9 @@ export const useMenu = defineStore(
default: () => label.value, default: () => label.value,
}), }),
breadcrumbLabel: label.value, breadcrumbLabel: label.value,
} as IMenuOptions } as AppMenuOption
/** 合并 icon */ /** 合并 icon */
const attr: IMenuOptions = Object.assign({}, route, { const attr: AppMenuOption = Object.assign({}, route, {
icon: hasMenuIcon(option), icon: hasMenuIcon(option),
}) })
@ -203,8 +204,8 @@ export const useMenu = defineStore(
return attr return attr
} }
const resolveRoutes = (routes: IMenuOptions[], index: number) => { const resolveRoutes = (routes: AppMenuOption[], index: number) => {
const catchArr: IMenuOptions[] = [] const catchArr: AppMenuOption[] = []
for (const curr of routes) { for (const curr of routes) {
if (curr.children?.length && validMenuItemShow(curr)) { if (curr.children?.length && validMenuItemShow(curr)) {
@ -221,7 +222,7 @@ export const useMenu = defineStore(
} }
/** 缓存菜单列表 */ /** 缓存菜单列表 */
menuState.options = resolveRoutes(routeModules as IMenuOptions[], 0) menuState.options = resolveRoutes(routeModules as AppMenuOption[], 0)
/** 初始化后渲染面包屑 */ /** 初始化后渲染面包屑 */
nextTick(() => { nextTick(() => {

View File

@ -6,7 +6,7 @@ import { useI18n } from '@/locales/useI18n'
import { APP_NAIVE_UI_THEME_OVERRIDES } from '@/appConfig/designConfig' import { APP_NAIVE_UI_THEME_OVERRIDES } from '@/appConfig/designConfig'
import { useDayjs } from '@/dayjs/index' import { useDayjs } from '@/dayjs/index'
import type { ConditionalPick } from '@/types/type-utils' import type { ConditionalPick } from '@/types/modules/helper'
import type { SettingState } from '@/store/modules/setting/type' import type { SettingState } from '@/store/modules/setting/type'
import type { DayjsLocal } from '@/dayjs/type' import type { DayjsLocal } from '@/dayjs/type'

View File

@ -1,7 +1,8 @@
import type { GlobalThemeOverrides } from 'naive-ui' import type { GlobalThemeOverrides } from 'naive-ui'
import type { Placement } from '@/types/modules/component'
export interface SettingState { export interface SettingState {
drawerPlacement: NaiveDrawerPlacement drawerPlacement: Placement
primaryColorOverride: GlobalThemeOverrides primaryColorOverride: GlobalThemeOverrides
themeValue: boolean themeValue: boolean
reloadRouteSwitch: boolean reloadRouteSwitch: boolean

15
src/types/axios.d.ts vendored
View File

@ -1,15 +0,0 @@
export {}
declare global {
/**
*
*
*
*
*/
declare interface AxiosResponseBody<T = unknown> {
data: T
message: string
code: number
}
}

View File

@ -1,5 +0,0 @@
export {}
declare global {
declare type CacheType = 'sessionStorage' | 'localStorage'
}

View File

@ -1,26 +0,0 @@
export {}
import type { ECharts } from 'echarts/core'
import type {
MessageApi,
DialogApi,
LoadingBarApi,
NotificationApi,
MenuOption,
MenuDividerOption,
MenuGroupOption,
} from 'naive-ui'
import type { VNodeChild } from 'vue'
declare global {
declare type ComponentSize = 'small' | 'medium' | 'large'
declare type EChartsInstance = ECharts
declare type NaiveDrawerPlacement = 'top' | 'right' | 'bottom' | 'left'
declare type NaiveMenuOptions =
| MenuOption
| MenuDividerOption
| MenuGroupOption
}

View File

@ -1,14 +1,17 @@
export {} /* eslint-disable @typescript-eslint/no-explicit-any */
import type { AppConfig } from './cfg'
import type { import type {
MessageApi, MessageApi,
DialogApi, DialogApi,
LoadingBarApi, LoadingBarApi,
NotificationApi, NotificationApi,
} from 'naive-ui' } from 'naive-ui'
import type { AppConfig } from './cfg'
export global { declare global {
declare interface UnknownObjectKey {
[propName: string]: any
}
declare const __APP_CFG__: AppConfig declare const __APP_CFG__: AppConfig
declare interface Window { declare interface Window {
@ -41,9 +44,9 @@ export global {
$loadingBar: LoadingBarApi $loadingBar: LoadingBarApi
$notification: NotificationApi $notification: NotificationApi
// eslint-disable-next-line @typescript-eslint/no-explicit-any
DocsAPI?: any DocsAPI?: any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
DocEditor?: any DocEditor?: any
msCrypto: Crypto
} }
} }

163
src/types/micro.d.ts vendored
View File

@ -1,163 +0,0 @@
export {}
declare global {
export declare type lifecycle = (appWindow: Window) => unknown
export declare type loadErrorHandler = (url: string, e: Error) => unknown
export declare type baseOptions = {
/** 唯一性用户必须保证 */
name: string
/** 需要渲染的url */
url: string
/** 代码替换钩子 */
replace?: (code: string) => string
/** 自定义fetch */
fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>
/** 注入给子应用的属性 */
props?: { [key: string]: unknown }
/** 自定义iframe属性 */
attrs?: { [key: string]: unknown }
/** 子应用采用fiber模式执行 */
fiber?: boolean
/** 子应用保活state不会丢失 */
alive?: boolean
/** 子应用采用降级iframe方案 */
degrade?: boolean
/** 子应用插件 */
plugins?: Array<plugin>
/** 子应用生命周期 */
beforeLoad?: lifecycle
beforeMount?: lifecycle
afterMount?: lifecycle
beforeUnmount?: lifecycle
afterUnmount?: lifecycle
activated?: lifecycle
deactivated?: lifecycle
loadError?: loadErrorHandler
}
export declare type preOptions = baseOptions & {
/** 预执行 */
exec?: boolean
}
export declare type startOptions = baseOptions & {
/** 渲染的容器 */
el: HTMLElement | string
/**
*
* falsehistory还是会增加
* https://html.spec.whatwg.org/multipage/history.html#the-history-interface
*/
sync?: boolean
/** 子应用短路径替换,路由同步时生效 */
prefix?: { [key: string]: string }
/** 子应用加载时loading元素 */
loading?: HTMLElement
}
export declare type optionProperty = 'url' | 'el'
/**
* preOptions startOptions url el
*/
export declare type cacheOptions = Omit<
preOptions & startOptions,
optionProperty
> &
Partial<Pick<startOptions, optionProperty>>
export declare type startOption = {
/** 唯一性用户必须保证 */
name: string
/** 需要渲染的url */
url: string
/** 渲染的容器 */
el: HTMLElement | string
/** 子应用加载时loading元素 */
loading?: HTMLElement
/** 路由同步开关, false刷新无效但是前进后退依然有效 */
sync?: boolean
/** 子应用短路径替换,路由同步时生效 */
prefix?: { [key: string]: string }
/** 子应用保活模式state不会丢失 */
alive?: boolean
/** 注入给子应用的数据 */
props?: { [key: string]: unknown }
/** js采用fiber模式执行 */
fiber?: boolean
/** 子应用采用降级iframe方案 */
degrade?: boolean
/** 自定义iframe属性 */
attrs?: { [key: string]: unknown }
/** 代码替换钩子 */
replace?: (codeText: string) => string
/** 自定义fetch资源和接口 */
fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>
/** 子应插件 */
plugins: Array<plugin>
/** 子应用生命周期 */
beforeLoad?: lifecycle
/** 没有做生命周期改造的子应用不会调用 */
beforeMount?: lifecycle
afterMount?: lifecycle
beforeUnmount?: lifecycle
afterUnmount?: lifecycle
/** 非保活应用不会调用 */
activated?: lifecycle
deactivated?: lifecycle
/** 子应用资源加载失败后调用 */
loadError?: loadErrorHandler
}
export declare type preOptions = {
/** 唯一性用户必须保证 */
name: string
/** 需要渲染的url */
url: string
/** 注入给子应用的数据 */
props?: { [key: string]: unknown }
/** 自定义iframe属性 */
attrs?: { [key: string]: unknown }
/** 代码替换钩子 */
replace?: (code: string) => string
/** 自定义fetch资源和接口 */
fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>
/** 子应用保活模式state不会丢失 */
alive?: boolean
/** 预执行模式 */
exec?: boolean
/** js采用fiber模式执行 */
fiber?: boolean
/** 子应用采用降级iframe方案 */
degrade?: boolean
/** 子应插件 */
plugins: Array<plugin>
/** 子应用生命周期 */
beforeLoad?: lifecycle
/** 没有做生命周期改造的子应用不会调用 */
beforeMount?: lifecycle
afterMount?: lifecycle
beforeUnmount?: lifecycle
afterUnmount?: lifecycle
/** 非保活应用不会调用 */
activated?: lifecycle
deactivated?: lifecycle
/** 子应用资源加载失败后调用 */
loadError?: loadErrorHandler
}
export declare class EventBus {
private id
private eventObj
constructor(id: string)
$on(event: string, fn: Function): EventBus
/** 任何$emit都会导致监听函数触发第一个参数为事件名后续的参数为$emit的参数 */
$onAll(fn: (event: string, ...args: Array<unknown>) => unknown): EventBus
$once(event: string, fn: Function): void
$off(event: string, fn: Function): EventBus
$offAll(fn: Function): EventBus
$emit(event: string, ...args: Array<unknown>): EventBus
$clear(): EventBus
}
}

21
src/types/modules/app.ts Normal file
View File

@ -0,0 +1,21 @@
import type { VNode } from 'vue'
import type { AppRouteRecordRaw, AppRouteMeta } from '@/router/type'
export type Key = string | number
export interface AppMenuOption extends AppRouteRecordRaw {
name: string
key: Key
path: string
label: string | (() => VNode)
show?: boolean
children?: AppMenuOption[]
meta: AppRouteMeta
breadcrumbLabel?: string
}
export interface MenuTagOptions extends AppMenuOption {
closeable?: boolean
}
export type AppMenuKey = Key | null

View File

@ -0,0 +1,5 @@
export interface AxiosResponseBody<T = unknown> {
data: T
message: string
code: number
}

View File

@ -5,6 +5,7 @@ import type {
AliasOptions, AliasOptions,
UserConfigExport, UserConfigExport,
} from 'vite' } from 'vite'
import type { Recordable } from '@/types/modules/helper'
export interface LayoutSideBarLogo { export interface LayoutSideBarLogo {
icon?: string icon?: string
@ -49,8 +50,6 @@ export interface Config {
appPrimaryColor?: AppPrimaryColor appPrimaryColor?: AppPrimaryColor
} }
export type Recordable<T = unknown> = Record<string, T>
/** /**
* *
* *

View File

@ -0,0 +1,10 @@
import type { ECharts } from 'echarts/core'
import type { MenuOption, MenuDividerOption, MenuGroupOption } from 'naive-ui'
export type ComponentSize = 'small' | 'medium' | 'large'
export type EChartsInstance = ECharts
export type Placement = 'top' | 'right' | 'bottom' | 'left'
export type NaiveMenuOptions = MenuOption | MenuDividerOption | MenuGroupOption

View File

@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type CryptoJS from 'crypto-js'
export type CacheType = 'sessionStorage' | 'localStorage'
export type EventListenerOrEventListenerObject =
| EventListener
| EventListenerObject
export type ValidteValueType =
| 'Object'
| 'Undefined'
| 'Null'
| 'Boolean'
| 'Number'
| 'String'
| 'Symbol'
| 'Function'
| 'Date'
| 'Array'
| 'RegExp'
| 'Map'
| 'Set'
| 'WeakMap'
| 'WeakSet'
| 'ArrayBuffer'
| 'DataView'
| 'Int8Array'
| 'Uint8Array'
| 'Uint8ClampedArray'
| 'Int16Array'
| 'Uint16Array'
| 'Int32Array'
| 'Uint32Array'
| 'Float32Array'
| 'Float64Array'
export type WordArray = CryptoJS.lib.WordArray
export type CipherParams = CryptoJS.lib.CipherParams
export type AnyFunc = (...args: any[]) => any
export type AnyVoidFunc = (...args: any[]) => void

26
src/types/store.d.ts vendored
View File

@ -1,26 +0,0 @@
export {}
import type { RouteRecordRaw, RouteMeta } from 'vue-router'
import type { MenuOption } from 'naive-ui'
import type { VNode } from 'vue'
import type { AppRouteRecordRaw, AppRouteMeta } from '@/router/type'
declare global {
declare interface IMenuOptions extends AppRouteRecordRaw, MenuOption {
name: string
key: string | number
path: string
label: string | Function
show?: boolean
children?: IMenuOptions[]
meta: AppRouteMeta
breadcrumbLabel?: string
noLocalTitle?: string | number
}
declare interface MenuTagOptions extends IMenuOptions {
closeable?: boolean
}
declare type MenuKey = null | string | number
}

39
src/types/utils.d.ts vendored
View File

@ -1,39 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export {}
import type CryptoJS from 'crypto-js'
import type { VNodeChild } from 'vue'
export global {
declare interface UnknownObjectKey {
[propName: string]: any
}
declare type EventListenerOrEventListenerObject =
| EventListener
| EventListenerObject
declare type ValidteValueType =
| 'Number'
| 'String'
| 'Boolean'
| 'Object'
| 'Function'
| 'Null'
| 'Undefined'
| 'Array'
| 'Date'
| 'Math'
| 'RegExp'
| 'Error'
declare type WordArray = CryptoJS.lib.WordArray
declare type CipherOption = CryptoJS.lib.CipherOption
declare type CipherParams = CryptoJS.lib.CipherParams
declare type VoidFunc = (...args: any[]) => void
declare type AnyFunc = (...args: any[]) => any
}

View File

@ -11,6 +11,8 @@
/** vue3 项目里建议直接用 vueuse useStorage 方法 */ /** vue3 项目里建议直接用 vueuse useStorage 方法 */
import type { CacheType } from '@/types/modules/utils'
/** /**
* *
* @param key key * @param key key
@ -32,16 +34,17 @@ export const setCache = <T = unknown>(
* *
* @param key key * @param key key
* @returns * @returns
*
* @remark 'no'
*/ */
export const getCache = (key: string, type: CacheType = 'sessionStorage') => { export const getCache = <T>(
key: string,
type: CacheType = 'sessionStorage',
): T | null => {
const data = const data =
type === 'localStorage' type === 'localStorage'
? window.localStorage.getItem(key) ? window.localStorage.getItem(key)
: window.sessionStorage.getItem(key) : window.sessionStorage.getItem(key)
return Object.is(data, null) ? 'no' : JSON.parse(data as string) return Object.is(data, null) ? null : JSON.parse(data as string)
} }
/** /**

View File

@ -1,8 +1,10 @@
import HmacSHA256 from 'crypto-js/hmac-sha256' // import HmacSHA256 from 'crypto-js/hmac-sha256'
import SHA256 from 'crypto-js/sha256' // import SHA256 from 'crypto-js/sha256'
import AES from 'crypto-js/aes' // import AES from 'crypto-js/aes'
import MD5 from 'crypto-js/md5' // import MD5 from 'crypto-js/md5'
import BASE64 from 'crypto-js/enc-base64' // import BASE64 from 'crypto-js/enc-base64'
// import type { WordArray, CipherParams } from '@/types/modules/utils'
/** /**
* *
@ -11,118 +13,3 @@ import BASE64 from 'crypto-js/enc-base64'
* *
* 手动补上官网地址: http://github.com/brix/crypto-js * 手动补上官网地址: http://github.com/brix/crypto-js
*/ */
/**
*
* @param message
* @param key key
*
* @remark HmacSHA256
*/
export const useHmacSHA256 = (
message: WordArray | string,
key: WordArray | string,
) => {
return new Promise((resolve) => {
const cry = HmacSHA256(message, key)
resolve(cry)
})
}
/**
*
* @param message
*
* @remark SHA256
*/
export const useSHA256 = (message: WordArray | string) => {
return new Promise((resolve) => {
const cry = SHA256(message)
resolve(cry)
})
}
/**
*
* @param message
* @param key key
* @param cfg
*
* @remark AES
*/
export const useAESEncrypt = (
message: WordArray | string,
key: WordArray | string,
cfg?: CipherOption,
) => {
return new Promise((resolve) => {
const cry = AES.encrypt(message, key, cfg)
resolve(cry)
})
}
/**
*
* @param ciphertext
* @param key key
* @param cfg
*
* @remark AES
*/
export const useAESDecrypt = (
ciphertext: CipherParams | string,
key: WordArray | string,
cfg?: CipherOption,
) => {
return new Promise((resolve) => {
const cry = AES.decrypt(ciphertext, key, cfg)
resolve(cry)
})
}
/**
*
* @param message
* @param cfg md5
*
* @remark md5
*/
export const useMD5 = (message: WordArray | string, cfg?: object) => {
return new Promise((resolve) => {
const cry = MD5(message, cfg)
resolve(cry)
})
}
/**
*
* @param wordArray base64
*
* @remark base64
*/
export const useBase64Stringify = (wordArray: WordArray) => {
return new Promise((resolve) => {
const cry = BASE64.stringify(wordArray)
resolve(cry)
})
}
/**
*
* @param str base64
*
* @remark base64
*/
export const useBase64Parse = (str: string) => {
return new Promise((resolve) => {
const cry = BASE64.parse(str)
resolve(cry)
})
}

View File

@ -1,11 +1,14 @@
import { validteValueType } from '@use-utils/hook' import { isValueType } from '@use-utils/hook'
import { ELEMENT_UNIT } from '@/appConfig/regConfig' import { ELEMENT_UNIT } from '@/appConfig/regConfig'
import type { EventListenerOrEventListenerObject } from '@/types/modules/utils'
/** /**
* *
* @param element Target element dom * @param element Target element dom
* @param event * @param event
* @param handler * @param handler
* @param useCapture
* *
* @remark * @remark
*/ */
@ -13,7 +16,7 @@ export const on = (
element: HTMLElement | Document | Window, element: HTMLElement | Document | Window,
event: string, event: string,
handler: EventListenerOrEventListenerObject, handler: EventListenerOrEventListenerObject,
useCapture = false, useCapture: boolean | AddEventListenerOptions = false,
) => { ) => {
if (element && event && handler) { if (element && event && handler) {
element.addEventListener(event, handler, useCapture) element.addEventListener(event, handler, useCapture)
@ -25,6 +28,7 @@ export const on = (
* @param element Target element dom * @param element Target element dom
* @param event * @param event
* @param handler * @param handler
* @param useCapture
* *
* @remark * @remark
*/ */
@ -32,7 +36,7 @@ export const off = (
element: HTMLElement | Document | Window, element: HTMLElement | Document | Window,
event: string, event: string,
handler: EventListenerOrEventListenerObject, handler: EventListenerOrEventListenerObject,
useCapture = false, useCapture: boolean | AddEventListenerOptions = false,
) => { ) => {
if (element && event && handler) { if (element && event && handler) {
element.removeEventListener(event, handler, useCapture) element.removeEventListener(event, handler, useCapture)
@ -133,12 +137,12 @@ export const addStyle = (
styles: string | Partial<CSSStyleDeclaration>, styles: string | Partial<CSSStyleDeclaration>,
) => { ) => {
if (el) { if (el) {
if (validteValueType(styles, 'Object')) { if (isValueType<object>(styles, 'Object')) {
Object.keys(styles).forEach((item) => { Object.keys(styles).forEach((item) => {
el.style[item] = styles[item] el.style[item] = styles[item]
}) })
} else if (validteValueType(styles, 'String')) { } else if (isValueType<string>(styles, 'String')) {
const _styles = styles as string const _styles = styles
_styles.split(';').forEach((item) => { _styles.split(';').forEach((item) => {
const [_k, _v] = item.split(':') const [_k, _v] = item.split(':')
@ -223,9 +227,9 @@ export const colorToRgba = (color: string, alpha = 1) => {
* *
* const el = getElement('attr:type') * const el = getElement('attr:type')
*/ */
export const getElement = (element: string) => { export const getElement = <T extends Element>(element: string) => {
if (!element) { if (!element) {
return return null
} }
let queryParam: string let queryParam: string
@ -237,7 +241,7 @@ export const getElement = (element: string) => {
} }
try { try {
const el = Array.from(document.querySelectorAll(queryParam)) const el = Array.from(document.querySelectorAll<T>(queryParam))
return el return el
} catch (e) { } catch (e) {
@ -248,15 +252,16 @@ export const getElement = (element: string) => {
/** /**
* *
* @param size css size * @param size css size
* @param unit css
* *
* @remark * @remark
*/ */
export const completeSize = (size: number | string) => { export const completeSize = (size: number | string, unit = 'px') => {
if (typeof size === 'number') { if (typeof size === 'number') {
return size.toString() + 'px' return size.toString() + unit
} else if (ELEMENT_UNIT.test(size)) { } else if (isValueType<string>(size, 'String') && ELEMENT_UNIT.test(size)) {
return size return size
} else { } else {
return size + 'px' return size + unit
} }
} }

View File

@ -1,3 +1,5 @@
import type { ValidteValueType } from '@/types/modules/utils'
/** /**
* *
* @returns * @returns
@ -14,9 +16,11 @@ export const getAppEnvironment = () => {
* *
* @returns formate binary to base64 of the image * @returns formate binary to base64 of the image
*/ */
export const useImagebufferToBase64 = ( export const arrayBufferToBase64Image = (data: ArrayBuffer): string | null => {
data: ArrayBufferLike | ArrayLike<number>, if (!data || data.byteLength) {
) => { return null
}
const base64 = const base64 =
'data:image/png;base64,' + 'data:image/png;base64,' +
window.btoa( window.btoa(
@ -34,10 +38,10 @@ export const useImagebufferToBase64 = (
* @param value * @param value
* @param type * @param type
*/ */
export const validteValueType = <T = unknown>( export const isValueType = <T>(
value: T, value: unknown,
type: ValidteValueType, type: ValidteValueType,
) => { ): value is T => {
const valid = Object.prototype.toString.call(value) const valid = Object.prototype.toString.call(value)
return valid.includes(type) return valid.includes(type)
@ -49,35 +53,29 @@ export const validteValueType = <T = unknown>(
* @param radix `uuid` * @param radix `uuid`
* @returns `uuid` * @returns `uuid`
*/ */
export const uuid = (length = 16, radix?: number) => { export const uuid = (length = 16, radix = 62) => {
const sad = // 定义可用的字符集,即 0-9, A-Z, a-z
const availableChars =
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('') '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
// 定义存储随机字符串的数组
const arr: string[] = [] const arr: string[] = []
// 获取加密对象,兼容 IE11
const cryptoObj = window.crypto || window.msCrypto
let i = 0 let i = 0
radix = radix || sad.length // 循环 length 次,生成随机字符,并添加到数组中
if (length) {
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
arr[i] = sad[0 | (Math.random() * radix)] // 生成一个随机数
} const randomValues = new Uint32Array(1)
} else {
let r
arr[23] = '-' cryptoObj.getRandomValues(randomValues)
arr[18] = arr[23]
arr[13] = arr[18]
arr[8] = arr[13]
arr[14] = '4'
for (i = 0; i < 36; i++) { // 根据随机数生成对应的字符,并添加到数组中
if (!arr[i]) { const index = randomValues[0] % radix
r = 0 | (Math.random() * radix)
arr[i] = sad[i === 19 ? (r & 0x3) | 0x8 : r] arr.push(availableChars[index])
}
}
} }
// 将数组中的字符连接起来,返回最终的字符串
return arr.join('') return arr.join('')
} }

View File

@ -32,6 +32,7 @@ import currency from 'currency.js'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import type { Options } from 'currency.js' import type { Options } from 'currency.js'
import type { AnyFunc } from '@/types/modules/utils'
export type CurrencyArguments = string | number | currency export type CurrencyArguments = string | number | currency

View File

@ -10,6 +10,7 @@ import {
NButton, NButton,
} from 'naive-ui' } from 'naive-ui'
import { onAxiosTest } from '@use-api/test' import { onAxiosTest } from '@use-api/test'
import { isArray } from 'lodash-es'
const Axios = defineComponent({ const Axios = defineComponent({
name: 'RAxios', name: 'RAxios',

View File

@ -20,7 +20,7 @@ import {
NFormItem, NFormItem,
} from 'naive-ui' } from 'naive-ui'
import type { ConditionalPick } from '@/types/type-utils' import type { ConditionalPick } from '@/types/modules/helper'
const RDirective = defineComponent({ const RDirective = defineComponent({
name: 'RDirective', name: 'RDirective',

View File

@ -3,6 +3,8 @@ import './index.scss'
import { NCard, NSwitch, NSpace, NP, NH6, NH2, NH3 } from 'naive-ui' import { NCard, NSwitch, NSpace, NP, NH6, NH2, NH3 } from 'naive-ui'
import RayChart from '@/components/RayChart/index' import RayChart from '@/components/RayChart/index'
import type { EChartsInstance } from '@/types/modules/component'
const Echart = defineComponent({ const Echart = defineComponent({
name: 'REchart', name: 'REchart',
setup() { setup() {

View File

@ -17,7 +17,7 @@
* , * ,
*/ */
import { NSpace } from 'naive-ui' import { NCard, NSpace } from 'naive-ui'
import RayIframe from '@/components/RayIframe/index' import RayIframe from '@/components/RayIframe/index'
const IframeDemo = defineComponent({ const IframeDemo = defineComponent({
@ -28,18 +28,20 @@ const IframeDemo = defineComponent({
render() { render() {
return ( return (
<NSpace vertical size={[20, 20]}> <NSpace vertical size={[20, 20]}>
<NSpace vertical size={[20, 20]}> <NCard title="naive ui延迟加载">
<h2>naive ui</h2>
<RayIframe <RayIframe
src="https://www.naiveui.com/zh-CN/dark" src="https://www.naiveui.com/zh-CN/dark"
height="500" height="300"
allow="fullscreen" allow="fullscreen"
/> />
</NSpace> </NCard>
<NSpace vertical size={[20, 20]}> <NCard title="vueuse立即加载">
<h2>vueuse</h2> <RayIframe
<RayIframe src="https://www.vueusejs.com/" height="500" /> src="https://www.vueusejs.com/"
</NSpace> height="300"
lazy={false}
/>
</NCard>
</NSpace> </NSpace>
) )
}, },

View File

@ -16,7 +16,7 @@ import type { PropType } from 'vue'
const Document = defineComponent({ const Document = defineComponent({
name: 'RDocument', name: 'RDocument',
setup() { setup() {
const editorUUID = uuid() const editorUUID = uuid(16)
const state = reactive({}) const state = reactive({})
const config = { const config = {
document: { document: {
@ -34,16 +34,6 @@ const Document = defineComponent({
}, },
} }
const registerEdtior = () => {
const uid = uuid(12)
}
onMounted(() => {
nextTick(() => {
registerEdtior()
})
})
return { return {
...toRefs(state), ...toRefs(state),
editorUUID, editorUUID,

View File

@ -47,6 +47,7 @@
"src/*.vue", "src/*.vue",
"src/*", "src/*",
"components.d.ts", "components.d.ts",
"auto-imports.d.ts" "auto-imports.d.ts",
"src/types/global.d.ts"
] ]
} }

View File

@ -7,7 +7,6 @@ import {
viteVueI18nPlugin, viteVueI18nPlugin,
viteSVGIcon, viteSVGIcon,
} from './vite-plugin/index' } from './vite-plugin/index'
import viteVueJSX from '@vitejs/plugin-vue-jsx' import viteVueJSX from '@vitejs/plugin-vue-jsx'
import viteVeI18nPlugin from '@intlify/unplugin-vue-i18n/vite' import viteVeI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import viteInspect from 'vite-plugin-inspect' import viteInspect from 'vite-plugin-inspect'