[#](#后台手册) 后台手册
===============
[#](#分页实现) 分页实现
---------------
前端基于Element封装的分页组件 `Pagination`
后端分页组件使用Mybatis分页插件 `PageHelper`
### [#](#前端调用实现) 前端调用实现
1、前端定义分页流程
// 一般在查询参数中定义分页变量
queryParams: {
pageNum: 1,
pageSize: 10
},
// 页面添加分页组件,传入分页变量
v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /> // 调用后台方法,传入参数 获取结果 listUser(this.queryParams).then(response => { this.userList = response.rows; this.total = response.total; } ); ### [#](#后台逻辑实现) 后台逻辑实现 [参考后台逻辑实现](/ruoyi/document/htsc.html#后台逻辑实现) [#](#导入导出) 导入导出 --------------- 在实际开发中经常需要使用导入导出功能来加快数据的操作。在项目中可以使用注解来完成此项功能。 在需要被导入导出的实体类属性添加`@Excel`注解 ### [#](#导出实现流程) 导出实现流程 1、前端调用方法(参考如下) // 查询参数 queryParams queryParams: { pageNum: 1, pageSize: 10, userName: undefined }, // 导出接口exportUser import { exportUser } from "@/api/system/user"; /** 导出按钮操作 */ handleExport() { const queryParams = this.queryParams; this.$confirm('是否确认导出所有用户数据项?', "警告", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }).then(function() { return exportConfig(queryParams); }).then(response => { this.download(response.msg); }).catch(function() {}); } } 2、添加导出按钮事件 type="warning" icon="el-icon-download" size="mini" @click="handleExport" >导出 3、在实体变量上添加@Excel注解 @Excel(name = "用户序号", prompt = "用户编号") private Long userId; @Excel(name = "用户名称") private String userName; @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知") private String sex; @Excel(name = "最后登陆时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") private Date loginDate; 4、在Controller添加导出方法 @Log(title = "用户管理", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:user:export')") @GetMapping("/export") public AjaxResult export(SysUser user) { List ExcelUtil return util.exportExcel(list, "用户数据"); } ### [#](#导入实现流程) 导入实现流程 1、前端调用方法(参考如下) // 用户导入参数 upload: { // 是否显示弹出层(用户导入) open: false, // 弹出层标题(用户导入) title: "", // 是否禁用上传 isUploading: false, // 是否更新已经存在的用户数据 updateSupport: 0, // 设置上传的请求头部 headers: { Authorization: "Bearer " + getToken() }, // 上传的地址 url: process.env.VUE_APP_BASE_API + "/system/user/importData" }, // 导入模板接口importTemplate import { importTemplate } from "@/api/system/user"; /** 导入按钮操作 */ handleImport() { this.upload.title = "用户导入"; this.upload.open = true; }, /** 下载模板操作 */ importTemplate() { importTemplate().then(response => { this.download(response.msg); }); }, // 文件上传中处理 handleFileUploadProgress(event, file, fileList) { this.upload.isUploading = true; }, // 文件上传成功处理 handleFileSuccess(response, file, fileList) { this.upload.open = false; this.upload.isUploading = false; this.$refs.upload.clearFiles(); this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true }); this.getList(); }, // 提交上传文件 submitFileForm() { this.$refs.upload.submit(); } 2、添加导入按钮事件 type="info" icon="el-icon-upload2" size="mini" @click="handleImport" >导入 3、添加导入前端代码 ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag > 将文件拖到此处,或 点击上传
4、在实体变量上添加@Excel注解,默认为导出导入,也可以单独设置仅导入Type.IMPORT
@Excel(name = "用户序号")
private Long id;
@Excel(name = "部门编号", type = Type.IMPORT)
private Long deptId;
@Excel(name = "用户名称")
private String userName;
/** 导出部门多个对象 */
@Excels({
@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
@Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
})
private SysDept dept;
/** 导出部门单个对象 */
@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT)
private SysDept dept;
5、在Controller添加导入方法,updateSupport属性为是否存在则覆盖(可选)
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
@PostMapping("/importData")
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
{
ExcelUtil
List
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
String operName = loginUser.getUsername();
String message = userService.importUser(userList, updateSupport, operName);
return AjaxResult.success(message);
}
@GetMapping("/importTemplate")
public AjaxResult importTemplate()
{
ExcelUtil
return util.importTemplateExcel("用户数据");
}
[#](#上传下载) 上传下载
---------------
首先创建一张上传文件的表,例如:
drop table if exists sys_file_info;
create table sys_file_info (
file_id int(11) not null auto_increment comment '文件id',
file_name varchar(50) default '' comment '文件名称',
file_path varchar(255) default '' comment '文件路径',
primary key (file_id)
) engine=innodb auto_increment=1 default charset=utf8 comment = '文件信息表';
### [#](#上传实现流程) 上传实现流程
待补充
### [#](#下载实现流程) 下载实现流程
待补充
[#](#事务管理) 事务管理
---------------
[参考事务管理实现](/ruoyi/document/htsc.html#事务管理)
[#](#异常处理) 异常处理
---------------
[参考异常处理实现](/ruoyi/document/htsc.html#异常处理)
[#](#系统日志) 系统日志
---------------
[参考系统日志实现](/ruoyi/document/htsc.html#系统日志)
[#](#数据权限) 数据权限
---------------
[参考数据权限实现](/ruoyi/document/htsc.html#数据权限)
[#](#多数据源) 多数据源
---------------
[参考多数据源实现](/ruoyi/document/htsc.html#多数据源)
[#](#代码生成) 代码生成
---------------
[参考代码生成实现](/ruoyi/document/htsc.html#代码生成)
[#](#定时任务) 定时任务
---------------
[参考定时任务实现](/ruoyi/document/htsc.html#定时任务)
[#](#系统接口) 系统接口
---------------
[参考系统接口实现](/ruoyi/document/htsc.html#系统接口)
[#](#国际化支持) 国际化支持
-----------------
### [#](#后台国际化流程) 后台国际化流程
[后台国际化流程](/ruoyi/document/htsc.html#后台国际化流程)
### [#](#前端国际化流程) 前端国际化流程
1、`package.json`中`dependencies`节点添加`vue-i18n`
"vue-i18n": "7.3.2",
1
2、`src`目录下创建lang目录,存放国际化文件
此处包含三个文件,分别是 `index.js` `zh.js` `en.js`
// index.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import Cookies from 'js-cookie'
import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang
import enLocale from './en'
import zhLocale from './zh'
Vue.use(VueI18n)
const messages = {
en: {
...enLocale,
...elementEnLocale
},
zh: {
...zhLocale,
...elementZhLocale
}
}
const i18n = new VueI18n({
// 设置语言 选项 en | zh
locale: Cookies.get('language') || 'en',
// 设置文本内容
messages
})
export default i18n
// zh.js
export default {
login: {
title: '若依后台管理系统',
logIn: '登录',
username: '账号',
password: '密码'
},
tagsView: {
refresh: '刷新',
close: '关闭',
closeOthers: '关闭其它',
closeAll: '关闭所有'
},
settings: {
title: '系统布局配置',
theme: '主题色',
tagsView: '开启 Tags-View',
fixedHeader: '固定 Header',
sidebarLogo: '侧边栏 Logo'
}
}
// en.js
export default {
login: {
title: 'RuoYi Login Form',
logIn: 'Log in',
username: 'Username',
password: 'Password'
},
tagsView: {
refresh: 'Refresh',
close: 'Close',
closeOthers: 'Close Others',
closeAll: 'Close All'
},
settings: {
title: 'Page style setting',
theme: 'Theme Color',
tagsView: 'Open Tags-View',
fixedHeader: 'Fixed Header',
sidebarLogo: 'Sidebar Logo'
}
}
3、在`src/main.js`中增量添加i18n
import i18n from './lang'
// use添加i18n
Vue.use(Element, {
i18n: (key, value) => i18n.t(key, value)
})
new Vue({
i18n,
})
4、在`src/store/getters.js`中添加language
language: state => state.app.language,
1
5、在`src/store/modules/app.js`中增量添加i18n
const state = {
language: Cookies.get('language') || 'en'
}
const mutations = {
SET_LANGUAGE: (state, language) => {
state.language = language
Cookies.set('language', language)
}
}
const actions = {
setLanguage({ commit }, language) {
commit('SET_LANGUAGE', language)
}
}
6、在`src/components/LangSelect/index.vue`中创建汉化组件
中文
English
export default {
computed: {
language() {
return this.$store.getters.language
}
},
methods: {
handleSetLanguage(lang) {
this.$i18n.locale = lang
this.$store.dispatch('app/setLanguage', lang)
this.$message({
message: '设置语言成功',
type: 'success'
})
}
}
}
=
7、登录页面汉化
{{ $t('login.title') }}
v-model="loginForm.password" type="password" auto-complete="off" :placeholder="$t('login.password')" @keyup.enter.native="handleLogin" >
v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleLogin" >
:loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin" > {{ $t('login.logIn') }} 登 录 中...
import LangSelect from '@/components/LangSelect'
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'
export default {
name: "Login",
components: { LangSelect },
data() {
return {
codeUrl: "",
cookiePassword: "",
loginForm: {
username: "admin",
password: "admin123",
rememberMe: false,
code: "",
uuid: ""
},
loginRules: {
username: [
{ required: true, trigger: "blur", message: "用户名不能为空" }
],
password: [
{ required: true, trigger: "blur", message: "密码不能为空" }
],
code: [{ required: true, trigger: "change", message: "验证码不能为空" }]
},
loading: false,
redirect: undefined
};
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true
}
},
created() {
this.getCode();
this.getCookie();
},
methods: {
getCode() {
getCodeImg().then(res => {
this.codeUrl = "data:image/gif;base64," + res.img;
this.loginForm.uuid = res.uuid;
});
},
getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
};
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true;
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 });
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
} else {
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove('rememberMe');
}
this.$store
.dispatch("Login", this.loginForm)
.then(() => {
this.loading = false;
this.$router.push({ path: this.redirect || "/" });
})
.catch(() => {
this.loading = false;
this.getCode();
});
}
});
}
}
};
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/image/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
普通文本使用方式: {{ $t('login.title') }}
标签内使用方式: :placeholder="$t('login.password')"
js内使用方式 this.$t('login.user.password.not.match')