若依框架后台开发文档

[#](#后台手册) 后台手册

===============

[#](#分页实现) 分页实现

---------------

前端基于Element封装的分页组件 `Pagination`

后端分页组件使用Mybatis分页插件 `PageHelper`

### [#](#前端调用实现) 前端调用实现

1、前端定义分页流程

// 一般在查询参数中定义分页变量

queryParams: {

pageNum: 1,

pageSize: 10

},


// 页面添加分页组件,传入分页变量

<pagination

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、添加导出按钮事件

<el-button

type="warning"

icon="el-icon-download"

size="mini"

@click="handleExport"

>导出</el-button>


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<SysUser> list = userService.selectUserList(user);

ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);

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、添加导入按钮事件

<el-button

type="info"

icon="el-icon-upload2"

size="mini"

@click="handleImport"

>导入</el-button>


3、添加导入前端代码

<!-- 用户导入对话框 -->

<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px">

<el-upload

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

>

<i class="el-icon-upload"></i>

<div class="el-upload__text">

将文件拖到此处,或

<em>点击上传</em>

</div>

<div class="el-upload__tip" slot="tip">

<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据

<el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>

</div>

<div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>

</el-upload>

<div slot="footer" class="dialog-footer">

<el-button type="primary" @click="submitFileForm">确 定</el-button>

<el-button @click="upload.open = false">取 消</el-button>

</div>

</el-dialog>


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<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);

List<SysUser> userList = util.importExcel(file.getInputStream());

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<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);

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`中创建汉化组件

<template>

<el-dropdown trigger="click" class="international" @command="handleSetLanguage">

<div>

<svg-icon class-name="international-icon" icon-class="language" />

</div>

<el-dropdown-menu slot="dropdown">

<el-dropdown-item :disabled="language==='zh'" command="zh">

中文

</el-dropdown-item>

<el-dropdown-item :disabled="language==='en'" command="en">

English

</el-dropdown-item>

</el-dropdown-menu>

</el-dropdown>

</template>


<script>

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'

})

}

}

}

</script>


=

7、登录页面汉化

<template>

<div class="login">

<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">

<h3 class="title">{{ $t('login.title') }}</h3>

<lang-select class="set-language" />

<el-form-item prop="username">

<el-input v-model="loginForm.username" type="text" auto-complete="off" :placeholder="$t('login.username')">

<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />

</el-input>

</el-form-item>

<el-form-item prop="password">

<el-input

v-model="loginForm.password"

type="password"

auto-complete="off"

:placeholder="$t('login.password')"

@keyup.enter.native="handleLogin"

>

<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />

</el-input>

</el-form-item>

<el-form-item prop="code">

<el-input

v-model="loginForm.code"

auto-complete="off"

placeholder="验证码"

style="width: 63%"

@keyup.enter.native="handleLogin"

>

<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />

</el-input>

<div class="login-code">

<img :src="codeUrl" @click="getCode" />

</div>

</el-form-item>

<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>

<el-form-item style="width:100%;">

<el-button

:loading="loading"

size="medium"

type="primary"

style="width:100%;"

@click.native.prevent="handleLogin"

>

<span v-if="!loading">{{ $t('login.logIn') }}</span>

<span v-else>登 录 中...</span>

</el-button>

</el-form-item>

</el-form>

<!--  底部  -->

<div class="el-login-footer">

<span>Copyright © 2018-2019 ruoyi.vip All Rights Reserved.</span>

</div>

</div>

</template>


<script>

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();

});

}

});

}

}

};

</script>


<style rel="stylesheet/scss" lang="scss">

.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;

}

</style>


普通文本使用方式: {{ $t('login.title') }}

标签内使用方式:  :placeholder="$t('login.password')"

js内使用方式      this.$t('login.user.password.not.match')

© 著作权归作者所有,转载或内容合作请联系作者