更新日期: 2025-10-23
适配版本: 5.0 以上单体和微服务版本
| 配置项 | 值 | 描述 |
|---|---|---|
| VITE_IS_MICRO | true |
是否是微服务架构(重要),因为单体和微服务版本共用一套前端 |
| VITE_GLOBAL_TITLE | 'PIGX ADMIN' |
网站主标题(修改需要清空 localstore) |
| VITE_FOOTER_TITLE | '©2024 pig4cloud.com' |
网站页脚信息(修改需要清空 localstore) |
| VITE_PUBLIC_PATH | / |
前端访问前缀 |
| VITE_API_URL | /api |
后端请求前缀 |
| VITE_ADMIN_PROXY_PATH | http://localhost:9999 |
ADMIN 服务地址 |
| VITE_PWD_ENC_KEY | 'pigxpigxpigxpigx' |
前端加密密钥(16 位) |
| VITE_OAUTH2_PASSWORD_CLIENT | 'pig:pig' |
OAUTH2 密码模式客户端信息 |
| VITE_OAUTH2_MOBILE_CLIENT | 'app:app' |
OAUTH2 短信客户端信息 |
| VITE_OAUTH2_SOCIAL_CLIENT | 'social:social' |
OAUTH2 社交登录客户端信息 |
| VITE_VERIFY_ENABLE | true |
是否开启前端滑块验证码 |
| VITE_VERIFY_IMAGE_ENABLE | false |
是否开启前端图形验证码 |
| VITE_WEBSOCKET_ENABLE | false |
是否开启 WebSocket 消息接收 |
| VITE_REGISTER_ENABLE | true |
是否开启注册 |
| VITE_AUTO_TENANT | false |
是否开启租户自动选择(根据租户域名) |
| VITE_I18N_ENABLE | true |
登录页是否开启多语言切换 |
| VITE_DARK_MODE_ENABLE | true |
登录页是否开启暗黑模式切换 |
| VITE_ENABLE_ANTI_DEBUG | false |
是否启用禁用浏览器调试功能(反爬) |
| VITE_ANTI_DEBUG_KEY | pig |
绕过反爬参数值(URL 中 ?ddtk=参数值) |
| VITE_GRAY_VERSION | 无 | 对应灰度路由的 header Version |
| VITE_API_ENC_ENABLED | false |
是否开启请求加解密 |
| VITE_TENANT_ENABLE | true |
是否开启租户功能(v5.9) |
配置文件: src/stores/themeConfig.ts
⚠️ 注意:
- 需要每次都清理
window.localStorage浏览器永久缓存- 或者点击布局配置最底部
一键恢复默认按钮即可看到效果
| 配置项 | 默认值 | 描述 |
|---|---|---|
isDrawer |
false |
是否开启布局配置抽屉 |
primary |
#2E5CF6 |
全局主题默认 primary 主题颜色 |
isDark |
false |
是否开启深色模式 |
| 配置项 | 默认值 | 描述 |
|---|---|---|
topBar |
#ffffff |
默认顶栏导航背景颜色 |
topBarColor |
#606266 |
默认顶栏导航字体颜色 |
isTopBarColorGradual |
false |
是否开启顶栏背景颜色渐变 |
| 配置项 | 默认值 | 描述 |
|---|---|---|
menuBar |
#FFFFFF |
默认菜单导航背景颜色 |
menuBarColor |
#505968 |
默认菜单导航字体颜色 |
menuBarActiveColor |
rgba(242...) |
默认菜单高亮背景色 |
isMenuBarColorGradual |
false |
是否开启菜单背景颜色渐变 |
| 配置项 | 默认值 | 描述 |
|---|---|---|
isCollapse |
false |
是否开启菜单水平折叠效果 |
isUniqueOpened |
true |
是否开启菜单手风琴效果 |
isFixedHeader |
false |
是否开启固定 Header |
isClassicSplitMenu |
false |
是否开启经典布局分割菜单 |
isLockScreen |
false |
是否开启自动锁屏 |
lockScreenTime |
30 |
开启自动锁屏倒计时(s/秒) |
| 配置项 | 默认值 | 描述 |
|---|---|---|
isShowLogo |
true |
是否开启侧边栏 Logo |
isBreadcrumb |
true |
是否开启 Breadcrumb |
isTagsview |
true |
是否开启 Tagsview |
isBreadcrumbIcon |
false |
是否开启 Breadcrumb 图标 |
isTagsviewIcon |
false |
是否开启 Tagsview 图标 |
isCacheTagsView |
true |
是否开启 TagsView 缓存 |
isSortableTagsView |
true |
是否开启 TagsView 拖拽 |
isShareTagsView |
false |
是否开启 TagsView 共用 |
isFooter |
true |
是否开启 Footer 底部版权信息 |
isGrayscale |
false |
是否开启灰色模式 |
isInvert |
false |
是否开启色弱模式 |
isWartermark |
true |
是否开启水印 |
wartermarkText |
PigX |
水印文案 |
| 配置项 | 默认值 | 描述 |
|---|---|---|
tagsStyle |
tags-style-five |
Tagsview 风格 |
animation |
slide-right |
主页面切换动画 |
columnsAsideStyle |
columns-round |
分栏高亮风格 |
columnsAsideLayout |
columns-vertical |
分栏布局风格 |
layout |
defaults |
布局设置 |
isRequestRoutes |
true |
后端控制路由是否开启 |
├── src/ # 源代码目录
│ ├── api/ # API 接口定义
│ ├── assets/ # 静态资源
│ ├── components/ # 公共组件
│ ├── directive/ # Vue 自定义指令
│ ├── hooks/ # Vue Composition API hooks
│ ├── i18n/ # 国际化相关
│ ├── layout/ # 布局组件
│ ├── locales/ # 语言包
│ ├── router/ # Vue Router 配置
│ ├── stores/ # Pinia 状态管理
│ ├── theme/ # 主题相关
│ ├── types/ # TypeScript 类型定义
│ ├── utils/ # 工具函数
│ ├── views/ # 页面组件
│ ├── App.vue # 根组件
│ └── main.ts # 应用入口文件
├── public/ # 公共静态资源
├── docker/ # Docker 相关配置
├── index.html # HTML 入口文件
├── vite.config.ts # Vite 配置
├── tsconfig.json # TypeScript 配置
├── tailwind.config.js # Tailwind CSS 配置
├── postcss.config.js # PostCSS 配置
├── package.json # 项目依赖配置
├── .env # 环境变量
├── .env.development # 开发环境变量
├── .env.development.local # 本地开发环境变量
├── .env.local # 本地环境变量
├── .eslintrc.js # ESLint 配置
└── .prettierrc.js # Prettier 配置
⚠️ 注意:清空浏览器永久缓存或者点击
布局配置 -> 一键恢复默认,前提是修改了/src/stores/themeConfig.ts配置文件内容。
框架内置 中文简体、英文
前端配置国际化
注意:页面国际化数据最好放
同级的目录中 i18n里。/@/i18n为框架内置,为了更好的升级,最好别添加到里面
后端配置国际化
与前端 i18n 配置 ts 文件格式相同,i18n 可以通过后台进行国际化管理的配置和使用。
页面上使用 .vue,$t('xxx.xxx')
<el-button>
<span>{{ $t('message.account.accountBtnText') }}</span>
</el-button>
<el-divider content-position="left">
{{ $t('message.layout.oneTitle') }}
</el-divider>
ts 上使用 .ts,i18n.global.t(xxx)
import { i18n } from '/@/i18n/index';
const webTitle = i18n.global.t(router.currentRoute.value.meta.title as any);
setup 里使用 ,t(xxx)
<script lang="ts">
import { defineComponent } from 'vue';
import { useI18n } from 'vue-i18n';
export default defineComponent({
name: 'xxx',
setup() {
const { t } = useI18n();
// 使用,xxx 为变量
t(xxx)
}
})
</script>
使用 element plus 的图标,可去 https://element-plus.org/zh-CN/component/icon.html 复制粘贴
<el-icon></el-icon> 包裹着
<el-input type="text" :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.userName" clearable autocomplete="off">
<template #prefix>
<el-icon class="el-input__icon"><ele-User /></el-icon>
</template>
</el-input>
1. 创建图标项目
FontClass/Symbol 前缀为 icon,Font Family 为 iconfont2. 设置在线链接
代码位置:/@/utils/setIconfont.ts
// `/@/utils/setIconfont.ts` cssCdnUrlList 方法中添加在线链接
// 字体图标 url (新增)
const cssCdnUrlList: Array<string> = [
'//at.alicdn.com/t/font_2298093_y6u00apwst.css',
'//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css',
];
3. 界面中使用
⚠️ 警告:
- iconfont(阿里巴巴素材库):需要添加
iconfont前缀,如:iconfont xitongshezhi- font-awesome:需要添加
fa前缀,如:fa xitongshezhi
<!-- 项目使用 -->
<i class="iconfont xitongshezhi"></i>
<!-- <i class="fa xitongshezhi"></i> -->
<!-- 或者 -->
<SvgIcon name="iconfont xitongshezhi"></SvgIcon>
<!-- <SvgIcon name="fa xitongshezhi"></SvgIcon> -->
支持下载 svg ,放在前端的 icons 目录
前端可通过 local-文件名的形式加载
<SvgIcon name="local-gitee" :size="30" />
为了提高系统的稳定性和加载速度,我们可以将原本使用的阿里巴巴在线图标库转换为本地离线使用。
1. 下载图标资源包
2. 创建本地图标目录
mkdir -p pigx-ui/public/assets/iconfont
3. 复制资源文件
将下载的资源包中的以下文件复制到 public/assets/iconfont/ 目录:
4. 修改配置文件
修改 src/utils/setIconfont.ts 文件中的图标引用路径:
const cssCdnUrlList: Array<string> = [
'/assets/iconfont/iconfont.css', // 本地图标文件
'/assets/styles/font-awesome.min.css',
];
组件位置:/@/components/auth
单个权限验证(:value="xxx")
<template>
<!-- 使用 -->
<Auth :value="'btn.add'" />
</template>
<script setup lang="ts" name="xxx">
// 局部引入
import Auth from '/@/components/auth/auth.vue';
</script>
多个权限验证,满足一个则显示(:value="[xxx,xxx]")
<template>
<!-- 使用 -->
<Auths :value="['btn.addsss', 'btn.edit', 'btn.delsss', 'btn.linksss']" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
// 局部引入
import Auths from '/@/components/auth/auths.vue';
export default defineComponent({
name: 'xxxx',
// 局部注册
components: { Auths },
});
</script>
多个权限验证,全部满足则显示(:value="[xxx,xxx]")
<template>
<!-- 使用 -->
<AuthAll :value="['btn.add', 'btn.edit', 'btn.del', 'btn.link']" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
// 局部引入
import AuthAll from '/@/components/auth/authAll.vue';
export default defineComponent({
name: 'xxxx',
// 局部注册
components: { AuthAll },
});
</script>
指令位置:/@/directive/authDirective.ts
单个权限验证(v-auth="xxx")
<div v-auth="'btn.add'">
<el-button>新增</el-button>
</div>
<div v-auth="'btn.edit'">
<el-button>编辑</el-button>
</div>
<div v-auth="'btn.del'">
<el-button>删除</el-button>
</div>
<div v-auth="'btn.link'">
<el-button>跳转</el-button>
</div>
多个权限验证,满足一个则显示(v-auths="[xxx,xxx]")
<div v-auths="['btn.addsss', 'btn.edit', 'btn.delsss', 'btn.linksss']">
<el-button>新增</el-button>
</div>
<div v-auths="['btn.add', 'btn.edit', 'btn.del', 'btn.link']">
<el-button>编辑</el-button>
</div>
多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]")
<div v-auth-all="['btn.add', 'btn.edit', 'btn.del', 'btn.link']">
<el-button>新增</el-button>
</div>
<div v-auth-all="['btn.add', 'btn.edit', 'btn.del', 'btn.link']">
<el-button>编辑</el-button>
</div>
方法位置:/@/utils/authFunction.ts,用于方法中的判断
<script lang="ts" setup>
import { ElMessage } from 'element-plus';
import { auth, auths, authAll } from '/@/utils/authFunction';
// 单个权限验证
const onAuthClick = () => {
if (!auth('btn.add')) ElMessage.error('抱歉,您没有权限!');
else ElMessage.success('恭喜,您有权限!');
};
// 多个权限验证,满足一个则为 true
const onAuthsClick = () => {
if (!auths(['btn.add', 'btn.edit'])) ElMessage.error('抱歉,您没有权限!');
else ElMessage.success('恭喜,您有权限!');
};
// 多个权限验证,全部满足则为 true
const onAuthAllClick = () => {
if (!authAll(['btn.add', 'btn.edit'])) ElMessage.error('抱歉,您没有权限!');
else ElMessage.success('恭喜,您有权限!');
};
</script>
或者在模板中使用:
<div v-if="auth('sys_file_del')">...</div>
静态路由是指直接在前端代码中配置的路由,不需要通过后端接口动态获取。这些路由在项目编译时就已确定,适用于固定不变的页面导航结构。
在 PIGX-UI 中使用静态路由的主要原因:适合配置系统级别的页面(如登录、404 等),可以独立于后端菜单权限系统(不需要鉴权等配置)
路由配置位置
src/
└── router/
└── route.ts # 路由配置文件
属性配置说明
| 配置项 | 说明 |
|---|---|
title |
菜单栏及 tagsView 栏、菜单搜索名称(国际化) |
isLink |
是否超链接菜单,开启外链条件:1. isLink: 链接地址不为空 2. isIframe: false |
isHide |
是否隐藏此路由 |
isKeepAlive |
是否缓存组件状态 |
isAuth |
是否需要认证才能进入的页面 |
isAffix |
是否固定在 tagsView 栏上 |
isIframe |
是否内嵌窗口,开启条件:1. isIframe: true 2. isLink:链接地址不为空 |
icon |
菜单、tagsView 图标,阿里:加 iconfont xxx,fontawesome:加 fa xxx |
点击页面上的按钮可以打开新的 Tagsview 标签页,同时也可以传递参数。
代码实现方式
① 菜单管理中定义隐藏菜单
⚠️ 注意为角色分配该菜单的权限。
② 点击目标按钮触发路由跳转
const click = () => {
router.push({
path: '/app/appArticle/form',
query: { tagsViewName: '动态路由测试', param1: '123' },
});
};
③ 在跳转的页面获取请求参数
const route = useRoute();
onMounted(() => {
console.log(route.query.tagsViewName);
console.log(route.query.param1);
});
在多个菜单中引用同一个路由下的组件,通过路由进行区分。
① 配置菜单(带参)
指向 /admin/test/index 组件
AAA /admin/test/1
BBB /admin/test/2
② 页面获取参数
admin/test/index.vue
const route = useRoute();
onMounted(() => {
// test/index/参数
const parts = route.path.split('/');
const lastParam = parts[parts.length - 1];
console.log(lastParam);
});
跳转函数中指定路由参数 tagsViewName。
const router = useRouter();
router.push({ path: '/xxx', query: { tagsViewName: '标签名称' } });
import { useRoute } from 'vue-router';
import mittBus from '/@/utils/mitt';
const route = useRoute();
// 刷新当前页面
const refreshPage = () => {
mittBus.emit('onCurrentContextmenuClick', {
contextMenuClickId: 0,
...route,
});
};
// 关闭当前页面
const closePage = () => {
mittBus.emit('onCurrentContextmenuClick', {
contextMenuClickId: 1,
...route,
});
};
// 关闭除当前页外的其它页面
const closeOthers = () => {
mittBus.emit('onCurrentContextmenuClick', {
contextMenuClickId: 2,
...route,
});
};
// 关闭所有页面
const closeAll = () => {
mittBus.emit('onCurrentContextmenuClick', {
contextMenuClickId: 3,
...route,
});
};
// 当前页面全屏显示
const fullscreen = () => {
mittBus.emit('onCurrentContextmenuClick', {
contextMenuClickId: 4,
...route,
});
};
操作 ID 说明
| 操作 ID | 功能说明 |
|---|---|
| 0 | 刷新当前页面 |
| 1 | 关闭当前页面 |
| 2 | 关闭其它页面 |
| 3 | 关闭全部页面 |
| 4 | 当前页全屏显示 |
框架中数据状态使用 vuex Module 模块化进行管理,您可能需要了解 vuex 核心概念 Module
代码位置:/src/stores
相关文档:pinia 官网
相关文档:vuex 3.x 官网
页面模块已做全局自动引入,代码位置:/@/store/index.ts。
const modulesFiles = import.meta.globEager("./modules/*.ts");
const pathList: string[] = [];
for (const path in modulesFiles) {
pathList.push(path);
}
const modules = pathList.reduce(
(modules: { [x: string]: any }, modulePath: string) => {
const moduleName = modulePath.replace(/^./modules/(.*).w+$/, "$1");
const value = modulesFiles[modulePath];
modules[moduleName] = value.default;
return modules;
},
{}
);
1. interface 定义
/@/store/interface/index.ts,如:路由缓存列表 KeepAliveNamesState
// 路由缓存列表
export interface KeepAliveNamesState {
keepAliveNames: Array<string>;
}
2. interface 使用
在 /@/store/modules/ 新增 keepAliveNames.ts,界面写入如下代码:
import { Module } from 'vuex';
import { KeepAliveNamesState, RootStateTypes } from '/@/store/interface/index';
const keepAliveNamesModule: Module<KeepAliveNamesState, RootStateTypes> = {
namespaced: true,
state: {
keepAliveNames: [],
},
mutations: {
// 设置路由缓存(name字段)
getCacheKeepAlive(state: any, data: Array<string>) {
state.keepAliveNames = data;
},
},
actions: {
// 设置路由缓存(name字段)
async setCacheKeepAlive({ commit }, data: Array<string>) {
commit('getCacheKeepAlive', data);
},
},
};
export default keepAliveNamesModule;
1. 在 .ts 中使用
import { store } from '/@/store/index.ts';
// dispatch
store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
// 或者 commit
// store.commit("keepAliveNames/getCacheKeepAlive", cacheList);
2. 在 .vue 中使用
<template>
<div v-if="getThemeConfig.isLockScreen">在 .vue 中使用</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { useStore } from '/@/store/index';
export default defineComponent({
name: 'app',
setup() {
const store = useStore();
// 获取布局配置信息
const getThemeConfig = computed(() => {
return store.state.themeConfig.themeConfig;
});
},
});
</script>
字典类型对应 sys_dict 表中字典数据
import {useDict} from '/@/hooks/dict';
const {字典类型A, 字典类型B} = useDict('字典类型A','字典类型B');
⚠️ 注意:element-plus 的 radio 和 select 等类型组件对 value 字段有强制的数据类型要求。实体字段应该使用字符串而不是数字类型来对应字典功能使用。
<el-table-column>
<template #default="scope">
<dict-tag :options="字典类型" :value="scope.row.xx"></dict-tag>
</template>
</el-table-column>
| 入参 | 出参 |
|---|---|
| sys_public_param 表中 publicKey 字段 | sys_public_param 表中 publicValue 字段 |
import { useParam } from '/@/hooks/param';
const param = useParam('GEN_TABLE_PREFIX');
{{ useParam('GEN_TABLE_PREFIX') }}
<button @click="copyText('文案内容')">复制</button>
const { copyText } = commonFunction();
html 代码中直接使用 parseDate parseTime 进行格式化
<el-table-column :label="t('tenant.startTime')" prop="startTime" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseDate(scope.row.startTime) }}</span>
</template>
</el-table-column>
<el-table-column :label="t('tenant.endTime')" prop="endTime" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.endTime) }}</span>
</template>
</el-table-column>
ts 中需要手动导入
import { formatDate, parseDate } from '/@/utils/formatTime';
import params from '/@/utils/params';
let result = await params.get('参数管理中的KEY');
官方对自定义 hook 定义:在 Vue 应用的概念中,"组合式函数" (Composables) 是一个利用 Vue 组合式 API 来封装和复用有状态逻辑的函数。
useTable 函数的名称就能清晰地表达其作用,它是集成了前端 element-plus 表格的一些通用函数。
| 方法名 | 描述 |
|---|---|
tableStyle |
返回包含表格样式的对象,其中包含 cellStyle 和 headerCellStyle 两个属性,分别用于设置表格单元格和表头单元格的样式 |
getDataList(refresh?: any) |
获取数据列表,并可选择是否刷新当前页码。如果需要刷新,则将 state.pagination.current 重置为 1 |
sizeChangeHandle(val: number) |
分页大小改变时触发的事件处理函数。会修改 state.pagination 中的 size 属性,并再次调用 query() 方法进行查询 |
currentChangeHandle(val: number) |
当前页码改变时触发的事件处理函数。会修改 state.pagination 中的 current 属性,并再次调用 query() 方法进行查询 |
sortChangeHandle(column: any) |
排序方式改变时触发的事件处理函数。根据 column 的内容,修改 state.descs 和 state.ascs 中的排序字段,并再次调用 query() 方法进行查询 |
downBlobFile(url: string, query: any, fileName: string) |
用于下载文件的方法。接收三个参数:文件下载地址 url、请求参数 query 和文件名 fileName。返回一个 Promise 对象,用于异步处理结果 |
// 使用 useTable 自动生成表格一些通用方法
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
如果你想通过 useTable 生成一些通用的表格方法,那么就需要向它提供一些初始值,比如查询的 URL 和分页大小等参数。
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: pageList,
});
完整的 BasicTable 定义属性如下
export interface BasicTableProps {
// 是否在创建页面时即调用数据列表接口,默认为true
createdIsNeed?: boolean;
// 是否需要分页,默认为true
isPage?: boolean;
// 查询条件表单对象,类型为any
queryForm?: any;
// 数据列表数组
dataList?: any[];
// 分页属性对象
pagination?: Pagination;
// 数据列表,loading状态标志,默认为false
dataListLoading?: boolean;
// 数据列表多选项数组
dataListSelections?: any[];
// 数据列表查询接口api方法,接收任意数量参数,返回Promise
pageList?: (...arg: any) => Promise<any>;
// loading标志,默认为false
loading?: Boolean;
// 多选结果数组
selectObjs?: any[];
// 排序字段数组
descs?: string[];
// 排序方式数组
ascs?: string[];
// props属性对象,类型为any
props?: any;
}
分页组件一般和表格组件一起使用,只需要回调 useTable hook 中的函数即可
<pagination v-bind="state.pagination" @current-change="currentChangeHandle" @size-change="sizeChangeHandle"></pagination>
const { currentChangeHandle, sizeChangeHandle } = useTable(state);
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
current |
Number |
1 |
当前页码 |
size |
Number |
10 |
每页展示的条数 |
total |
Number |
0 |
数据总数 |
pageSizes |
Array |
[1, 10, 20, 50, 100, 200] |
每页展示的条数可选项 |
layout |
String |
'total, sizes, prev, pager, next, jumper' |
分页组件的布局 |
工具栏组件一般和表格组件一起使用,只需要回调 useTable hook 中的函数即可
<right-toolbar v-model:showSearch="showSearch" :export="'sys_user_export'" @exportExcel="exportExcel" @queryTable="getDataList" />
const { getDataList } = useTable(state);
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
showSearch |
Boolean |
true |
是否显示搜索框 |
export |
String or Boolean |
当设置为true的显示,如设置为权限字符串则根据当前用户权限动态控制 |
是否导出下载按钮 |
search |
Boolean |
true |
是否显示搜索框 |
gutter |
Number |
10 |
列表项之间的间距 |
<upload-file @change="success" />
属性说明
| 属性名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
modelValue |
组件的值 | string |
Array |
limit |
数量限制 | number |
5 |
fileSize |
文件大小限制 | number |
5MB |
fileType |
文件类型限制 | Array |
['png', 'jpg', 'jpeg', 'doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'pptx'] |
isShowTip |
是否显示提示 | boolean |
true |
uploadFileUrl |
上传文件的 API 方法 | string |
'/admin/sys-file/upload' |
type |
组件类型 | string |
'default' |
data |
需要额外传递给 API 的数据 | Object |
- |
dir |
子目录名称 | String |
a/b 格式, v5.3+ |
autoUpload |
是否自动上传文件 | boolean |
true |
<upload-img v-model:imageUrl="formData.avatar" borderRadius="50%">
<template #empty>
<el-icon><Avatar /></el-icon>
<span>请上传头像</span>
</template>
</upload-img>
属性说明
| 属性名称 | 描述 | 类型 |
|---|---|---|
imageUrl |
图片地址(双向绑定,上传会更新返回此字段) | string (必传) |
uploadFileUrl |
上传图片的 API 方法 | string (非必传) |
dir |
子目录名称 | String (非必传) |
drag |
是否支持拖拽上传 | boolean (非必传,默认为 true) |
disabled |
是否禁用上传组件 | boolean (非必传,默认为 false) |
fileSize |
图片大小限制 | number (非必传,默认为 5M) |
fileType |
图片类型限制 | File.ImageMimeType[] (非必传,默认为 ["image/jpeg", "image/png", "image/gif"]) |
height |
组件高度 | string (非必传,默认为 150px) |
width |
组件宽度 | string (非必传,默认为 150px) |
borderRadius |
组件边框圆角 | string (非必传,默认为 8px) |
<upload-excel
ref="excelUploadRef"
:title="$t('sysuser.importUserTip')"
temp-url="/admin/sys-file/local/file/user.xlsx"
url="/admin/user/import"
@refreshDataList="getDataList"
/>
属性说明
| 属性名称 | 描述 | 类型 |
|---|---|---|
url |
导入文件后台接口 | String |
title |
弹出框标题 | String |
tempUrl |
获取当前导如 excel 模板地址 | String |
Wangeditor 是一款基于 Web 的所见即所得富文本编辑器,它提供了丰富的富文本编辑功能,支持插入图片、音视频等多媒体内容,并且可以通过自定义插件扩展其功能。
<editor v-model:get-html="form.content" />
| 属性名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
disable |
是否禁用编辑器 | Boolean |
false |
placeholder |
编辑器默认占位符 | String |
"请输入内容..." |
mode |
编辑器模式,可选值为 default 或 simple | String |
default |
height |
编辑器高度 | String |
"310px" |
getHtml |
双向绑定的属性,用于获取编辑器中 HTML 内容 | String |
- |
getText |
双向绑定的属性,用于获取编辑器中纯文本内容 | String |
- |
uploadFileUrl |
上传文件的接口地址 | String |
"/admin/sys-file/upload" |
const CodeEditor = defineAsyncComponent(() => import('/@/components/CodeEditor/index.vue'));
<template>
<div>
<CodeEditor v-model="code" mode="go" theme="idea" :readOnly="false" :height="300" />
</div>
</template>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue |
String |
'' |
绑定的代码内容 |
mode |
String |
'go' |
代码语言 |
theme |
String |
'idea' |
代码编辑器的主题 |
height |
[String, Number] |
300 |
代码编辑器的高度 |
options |
Object |
{} |
CodeMirror 的配置选项 |
readOnly |
Boolean |
false |
是否只读 |
Vue Echarts 是一个 Vue.js 的 ECharts 图表组件,对 EChart 进行了封装,简化了 Echart 图表的使用。
pigx-ui 默认引入了 vue-echarts ,业务代码中可以非常方便地使用相关的 EChart 图表组件【例如:日志管理】。
访问 ECharts 官网,选择目标类型的图表组件,获取图表的 option 配置 JSON。
<template>
<v-chart class="h-80 w-full" :option="option" />
</template>
<script setup lang="ts" name="demo-chart">
// 直接复制 vue-echart codegen 生成的 vue 代码部分
import { use, reactive } from 'echarts/core'
import {
BarChart
} from 'echarts/charts'
import {
GridComponent
} from 'echarts/components'
import {
CanvasRenderer
} from 'echarts/renderers'
use([
GridComponent,
BarChart,
CanvasRenderer
])
// 定义 JSON
const option = reactive(复制 EChart option JSON)
</script>
<query-tree :query="state.queryList" @node-click="handleNodeClick">
</query-tree>
const QueryTree = defineAsyncComponent(() => import('/@/components/QueryTree/index.vue'));
const state = reactive({
queryList: (name: String) => {
return api({ name: name });
},
});
const handleNodeClick = (e: any) => {};
<query-tree>
<template #default="{ node, data }">
</template>
</query-tree>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
props |
Object |
{ label: 'name', children: 'children', value: 'id' } |
树形结构的属性配置 |
placeholder |
String |
'' |
输入框的占位符 |
loading |
Boolean |
false |
是否显示加载状态 |
query |
Function |
- | 包含查询方法的函数,必须返回 Promise 类型的数据,并在组件中被调用 |
<template>
<org-selector v-model:orgList="userList" type="user" :multiple="false" />
</template>
<script setup>
import orgSelector from '/@/components/OrgSelector/index.vue';
</script>
[
{
"type": "user",
"id": "1",
"name": "admin",
"avatar": "xx.png"
}
]
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
orgList |
Array |
[] |
组织列表,用于显示可选的组织 |
type |
String |
user |
类型,可选值为 user、dept、org (部门、用户 同时可选)、role、post |
multiple |
Boolean |
true |
是否允许多选。如果为 true,则可以选择多个组织或用户;如果为 false,则只能选择一个组织或用户。默认为 true |
disabled |
Boolean |
false |
是否禁用组件。如果为 true,则组件将不可用,用户无法进行选择。默认为 false |
selectSelf |
Boolean |
true |
是否包含自身。如果为 true,则在可选项中包含当前用户自身;如果为 false,则不包含当前用户自身。默认为 true |
<tag-list buttonText="+手机号" v-model="phoneList" />
;
<script setup>
const phoneList = ref([]);
</script>
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue |
Array[String] |
[] |
双向绑定绑定的标签数组 |
buttonText |
String |
+ New Tag |
按钮显示的文本 |
tagType |
'success', 'info', 'warning', 'danger' |
- | 按钮显示类型 |
const PopoverInput = defineAsyncComponent(() => import('/@/components/PopoverInput/index.vue'));
<popover-input @confirm="onConfirm">
<template #default>
<el-button> 点击输入 </el-button>
</template>
</popover-input>
| 属性名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
value |
值 | String |
- |
type |
类型 | String |
'text' |
width |
宽度 | Number |
String |
placeholder |
提示文字 | String |
- |
disabled |
是否禁用 | Boolean |
false |
options |
选项列表 | Array<any[]> |
[] |
size |
大小 | 'default' |
'small' |
limit |
字符限制 | Number |
200 |
showLimit |
是否显示字符限制 | Boolean |
false |
teleported |
是否使用传送门(teleport)进行渲染 | Boolean |
true |
<el-form-item label="初始浏览量" prop="visit">
<template #label>
浏览量<tip content="初始值" />
</template>
</el-form-item>
| 属性名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
content |
内容 | String |
- |
placement |
放置位置 | String |
'top-start' |
const ChinaArea = defineAsyncComponent(() => import('/@/components/ChinaArea/index.vue'));
<china-area v-model="data" @change="handleChange" />
;
<script setup>
// 双向绑定数据 自动回显: 北京市/市辖区/东城区
const data = ref('11,1101,110101');
// 可选 输出: 11,1101,110101
const handleChange = (val: String) => {};
</script>
| 属性名称 | 描述 | 类型 |
|---|---|---|
v-model |
双向绑定 | String |
type |
省级 1 市 2 区 3 街道 4 | Number |
plus |
默认 false, 不用选择某级 | Boolean |
@change |
选中回调事件 | Function |
下载 👉🏻 省市街区详细 SQL,导入至 sys_area 表即可。
如果此数据(来自民政部 2023 年的数据)中不存在对应地区,您可以根据规则自行新增。请注意,编码需保持唯一。
Form 组件允许你验证用户的输入是否符合规范,来帮助你找到和纠正错误。
Form 组件提供了表单验证的功能,只需为 rules 属性传入约定的验证规则,并将 form-Item 的 prop 属性设置为需要验证的特殊键值即可。
const rule = ref({
字段名称: [
// 校验用户输入的长度避免超长 0-255个字符 超长
{ validator: rule.overLength, trigger: 'blur' },
// 根据字段自动查询后台是否重复
{
validator: (rule: any, value: any, callback: any) => {
validateExist(rule, value, callback, form.id !== '');
},
trigger: 'blur',
},
],
});
⚠️ 注意:element-plus 的 radio 和 select 等类型组件对 value 字段有强制的数据类型要求。实体字段应该使用字符串而不是数字类型来对应字典功能使用。
| 函数名称 | 函数作用 |
|---|---|
validateExist |
根据字段自动查询后台是否重复 |
overLength |
校验用户输入的长度避免超长,范围为 0-255 个字符 |
validatorNameCn |
校验用户输入是否为中文、英文、数字包括下划线 |
validatorCapital |
校验用户输入是否为大写英文、下划线 |
validatorLowercase |
校验用户输入是否为小写英文、下划线 |
validatorLower |
校验用户输入是否为小写英文 |
checkSpace |
校验输入是否包含首尾空白字符 |
validatePhone |
校验手机号的合法性 |
number |
校验输入是否为数字 |
letter |
校验输入是否为字母 |
letterAndNumber |
校验输入是否为字母和数字 |
mobilePhone |
校验输入是否为正确格式的手机号码 |
letterStartNumberIncluded |
校验输入是否以字母开头,可包含数字 |
noChinese |
校验输入是否包含中文字符 |
chinese |
校验输入是否为中文字符 |
email |
校验输入是否为正确格式的电子邮箱 |
url |
校验输入是否为正确格式的 URL |
regExp |
校验输入是否符合给定的正则表达式 |
在 src/views/home/widgets/components 目录下创建组件
在 src/views/home/widgets/index.vue 中挂载组件,将 myGrid 数组增加上一步创建的组件文件名称
const myGrid = ['test-demo'];
本文档汇总了 PIGX 前端技术框架的核心内容,包括:
更多详细信息请参考官方文档:https://pig4cloud.com
文档版本: v1.0
最后更新: 2025-10-23
维护团队: PIGX 开发团队