Template
1
0
mirror of https://github.com/un-pany/v3-admin-vite.git synced 2025-04-20 10:59:21 +08:00

docs: 统一注释风格 (允许顶层变量采用 /** 内层变量采用默认的 //)

This commit is contained in:
pany 2024-11-25 14:21:18 +08:00
parent 0b517855b6
commit 23ab6b7ab5
22 changed files with 125 additions and 107 deletions

View File

@ -5,7 +5,7 @@
*/
:root {
/*color*/
/* color */
--vxe-font-color: var(--el-text-color-regular);
--vxe-primary-color: var(--el-color-primary);
--vxe-success-color: var(--el-color-success);
@ -34,16 +34,16 @@
--vxe-warning-disabled-color: var(--el-color-warning-light-5);
--vxe-danger-disabled-color: var(--el-color-danger-light-5);
/*input/radio/checkbox*/
/* input/radio/checkbox */
--vxe-input-border-color: var(--el-border-color);
--vxe-input-disabled-color: var(--el-text-color-disabled);
--vxe-input-disabled-background-color: var(--el-fill-color-light);
--vxe-input-placeholder-color: var(--el-text-color-placeholder);
/*popup*/
/* popup */
--vxe-table-popup-border-color: var(--el-border-color);
/*table*/
/* table */
--vxe-table-header-font-color: var(--el-text-color-regular);
--vxe-table-footer-font-color: var(--el-text-color-regular);
--vxe-table-border-color: var(--el-border-color-lighter);
@ -57,41 +57,41 @@
--vxe-table-checkbox-range-background-color: var(--el-fill-color-light);
/*menu*/
/* menu */
--vxe-table-menu-background-color: var(--el-bg-color-overlay);
/*loading*/
/* loading */
--vxe-loading-color: var(--el-color-primary);
--vxe-loading-background-color: var(--el-mask-color);
/*validate*/
/* validate */
--vxe-table-validate-error-color: var(--el-color-danger);
/*toolbar*/
/* toolbar */
--vxe-toolbar-background-color: var(--el-bg-color);
--vxe-toolbar-custom-active-background-color: var(--el-bg-color-overlay);
--vxe-toolbar-panel-background-color: var(--el-bg-color-overlay);
/*pager*/
/* pager */
--vxe-pager-background-color: var(--el-bg-color);
/*modal*/
/* modal */
--vxe-modal-header-background-color: var(--el-bg-color);
--vxe-modal-body-background-color: var(--el-bg-color);
--vxe-modal-border-color: var(--el-border-color);
/*button*/
/* button */
--vxe-button-default-background-color: var(--el-bg-color-overlay);
/*input*/
/* input */
--vxe-input-background-color: var(--el-fill-color-blank);
--vxe-input-panel-background-color: var(--el-fill-color-blank);
/*form*/
/* form */
--vxe-form-background-color: var(--el-bg-color);
--vxe-form-validate-error-color: var(--el-color-danger);
/*select*/
/* select */
--vxe-select-option-hover-background-color: var(--el-bg-color-overlay);
--vxe-select-panel-background-color: var(--el-bg-color);
}

View File

@ -6,6 +6,7 @@ const appStore = useAppStore()
const isMobile = computed(() => appStore.device === DeviceEnum.Mobile)
const isDesktop = computed(() => appStore.device === DeviceEnum.Desktop)
/** 设备类型 Composable */
export function useDevice() {
return { isMobile, isDesktop }
}

View File

@ -17,6 +17,7 @@ interface FetchSelectProps {
api: () => Promise<ApiData>
}
/** 下拉选择器 Composable */
export function useFetchSelect(props: FetchSelectProps) {
const { api } = props
@ -24,7 +25,7 @@ export function useFetchSelect(props: FetchSelectProps) {
const options = ref<SelectOption[]>([])
const value = ref<OptionValue>("")
/** 调用接口获取数据 */
// 调用接口获取数据
const loadData = () => {
loading.value = true
options.value = []

View File

@ -18,7 +18,8 @@ const DEFAULT_OPTIONS = {
}
/**
* fnLoading
* @name Composable
* @description fnLoading
* @param fn
* @param options LoadingOptions
* @returns Promise

View File

@ -11,6 +11,7 @@ function setLayoutMode(mode: LayoutModeEnum) {
settingsStore.layoutMode = mode
}
/** 布局模式 Composable */
export function useLayoutMode() {
return { isLeft, isTop, isLeftTop, setLayoutMode }
}

View File

@ -17,14 +17,15 @@ const DEFAULT_PAGINATION_DATA = {
layout: "total, sizes, prev, pager, next, jumper"
}
/** 分页 Composable */
export function usePagination(initPaginationData: PaginationData = {}) {
/** 合并分页参数 */
// 合并分页参数
const paginationData = reactive({ ...DEFAULT_PAGINATION_DATA, ...initPaginationData })
/** 改变当前页码 */
// 改变当前页码
const handleCurrentChange = (value: number) => {
paginationData.currentPage = value
}
/** 改变页面大小 */
// 改变每页显示条数
const handleSizeChange = (value: number) => {
paginationData.pageSize = value
}

View File

@ -17,12 +17,16 @@ export function setRouteChange(to: RouteLocationNormalized) {
latestRoute = to
}
/** 单独监听路由会浪费渲染性能,使用发布订阅模式去进行分发管理 */
/**
* Composable
* 1. watch
* 2. 使
*/
export function useRouteListener() {
// 回调函数集合
const callbackList: Callback[] = []
/** 监听路由变化(可以选择立即执行) */
// 监听路由变化(可以选择立即执行)
const listenerRouteChange = (callback: Callback, immediate = false) => {
// 缓存回调函数
callbackList.push(callback)
@ -32,12 +36,12 @@ export function useRouteListener() {
immediate && latestRoute && callback(latestRoute)
}
/** 移除路由变化事件监听器 */
// 移除路由变化事件监听器
const removeRouteListener = (callback: Callback) => {
emitter.off(key, callback as Handler)
}
/** 组件销毁前移除监听器 */
// 组件销毁前移除监听器
onBeforeUnmount(() => {
for (let i = 0; i < callbackList.length; i++) {
removeRouteListener(callbackList[i])

View File

@ -18,6 +18,7 @@ watch(dynamicTitle, (value, oldValue) => {
}
})
/** 标题 Composable */
export function useTitle() {
return { setTitle }
}

View File

@ -34,25 +34,25 @@ const DEFAULT_CONFIG = {
const bodyEl = ref<HTMLElement>(document.body)
/**
*
* Composable
* 1. body
* 2.
*/
export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
/** 备份文本 */
// 备份文本
let backupText: string
/** 最终配置 */
// 最终配置
let mergeConfig: DefaultConfig
/** 水印元素 */
// 水印元素
let watermarkEl: HTMLElement | null = null
/** 观察器 */
// 观察器
const observer: Observer = {
watermarkElMutationObserver: undefined,
parentElMutationObserver: undefined,
parentElResizeObserver: undefined
}
/** 设置水印 */
// 设置水印
const setWatermark = (text: string, config: Partial<DefaultConfig> = {}) => {
if (!parentEl.value) return console.warn("请在 DOM 挂载完成后再调用 setWatermark 方法设置水印")
// 备份文本
@ -65,7 +65,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
addElListener(parentEl.value)
}
/** 创建水印元素 */
// 创建水印元素
const createWatermarkEl = () => {
const isBody = parentEl.value!.tagName.toLowerCase() === bodyEl.value.tagName.toLowerCase()
const watermarkElPosition = isBody ? "fixed" : "absolute"
@ -84,7 +84,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
parentEl.value!.appendChild(watermarkEl)
}
/** 更新水印元素 */
// 更新水印元素
const updateWatermarkEl = (
options: Partial<{
width: number
@ -97,7 +97,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
options.height && (watermarkEl.style.height = `${options.height}px`)
}
/** 创建 base64 图片 */
// 创建 base64 图片
const createBase64 = () => {
const { color, opacity, size, family, angle, width, height } = mergeConfig
const canvasEl = document.createElement("canvas")
@ -114,7 +114,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
return canvasEl.toDataURL()
}
/** 清除水印 */
// 清除水印
const clearWatermark = () => {
if (!parentEl.value || !watermarkEl) return
// 移除对水印元素和容器元素的监听
@ -130,14 +130,14 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
}
}
/** 刷新水印(防御时调用) */
// 刷新水印(防御时调用)
const updateWatermark = debounce(() => {
clearWatermark()
createWatermarkEl()
addElListener(parentEl.value!)
}, 100)
/** 监听水印元素和容器元素的变化DOM 变化 & DOM 大小变化) */
// 监听水印元素和容器元素的变化DOM 变化 & DOM 大小变化)
const addElListener = (targetNode: HTMLElement) => {
// 判断是否开启防御
if (mergeConfig.defense) {
@ -157,7 +157,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
}
}
/** 移除对水印元素和容器元素的监听,传参可指定要移除哪个监听,不传默认移除全部监听 */
// 移除对水印元素和容器元素的监听,传参可指定要移除哪个监听,不传默认移除全部监听
const removeListener = (kind: "mutation" | "resize" | "all" = "all") => {
// 移除 mutation 监听
if (kind === "mutation" || kind === "all") {
@ -173,7 +173,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
}
}
/** 监听 DOM 变化 */
// 监听 DOM 变化
const addMutationListener = (targetNode: HTMLElement) => {
// 当观察到变动时执行的回调
const mutationCallback = debounce((mutationList: MutationRecord[]) => {
@ -212,7 +212,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
})
}
/** 监听 DOM 大小变化 */
// 监听 DOM 大小变化
const addResizeListener = (targetNode: HTMLElement) => {
// 当 targetNode 元素大小变化时去更新整个水印的大小
const resizeCallback = debounce(() => {

View File

@ -33,7 +33,7 @@ function handleLink(item: RouteLocationMatched) {
router.push(pathCompile(path))
}
/** 监听路由变化,更新面包屑导航信息 */
//
listenerRouteChange((route) => {
if (route.path.startsWith("/redirect/")) return
getBreadcrumb()

View File

@ -44,11 +44,11 @@ function wheelScroll({ deltaY }: WheelEvent) {
/** 获取可能需要的宽度 */
function getWidth() {
/** 可滚动内容的长度 */
//
const scrollbarContentRefWidth = scrollbarContentRef.value!.clientWidth
/** 滚动可视区宽度 */
//
const scrollbarRefWidth = scrollbarRef.value!.wrapRef!.clientWidth
/** 最后剩余可滚动的宽度 */
//
const lastDistance = scrollbarContentRefWidth - scrollbarRefWidth - currentScrollLeft
return { scrollbarContentRefWidth, scrollbarRefWidth, lastDistance }
@ -96,7 +96,7 @@ function moveTo() {
}
}
/** 监听路由变化,移动到目标位置 */
//
listenerRouteChange(() => {
nextTick(moveTo)
})

View File

@ -6,18 +6,21 @@ import { onBeforeMount, onBeforeUnmount, onMounted } from "vue"
/** 参考 Bootstrap 的响应式设计将最大移动端宽度设置为 992 */
const MAX_MOBILE_WIDTH = 992
/** 根据浏览器宽度变化,变换 Layout 布局 */
/**
* @name Composable
* @description Layout
*/
export default () => {
const appStore = useAppStore()
const { listenerRouteChange } = useRouteListener()
/** 用于判断当前设备是否为移动端 */
// 用于判断当前设备是否为移动端
const _isMobile = () => {
const rect = document.body.getBoundingClientRect()
return rect.width - 1 < MAX_MOBILE_WIDTH
}
/** 用于处理窗口大小变化事件 */
// 用于处理窗口大小变化事件
const _resizeHandler = () => {
if (!document.hidden) {
const isMobile = _isMobile()
@ -25,19 +28,20 @@ export default () => {
isMobile && appStore.closeSidebar(true)
}
}
/** 监听路由变化,根据设备类型调整布局 */
// 监听路由变化,根据设备类型调整布局
listenerRouteChange(() => {
if (appStore.device === DeviceEnum.Mobile && appStore.sidebar.opened) {
appStore.closeSidebar(false)
}
})
/** 在组件挂载前添加窗口大小变化事件监听器 */
// 在组件挂载前添加窗口大小变化事件监听器
onBeforeMount(() => {
window.addEventListener("resize", _resizeHandler)
})
/** 在组件挂载后根据窗口大小判断设备类型并调整布局 */
// 在组件挂载后根据窗口大小判断设备类型并调整布局
onMounted(() => {
if (_isMobile()) {
appStore.toggleDevice(DeviceEnum.Mobile)
@ -45,7 +49,7 @@ export default () => {
}
})
/** 在组件卸载前移除窗口大小变化事件监听器 */
// 在组件卸载前移除窗口大小变化事件监听器
onBeforeUnmount(() => {
window.removeEventListener("resize", _resizeHandler)
})

View File

@ -1,14 +1,16 @@
import { ref } from "vue"
/** 焦点 Composable */
export function useFocus() {
/** 是否有焦点 */
// 是否有焦点
const isFocus = ref<boolean>(false)
/** 失去焦点 */
// 失去焦点
const handleBlur = () => {
isFocus.value = false
}
/** 获取焦点 */
// 获取焦点
const handleFocus = () => {
isFocus.value = true
}

View File

@ -15,12 +15,12 @@ function handleSidebarStatus(opened: boolean) {
}
export const useAppStore = defineStore("app", () => {
/** 侧边栏状态 */
// 侧边栏状态
const sidebar: Sidebar = reactive({
opened: getSidebarStatus() !== SIDEBAR_CLOSED,
withoutAnimation: false
})
/** 设备类型 */
// 设备类型
const device = ref<DeviceEnum>(DeviceEnum.Desktop)
// 监听侧边栏 opened 状态
@ -29,17 +29,17 @@ export const useAppStore = defineStore("app", () => {
opened => handleSidebarStatus(opened)
)
/** 切换侧边栏 */
// 切换侧边栏
const toggleSidebar = (withoutAnimation: boolean) => {
sidebar.opened = !sidebar.opened
sidebar.withoutAnimation = withoutAnimation
}
/** 关闭侧边栏 */
// 关闭侧边栏
const closeSidebar = (withoutAnimation: boolean) => {
sidebar.opened = false
sidebar.withoutAnimation = withoutAnimation
}
/** 切换设备类型 */
// 切换设备类型
const toggleDevice = (value: DeviceEnum) => {
device.value = value
}
@ -48,8 +48,8 @@ export const useAppStore = defineStore("app", () => {
})
/**
* SPA pinia 使 store
* SSR setup 使 store
* @description SPA pinia 使 store
* @description SSR setup 使 store
*/
export function useAppStoreOutside() {
return useAppStore(pinia)

View File

@ -26,18 +26,18 @@ function filterDynamicRoutes(routes: RouteRecordRaw[], roles: string[]) {
}
export const usePermissionStore = defineStore("permission", () => {
/** 可访问的路由 */
// 可访问的路由
const routes = ref<RouteRecordRaw[]>([])
/** 有访问权限的动态路由 */
// 有访问权限的动态路由
const addRoutes = ref<RouteRecordRaw[]>([])
/** 根据角色生成可访问的 Routes可访问的路由 = 常驻路由 + 有访问权限的动态路由) */
// 根据角色生成可访问的 Routes可访问的路由 = 常驻路由 + 有访问权限的动态路由)
const setRoutes = (roles: string[]) => {
const accessedRoutes = filterDynamicRoutes(dynamicRoutes, roles)
_set(accessedRoutes)
}
/** 所有路由 = 所有常驻路由 + 所有动态路由 */
// 所有路由 = 所有常驻路由 + 所有动态路由
const setAllRoutes = () => {
_set(dynamicRoutes)
}
@ -51,8 +51,8 @@ export const usePermissionStore = defineStore("permission", () => {
})
/**
* SPA pinia 使 store
* SSR setup 使 store
* @description SPA pinia 使 store
* @description SSR setup 使 store
*/
export function usePermissionStoreOutside() {
return usePermissionStore(pinia)

View File

@ -14,7 +14,7 @@ type SettingsStore = {
type SettingsStoreKey = keyof SettingsStore
export const useSettingsStore = defineStore("settings", () => {
/** 状态对象 */
// 状态对象
const state = {} as SettingsStore
// 遍历 layoutSettings 对象的键值对
for (const [key, value] of Object.entries(layoutSettings)) {
@ -29,7 +29,7 @@ export const useSettingsStore = defineStore("settings", () => {
setConfigLayout(settings)
})
}
/** 获取要缓存的数据:将 state 对象转化为 settings 对象 */
// 获取要缓存的数据:将 state 对象转化为 settings 对象
const _getCacheData = () => {
const settings = {} as LayoutSettings
for (const [key, value] of Object.entries(state)) {
@ -43,8 +43,8 @@ export const useSettingsStore = defineStore("settings", () => {
})
/**
* SPA pinia 使 store
* SSR setup 使 store
* @description SPA pinia 使 store
* @description SSR setup 使 store
*/
export function useSettingsStoreOutside() {
return useSettingsStore(pinia)

View File

@ -96,8 +96,8 @@ export const useTagsViewStore = defineStore("tags-view", () => {
})
/**
* SPA pinia 使 store
* SSR setup 使 store
* @description SPA pinia 使 store
* @description SSR setup 使 store
*/
export function useTagsViewStoreOutside() {
return useTagsViewStore(pinia)

View File

@ -17,20 +17,20 @@ export const useUserStore = defineStore("user", () => {
const tagsViewStore = useTagsViewStore()
const settingsStore = useSettingsStore()
/** 登录 */
// 登录
const login = async ({ username, password, code }: LoginRequestData) => {
const { data } = await loginApi({ username, password, code })
setToken(data.token)
token.value = data.token
}
/** 获取用户详情 */
// 获取用户详情
const getInfo = async () => {
const { data } = await getUserInfoApi()
username.value = data.username
// 验证返回的 roles 是否为一个非空数组,否则塞入一个没有任何作用的默认角色,防止路由守卫逻辑进入无限循环
roles.value = data.roles?.length > 0 ? data.roles : routeSettings.defaultRoles
}
/** 模拟角色变化 */
// 模拟角色变化
const changeRoles = async (role: string) => {
const newToken = `token-${role}`
token.value = newToken
@ -38,7 +38,7 @@ export const useUserStore = defineStore("user", () => {
// 用刷新页面代替重新登录
window.location.reload()
}
/** 登出 */
// 登出
const logout = () => {
removeToken()
token.value = ""
@ -46,13 +46,13 @@ export const useUserStore = defineStore("user", () => {
resetRouter()
_resetTagsView()
}
/** 重置 Token */
// 重置 Token
const resetToken = () => {
removeToken()
token.value = ""
roles.value = []
}
/** 重置 Visited Views 和 Cached Views */
// 重置 Visited Views 和 Cached Views
const _resetTagsView = () => {
if (!settingsStore.cacheTagsView) {
tagsViewStore.delAllVisitedViews()
@ -64,8 +64,8 @@ export const useUserStore = defineStore("user", () => {
})
/**
* SPA pinia 使 store
* SSR setup 使 store
* @description SPA pinia 使 store
* @description SSR setup 使 store
*/
export function useUserStoreOutside() {
return useUserStore(pinia)

View File

@ -6,8 +6,8 @@ import { flatMultiLevelRoutes, history } from "./helper"
const Layouts = () => import("@/layouts/index.vue")
/**
*
* redirect/403/404/login Name
* @name
* @description redirect/403/404/login Name
*/
export const constantRoutes: RouteRecordRaw[] = [
{
@ -252,9 +252,9 @@ export const constantRoutes: RouteRecordRaw[] = [
]
/**
*
* (Roles )
* Name
* @name
* @description (Roles )
* @description Name
*/
export const dynamicRoutes: RouteRecordRaw[] = [
{

View File

@ -1,6 +1,8 @@
// https://www.typescriptlang.org/tsconfig
// https://cn.vuejs.org/guide/typescript/overview#configuring-tsconfig-json
// https://cn.vite.dev/guide/features#typescript-compiler-options
/**
* @link https://www.typescriptlang.org/tsconfig
* @link https://cn.vuejs.org/guide/typescript/overview#configuring-tsconfig-json
* @link https://cn.vite.dev/guide/features#typescript-compiler-options
*/
{
"compilerOptions": {

32
types/vue-router.d.ts vendored
View File

@ -5,49 +5,49 @@ export {}
declare module "vue-router" {
interface RouteMeta {
/**
*
* @description
*/
title?: string
/**
* svg @/assets/icons
* @description svg @/assets/icons
*/
svgIcon?: string
/**
* 使 Element Plus Icon svgIcon svgIcon
* @description 使 Element Plus Icon svgIcon svgIcon
*/
elIcon?: string
/**
* false true
* @description false true
*/
hidden?: boolean
/**
*
* @description
*/
roles?: string[]
/**
* true false
* @description true false
*/
breadcrumb?: boolean
/**
* false true tags-view
* @description false true tags-view
*/
affix?: boolean
/**
* children 1
*
* children
* alwaysShow: true
* @description children 1
* @description
* @description children
* @description alwaysShow: true
*/
alwaysShow?: boolean
/**
* 示例: activeMenu: "/xxx/xxx"
* activeMenu
* 使 hidden: true
* @description 示例: activeMenu: "/xxx/xxx"
* @description activeMenu
* @description 使 hidden: true
*/
activeMenu?: string
/**
*
* false true Name
* @description
* @description false true Name
*/
keepAlive?: boolean
}

View File

@ -54,9 +54,9 @@ export default defineConfig(({ mode }) => {
rollupOptions: {
output: {
/**
*
* 1.
* 2. chunk
* @name
* @description 1.
* @description 2. chunk
*/
manualChunks: {
vue: ["vue", "vue-router", "pinia"],