前端手册
前端手册
项目结构
查看项目目录
├─bat #项目启动脚本
├─dist #打包后的文件
├─html
├─public
├─src
│ ├─api #网络请求api
│ │ ├─article
│ │ ├─monitor
│ │ ├─system
│ │ │ └─dict
│ │ └─tool
│ ├─assets #资源目录
│ │ ├─401_images
│ │ ├─404_images
│ │ ├─iconfont
│ │ ├─icons
│ │ │ └─svg
│ │ ├─images
│ │ ├─logo
│ │ └─styles
│ ├─components
│ │ ├─Breadcrumb #面包絮组件
│ │ ├─Crontab #定时任务cron表达式
│ │ ├─DictTag #字典组件
│ │ ├─Echarts
│ │ ├─Editor #富文本编辑器
│ │ ├─FileUpload #文件上传组件
│ │ ├─Hamburger
│ │ ├─HeaderSearch #搜索
│ │ ├─IconSelect #图标选择
│ │ ├─iFrame #Iframe
│ │ ├─ImagePreview #图片预览
│ │ ├─ImageUpload #图片上传
│ │ ├─LangSelect #多语言选择
│ │ ├─Notice
│ │ ├─Pagination #分页组件
│ │ ├─ParentView
│ │ ├─RightToolbar
│ │ ├─Screenfull
│ │ ├─SizeSelect
│ │ ├─SvgIcon
│ │ ├─TopNav
│ │ ├─vue3-cron-core
│ │ └─Zr
│ │ ├─Doc
│ │ └─Git
│ ├─directive
│ │ ├─module
│ │ └─permission
│ ├─i18n
│ │ ├─lang
│ │ └─pages
│ │ ├─login
│ │ └─menu
│ ├─layout #系统布局
│ │ └─components
│ │ ├─IframeToggle
│ │ ├─InnerLink
│ │ ├─Settings
│ │ ├─Sidebar
│ │ └─TagsView
│ ├─plugins
│ ├─router
│ ├─store
│ │ └─modules
│ ├─utils
│ └─views
│ ├─components
│ │ ├─CommonMenu
│ │ └─icons
│ ├─dashboard
│ ├─error
│ ├─monitor
│ │ ├─cache
│ │ ├─job
│ │ ├─logininfor
│ │ ├─operlog
│ │ └─server
│ ├─redirect
│ ├─system
│ │ ├─article
│ │ ├─commonLang
│ │ ├─config
│ │ ├─dept
│ │ ├─dict
│ │ ├─menu
│ │ ├─notice
│ │ ├─oauth
│ │ ├─post
│ │ ├─role
│ │ ├─roleusers
│ │ └─user
│ │ └─profile
│ └─tool
│ ├─build
│ ├─email
│ ├─file
│ ├─gen
│ └─swagger
└─vite
└─plugins
系统配置
vue3 配置文件路径src/settings.js
,可以配置侧边栏路由是否显示 New 标记(最近 7 天内添加的菜单会显示),默认主题色等
export default {
/**
* 网页标题
*/
title: import.meta.env.VITE_APP_TITLE,
/**
* 侧边栏主题 深色主题theme-dark,浅色主题theme-light
*/
sideTheme: "theme-dark",
/**
* 框架默认主题颜色值
*/
theme: "#FF8C00",
/**
* 是否显示系统布局配置
*/
showSettings: false,
/**
* 是否显示顶部导航
*/
topNav: false,
/**
* 是否显示 tagsView
*/
tagsView: true,
/**
* 是否固定头部
*/
fixedHeader: false,
/**
* 是否显示logo
*/
sidebarLogo: true,
/**
* 是否显示动态标题
*/
dynamicTitle: false,
/**
* @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
*/
errorLog: "production",
/**
* 版权信息
*/
copyright:
'Copyright ©2024 <a target="_black" href="http://www.izhaorui.cn/doc">ZRAdmin.NET</a> All Rights Reserved.',
/**
* 是否显示底部栏
*/
showFooter: true,
/**
* 是否显示水印
*/
showWatermark: false,
/**
* 水印文案
*/
watermarkText: "ZRAdmin.NET",
/**
* 是否显示其他登录
*/
showOtherLogin: true,
/**
* 默认大小
*/
defaultSize: "default",
/**
* 默认语言
*/
defaultLang: "zh-cn",
/**
* 左侧菜单是否显示New标记
*/
menuShowNew: false,
};
通用方法
路由使用
开发规范
新增 view
在 src/views
文件下 创建对应的文件夹,一般性一个路由对应一个文件, 该模块下的功能就建议在本文件夹下创建一个新文件夹,各个功能模块维护自己的 utils 或 components 组件。
比如:src/views/Demo.vue
表示在 views 下面创建一个 Demo 的页面
新增 api
在 src/api
文件夹下创建本模块对应的 api 服务。
新增组件
在全局的 src/components 写一些全局的组件,如富文本,各种搜索组件,封装的分页组件等等能被公用的组件。 每个页面或者模块特定的业务组件则会写在当前 @/views 下面。 如:src/views/components/user/xxx.vue
。这样拆分大大减轻了维护成本。
新增样式
在 src/assets/styles
文件夹下新增自己的 ui 样式。
请求流程
TODO 完善文档
引用依赖
除了项目正常的使用包,开发中我们还会使用到其他的包比如 mavon-editor
在终端输入下面的命令完成安装:
npm install mavon-editor --save
加上 --save 参数会自动添加依赖到 package.json 中去。
内置组件使用
页面缓存(keepAlive)
由于目前 keep-alive
和 router-view
是强耦合的,而且查看文档和源码不难发现 keep-alive
的 include
默认是优先匹配组件的 name ,所以在编写路由 router 和路由对应的 view component 的时候一定要确保 两者的 name 是完全一致的。(切记 name 命名时候尽量保证唯一性 切记不要和某些组件的命名重复了,不然会递归引用最后内存溢出等问题)
提示
在系统管理 ->菜单管理 -> 编辑菜单 ->是否缓存选是 Vue 页面 name(要求小写)和路由地址(无要求)确保相同
<script setup name="index">
<script>
export default {
name: "index",
...
</script>
使用字典
字典管理是用来维护数据类型的数据,如下拉框、单选按钮、复选框、树选择的数据,方便系统管理员维护。主要功能包括:字典分类管理、字典数据管理
- 加载数据字典
export default {
data() {
return {
staticOptions: [
{ dictLabel: "字典名称A", dictValue: "字典值1", cssClass: "text-info"},
{ dictLabel: "字典名称B", dictValue: "字典值2"}
],
xxxOptions: [],
customOptions: []
.....
...
}
},
created() {
//1.从字典读取数据
this.getDicts("字典类型").then(response => {
this.xxxOptions = response.data;
});
//2.页面组件单独定义数据
//如上staticOptions,字典名称 和 字典值名称不能变,如果使用样式 添加 cssClass样式
//3.自定义数据来源
listXXX().then((res) => {
this.customOptions = this.handleDict(res.data.result, 'id', 'name')
})
//读取多个字典数据
var dictParams = [
{ dictType: "sys_oper_type", columnName: "businessTypeOptions" },
{ dictType: "sys_common_status", columnName: "statusOptions" },
];
this.getDicts(dictParams).then((response) => {
response.data.forEach((element) => {
this[element.columnName] = element.list;
});
});
}
},
<script setup name="index">
const state = reactive({
options: {
// 显示状态选项列表(动态字典将会从后台获取数据)
sys_common_status: [],
// 性别选项列表(静态字典不会从后台获取数据)
sys_user_sex: [
{ dictLabel: '是', dictValue: '1' },
{ dictLabel: '否', dictValue: '0', listClass: 'danger' }
]
}
})
const { options } = toRefs(state)
//从后台读取多个字典数据
var dictParams = [{ dictType: 'sys_common_status' }]
proxy.getDicts(dictParams).then((response) => {
response.data.forEach((element) => {
state.options[element.dictType] = element.list
})
})
</script>
提示
注意:如果使用系统自带 dict-tag
组件,dictValue
要使用 string 类型
- 读取数据字典
<el-option
v-for="dict in options.xxxOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
></el-option>
注意
如果你的业务表数据字段类型是 int
value 值要转换 :value="parseInt(dict.dictValue)"
- table 显示字典数据
// 字典标签组件回显
<el-table-column label="我是名称" prop="xxx">
<template slot-scope="scope">
<dict-tag :options="options.xxxOptions" :value="scope.row.xxx" />
</template>
</el-table-column>
//CheckBox 回显
<dict-tag
:options="options.xxxOptions"
:value="scope.row.xxx ? scope.row.xxx.split(',') : []"
></dict-tag>
自定义字典使用
将自己的业务表即使用sql数据源
作为字典数据
系统管理 → 字典管理 → 新增 → 字典类型使用"sql_" 开头字符串, sql 语句按照页面提示输入即可
使用参数
参数设置是提供开发人员、实施人员的动态系统配置参数,不需要去频繁修改后台配置文件,也无需重启服务器即可生效。
- main.js 中引入全局变量和方法(已存在)
import { getConfigKey } from "@/api/system/config";
Vue.prototype.getConfigKey = getConfigKey;
- 页面使用参数
this.getConfigKey("参数键值名").then((response) => {
//response 返回结果{code: 200, msg: "SUCCESS", data: "123456"}
this.xxx = response.data;
});
日期组件
el-date-picker
组件使用快捷选项(vue3)
:shortcuts="dateOptions"
dateOptions
系统默认支持了一些常用的方法,在src/utils/dateOptions
中进行设置,可自行扩展
组件默认展示日期时间
<template>
<el-date-picker
v-model="dateRange"
type="daterange"
value-format="YYYY-MM-DD"
:default-time="defaultTime">
</el-date-picker>
</template>
<script setup>
//默认将显示今天的日期
const dateRange = ref([dayjs().format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD')])
//默认时间格式
在选择日期范围时,你可以指定起始日期和结束日期的默认时间。
默认情况下,开始日期和结束日期的时间部分都是选择日期当日的 00:00:00。 通过 default-time 可以分别指定开始日期和结束日期的具体时刻。 它接受最多两个日期对象的数组。 其中第一项控制起始日期的具体时刻,第二项控制结束日期的具体时刻。
const defaultTime = ref([new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)])
发送到后端的日期将是 开始日期 + 00:00:00,结束日期 + 23:59:59
注意:value-format 需要设置成="YYYY-MM-DD HH:mm:ss"
</script>
格式化时间格式
- Vue3
{{parseTime('传入要格式化的时间', 'YYYY-MM-DD HH:mm:ss')}}
国际化
仅 Vue3 支持 i18n 静态翻译文件存储在 src/i18n
目录下,建议每个页面新建一个文件夹存放翻译文件存放于 pages 文件夹目录下,对于常用的翻译文件也可以动态存储 系统管理 -> 多语言设置 ,配置完成之后就可以根据 key 文件进行访问
js 文件中使用 直接使用
t('message.hello')
view 中使用
{{ $t('message.hello')}}
vscode 推荐插件 i18n Ally 可以一键帮你翻译
获取用户信息
//获取id
var userId = this.$store.getters.userId;
//获取登录信息
var userInfo = this.$store.getters.userinfo;
import useUserStore from "@/store/modules/user";
var userId = useUserStore().userId;
var userInfo = useUserStore().userInfo;
//{"userId":1,"userName":"admin","nickName":"管理员","userType":"0","avatar":"","email":"","phonenumber":"","sex":0,"status":0,"delFlag":0,"loginIP":"127.0.0.1","loginDate":"2023-07-25 16:58:43","deptId":0,"deptName":null,"roleIds":[1],"postIds":null,"roles":[{"roleId":1,"roleName":"超级管理员","roleKey":"admin","roleSort":1,"status":0,"delFlag":0,"dataScope":1,"menuCheckStrictly":true,"deptCheckStrictly":false,"menuIds":null,"deptIds":null,"userNum":0,"createBy":"admin","createTime":"2023-07-12 18:19:06","updateTime":null,"remark":"超级管理员"}],"welcomeMessage":"早上好","welcomeContent":"忙碌了一周,停一停脚步!","createBy":"","createTime":"2023-07-26 09:59:39","updateTime":null,"remark":"管理员"}
// 昵称
var nickName = useUserStore().name;
异常处理
@/utils/request.js
是基于 axios
的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。它封装了全局 request拦截器
、response拦截器
、统一的错误处理
、统一做了超时处理
、baseURL设置等
。
import axios from "axios";
import { ElMessageBox, ElMessage, ElLoading } from "element-plus";
import { getToken } from "@/utils/auth";
import errorCode from "@/utils/errorCode";
import useUserStore from "@/store/modules/user";
import { blobValidate } from "@/utils/ruoyi";
let downloadLoadingInstance;
// 解决后端跨域获取不到cookie问题
// axios.defaults.withCredentials = true
axios.defaults.headers["Content-Type"] = "application/json;charset=utf-8";
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: import.meta.env.VITE_APP_BASE_API,
// 超时
timeout: 30000,
});
// request拦截器
service.interceptors.request.use(
(config) => {
// 是否需要设置 token
if (getToken()) {
//将token放到请求头发送给服务器,将tokenkey放在请求头中
config.headers["Authorization"] = "Bearer " + getToken();
config.headers["userid"] = useUserStore().userId;
config.headers["userName"] = useUserStore().userName;
}
return config;
},
(error) => {
console.log(error);
Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(res) => {
if (res.status !== 200) {
Promise.reject("network error");
return;
}
// 未设置状态码则默认成功状态
const { code, msg } = res.data;
// 二进制数据则直接返回
if (
res.request.responseType === "blob" ||
res.request.responseType === "arraybuffer"
) {
return res;
}
if (code == 401) {
ElMessageBox.confirm("登录状态已过期,请重新登录", "系统提示", {
confirmButtonText: "重新登陆",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
useUserStore()
.logOut()
.then(() => {
location.href = import.meta.env.VITE_APP_ROUTER_PREFIX + "index";
});
});
return Promise.reject("无效的会话,或者会话已过期,请重新登录。");
} else if (
code == 0 ||
code == 1 ||
code == 110 ||
code == 101 ||
code == 403 ||
code == 500 ||
code == 429
) {
ElMessage({
message: msg,
type: "error",
});
return Promise.reject(res.data);
} else {
//返回标准 code/msg/data字段
return res.data;
}
},
(error) => {
console.log("err" + error);
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code 429")) {
message = "请求过于频繁,请稍后再试";
} else if (message.includes("Request failed with status code")) {
message =
"系统接口" + message.substr(message.length - 3) + "异常,请联系管理员";
}
ElMessage({
message: message,
type: "error",
duration: 3 * 1000,
grouping: true,
});
return Promise.reject(error);
}
);
export default service;
默认语言
可通过前端项目右上角进行设置
默认语言为简体中文 zh-cn
,可通过settings.js
中设置
默认字体大小
可通过前端项目右上角进行设置
默认语言为简体中文 default
,可通过settings.js
设置。支持 large
、default
、small
省市区组件
安装包
npm install element-china-area-data