diff --git a/docs/.vitepress/theme/router/index.ts b/docs/.vitepress/theme/router/index.ts index 437f6b4..60e54d5 100644 --- a/docs/.vitepress/theme/router/index.ts +++ b/docs/.vitepress/theme/router/index.ts @@ -5,8 +5,9 @@ export const routers = [ { text: '🌿 Vue', items: [ - { text: 'Vue3-Common', link: '/Web/Vue/Vue3-Common' }, { text: 'Vue3架构原理', link: '/Web/Vue/Vue3-Architecture' }, + { text: 'Vue3自定义指令', link: '/Web/Vue/Vue3-Directive' }, + { text: 'Vue3 defineModel', link: '/Web/Vue/Vue3-DefineModel' }, { text: 'JavaScript知识点整理', link: '/Web/Vue/JavaScript-Guide' }, { text: '前端包管理器', link: '/Web/Vue/Package' }, { text: 'Vite核心原理', link: '/Web/Vue/Vite-Principle' }, @@ -27,7 +28,6 @@ export const routers = [ { text: 'SpringBoot注解', link: '/Web/SpringBoot/SpringBoot-Annotation' }, { text: 'SpringBoot3原生镜像', link: '/Web/SpringBoot/SpringBoot3-GraalVM' }, { text: 'SpringBoot技巧', link: '/Web/SpringBoot/SpringBoot-Skills' }, - { text: 'SpringBoot Common', link: '/Web/SpringBoot/SpringBoot-Common' }, { text: 'SpringBoot RestClient简介', link: '/Web/SpringBoot/SpringBoot-RestClient' }, { text: 'SpringBoot Redis简介和使用', link: '/Web/SpringBoot/SpringBoot-Redis' }, { text: 'SpringBoot 线程与事件', link: '/Web/SpringBoot/SpringBoot-Thread' } @@ -88,7 +88,7 @@ export const routers = [ { text: '🚀 运维部署', items: [ - { text: 'OpenObserve部署和使用', link: '/DevOps/OpenObserve' }, + { text: '⭐ OpenObserve部署和使用', link: '/DevOps/OpenObserve' }, { text: 'Jenkins部署和使用', link: '/DevOps/Jenkins' }, { text: 'ElasticSearch部署和使用', link: '/DevOps/ElasticSearch' }, { text: 'Docker简介和安装', link: '/DevOps/Docker' }, @@ -98,6 +98,13 @@ export const routers = [ { text: '🏗️ 项目实战', items: [ + { + text: '🏢 通用模块', + items: [ + { text: 'Vue3 Common', link: '/Practice/Common/Vue3-Common' }, + { text: 'SpringBoot Common', link: '/Practice/Common/SpringBoot-Common' }, + ] + }, { text: '🏢 公司项目', items: [ diff --git a/docs/DevOps/Docker.md b/docs/DevOps/Docker.md index 0c9de8e..62a22b6 100644 --- a/docs/DevOps/Docker.md +++ b/docs/DevOps/Docker.md @@ -1,7 +1,6 @@ --- title: Docker简介和安装 date: 2025-12-15 - isGreat: true --- # 一、Docker简介 diff --git a/docs/DevOps/OpenObserve.md b/docs/DevOps/OpenObserve.md index 61b16b7..ab0ce67 100644 --- a/docs/DevOps/OpenObserve.md +++ b/docs/DevOps/OpenObserve.md @@ -1,6 +1,7 @@ --- title: OpenObserve部署和使用 date: 2025-11-26 + isGreat: true --- # 一、基础概念 @@ -551,6 +552,40 @@ public class FluentBitLogger : MonoBehaviour docker-compose文件中也要增加9880端口映射。 ::: +## 3.5 Vue +  发送HTTP数据到FluentBit中: +```ts +export const sendError = (err, instance, info) => { + try { + const log = { + top: 'vue-ui', + level: 'ERROR', + info, + component: instance?.$options?.name || 'Anonymous', + message: err.message, + url: location.href + } + + fetch('http://ip:9880', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(log) + }) + } catch { + + } +} +``` + +  利用app.config.errorHandler监听异常: +```ts +app.config.errorHandler = (err, instance, info) => { + sendError(err, instance, info) +} +``` + # 四、简单使用 ## 3.1 配置数据流   打开控制台,选择数据流->添加数据流,输入fluent bit配置文件中的流名称,选择数据流类型为Logs。 diff --git a/docs/Web/SpringBoot/SpringBoot-Common.md b/docs/Practice/Common/SpringBoot-Common.md similarity index 82% rename from docs/Web/SpringBoot/SpringBoot-Common.md rename to docs/Practice/Common/SpringBoot-Common.md index 66d75ab..6d29356 100644 --- a/docs/Web/SpringBoot/SpringBoot-Common.md +++ b/docs/Practice/Common/SpringBoot-Common.md @@ -365,7 +365,7 @@ public abstract class AbstractException extends RuntimeException { ``` ::: -### 3.4 starters模块 +## 3.4 starters模块   该模块为整个项目的核心模块,在实际项目中,通过引入相应的starter模块,并配合autoconfigure模块中的功能,即可实现快速自动装配。   该模块的pom.xml声明的依赖会注入到实际的项目中。 ::: danger @@ -373,7 +373,7 @@ public abstract class AbstractException extends RuntimeException { 之前的SringBoot2,是在**main->resources->META-INF**目录下新建spring.factories文件。 ::: -#### 3.4.1 stater-jdbc +### 3.4.1 stater-jdbc   该模块主要提供数据库相关的配置功能。   目前实现的功能有: 1. 配置MybatisPlus拦截器,添加乐观锁和分页插件。 @@ -450,7 +450,7 @@ public class MybatisMetaObjectHandler implements MetaObjectHandler {   `@ConditionalOnClass(SqlSessionFactory.class)`表示只有存在SqlSessionFactory类时,这个配置类才会生效。即如果没有 MyBatis 相关依赖,这个配置类会被 Spring 完全忽略。   `@Import`用于导入其他配置类或组件到当前配置类中。 -#### 3.4.2 starter-web +### 3.4.2 starter-web   该模块主要提供web相关的配置功能。   目前实现的功能有: 1. 注册审计拦截器 @@ -748,6 +748,162 @@ HandlerInterceptor 拦截器执行顺序: 4. afterCompletion():视图渲染后 按注册顺序逆序执行。 ::: +### 3.4.3 starter-logging +  在`src->main->resources`中添加`logback-spring.xml`文件: +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DEBUG + + + + ${CONSOLE_LOG_PATTERN} + + ${ENCODING} + + + + + + + + INFO + ACCEPT + DENY + + + ${log.path}/log_info.log + + ${FILE_LOG_PATTERN} + ${ENCODING} + + + + + ${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log + + 100MB + + 15 + + + + + + + WARN + ACCEPT + DENY + + + ${log.path}/log_warn.log + + ${FILE_LOG_PATTERN} + ${ENCODING} + + + + ${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log + + 100MB + + 15 + + + + + + + ERROR + ACCEPT + DENY + + + ${log.path}/log_error.log + + ${FILE_LOG_PATTERN} + ${ENCODING} + + + + ${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log + + 100MB + + 15 + + + + + + ${fluentdHost} + ${fluentdPort} + + topic + ${topic} + + caller + true + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +  该文件会根据当前环境自动添加日志输出节点。 + # 四、项目发布 ## 4.1 发布到Git中 diff --git a/docs/Web/Vue/Vue3-Common.md b/docs/Practice/Common/Vue3-Common.md similarity index 71% rename from docs/Web/Vue/Vue3-Common.md rename to docs/Practice/Common/Vue3-Common.md index aef6633..c469700 100644 --- a/docs/Web/Vue/Vue3-Common.md +++ b/docs/Practice/Common/Vue3-Common.md @@ -1,5 +1,5 @@ --- - title: Vue3-Common + title: Vue3 Common date: 2025-12-15 23:25 --- @@ -32,7 +32,7 @@ ::: # 二、vite.config.ts配置 -## 2.1 生成Typescript类型文件 +## 2.1 生成ts类型文件   安装vite-plugin-dts插件 ```cmd @@ -377,6 +377,167 @@ const app = createApp(App) app.use(router) ``` +8. 在layout中使用: +```vue + + + +``` + +  如果需要对路由菜单进行权限处理,可以使用计算属性过滤一遍: +```ts +const routers = computed(() => { + const menuPathList = menuRoutes.map((item) => item.path) + const removePathList = menuPathList.filter((item) => !authStore.currentUser.menu.includes(item)) + + removePathList.forEach((item) => { + router.removeRoute(capitalizeStr(item.replace('/', ''))) + }) + + return menuRoutes.filter((route) => !removePathList.includes(route.path)) +}) +``` + +::: tip +实现原理: +```ts +import type { RouteComponent, RouteRecordRaw, RouteMeta } from 'vue-router' + +/** + * 任意对象类型 + */ +interface ICommonObj { + [key: string]: any; +} + +/** + * 路由meta配置 + */ +interface IRouteMetaConfig { + [key: string]: RouteMeta; +} + +/** + * 路由路径转为名称 /admin/dashboard -> AdminDashboard + * @param path + */ +export const convertPath2Name = (path: string): string => { + // 移除路径开头和结尾的斜杠(如果存在) + const newPath = path.replace(/^\/|\/$/g, '') + + // 将路径按斜杠分割成多个部分 + const parts = newPath.split('/') + + // 处理每个部分:将连字符后的字母大写,并移除连字符;处理动态参数(如 :id) + return parts.map((part) => + part.split('-').map((subPart) => { + // 处理动态参数(如 :id) + if (subPart.startsWith(':')) { + return subPart.slice(1).charAt(0).toUpperCase() + subPart.slice(2) + } + // 普通部分 + return subPart.charAt(0).toUpperCase() + subPart.slice(1) + }).join('')).join('') +} + +/** + * 根据meta的order排序 + * @param routes 路由列表 + */ +export const sortRoutesByOrder = (routes: RouteRecordRaw[]): RouteRecordRaw[] => { + // 排序当前路由的子路由 + routes.forEach((route) => { + if (route.children && route.children.length > 0) { + // 如果有子路由,递归排序子路由 + route.children = sortRoutesByOrder(route.children) + } + }) + + // 对当前路由按 meta.order 排序 + return routes.sort((a, b) => (a.meta?.order as number || 0) - (b.meta?.order as number || 0)) +} + +/** + * 获取路由 + * @param modules 通过import.meta.glob导入的模块 + * @param layout 布局组件 + * @param metaConfig 路由meta配置 + */ +export const getRoutersByModules = (modules: ICommonObj, + layout: RouteComponent, metaConfig?: IRouteMetaConfig): RouteRecordRaw[] => { + // const modules = import.meta.glob('@/views/admin/**/*.vue') + const routes: RouteRecordRaw[] = [] + + Object.keys(modules).forEach((filePath) => { + // 获取文件的模块路径和文件名 + const parentPath = filePath.substring(0, filePath.lastIndexOf('/')).replace('/src/views', '') + const path = filePath.replace('.vue', '') + .replace('/src/views', '') + .replace(/\[([^\]]+)]/g, '/:$1') + + // 为每个文件生成对应的路由 + const route: RouteRecordRaw = { + path, + name: convertPath2Name(path), + component: modules[filePath] + } + + // 如果存在meta配置 + if (metaConfig) { + route.meta = metaConfig[path] + + // 设置重定向属性 + if (route.meta?.redirect) { + route.redirect = route.meta?.redirect as any + } + } + + // 如果该路径已经存在(嵌套路由),则将其作为子路由 + let parentRoute = routes.find((item) => item.path === parentPath) + if (!parentRoute) { + parentRoute = { + path: parentPath, + name: convertPath2Name(parentPath), + component: layout, + children: [] + } + + // 如果存在meta配置 + if (metaConfig) { + parentRoute.meta = metaConfig[parentPath] + + // 设置重定向属性 + if (parentRoute.meta?.redirect) { + parentRoute.redirect = parentRoute.meta?.redirect + } + } + + routes.push(parentRoute) + } + + // 如果是子路由,加入到父路由的 `children` 数组 + parentRoute.children?.push(route) + }) + + return routes +} +``` + +  核心原理就是利用`import.meta.glob`创建路径->组件的映射,然后结合路由配置表,转为路由对象并添加到`vue router`中。 +::: + ## 5.2 图标组件 1. 安装vite-plugin-svg-icons依赖 ```cmd diff --git a/docs/Web/Vue/Vue3-DefineModel.md b/docs/Web/Vue/Vue3-DefineModel.md new file mode 100644 index 0000000..8632d8e --- /dev/null +++ b/docs/Web/Vue/Vue3-DefineModel.md @@ -0,0 +1,93 @@ +--- + title: Vue3 defineModel + date: 2026-06-05 +--- + +# 一、概念 +  defineModel是对 props + emit的语法糖,返回一个可写的 ref。Vu3.4开始支持。 +  之前的做法: +```ts +// 子组件 +const props = defineProps({ + modelValue: Number +}) + +const emit = defineEmits(['update:modelValue']) + +function increment() { + emit('update:modelValue', props.modelValue + 1) +} +``` + +  现在做法: +```ts +const model = defineModel() +``` + +# 二、简单示例 +  父组件: +```vue + + + +``` + +  子组件: +```vue + + + +``` + +  和`defineProps`定义类似,可以指定类型和默认值。 + +# 三、多个v-model +  父组件: +```vue + +``` + +  子组件: +```vue + + + +``` + +::: tip +defineProps: 只读,不能改 +defineModel: 可写 +::: \ No newline at end of file diff --git a/docs/Web/Vue/Vue3-Directive.md b/docs/Web/Vue/Vue3-Directive.md new file mode 100644 index 0000000..b8901b6 --- /dev/null +++ b/docs/Web/Vue/Vue3-Directive.md @@ -0,0 +1,79 @@ +--- + title: Vue3自定义指令 + date: 2026-06-05 +--- + +# 一、概念 +  自定义指令(Directive)​ 是 Vue 提供的一种机制,用于直接操作 DOM,封装可复用的底层 DOM 行为。它是对模板能力的补充,当现有模板语法(v-if / v-bind / v-on)不够用时,就可以用指令。 + +# 二、简单示例 +  注册: +```ts +app.directive('demo', { + mounted(el, binding) { + console.log(el, binding) + } +}) +``` + +  使用: +```vue +
+``` + +  使用该指令,就会触发打印效果。 + +# 三、生命周期 +| 钩子 | 说明 | +| ----- | ----- | +| created | 绑定前 | +| beforeMount | 元素挂载前 | +| mounted | 元素已挂载 | +| beforeUpdate | 更新前 | +| updated | 更新后 | +| beforeUnmount | 卸载前 | +| unmounted | 卸载后 | + +# 四、参数 +  mounted(el, binding, vnode, prevVnode): +| 参数 | 说明 | +| ----- | ----- | +| el | 当前 DOM 元素 | +| binding.value | 指令绑定的值 | +| binding.arg | 参数 | +| binding.modifiers | 修饰符 | +| vnode | 虚拟节点 | + +# 五、封装 +  在`src`目录新建`directives/**.ts`,定义指令: +```ts +import { useAuthStore } from '@/stores/auth' + +export default { + mounted(el, binding) { + const authStore = useAuthStore() + const permission = binding.value + + const hasPermission = authStore.currentUser?.permission?.includes(permission) + + if (!hasPermission) { + el.parentNode?.removeChild(el) + } + } +} +``` + +  该指令根据用户权限控制DOM是否显示。 + +  然后在`main.ts`中注册指令: +```ts +import permissionDirective from '@/directives/permission' + +app.directive('permission', permissionDirective) +``` + +  最后在需要的元素中加上`v-permission=""`即可。 + +::: tip +自定义指令只做DOM相关的事情,比如隐藏DOM,禁止点击、修改样式等等。 +:::