# FaAnimatedBeam 动画光束 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------ | -------------------------- | ------------- | ----------- | | containerRef | 容器元素 | `HTMLElement` | - | | fromRef | 起始元素 | `HTMLElement` | - | | toRef | 结束元素 | `HTMLElement` | - | | curvature | 曲率,数值越大,路径越弯曲 | `number` | `0` | | reverse | 是否反向 | `boolean` | `false` | | pathColor | 路径颜色 | `string` | `gray` | | pathWidth | 路径宽度 | `number` | `2` | | pathOpacity | 路径透明度 | `number` | `0.2` | | gradientStartColor | 光束渐变动画起始颜色 | `string` | `#FFAA40` | | gradientStopColor | 光束渐变动画结束颜色 | `string` | `#9C40FF` | | delay | 动画延迟时间 | `number` | `0` | | duration | 动画持续时间 | `number` | 随机 4-7 秒 | | startXOffset | 起始点 X 偏移量 | `number` | `0` | | startYOffset | 起始点 Y 偏移量 | `number` | `0` | | endXOffset | 结束点 X 偏移量 | `number` | `0` | | endYOffset | 结束点 Y 偏移量 | `number` | `0` | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-animated-count-to.md --- # FaAnimatedCountTo 动画计数 包含 `FaAnimatedCountToGroup` 和 `FaAnimatedCountTo` 两个组件。 ## `FaAnimatedCountTo` Props | 属性名 | 说明 | 类型 | 默认值 | | --------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | | value | 数值 | `number` | - | | format | 格式化选项 | [Intl.NumberFormatOptions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options) | - | | locales | 语言环境 | [Intl.LocalesArgument](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#locales) | - | | prefix | 前缀 | `string` | - | | suffix | 后缀 | `string` | - | | trend | 控制数字方向 | `1 \| 0 \| -1` | - | | transformTiming | 转换动画 | [EffectTiming](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffect/getTiming#return_value) | - | | spinTiming | 旋转动画 | [EffectTiming](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffect/getTiming#return_value) | - | | opacityTiming | 透明度动画 | [EffectTiming](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEffect/getTiming#return_value) | - | | willChange | 优化性能 | `boolean` | - | | class | 自定义类名 | `string` | - | ## `FaAnimatedCountTo` Events | 事件名 | 说明 | 参数 | | --------------- | ------------ | ---- | | animationsstart | 动画开始时 | - | | animationsend | 动画结束时 | - | --- --- url: /components/fa-auth.md --- # FaAuth 鉴权 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | -------------------------------------------------------- | -------------------- | ------- | | value | 权限数据,可传入单个或一组需要验证的权限数据 | `string \| string[]` | - | | all | 是否验证全部权限数据,默认匹配中其中一项则判定为鉴权成功 | `boolean` | `false` | ## Slots | 插槽名 | 说明 | | ------- | ------------------------ | | default | 鉴权成功显示的 HTML 内容 | | no-auth | 鉴权失败显示的 HTML 内容 | --- --- url: /components/fa-avatar.md --- # FaAvatar 头像 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------- | ------------------------------------ | ---------------------- | ---------- | | src | 头像图片地址,支持网络图片和本地图片 | `string` | - | | fallback | 头像图片加载失败时显示的文字 | `string` | - | | shape | 头像形状,默认圆形 | `'square' \| 'circle'` | `'circle'` | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | ------------------------------------------------ | | default | 头像图片加载失败时显示,设置会覆盖 fallback 属性 | --- --- url: /components/fa-badge.md --- # FaBadge 徽章 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------- | ---------- | ------------------------------------------- | ----------- | | variant | 徽章类型 | `'default' \| 'secondary' \| 'destructive'` | `'default'` | | value | 徽章内容 | `string \| number \| boolean` | - | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-blur-reveal.md --- # FaBlurReveal 模糊显示 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------- | ---------------------- | -------- | ------ | | duration | 持续时间 | `number` | `1` | | delay | 延迟时间 | `number` | `1` | | blur | 子组件的模糊量 | `string` | `10px` | | yOffset | 入口动画的垂直偏移距离 | `number` | `20` | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------- | | default | 默认内容 | --- --- url: /components/fa-border-beam.md --- # FaBorderBeam 边框光束 ## Props | 属性名 | 说明 | 类型 | 默认值 | | --------- | ------------------------ | -------- | --------- | | size | 大小 | `number` | `200` | | duration | 持续时间 | `number` | `15000` | | delay | 延迟时间 | `number` | `0` | | anchor | 锚点,确定其沿边界的位置 | `string` | `90` | | border | 边框宽度 | `number` | `1` | | colorFrom | 起始颜色 | `string` | `#ffaa40` | | colorTo | 结束颜色 | `string` | `#9c40ff` | --- --- url: /components/fa-button.md --- # FaButton 按钮 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------- | ---------- | ----------------------------------------------------------------------------- | ----------- | | variant | 按钮类型 | `'default' \| 'link' \| 'secondary' \| 'destructive' \| 'outline' \| 'ghost'` | `'default'` | | size | 按钮尺寸 | `'default' \| 'sm' \| 'lg' \| 'icon'` | `'default'` | | class | 自定义类名 | `string` | - | | disabled | 是否禁用 | `boolean` | `false` | | loading | 是否加载中 | `boolean` | `false` | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-card.md --- # FaCard 卡片 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------ | -------------- | -------- | ------ | | title | 标题 | `string` | - | | description | 描述 | `string` | - | | class | 自定义类名 | `string` | - | | headerClass | 头部自定义类名 | `string` | - | | contentClass | 内容自定义类名 | `string` | - | | footerClass | 底部自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | | header | 头部内容 | | footer | 底部内容 | --- --- url: /components/fa-carousel.md --- # FaCarousel 轮播图 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------ | ---------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------------- | | opts | 选择项,详见 Embla Carousel [Options](https://www.embla-carousel.com/api/options/) | `object` | - | | orientation | 方向 | `'vertical' \| 'horizontal'` | `'horizontal'` | | autoplay | 自动播放,详见 Embla Carousel [Autoplay Options](https://www.embla-carousel.com/plugins/autoplay/#options) | `object` | - | | autoScroll | 自动滚动,详见 Embla Carousel [Auto Scroll Options](https://www.embla-carousel.com/plugins/auto-scroll/#options) | `object` | - | | fade | 淡入淡出 | `boolean` | `false` | | class | 自定义类名 | `string` | - | | contentClass | 内容容器自定义类名 | `string` | - | | itemClass | 内容项自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-checkbox.md --- # FaCheckbox 复选框 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------- | -------- | --------- | ------- | | modelValue(v-model) | 绑定值 | `boolean` | - | | disabled | 是否禁用 | `boolean` | `false` | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-code.md --- # FaCode 代码块 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ----------------------------- | ---------- | -------- | ------ | | code | 代码 | `string` | - | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-code-preview.md --- # FaCodePreview 代码预览 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | ---- | -------- | ------ | | code | 代码 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------- | | default | 默认插槽 | --- --- url: /components/fa-count-to.md --- # FaCountTo 计数到 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ---------- | ------------ | ------------------- | ---------- | | startVal | 开始值 | `number` | - | | endVal | 结束值 | `number` | - | | autoplay | 是否自动播放 | `boolean` | `true` | | duration | 持续时间 | `number` | `2000` | | transition | 过渡动画 | `TransitionPresets` | `'linear'` | | delay | 延迟时间 | `number` | `0` | | decimals | 小数位数 | `number` | `0` | | separator | 分隔符 | `string` | `','` | | prefix | 前缀 | `string` | - | | suffix | 后缀 | `string` | - | ## Events | 事件名 | 说明 | 参数 | | ---------- | ---- | ------------ | | onStarted | 开始 | `() => void` | | onFinished | 结束 | `() => void` | ## Expose | 属性名 | 说明 | 类型 | | ------ | ---- | ------------ | | start | 开始 | `() => void` | | end | 结束 | `() => void` | --- --- url: /components/fa-digital-card.md --- # FaDigitalCard 数字卡片 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ----------- | ------------------------------------ | ---------------------------- | ------ | | title | 标题 | `string` | - | | titleTips | 标题提示 | `string` | - | | icon | 图标,即 `FaIcon` 组件的 `name` 属性 | `string` | - | | digital | 数字 | `string \| number` | - | | description | 描述 | `string` | - | | trend | 趋势 | `'up' \| 'stable' \| 'down'` | - | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-divider.md --- # FaDivider 分割线 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ----------------------------- | ---------- | ------------------ | ------ | | position | 位置 | `'start' \| 'end'` | - | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-drawer.md --- # FaDrawer 抽屉 ## Props | 属性名 | 说明 | 类型 | 默认值 | | --------------------- | ------------------ | ---------------------------------------- | --------- | | modelValue(v-model) | 绑定值 | `boolean` | - | | side | 位置 | `'top' \| 'bottom' \| 'left' \| 'right'` | `'right'` | | title | 标题 | `string` | - | | description | 描述 | `string` | - | | loading | 是否加载中 | `boolean` | `false` | | closable | 是否显示关闭按钮 | `boolean` | `true` | | centered | 头部是否居中 | `boolean` | `false` | | bordered | 是否显示边框 | `boolean` | `true` | | overlay | 是否显示遮罩 | `boolean` | `true` | | overlayBlur | 是否开启遮罩模糊 | `boolean` | `false` | | showConfirmButton | 是否显示确认按钮 | `boolean` | `true` | | showCancelButton | 是否显示取消按钮 | `boolean` | `false` | | confirmButtonText | 确认按钮文本 | `string` | `'确认'` | | cancelButtonText | 取消按钮文本 | `string` | `'取消'` | | confirmButtonDisabled | 确认按钮是否禁用 | `boolean` | `false` | | confirmButtonLoading | 确认按钮是否加载中 | `boolean` | `false` | | header | 是否显示头部内容 | `boolean` | `true` | | footer | 是否显示底部内容 | `boolean` | `true` | | closeOnClickOverlay | 是否点击遮罩关闭 | `boolean` | `true` | | closeOnPressEscape | 是否按下 ESC 关闭 | `boolean` | `true` | | contentClass | 内容自定义类名 | `string` | - | | headerClass | 头部自定义类名 | `string` | - | | footerClass | 底部自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | | header | 头部内容 | | footer | 底部内容 | ## Events | 事件名 | 说明 | 回调参数 | | ------- | ------------------ | ------------ | | open | 打开时触发 | `() => void` | | opened | 打开动画结束时触发 | `() => void` | | close | 关闭时触发 | `() => void` | | closed | 关闭动画结束时触发 | `() => void` | | confirm | 确认时触发 | `() => void` | | cancel | 取消时触发 | `() => void` | --- --- url: /components/fa-dropdown.md --- # FaDropdown 下拉菜单 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ---------------- | -------- | --------------------------------------------------------------------------------------------- | ---------- | | align | 对齐方式 | `'start' \| 'center' \| 'end'` | `'center'` | | alignOffset | 对齐偏移 | `number` | `0` | | side | 方向 | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | | sideOffset | 方向偏移 | `number` | `0` | | collisionPadding | 碰撞填充 | `number \| Partial>` | `0` | | items | 菜单项 | `{label: string, icon?: string, disabled?: boolean, hide?: boolean, handle?: () => void}[][]` | - | --- --- url: /components/fa-fixed-action-bar.md --- # FaFixedActionBar 固定底部操作栏 ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-flip-card.md --- # FaFlipCard 翻转卡片 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | ---------- | ------------ | ------ | | rotate | 翻转方向 | `'x' \| 'y'` | `'y'` | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | | back | 自定义背面内容 | --- --- url: /components/fa-flip-words.md --- # FaFlipWords 翻转文字 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------- | ---------------------------- | -------- | ------ | | words | 设置动画的单词数组 | `string` | - | | duration | 翻转到下个单词的动画持续时间 | `number` | `3000` | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-glowy-card.md --- # FaGlowyCard 发光卡片 包含 `FaGlowyCardWrapper` 和 `FaGlowyCard` 两个组件。 ## `FaGlowyCardWrapper` Props | 属性名 | 说明 | 类型 | 默认值 | | ---------- | ------------ | -------- | ------ | | hue | HSL 色相值 | `number` | `210` | | saturation | HSL 饱和度值 | `number` | `100` | | lightness | HSL 亮度值 | `number` | `50` | | size | 聚光灯大小 | `number` | `200` | | border | 卡片边框 | `number` | `2` | | radius | 卡片圆角 | `number` | `10` | --- --- url: /components/fa-gradient-button.md --- # FaGradientButton 渐变按钮 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------ | -------------- | ---------- | ------------ | | colors | 颜色数组 | `string[]` | 彩虹颜色数组 | | duration | 持续时间 | `number` | `2500` | | class | 自定义类名 | `string` | - | | contentClass | 内容自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------- | | default | 按钮内容 | --- --- url: /components/fa-icon.md --- # FaIcon 图标 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | -------------------------------------------------------------------------------------------------- | -------- | ------ | | name | 图标名称,支持 `本地 svg 文件` / `Iconify 图标` / `UnoCSS 图标`,详细可阅读《[图标](/guide/icon)》 | `string` | - | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-icon-picker.md --- # FaIconPicker 图标选择器 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------------------- | ---------- | ------ | -------- | | modelValue(v-model) | 图标名称 | `string` | - | ## Slots | 插槽名 | 说明 | 类型 | | ------- | -------------- | ------------------ | | default | 自定义默认内容 | `{ icon: string }` | --- --- url: /components/fa-input.md --- # FaInput 输入框 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------- | ---------- | --------- | ------ | | modelValue(v-model) | 输入框值 | `string` | - | | disabled | 是否禁用 | `boolean` | false | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-interactive-button.md --- # FaInteractiveButton 交互式按钮 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | ---------- | -------- | ------ | | text | 按钮文本 | `string` | - | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-kbd.md --- # FaKbd 键盘 ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-layout-container.md --- # FaLayoutContainer 布局容器 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------------------------------------------- | ------------------------ | ------------------ | ------- | | vertical | 是否垂直布局 | `boolean` | `false` | | enableLeftSide | 是否启用左侧边栏 | `boolean` | `true` | | enableRightSide | 是否启用右侧边栏 | `boolean` | `true` | | enableTopSide | 是否启用顶部边栏 | `boolean` | `true` | | enableBottomSide | 是否启用底部边栏 | `boolean` | `true` | | leftSideWidth | 左侧边栏宽度 | `number \| string` | `300` | | rightSideWidth | 右侧边栏宽度 | `number \| string` | `300` | | topSideHeight | 顶部边栏高度 | `number \| string` | `200` | | bottomSideHeight | 底部边栏高度 | `number \| string` | `200` | | hideLeftSideToggle | 是否隐藏左侧边栏切换按钮 | `boolean` | `false` | | hideRightSideToggle | 是否隐藏右侧边栏切换按钮 | `boolean` | `false` | | hideTopSideToggle | 是否隐藏顶部边栏切换按钮 | `boolean` | `false` | | hideBottomSideToggle | 是否隐藏底部边栏切换按钮 | `boolean` | `false` | | class | 自定义类名 | `string` | - | | leftSideClass | 左侧边栏自定义类名 | `string` | - | | rightSideClass | 右侧边栏自定义类名 | `string` | - | | topSideClass | 顶部边栏自定义类名 | `string` | - | | bottomSideClass | 底部边栏自定义类名 | `string` | - | | defaultClass | 默认自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ---------------------------------- | -------------- | | default | 自定义默认内容 | | leftSide | 自定义左侧内容 | | rightSide | 自定义右侧内容 | | topSide | 自定义顶部内容 | | bottomSide | 自定义底部内容 | --- --- url: /components/fa-link-preview.md --- # FaLinkPreview 链接预览 ## Props | 属性名 | 说明 | 类型 | 默认值 | | --------- | ------------------------------------------ | --------- | ------- | | class | 主元素自定义类名 | `string` | - | | linkClass | 链接元素自定义类名 | `string` | - | | width | 宽度 | `number` | `200` | | height | 高度 | `number` | `150` | | isStatic | 预览图像是静态的还是URL预览 | `boolean` | `false` | | imageSrc | 静态预览图(如果 isStatic 为 true 则需要) | `string` | - | | url | URL预览(如果 isStatic 为 false 则需要) | `string` | - | --- --- url: /components/fa-loading.md --- # FaLoading 加载遮罩 ## 示例 ```ts import { loadingHide, loadingShow } from '@/ui/components/FaLoading' loadingShow({ type: 'plane', size: 50, text: '加载中...', }) setTimeout(() => { loadingHide() }, 2000) ``` ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------- | --------- | | type | 加载图案类型 | `'plane' \| 'chase' \| 'bounce' \| 'wave' \| 'pulse' \| 'flow' \| 'swing' \| 'circle' \| 'circle-fade' \| 'grid' \| 'fold' \| 'wander'` | `'plane'` | | size | 加载图案大小 | `number` | `50` | | text | 加载文本 | `string` | - | --- --- url: /components/fa-marquee.md --- # FaMarquee 跑马灯 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------ | ------------------ | --------- | ------- | | class | 自定义类名 | `string` | - | | reverse | 是否反向 | `boolean` | `false` | | pauseOnHover | 是否悬停暂停 | `boolean` | `false` | | vertical | 是否垂直滚动 | `boolean` | `false` | | repeat | 跑马灯内容重复次数 | `number` | `4` | ## Slots | 插槽名 | 说明 | | ------- | -------- | | default | 跑马灯内容 | ## 其他 可以通过设置以下 CSS 变量来自定义项目之间的速度和间距: * `--duration`:控制动画的速度 * `--gap`:控制项目之间的间距 --- --- url: /components/fa-modal.md --- # FaModal 弹窗 ## Props | 属性名 | 说明 | 类型 | 默认值 | | --------------------- | ------------------ | --------------------------------------------- | -------- | | modelValue(v-model) | 是否显示 | `boolean` | - | | title | 标题 | `string` | - | | description | 描述 | `string` | - | | icon | 图标 | `'info' \| 'success' \| 'warning' \| 'error'` | - | | loading | 是否加载中 | `boolean` | - | | closable | 是否显示关闭按钮 | `boolean` | `true` | | maximize | 是否最大化 | `boolean` | `false` | | maximizable | 是否显示最大化按钮 | `boolean` | `false` | | draggable | 是否可拖动 | `boolean` | `false` | | center | 是否内容居中 | `boolean` | `false` | | border | 是否显示边框 | `boolean` | `true` | | alignCenter | 是否窗口居中 | `boolean` | `false` | | overlay | 是否显示遮罩 | `boolean` | `true` | | overlayBlur | 是否开启遮罩模糊 | `boolean` | `false` | | showConfirmButton | 是否显示确认按钮 | `boolean` | `true` | | showCancelButton | 是否显示取消按钮 | `boolean` | `false` | | confirmButtonText | 确认按钮文本 | `string` | `'确认'` | | cancelButtonText | 取消按钮文本 | `string` | `'取消'` | | confirmButtonDisabled | 确认按钮是否禁用 | `boolean` | `false` | | confirmButtonLoading | 确认按钮是否加载中 | `boolean` | `false` | | header | 是否显示头部内容 | `boolean` | `true` | | footer | 是否显示底部内容 | `boolean` | `true` | | closeOnClickOverlay | 是否点击遮罩关闭 | `boolean` | `true` | | closeOnPressEscape | 是否按下 ESC 关闭 | `boolean` | `true` | | class | 自定义类名 | `string` | - | | headerClass | 头部自定义类名 | `string` | - | | contentClass | 内容自定义类名 | `string` | - | | footerClass | 底部自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | | header | 头部内容 | | footer | 底部内容 | ## Events | 事件名 | 说明 | 回调参数 | | ------- | ------------------ | ------------ | | open | 打开时触发 | `() => void` | | opened | 打开动画结束时触发 | `() => void` | | close | 关闭时触发 | `() => void` | | closed | 关闭动画结束时触发 | `() => void` | | confirm | 确认时触发 | `() => void` | | cancel | 取消时触发 | `() => void` | --- --- url: /index.md --- --- --- url: /components/fa-page-header.md --- # FaPageHeader 页头 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------ | ------------ | -------- | ------ | | title | 标题 | `string` | - | | description | 描述 | `string` | - | | class | 自定义类名 | `string` | - | | mainClass | 主容器类名 | `string` | - | | defaultClass | 默认容器类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ----------- | -------------- | | default | 自定义默认内容 | | title | 标题内容 | | description | 描述内容 | --- --- url: /components/fa-page-main.md --- # FaPageMain 内容块 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ---------- | ---------------------------------------- | --------- | ------- | | title | 标题 | `string` | - | | collaspe | 是否折叠 | `boolean` | `false` | | height | 展示高度,当 `collaspe` 为 `true` 时生效 | `string` | - | | class | 自定义类名 | `string` | - | | titleClass | 标题区自定义类名 | `string` | - | | mainClass | 主容器自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | | title | 标题区内容 | --- --- url: /components/fa-pagination.md --- # FaPagination 分页 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | -------- | -------- | ------ | | page | 当前页码 | `number` | - | | size | 每页条数 | `number` | - | | total | 总数 | `number` | - | ## Events | 事件名 | 说明 | 参数 | | ---------- | -------------- | ------------------------ | | pageChange | 页码改变时触发 | `(page: number) => void` | --- --- url: /components/fa-particles-bg.md --- # FaParticlesBg 粒子背景 ## Props | 属性名 | 说明 | 类型 | 默认值 | | --------- | ------------------------------------------------------ | -------- | ------ | | color | 粒子颜色,支持 HEX 颜色代码 | `string` | `#FFF` | | quantity | 粒子数量 | `number` | `100` | | staticity | 根据鼠标的接近程度确定粒子移动的量,数值越大,移动越慢 | `number` | `50` | | ease | 粒子移动的缓和效果,数值越小,会使粒子更紧密地跟随鼠标 | `number` | `50` | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-password-strength.md --- # FaPasswordStrength 密码强度 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------- | ---- | -------- | ------ | | password | 密码 | `string` | - | --- --- url: /components/fa-pattern-bg.md --- # FaPatternBg 图案背景 ## Props | 属性名 | 说明 | 类型 | 默认值 | | --------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | class | 自定义类名 | `string` | - | | variant | 变体 | `'grid' \| 'dot' \| 'big-dot'` | `'grid'` | | size | 尺寸 | `'xs' \| 'sm' \| 'md' \| 'lg'` | `'md'` | | mask | 遮罩 | `'ellipse' \| 'ellipse-top' \| 'ellipse-bottom' \| 'ellipse-left' \| 'ellipse-right' \| 'ellipse-top-left' \| 'ellipse-top-right' \| 'ellipse-bottom-left' \| 'ellipse-bottom-right'` | `'ellipse'` | | animate | 动画 | `boolean` | `false` | | direction | 背景运动方向 | `'top' \| 'bottom' \| 'left' \| 'right' \| 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `'top'` | | speed | 动画持续时间 | `number` | `10000` | ## Slots | 名称 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-pin-input.md --- # FaPinInput 数字输入框 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------- | ---- | -------- | ------ | | modelValue(v-model) | 值 | `string` | - | | length | 长度 | `number` | `6` | --- --- url: /components/fa-popover.md --- # FaPopover 浮动面板 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ---------------------------- | ---------------- | --------------------------------------------------------------------------- | ---------- | | open | 手动控制是否打开 | `boolean` | - | | align | 对齐方式 | `'start' \| 'center' \| 'end'` | `'center'` | | alignOffset | 对齐偏移 | `number` | `0` | | side | 方向 | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | | sideOffset | 方向偏移 | `number` | `0` | | collisionPadding | 碰撞填充 | `number \| Partial>` | `0` | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | | panel | 面板内容 | --- --- url: /components/fa-scratch-off.md --- # FaScratchOff 刮刮乐 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------------------- | ------------------------- | -------------------------- | ----------------------------------- | | width | 宽度 | `number` | `250` | | height | 高度 | `number` | `250` | | minScratchPercentage | 最小刮除百分比,0-100之间 | `number` | `50` | | gradientColors | 渐变色,用于划痕效果 | `[string, string, string]` | `['#A97CF8', '#F38CB8', '#FDCC92']` | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | ## Events | 事件名 | 说明 | 参数 | | -------- | -------- | ---- | | complete | 刮除完成 | - | --- --- url: /components/fa-scroll-area.md --- # FaScrollArea 滚动区域 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------- | ------------------------------------ | --------- | -------------------------- | | horizontal | 是否水平 | `boolean` | `false` | | scrollbar | 是否显示滚动条 | `boolean` | `true` | | mask | 是否显示遮罩 | `boolean` | `false` | | gradientColor | 遮罩渐变颜色,会从透明渐变到遮罩颜色 | `string` | `'hsl(var(--background))'` | | class | 自定义类名 | `string` | - | | contentClass | 内容自定义类名 | `string` | - | ## Slots | 名称 | 说明 | | ------- | -------- | | default | 默认插槽 | --- --- url: /components/fa-select.md --- # FaSelect 选择器 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------- | -------- | -------------------------------------------------------- | ------- | | modelValue(v-model) | 值 | `string` | - | | disabled | 是否禁用 | `boolean` | `false` | | options | 选项 | `{ label: string, value: string, disabled?: boolean }[]` | - | --- --- url: /components/fa-slider.md --- # FaSlider 滑块 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------- | -------------------------------------- | ---------------------------- | -------------- | | modelValue(v-model) | 值 | `number[]` | - | | defaultValue | 默认值,当您不需要控制滑块的状态时使用 | `number[]` | `[0]` | | disabled | 是否禁用 | `boolean` | `false` | | inverted | 是否反转 | `boolean` | `false` | | max | 最大值 | `number` | `100` | | min | 最小值 | `number` | `0` | | step | 步长 | `number` | `1` | | orientation | 方向 | `'horizontal' \| 'vertical'` | `'horizontal'` | | thumbAlignment | 滑块对齐方式 | `'contain' \| 'overflow'` | `'contain'` | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-sparkles-text.md --- # FaSparklesText 闪烁文字 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------- | ------------ | ----------------------------------- | ----------------------------------------- | | text | 文字内容 | `string` | - | | sparklesCount | 闪烁星星数量 | `number` | `10` | | colors | 闪烁颜色 | `{ first: string, second: string }` | `{ first: '#9E7AFF', second: '#FE8BBB' }` | | class | 自定义类名 | `string` | - | --- --- url: /components/fa-sparkline.md --- # FaSparkline 迷你图 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------ | ----------------------------- | -------------------------------------------------- | --------- | | value | 迷你图数据 | `number[] \| { value: number, tooltip: string }[]` | - | | width | 展示宽度 | `number` | `100` | | height | 展示高度 | `number` | `30` | | stroke-width | 折线宽度 | `number` | `3` | | stroke-color | 折线颜色 | `string` | `#dc2b33` | | fill-color | 填充颜色 | `string` | - | | cursor-color | 鼠标 hover 时辅助线颜色 | `string` | `#dc2b33` | | spot-color | 鼠标 hover 时辅助点颜色 | `string` | `#dc2b33` | | tooltip | 鼠标 hover 时是否显示文字提示 | `boolean` | `false` | --- --- url: /components/fa-spotlight-card.md --- # FaSpotlightCard 聚光卡片 ## Props | 属性名 | 说明 | 类型 | 默认值 | | --------------- | ------------------------ | -------- | ----------------------- | | gradientSize | 聚光灯效果的半径 | `number` | `200` | | gradientColor | 聚光灯渐变的颜色 | `string` | `'hsl(var(--primary))'` | | gradientOpacity | 聚光灯渐变效果的不透明度 | `number` | `0.1` | | class | 自定义类名 | `string` | - | | slotClass | 插槽的父容器自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-storage-box.md --- # FaStorageBox 储物箱 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------ | ------------------ | ----------------- | ------ | | data | 需要储存的数据 | `object \| any[]` | - | | name | 数据存放的命名空间 | `string` | - | | title | 下拉面板标题 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | ## Events | 事件名 | 说明 | 回调参数 | | ------- | ---------------------------- | ---------------------------------- | | takeOut | 点击下拉面板中某条记录时触发 | `() => { value: object \| any[] }` | --- --- url: /components/fa-switch.md --- # FaSwitch 开关 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------- | -------------------------------------------- | --------- | ------- | | modelValue(v-model) | 值 | `boolean` | - | | disabled | 是否禁用 | `boolean` | `false` | | onIcon | 开启状态图标,即 `FaIcon` 组件的 `name` 属性 | `string` | - | | offIcon | 关闭状态图标,即 `FaIcon` 组件的 `name` 属性 | `string` | - | --- --- url: /components/fa-tabs.md --- # FaTabs 标签页 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------------- | ---------- | ------------------------------------------------------------- | ------ | | modelValue(v-model) | 值 | `string \| number` | - | | list | 选项卡 | `{ icon?: string, label: string, value: string \| number }[]` | - | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------------------------ | ---------- | | `list` 属性的 `value` 值 | 标签页内容 | --- --- url: /components/fa-text-highlight.md --- # FaTextHighlight 文字高亮 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------------ | ---------------- | -------- | --------- | | delay | 延迟时间 | `number` | `0` | | duration | 持续时间 | `number` | `2000` | | textEndColor | 动画末尾文本颜色 | `string` | `inherit` | | class | 自定义类名 | `string` | - | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | --- --- url: /components/fa-time-ago.md --- # FaTimeAgo 可阅读时间 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------------- | ---------------------- | ---------------------------- | ------------ | | date | 日期 | `Date` | `new Date()` | | max | 显示完整日期的最大单位 | `UseTimeAgoUnitNamesDefault` | - | | messages | 格式化字符串的信息 | `UseTimeAgoMessages` | - | | showSecond | 是否显示秒 | `boolean` | `false` | | updateInterval | 更新间隔 | `number` | `30_000` | --- --- url: /components/fa-toast.md --- # FaToast 轻提示 ## 使用示例 ```ts import { toast } from 'vue-sonner' toast('Event has been created') toast('Event has been created', { description: 'Monday, January 3rd at 6:00pm' }) toast.success('Event has been created') toast.error('Event has not been created') toast('Event has been created', { action: { label: 'Undo', onClick: () => console.log('Undo') } }) ``` --- --- url: /components/fa-tooltip.md --- # FaTooltip 文字提示 ## Props | 属性名 | 说明 | 类型 | 默认值 | | -------- | ------------ | ---------------------------------------- | ---------- | | text | 内容 | `string` | - | | delay | 延迟显示时间 | `number` | `700` | | side | 位置 | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | | align | 对齐方式 | `'start' \| 'center' \| 'end'` | `'center'` | | disabled | 是否禁用 | `boolean` | `false` | ## Slots | 插槽名 | 说明 | | ------- | -------------- | | default | 自定义默认内容 | | content | 自定义内容 | --- --- url: /components/fa-trend.md --- # FaTrend 趋势标记 ## Props | 属性名 | 说明 | 类型 | 默认值 | | ------- | -------- | ---------------- | ------- | | value | 内容 | `string` | - | | type | 类型 | `'up' \| 'down'` | `up` | | prefix | 前缀 | `string` | - | | suffix | 后缀 | `string` | - | | reverse | 颜色反转 | `boolean` | `false` | --- --- url: /components/file-upload.md --- # FileUpload 文件上传 ## Props | 参数 | 说明 | 类型 | 可选值 | 默认值 | | :------ | :----------------------------------------------------------------------- | :------ | :----- | :------------- | | action | 必选参数,上传的地址 | string | - | - | | headers | 设置上传的请求头部 | object | - | - | | data | 上传时附带的额外参数 | object | - | - | | name | 上传的文件字段名 | string | - | file | | size | 上传文件大小限制,单位为MB | number | - | 2 | | max | 上传数量限制 | number | - | 3 | | files | 文件列表,例如:`[{name: 'xxx.jpg', url: 'http://xxx.cdn.com/xxx.jpg'}]` | array | - | \[] | | notip | 是否隐藏提示栏 | boolean | - | false | | ext | 支持的文件类型 | array | - | \['zip', 'rar'] | --- --- url: /components/image-preview.md --- # ImagePreview 图片预览 ## Props | 参数 | 说明 | 类型 | 可选值 | 默认值 | | :----- | :------- | :----- | :----- | :----- | | src | 图片链接 | string | - | - | | width | 展示宽度 | string | - | - | | height | 展示高度 | string | - | - | --- --- url: /components/images-upload.md --- # ImagesUpload 多图上传 ## Props | 参数 | 说明 | 类型 | 可选值 | 默认值 | | :---------- | :------------------------- | :------ | :----- | :--------------------------- | | v-model | 图片列表 | array | - | \[] | | action | 必选参数,上传的地址 | string | - | - | | headers | 设置上传的请求头部 | object | - | - | | data | 上传时附带的额外参数 | object | - | - | | name | 上传的文件字段名 | string | - | file | | max | 上传数量限制 | number | - | 3 | | size | 上传文件大小限制,单位为MB | number | - | 2 | | width | 展示宽度 | number | - | 150 | | height | 展示高度 | number | - | 150 | | placeholder | 占位图 | string | - | - | | notip | 是否隐藏提示栏 | boolean | - | false | | ext | 支持的文件类型 | array | - | \['jpg', 'png', 'gif', 'bmp'] | --- --- url: /components/image-upload.md --- # ImageUpload 单图上传 ## Props | 参数 | 说明 | 类型 | 可选值 | 默认值 | | :---------- | :------------------------- | :------ | :----- | :--------------------------- | | v-model | 图片地址 | string | - | - | | action | 必选参数,上传的地址 | string | - | - | | headers | 设置上传的请求头部 | object | - | - | | data | 上传时附带的额外参数 | object | - | - | | name | 上传的文件字段名 | string | - | file | | size | 上传文件大小限制,单位为MB | number | - | 2 | | width | 展示宽度 | number | - | 150 | | height | 展示高度 | number | - | 150 | | placeholder | 占位图 | string | - | - | | notip | 是否隐藏提示栏 | boolean | - | false | | ext | 支持的文件类型 | array | - | \['jpg', 'png', 'gif', 'bmp'] | --- --- url: /guide/jsx.md --- # JSX > 如果你不了解 JSX ,甚至没有听说过,可以访问最后推荐的几篇文章,先快速了解熟悉下。 首先说明一点,JSX 并不是 Vue 官方推崇的开发方式,这点从 Vue 官方文档上就可以看来出来。Vue 官方推荐大家使用 SFC(Single File Component) 的方式去编写 Vue 组件,也就是我们熟悉的 `.vue` 文件。 ## 开发模式 ### 在 tsx 文件中开发 ```tsx // 在 render 中返回 export default defineComponent({ name: 'Tsx', render() { return
我是一个div
}, }) // 在 setup 中返回 export default defineComponent({ name: 'Tsx', setup() { return () =>
我是一个div
}, }) ``` 以上两种方式均可以,具体看个人开发习惯。其中 setup 中访问不到 `this` ,而在 render 中可以通过 `this` 访问当前 Vue 实例。 ### 在 vue 文件中开发 是的,你依旧可以在 `.vue` 文件中以 SFC 的方式去编写开发我们的业务代码,只需要给 ` ``` ## 定义组件名 使用 `defineOptions` 在 ` ``` --- --- url: /get-v1-pro.md --- # 免费领取 v1 专业版 > v1 专业版的技术栈为 Vue2 ## 领取方式 只需给下方三个项目的 Github 和 Gitee 仓库分别点 ⭐️ ,并将 ⭐️ 截图发送到邮箱 `304327508#qq.com` (`#`替换成`@`),即可免费领取 v1 专业版源码。 * Fantastic-admin \[[Github](https://github.com/fantastic-admin/basic)] \[[Gitee](https://gitee.com/fantastic-admin/basic)] * One-step-admin \[[Github](https://github.com/one-step-admin/basic)] \[[Gitee](https://gitee.com/one-step-admin/basic)] * Fantastic-mobile \[[Github](https://github.com/fantastic-mobile/basic)] \[[Gitee](https://gitee.com/fantastic-mobile/basic)] ## Q\&A 1. v1 专业版是什么意思? > v1 表示本框架 v1.0 的历史版本,目前已经停止更新维护。 2. 是否提供技术支持? > 仅提供开发文档支持,使用过程中若遇到问题,需自行解决。 ## 演示 ![](public/v1-pro.png){data-zoomable} --- --- url: /guide/store.md --- # 全局状态管理 :::tip [Pinia](https://pinia.vuejs.org/) 已正式成为 Vue.js 官方状态库,如果你对 Pinia 还不熟悉,除了通过 Pinia 官网学习外,我还收集了一些文字/视频的介绍,可以帮助你快速上手。 * [欧耶!Pinia 正式成为 vuejs 的一员](https://mp.weixin.qq.com/s/_OlLFedVJfyEapGzYFETuw) * [全新的 Vue3 状态管理工具:Pinia](https://mp.weixin.qq.com/s/4B-ZzOXdYrF-Auvm_wWBVQ) * [【探索学习】面向未来的 Vuex -- pinia](https://www.bilibili.com/video/BV1Mb4y1X7NL/) ::: 全局状态文件存放在 `/src/store/modules/` 目录下,请按模块进行区分。同时请保证文件名和文件内唯一ID保持一致,建议使用 `pnpm new` 指令进行创建。 例如新建一个 `example.ts` 的文件: ```ts const useExampleStore = defineStore( // 唯一ID 'example', () => { const someThing = ref(0) return { someThing, } }, ) export default useExampleStore ``` 使用方法: ```ts import useExampleStore from '@/store/modules/example' const exampleStore = useExampleStore() exampleStore.someThing ``` --- --- url: /guide/ready.md --- # 准备工作 ## 源码 阅读开发文档前,请确保手上已经有 Fantastic-admin 源码,因为文档中提及的内容,都是需要在本地项目中编写或修改代码并运行才能呈现的。 :::tip 源码分为两种: * **框架源码** 不含示例代码,可直接用于实际开发 * **演示源码** 同演示站,在框架源码基础上,提供了大量示例代码 ::: ### 基础版 到 [Github Releases](https://github.com/fantastic-admin/basic/releases) 页面下载最新版本的压缩包,如下图所示: ![](/download.png){data-zoomable} 或者也可以从 Github/Gitee 上拉取源码,但需要注意,直接拉取源码可能会包含未发布的内容,最终发布时可能会有变动,请谨慎使用。 ::: code-group ```sh [从 Github 拉取] # 拉取框架源码 git clone https://github.com/fantastic-admin/basic.git # 拉取演示源码 git clone -b example https://github.com/fantastic-admin/basic.git ``` ```sh [从 Gitee 拉取] # 拉取框架源码 git clone https://gitee.com/fantastic-admin/basic.git # 拉取演示源码 git clone -b example https://gitee.com/fantastic-admin/basic.git ``` ::: ### 专业版 专业版用户会被邀请加入到 [Fantastic-admin](https://github.com/fantastic-admin) Github 官方组织,加入组织后可访问[专业版私有仓库](https://github.com/fantastic-admin/pro),源码获取方式和基础版无差异,只是源码仓库不同。 如果你想获取专业版源码,可以点[这里](../buy)去购买。 ## 开发环境 使用本模板前,需要在本地依次安装好 [Node.js](https://nodejs.org/), [pnpm](https://pnpm.io/zh/), [Git](https://git-scm.com/)(非必须) 和 [Visual Studio Code](https://code.visualstudio.com/)。 ::: warning 注意 * 在 [package.json](https://github.com/fantastic-admin/basic/blob/main/package.json#L4-L6) 文件中有限制 node 要求版本,建议使用最新 LTS 版本。 * 如果你不想使用 VSCode ,我们也强烈建议你使用基于 VSCode 内核的 IDE ,如 [Cursor](https://www.cursor.com/) 。 ::: 然后在 Visual Studio Code 里安装好以下扩展: * [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) * [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) * [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) * [stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) * [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) * [UnoCSS](https://marketplace.visualstudio.com/items?itemName=antfu.unocss) 在 Visual Studio Code 里打开源码文件夹,右下角会自动提示需要安装的依赖,直接点击安装即可。 ![](/vscode.png){data-zoomable} ::: tip 额外推荐 以上为开发时必备扩展,以下则是作者推荐安装的扩展,安装它们将在一定程度上提升开发效率。 * [Chinese (Simplified) Language Pack for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-zh-hans) 中文语言包 * [Color Highlight](https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight) 在代码中高亮颜色 * [Highlight Matching Tag](https://marketplace.visualstudio.com/items?itemName=vincaslt.highlight-matching-tag) 高亮显示匹配的标签 * [Image preview](https://marketplace.visualstudio.com/items?itemName=kisstkondoros.vscode-gutter-preview) 图片预览 * [indent-rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow) 彩虹缩进提示 ::: ## 技术栈 了解并熟悉框架使用到的技术栈,能让你使用本框架更得心应手。 * [Vite](https://cn.vitejs.dev/) * [Vue 3](https://cn.vuejs.org/) ([v3 迁移指南](https://v3-migration.vuejs.org/)) * [Vue Router](https://router.vuejs.org/zh/) * [Pinia](https://pinia.vuejs.org/zh/) * [UnoCSS](https://unocss.dev/) --- --- url: /guide/title.md --- # 动态标题 让网页标题显示路由配置的 `meta.title` 字段。 ## 使用 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { app: { /** * 是否开启动态标题 * @默认值 `false` */ enableDynamicTitle: true, }, } ``` 效果如下: ![](/dynamic-title.gif){data-zoomable} --- --- url: /guide/i18n.md --- # 国际化 :::info 该特性由 [vue-i18n](https://vue-i18n.intlify.dev/) 提供技术支持。 ::: ## vscode 扩展 如果使用 vscode 进行开发,推荐安装 [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) 这个扩展。 安装该扩展后,代码里可以实时查看对应语言的内容。 ![](/i18n-ally.png){data-zoomable} ## 默认语言 在应用配置中设置默认语言,可选设置的值参考 `/src/locales/lang/` 目录下文件名,留空则会根据浏览器语言自动判断,如果找不到对应的语言则使用 **中文(简体)** 兜底。 ```ts {2-9} const globalSettings: Settings.all = { app: { /** * 默认语言 * @默认值 `''` 跟随浏览器语言设置 * @可选值 参考 `/src/locales/index.ts` 里的语言列表 */ defaultLang: '', }, } ``` ## 语言包 框架自身的语言包存放在 `/src/locales/lang/` 目录下,如果需要新增某个语言,请在该目录下新建一个 json 文件,文件名为语言代码,比如 `ja.json` 代表日文,并在 `/src/locales/index.ts` 里增加: ```ts const localesName: Record = {} for (const key in messages) { switch (key) { case 'zh-cn': localesName[key] = '中文(简体)' break case 'zh-tw': localesName[key] = '中文(繁體)' break case 'en': localesName[key] = 'English' break case 'ja': // [!code ++] localesName[key] = '日本語' // [!code ++] break // [!code ++] } } ``` 同时因为 Element Plus 本身也有自己的语言包,所以在做国际化支持的时候,框架的语言包和 Element Plus 的语言包需要进行数据合并,可[点击这里](https://github.com/element-plus/element-plus/tree/dev/packages/locale/lang)查看 Element Plus 的语言包文件。 假设你已经在 `/src/locales/lang/` 目录下新增并配置好了一个日文语言包 `ja.json` ,然后你需要到 `/src/ui/provider/index.ts` 文件里做以下调整: ```ts import zhCN from 'element-plus/es/locale/lang/zh-cn.mjs' import zhTW from 'element-plus/es/locale/lang/zh-tw.mjs' import en from 'element-plus/es/locale/lang/en.mjs' import ja from 'element-plus/es/locale/lang/ja.mjs' // [!code ++] // 此处的对象属性和 src/locales/index.ts 中的 messages 对象属性一一对应 const locales: Record = { 'zh-cn': zhCN, 'zh-tw': zhTW, 'en': en, 'ja': ja // [!code ++] } ``` ## 路由设置 以中文(简体)为例,打开 `/src/locales/lang/zh-cn.json` 文件可以看到路由相关的配置,在 `route` 对象里可以扩展需要开启国际化支持的路由。 ```json { "route": { "page": "页面标题", } } ``` 如果需要新增某个路由的国际化支持,光设置好中文(简体)的还不行,其它语言包文件里也要同步添加。当都设置好后,可在该路由的 `title` 参数上直接设置对应 key 值,例如: ```ts meta: { title: 'route.page', }, ``` ## 框架设置 以中文(简体)为例,打开 `/src/locales/lang/zh-cn.json` 文件可以看到框架相关的配置,在 `app` 对象里的就是框架部分的语言信息,如果需要对框架进行二次开发,请在这里扩展。 ## 单页组件 如果每个页面都要做国际化支持,那语言包文件就会变得无比庞大且难以维护,推荐在每个页面组件里使用 `` 自定义块进行语言维护,可访问 `/src/views/feature_example/i18n.vue` 查看示例。 更多 [vue-i18n](https://vue-i18n.intlify.dev/) 的使用技巧请参考官方文档。 ## 与服务端交互 所有的请求均会在请求头里带上 [`Accept-Language`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Language) ,后端可根据这一状态信息做动态数据国际化处理。 ## 关闭国际化 如果不想开启国际化,可参考以下设置,该设置表示关闭语言选择器,并以中文(简体)显示。 ```ts {2-7} const globalSettings: Settings.all = { app: { defaultLang: 'zh-cn', }, toolbar: { i18n: false, }, } ``` --- --- url: /guide/icon.md --- # 图标 框架提供了三种使用图标的方式,你可以根据自己的使用需求自行选择。 ## 自定义图标 你可以去[阿里巴巴矢量图标库](https://www.iconfont.cn/),或者其它支持下载 SVG 图标文件的网站,又或者是设计师绘制的 SVG 文件,将准备好的 SVG 图标文件放到 `/src/assets/icons/` 目录下,然后在页面中就可以通过 FaIcon 组件使用了,name 就是 svg 的文件名。 ```vue ``` ## Iconify 图标 ::: tip 介绍 [Iconify](https://github.com/iconify/iconify) 提供 100+ 套图标集,有 100,000+ 个图标可以免费使用。 ::: 除了可以在 Iconify 官网上查找搜需要的图标,你还可以在 [Icônes 网站](https://icones.js.org/) 上查找,这是一个基于 Iconify 的在线图标搜索网站,它比 Iconify 官网的操作更直观。 ![](/icones1.png){data-zoomable} ![](/icones2.png){data-zoomable} ### Unocss 方案 ::: tip 说明 Unocss 方案采用了 CSS 去处理图标的展示,框架大部分核心模块里采用的是这种方式,如果你对其中的技术细节感兴趣,可以阅读这篇 Unocss 作者的《[聊聊纯 CSS 图标](https://antfu.me/posts/icons-in-pure-css-zh)》这篇文章。 ::: 框架已经做好了所有配置,使用方式也极为简单,你只需进入 [Iconify 官网](https://icon-sets.iconify.design/) 上查找 Iconify 提供的所有图标,然后点击需要使用的图标,复制图标名称,在任意原生 HTML 标签上通过设置 class ,格式为 `i-{集合名}:{图标名}`,例如: ```vue
``` 当然你同样也可以通过 FaIcon 使用它。 ```vue ``` 在使用 Unocss 图标时,需要注意以下两点: * 图标字符串不支持拼接 ```vue ``` * 图标字符串不支持异步返回 ```vue ``` 如果确实有以上需求,你可以使用 Iconify 原生提供的方案。 ### Iconify 原生方案 ::: tip 说明 框架保留了 Iconify 官方提供的使用方式,格式为 `{集合名}:{图标名}` 。 ::: ```vue ``` 当然这么使用并没有很方便,依旧还是需要手动导入一个 Icon 组件。如果你也觉得麻烦的话,那么你可以使用 FaIcon 组件来展示,框架已经帮你做好的所有处理。 ```vue ``` ### 离线/内网环境使用 ::: tip 说明 优先推荐使用 Unocss 方案,它不受网络环境限制,且相对于 Iconify 原生方案,它的性能更好。 ::: 如果你清楚自己需要使用 Iconify 原生方案,并且想要在离线/内网环境使用,需要做一些额外的配置。因为 Iconify 图标默认是提供在线的服务,即首次调用会触发一个外部网络请求去获取 svg 原始数据,并缓存在 localStorage 和 sessionStorage 中,这样下次再调用的时候,则直接从缓存中获取并展示。 框架提供了一份解决方案,在命令行执行 `pnpm run generate:icons` ,按照指引选择你需要用到的图标集(此处选择的图标集也是图标选择器里展示的图标集),并选择使用方式为离线。这样再在框架中使用这些图标,就不会触发外部网络请求了,但如果使用选择之外的图标,依旧还是会触发外部网络请求。 ## 图标选择器 图标选择器是一个特殊的组件,它需要展示多套图标集内的所有图标。 通过执行 `pnpm run generate:icons` 命令,并按照指引完成操作后,图标选择器就会自动生效了。 --- --- url: /guide/file-system-route.md --- # 基于文件系统的路由 :::info 该特性由 [vite-plugin-pages](https://github.com/hannoeru/vite-plugin-pages) 和 [vite-plugin-vue-layouts](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) 提供技术支持。 ::: 传统使用路由的方式需要手动编写路由,而基于文件系统的路由则会根据 `/src/views/` 下的文件目录结构,自动生成每个 `.vue` 文件对应的路由配置,从而节省手动配置路由的时间。 ## 使用介绍 框架默认不启用该特性,如果需要开启,需要到应用配置里修改设置。 ```ts {2-10} const globalSettings: Settings.all = { app: { /** * 路由数据来源 * @默认值 `'frontend'` 前端 * @可选值 `'backend'` 后端 * @可选值 `'filesystem'` 文件系统 */ routeBaseOn: 'filesystem', }, } ``` 启用基于文件系统的路由后,`/src/router/modules/` 目录将不再被需要,而 `/src/views/` 目录下的文件会自动被注册成路由。 ``` 文件系统 路由地址 路由 name views ├─ example │ ├─ components │ │ └─ List │ │ └─ index.vue │ ├─ params │ │ └─ [id].vue /example/params/:id example-params │ ├─ axios.vue /example/axios example-axios │ ├─ cookie.vue /example/cookie example-cookie │ └─ icon.vue /example/icon example-icon ├─ [...all].vue /:all(.*)* all ├─ index.vue / index ├─ reload.vue /reload reload └─ login.vue /login login ``` 通过上面的示例,可以看出几个特性: * 使用路由参数需通过 \[ ] 将参数名包裹,并设为文件名 * 文件夹不会生成路由,例如 example 文件夹并没有生成 /example 路由 * 路由 name 会根据文件的目录结构自动生成,并用`-`连接,可确保 name 的唯一性 * 所有 `components/` 目录均不会生成路由 ## 进阶使用 默认生成的路由均为嵌套路由,父级 component 指向 `/src/layouts/index.vue` 组件,即: ```ts // 生成的路由 { path: '/example/list', component: () => import('/src/layouts/index.vue'), children: [ { path: '', component: () => import('/src/views/example/list.vue'), name: 'example-list', meta: { layout: 'index', }, }, ], } ``` 你可以在 SFC 单文件组件里将 layout 设置为 false,这样该路由则不会生成嵌套路由: ```vue {1-4} meta: layout: false ``` ```ts // 生成的路由 { path: '/example/list', component: () => import('/src/views/example/list.vue'), name: 'example-list', meta: { layout: false, }, } ``` ## 路由参数 你应该已经发现,原先在路由的配置信息被转移到了 SFC 单文件组件里的 `` 标签内。 需要注意的是,既然使用了基于文件系统的路由,不建议再手动去设置 `path` 和 `name` ,同时因为路由不再承担生成导航的特性,所以 `meta` 对象的可配置项也有部分调整,仅支持以下参数: * [title](router#title) * [i18n](router#i18n) * [icon](router#icon) * [activeIcon](router#activeicon) * [permanent](router#permanent) * [auth](router#auth) * [activeMenu](router#activemenu) * [cache](router#cache) * [noCache](router#nocache) * [copyright](router#copyright) 另外还新增了三个特殊参数: ### enabled * 类型:`boolean` * 默认值:`true` * 说明:是否将该文件生成路由 如果你想临时取消某个文件路由的生成,可以通过设置 `enabled: false` 来实现,从而不需要通过删除文件来实现。 ### layout * 类型:`boolean | string` * 默认值:`'index'` * 说明:布局模版名称,对应 layouts 目录下文件名 ### constant * 类型:`boolean` * 默认值:`false` * 说明:是否为固定路由,默认为动态路由 ## 导航参数 由于导航无法通过路由自动生成,所以在基于文件系统的路由模式下,我们需要手动配置导航数据。 导航数据存放在 `/menu/` 目录下,和 `/router/` 的目录结构类似, `/menu/modules/` 用于存放每个模块的导航配置,最终在 `/menu/index.ts` 文件里引用并进行归类,即主导航。 导航对象有三个标准参数: * path 完整路由地址,如果有下级导航,则无需设置 * meta 同路由 `meta` 对象,支持以下参数: * [title](router#title) * [i18n](router#i18n) * [icon](router#icon) * [activeIcon](router#activeicon) * [auth](router#auth) * [badge](router#badge) * [badgeVariant](router#badgevariant) * [query](router#query) * [maximize](router#maximize) * [exitMaximize](router#exitmaximize) * [newWindow](router#newwindow) * [iframe](router#iframe) * [link](router#link) * [sort](router#sort) * children 下级导航数组 同样的,导航数据也可通过后端进行返回,只需在应用配置中设置: ```ts {2-9} const globalSettings: Settings.all = { menu: { /** * 导航栏数据来源,当 `app.routeBaseOn: 'filesystem'` 时生效 * @默认值 `'frontend'` 前端 * @可选值 `'backend'` 后端 */ baseOn: 'backend', }, } ``` 开启后在 `/src/api/modules/app.ts` 文件里找到 `menuList()` 这个函数,并修改这个函数的请求地址,请求返回的数据就是导航数据,你可以在 `/src/mock/app.ts` 里查看 mock 数据。 ## 功能取舍 需要注意,使用文件系统的路由后,将无法再使用以下功能或特性: * 面包屑导航 * 次导航默认展开 * 次导航始终展开 * JSX --- --- url: /customize.md --- # 定制开发 ## 介绍 作者提供基于 Fantastic-admin 框架的定制开发服务,如**界面定制**、**功能定制**、**业务模块委托开发**。 ## 收费标准 具体费用视开发周期而定,如果你有相对完整的原型图或需求文档,可以直接加我微信,我会根据你提供的信息评估具体的开发周期和费用。 收费模式为 3/7 ,即确认开发前,收取总费用的 30% 做为预付款,开发完成后,收取剩余 70% 尾款后并提供完整源码。 开发期间我将提供在线预览地址,方便你了解开发进度,以便能及时沟通或调整需求。 ## 部分案例 --- --- url: /guide/menu.md --- # 导航菜单 ## 模式 提供 7 种导航栏模式,其中后 4 种为 才有,在应用配置中设置: ```ts {2-14} const globalSettings: Settings.all = { menu: { /** * 导航栏模式 * @默认值 `'side'` 侧边栏模式(有主导航) * @可选值 `'head'` 顶部模式 * @可选值 `'single'` 侧边栏模式(无主导航) * @可选值 `'only-side'` 侧边栏精简模式 * @可选值 `'only-head'` 顶部精简模式 * @可选值 `'side-panel'` 侧边栏面板模式 * @可选值 `'head-panel'` 顶部面板模式 */ mode: 'head', }, } ``` :::: tabs ::: tab head ![](/menu-mode-head.png){data-zoomable} ::: ::: tab side ![](/menu-mode-side.png){data-zoomable} ::: ::: tab single ![](/menu-mode-single.png){data-zoomable} ::: ::: tab only-side ![](/menu-mode-only-side.png){data-zoomable} ::: ::: tab only-head ![](/menu-mode-only-head.png){data-zoomable} ::: ::: tab side-panel ![](/menu-mode-side-panel.png){data-zoomable} ::: ::: tab head-panel ![](/menu-mode-head-panel.png){data-zoomable} ::: :::: ## 风格 在应用配置中设置: ```ts {2-11} const globalSettings: Settings.all = { menu: { /** * 导航栏风格 * @默认值 `''` * @可选值 `'arrow'` 箭头 * @可选值 `'line'` 线条 * @可选值 `'dot'` 圆点 */ style: '', }, } ``` ![](/menu-style.png){data-zoomable} ## 主导航点击模式 在应用配置中设置: ```ts {2-10} const globalSettings: Settings.all = { menu: { /** * 主导航点击模式 * @默认值 `'switch'` 切换 * @可选值 `'jump'` 跳转 * @可选值 `'smart'` 智能选择,判断次导航是否只有且只有一个可访问的菜单进行切换或跳转操作 */ mainMenuClickMode: 'jump', }, } ``` ![](/menu-mainmenuclickmode.gif){data-zoomable} 当设置成 `'jump'` 或 `'smart'` 时,支持次导航只有一个导航时,点击主导航会跳转并隐藏: ![](/menu-mainmenuclickmodeplus.gif){data-zoomable} 你只需要在某个主导航下只保留一个次导航,并且通过 `meta.menu` 将其隐藏,就像这样: ```ts {16-43} import MultilevelMenuExample from './modules/multilevel.menu.example' import BreadcrumbExample from './modules/breadcrumb.example' // 动态路由(异步路由、导航栏路由) const asyncRoutes: Route.recordMainRaw[] = [ { meta: { title: $t('route.demo'), icon: 'menu-default', }, children: [ MultilevelMenuExample, BreadcrumbExample, ], }, { meta: { title: '测试', }, children: [ { path: '/test', component: () => import('@/layouts/index.vue'), redirect: '/test/page', name: 'test', meta: { title: '演示页面', menu: false, // 注意,需要将这个导航隐藏 }, children: [ { path: 'page', name: 'testPage', component: () => import('@/views/test/page.vue'), meta: { title: '演示页面', menu: false, }, }, ], }, ], }, ] ``` ## 次导航可同时展开多个子项 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { menu: { /** * 次导航是否只保持一个子项的展开 * @默认值 `true` */ subMenuUniqueOpened: false, }, } ``` ![](/menu-submenuuniqueopened.gif){data-zoomable} ## 次导航默认收起 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { menu: { /** * 次导航是否收起 * @默认值 `false` */ subMenuCollapse: true, }, } ``` ![](/menu-submenucollapse.png){data-zoomable} ## 次导航自动收起 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { menu: { /** * 次导航是否自动收起 * @默认值 `false` */ subMenuAutoCollapse: true, }, } ``` 当次导航处于收起状态时可以实现如下的效果: ![](/menu-submenuautocollapse.gif){data-zoomable} ## 开启次导航展开/收起按钮 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { menu: { /** * 是否开启次导航的展开/收起按钮 * @默认值 `false` */ enableSubMenuCollapseButton: true, }, } ``` ![](/menu-enablesubmenucollapsebutton.gif){data-zoomable} --- --- url: /guide/toolbar.md --- # 工具栏 ## 是否启用 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启工具栏 * @默认值 `true` */ enable: false, }, } ``` 该设置仅控制工具栏区域是否启用。 意味着你可以通过关闭工具栏,并使用 `HeaderAfterMenu` 预留插槽,将原本工具栏内的功能模块移至头部显示,如下: ![](/toolbar-slots.png){data-zoomable} ::: code-group ```ts {7-12} [src/settings.ts] import type { RecursiveRequired, Settings } from '#/global' import settingsDefault from '@/settings.default' import { merge } from '@/utils/object' import { cloneDeep } from 'es-toolkit' const globalSettings: Settings.all = { menu: { mode: 'head', }, toolbar: { enable: false, }, } export default merge(globalSettings, cloneDeep(settingsDefault)) as RecursiveRequired ``` ```vue [src/slots/HeaderAfterMenu/index.vue] ``` ::: ## 收藏夹 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启收藏夹 * @默认值 `false` */ favorites: true, }, } ``` 开启后可将常用的导航菜单添加进收藏夹,方便快速访问。 ![](/favorites.png){data-zoomable} ### 数据存储 收藏夹默认存储在浏览器本地 localStorage 里,如果需要将数据存储到服务器,可以通过 `favorites.storageTo` 配置项来实现,具体配置如下: ```ts {2-9} const globalSettings: Settings.all = { favorites: { /** * 存储位置 * @默认值 `'local'` 本地存储 * @可选值 `'server'` 服务器存储 */ storageTo: 'server', }, } ``` 然后到 `/src/api/modules/user.ts` 中找到 `favorites()` 和 `favoritesEdit()` 这两个函数,并分别修改这两个函数的请求地址。 :::tip 建议 为减轻后端处理,数据会直接以 JSON 字符串进行存储,建议后端可以在用户表增加相关字段,并将字段类型设为 `longtext` 。 ::: ## 面包屑导航 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启面包屑导航 * @默认值 `true` */ breadcrumb: true, }, } ``` 移动端访问时,会隐藏面包屑导航。 当使用文件系统路由时,将无法使用面包屑导航,详细可阅读《[基于文件系统的路由](file-system-route)》。 ### 风格 在应用配置中设置: ```ts {2-9} const globalSettings: Settings.all = { breadcrumb: { /** * 面包屑导航风格 * @默认值 `''` 默认 * @可选值 `'modern'` 现代 */ style: '', }, } ``` ![](/breadcrumb-style.png){data-zoomable} ### 显示主导航 在应用配置里设置: ```ts {2-8} const globalSettings: Settings.all = { breadcrumb: { /** * 是否在面包屑导航里显示主导航 * @默认值 `false` */ enableMainMenu: true, }, } ``` ![](/breadcrumb-mainmenu.png){data-zoomable} ## 导航搜索 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启导航搜索 * @默认值 `true` */ navSearch: true, }, } ``` ## 通知中心 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启通知中心 * @默认值 `false` */ notification: true, }, } ``` 通知中心不涉及具体业务,需开发者自行实现,相关文件在 `/src/layouts/components/Topbar/Toolbar/Notification` 目录下。 ## 国际化 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启国际化 * @默认值 `false` */ i18n: true, }, } ``` 如果设置为不启用,并不代表不支持国际化切换,只是不会在工具栏显示切换语言的图标,详细可阅读《[国际化](i18n)》。 ## 浏览器全屏 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启全屏 * @默认值 `false` */ fullscreen: true, }, } ``` ## 页面刷新 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启页面刷新 * @默认值 `false` */ pageReload: true, }, } ``` ## 颜色主题 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 是否开启颜色主题 * @默认值 `false` */ colorScheme: true, }, } ``` 如果设置为不启用,并不代表不支持颜色主题切换,只是不会在工具栏显示切换颜色主题的图标。 ## 布局 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { toolbar: { /** * 布局设置,可自定义摆放位置和顺序,其中 `->` 为分隔符,用于分隔左右两侧的工具栏。修改时请确保默认值里的所有值都存在,不可删减。 * @默认值 `['favorites', 'breadcrumb', '->', 'navSearch', 'notification', 'i18n', 'fullscreen', 'pageReload', 'colorScheme']` */ layout: ['favorites', 'breadcrumb', '->', 'navSearch', 'notification', 'i18n', 'fullscreen', 'pageReload', 'colorScheme'], }, } ``` --- --- url: /guide/layout.md --- # 布局 ## 页宽模式 提供 4 种基于页宽(页面宽度)模式,在应用配置中设置: ```ts {2-11} const globalSettings: Settings.all = { layout: { /** * 页宽模式,当设置为非 `'adaption'` 时,可以去 /src/assets/styles/globals.css 里设置 `--g-app-width` 宽度变量 * @默认值 `'adaption'` 自适应 * @可选值 `'adaption-min-width'` 自适应(有最小宽度) * @可选值 `'center'` 定宽居中 * @可选值 `'center-max-width'` 定宽居中(有最大宽度) */ widthMode: 'adaption', }, } ``` :::: tabs ::: tab adaption ![](/layout_1.gif){data-zoomable} ::: ::: tab adaption-min-width ![](/layout_2.gif){data-zoomable} ::: ::: tab center ![](/layout_3.gif){data-zoomable} ::: ::: tab center-max-width ![](/layout_4.gif){data-zoomable} ::: :::: ## 页宽模式应用范围 在应用配置中设置: ```ts {2-9} const globalSettings: Settings.all = { layout: { /** * 页宽模式作用范围 * @默认值 `'outer'` 外层 * @可选值 `'inner'` 内层 */ widthModeScope: 'inner', }, } ``` ## 变量 布局相关的变量存放在 `/src/assets/styles/globals.css` 文件中(注意看注释),均为 CSS 变量。 ## 移动端 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { layout: { /** * 是否开启移动端适配,开启后当页面宽度小于 1024px 时自动切换为移动端展示 * @默认值 `false` */ enableMobileAdaptation: true, }, } ``` 开启移动端支持后,当页面宽度小于 `1024px` 时会切换为移动端布局显示,移动端下不支持设置框架布局,以及部分不支持移动端的操作按钮也会进行隐藏,例如“全屏”按钮。 ![](/layout-mobile.gif){data-zoomable} 虽然框架本身兼容移动端,但由于后台系统在开发时可能会引用各类第三方插件,这部分的兼容性需要开发者自行适配。 :::tip 建议 由于后台系统属于生产效率工具,而移动端天生不适合复杂的操作,尤其是遇到一些比较复杂的表单,在移动端上操作是极其“恼火”的。 依据作者的开发经验,建议移动端后台可以独立开发一套,在功能上进行删减,保留轻量级的管理操作。 如果打算独立开发一套移动端的系统,建议使用 [Fantastic-mobile](https://fantastic-mobile.hurui.me/)。 ::: --- --- url: /guide/api.md --- # 常用 API ## 接口请求 详细可阅读《[与服务端交互 - 接口请求](axios#接口请求)》。 ```ts import api from '@/api' api.get() api.post() ``` ## 鉴权 详细可阅读《[权限 - 鉴权函数](permission#鉴权函数)》。 ```ts const { auth, authAll } = useAuth() auth() authAll() ``` ## 主导航 ### 切换 切换主导航,`index` 为主导航序列数。 ```ts const { switchTo } = useMenu() switchTo(index) ``` ## 主页面 ### 刷新 ```ts const { reload } = useMainPage() reload() ``` ### 设置自定义标题 ```ts const { setCustomTitle } = useMainPage() setCustomTitle(title) ``` ### 重置自定义标题 ```ts const { resetCustomTitle } = useMainPage() resetCustomTitle() ``` ### 最大化 ```ts const { maximize } = useMainPage() // status: true / false maximize(status) ``` ## 标签栏 ### 获取当前标签页 tabId ```ts const { getId } = useTabbar() getId() ``` ### ~~打开新标签页~~ :::danger 注意 该方法已弃用,直接使用 `router.push(to)` 即可达到相同效果。 ::: 该方法接收一个 `to` 参数,该参数与 `router.push(to)` 一致,点击阅读[参数说明](https://router.vuejs.org/zh/api/interfaces/Router.html#Methods-push)。 通过该方式跳转页面,新增的标签页会插入到当前标签页后面,而直接通过路由跳转,新增的标签页会插入到所有标签页的最后。 ```ts const { open } = useTabbar() open(to) ``` ### ~~后退标签页~~ :::danger 注意 该方法已弃用,直接使用 `router.go(delta)` 即可达到相同效果。 ::: 该方法接收一个 `delta` 参数,该参数与 `router.go(delta)` 一致,点击阅读[参数说明](https://router.vuejs.org/zh/api/interfaces/Router.html#Methods-go)。 通过该方式后退页面,可以同时关闭当前标签页,而直接通过路由后退,当前标签页会被保留。 ```ts const { go } = useTabbar() go(delta) ``` ### ~~替换当前标签页~~ :::danger 注意 该方法已弃用,直接使用 `router.replace(to)` 即可达到相同效果。 ::: 该方法接收一个 `to` 参数,该参数与 `router.replace(to)` 一致,点击阅读[参数说明](https://router.vuejs.org/zh/api/interfaces/Router.html#Methods-replace)。 通过该方式替换当前标签页,可以同时关闭当前标签页,而直接通过路由替换,当前标签页会被保留。 ```ts const { replace } = useTabbar() replace(to) ``` ### 关闭当前标签页 该方法接收一个 `to` 参数,该参数与 `router.push(to)` 一致,点击阅读[参数说明](https://router.vuejs.org/zh/api/interfaces/Router.html#Methods-push)。 通过该方式跳转页面,可以同时关闭当前标签页,而直接通过路由跳转,当前标签页会被保留。 ```ts const { close } = useTabbar() close(to) ``` ### 关闭指定标签页 该方法接收一个 `tabId` 参数,如果不传则默认为当前页的 `tabId` 。 ```ts const { closeById } = useTabbar() closeById(tabId) ``` ### 关闭两侧标签页 该方法接收一个 `tabId` 参数,如果不传则默认为当前页的 `tabId` 。 ```ts const { closeOtherSide } = useTabbar() closeOtherSide(tabId) ``` ### 关闭左侧标签页 该方法接收一个 `tabId` 参数,如果不传则默认为当前页的 `tabId` 。 ```ts const { closeLeftSide } = useTabbar() closeLeftSide(tabId) ``` ### 关闭右侧标签页 该方法接收一个 `tabId` 参数,如果不传则默认为当前页的 `tabId` 。 ```ts const { closeRightSide } = useTabbar() closeRightSide(tabId) ``` ### 校验指定标签两侧是否有可关闭的标签 该方法接收一个 `tabId` 参数,如果不传则默认为当前页的 `tabId` 。 ```ts const { checkCloseOtherSide } = useTabbar() checkCloseOtherSide(tabId) ``` ### 校验指定标签左侧是否有可关闭的标签 该方法接收一个 `tabId` 参数,如果不传则默认为当前页的 `tabId` 。 ```ts const { checkCloseLeftSide } = useTabbar() checkCloseLeftSide(tabId) ``` ### 校验指定标签右侧是否有可关闭的标签 该方法接收一个 `tabId` 参数,如果不传则默认为当前页的 `tabId` 。 ```ts const { checkCloseRightSide } = useTabbar() checkCloseRightSide(tabId) ``` ## 事件总线 基于 [mitt](https://github.com/developit/mitt) 简单封装,使用方法请查阅官方文档。 ```ts import eventBus from '@/utils/eventBus' eventBus.on() eventBus.emit() eventBus.off() ``` ## 日期 基于 [dayjs](https://day.js.org/zh-CN/) 简单封装,使用方法请查阅官方文档。 ```ts import dayjs from '@/utils/dayjs' dayjs() ``` --- --- url: /guide/q-a.md --- # 常见问题 ## 安装依赖时有警告 ![](/qa1.png){data-zoomable} 这是一个可以无视的警告,因为依赖已经安装成功了。 如果对这个问题感兴趣,可以浏览下这个 [issue](https://github.com/pnpm/pnpm/issues/4183) ,里面有给出一个忽略警告的方案,就是在 `package.json` 中添加: ```json { "pnpm": { "peerDependencyRules": { "ignoreMissing": [ "postcss", "rollup" ] } } } ``` 这样你下次再安装依赖的时候,就不会出现该警告了。 ## 为什么本地开发环境首次载入很慢 主要是 Vite 的原因,具体可以阅读这篇文章了解《[为什么有人说 vite 快,有人却说 vite 慢?](https://juejin.cn/post/7129041114174062628)》。 Vite 4.3 显著提升了开发服务器的性能,具体可以阅读这篇文章了解《[Vite 4.3 is out!](https://vitejs.dev/blog/announcing-vite4-3.html)》,同时框架 v3.0.0 版本开始,vite 也升级到了 4.3 版本。 ## 项目 URL 里的 # 号能不能去掉 这是因为路由默认使用的是 Hash 模式,你可以在 `/src/router/index.ts` 修改为 HTML5 模式,但需要注意,开启 HTML5 模式,服务器也需要做相应的配置调整,详细可阅读《[Vue-router 不同的历史模式](https://next.router.vuejs.org/zh/guide/essentials/history-mode.html)》。 ## 页面切换后显示空白 因为路由切换有使用到 `` 动画,而 `` 组件无法处理多个根节点的组件,所以请检查路由对应所有的页面文件的根节点是否均为单个。 错误示例: ```vue ``` 正确示例: ```vue ``` 相关 [Issue](https://github.com/vuejs/vue-next/issues/1850) 说明。 ## 开发环境修改代码后,路由跳转导致页面空白 参考这个 [issue](https://github.com/vuejs/core/issues/7121) ,未来 Vue 官方可能会修复这个问题,目前只能手动刷新浏览器。 ## 构建报错,提示内存溢出 构建时失败并在错误信息里提示 `Reached heap limit Allocation failed - JavaScript heap out of memory` 。 你可以执行 `pnpm add cross-env -D` 安装 cross-env 依赖,并在 `package.json` 里修改构建脚本指令: ```json {3} { "scripts": { "build": "vue-tsc -b && cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build" } } ``` 其中 8192 表示内存空间大小。 ## 直接修改构建产物的接口地址 如果你需要将构建产物部署到多台服务器,并且根据不同服务器配置不同的接口地址。这时候如果采用新增环境配置文件的方式,会存在一个弊端,就是不同环境需要分别进行构建。下面的方法可以让你直接修改构建产物的接口地址。 新增 `/public/config.js` 文件: ```js window.globalConfig = { API_BASEURL: '/', } ``` 在 `/index.html` 中引入: ```html ... // [!code ++] ``` 修改 `/src/api/index.ts` ,仅在生产环境时使用: ```ts const api = axios.create({ baseURL: (import.meta.env.DEV && import.meta.env.VITE_OPEN_PROXY === 'true') ? '/proxy/' : import.meta.env.VITE_APP_API_BASEURL, // [!code --] baseURL: (import.meta.env.DEV && import.meta.env.VITE_OPEN_PROXY === 'true') ? '/proxy/' : (import.meta.env.DEV ? import.meta.env.VITE_APP_API_BASEURL : (window as any).globalConfig.API_BASEURL), // [!code ++] timeout: 1000 * 60, responseType: 'json', }) ``` 之后你就可以在构建产物目录下直接修改 `config.js` 文件内的接口地址了,此方法不仅适用于接口地址,可以自行扩展。 ## 不会 TypeScript 怎么办 不管个人还是团队、产品或者项目,从长远考虑我们都建议你学习 TypeScript,因为它是未来的趋势,而且大部分框架、库、插件都是用 TypeScript 开发的,足以证明它是构建一款成熟稳健产品的基石。 但考虑到实际情况,会各种客观原因存在,如果必须要用传统 JavaScript 进行开发,你可以在 `tsconfig.app.json` 里将 `allowJs` 设置为 `true` 即可,框架原有的 TypeScript 代码不会受到影响,并且你也可以在项目中使用 JavaScript 编写代码。 --- --- url: /guide/devtools.md --- # 开发者工具 :::info 该特性由 [Vue DevTools](https://github.com/vuejs/devtools) 提供技术支持。 ::: ## 使用介绍 在 `.env.development` 开发环境配置文件中开启: ```yaml # 是否开启开发者工具 VITE_OPEN_DEVTOOLS = true ``` 开启后,在本地运行时,默认会在页面底部中间显示一个开发者工具按钮。 ![](/devtools.gif){data-zoomable} ## 默认启动 IDE Vue DevTools 支持在浏览器中选择组件时,自动在 IDE 中打开相应的源文件。 默认打开 VSCode ,如果你使用其他 IDE ,建议在根目录手动创建 `.env.development.local` 文件并写入: ```yaml VITE_VUE_DEVTOOLS_LAUNCH_EDITOR = cursor ``` 点击查看[支持的 IDE 列表](https://github.com/yyx990803/launch-editor#supported-editors)。 --- --- url: /guide/start.md --- # 开始 准备工作完成后,在源码文件夹根目录下依次执行以下命令: ```sh # 安装依赖 # 注意,必须使用 pnpm 安装依赖,请勿使用 npm 或 yarn 安装依赖 pnpm install # 运行 pnpm run dev ``` 运行成功后,会自动访问页面,默认地址为 `http://localhost:9000` ::: warning 报错 如果无法正常安装依赖,可能是因为 npm 默认源无法访问,可以尝试执行 `pnpm config set registry https://registry.npmmirror.com/` 切换为国内 npmmirror 镜像源(也可以使用 [nrm](https://github.com/Pana/nrm) 一键切换源),然后删除根目录下 `/node_modules` 文件夹并重新安装依赖。 如果依旧无法运行(基本不太可能),可尝试删除根目录下 `/node_modules` 文件夹与 `pnpm-lock.yaml` 文件后,再删除 `package.json` 中 `"preinstall": "npx only-allow pnpm"` 这句脚本,最后使用 `npm / yarn` 或其他包管理工具进行安装依赖。但需要清楚一点,这样操作后,将无法与官方环境锁定的依赖包版本保持一致,可能会出现无法预知的问题,非必要情况下,请勿使用该方案。 ::: --- --- url: /guide/hotkeys.md --- # 快捷键 在用户下拉列表中可查看当前启用的所有快捷键。 ![](/hotkeys.gif){data-zoomable} ## 导航搜索 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { navSearch: { /** * 是否开启导航搜索快捷键 * @默认值 `true` */ enableHotkeys: true, }, } ``` ## 导航 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { menu: { /** * 是否开启主导航切换快捷键 * @默认值 `false` */ enableHotkeys: true, }, } ``` ## 标签栏 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { tabbar: { /** * 是否开启标签栏快捷键 * @默认值 `false` */ enableHotkeys: true, }, } ``` ## 页面 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { mainPage: { /** * 是否开启页面快捷键 * @默认值 `true` */ enableHotkeys: true, }, } ``` --- --- url: /support.md --- # 技术支持 ## 基础版 在使用框架的过程中难免会遇到问题,优先推荐在仓库提交 Issue ,你可以更详细描述问题产生的操作步骤,或者提供完整的最小复现,这样做可以让更多的人参与讨论,也方便后人查阅。 * [Github Issue](https://github.com/fantastic-admin/basic/issues) * [Gitee Issue](https://gitee.com/fantastic-admin/basic/issues) 除了可以在项目仓库提交 Issue 外,你也可以加入微信群讨论。 如果邀请二维码失效,也可以加我微信并备注「**加群**」。 ## 专业版 购买专业版的用户会邀请到专业版的微信群,并在群内提供技术支持。 --- --- url: /guide/intro.md --- # 文档说明 ::: tip ⭐⭐⭐⭐⭐ 相信你已经准备或正在使用 Fantastic-admin 进行开发工作了,在此之前,希望你可以去 **Github** 或者 **Gitee(码云)** 帮我点个 ⭐ ,这将是对我极大的鼓励。 [![star](https://img.shields.io/github/stars/fantastic-admin/basic?style=social)](https://github.com/fantastic-admin/basic) [![star](https://gitee.com/fantastic-admin/basic/badge/star.svg?theme=dark)](https://gitee.com/fantastic-admin/basic) ::: 文档中标记 的地方,表示该功能仅提供于专业版使用,使用基础版的开发者可直接跳过阅读。 如果你准备好了,那我们就[开始](/guide/ready)吧~ --- --- url: /guide/changelog.md --- # 更新日志 只记录 feat/fix 以及破坏性变更。 ## v5.2.0 :::info [基础版](https://github.com/fantastic-admin/basic/releases/tag/v5.2.0) 🚨 Breaking Changes * Radix-vue 迁移到 reka-ui  -  by @hooray [(dcad2)](https://github.com/fantastic-admin/basic/commit/dcad2c6) * 重写路由 `push/go/replace` 函数,移除 useTabbar 中 `open/go/replace` 函数  -  by @hooray [(2b18c)](https://github.com/fantastic-admin/basic/commit/2b18c3f) 🚀 Features * `FaDivider` 增加 class props  -  by @hooray [(b533c)](https://github.com/fantastic-admin/basic/commit/b533c5a) * Layouts 布局支持 ``  -  by @hooray [(ce747)](https://github.com/fantastic-admin/basic/commit/ce7477b) * 新增 `FaSlider` 组件  -  by @hooray [(f0229)](https://github.com/fantastic-admin/basic/commit/f02298b) * 增加 cursor 配置  -  by @hooray [(b0ac0)](https://github.com/fantastic-admin/basic/commit/b0ac061) 🐞 Bug Fixes * `FaContextMenu` z-index 被遮挡  -  by @hooray [(ebf61)](https://github.com/fantastic-admin/basic/commit/ebf61b0) * 修复 `FaDrawer` 组件 `contentClass` 设置无效  -  by @hooray [(5bfb3)](https://github.com/fantastic-admin/basic/commit/5bfb3c8) * 浏览器不支持 color-mix 时,框架主题不会同步至 element-plus 主题  -  by @hooray [(609e7)](https://github.com/fantastic-admin/basic/commit/609e77c) * 在路由守卫中捕获异常时,添加登出逻辑  -  by @hooray [(5fcd3)](https://github.com/fantastic-admin/basic/commit/5fcd3fe) 🏎 Performance * 优化导航菜单  -  by @hooray [(5e59d)](https://github.com/fantastic-admin/basic/commit/5e59d12) * 优化子菜单过渡效果,支持两套实现方案  -  by @hooray [(10c84)](https://github.com/fantastic-admin/basic/commit/10c8401) ::: :::tip [专业版](https://github.com/fantastic-admin/pro/releases/tag/v5.2.0) 🚨 Breaking Changes * Radix-vue 迁移到 reka-ui  -  by @hooray [(5b45b)](https://github.com/fantastic-admin/pro/commit/5b45b75a) * 重写路由 `push/go/replace` 函数,移除 useTabbar 中 `open/go/replace` 函数  -  by @hooray [(8ca74)](https://github.com/fantastic-admin/pro/commit/8ca74642) 🚀 Features * `FaDivider` 增加 class props  -  by @hooray [(73e87)](https://github.com/fantastic-admin/pro/commit/73e87bda) * 新增 `FaFlipCard` 组件  -  by @hooray [(87122)](https://github.com/fantastic-admin/pro/commit/87122797) * 新增 `FaLinkPreview` 组件  -  by @hooray [(28b3c)](https://github.com/fantastic-admin/pro/commit/28b3c973) * 新增 `FaInteractiveButton` 组件  -  by @hooray [(27c12)](https://github.com/fantastic-admin/pro/commit/27c12b5c) * 新增 `FaGradientButton` 组件  -  by @hooray [(595c2)](https://github.com/fantastic-admin/pro/commit/595c2e37) * 新增 `FaMarquee` 组件  -  by @hooray [(7efc5)](https://github.com/fantastic-admin/pro/commit/7efc592f) * 新增 `FaBlurReveal` 组件  -  by @hooray [(b4d6d)](https://github.com/fantastic-admin/pro/commit/b4d6d32c) * 新增 `FaParticlesBg` 组件  -  by @hooray [(8f9af)](https://github.com/fantastic-admin/pro/commit/8f9afb5e) * 新增 `FaTextHighlight` 组件  -  by @hooray [(9e1a0)](https://github.com/fantastic-admin/pro/commit/9e1a0cc3) * 新增 `FaFlipWords` 组件  -  by @hooray [(83e7f)](https://github.com/fantastic-admin/pro/commit/83e7f32f) * 新增 `FaGlowyCardWrapper` / `FaGlowyCard` 组件  -  by @hooray [(e3191)](https://github.com/fantastic-admin/pro/commit/e3191464) * 新增 `FaAnimatedBeam` 组件  -  by @hooray [(e305e)](https://github.com/fantastic-admin/pro/commit/e305ed97) * 新增 `FaSparklesText` 组件  -  by @hooray [(500cf)](https://github.com/fantastic-admin/pro/commit/500cf410) * `FaAnimatedBeam` 组件增加虚线光束支持  -  by @hooray [(0fa92)](https://github.com/fantastic-admin/pro/commit/0fa92486) * 新增 `FaSpotlightCard` 组件  -  by @hooray [(9792b)](https://github.com/fantastic-admin/pro/commit/9792b757) * 新增 `useConfetti` 函数  -  by @hooray [(2d665)](https://github.com/fantastic-admin/pro/commit/2d665f06) * 新增 `FaPatternBg` 组件  -  by @hooray [(7a063)](https://github.com/fantastic-admin/pro/commit/7a06351a) * 新增 `FaScratchOff` 组件  -  by @hooray [(a09f3)](https://github.com/fantastic-admin/pro/commit/a09f35d4) * 新增 `FaBorderBeam` 组件  -  by @hooray [(b290c)](https://github.com/fantastic-admin/pro/commit/b290c961) * 增加 `layout.widthModeScope` 应用配置  -  by @hooray [(20d02)](https://github.com/fantastic-admin/pro/commit/20d02a0f) * Layouts 布局支持 ``  -  by @hooray [(27f8e)](https://github.com/fantastic-admin/pro/commit/27f8ec12) * 新增 `FaCarousel` 组件  -  by @hooray [(62806)](https://github.com/fantastic-admin/pro/commit/62806dec) * 新增 `FaSlider` 组件  -  by @hooray [(f2c9e)](https://github.com/fantastic-admin/pro/commit/f2c9e38c) * 增加 cursor 配置  -  by @hooray [(ec799)](https://github.com/fantastic-admin/pro/commit/ec79989d) * `FaCode` 组件增加 class 属性  -  by @hooray [(5b04b)](https://github.com/fantastic-admin/pro/commit/5b04bf8b) * 新增 `FaCodePreview` 组件  -  by @hooray [(1be49)](https://github.com/fantastic-admin/pro/commit/1be49849) 🐞 Bug Fixes * `FaContextMenu` z-index 被遮挡  -  by @hooray [(511f6)](https://github.com/fantastic-admin/pro/commit/511f64c4) * 修复 `FaDrawer` 组件 `contentClass` 设置无效  -  by @hooray [(9215d)](https://github.com/fantastic-admin/pro/commit/9215d5bd) * 浏览器不支持 color-mix 时,框架主题不会同步至 element-plus 主题  -  by @hooray [(7e6a9)](https://github.com/fantastic-admin/pro/commit/7e6a9ca5) * 修复 `FaGlowyCard` 组件在移动端下导致页面无法滑动的问题  -  by @hooray [(7e420)](https://github.com/fantastic-admin/pro/commit/7e4200aa) * 修复路由 `meta.permanent` 参数失效  -  by @hooray [(325d6)](https://github.com/fantastic-admin/pro/commit/325d68d2) * 修复页宽模式在移动端布局错乱  -  by @hooray [(2bd6c)](https://github.com/fantastic-admin/pro/commit/2bd6c317) * 在路由守卫中捕获异常时,添加登出逻辑  -  by @hooray [(d95ee)](https://github.com/fantastic-admin/pro/commit/d95ee6c2) * 修复主导航文字不显示  -  by @hooray [(867f0)](https://github.com/fantastic-admin/pro/commit/867f03be) 🏎 Performance * 优化导航菜单  -  by @hooray [(951d0)](https://github.com/fantastic-admin/pro/commit/951d0f1f) * 优化子菜单过渡效果,支持两套实现方案  -  by @hooray [(f3858)](https://github.com/fantastic-admin/pro/commit/f385819c) ::: ## v5.1.0 :::info [基础版](https://github.com/fantastic-admin/basic/releases/tag/v5.1.0) 🚨 Breaking Changes * 重构注册路由数据结构  -  by @hooray [(cfb4f)](https://github.com/fantastic-admin/basic/commit/cfb4f23) 🚀 Features * `FaSelect` 组件增加 class props  -  by @hooray [(eff07)](https://github.com/fantastic-admin/basic/commit/eff07c2) * 刷新按钮增加按住ctrl使用原生浏览器刷新功能  -  by @hooray [(2100b)](https://github.com/fantastic-admin/basic/commit/2100bbe) * 增加 vue devtools 启动编辑器环境变量  -  by @hooray [(643d4)](https://github.com/fantastic-admin/basic/commit/643d458) * `FaPopover` 组件增加手动控制面板显示  -  by @hooray [(6d58f)](https://github.com/fantastic-admin/basic/commit/6d58f1c) 🐞 Bug Fixes * 导航搜索面板唤起时输入框未聚焦  -  by @hooray [(a6e66)](https://github.com/fantastic-admin/basic/commit/a6e66c3) * 修复 `useFaModal` 弹窗警告  -  by @hooray [(b3b89)](https://github.com/fantastic-admin/basic/commit/b3b8947) ::: :::tip [专业版](https://github.com/fantastic-admin/pro/releases/tag/v5.1.0) 🚨 Breaking Changes * 重构注册路由数据结构  -  by @hooray [(c0d8b)](https://github.com/fantastic-admin/pro/commit/c0d8b9bf) 🚀 Features * `FaSelect` 组件增加 class props  -  by @hooray [(83e5a)](https://github.com/fantastic-admin/pro/commit/83e5a9e3) * 新增 `FaCode` 组件  -  by @hooray [(ac4e1)](https://github.com/fantastic-admin/pro/commit/ac4e1678) * 刷新按钮增加按住ctrl使用原生浏览器刷新功能  -  by @hooray [(a152b)](https://github.com/fantastic-admin/pro/commit/a152b948) * `FaLayoutContainer` 组件增加顶部底部区域  -  by @hooray [(66def)](https://github.com/fantastic-admin/pro/commit/66def612) * 增加 vue devtools 启动编辑器环境变量  -  by @hooray [(f1e86)](https://github.com/fantastic-admin/pro/commit/f1e863d1) * `FaPopover` 组件增加手动控制面板显示  -  by @hooray [(9c961)](https://github.com/fantastic-admin/pro/commit/9c961713) 🐞 Bug Fixes * 导航搜索面板唤起时输入框未聚焦  -  by @hooray [(0611c)](https://github.com/fantastic-admin/pro/commit/0611ca1a) * 修复 `useFaModal` 弹窗警告  -  by @hooray [(a2384)](https://github.com/fantastic-admin/pro/commit/a2384f0e) ::: ## v5.0.0 **此版本有较多破坏性的变更,如果打算从 v4.x 升级,请仔细阅读并谨慎迁移代码。** * 引入 [shadcn-vue](https://www.shadcn-vue.com/) ,内建组件和部分扩展组件基于 shadcn-vue 进行重构 * 系统主题重构,挑选了 shadcn-vue 中的 8 款主题并进行定制 * 所有内建组件名均改为 `Fa` 开头,例如 `FaButton` 。部分扩展组件也转为内建组件,例如 `FaPageHeader` 。新增了一系列基于 shadcn-vue 的组件,例如 `FaPopover` 。为与扩展组件做区分,内建组件存放在 `/src/ui/components/` 目录下 * 登录页使用内建组件进行重构,不再依赖 `element-plus` ,更方便迁移其他 UI 组件库 * 新增 `app.themeSync` 应用设置 * 路由 `meta` 配置项调整: * 移除 `meta.i18n` ,`meta.title` 支持国际化 * 移除 `meta.sidebar` ,改为 `meta.menu` * 移除 `meta.paddingBottom` ,改为由框架自动处理 * 新增 `meta.badgeVariant` ,用于设置导航徽章颜色 * 新增 `meta.query` ,用于设置点击导航时进行路由跳转时,携带的参数 * 新增 `meta.maximize` ,用于设置访问导航的路由时,是否最大化 * 新增 `meta.exitMaximize` ,用于设置离开导航的路由时,是否退出最大化 * 新增 `meta.sort` ,用于设置导航的排序 * 主导航增加徽章和徽章颜色设置 * 新增 `app.loginExpiredMode` 应用设置,设置登录状态过期后的行为 * 新增 `app.enableCheckUpdates` 应用设置,检查网站是否有更新 * 移除 `menu.switchMainMenuAndPageJump` 应用设置,新增 `menu.mainMenuClickMode` 应用设置,更灵活控制主导航的点击行为 * 增加全局插槽,用于在导航、顶栏等位置插入自定义内容 ## v4.x 前往 [v4](https://fantastic-admin.hurui.me/v4-docs/guide/changelog.html) 文档查看 ## v3.x 前往 [v3](https://fantastic-admin.hurui.me/v3-docs/guide/changelog.html) 文档查看 ## v2.x 前往 [v2](https://fantastic-admin.hurui.me/v2-docs/guide/changelog.html) 文档查看 --- --- url: /guide/replace-to-antd.md --- # 替换为 Ant Design Vue 由于框架默认使用的是 Element Plus 组件库,并且演示源码中大量示例也使用了 Element Plus,如果你需要使用 [Ant Design Vue](https://www.antdv.com/docs/vue/introduce-cn),请拉取框架源码分支,或者到 [Github Releases](https://github.com/fantastic-admin/basic/releases) 页面下载框架源码压缩包。 专业版用户也同样,请到专业版仓库下载框架源码。 ## 安装 ```sh # 安装依赖 pnpm install # 安装 Ant Design Vue pnpm add ant-design-vue@4.x ``` ## 代码调整 ::: details 基础版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import Antd from 'ant-design-vue' import 'ant-design-vue/dist/reset.css' function install(app: App) { app.use(Antd) } export default { install } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload └─ ImageUpload ``` ::: ::: details 专业版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import Antd from 'ant-design-vue' import 'ant-design-vue/dist/reset.css' import zhCN from 'ant-design-vue/es/locale/zh_CN' import zhTW from 'ant-design-vue/es/locale/zh_TW' import en from 'ant-design-vue/es/locale/en_US' function install(app: App) { app.use(Antd) } // 此处的对象属性和 src/locales/index.ts 中的 messages 对象属性一一对应 const locales: Record = { 'zh-cn': zhCN, 'zh-tw': zhTW, 'en': en, } export default { install } export { locales } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . ├─ plop-templates │ └─ module // 标准模块模板基于 Element Plus 开发,需要删除 └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload ├─ ImageUpload └─ PcasCascader ``` ::: ## 卸载 ```sh # 卸载 Element Plus pnpm remove element-plus ``` ## 完成 至此,你已经将框架中的 Element Plus 组件库替换为 Ant Design Vue 组件库,并且可以开始使用 Ant Design Vue 进行业务开发了。 ## 示例 如果对上述的步骤还有不清楚的地方,可以访问[此仓库](https://github.com/fantastic-admin/antd-example)查看示例源码,以及[此链接](https://fantastic-admin.hurui.me/antd-example/)查看示例网站。 ![](/ui-antd.png){data-zoomable} --- --- url: /guide/replace-to-arco.md --- # 替换为 Arco Design Vue 由于框架默认使用的是 Element Plus 组件库,并且演示源码中大量示例也使用了 Element Plus,如果你需要使用 [Arco Design Vue](https://arco.design/vue/docs/start),请拉取框架源码分支,或者到 [Github Releases](https://github.com/fantastic-admin/basic/releases) 页面下载框架源码压缩包。 专业版用户也同样,请到专业版仓库下载框架源码。 ## 安装 ```sh # 安装依赖 pnpm install # 安装 Arco Design Vue pnpm add @arco-design/web-vue -D ``` ## 代码调整 ::: details 基础版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global", // [!code --] ... ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import ArcoVue from '@arco-design/web-vue' import '@arco-design/web-vue/dist/arco.css' function install(app: App) { app.use(ArcoVue) } export default { install } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload └─ ImageUpload ``` ::: ::: details 专业版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import ArcoVue from '@arco-design/web-vue' import '@arco-design/web-vue/dist/arco.css' import zhCN from '@arco-design/web-vue/es/locale/lang/zh-CN' import zhTW from '@arco-design/web-vue/es/locale/lang/zh-TW' import en from '@arco-design/web-vue/es/locale/lang/en-US' function install(app: App) { app.use(ArcoVue) } // 此处的对象属性和 src/locales/index.ts 中的 messages 对象属性一一对应 const locales: Record = { 'zh-cn': zhCN, 'zh-tw': zhTW, 'en': en, } export default { install } export { locales } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . ├─ plop-templates │ └─ module // 标准模块模板基于 Element Plus 开发,需要删除 └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload ├─ ImageUpload └─ PcasCascader ``` ::: ## 卸载 ```sh # 卸载 Element Plus pnpm remove element-plus ``` ## 完成 至此,你已经将框架中的 Element Plus 组件库替换为 Arco Design Vue 组件库,并且可以开始使用 Arco Design Vue 进行业务开发了。 ## 示例 如果对上述的步骤还有不清楚的地方,可以访问[此仓库](https://github.com/fantastic-admin/arco-example)查看示例源码,以及[此链接](https://fantastic-admin.hurui.me/arco-example/)查看示例网站。 ![](/ui-arco.png){data-zoomable} --- --- url: /guide/replace-to-idux.md --- # 替换为 iDux 由于框架默认使用的是 Element Plus 组件库,并且演示源码中大量示例也使用了 Element Plus,如果你需要使用 [iDux](https://idux.site/),请拉取框架源码分支,或者到 [Github Releases](https://github.com/fantastic-admin/basic/releases) 页面下载框架源码压缩包。 专业版用户也同样,请到专业版仓库下载框架源码。 ## 安装 ```sh # 安装依赖 pnpm install # 安装 iDux pnpm add @idux/cdk @idux/components ``` ## 代码调整 ::: details 基础版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import IduxCdk from '@idux/cdk' import IduxComponents from '@idux/components' import { createGlobalConfig } from '@idux/components/config' import { IDUX_ICON_DEPENDENCIES, addIconDefinitions } from '@idux/components/icon' import { zhCN } from '@idux/components/locales' import '@idux/components/index.full.css' function install(app: App) { addIconDefinitions(IDUX_ICON_DEPENDENCIES) app.use(IduxCdk).use(IduxComponents).use(createGlobalConfig({ locale: zhCN })) } export default { install } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload └─ ImageUpload ``` ::: ::: details 专业版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import IduxCdk from '@idux/cdk' import IduxComponents from '@idux/components' import { IDUX_ICON_DEPENDENCIES, addIconDefinitions } from '@idux/components/icon' import { enUS, zhCN } from '@idux/components/locales' import '@idux/components/index.full.css' // 此处的对象属性和 src/locales/index.ts 中的 messages 对象属性一一对应 const locales: Record = { 'zh-cn': zhCN, 'zh-tw': zhCN, 'en': enUS, } function install(app: App) { addIconDefinitions(IDUX_ICON_DEPENDENCIES) app.use(IduxCdk).use(IduxComponents) } export default { install } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . ├─ plop-templates │ └─ module // 标准模块模板基于 Element Plus 开发,需要删除 └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload ├─ ImageUpload └─ PcasCascader ``` ::: ## 卸载 ```sh # 卸载 Element Plus pnpm remove element-plus ``` ## 完成 至此,你已经将框架中的 Element Plus 组件库替换为 iDux 组件库,并且可以开始使用 iDux 进行业务开发了。 ## 示例 如果对上述的步骤还有不清楚的地方,可以访问[此仓库](https://github.com/fantastic-admin/idux-example)查看示例源码,以及[此链接](https://fantastic-admin.hurui.me/idux-example/)查看示例网站。 ![](/ui-idux.png){data-zoomable} --- --- url: /guide/replace-to-naive.md --- # 替换为 Naive UI 由于框架默认使用的是 Element Plus 组件库,并且演示源码中大量示例也使用了 Element Plus,如果你需要使用 [Naive UI](https://www.naiveui.com/zh-CN),请拉取框架源码分支,或者到 [Github Releases](https://github.com/fantastic-admin/basic/releases) 页面下载框架源码压缩包。 专业版用户也同样,请到专业版仓库下载框架源码。 ## 安装 ```sh # 安装依赖 pnpm install # 安装 Naive UI pnpm add naive-ui -D ``` ## 代码调整 ::: details 基础版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] "naive-ui/volar" // [!code ++] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import naive from 'naive-ui' function install(app: App) { app.use(naive) } export default { install } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload └─ ImageUpload ``` ::: ::: details 专业版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] "naive-ui/volar" // [!code ++] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import naive, { dateEnUS, dateZhCN, dateZhTW, enUS, zhCN, zhTW } from 'naive-ui' function install(app: App) { app.use(naive) } // 此处的对象属性和 src/locales/index.ts 中的 messages 对象属性一一对应 const locales: Record = { 'zh-cn': { ui: zhCN, date: dateZhCN, }, 'zh-tw': { ui: zhTW, date: dateZhTW, }, 'en': { ui: enUS, date: dateEnUS, }, } export default { install } export { locales } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . ├─ plop-templates │ └─ module // 标准模块模板基于 Element Plus 开发,需要删除 └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload ├─ ImageUpload └─ PcasCascader ``` ::: ## 卸载 ```sh # 卸载 Element Plus pnpm remove element-plus ``` ## 完成 至此,你已经将框架中的 Element Plus 组件库替换为 Naive UI 组件库,并且可以开始使用 Naive UI 进行业务开发了。 ## 示例 如果对上述的步骤还有不清楚的地方,可以访问[此仓库](https://github.com/fantastic-admin/naive-example)查看示例源码,以及[此链接](https://fantastic-admin.hurui.me/naive-example/)查看示例网站。 ![](/ui-naive.png){data-zoomable} --- --- url: /guide/replace-to-tdesign.md --- # 替换为 TDesign 由于框架默认使用的是 Element Plus 组件库,并且演示源码中大量示例也使用了 Element Plus,如果你需要使用 [TDesign](https://tdesign.tencent.com/vue-next),请拉取框架源码分支,或者到 [Github Releases](https://github.com/fantastic-admin/basic/releases) 页面下载框架源码压缩包。 专业版用户也同样,请到专业版仓库下载框架源码。 ## 安装 ```sh # 安装依赖 pnpm install # 安装 TDesign pnpm add tdesign-vue-next ``` ## 代码调整 ::: details 基础版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... }, ... "include": [ "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue" // [!code --] "src/**/*.vue", // [!code ++] "node_modules/tdesign-vue-next/global.d.ts" // [!code ++] ] } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import TDesign from 'tdesign-vue-next' import 'tdesign-vue-next/es/style/index.css' function install(app: App) { app.use(TDesign) } export default { install } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload └─ ImageUpload ``` ::: ::: details 专业版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... }, ... "include": [ "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue" // [!code --] "src/**/*.vue", // [!code ++] "node_modules/tdesign-vue-next/global.d.ts" // [!code ++] ] } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import TDesign from 'tdesign-vue-next' import 'tdesign-vue-next/es/style/index.css' import zhCN from 'tdesign-vue-next/es/locale/zh_CN' import zhTW from 'tdesign-vue-next/es/locale/zh_TW' import en from 'tdesign-vue-next/es/locale/en_US' function install(app: App) { app.use(TDesign) } // 此处的对象属性和 src/locales/index.ts 中的 messages 对象属性一一对应 const locales: Record = { 'zh-cn': zhCN, 'zh-tw': zhTW, 'en': en, } export default { install } export { locales } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . ├─ plop-templates │ └─ module // 标准模块模板基于 Element Plus 开发,需要删除 └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload ├─ ImageUpload └─ PcasCascader ``` ::: ## 卸载 ```sh # 卸载 Element Plus pnpm remove element-plus ``` ## 完成 至此,你已经将框架中的 Element Plus 组件库替换为 TDesign 组件库,并且可以开始使用 TDesign 进行业务开发了。 ## 示例 如果对上述的步骤还有不清楚的地方,可以访问[此仓库](https://github.com/fantastic-admin/tdesign-example)查看示例源码,以及[此链接](https://fantastic-admin.hurui.me/tdesign-example/)查看示例网站。 ![](/ui-tdesign.png){data-zoomable} --- --- url: /guide/replace-to-vexip.md --- # 替换为 Vexip UI 由于框架默认使用的是 Element Plus 组件库,并且演示源码中大量示例也使用了 Element Plus,如果你需要使用 [Vexip UI](https://www.vexipui.com/zh-CN/),请拉取框架源码分支,或者到 [Github Releases](https://github.com/fantastic-admin/basic/releases) 页面下载框架源码压缩包。 专业版用户也同样,请到专业版仓库下载框架源码。 ## 安装 ```sh # 安装依赖 pnpm install # 安装 Vexip UI pnpm add vexip-ui ``` ## 代码调整 ::: details 基础版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import { install as vexipInstall } from 'vexip-ui' import 'vexip-ui/css/index.css' import 'vexip-ui/css/dark/index.css' function install(app: App) { app.use(vexipInstall, { prefix: 'vxp', }) } export default { install } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload └─ ImageUpload ``` ::: ::: details 专业版 修改 `/tsconfig.app.json` 文件 ```json { "compilerOptions": { ... "types": [ ... "element-plus/global" // [!code --] ], ... } } ``` 整体修改 `/src/ui/provider/index.ts` 文件 ```ts import type { App } from 'vue' import { install as vexipInstall, zhCNLocale, zhTWLocale, enUSLocale } from 'vexip-ui' import 'vexip-ui/css/index.css' import 'vexip-ui/css/dark/index.css' function install(app: App) { app.use(vexipInstall, { prefix: 'vxp', }) } // 此处的对象属性和 src/locales/index.ts 中的 messages 对象属性一一对应 const locales: Record = { 'zh-cn': zhCNLocale(), 'zh-tw': zhTWLocale(), 'en': enUSLocale(), } export default { install } export { locales } ``` 整体修改 `/src/ui/provider/index.vue` 文件 ```vue ``` 删除相关文件 ``` . ├─ plop-templates │ └─ module // 标准模块模板基于 Element Plus 开发,需要删除 └─ src └─ components // 下列扩展组件基于 Element Plus 二次封装,需要删除 ├─ FileUpload ├─ ImagePreview ├─ ImagesUpload ├─ ImageUpload └─ PcasCascader ``` ::: ## 卸载 ```sh # 卸载 Element Plus pnpm remove element-plus ``` ## 完成 至此,你已经将框架中的 Element Plus 组件库替换为 Vexip UI 组件库,并且可以开始使用 Vexip UI 进行业务开发了。 ## 示例 如果对上述的步骤还有不清楚的地方,可以访问[此仓库](https://github.com/fantastic-admin/vexip-example)查看示例源码,以及[此链接](https://fantastic-admin.hurui.me/vexip-example/)查看示例网站。 ![](/ui-vexip.png){data-zoomable} --- --- url: /guide/term.md --- # 术语 熟悉框架术语,能帮助你轻松阅读文档,同时与其它开发者交流时,也能帮助你准确地表述问题。 ## 主导航 ![](/term-mainsidebar-1.png){data-zoomable} ![](/term-mainsidebar-2.png){data-zoomable} ## 次导航 ![](/term-subsidebar.png){data-zoomable} ### 一级导航(一级路由) ![](/term-route-1.png){data-zoomable} ### 二级导航(二级路由) ![](/term-route-2.png){data-zoomable} ### 三级导航(三级路由) ![](/term-route-3.png){data-zoomable} ## 顶栏 顶栏 = 标签栏 + 工具栏 ### 标签栏 ![](/term-tabbar.png){data-zoomable} ### 工具栏 ![](/term-toolbar.png){data-zoomable} --- --- url: /guide/permission.md --- # 权限 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { app: { /** * 是否开启权限功能 * @默认值 `false` */ enablePermission: true, }, } ``` 然后在 `/src/api/modules/user.ts` 文件里找到 `getPermissions` 的方法,该方法用于登录成功后获取用户权限。在实际开发中,需要手动进行修改,框架默认通过 mock 模拟获取用户权限。 在演示源码中,默认提供了两组权限,你可以在“权限验证”导航里切换帐号查看不同权限下的效果。 ## 路由权限 在路由的 `meta` 配置项中,其中有一个 `auth` 参数,这个就是用来配置路由的权限,一个路由可以配置多个权限,当配置多个权限时,只要满足其中任何一个,则视为用户有访问该路由的权限,如下: ```ts meta: { auth: ['news.browse', 'news.edit'], }, ``` 框架内部鉴权的逻辑是字符串比对,所以建议对权限有个统一的格式,例如为 `xxx.yyy` ,其中 `xxx` 表示模块名, `yyy` 表示操作类型。那么上面那个例子就表示: * `news.browse` 新闻模块的浏览权限 * `news.edit` 新闻模块的编辑权限 路由权限是比较暴力的,即没有权限则该路由页面无法访问,并且也不会在导航栏中显示。但在实际业务中,遇到更多的情况通常是,可以访问路由页面,但会根据不同权限,使用页面里的不同功能,这时候就需要用到下面三种鉴权方式。 ## 鉴权指令 对于单个元素,提供了 `v-auth` 指令。 ```vue-html ``` ## 鉴权组件 页面中某个模块,当前用户具备该权限是如何显示,不具备该权限又是如何显示,针对这样的需求,框架提供了 `` 组件。 ```vue-html

你有该权限

你有该权限

你有该权限

``` ## 鉴权函数 鉴权组件和鉴权指令控制的是页面上的元素,而鉴权函数则更多是使用在业务流程代码里的权限判断。 ```ts import useAuth from '@/utils/composables/useAuth' const { auth, authAll } = useAuth() // 单权限验证,返回 true 或 false auth('department.create') // 多权限验证,用户只要具备其中任何一个权限,则验证通过,返回 true 或 false auth(['department.create', 'department.edit']) // 多权限验证,用户必须具备全部权限,才验证通过,返回 true 或 false authAll(['department.create', 'department.edit']) ``` ## 小技巧 由于权限配置不涉及角色,所以在实现上会更灵活,开发者可自行扩展出角色模块,根据不同角色动态设置该角色所拥有的权限,然后用户与角色挂钩,这样就无需繁琐的给每个用户重复配置权限。 当然了,业务有大有小,针对一些小型的管理系统,对权限这块没有这么多复杂的要求,甚至什么角色拥有什么权限都是写死固定的,不需要自由配置。针对这种情况,框架也可以很方便的实现。 ```ts import type { RouteRecordRaw } from 'vue-router' import Layout from '@/layouts/index.vue' const routes: RouteRecordRaw = { path: '/banner', component: Layout, redirect: '/banner/list', name: 'banner', meta: { title: 'Banner 管理', icon: 'banner', auth: ['admin', 'editor'], }, children: [ { path: 'detail', name: 'bannerCreate', component: () => import('@/views/banner/detail.vue'), meta: { title: '新增 Banner', auth: ['admin', 'editor'], }, }, { path: 'list', name: 'bannerList', component: () => import('@/views/banner/list.vue'), meta: { title: 'Banner 列表', auth: ['admin'], }, }, { path: 'detail/:id', name: 'bannerEdit', component: () => import('@/views/banner/detail.vue'), meta: { title: '编辑 Banner', auth: ['admin'], menu: false, }, }, ], } export default routes ``` 如上所示,假设有 2 种角色,一个是管理员 `admin` ,一个是编辑员 `editor` ,如果用户是 `admin` 权限,则可以操作 Banner 管理下的所有功能,如果是 `editor` 权限,则只能进行新增 Banner 操作。 --- --- url: /guide/build.md --- # 构建与预览 ## 构建 项目开发完成之后,可以执行 `pnpm run build` 命令进行构建,构建打包成功之后,会在根目录生成 dist 文件夹,里面就是构建打包好的文件。 如果是需要构建测试环境,则执行 `pnpm run build:test` 命令,对应会在根目录生成 dist-test 文件夹。 :::tip 如果最终访问地址为域名非根节点,如 `https://www.example.com/app`,则需要在 `vite.config.ts` 中设置 `base` 选项为 `/app/`,否则会出现资源引用错误。 ::: ## 预览 生成好的 dist 文件夹一般需要部署至服务器才算部署发布成功,但为了保证构建出来的文件能正常运行,开发者通常希望能在本地先预览一下,可执行 `pnpm run serve` 或 `pnpm run serve:test` 命令预览不同环境构建出的文件夹。 ## 压缩 在环境配置文件里设置 `VITE_BUILD_COMPRESS` 即可在构建时生成 `.gz` 或 `.br` 文件。 ``` # 单独开启 gzip VITE_BUILD_COMPRESS = gzip # 单独开启 brotli ,brotli 是比 gzip 压缩率更高的算法 VITE_BUILD_COMPRESS = brotli # 或者也可以都开启,两者可以共存 VITE_BUILD_COMPRESS = gzip,brotli ``` 两者均需要 nginx 安装指定模块并开启后才会生效。 ## 生成存档 在环境配置文件里设置 `VITE_BUILD_ARCHIVE` 即可在构建完后成生成 `.zip` 或 `.tar.gz` 文件。 ``` # 生成 zip VITE_BUILD_ARCHIVE = zip # 生成 tar.gz VITE_BUILD_ARCHIVE = tar ``` ## 禁用浏览器开发者工具 在环境配置文件里设置 `VITE_APP_DISABLE_DEVTOOLS` 即可在构建后禁用浏览器开发者工具。 ``` # 禁用开发者工具 VITE_APP_DISABLE_DEVTOOLS = true ``` ## 其它设置 ``` # 是否在打包时生成 sourcemap VITE_BUILD_SOURCEMAP = true ``` --- --- url: /guide/plop-module.md --- # 标准模块 在《[代码文件自动生成 - module](plop#module)》里介绍了如何快速生成一个标准模块,这个标准模块是一个最基础的 CURD 模块,它包含列表页和编辑页,同时提供了搜索和删除的功能,并且同时也可以生成对应的 mock 文件,在这基础上可以更方便的进行业务扩展。 下面我就实际操作一遍,并介绍一下这个标准模块有哪些特性。 ## 使用介绍 ``` ? 请选择需要创建的模式: module - 创建标准模块(包含列表页&详情页) ? 请选择模块创建目录 src/views ? 请输入模块名 example ? 请输入模块中文名称 演示 ? 是否生成 Mock Yes √ ++ \src\views\example\list.vue √ ++ \src\views\example\detail.vue √ ++ \src\views\example\components\DetailForm\index.vue √ ++ \src\views\example\components\FormMode\index.vue √ ++ \src\mock\example.ts ``` 这里我已经通过命令在 `/src/views/` 目录下创建好了一个 example 文件夹,并且也生成了 mock 数据。接下来需要去配置下路由,这样我们才可以在导航栏里访问到。 首先在 `/src/router/modules/` 目录下新建一个与文件夹同名的 `example.ts` 文件,并在里面复制以下代码: ```ts import type { RouteRecordRaw } from 'vue-router' const Layout = () => import('@/layouts/index.vue') const routes: RouteRecordRaw = { path: '/example', component: Layout, redirect: '/example/list', name: 'example', meta: { title: '演示', }, children: [ { path: 'list', name: 'exampleList', component: () => import('@/views/example/list.vue'), meta: { title: '列表', }, }, { path: 'create', name: 'exampleCreate', component: () => import('@/views/example/detail.vue'), meta: { title: '新增', menu: false, activeMenu: '/example/list', }, }, { path: 'edit/:id', name: 'exampleEdit', component: () => import('@/views/example/detail.vue'), meta: { title: '编辑', menu: false, activeMenu: '/example/list', }, }, ], } export default routes ``` 然后到 `/src/router/routes.ts` 文件里加上这个路由配置文件的引用。 ```ts {1,12} import Example from './modules/example' const asyncRoutes: Route.recordMainRaw[] = [ ..., { meta: { title: '页面', icon: 'ri-pages-line', }, children: [ ...PagesExample, Example, ], }, ] ``` 最后,我们还需要替换几处页面中路由的 `name` 因为需要和我们配置的路由 `name` 一致,才可以正确跳转页面。 先打开 `list.vue` 文件,找到 `onCreate()` 和 `onEdit()` 方法并替换: ```ts {5,10,24,32} function onCreate() { if (formMode.value === 'router') { if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') { tabbar.open({ name: 'routeName', }) } else { router.push({ name: 'routeName', }) } } else { formModeProps.value.id = '' formModeProps.value.visible = true } } function onEdit(row: any) { if (formMode.value === 'router') { if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') { tabbar.open({ name: 'routeName', params: { id: row.id, }, }) } else { router.push({ name: 'routeName', params: { id: row.id, }, }) } } else { formModeProps.value.id = row.id formModeProps.value.visible = true } } ``` 然后打开 `detail.vue` 文件,替换以下两处: ```vue-html {1} 返回 ``` ```ts {3,6} function goBack() { if (settingsStore.settings.tabbar.enable && settingsStore.settings.tabbar.mergeTabsBy !== 'activeMenu') { tabbar.close({ name: 'exampleList' }) } else { router.push({ name: 'exampleList' }) } } ``` 这时候就可以通过导航栏访问到我们的页面了,我们的一个演示模块也就初步创建好了。 ![](/module1.gif){data-zoomable} ## 特性介绍 功能部分的介绍主要还是要看代码,先从列表页 `list.vue` 开始。 最先看到的是这行代码,因为几乎每个列表页都需要翻页功能,所以把翻页相关的东西都存放在 `/src/utils/composables/usePagination.ts` 方便复用。 ```ts const { pagination, getParams, onSizeChange, onCurrentChange, onSortChange } = usePagination() ``` 接着是标准模块提供的一些配置项和必要数据字段。 ```ts {10} // 表格是否自适应高度 const tableAutoHeight = ref(false) /** * 详情展示模式 * router 路由跳转 * dialog 对话框 * drawer 抽屉 */ const formMode = ref<'router' | 'dialog' | 'drawer'>('router') // 详情 const formModeProps = ref({ visible: false, id: '', }) // 搜索 const searchDefault = { title: '', } const search = ref({ ...searchDefault }) function searchReset() { Object.assign(search.value, searchDefault) } // 批量操作 const batch = ref({ enable: true, selectionDataList: [], }) // 列表 const loading = ref(false) const dataList = ref([]) ``` 标准模块提供了 3 种详情展示模式,默认是路由跳转的方式,你可以修改 `formMode` 开启详情弹窗模式,保存后效果如下: ![](/module2.gif){data-zoomable} 紧接着的是下面这段代码,它的作用是当列表页开启缓存时,并以路由跳转的方式进入详情页进行新增或编辑操作后,先对缓存的列表页进行一次数据更新,然后再跳转回列表页,这样即可以保证列表页相关搜索、翻页等状态可以被缓存,又能保证数据是最新。具体实现则是通过绑定一个事件总线,并在详情页里调用这个事件。需要注意的是,专业版如果开启标签栏,事件总线的名称得确保唯一。 ```ts onMounted(() => { getDataList() if (formMode.value === 'router') { eventBus.on('get-data-list', () => { getDataList() }) } }) onBeforeUnmount(() => { if (formMode.value === 'router') { eventBus.off('get-data-list') } }) ``` 再往下就是需要你修改或编写业务代码的部分,这里就不继续展开了。 详情页的代码就不多介绍了,相对比较简单,可自行阅读理解。其中表单部分单独封装成组件存放在 `/src/views/[模块文件夹]/components/DetailForm/index.vue` 里了,同样你在 `components/` 文件夹下还能看到另外一个 `FormMode` 的文件夹,这样的用意是让表单可以复用,**可以通过路由跳转的形式进入详情页,也可以通过弹窗或抽屉的形式打开详情页**。 可能有人会有疑问,为什么不在生成文件的时候直接让我选择用哪种形式,这样生成出来就是哪种,而是在生成好的代码文件里再进行配置? 这样设计的目的主要有三点: 1. **合理使用**。关于表单具体使用哪种展示模式比较好,我们的建议是,当表单与当前列表页关联性较强,内容少则使用弹窗,内容多则使用抽屉;而当表单与当前列表页关联性较弱,且内容多,则使用路由跳转,让新页面进行承载。 2. **方便后期维护**。考虑到需求会变,可能一开始是一个很简单的表单,后期需求一点点增加,变成了一个庞大的表单,这时候就要从弹窗或抽屉改成路由跳转,反之也可能是从路由跳转改成弹窗或抽屉,处理起来都很麻烦。所以方便后期维护,这部分是有意而为之,做成了 3 种形式共存,通过配置可一键切换。 3. **跨模块的组件调用**。例如有两个管理模块,一个用户管理,一个部门管理,当我在填写新增用户表单的时候,表单项里有一项是选择部门,这时候部门可能还没创建,但表单已经填写一半了。如果让用户离开页面去部门管理里创建好部门后,再回来新建用户,先不说数据如何缓存的问题,光是操作流被打断,页面跳来跳去就很影响用户体验了。所以这个时候就可以在选择部门后面放一个新增部门的操作按钮,点击后弹出新增部门的弹窗,新增完成后弹窗关闭,让用户可以继续在新增用户的界面做后续操作。 *** 当然标准模块也只是框架提供的一个标准,你可以沿用,也可以根据自己的需求指定一套标准,毕竟最终目的都是提高开发效率,同时也确保多人协作开发的时候有个统一标准,不会出现每个人做出来的模块风格都不一样。 --- --- url: /guide/tabbar.md --- # 标签栏 ## 是否启用 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { tabbar: { /** * 是否开启标签栏 * @默认值 `false` */ enable: true, }, } ``` ## 风格 在应用配置中设置: ```ts {2-11} const globalSettings: Settings.all = { tabbar: { /** * 标签栏风格 * @默认值 `''` 默认 * @可选值 `'fashion'` 时尚 * @可选值 `'card'` 卡片 * @可选值 `'square'` 方块 */ style: 'fashion', }, } ``` ![](/tabbar-style.png){data-zoomable} ## 宽度自适应 在 `/src/assets/styles/globals.css` 中设置标签栏中页签的宽度,默认为 `150px` 固定宽度,例如将 2 个变量均设置为 `unset` 时,标签页宽度将随页面标题长度自适应,效果如下: ```scss :root { // 标签页最大最小宽度,两个宽度为同一数值时,则为固定宽度,反之将宽度设置为 unset 则为自适应 --g-tabbar-tab-max-width: unset; --g-tabbar-tab-min-width: unset; } ``` ![](/tabbar-width.png){data-zoomable} ## 右键菜单 其中**固定**、**最大化**、**新窗口打开**为 功能。 ![](/tabbar-context.png){data-zoomable} ### 固定 固定的标签页无法直接关闭,并且下次访问将保留固定标签页状态。 固定标签页默认存储在浏览器本地 localStorage 里,如果需要将数据存储到服务器,可以通过 `tabbar.storageTo` 配置项来实现,具体配置如下: ```ts {2-9} const globalSettings: Settings.all = { tabbar: { /** * 固定标签页存储位置 * @默认值 `'local'` 本地存储 * @可选值 `'server'` 服务器存储 */ storageTo: 'server', }, } ``` 然后到 `/src/api/modules/user.ts` 中找到 `tabbar()` 和 `tabbarEdit()` 这两个函数,并分别修改这两个函数的请求地址。 :::tip 建议 为减轻后端处理,数据会直接以 JSON 字符串进行存储,建议后端可以在用户表增加相关字段,并将字段类型设为 `longtext` 。 ::: ## 拖拽排序 ![](/tabbar-draggable.gif){data-zoomable} ## 快捷操作 ![](/tabbar-action.png){data-zoomable} ## 标签栏双击 在应用配置中设置: ```ts {2-12} const globalSettings: Settings.all = { tabbar: { /** * 标签栏双击执行动作 * @默认值 `'close'` 关闭 * @可选值 `'reload'` 刷新 * @可选值 `'pin'` 固定/取消固定 * @可选值 `'maximize'` 最大化 * @可选值 `'window'` 新窗口打开 */ dblclickAction: 'close', }, } ``` ## 标签页合并 标签页合并功能在一定程度上可以减少标签页的数量,让用户能够准确的找到自己想要的标签页。 在应用配置中设置: ```ts {2-10} const globalSettings: Settings.all = { tabbar: { /** * 标签页合并规则 * @默认值 `''` 不合并 * @可选值 `'routeName'` 根据路由名称,相同路由名称的路由合并 * @可选值 `'activeMenu'` 根据路由的 `meta.activeMenu` 字段,与指向的目标路由合并 */ mergeTabsBy: '', }, } ``` 以下面这段路由配置为例: ```ts const routes: RouteRecordRaw = { path: '/manager', meta: { title: '管理员管理', }, children: [ { path: '', name: 'ManagerList' meta: { title: '管理员列表', }, }, { path: 'detail', name: 'ManagerCreate', meta: { title: '新增管理员', menu: false, activeMenu: '/manager', }, }, { path: 'detail/:id', name: 'ManagerEdit', meta: { title: '编辑管理员', menu: false, activeMenu: '/manager', }, }, ], } ``` ### 不合并 从列表页进入详情页时,框架会新增一个**编辑管理员**的标签页,并且在不关闭详情页时,可打开多个不同的**编辑管理员**标签页,效果如下: ![](/tabbar-no-merge.gif){data-zoomable} ### 根据路由名称合并 从列表页进入详情页时,框架会新增一个**编辑管理员**的标签页,并且在不关闭详情页时,打开多个不同的详情页,只会保持一个**编辑管理员**标签页,效果如下: ![](/tabbar-merge-routename.gif){data-zoomable} ### 根据 `meta.activeMenu` 字段合并 从始至终只会保持一个标签页,其中的关键条件就是 `activeMenu` 这个参数,也就是框架会将设置过 `activeMenu` 的路由与 `activeMenu` 指向的目标路由合并为一个标签页,当在这些路由里相互跳转时,始终只保持一个标签页,效果如下: ![](/tabbar-merge-activemenu.gif){data-zoomable} ## 显示图标 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { tabbar: { /** * 是否开启标签栏图标显示 * @默认值 `false` */ enableIcon: true, }, } ``` 会根据当前路由配置中的 `meta.icon` 和 `meta.activeIcon` 属性来显示图标,如果未设置,则会根据路由嵌套层级,依次向上查找父级路由的 `meta.icon` 和 `meta.activeIcon` 属性进行显示。 ## 记忆功能 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { tabbar: { /** * 是否开启标签栏记忆功能 * @默认值 `false` */ enableMemory: true, }, } ``` 当开启记忆功能时,框架会将当前标签页的状态记录到浏览器当前会话缓存中,刷新页面或重新登录会自动恢复,效果如下: ![](/tabbar-memory.gif){data-zoomable} --- --- url: /guide/upgrade.md --- # 框架更新 首先明确一点,Fantastic-admin 无法像 npm 的插件一样更新,不仅我们的框架如此,其实大部分管理系统框架都是如此。 因为本质上这类框架其实是一个初始模板,开发者会根据自身需求去修改,然后基于业务开展业务代码编写。 所以一旦下载开始使用,基本是无法更新的,你在哪个时间点开始使用,项目就固定在什么版本了。 > 虽然有小部分框架选择将部分核心源码封装成 npm 依赖包,由作者全权维护,这样的处理在一定程度上有解决版本更新的问题,但弊端也很明显,开发者在二次开发上会有明显的局限,作者认为是得不偿失的。 那有没有解决办法么?其实也有,参考如下: 1. 在基于 Fantastic-admin 做项目开发时尽量避免框架自带模块或组件的改动,或者改动地方做一个文档记录,可以清楚知道改动了哪些,这样当你需要进行新版本更新时,按照之前记录的文档可以有个大致的迁移方案,而业务代码则可以直接拷贝过去。 2. 我们尽量在提交代码时标明每次提交改动的变更记录说明,这样你可以选择性的更新部分新代码到项目中,也就是局部更新。这种方案也是作者在公司内部项目经常使用的,因为大部分项目是无需全局更新到新版的,只需将必要的一些新特性或 bug 修复同步到原有项目中即可。 3. 使用文件比较工具,例如 **Beyond Compare**,这款工具可以直接对比文件夹,可以清晰的列出文件夹内所有文件的差异,可以协助升级工作开展。 当然个人建议是,做为一个中后台系统框架,稳定是第一诉求,不到万不得已不建议频繁更新,因为更新的成本挺高的,每一次大更新,都需要一次完整的回归测试,以确保功能正常运行。 --- --- url: /guide/check-updates.md --- # 检查更新 ## 使用 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { app: { /** * 是否开启检查更新 * @默认值 `false` */ enableCheckUpdates: true }, } ``` 效果如下: ![](/check-updates.png){data-zoomable} ## 自定义检查更新 框架默认采用轮询请求 `index.html`,并获取响应头中的 `etag` 或 `last-modified` 作为版本标识的方法来判断页面是否有更新。 你也可以修改 `/src/ui/components/FaCheckUpdates/index.vue` 文件中的 `getVersionTag` 方法,实现自定义检查更新。 --- --- url: /guide/copyright.md --- # 版权信息 版权信息位于页面底部显示。 ![](/copyright.png){data-zoomable} ## 使用 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { copyright: { /** * 是否开启底部版权,同时在路由 meta 对象里可以单独设置某个路由是否显示底部版权信息 * @默认值 `false` */ enable: true, }, } ``` 路由配置中的 `meta.copyright` 优先级会比应用配置更高,意味着你可以在某些页面中单独控制版权信息的显示或隐藏。 ## 网站运行日期 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { copyright: { /** * 网站运行日期 * @默认值 `''` */ dates: '2020-2022', }, } ``` ## 公司名称 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { copyright: { /** * 公司名称 * @默认值 `''` */ company: 'Fantastic-admin', }, } ``` ## 网站地址 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { copyright: { /** * 网站地址 * @默认值 `''` */ website: 'https://fantastic-admin.hurui.me', }, } ``` 如果未设置公司名称,则该设置将被忽略。 ## 备案号 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { copyright: { /** * 网站备案号 * @默认值 `''` */ beian: '', }, } ``` --- --- url: /guide/preferences.md --- # 用户偏好设置 如果希望将框架的部分应用配置项暴露给用户,让用户可以自行设置,那么可以使用用户偏好设置功能。 ## 开启 在应用配置中设置: ```ts {2-8} const globalSettings: Settings.all = { userPreferences: { /** * 是否开启用户偏好设置 * @默认值 `false` */ enable: true, }, } ``` ![](/preferences.gif){data-zoomable} ## 定制偏好设置内容 然后打开 `/src/store/modules/user.ts` 文件,你可以在文件里进一步定制用户偏好设置里的内容: ```ts // 框架已将可提供给用户配置的选项提取出来,请勿新增其他选项,不需要的选项可以在这里注释掉 const preferences = ref({ app: { colorScheme: settingsDefault.app.colorScheme, theme: settingsDefault.app.theme, enableProgress: settingsDefault.app.enableProgress, }, ... }) ``` 如果仔细对比,会发现这里的配置项并不是框架的完整应用配置,这是因为有部分配置项并不适合暴露给用户。比如 `userPreferences.enable` 这个配置项就是用来控制是否开启用户偏好设置的,如果开启了用户偏好设置,那么这个配置项就不应该再暴露给用户了,否则用户就可以关闭用户偏好设置了,这样就没有意义了。再比如 `app.routeBaseOn` 这个配置项是用来控制路由数据来源的,修改它会直接影响代码的调整,所以也是不能暴露给用户的。 所以请勿新增这里的配置项,你需要做的就是将不需要暴露给用户的配置项注释掉即可。 ## 处理请求 用户偏好设置默认存储在浏览器本地 localStorage 里,如果需要将数据存储到服务器,可以通过 `userPreferences.storageTo` 配置项来实现,具体配置如下: ```ts {2-9} const globalSettings: Settings.all = { userPreferences: { /** * 存储位置 * @默认值 `'local'` 本地存储 * @可选值 `'server'` 服务器存储 */ storageTo: 'server', }, } ``` 然后到 `/src/api/modules/user.ts` 中找到 `preferences()` 和 `preferencesEdit()` 这两个函数,并分别修改这两个函数的请求地址。 :::tip 建议 为减轻后端处理,数据会直接以 JSON 字符串进行存储,建议后端可以在用户表增加相关字段,并将字段类型设为 `longtext` 。 ::: --- --- url: /guide/login.md --- # 登录相关 登录相关功能包括登录、注册、忘记密码等,所有的表单组件均存放在 `/src/components/AccountForm` 目录下。 ## 登录 开发者通常在简单熟悉本框架后,涉及到的第一步业务开发就是修改登录功能,将其替换为自己的登录接口。 但在实践过程中,经常会遇到一些问题,比如: * 替换真实接口后,无法正常登录 * 登录接口请求成功,但是无法跳转到后台主页 * ... 针对这些问题你需要依次检查以下几点: 1. 在 `.env.development` 里检查接口请求地址是否正确。 2. 在 `/src/api/index.ts` 里修改响应拦截器里的代码,按照实际情况进行调整。例如什么状态下是请求成功,什么状态下是请求异常,并进行错误提示。 3. 在 `/src/api/modules/user.ts` 里修改 `login` 函数,确保接口可以请求成功。 4. 在 `/src/store/modules/user.ts` 里修改 `isLogin` 计算属性,这部分需要根据实际存储的用户信息去判断是否登录。 ## 注册、忘记密码 如果不需要注册、忘记密码功能,可以在 `/src/views/login.vue` 中删除相关组件使用的代码。 ## 登录过期弹窗 默认情况下,登录过期后会直接跳转到登录页,但框架也支持弹出重新登录的弹窗,需要在应用配置中设置: ```ts {2-9} const globalSettings: Settings.all = { app: { /** * 登录过期模式 * @默认值 `'redirect'` 跳转到登录页 * @可选值 `'popup'` 弹出登录窗口 */ loginExpiredMode: 'popup', }, } ``` ![](/login-expired.png){data-zoomable} 需注意,重新登录表单需要开发者自行接入后端接口。 --- --- url: /guide/storage.md --- # 私有 Storage 数据 由于 localStorage 和 sessionStorage 的同源策略,同一域名下的 storage 数据会共享。如果你恰好需要在同一域名下部署两套(及以上)系统,不可避免会出现 storage 数据冲突,框架提供了一个 storage 类来解决这个问题。 解决同源 storage 数据冲突的方式就是增加前缀区分,首先需要在应用配置中设置一个唯一且不重名的前缀: ```ts {2-8} const globalSettings: Settings.all = { app: { /** * localStorage/sessionStorage 前缀 * @默认值 `'fa_'` */ storagePrefix: 'fa_', }, } ``` 然后在需要使用到 storage 的地方引入: ```ts import storage from '@/utils/storage' ``` 这个类封装了 `setItem()` ,`getItem()` ,`removeItem()` ,`clear()` 方法,同时还增加了一个 `has()` 方法用来判断对象是否存在: ```ts // localStorage storage.local.has(key) storage.local.get(key) storage.local.set(key, value) storage.local.remove(key) storage.local.clear() // sessionStorage storage.session.has(key) storage.session.get(key) storage.session.set(key, value) storage.session.remove(key) storage.session.clear() ``` :::warning 注意 由于 localStorage 有容量上限,一般为 5M ,如果一同域名下部署两套系统,意味着两套系统共享 5M 容量,所以不建议在同一域名部署太多套系统,避免出现 localStorage 不够用的情况。 ::: --- --- url: /guide/font.md --- # 自定义字体 用户访问使用了自定义字体的页面时,会自动下载字体文件,字体文件有大有小,所以不建议在非英文环境中使用。 框架预设了 Digital 7 的两套字体,除此之外,你也可以通过以下方法引入你需要的自定义字体。 ## 找字体 访问 [DaFont](https://www.dafont.com/) 或其它字体下载网站,下载 `.ttf` 格式的字体文件。 ![](/font1.png){data-zoomable} ## 生成字体 因为 `.ttf` 格式的字体文件不是浏览器支持的字体格式,所以需要通过 `.ttf` 生成其它格式的字体文件。 访问 [Font Squirrel](https://www.fontsquirrel.com/tools/webfont-generator),上传 `.ttf` 文件,并按照下面设置后,点击下载。 ![](/font2.png){data-zoomable} ## 使用 将上一步下载的压缩包解压并放入 `/src/assets/fonts/` 目录下,注意按文件夹区分,随后引入文件夹中的 `stylesheet.css` 即可使用,以 Digital 7 字体为例: ```scss @import '../../assets/fonts/digital-7/stylesheet.css'; .digital-7 { font-family: 'digital-7regular'; } ``` 字体的 `font-family` 名称在 `stylesheet.css` 里查看。 另外你也可以将 `@import '../../assets/fonts/digital-7/stylesheet.css';` 这句代码放到全局引入,这样所有页面就都可以通过设置 `font-family: 'digital-7regular';` 直接使用了。 --- --- url: /buy-history-version.md --- # 购买历史专业版 :::: tabs ::: tab v2 专业版 ### 价格 199 元 (本价格不参与任何限时优惠活动) ### 演示 ![](public/v2-pro.png){data-zoomable} 399 元 (本价格不参与任何限时优惠活动) ### 演示 ![](public/v3-pro.png){data-zoomable} 599 元 (本价格不参与任何限时优惠活动) ### 演示 ![](public/v4-pro.png){data-zoomable} ## 购买流程 1. 请先加作者微信进行在线咨询。 2) 通过**微信**转账支付。 3) 作者将直接通过微信发送专业版源码,包含框架源码和演示源码,共 2 份压缩包文件。 ## Q\&A 1. 历史版本是什么意思? > 本框架经过多年的迭代,目前最新主版本为 v5,在 v5 之前的均为历史版本。历史版本均已停止更新维护,仅提供源码购买。 2. 什么人适合购买? > * 担心永久专业版可能不适合自己,使用最小成本体验下专业版。 > * 不需要实时获取最新版本的用户。 3. 是否提供技术支持? > 仅提供开发文档支持,使用过程中若遇到问题,需自行解决。 4. 是否支持补差价升级到永久专业版? > 支持,任何时候都可以补差价升级到永久专业版。 5. 是否支持开发票? > 不支持。 --- --- url: /buy.md --- # 购买永久专业版 :::tip 什么是永久专业版 顾名思义,永久专业版是指本框架后续发布的新版本,无需再次购买即可获得最新专业版源码。 ::: ## 购买 1. 请先加作者微信进行在线咨询。 2) 通过**微信**或**支付宝**扫码支付,并在备注里留下**手机/微信/QQ/邮箱**等任意一种联系方式。 3) 支付成功后需提供: * **付款截图凭证** * **授权邮箱号(常用邮箱)**。专业版客户的唯一凭证,用于接收框架相关通知公告的唯一方式,但通常情况下我们不会随意打扰你。 * **Github 用户名**。专业版源码托管在 Github 平台,需提供你的 Github 用户名,我们会邀请你加入组织。 4) 同意邀请后,进入[专业版开发者私有组织](https://github.com/fantastic-admin),获取源码。 ## 优惠合集(仅限个人购买) :::details 超值优惠合集①:Fantastic-admin + One-step-admin 原价:¥1199.00 Fantastic-admin + ¥999.00 [One-step-admin](https://one-step-admin.hurui.me) = ¥2198.00 合集优惠价:¥1299.00 (本价格不参与任何限时优惠活动) 请加作者微信进行购买 ::: :::details 超值优惠合集②:Fantastic-admin + Fantastic-mobile 原价:¥1199.00 Fantastic-admin + ¥599.00 [Fantastic-mobile](https://fantastic-mobile.hurui.me) = ¥1798.00 合集优惠价:¥1099.00 (本价格不参与任何限时优惠活动) 请加作者微信进行购买 ::: :::details 超值优惠合集③:Fantastic-admin + One-step-admin + Fantastic-mobile 原价:¥1199.00 Fantastic-admin + ¥999.00 [One-step-admin](https://one-step-admin.hurui.me) + ¥599.00 [Fantastic-mobile](https://fantastic-mobile.hurui.me) = ¥2797.00 合集优惠价:¥1499.00 (本价格不参与任何限时优惠活动) 请加作者微信进行购买 ::: ## 部分客户评价 ## 基础版与专业版区别 ## 专业版个人与企业团队区别 ## 使用说明 * 购买者可将本产品用于任意「**符合国家法律法规**」的应用平台,禁止用于黄赌毒等危害国家安全与稳定的网站。 * 本产品购买后可用于开发商业项目,不限制域名和项目数量。 * 购买者需保证不传播产品源码,不得直接对本产品(或简单包装成同类产品)进行二次转售或发布。无论有意或无意,我们有权利收回产品授权及更新权限。 * 本产品的源码(包含全部源码,及部分源码片段),在未经我们许可下,不可以用于任何形式的开源项目,否则我们有权利收回产品授权及更新权限。 * 因使用本产品所产生的损害及风险,包括但不限于个人损害、商业赢利丧失、贸易中断、商业信息丢失或任何其它经济损失,需由购买者自行承担,我们不承担任何责任。 * 虚拟物品不支持退货退款。 * 最终解释权归 Fantastic-admin 所有。 ## 什么场景需要 Fantastic-admin * **没有前端开发人员的小型公司。** 据了解,有些小型公司没有前端开发人员,而这些公司在开发中后台系统的时候,直接要求后端开发人员来进行开发工作。所以借助 Vue 的易学习易上手特性,再加上本框架的加持,可以让后端开发人员能在短时间内转型成为全栈开发。 * **前端开发人员不足的中小型公司。** 根据招聘网站统计,几乎所有公司都缺前端,其中有很大一部分中小型公司标配只有1-2名前端开发人员,而这些公司在开发中后台系统的时候,如果能有一套现成的中后台框架系统,不仅能提高项目开发效率,同时还大大减轻前端开发人员工作压力。 * **项目型公司。** 特点为项目多,周期短,甲方对页面布局和主题风格有绝对话语权,而通过专业版提供的布局和主题风格,可应对绝大部分甲方需求,并且可自定义扩展主题风格的样式,实现高度定制化。 * **产品型公司。** 产品型公司最担心的就是产品开发中代码不可控的因素,本框架除了提供完善的开发文档和代码注释外,作者还提供一对一的技术支持,确保开发人员尽可能理解整套框架源码的方方面面,为产品保驾护航。 * **个人开发者。** 手里有一套可高度定制化的中后台框架,什么项目都不用担心啦~ ## 为什么选择 Fantastic-admin * **作者拥有10年+的前后端开发经验。** 部分框架的作者由于缺少后端开发经验,可能会在设计框架的时候,很少或者没有考虑后端的实现逻辑,导致框架在实际使用中,业务场景无法落地,开发人员得通过修改源码自行实现业务。 * **经历过数十个真实项目的打磨。** 没用在真实业务场景中使用过的框架都是纸飞机,哪怕它提供的演示功能特别华丽。而本框架在作者就职的公司,已经稳定应用在电商、直播、OA、CRM、ERP等多个不同领域的中后台系统中。 * **丰富的组件库。** 除了支持 Element Plus 自带的组件外,框架还扩充了部分业务组件,以及第三方插件。借助以往的项目经验,提供最佳实践方案,方便开发人员直接使用。 * **持续更新的业务应用静态页面。** 通过项目积累,沉淀出数十个业务应用的静态页面,做到开发人员拿来即可使用,极大提升开发效率的同时,还省去了产品和设计人员的工作。 * **长期维护。** 无论是免费的基础版,还是付费的专业版,均提供长期维护。区别在于基础版侧重于稳定性维护,主要在修复 bug ,不定期增加新特性;专业版侧重于新特性开发,在确保稳定的基础上,会长期深挖中后台系统框架,持续产出可落地的特性或开发规范。 ## 反哺开源社区计划 Fantastic-admin 在探索商业化的道路上,离不开开源项目的支持,所以我们将会不定期拿出 10~20% 的收入赞助给开源项目或作者。这意味着购买专业版的你,也在以另一种方式参与建设开源社区,让开源社区变得更美好。 历史赞助记录: | 赞助时间 | 赞助项目/作者 | 赞助金额(¥) | | ---------- | :-------------------------------------------------: | -----------: | | 2022/05/08 | [Element Plus](https://element-plus.org/zh-CN/) | 4000.00 | | 2022/07/06 | [Element Plus](https://element-plus.org/zh-CN/) | 4000.00 | | 2022/08/08 | [Element Plus](https://element-plus.org/zh-CN/) | 4000.00 | | 2024/01/09 | [condorheroblog](https://github.com/condorheroblog) | 100.00 | | 2024/01/12 | [antfu](https://github.com/antfu) | 1024.00 | | 2024/01/12 | [sxzz](https://github.com/sxzz) | 256.00 | | 2024/02/04 | [Vue.js](https://cn.vuejs.org/) | 15000.00 | | 2024/05/06 | [Element Plus](https://element-plus.org/zh-CN/) | 2000.00 | | 2024/07/17 | [Vxe Table](https://vxetable.cn/) | 800.00 | | 2024/10/18 | [Element Plus](https://element-plus.org/zh-CN/) | 2000.00 | | 2025/02/28 | [hyoban](https://github.com/hyoban) | 60.00 | | 2025/03/19 | [Element Plus](https://element-plus.org/zh-CN/) | 10000.00 | --- --- url: /guide/resources.md --- # 资源 ## 图片 ### 全局公共 全局公共图片存放在 `/src/assets/images/` 目录下,可自行新建文件夹分类管理。 ### 局部私有 局部私有图片建议采用就近原则,你可以在需要的模块文件夹下建立一个 `images` 文件夹,专门用于存放局部私有图片。 ## 样式 ### 全局公共 全局公共样式存放在 `/src/assets/styles/` 目录下,可自行新建文件,并在 `/src/main.ts` 中引入即可。 此目录下还有一个特殊目录,即 `/src/assets/styles/resources/` ,这是全局 SCSS 资源目录,你可以在该目录下编写变量、函数、混合等支持 SCSS 特性的代码。 ### 局部私有 基于单文件组件规范,局部私有样式建议直接在 `.vue` 文件中编写,框架集成了 UnoCSS / PostCSS / SCSS 方案,可选择自己适合的方案。更多单文件组件 CSS 功能请参考[这里](https://cn.vuejs.org/api/sfc-css-features)。 #### UnoCSS ```vue ``` #### PostCSS 框架内置了 [postcss-nested](https://github.com/postcss/postcss-nested) 插件,可实现接近于 SCSS 的写法和特性。 ```vue ``` #### SCSS ```vue ``` ## 组件 ### 全局公共 ::: tip 说明 全局公共组件在使用时,无需手动引入,框架会在你使用时自动引入,该特性由 [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components) 提供支持。 ::: 全局公共组件存放在 `/src/components/` 目录下,每个组件按文件夹进行区分。 每个组件的文件夹内至少保留一个文件名为 `index.vue` 的组件入口,文件夹名称即为组件名。 推荐使用 `pnpm new` 指令进行组件生成,详细可查看《[代码文件自动生成](plop)》。 ### 局部私有 局部私有组件建议采用就近原则,你可以在需要的模块文件夹下建立一个 `components` 文件夹,专门用于存放局部私有组件。 --- --- url: /guide/router.md --- # 路由(导航) 默认配置下,导航菜单通过路由数据自动生成。 项目路由存放在 `/src/router/modules/` 目录下,每一个 ts 文件会被视为一个路由模块。所有路由模块最终会在 `/src/router/routes.ts` 文件里引入并放到不同的主导航下。 ## 基本配置 ### 二级路由 一个最常见的路由模块可参考以下结构: ```ts import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/example', component: () => import('@/layouts/index.vue'), redirect: '/example/index', name: 'Example', meta: { title: '演示', }, children: [ { path: 'index', name: 'ExampleIndex', component: () => import('@/views/example/index.vue'), meta: { title: '演示页面', }, }, ], } export default routes ``` :::warning 注意 * 所有路由的 `name` 请确保唯一,不能重复 * 一级路由的 `component` 需设置为 `() => import('@/layouts/index.vue')` ,并且 path 前面需要加 `/`,其余子路由都不要以 `/` 开头 ::: ### 多级路由 :::tip 说明 多级路由的中间层级,无需设置 `component` ,其原因可阅读《[关于 KeepAlive 多级路由缓存问题的终极解决方案](https://juejin.cn/post/7471722655933579290)》。 ::: ```ts import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/example', component: () => import('@/layouts/index.vue'), redirect: '/example/level/index', name: 'Example', meta: { title: '演示', }, children: [ { path: 'level', name: 'ExampleLevel', // 无需设置 componment meta: { title: '中间层级', }, children: [ { path: 'index', name: 'ExampleLevelIndex', component: () => import('@/views/example/index.vue'), meta: { title: '演示页面', }, }, ], }, ], } export default routes ``` ### 主导航 主导航并非路由的一部分,它只是将路由模块进行归类,这么做的目的是方便调整单个路由模块的展示位置,并且不会影响路由路径。 在 `/src/router/routes.ts` 里进行设置: ```ts const asyncRoutes: Route.recordMainRaw[] = [ { meta: { title: '演示', icon: 'menu-default', }, children: [ MultilevelMenuExample, BreadcrumbExample, KeepAliveExample, ], }, { meta: { title: '其它', icon: 'menu-other', }, children: [ ComponentExample, PermissionExample, ], }, ] ``` 主导航只需设置 `meta` 和 `children` 两个参数,其中 `meta` 接受 `title`、`icon`、`activeIcon`、`badge`、`badgeVariant`、`auth`、`sort` 这些参数,`children` 则是存放不同的路由模块。 ## 导航配置 框架的核心是通过路由数据生成导航菜单,所以除了路由的基本配置外,框架还提供了针对导航的自定义配置,这些配置都存放在 `meta` 对象里。 ### title * 类型:`string` * 默认值:`undefined` * 说明:导航、标签页、面包屑导航以及页面中展示的标题 专业版支持设置 i18n 对应的 key 值,详细可阅读《[国际化](i18n)》。 ### icon * 类型:`string` * 默认值:`undefined` * 说明:导航中显示的图标 该项配置最终会通过 `` 组件进行展示,意味着你可以使用自定义图标,也可使用 Iconify 提供的图标,详细可阅读《[图标](./icon)》。 ### activeIcon * 类型:`string` * 默认值:`undefined` * 说明:导航激活时显示的图标 该项配置最终会通过 `` 组件进行展示,意味着你可以使用自定义图标,也可使用 Iconify 提供的图标,详细可阅读《[图标](./icon)》。 ### defaultOpened * 类型:`boolean` * 默认值:`false` * 说明:子导航是否默认展开 该特性仅在 `顶部模式` / `侧边栏模式(含主导航)` / `侧边栏模式(无主导航)` 下生效。 使用该特性时,建议在应用配置中关闭 `menu.subMenuUniqueOpened` 设置。 ### alwaysOpened * 类型:`boolean` * 默认值:`false` * 说明:子导航是否始终展开 该特性仅在 `顶部模式` / `侧边栏模式(含主导航)` / `侧边栏模式(无主导航)` 下生效。 ### permanent * 类型:`boolean` * 默认值:`false` * 说明:是否常驻标签页 使用该特性时,需要在应用配置中开启 `tabbar.enable` 设置,同时需注意,请勿在带有参数的路由上设置该特性。 ### auth * 类型:`string | string[]` * 默认值:`undefined` * 说明:该路由访问权限,支持多个权限叠加,只要满足一个,即可进入 用户在访问路由时,会判断当前路由是否具备访问权限,不具备访问权限则会显示 403 页面,详细可阅读《[权限 - 路由权限](permission#路由权限)》。 如果在某个多级路由的多个层级上均设置了 `auth` ,则框架会依次判断,必须每一层级都具备访问权限,才能访问该路由。 ```ts {13,26} import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/system', meta: { title: '系统管理', }, children: [ { path: 'department', meta: { title: '部门管理', auth: 'a', }, children: [ { path: 'job', meta: { title: '职位管理', }, children: [ { path: 'member', meta: { title: '人员管理', auth: 'b', // 只有当用户权限里同时含有 a 和 b 时,才能访问该路由 }, }, ], }, ], }, ], } export default routes ``` ### auths * 类型:`{ name: string; value: string }[]` * 默认值:`undefined` * 说明:权限池,对路由本身无实际作用,通常用于角色管理模块,展示路由(导航)可配置权限 权限池存放了该路由相关的所有权限,包括但不限于:访问权限、按钮权限、颗粒度更细的权限等。以下是一个示例: :::tip 注意 * `auths` 里需包含 `auth` 所设置的权限,否则会导致无法设置该路由的访问权限。 * `auths` 的存放位置并不固定,可以放在任意一级路由上,但通常建议放在某个模块的入口路由上,表示该模块下所有子路由具备的可配置权限。 ::: ```ts {8-15} import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/news', component: () => import('@/layouts/index.vue'), meta: { title: '新闻管理', auths: [ { name: '浏览', value: 'browse' }, { name: '新增', value: 'add' }, { name: '编辑', value: 'edit' }, { name: '删除', value: 'delete' }, { name: '导出', value: 'export' }, { name: '导入', value: 'import' }, ], }, children: [ { path: 'list', component: () => import('@/views/news/list.vue'), meta: { title: '新闻列表', auth: 'browse', }, }, { path: 'detail', component: () => import('@/views/news/detail.vue'), meta: { title: '新闻详情', menu: false, activeMenu: '/news/list', auth: 'browse', }, }, ], } export default routes ``` 该配置的具体应用可参考专业版演示站[示例](https://fantastic-admin.hurui.me/pro-example/#/pages_example/general/role)及[源码](https://github.com/fantastic-admin/pro/tree/example/src/views/pages_example/role)。 ### menu * 类型:`boolean` * 默认值:`true` * 说明:是否在导航中展示 当子导航里没有可展示的导航时,会直接显示父导航,例如: ```ts {15} import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/permission', component: () => import('@/layouts/index.vue'), meta: { title: '权限验证', }, children: [ { path: '', component: () => import('@/views/permission.vue'), meta: { title: '权限验证', menu: false, }, }, ], } export default routes ``` ![](/route-meta-menu.png){data-zoomable} ### activeMenu * 类型:`string` * 默认值:`undefined` * 说明:指定高亮的导航,需要设置完整路由地址 该配置与 `meta.menu: false` 一起使用,因为子导航不显示,会导致进入该导航路由后,导航高亮效果失效,所以需要手动指定。 ```ts {22-23} import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/news', component: () => import('@/layouts/index.vue'), meta: { title: '新闻管理', }, children: [ { path: 'list', component: () => import('@/views/news/list.vue'), meta: { title: '新闻列表', }, }, { path: 'detail', component: () => import('@/views/news/detail.vue'), meta: { title: '新闻详情', menu: false, activeMenu: '/news/list', }, }, ], } export default routes ``` ### singleMenu * 类型:`boolean` * 默认值:`false` * 说明:是否为单个一级导航 该配置用于简化只想展示一级,没有二级导航的路由配置。 需注意,该配置只能在一级路由上设置,且只在一级路由上生效。 ```ts {9} import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/test', name: 'test', component: () => import('@/views/test/index.vue'), meta: { title: '测试页面', singleMenu: true, }, } export default routes ``` 以上路由配置等同于以下配置: ```ts import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw = { path: '/test', component: () => import('@/layouts/index.vue'), meta: { title: '测试页面', }, children: [ { path: '', name: 'test', component: () => import('@/views/test/index.vue'), meta: { title: '测试页面', menu: false, breadcrumb: false, }, }, ], } export default routes ``` ### breadcrumb * 类型:`boolean` * 默认值:`true` * 说明:是否在面包屑导航中展示 ### cache * 类型:`boolean | string | string[]` * 默认值:`undefined` * 说明:是否对该页面进行缓存 设置不同的类型值,可满足不同场景的缓存需求: * `boolean` 设置为 true 时,该路由页面会被一直缓存 * `string` 设置某个目标路由的 name ,表示当前路由页面跳转到设置的 name 对应的路由页面时,则将当前路由页面进行缓存,否则不缓存 * `string[]` ,可设置一个目标路由的 name 数组 当类型为 `string` 或 `string[]` 时,可以更精细的去控制页面缓存的逻辑。例如从列表页进入详情页,则需要将列表页进行缓存;而从列表页进入其它页面,则无需将列表页进行缓存。详细可阅读《[页面缓存](keep-alive)》。 ### noCache * 类型:`string | string[]` * 默认值:`undefined` * 说明:是否对该页面清除缓存,须设置 cache 才会生效 设置不同的类型值,可满足不同场景的缓存需求: * `string` 设置某个目标路由的 name ,表示当前路由页面跳转到设置的 name 对应的路由页面时,则将当前路由页面清除缓存,否则不清除缓存 * `string[]` ,可设置一个目标路由的 name 数组 该属性通常在启用标签栏合并时会使用到。详细可阅读《[页面缓存 - 标签栏开启且合并](keep-alive#标签栏开启且合并)》。 ### badge * 类型:`boolean | string | number | (() => boolean | string | number)` * 默认值:`false` * 说明:导航徽章 设置不同的类型值,展示效果也会不同: * `boolean` 展示形式为点,当值为 false 时隐藏 * `number` 展示形式为文本,当值小于等于 0 时隐藏 * `string` 展示形式为文本,当值为空时隐藏 如果标记需要动态更新,请设置为箭头函数形式,并返回外部变量,例如搭配 pinia 一起使用。 ```ts badge: () => globalStore.number ``` ### badgeVariant * 类型:`'default' | 'secondary' | 'destructive' | (() => 'default' | 'secondary' | 'destructive')` * 默认值:`'default'` * 说明:导航徽章颜色 如果标记需要动态更新,请设置为箭头函数形式,并返回外部变量,例如搭配 pinia 一起使用。 ```ts badgeVariant: () => globalStore.status ``` ### query * 类型:`Record` * 默认值:`{}` * 说明:点击导航时进行路由跳转时,携带的参数 ### maximize * 类型:`boolean` * 默认值:`false` * 说明:是否最大化 访问该导航的路由时,是否最大化业务页面组件展示区。 ### exitMaximize * 类型:`boolean` * 默认值:`false` * 说明:是否退出最大化 离开该导航的路由时,是否退出最大化业务页面组件展示区。 ### newWindow * 类型:`boolean` * 默认值:`false` * 说明:是否在新窗口打开 该设置仅在菜单导航里点击生效。 ### iframe * 类型:`string | boolean` * 默认值:`false` * 说明:内嵌网页链接,会启用一个 `