Merge branch 'master' of https://github.com/YunaiV/ruoyi-vue-pro into feature/1.6.2

This commit is contained in:
YunaiV
2022-05-23 20:17:28 +08:00
92 changed files with 2169 additions and 13137 deletions

View File

@ -499,7 +499,8 @@ export const selectComponents = [
__slot__: {
'list-type': true
},
action: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 请求地址
// action: process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload", // 请求地址
action: '/infra/file/upload', // 请求地址
disabled: false,
accept: '',
name: 'file',

View File

@ -1,6 +1,7 @@
<script>
import { deepClone } from '@/utils/index'
import render from '@/components/render/render.js'
import {getAccessToken} from "@/utils/auth";
const ruleTrigger = {
'el-input': 'blur',
@ -79,10 +80,51 @@ function formBtns(h) {
}
function renderFormItem(h, elementList) {
const that = this
const data = this[this.formConf.formModel]
// const formRef = that.$refs[that.formConf.formRef] // 这里直接添加有问题,此时还找不到表单 $refs
return elementList.map(scheme => {
const config = scheme.__config__
const layout = layouts[config.layout]
// edit by 芋道源码,解决 el-upload 上传的问题
// 参考 https://github.com/JakHuang/form-generator/blob/master/src/components/parser/example/Index.vue 实现
const vModel = scheme.__vModel__
const val = data[vModel]
if (scheme.__config__.tag === 'el-upload') {
// 回显图片
scheme['file-list'] = (val || []).map(url => ({ name: url, url }))
// 上传地址 + 请求头
scheme.action = process.env.VUE_APP_BASE_API + "/admin-api/infra/file/upload"
scheme.headers = { Authorization: "Bearer " + getAccessToken() }
// 注意 on-success 不能绑定箭头函数!!!
scheme['on-success'] = function (response, file, fileList) {
if (response.code !== 0) {
return;
}
// 添加到 data 中
const prev = data[vModel] || []
this.$set(data, vModel, [
...prev,
response.data
])
// 发起表单校验
that.$refs[that.formConf.formRef].validateField(vModel)
}
// 注意 on-remove 不能绑定箭头函数!!!
scheme['on-remove'] = function (file, fileList) {
// 移除从 data 中
const prev = data[vModel] || []
const index = prev.indexOf(file.response.data)
if (index === -1) {
return
}
prev.splice(index, 1) // 直接移除即可,无需重复 set因为 array 是引用
// 发起表单校验
that.$refs[that.formConf.formRef].validateField(vModel)
}
}
if (layout) {
return layout.call(this, h, scheme)
}

View File

@ -152,31 +152,24 @@ export default {
})
},
refreshSelectedTag(view) {
this.$store.dispatch('tagsView/delCachedView', view).then(() => {
const { fullPath } = view
this.$nextTick(() => {
this.$router.replace({
path: '/redirect' + fullPath
})
})
})
this.$tab.refreshPage(view);
},
closeSelectedTag(view) {
this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
this.$tab.closePage(view).then(({ visitedViews }) => {
if (this.isActive(view)) {
this.toLastView(visitedViews, view)
}
})
},
closeRightTags() {
this.$store.dispatch('tagsView/delRightTags', this.selectedTag).then(visitedViews => {
this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
this.toLastView(visitedViews)
}
})
},
closeLeftTags() {
this.$store.dispatch('tagsView/delLeftTags', this.selectedTag).then(visitedViews => {
this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
this.toLastView(visitedViews)
}
@ -184,12 +177,12 @@ export default {
},
closeOthersTags() {
this.$router.push(this.selectedTag).catch(()=>{});
this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
this.$tab.closeOtherPage(this.selectedTag).then(() => {
this.moveToCurrentTag()
})
},
closeAllTags(view) {
this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
this.$tab.closeAllPage().then(({ visitedViews }) => {
if (this.affixTags.some(tag => tag.path === this.$route.path)) {
return
}

View File

@ -69,8 +69,9 @@ import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
import Tinymce from '@/components/tinymce/index.vue'
Vue.component('tinymce', Tinymce)
import '@/icons'
import axios from 'axios'
Vue.prototype.$axios = axios
import request from "@/utils/request" // 实现 form generator 使用自己定义的 axios request 对象
console.log(request)
Vue.prototype.$axios = request
import '@/styles/index.scss'
/**

View File

@ -2,6 +2,7 @@ import { constantRoutes } from '@/router'
import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView';
import { toCamelCase } from "@/utils";
const permission = {
state: {
@ -56,6 +57,8 @@ function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
icon: route.icon,
noCache: !route.keepAlive,
}
// 路由地址转首字母大写驼峰作为路由名称适配keepAlive
route.name = toCamelCase(route.path, true)
route.hidden = !route.visible
// 处理 component 属性
if (route.children) { // 父节点

View File

@ -63,7 +63,7 @@ const mutations = {
}
}
},
DEL_RIGHT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
@ -79,6 +79,23 @@ const mutations = {
}
return false
})
},
DEL_LEFT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx >= index || (item.meta && item.meta.affix)) {
return true
}
const i = state.cachedViews.indexOf(item.name)
if (i > -1) {
state.cachedViews.splice(i, 1)
}
return false
})
}
}
@ -172,7 +189,14 @@ const actions = {
commit('DEL_RIGHT_VIEWS', view)
resolve([...state.visitedViews])
})
}
},
delLeftTags({ commit }, view) {
return new Promise(resolve => {
commit('DEL_LEFT_VIEWS', view)
resolve([...state.visitedViews])
})
},
}
export default {

View File

@ -1,22 +1,96 @@
import Cookies from 'js-cookie'
import {decrypt, encrypt} from "@/utils/jsencrypt";
const AccessTokenKey = 'ACCESS_TOKEN'
const RefreshTokenKey = 'REFRESH_TOKEN'
// ========== Token 相关 ==========
export function getAccessToken() {
return Cookies.get(AccessTokenKey)
return localStorage.getItem(AccessTokenKey)
}
export function getRefreshToken() {
return Cookies.get(RefreshTokenKey)
return localStorage.getItem(RefreshTokenKey)
}
export function setToken(token) {
Cookies.set(AccessTokenKey, token.accessToken)
Cookies.set(RefreshTokenKey, token.refreshToken)
localStorage.setItem(AccessTokenKey, token.accessToken)
localStorage.setItem(RefreshTokenKey, token.refreshToken)
}
export function removeToken() {
Cookies.remove(AccessTokenKey)
Cookies.remove(RefreshTokenKey)
localStorage.removeItem(AccessTokenKey)
localStorage.removeItem(RefreshTokenKey)
}
// ========== 账号相关 ==========
const UsernameKey = 'USERNAME'
const PasswordKey = 'PASSWORD'
const RememberMeKey = 'REMEMBER_ME'
export function getUsername() {
return localStorage.getItem(UsernameKey)
}
export function setUsername(username) {
localStorage.setItem(UsernameKey, username)
}
export function removeUsername() {
localStorage.removeItem(UsernameKey)
}
export function getPassword() {
const password = localStorage.getItem(PasswordKey)
return password ? decrypt(password) : undefined
}
export function setPassword(password) {
localStorage.setItem(PasswordKey, encrypt(password))
}
export function removePassword() {
localStorage.removeItem(PasswordKey)
}
export function getRememberMe() {
return localStorage.getItem(RememberMeKey) === 'true'
}
export function setRememberMe(rememberMe) {
localStorage.setItem(RememberMeKey, rememberMe)
}
export function removeRememberMe() {
localStorage.removeItem(RememberMeKey)
}
// ========== 租户相关 ==========
const TenantIdKey = 'TENANT_ID'
const TenantNameKey = 'TENANT_NAME'
export function getTenantName() {
return localStorage.getItem(TenantNameKey)
}
export function setTenantName(username) {
localStorage.setItem(TenantNameKey, username)
}
export function removeTenantName() {
localStorage.removeItem(TenantNameKey)
}
export function getTenantId() {
return localStorage.getItem(TenantIdKey)
}
export function setTenantId(username) {
localStorage.setItem(TenantIdKey, username)
}
export function removeTenantId() {
localStorage.removeItem(TenantIdKey)
}

View File

@ -75,13 +75,13 @@ export const SystemUserSocialTypeEnum = {
title: "钉钉",
type: 20,
source: "dingtalk",
img: "https://cdn.jsdelivr.net/gh/justauth/justauth-oauth-logo@1.11/dingtalk.png",
img: "https://s1.ax1x.com/2022/05/22/OzMDRs.png",
},
WECHAT_ENTERPRISE: {
title: "企业微信",
type: 30,
source: "wechat_enterprise",
img: "https://cdn.jsdelivr.net/gh/justauth/justauth-oauth-logo@1.11/wechat_enterprise.png",
img: "https://s1.ax1x.com/2022/05/22/OzMrzn.png",
}
}

View File

@ -427,3 +427,15 @@ export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}
// -转驼峰
export function toCamelCase(str, upperCaseFirst) {
str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {
return group1.toUpperCase();
});
if (upperCaseFirst && str) {
str = str.charAt(0).toUpperCase() + str.slice(1);
}
return str;
}

View File

@ -1,12 +1,17 @@
import axios from 'axios'
import { Notification, MessageBox, Message } from 'element-ui'
import {Message, MessageBox, Notification} from 'element-ui'
import store from '@/store'
import {getAccessToken, getRefreshToken, setToken} from '@/utils/auth'
import {getAccessToken, getRefreshToken, getTenantId, setToken} from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import Cookies from "js-cookie";
import {getPath, getTenantEnable} from "@/utils/ruoyi";
import {refreshToken} from "@/api/login";
// 需要忽略的提示。忽略后,自动 Promise.reject('error')
const ignoreMsgs = [
"无效的刷新令牌", // 刷新令牌被删除时,不用提示
"刷新令牌已过期" // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401无法跳转到登出界面
]
// 是否显示重新登录
export let isRelogin = { show: false };
// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
@ -21,7 +26,9 @@ const service = axios.create({
// axios中请求配置有baseURL选项表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API + '/admin-api/', // 此处的 /admin-api/ 地址,原因是后端的基础路径为 /admin-api/
// 超时
timeout: 30000
timeout: 30000,
// 禁用 Cookie 等信息
withCredentials: false,
})
// request拦截器
service.interceptors.request.use(config => {
@ -32,7 +39,7 @@ service.interceptors.request.use(config => {
}
// 设置租户
if (getTenantEnable()) {
const tenantId = Cookies.get('tenantId');
const tenantId = getTenantId();
if (tenantId) {
config.headers['tenant-id'] = tenantId;
}
@ -66,85 +73,84 @@ service.interceptors.request.use(config => {
})
// 响应拦截器
service.interceptors.response.use( async res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default']
if (code === 401) {
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) {
isRefreshToken = true;
// 1. 如果获取不到刷新令牌,则只能执行登出操作
if (!getRefreshToken()) {
return handleAuthorized();
}
// 2. 进行刷新访问令牌
try {
const refreshTokenRes = await refreshToken()
// 2.1 刷新成功,则回放队列的请求 + 当前请求
setToken(refreshTokenRes.data)
requestList.forEach(cb => cb())
return service(res.config)
} catch (e) {// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求
requestList.forEach(cb => cb())
// 提示是否要登出。即不回放当前请求!不然会形成递归
return handleAuthorized();
} finally {
requestList = []
isRefreshToken = false
}
} else {
// 添加到队列,等待刷新获取到新的令牌
return new Promise(resolve => {
requestList.push(() => {
res.config.headers['Authorization'] = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(service(res.config))
})
})
service.interceptors.response.use(async res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = res.data.msg || errorCode[code] || errorCode['default']
if (ignoreMsgs.indexOf(msg) !== -1) { // 如果是忽略的错误码,直接返回 msg 异常
return Promise.reject(msg)
} else if (code === 401) {
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) {
isRefreshToken = true;
// 1. 如果获取不到刷新令牌,则只能执行登出操作
if (!getRefreshToken()) {
return handleAuthorized();
}
} else if (code === 500) {
Message({
message: msg,
type: 'error'
})
return Promise.reject(new Error(msg))
} else if (code === 901) {
Message({
type: 'error',
duration: 0,
dangerouslyUseHTMLString: true,
message: '<div>演示模式,无法进行写操作</div>'
+ '<div> &nbsp; </div>'
+ '<div>参考 https://doc.iocoder.cn/ 教程</div>'
+ '<div> &nbsp; </div>'
+ '<div>5 分钟搭建本地环境</div>',
})
return Promise.reject(new Error(msg))
} else if (code !== 200) {
if (msg === '无效的刷新令牌') { // hard coding忽略这个提示直接登出
console.log('无效的刷新令牌')
} else {
Notification.error({
title: msg
})
// 2. 进行刷新访问令牌
try {
const refreshTokenRes = await refreshToken()
// 2.1 刷新成功,则回放队列的请求 + 当前请求
setToken(refreshTokenRes.data)
requestList.forEach(cb => cb())
return service(res.config)
} catch (e) {// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求
requestList.forEach(cb => cb())
// 提示是否要登出。即不回放当前请求!不然会形成递归
return handleAuthorized();
} finally {
requestList = []
isRefreshToken = false
}
return Promise.reject('error')
} else {
return res.data
// 添加到队列,等待刷新获取到新的令牌
return new Promise(resolve => {
requestList.push(() => {
res.config.headers['Authorization'] = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(service(res.config))
})
})
}
},
error => {
} else if (code === 500) {
Message({
message: msg,
type: 'error'
})
return Promise.reject(new Error(msg))
} else if (code === 901) {
Message({
type: 'error',
duration: 0,
dangerouslyUseHTMLString: true,
message: '<div>演示模式,无法进行写操作</div>'
+ '<div> &nbsp; </div>'
+ '<div>参考 https://doc.iocoder.cn/ 教程</div>'
+ '<div> &nbsp; </div>'
+ '<div>5 分钟搭建本地环境</div>',
})
return Promise.reject(new Error(msg))
} else if (code !== 200) {
if (msg === '无效的刷新令牌') { // hard coding忽略这个提示直接登出
console.log(msg)
} else {
Notification.error({
title: msg
})
}
return Promise.reject('error')
} else {
return res.data
}
}, error => {
console.log('err' + error)
let { message } = error;
let {message} = error;
if (message === "Network Error") {
message = "后端接口连接异常";
}
else if (message.includes("timeout")) {
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
}
else if (message.includes("Request failed with status code")) {
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
Message({
@ -159,7 +165,7 @@ service.interceptors.response.use( async res => {
export function getBaseHeader() {
return {
'Authorization': "Bearer " + getAccessToken(),
'tenant-id': Cookies.get('tenantId'),
'tenant-id': getTenantId(),
}
}

View File

@ -429,7 +429,7 @@ export default {
this.$modal.confirm('是否删除该流程!!').then(function() {
deleteModel(row.id).then(response => {
that.getList();
that.msgSuccess("删除成功");
that.$modal.msgSuccess("删除成功");
})
}).catch(() => {});
},
@ -439,7 +439,7 @@ export default {
this.$modal.confirm('是否部署该流程!!').then(function() {
deployModel(row.id).then(response => {
that.getList();
that.msgSuccess("部署成功");
that.$modal.msgSuccess("部署成功");
})
}).catch(() => {});
},

View File

@ -55,10 +55,9 @@
<script>
import {getProcessDefinitionBpmnXML, getProcessDefinitionList} from "@/api/bpm/definition";
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
import {getForm} from "@/api/bpm/form";
import {decodeFields} from "@/utils/formGenerator";
import Parser from '@/components/parser/Parser'
import {createProcessInstance, getMyProcessInstancePage} from "@/api/bpm/processInstance";
import {createProcessInstance} from "@/api/bpm/processInstance";
// 流程实例的发起
export default {

View File

@ -58,7 +58,7 @@
</el-table-column>
<el-table-column label="当前审批任务" align="center" prop="tasks">
<template slot-scope="scope">
<el-button v-for="task in scope.row.tasks" type="text" @click="handleFormDetail(task.id)">
<el-button v-for="task in scope.row.tasks" :key="task.id" type="text" @click="handleFormDetail(task.id)">
<span>{{ task.name }}</span>
</el-button>
</template>

View File

@ -12,7 +12,7 @@
</el-table-column>
<el-table-column label="规则范围" align="center" prop="options" width="440px">
<template slot-scope="scope">
<el-tag size="medium" v-if="scope.row.options" v-for="option in scope.row.options">
<el-tag size="medium" v-if="scope.row.options" :key="option" v-for="option in scope.row.options">
{{ getAssignRuleOptionName(scope.row.type, option) }}
</el-tag>
</template>

View File

@ -107,9 +107,17 @@
import {getCodeImg, sendSmsCode, socialAuthRedirect} from "@/api/login";
import {getTenantIdByName} from "@/api/system/tenant";
import Cookies from "js-cookie";
import {decrypt, encrypt} from '@/utils/jsencrypt'
import {SystemUserSocialTypeEnum} from "@/utils/constants";
import {getTenantEnable} from "@/utils/ruoyi";
import {
getPassword,
getRememberMe, getTenantName,
getUsername,
removePassword, removeRememberMe, removeTenantName,
removeUsername,
setPassword, setRememberMe, setTenantId, setTenantName,
setUsername
} from "@/utils/auth";
export default {
name: "Login",
@ -161,7 +169,7 @@ export default {
const tenantId = res.data;
if (tenantId && tenantId >= 0) {
// 设置租户
Cookies.set("tenantId", tenantId);
setTenantId(tenantId)
callback();
} else {
callback('租户不存在');
@ -172,8 +180,6 @@ export default {
}
]
},
loading: false,
redirect: undefined,
// 枚举
@ -213,21 +219,16 @@ export default {
});
},
getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe')
const tenantName = Cookies.get('tenantName');
const mobile = Cookies.get('mobile');
const mobileCode = Cookies.get('mobileCode');
const loginType = Cookies.get('loginType');
const username = getUsername();
const password = getPassword();
const rememberMe = getRememberMe();
const tenantName = getTenantName();
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
tenantName: tenantName === undefined ? this.loginForm.tenantName : tenantName,
mobile: mobile === undefined ? this.loginForm.mobile : mobile,
mobileCode: mobileCode === undefined ? this.loginForm.mobileCode : mobileCode,
loginType: loginType === undefined ? this.loginForm.loginType : loginType,
...this.loginForm,
username: username ? username : this.loginForm.username,
password: password ? password : this.loginForm.password,
rememberMe: rememberMe ? getRememberMe() : false,
tenantName: tenantName ? tenantName : this.loginForm.tenantName,
};
},
handleLogin() {
@ -236,18 +237,18 @@ export default {
this.loading = true;
// 设置 Cookie
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});
Cookies.set('tenantName', this.loginForm.tenantName, {expires: 30});
setUsername(this.loginForm.username)
setPassword(this.loginForm.password)
setRememberMe(this.loginForm.rememberMe)
setTenantName(this.loginForm.tenantName)
} else {
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove('rememberMe');
Cookies.remove('tenantName');
removeUsername()
removePassword()
removeRememberMe()
removeTenantName()
}
// 发起登陆
console.log("发起登录", this.loginForm);
// console.log("发起登录", this.loginForm);
this.$store.dispatch(this.loginForm.loginType === "sms" ? "SmsLogin" : "Login", this.loginForm).then(() => {
this.$router.push({path: this.redirect || "/"}).catch(() => {
});

View File

@ -74,7 +74,7 @@
<!-- <el-table-column label="商户名称" align="center" prop="merchantName" width="120"/>-->
<!-- <el-table-column label="应用名称" align="center" prop="appName" width="120"/>-->
<el-table-column label="支付渠道" align="center" width="130">
<template v-slot="scope">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
<p>商户名称: {{ scope.row.merchantName }}</p>
<p>应用名称: {{ scope.row.appName }}</p>
@ -88,7 +88,7 @@
<!-- <el-table-column label="交易订单号" align="center" prop="tradeNo" width="140"/>-->
<!-- <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" width="140"/>-->
<el-table-column label="商户订单号" align="left" width="230">
<template v-slot="scope">
<template slot-scope="scope">
<p class="order-font">
<el-tag size="mini">退款</el-tag>
{{ scope.row.merchantRefundNo }}
@ -100,7 +100,7 @@
</template>
</el-table-column>
<el-table-column label="支付订单号" align="center" prop="merchantRefundNo" width="250">
<template v-slot="scope">
<template slot-scope="scope">
<p class="order-font">
<el-tag size="mini">交易</el-tag>
{{ scope.row.tradeNo }}
@ -112,7 +112,7 @@
</template>
</el-table-column>
<el-table-column label="支付金额(元)" align="center" prop="payAmount" width="100">
<template v-slot="scope" class="">
<template slot-scope="scope" class="">
{{ parseFloat(scope.row.payAmount / 100).toFixed(2) }}
</template>
</el-table-column>
@ -122,17 +122,17 @@
</template>
</el-table-column>
<el-table-column label="退款类型" align="center" prop="type" width="80">
<template v-slot="scope">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="退款状态" align="center" prop="status">
<template v-slot="scope">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="回调状态" align="center" prop="notifyStatus">
<template v-slot="scope">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PAY_ORDER_NOTIFY_STATUS" :value="scope.row.notifyStatus" />
</template>
</el-table-column>
@ -183,7 +183,7 @@
<el-tag class="tag-purple" size="mini">{{ parseFloat(refundDetail.refundAmount / 100).toFixed(2) }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="退款类型">
<template v-slot="scope">
<template slot-scope="scope">
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_TYPE" :value="refundDetail.type" />
</template>
</el-descriptions-item>

View File

@ -19,7 +19,7 @@
</el-tab-pane>
</el-tabs>
<div>
<el-form ref="loginForm" :model="loginForm" :rules="LoginRules" class="login-form">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<!-- 账号密码登录 -->
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
@ -65,16 +65,28 @@
<script>
import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'
import {
getPassword, getRememberMe,
getUsername,
removePassword,
removeUsername,
setPassword,
setRememberMe,
setUsername
} from "@/utils/auth";
import {getCodeImg} from "@/api/login";
export default {
name: "ThirdLogin",
data() {
return {
codeUrl: "",
captchaEnable: true,
loginForm: {
loginType: "uname",
username: "admin",
password: "admin123",
rememberMe: false, // TODO 芋艿:后面看情况,去掉这块
rememberMe: false,
},
loginRules: {
username: [
@ -104,6 +116,7 @@ export default {
this.getCookie();
// 重定向地址
this.redirect = this.$route.query.redirect;
this.getCode();
// 社交登录相关
this.type = this.$route.query.type;
this.code = this.$route.query.code;
@ -119,16 +132,30 @@ export default {
});
},
methods: {
getCode() {
// 只有开启的状态,才加载验证码。默认开启
if (!this.captchaEnable) {
return;
}
// 请求远程,获得验证码
getCodeImg().then(res => {
res = res.data;
this.captchaEnable = res.enable;
if (this.captchaEnable) {
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')
const loginType = Cookies.get('loginType');
const username = getUsername();
const password = getPassword();
const rememberMe = getRememberMe();
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
loginType: loginType === undefined ? this.loginForm.loginType : loginType,
username: username ? username : this.loginForm.username,
password: password ? password : this.loginForm.password,
rememberMe: rememberMe ? getRememberMe() : false,
loginType: this.loginForm.loginType,
};
},
handleLogin() {
@ -136,11 +163,12 @@ export default {
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 });
setUsername(this.loginForm.username)
setPassword(this.loginForm.password)
setRememberMe(this.loginForm.rememberMe)
} else {
Cookies.remove("username");
Cookies.remove("password");
removeUsername()
removePassword()
}
this.$store.dispatch("SocialLogin2", {
code: this.code,

View File

@ -50,7 +50,7 @@
</el-table-column>
<el-table-column label="授权类型" align="center" prop="authorizedGrantTypes">
<template slot-scope="scope">
<el-tag :disable-transitions="true" v-for="(authorizedGrantType, index) in scope.row.authorizedGrantTypes" :index="index">
<el-tag :disable-transitions="true" :key="index" v-for="(authorizedGrantType, index) in scope.row.authorizedGrantTypes" :index="index">
{{ authorizedGrantType }}
</el-tag>
</template>

View File

@ -54,7 +54,7 @@
<el-table-column label="描述" align="center" prop="description"/>
<el-table-column label="标签" align="center" prop="tags">
<template slot-scope="scope">
<el-tag :disable-transitions="true" v-for="(tag, index) in scope.row.tags" :index="index">
<el-tag :disable-transitions="true" :key="index" v-for="(tag, index) in scope.row.tags" :index="index">
{{ tag }}
</el-tag>
</template>

View File

@ -147,7 +147,7 @@
<el-form-item label="手机号" prop="mobile">
<el-input v-model="sendSmsForm.mobile" placeholder="请输入手机号" />
</el-form-item>
<el-form-item v-for="param in sendSmsForm.params" :label="'参数 {' + param + '}'" :prop="'templateParams.' + param">
<el-form-item v-for="param in sendSmsForm.params" :key="param" :label="'参数 {' + param + '}'" :prop="'templateParams.' + param">
<el-input v-model="sendSmsForm.templateParams[param]" :placeholder="'请输入 ' + param + ' 参数'" />
</el-form-item>
</el-form>

View File

@ -111,7 +111,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<treeselect v-model="form.deptId" :options="deptOptions" :show-count="true"
<treeselect v-model="form.deptId" :options="deptOptions" :show-count="true" :clearable="false"
placeholder="请选择归属部门" :normalizer="normalizer"/>
</el-form-item>
</el-col>
@ -304,7 +304,7 @@ export default {
// 设置上传的请求头部
headers: getBaseHeader(),
// 上传的地址
url: process.env.VUE_APP_BASE_API + '/admin-api/' + "/system/user/import"
url: process.env.VUE_APP_BASE_API + '/admin-api/system/user/import'
},
// 查询参数
queryParams: {