Commit 664413e5 by zhangdaiscott

JeecgBoot 2.4.6版本发布

parent 986f9096
Ant Design Jeecg Vue Ant Design Jeecg Vue
==== ====
当前最新版本: 2.4.5(发布日期:20210607 当前最新版本: 2.4.6(发布日期:20210816
Overview Overview
---- ----
......
{ {
"name": "vue-antd-jeecg", "name": "vue-antd-jeecg",
"version": "2.4.5", "version": "2.4.6",
"private": true, "private": true,
"scripts": { "scripts": {
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ", "pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
}, },
"dependencies": { "dependencies": {
"ant-design-vue": "^1.7.2", "ant-design-vue": "^1.7.2",
"@jeecg/antd-online-mini": "2.4.5-RC", "@jeecg/antd-online-mini": "2.4.6-beta",
"@antv/data-set": "^0.11.4", "@antv/data-set": "^0.11.4",
"viser-vue": "^2.4.8", "viser-vue": "^2.4.8",
"axios": "^0.18.0", "axios": "^0.18.0",
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
"tinymce": "^5.3.2", "tinymce": "^5.3.2",
"@toast-ui/editor": "^2.1.2", "@toast-ui/editor": "^2.1.2",
"vue-area-linkage": "^5.1.0", "vue-area-linkage": "^5.1.0",
"area-data": "^5.0.6", "china-area-data": "^5.0.1",
"dom-align": "1.12.0", "dom-align": "1.12.0",
"xe-utils": "2.4.8", "xe-utils": "2.4.8",
"vxe-table": "2.9.13", "vxe-table": "2.9.13",
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
<span style="margin-left:5px">{{ ellipsisFileName }}</span> <span style="margin-left:5px">{{ ellipsisFileName }}</span>
</a-tooltip> </a-tooltip>
<a-tooltip v-else :title="file.name"> <a-tooltip v-else :title="file.message||'上传失败'">
<a-icon type="paper-clip" style="color:red;"/> <a-icon type="exclamation-circle" style="color:red;"/>
<span style="color:red;margin-left:5px">{{ ellipsisFileName }}</span> <span style="margin-left:5px">{{ ellipsisFileName }}</span>
</a-tooltip> </a-tooltip>
<template style="width: 30px"> <template style="width: 30px">
...@@ -179,8 +179,19 @@ ...@@ -179,8 +179,19 @@
value['responseName'] = file.response[this.responseName] value['responseName'] = file.response[this.responseName]
} }
if (file.status === 'done') { if (file.status === 'done') {
value['path'] = file.response[this.responseName] if (typeof file.response.success === 'boolean') {
this.handleChangeCommon(value) if (file.response.success) {
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
} else {
value['status'] = 'error'
value['message'] = file.response.message || '未知错误'
}
} else {
// 考虑到如果设置action上传路径为非jeecg-boot后台,可能不会返回 success 属性的情况,就默认为成功
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
}
} else if (file.status === 'error') { } else if (file.status === 'error') {
value['message'] = file.response.message || '未知错误' value['message'] = file.response.message || '未知错误'
} }
......
...@@ -10,20 +10,9 @@ ...@@ -10,20 +10,9 @@
<template v-else-if="file['path']"> <template v-else-if="file['path']">
<img class="j-editable-image" :src="imgSrc" alt="无图片" @click="handleMoreOperation"/> <img class="j-editable-image" :src="imgSrc" alt="无图片" @click="handleMoreOperation"/>
</template> </template>
<template v-else> <a-tooltip v-else :title="file.message||'上传失败'" @click="handleClickShowImageError">
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError"/> <a-icon type="exclamation-circle" style="color:red;"/>
</template> </a-tooltip>
<template slot="addonBefore" style="width: 30px">
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
<a-icon type="loading"/>
</a-tooltip>
<a-tooltip v-else-if="file.status==='done'" title="上传完成">
<a-icon type="check-circle" style="color:#00DB00;"/>
</a-tooltip>
<a-tooltip v-else title="上传失败">
<a-icon type="exclamation-circle" style="color:red;"/>
</a-tooltip>
</template>
<template style="width: 30px"> <template style="width: 30px">
<a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;"> <a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;">
...@@ -196,8 +185,19 @@ ...@@ -196,8 +185,19 @@
value['responseName'] = file.response[this.responseName] value['responseName'] = file.response[this.responseName]
} }
if (file.status === 'done') { if (file.status === 'done') {
value['path'] = file.response[this.responseName] if (typeof file.response.success === 'boolean') {
this.handleChangeCommon(value) if (file.response.success) {
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
} else {
value['status'] = 'error'
value['message'] = file.response.message || '未知错误'
}
} else {
// 考虑到如果设置action上传路径为非jeecg-boot后台,可能不会返回 success 属性的情况,就默认为成功
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
}
} else if (file.status === 'error') { } else if (file.status === 'error') {
value['message'] = file.response.message || '未知错误' value['message'] = file.response.message || '未知错误'
} }
......
import { pcaa } from 'area-data'
/** /**
* 省市区 * 省市区
*/ */
...@@ -8,7 +6,7 @@ export default class Area { ...@@ -8,7 +6,7 @@ export default class Area {
* 构造器 * 构造器
* @param express * @param express
*/ */
constructor() { constructor(pcaa) {
let arr = [] let arr = []
const province = pcaa['86'] const province = pcaa['86']
Object.keys(province).map(key=>{ Object.keys(province).map(key=>{
...@@ -17,9 +15,11 @@ export default class Area { ...@@ -17,9 +15,11 @@ export default class Area {
Object.keys(city).map(key2=>{ Object.keys(city).map(key2=>{
arr.push({id:key2, text:city[key2], pid:key, index:2}); arr.push({id:key2, text:city[key2], pid:key, index:2});
const qu = pcaa[key2]; const qu = pcaa[key2];
Object.keys(qu).map(key3=>{ if(qu){
arr.push({id:key3, text:qu[key3], pid:key2, index:3}); Object.keys(qu).map(key3=>{
}) arr.push({id:key3, text:qu[key3], pid:key2, index:3});
})
}
}) })
}) })
this.all = arr; this.all = arr;
......
...@@ -32,4 +32,15 @@ export const cutStrByFullLength = (str = '', maxLength) => { ...@@ -32,4 +32,15 @@ export const cutStrByFullLength = (str = '', maxLength) => {
} }
return pre return pre
}, '') }, '')
}
// 下划线转换驼峰
export function underLinetoHump(name) {
return name.replace(/\_(\w)/g, function(all, letter){
return letter.toUpperCase();
});
}
// 驼峰转换下划线
export function humptoUnderLine(name) {
return name.replace(/([A-Z])/g,"_$1").toLowerCase();
} }
\ No newline at end of file
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
</template> </template>
<script> <script>
import { pcaa } from 'area-data'
import Area from '@/components/_util/Area' import Area from '@/components/_util/Area'
export default { export default {
...@@ -53,7 +52,7 @@ ...@@ -53,7 +52,7 @@
}, },
data() { data() {
return { return {
pcaa, pcaa: this.$Jpcaa,
innerValue: [], innerValue: [],
usedListeners: ['change'], usedListeners: ['change'],
enums: { enums: {
...@@ -114,7 +113,7 @@ ...@@ -114,7 +113,7 @@
/** 通过地区code获取子级 */ /** 通过地区code获取子级 */
loadDataByCode(value) { loadDataByCode(value) {
let options = [] let options = []
let data = pcaa[value] let data = this.pcaa[value]
if (data) { if (data) {
for (let key in data) { for (let key in data) {
if (data.hasOwnProperty(key)) { if (data.hasOwnProperty(key)) {
...@@ -139,7 +138,7 @@ ...@@ -139,7 +138,7 @@
}, },
initAreaData(){ initAreaData(){
if(!this.areaData){ if(!this.areaData){
this.areaData = new Area(); this.areaData = new Area(this.$Jpcaa);
} }
}, },
......
...@@ -400,6 +400,10 @@ ...@@ -400,6 +400,10 @@
.null-tip-hidden{ .null-tip-hidden{
display: none; display: none;
} }
/**选中样式偶然出现高度不够的情况*/
.CodeMirror-selected{
min-height: 19px !important;
}
} }
/* 全屏样式 */ /* 全屏样式 */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
:showTime="showTime" :showTime="showTime"
:format="dateFormat" :format="dateFormat"
:getCalendarContainer="getCalendarContainer" :getCalendarContainer="getCalendarContainer"
/> v-bind="$attrs"/>
</template> </template>
<script> <script>
import moment from 'moment' import moment from 'moment'
......
...@@ -158,7 +158,49 @@ export default { ...@@ -158,7 +158,49 @@ export default {
cronValue_c(newVal, oldVal) { cronValue_c(newVal, oldVal) {
this.calTriggerList() this.calTriggerList()
this.$emit('change', newVal) this.$emit('change', newVal)
this.assignInput()
},
minute() {
if (this.second === '*') {
this.second = '0'
}
},
hour() {
if (this.minute === '*') {
this.minute = '0'
}
},
day(day) {
if (day !== '?' && this.hour === '*') {
this.hour = '0'
}
},
week(week) {
if (week !== '?' && this.hour === '*') {
this.hour = '0'
}
},
month() {
if (this.day === '?' && this.week === '*') {
this.week = '1'
} else if (this.week === '?' && this.day === '*') {
this.day = '1'
}
},
year() {
if (this.month === '*') {
this.month = '1'
}
},
},
created() {
this.formatValue()
this.$nextTick(() => {
this.calTriggerListInner()
})
},
methods: {
assignInput() {
Object.assign(this.inputValues, { Object.assign(this.inputValues, {
second: this.second, second: this.second,
minute: this.minute, minute: this.minute,
...@@ -169,15 +211,7 @@ export default { ...@@ -169,15 +211,7 @@ export default {
year: this.year, year: this.year,
cron: this.cronValue_c, cron: this.cronValue_c,
}) })
} },
},
created() {
this.formatValue()
this.$nextTick(() => {
this.calTriggerListInner()
})
},
methods: {
formatValue() { formatValue() {
if (!this.cronValue) return if (!this.cronValue) return
const values = this.cronValue.split(' ').filter(item => !!item) const values = this.cronValue.split(' ').filter(item => !!item)
...@@ -190,6 +224,7 @@ export default { ...@@ -190,6 +224,7 @@ export default {
if (values.length > i) this.month = values[i++] if (values.length > i) this.month = values[i++]
if (values.length > i) this.week = values[i++] if (values.length > i) this.week = values[i++]
if (values.length > i) this.year = values[i] if (values.length > i) this.year = values[i]
this.assignInput()
}, },
calTriggerList: simpleDebounce(function () { calTriggerList: simpleDebounce(function () {
this.calTriggerListInner() this.calTriggerListInner()
......
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio> <a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio>
<div class="list"> <div class="list">
<a-checkbox-group v-model="valueList"> <a-checkbox-group v-model="valueList">
<template v-for="i in maxValue+1"> <template v-for="i of specifyRange">
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox> <a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</a-checkbox>
</template> </template>
</a-checkbox-group> </a-checkbox-group>
</div> </div>
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio> <a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
<div class="list"> <div class="list">
<a-checkbox-group v-model="valueList"> <a-checkbox-group v-model="valueList">
<template v-for="i in maxValue+1"> <template v-for="i in specifyRange">
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox> <a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</a-checkbox>
</template> </template>
</a-checkbox-group> </a-checkbox-group>
</div> </div>
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio> <a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
<div class="list"> <div class="list">
<a-checkbox-group v-model="valueList"> <a-checkbox-group v-model="valueList">
<template v-for="i in maxValue+1"> <template v-for="i in specifyRange">
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox> <a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</a-checkbox>
</template> </template>
</a-checkbox-group> </a-checkbox-group>
</div> </div>
......
...@@ -89,6 +89,9 @@ export default { ...@@ -89,6 +89,9 @@ export default {
result.push('L') result.push('L')
break break
case TYPE_SPECIFY: case TYPE_SPECIFY:
if (this.valueList.length === 0) {
this.valueList.push(this.minValue)
}
result.push(this.valueList.join(',')) result.push(this.valueList.join(','))
break break
default: default:
...@@ -96,7 +99,15 @@ export default { ...@@ -96,7 +99,15 @@ export default {
break break
} }
return result.length > 0 ? result.join('') : this.DEFAULT_VALUE return result.length > 0 ? result.join('') : this.DEFAULT_VALUE
} },
// 指定值范围区间,介于最小值和最大值之间
specifyRange() {
let range = []
for (let i = this.minValue; i <= this.maxValue; i++) {
range.push(i)
}
return range
},
}, },
methods: { methods: {
parseProp (value) { parseProp (value) {
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio> <a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
<div class="list"> <div class="list">
<a-checkbox-group v-model="valueList"> <a-checkbox-group v-model="valueList">
<template v-for="i in maxValue+1"> <template v-for="i of specifyRange">
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox> <a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</a-checkbox>
</template> </template>
</a-checkbox-group> </a-checkbox-group>
</div> </div>
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio> <a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
<div class="list"> <div class="list">
<a-checkbox-group v-model="valueList"> <a-checkbox-group v-model="valueList">
<template v-for="i in maxValue+1"> <template v-for="i in specifyRange">
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox> <a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</a-checkbox>
</template> </template>
</a-checkbox-group> </a-checkbox-group>
</div> </div>
......
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio> <a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio>
<div class="list"> <div class="list">
<a-checkbox-group v-model="valueList"> <a-checkbox-group v-model="valueList">
<template v-for="i in maxValue+1"> <template v-for="i in specifyRange">
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox> <a-checkbox class="list-check-item" :key="`key-${i}`" :value="i" :disabled="type!==TYPE_SPECIFY || disabled">{{i}}</a-checkbox>
</template> </template>
</a-checkbox-group> </a-checkbox-group>
</div> </div>
...@@ -51,13 +51,14 @@ import mixin from './mixin' ...@@ -51,13 +51,14 @@ import mixin from './mixin'
import { replaceWeekName, WEEK_MAP_EN } from './const.js' import { replaceWeekName, WEEK_MAP_EN } from './const.js'
const WEEK_MAP = { const WEEK_MAP = {
'周日': 0,
'周一': 1, '周一': 1,
'周二': 2, '周二': 2,
'周三': 3, '周三': 3,
'周四': 4, '周四': 4,
'周五': 5, '周五': 5,
'周六': 6 '周六': 6,
// 按照国人习惯,将周日放到每周的最后一天
'周日': 7,
} }
export default { export default {
...@@ -101,10 +102,10 @@ export default { ...@@ -101,10 +102,10 @@ export default {
created() { created() {
this.DEFAULT_VALUE = '*' this.DEFAULT_VALUE = '*'
// 0,7表示周日 1表示周一 // 0,7表示周日 1表示周一
this.minValue = 0 this.minValue = 1
this.maxValue = 6 this.maxValue = 7
this.valueRange.start = 0 this.valueRange.start = 1
this.valueRange.end = 6 this.valueRange.end = 7
this.valueLoop.start = 2 this.valueLoop.start = 2
this.valueLoop.interval = 1 this.valueLoop.interval = 1
this.parseProp(this.prop) this.parseProp(this.prop)
......
...@@ -134,9 +134,17 @@ ...@@ -134,9 +134,17 @@
}else{ }else{
//update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------ //update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------
let tabLayout = getVmParentByName(this, 'TabLayout') let tabLayout = getVmParentByName(this, 'TabLayout')
tabLayout.excuteCallback(()=>{ //update--begin--autor:liusq-----date:20210713------for:处理特殊情况excuteCallback不能使用------
this.reload() try {
}) tabLayout.excuteCallback(() => {
this.reload()
})
} catch (error) {
if (tabLayout) {
this.reload()
}
}
//update--end--autor:liusq-----date:20210713------for:处理特殊情况excuteCallback不能使用------
//update--begin--autor:wangshuai-----date:20200724------for:文本编辑器切换tab无法修改------ //update--begin--autor:wangshuai-----date:20200724------for:文本编辑器切换tab无法修改------
} }
}, },
......
<template>
<a-modal
ref="modal"
:class="getClass(modalClass)"
:style="getStyle(modalStyle)"
:visible="visible"
v-bind="_attrs"
v-on="$listeners"
@ok="handleOk"
@cancel="handleCancel"
destroyOnClose
>
<slot></slot>
<!--有设置标题-->
<template v-if="!isNoTitle" slot="title">
<a-row class="j-modal-title-row" type="flex">
<a-col class="left">
<slot name="title">{{ title }}</slot>
</a-col>
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
</a-col>
</a-row>
</template>
<!--没有设置标题-->
<template v-else slot="title">
<a-row class="j-modal-title-row" type="flex">
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
</a-col>
</a-row>
</template>
<!-- 处理 scopedSlots -->
<template v-for="slotName of scopedSlotsKeys" :slot="slotName">
<slot :name="slotName"></slot>
</template>
<!-- 处理 slots -->
<template v-for="slotName of slotsKeys" v-slot:[slotName]>
<slot :name="slotName"></slot>
</template>
</a-modal>
</template>
<script>
import { getClass, getStyle } from '@/utils/props-util'
import { triggerWindowResizeEvent } from '@/utils/util'
export default {
name: 'JModal',
props: {
title: String,
// 可使用 .sync 修饰符
visible: Boolean,
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
fullscreen: {
type: Boolean,
default: false
},
// 是否允许切换全屏(允许后右上角会出现一个按钮)
switchFullscreen: {
type: Boolean,
default: false
},
// 点击确定按钮的时候是否关闭弹窗
okClose: {
type: Boolean,
default: true
},
},
data() {
return {
// 内部使用的 slots ,不再处理
usedSlots: ['title'],
// 实际控制是否全屏的参数
innerFullscreen: this.fullscreen,
}
},
computed: {
// 一些未处理的参数或特殊处理的参数绑定到 a-modal 上
_attrs() {
let attrs = { ...this.$attrs }
// 如果全屏就将宽度设为 100%
if (this.innerFullscreen) {
attrs['width'] = '100%'
}
return attrs
},
modalClass() {
return {
'j-modal-box': true,
'fullscreen': this.innerFullscreen,
'no-title': this.isNoTitle,
'no-footer': this.isNoFooter,
}
},
modalStyle() {
let style = {}
// 如果全屏就将top设为 0
if (this.innerFullscreen) {
style['top'] = '0'
}
return style
},
isNoTitle() {
return !this.title && !this.allSlotsKeys.includes('title')
},
isNoFooter() {
return this._attrs['footer'] === null
},
slotsKeys() {
return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))
},
scopedSlotsKeys() {
return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
},
allSlotsKeys() {
return Object.keys(this.$slots).concat(Object.keys(this.$scopedSlots))
},
// 切换全屏的按钮图标
fullscreenButtonIcon() {
return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
},
},
watch: {
visible() {
if (this.visible) {
this.innerFullscreen = this.fullscreen
}
},
innerFullscreen(val) {
this.$emit('update:fullscreen', val)
},
},
methods: {
getClass(clazz) {
return { ...getClass(this), ...clazz }
},
getStyle(style) {
return { ...getStyle(this), ...style }
},
close() {
this.$emit('update:visible', false)
},
handleOk() {
if (this.okClose) {
this.close()
}
},
handleCancel() {
this.close()
},
/** 切换全屏 */
toggleFullscreen() {
this.innerFullscreen = !this.innerFullscreen
triggerWindowResizeEvent()
},
}
}
</script>
<style lang="less">
.j-modal-box {
&.fullscreen {
top: 0;
left: 0;
padding: 0;
// 兼容1.6.2版本的antdv
& .ant-modal {
top: 0;
padding: 0;
height: 100vh;
}
& .ant-modal-content {
height: 100vh;
border-radius: 0;
& .ant-modal-body {
/* title 和 footer 各占 55px */
height: calc(100% - 55px - 55px);
overflow: auto;
}
}
&.no-title, &.no-footer {
.ant-modal-body {
height: calc(100% - 55px);
}
}
&.no-title.no-footer {
.ant-modal-body {
height: 100%;
}
}
}
.j-modal-title-row {
.left {
width: calc(100% - 56px - 56px);
}
.right {
width: 56px;
position: inherit;
.ant-modal-close {
right: 56px;
color: rgba(0, 0, 0, 0.45);
&:hover {
color: rgba(0, 0, 0, 0.75);
}
}
}
}
&.no-title{
.ant-modal-header {
padding: 0px 24px;
border-bottom: 0px !important;
}
}
}
@media (max-width: 767px) {
.j-modal-box.fullscreen {
margin: 0;
max-width: 100vw;
}
}
</style>
\ No newline at end of file
<template>
<j-modal :visible="visible" :confirmLoading="loading" :after-close="afterClose" v-bind="modalProps" @ok="onOk" @cancel="onCancel">
<a-spin :spinning="loading">
<div v-html="content"></div>
<a-form-model ref="form" :model="model" :rules="rules">
<a-form-model-item prop="input">
<a-input ref="input" v-model="model.input" v-bind="inputProps" @pressEnter="onInputPressEnter"/>
</a-form-model-item>
</a-form-model>
</a-spin>
</j-modal>
</template>
<script>
import pick from 'lodash.pick'
export default {
name: 'JPrompt',
data() {
return {
visible: false,
loading: false,
content: '',
// 弹窗参数
modalProps: {
title: '',
},
inputProps: {
placeholder: '',
},
// form model
model: {
input: '',
},
// 校验
rule: [],
// 回调函数
callback: {},
}
},
computed: {
rules() {
return {
input: this.rule
}
},
},
methods: {
show(options) {
this.content = options.content
if (Array.isArray(options.rule)) {
this.rule = options.rule
}
if (options.defaultValue != null) {
this.model.input = options.defaultValue
}
// 取出常用的弹窗参数
let pickModalProps = pick(options, 'title', 'centered', 'cancelText', 'closable', 'mask', 'maskClosable', 'okText', 'okType', 'okButtonProps', 'cancelButtonProps', 'width', 'wrapClassName', 'zIndex', 'dialogStyle', 'dialogClass')
this.modalProps = Object.assign({}, pickModalProps, options.modalProps)
// 取出常用的input参数
let pickInputProps = pick(options, 'placeholder', 'allowClear')
this.inputProps = Object.assign({}, pickInputProps, options.inputProps)
// 回调函数
this.callback = pick(options, 'onOk', 'onOkAsync', 'onCancel')
this.visible = true
this.$nextTick(() => this.$refs.input.focus())
},
onOk() {
this.$refs.form.validate((ok, err) => {
if (ok) {
let event = {value: this.model.input, target: this}
// 异步方法优先级高于同步方法
if (typeof this.callback.onOkAsync === 'function') {
this.callback.onOkAsync(event)
} else if (typeof this.callback.onOk === 'function') {
this.callback.onOk(event)
this.close()
} else {
this.close()
}
}
})
},
onCancel() {
if (typeof this.callback.onCancel === 'function') {
this.callback.onCancel(this.model.input)
}
this.close()
},
onInputPressEnter() {
this.onOk()
},
close() {
this.visible = this.loading ? this.visible : false
},
forceClose() {
this.visible = false
},
showLoading() {
this.loading = true
},
hideLoading() {
this.loading = false
},
afterClose(e) {
if (typeof this.modalProps.afterClose === 'function') {
this.modalProps.afterClose(e)
}
this.$emit('after-close', e)
},
},
}
</script>
<style scoped>
</style>
\ No newline at end of file
import JModal from './JModal'
import JPrompt from './JPrompt'
export default {
install(Vue) {
Vue.component(JModal.name, JModal)
const JPromptExtend = Vue.extend(JPrompt)
Vue.prototype.$JPrompt = function (options = {}) {
// 创建prompt实例
const vm = new JPromptExtend().$mount()
vm.show(options)
// 关闭后销毁
vm.$on('after-close', () => vm.$destroy())
return vm
}
},
}
\ No newline at end of file
...@@ -173,9 +173,11 @@ ...@@ -173,9 +173,11 @@
let tempDestArr = [] let tempDestArr = []
for(let rw of rows){ for(let rw of rows){
let val = rw[orgFieldsArr[i]] let val = rw[orgFieldsArr[i]]
if(!val){ // update--begin--autor:liusq-----date:20210713------for:处理val等于0的情况issues/I3ZL4T------
if(typeof val=='undefined'|| val==null || val.toString()==""){
val = "" val = ""
} }
// update--end--autor:liusq-----date:20210713------for:处理val等于0的情况issues/I3ZL4T------
tempDestArr.push(val) tempDestArr.push(val)
} }
res[destFieldsArr[i]] = tempDestArr.join(",") res[destFieldsArr[i]] = tempDestArr.join(",")
......
<template> <template>
<a-select :value="arrayValue" @change="onChange" mode="multiple" :placeholder="placeholder"> <a-select :value="arrayValue" @change="onChange" mode="multiple" :placeholder="placeholder">
<a-select-option <a-select-option
v-for="(item,index) in options" v-for="(item,index) in selectOptions"
:key="index" :key="index"
:getPopupContainer="getParentContainer" :getPopupContainer="getParentContainer"
:value="item.value"> :value="item.value">
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
<script> <script>
//option {label:,value:} //option {label:,value:}
import { getAction } from '@api/manage'
export default { export default {
name: 'JSelectMultiple', name: 'JSelectMultiple',
props: { props: {
...@@ -31,7 +33,8 @@ ...@@ -31,7 +33,8 @@
}, },
options:{ options:{
type: Array, type: Array,
required: true default:()=>[],
required: false
}, },
triggerChange:{ triggerChange:{
type: Boolean, type: Boolean,
...@@ -48,12 +51,22 @@ ...@@ -48,12 +51,22 @@
default:'', default:'',
required:false required:false
}, },
dictCode:{
type:String,
required:false
},
}, },
data(){ data(){
return { return {
arrayValue:!this.value?[]:this.value.split(this.spliter) arrayValue:!this.value?[]:this.value.split(this.spliter),
dictOptions: [],
} }
}, },
computed:{
selectOptions(){
return this.dictOptions.length > 0 ? this.dictOptions : this.options
},
},
watch:{ watch:{
value (val) { value (val) {
if(!val){ if(!val){
...@@ -63,6 +76,11 @@ ...@@ -63,6 +76,11 @@
} }
} }
}, },
mounted(){
if (this.dictCode) {
this.loadDictOptions()
}
},
methods:{ methods:{
onChange (selectedValue) { onChange (selectedValue) {
if(this.triggerChange){ if(this.triggerChange){
...@@ -77,7 +95,18 @@ ...@@ -77,7 +95,18 @@
}else{ }else{
return document.querySelector(this.popContainer) return document.querySelector(this.popContainer)
} }
} },
// 根据字典code查询字典项
loadDictOptions(){
getAction(`/sys/dict/getDictItems/${this.dictCode}`,{}).then(res=>{
if (res.success) {
this.dictOptions = res.result.map(item => ({value: item.value, label: item.text}))
} else {
console.error('getDictItems error: : ', res)
this.dictOptions = []
}
})
},
}, },
} }
......
...@@ -412,8 +412,9 @@ ...@@ -412,8 +412,9 @@
this.queryParamsModel.splice(index, 1) this.queryParamsModel.splice(index, 1)
}, },
handleSelected(node, item) { handleSelected(node, item) {
let { type, options, dictCode, dictTable, dictText, customReturnField, popup } = node.dataRef let { type, dbType, options, dictCode, dictTable, dictText, customReturnField, popup } = node.dataRef
item['type'] = type item['type'] = type
item['dbType'] = dbType
item['options'] = options item['options'] = options
item['dictCode'] = dictCode item['dictCode'] = dictCode
item['dictTable'] = dictTable item['dictTable'] = dictTable
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
:headers="headers" :headers="headers"
:data="{'biz':bizPath}" :data="{'biz':bizPath}"
:fileList="fileList" :fileList="fileList"
:beforeUpload="beforeUpload" :beforeUpload="doBeforeUpload"
@change="handleChange" @change="handleChange"
:disabled="disabled" :disabled="disabled"
:returnUrl="returnUrl" :returnUrl="returnUrl"
...@@ -139,6 +139,9 @@ ...@@ -139,6 +139,9 @@
type: Boolean, type: Boolean,
default: true default: true
}, },
beforeUpload: {
type: Function
},
}, },
watch:{ watch:{
value:{ value:{
...@@ -242,7 +245,7 @@ ...@@ -242,7 +245,7 @@
} }
this.$emit('change', path); this.$emit('change', path);
}, },
beforeUpload(file){ doBeforeUpload(file){
this.uploadGoOn=true this.uploadGoOn=true
var fileType = file.type; var fileType = file.type;
if(this.fileType===FILE_TYPE_IMG){ if(this.fileType===FILE_TYPE_IMG){
...@@ -252,7 +255,10 @@ ...@@ -252,7 +255,10 @@
return false; return false;
} }
} }
//TODO 扩展功能验证文件大小 // 扩展 beforeUpload 验证
if (typeof this.beforeUpload === 'function') {
return this.beforeUpload(file)
}
return true return true
}, },
handleChange(info) { handleChange(info) {
......
...@@ -668,7 +668,11 @@ export default { ...@@ -668,7 +668,11 @@ export default {
async loadNewData(dataSource) { async loadNewData(dataSource) {
if (Array.isArray(dataSource)) { if (Array.isArray(dataSource)) {
let {xTable} = this.$refs.vxe.$refs let {xTable} = this.$refs.vxe.$refs
return await xTable.loadData(dataSource) // issues/2784
// 先清空所有数据
xTable.loadData([])
// 再新增
return xTable.insertAt(dataSource)
} }
return [] return []
}, },
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<a-tooltip v-else-if="file.status === 'done'" title="上传完成"> <a-tooltip v-else-if="file.status === 'done'" title="上传完成">
<a-icon type="check-circle" style="color:#00DB00;"/> <a-icon type="check-circle" style="color:#00DB00;"/>
</a-tooltip> </a-tooltip>
<a-tooltip v-else title="上传失败"> <a-tooltip v-else :title="file.message||'上传失败'">
<a-icon type="exclamation-circle" style="color:red;"/> <a-icon type="exclamation-circle" style="color:red;"/>
</a-tooltip> </a-tooltip>
</template> </template>
...@@ -118,8 +118,17 @@ ...@@ -118,8 +118,17 @@
value['responseName'] = file.response[col.responseName] value['responseName'] = file.response[col.responseName]
} }
if (file.status === 'done') { if (file.status === 'done') {
value['path'] = file.response[col.responseName] if (typeof file.response.success === 'boolean') {
this.handleChangeCommon(value) if (file.response.success) {
value['path'] = file.response[col.responseName]
} else {
value['status'] = 'error'
value['message'] = file.response.message || '未知错误'
}
} else {
// 考虑到如果设置action上传路径为非jeecg-boot后台,可能不会返回 success 属性的情况,就默认为成功
value['path'] = file.response[col.responseName]
}
} else if (file.status === 'error') { } else if (file.status === 'error') {
value['message'] = file.response.message || '未知错误' value['message'] = file.response.message || '未知错误'
} }
......
...@@ -26,19 +26,24 @@ import JSlider from './JSlider.vue' ...@@ -26,19 +26,24 @@ import JSlider from './JSlider.vue'
import JSwitch from './JSwitch.vue' import JSwitch from './JSwitch.vue'
import JTime from './JTime.vue' import JTime from './JTime.vue'
import JTreeTable from './JTreeTable.vue' import JTreeTable from './JTreeTable.vue'
import JEasyCron from "@/components/jeecg/JEasyCron"; import JEasyCron from '@/components/jeecg/JEasyCron'
//jeecgbiz //jeecgbiz
import JSelectDepart from '../jeecgbiz/JSelectDepart.vue' import JSelectDepart from '../jeecgbiz/JSelectDepart.vue'
import JSelectMultiUser from '../jeecgbiz/JSelectMultiUser.vue' import JSelectMultiUser from '../jeecgbiz/JSelectMultiUser.vue'
import JSelectPosition from '../jeecgbiz/JSelectPosition.vue' import JSelectPosition from '../jeecgbiz/JSelectPosition.vue'
import JSelectRole from '../jeecgbiz/JSelectRole.vue' import JSelectRole from '../jeecgbiz/JSelectRole.vue'
import JSelectUserByDep from '../jeecgbiz/JSelectUserByDep.vue' import JSelectUserByDep from '../jeecgbiz/JSelectUserByDep.vue'
//引入需要全局注册的js函数和变量
import { Modal, notification,message } from 'ant-design-vue'
import lodash_object from 'lodash'
import debounce from 'lodash/debounce'
import pick from 'lodash.pick'
import data from 'china-area-data'
export default { export default {
install(Vue) { install(Vue) {
Vue.use(JModal)
Vue.component('JMarkdownEditor', JMarkdownEditor) Vue.component('JMarkdownEditor', JMarkdownEditor)
Vue.component(JModal.name, JModal)
Vue.component('JPopupOnlReport', JPopupOnlReport) Vue.component('JPopupOnlReport', JPopupOnlReport)
Vue.component('JFilePop', JFilePop) Vue.component('JFilePop', JFilePop)
Vue.component('JInputPop', JInputPop) Vue.component('JInputPop', JInputPop)
...@@ -73,5 +78,14 @@ export default { ...@@ -73,5 +78,14 @@ export default {
Vue.component('JSelectRole', JSelectRole) Vue.component('JSelectRole', JSelectRole)
Vue.component('JSelectUserByDep', JSelectUserByDep) Vue.component('JSelectUserByDep', JSelectUserByDep)
Vue.component(JEasyCron.name, JEasyCron) Vue.component(JEasyCron.name, JEasyCron)
//注册全局js函数和变量
Vue.prototype.$Jnotification = notification
Vue.prototype.$Jmodal = Modal
Vue.prototype.$Jmessage = message
Vue.prototype.$Jlodash = lodash_object
Vue.prototype.$Jdebounce= debounce
Vue.prototype.$Jpick = pick
Vue.prototype.$Jpcaa = data
} }
} }
\ No newline at end of file
...@@ -137,8 +137,12 @@ ...@@ -137,8 +137,12 @@
param:{ param:{
deep:true, deep:true,
handler(){ handler(){
this.dynamicParamHandler() // update--begin--autor:liusq-----date:20210706------for:JPopup组件在modal中使用报错#2729------
this.loadData(); if(this.visible){
this.dynamicParamHandler()
this.loadData();
}
// update--begin--autor:liusq-----date:20210706------for:JPopup组件在modal中使用报错#2729------
}, },
}, },
sorter: { sorter: {
......
<template> <template>
<div class="components-input-demo-presuffix"> <div class="components-input-demo-presuffix">
<!----> <!---->
<a-input @click="openModal" placeholder="请点击选择部门" v-model="departNames" readOnly :disabled="disabled"> <a-input @click="openModal" placeholder="请点击选择部门" v-model="textVals" readOnly :disabled="disabled">
<a-icon slot="prefix" type="cluster" title="部门选择控件"/> <a-icon slot="prefix" type="cluster" title="部门选择控件"/>
<a-icon v-if="departIds" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/> <a-icon v-if="storeVals" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
</a-input> </a-input>
<j-select-depart-modal <j-select-depart-modal
...@@ -11,7 +11,10 @@ ...@@ -11,7 +11,10 @@
:modal-width="modalWidth" :modal-width="modalWidth"
:multi="multi" :multi="multi"
:rootOpened="rootOpened" :rootOpened="rootOpened"
:depart-id="departIds" :depart-id="value"
:store="storeField"
:text="textField"
:treeOpera="treeOpera"
@ok="handleOK" @ok="handleOK"
@initComp="initComp"/> @initComp="initComp"/>
</div> </div>
...@@ -19,6 +22,7 @@ ...@@ -19,6 +22,7 @@
<script> <script>
import JSelectDepartModal from './modal/JSelectDepartModal' import JSelectDepartModal from './modal/JSelectDepartModal'
import { underLinetoHump } from '@/components/_util/StringUtil'
export default { export default {
name: 'JSelectDepart', name: 'JSelectDepart',
components:{ components:{
...@@ -52,56 +56,70 @@ ...@@ -52,56 +56,70 @@
// 自定义返回字段,默认返回 id // 自定义返回字段,默认返回 id
customReturnField: { customReturnField: {
type: String, type: String,
default: 'id' default: ''
}, },
backDepart: { backDepart: {
type: Boolean, type: Boolean,
default: false, default: false,
required: false required: false
},
// 存储字段 [key field]
store: {
type: String,
default: 'id',
required: false
},
// 显示字段 [label field]
text: {
type: String,
default: 'departName',
required: false
},
treeOpera: {
type: Boolean,
default: false,
required: false
} }
}, },
data(){ data(){
return { return {
visible:false, visible:false,
confirmLoading:false, confirmLoading:false,
departNames:"", storeVals: '', //[key values]
departIds:'' textVals: '' //[label values]
}
},
computed:{
storeField(){
let field = this.customReturnField
if(!field){
field = this.store;
}
return underLinetoHump(field)
},
textField(){
return underLinetoHump(this.text)
} }
}, },
mounted(){ mounted(){
this.departIds = this.value this.storeVals = this.value
}, },
watch:{ watch:{
value(val){ value(val){
//update-begin-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2 this.storeVals = val
// if (this.customReturnField === 'id') {
this.departIds = val
// }
//update-end-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2
} }
}, },
methods:{ methods:{
initComp(departNames){ initComp(textVals){
this.departNames = departNames this.textVals = textVals
//update-begin-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
//TODO 当返回字段为部门名称时会有问题,因为部门名称不唯一
//返回字段不为id时,根据返回字段获取id
if(this.customReturnField !== 'id' && this.value){
const dataList = this.$refs.innerDepartSelectModal.dataList;
console.log('this.value',this.value)
this.departIds = this.value.split(',').map(item => {
const data = dataList.filter(d=>d[this.customReturnField] === item)
return data.length > 0 ? data[0].id : ''
}).join(',')
}
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
}, },
//返回选中的部门信息 //返回选中的部门信息
backDeparInfo(){ backDeparInfo(){
if(this.backDepart===true){ if(this.backDepart===true){
if(this.departIds && this.departIds.length>0){ if(this.departIds && this.departIds.length>0){
let arr1 = this.departIds.split(',') let arr1 = this.storeVals.split(',')
let arr2 = this.departNames.split(',') let arr2 = this.textVals.split(',')
let info = [] let info = []
for(let i=0;i<arr1.length;i++){ for(let i=0;i<arr1.length;i++){
info.push({ info.push({
...@@ -116,17 +134,21 @@ ...@@ -116,17 +134,21 @@
openModal(){ openModal(){
this.$refs.innerDepartSelectModal.show() this.$refs.innerDepartSelectModal.show()
}, },
handleOK(rows, idstr) { handleOK(rows) {
let value = ''
if (!rows && rows.length <= 0) { if (!rows && rows.length <= 0) {
this.departNames = '' this.textVals = ''
this.departIds = '' this.storeVals = ''
} else { } else {
value = rows.map(row => row[this.customReturnField]).join(',') let arr1 = []
this.departNames = rows.map(row => row['departName']).join(',') let arr2 = []
this.departIds = idstr for(let dep of rows){
arr1.push(dep[this.storeField])
arr2.push(dep[this.textField])
}
this.storeVals = arr1.join(',')
this.textVals = arr2.join(',')
} }
this.$emit("change", value) this.$emit("change", this.storeVals)
this.backDeparInfo() this.backDeparInfo()
}, },
getDepartNames(){ getDepartNames(){
......
<template> <template>
<div> <div>
<a-input-search <a-input-search
v-model="userNames" v-model="textVals"
placeholder="请先选择用户" placeholder="请先选择用户"
readOnly readOnly
unselectable="on" unselectable="on"
@search="onSearchDepUser"> @search="onSearchDepUser">
<a-button slot="enterButton" :disabled="disabled">选择用户</a-button> <a-button slot="enterButton" :disabled="disabled">选择用户</a-button>
</a-input-search> </a-input-search>
<j-select-user-by-dep-modal ref="selectModal" :modal-width="modalWidth" :multi="multi" @ok="selectOK" :user-ids="value" @initComp="initComp"/> <j-select-user-by-dep-modal
ref="selectModal"
:modal-width="modalWidth"
:multi="multi"
@ok="selectOK"
:user-ids="value"
:store="storeField"
:text="textField"
@initComp="initComp"/>
</div> </div>
</template> </template>
<script> <script>
import JSelectUserByDepModal from './modal/JSelectUserByDepModal' import JSelectUserByDepModal from './modal/JSelectUserByDepModal'
import { underLinetoHump } from '@/components/_util/StringUtil'
export default { export default {
name: 'JSelectUserByDep', name: 'JSelectUserByDep',
...@@ -42,20 +51,44 @@ ...@@ -42,20 +51,44 @@
type: Boolean, type: Boolean,
default: false, default: false,
required: false required: false
},
// 存储字段 [key field]
store: {
type: String,
default: 'username',
required: false
},
// 显示字段 [label field]
text: {
type: String,
default: 'realname',
required: false
} }
}, },
data() { data() {
return { return {
userIds: "", storeVals: '', //[key values]
userNames: "" textVals: '' //[label values]
}
},
computed:{
storeField(){
let field = this.customReturnField
if(!field){
field = this.store;
}
return underLinetoHump(field)
},
textField(){
return underLinetoHump(this.text)
} }
}, },
mounted() { mounted() {
this.userIds = this.value this.storeVals = this.value
}, },
watch: { watch: {
value(val) { value(val) {
this.userIds = val this.storeVals = val
} }
}, },
model: { model: {
...@@ -63,15 +96,15 @@ ...@@ -63,15 +96,15 @@
event: 'change' event: 'change'
}, },
methods: { methods: {
initComp(userNames) { initComp(textVals) {
this.userNames = userNames this.textVals = textVals
}, },
//返回选中的用户信息 //返回选中的用户信息
backDeparInfo(){ backDeparInfo(){
if(this.backUser===true){ if(this.backUser===true){
if(this.userIds && this.userIds.length>0){ if(this.storeVals && this.storeVals.length>0){
let arr1 = this.userIds.split(',') let arr1 = this.storeVals.split(',')
let arr2 = this.userNames.split(',') let arr2 = this.textVals.split(',')
let info = [] let info = []
for(let i=0;i<arr1.length;i++){ for(let i=0;i<arr1.length;i++){
info.push({ info.push({
...@@ -86,21 +119,22 @@ ...@@ -86,21 +119,22 @@
onSearchDepUser() { onSearchDepUser() {
this.$refs.selectModal.showModal() this.$refs.selectModal.showModal()
}, },
selectOK(rows, idstr) { selectOK(rows) {
console.log("当前选中用户", rows) console.log("当前选中用户", rows)
console.log("当前选中用户ID", idstr)
if (!rows) { if (!rows) {
this.userNames = '' this.storeVals = ''
this.userIds = '' this.textVals = ''
} else { } else {
let temp = '' let temp1 = []
let temp2 = []
for (let item of rows) { for (let item of rows) {
temp += ',' + item.realname temp1.push(item[this.storeField])
temp2.push(item[this.textField])
} }
this.userNames = temp.substring(1) this.storeVals = temp1.join(',')
this.userIds = idstr this.textVals = temp2.join(',')
} }
this.$emit("change", this.userIds) this.$emit("change", this.storeVals)
} }
} }
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
:confirmLoading="confirmLoading" :confirmLoading="confirmLoading"
@ok="handleSubmit" @ok="handleSubmit"
@cancel="handleCancel" @cancel="handleCancel"
@update:fullscreen="isFullscreen"
wrapClassName="j-depart-select-modal" wrapClassName="j-depart-select-modal"
switchFullscreen switchFullscreen
cancelText="关闭"> cancelText="关闭">
...@@ -13,9 +14,9 @@ ...@@ -13,9 +14,9 @@
<a-input-search style="margin-bottom: 1px" placeholder="请输入部门名称按回车进行搜索" @search="onSearch" /> <a-input-search style="margin-bottom: 1px" placeholder="请输入部门名称按回车进行搜索" @search="onSearch" />
<a-tree <a-tree
checkable checkable
class="my-dept-select-tree" :class="treeScreenClass"
:treeData="treeData" :treeData="treeData"
:checkStrictly="true" :checkStrictly="checkStrictly"
@check="onCheck" @check="onCheck"
@select="onSelect" @select="onSelect"
@expand="onExpand" @expand="onExpand"
...@@ -32,8 +33,23 @@ ...@@ -32,8 +33,23 @@
<span v-else>{{title}}</span> <span v-else>{{title}}</span>
</template> </template>
</a-tree> </a-tree>
</a-spin> </a-spin>
<!--底部父子关联操作和确认取消按钮-->
<template slot="footer" v-if="treeOpera && multi">
<div class="drawer-bootom-button">
<a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
<a-menu slot="overlay">
<a-menu-item key="1" @click="switchCheckStrictly(1)">父子关联</a-menu-item>
<a-menu-item key="2" @click="switchCheckStrictly(2)">取消关联</a-menu-item>
</a-menu>
<a-button>
树操作 <a-icon type="up" />
</a-button>
</a-dropdown>
<a-button @click="handleCancel" type="primary" style="margin-right: 0.8rem">关闭</a-button>
<a-button @click="handleSubmit" type="primary" >确认</a-button>
</div>
</template>
</j-modal> </j-modal>
</template> </template>
...@@ -41,7 +57,7 @@ ...@@ -41,7 +57,7 @@
import { queryDepartTreeList } from '@/api/api' import { queryDepartTreeList } from '@/api/api'
export default { export default {
name: 'JSelectDepartModal', name: 'JSelectDepartModal',
props:['modalWidth','multi','rootOpened','departId'], props:['modalWidth','multi','rootOpened','departId', 'store', 'text','treeOpera'],
data(){ data(){
return { return {
visible:false, visible:false,
...@@ -52,7 +68,9 @@ ...@@ -52,7 +68,9 @@
dataList:[], dataList:[],
checkedKeys:[], checkedKeys:[],
checkedRows:[], checkedRows:[],
searchValue:"" searchValue:"",
checkStrictly: true,
fullscreen:false
} }
}, },
created(){ created(){
...@@ -64,15 +82,18 @@ ...@@ -64,15 +82,18 @@
}, },
visible: { visible: {
handler() { handler() {
if (this.departId) { this.initDepartComponent(true)
this.checkedKeys = this.departId.split(",");
// console.log('this.departId', this.departId)
} else {
this.checkedKeys = [];
}
} }
} }
}, },
computed:{
treeScreenClass() {
return {
'my-dept-select-tree': true,
'fullscreen': this.fullscreen,
}
},
},
methods:{ methods:{
show(){ show(){
this.visible=true this.visible=true
...@@ -80,6 +101,7 @@ ...@@ -80,6 +101,7 @@
this.checkedKeys=[] this.checkedKeys=[]
}, },
loadDepart(){ loadDepart(){
// 这个方法是找到所有的部门信息
queryDepartTreeList().then(res=>{ queryDepartTreeList().then(res=>{
if(res.success){ if(res.success){
let arr = [...res.result] let arr = [...res.result]
...@@ -92,20 +114,23 @@ ...@@ -92,20 +114,23 @@
} }
}) })
}, },
initDepartComponent(){ initDepartComponent(flag){
let names = '' let arr = []
//该方法两个地方用 1.visible改变事件重新设置选中项 2.组件编辑页面回显
let fieldName = flag==true?'key':this.text
if(this.departId){ if(this.departId){
let currDepartId = this.departId let arr2 = this.departId.split(',')
for(let item of this.dataList){ for(let item of this.dataList){
if(currDepartId.indexOf(item.key)>=0){ if(arr2.indexOf(item[this.store])>=0){
names+=","+item.title arr.push(item[fieldName])
} }
} }
if(names){
names = names.substring(1)
}
} }
this.$emit("initComp",names) if(flag==true){
this.checkedKeys = [...arr]
}else{
this.$emit("initComp", arr.join(','))
}
}, },
reWriterWithSlot(arr){ reWriterWithSlot(arr){
for(let item of arr){ for(let item of arr){
...@@ -129,8 +154,11 @@ ...@@ -129,8 +154,11 @@
} }
} }
this.expandedKeys=[...keys] this.expandedKeys=[...keys]
//全部keys
//this.allTreeKeys = [...keys]
}else{ }else{
this.expandedKeys=[] this.expandedKeys=[]
//this.allTreeKeys = []
} }
}, },
onCheck (checkedKeys,info) { onCheck (checkedKeys,info) {
...@@ -139,25 +167,32 @@ ...@@ -139,25 +167,32 @@
this.checkedKeys = [...arr] this.checkedKeys = [...arr]
this.checkedRows = (this.checkedKeys.length === 0) ? [] : [info.node.dataRef] this.checkedRows = (this.checkedKeys.length === 0) ? [] : [info.node.dataRef]
}else{ }else{
this.checkedKeys = checkedKeys.checked if(this.checkStrictly){
this.checkedKeys = checkedKeys.checked
}else{
this.checkedKeys = checkedKeys
}
this.checkedRows = this.getCheckedRows(this.checkedKeys) this.checkedRows = this.getCheckedRows(this.checkedKeys)
} }
}, },
onSelect(selectedKeys,info) { onSelect(selectedKeys,info) {
let keys = [] //取消关联的情况下才走onSelect的逻辑
keys.push(selectedKeys[0]) if(this.checkStrictly){
if(!this.checkedKeys || this.checkedKeys.length===0 || !this.multi){ let keys = []
this.checkedKeys = [...keys] keys.push(selectedKeys[0])
this.checkedRows=[info.node.dataRef] if(!this.checkedKeys || this.checkedKeys.length===0 || !this.multi){
}else{ this.checkedKeys = [...keys]
let currKey = info.node.dataRef.key this.checkedRows=[info.node.dataRef]
if(this.checkedKeys.indexOf(currKey)>=0){
this.checkedKeys = this.checkedKeys.filter(item=> item !==currKey)
}else{ }else{
this.checkedKeys.push(...keys) let currKey = info.node.dataRef.key
if(this.checkedKeys.indexOf(currKey)>=0){
this.checkedKeys = this.checkedKeys.filter(item=> item !==currKey)
}else{
this.checkedKeys.push(...keys)
}
} }
this.checkedRows = this.getCheckedRows(this.checkedKeys)
} }
this.checkedRows = this.getCheckedRows(this.checkedKeys)
}, },
onExpand (expandedKeys) { onExpand (expandedKeys) {
this.expandedKeys = expandedKeys this.expandedKeys = expandedKeys
...@@ -235,6 +270,16 @@ ...@@ -235,6 +270,16 @@
} }
} }
return rows return rows
},
switchCheckStrictly (v) {
if(v==1){
this.checkStrictly = false
}else if(v==2){
this.checkStrictly = true
}
},
isFullscreen(val){
this.fullscreen=val
} }
} }
} }
...@@ -244,8 +289,22 @@ ...@@ -244,8 +289,22 @@
<style lang="less" scoped> <style lang="less" scoped>
// 限制部门选择树高度,避免部门太多时点击确定不便 // 限制部门选择树高度,避免部门太多时点击确定不便
.my-dept-select-tree{ .my-dept-select-tree{
height: 350px; height:350px;
&.fullscreen{
height: calc(100vh - 250px);
}
overflow-y: scroll; overflow-y: scroll;
} }
.drawer-bootom-button {
position: absolute;
bottom: 0;
width: 100%;
border-top: 1px solid #e8e8e8;
padding: 10px 16px;
text-align: right;
left: 0;
background: #fff;
border-radius: 0 0 2px 2px;
}
</style> </style>
\ No newline at end of file
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
export default { export default {
name: 'JSelectUserByDepModal', name: 'JSelectUserByDepModal',
components: {}, components: {},
props: ['modalWidth', 'multi', 'userIds'], props: ['modalWidth', 'multi', 'userIds', 'store', 'text'],
data() { data() {
return { return {
queryParam: { queryParam: {
...@@ -159,27 +159,27 @@ ...@@ -159,27 +159,27 @@
if (this.userIds) { if (this.userIds) {
// 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确 // 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确
let values = this.userIds.split(',') + ',' let values = this.userIds.split(',') + ','
getUserList({ let param = {[this.store]: values}
username: values, getAction('/sys/user/getMultiUser', param).then((list)=>{
pageNo: 1, this.selectionRows = []
pageSize: values.length let selectedRowKeys = []
}).then((res) => { let textArray = []
if (res.success) { if(list && list.length>0){
this.selectionRows = [] for(let user of list){
let selectedRowKeys = [] textArray.push(user[this.text])
let realNames = []
res.result.records.forEach(user => {
realNames.push(user['realname'])
selectedRowKeys.push(user['id']) selectedRowKeys.push(user['id'])
this.selectionRows.push(user) this.selectionRows.push(user)
}) }
this.selectedRowKeys = selectedRowKeys
this.$emit('initComp', realNames.join(','))
} }
this.selectedRowKeys = selectedRowKeys
this.$emit('initComp', textArray.join(','))
}) })
} else { } else {
// JSelectUserByDep组件bug issues/I16634 // JSelectUserByDep组件bug issues/I16634
this.$emit('initComp', '') this.$emit('initComp', '')
// 前端用户选择单选无法置空的问题 #2610
this.selectedRowKeys = []
} }
}, },
async loadData(arg) { async loadData(arg) {
...@@ -254,7 +254,7 @@ ...@@ -254,7 +254,7 @@
handleSubmit() { handleSubmit() {
let that = this; let that = this;
this.getSelectUserRows(); this.getSelectUserRows();
that.$emit('ok', that.selectUserRows, that.selectUserIds); that.$emit('ok', that.selectUserRows);
that.searchReset(0) that.searchReset(0)
that.close(); that.close();
}, },
......
<template> <template>
<div class="logo"> <div class="logo">
<router-link :to="{name:'dashboard'}"> <router-link :to="routerLinkTo">
<!-- update-begin- author:sunjianlei --- date:20190814 --- for: logo颜色根据主题颜色变化 --> <!-- update-begin- author:sunjianlei --- date:20190814 --- for: logo颜色根据主题颜色变化 -->
<img v-if="navTheme === 'dark'" src="~@/assets/logo-white.png" alt="logo"> <img v-if="navTheme === 'dark'" src="~@/assets/logo-white.png" alt="logo">
...@@ -28,7 +28,12 @@ ...@@ -28,7 +28,12 @@
type: Boolean, type: Boolean,
default: true, default: true,
required: false required: false
} },
// 点击Logo跳转地址
routerLinkTo: {
type: Object,
default: () => ({name: 'dashboard'}),
},
} }
} }
</script> </script>
......
...@@ -348,6 +348,21 @@ export const constantRouterMap = [ ...@@ -348,6 +348,21 @@ export const constantRouterMap = [
// }, // },
{ {
// OAuth2 APP页面路由
path: '/oauth2-app',
component: BlankLayout,
redirect: '/oauth2-app/login',
children: [
{
// OAuth2 登录路由
path: 'login',
name: 'login',
component: () => import(/* webpackChunkName: "oauth2-app.login" */ '@/views/user/oauth2/OAuth2Login')
},
]
},
{
path: '/test', path: '/test',
component: BlankLayout, component: BlankLayout,
redirect: '/test/home', redirect: '/test/home',
......
...@@ -8,7 +8,6 @@ import { deleteAction, getAction,downFile,getFileAccessHttpUrl } from '@/api/man ...@@ -8,7 +8,6 @@ import { deleteAction, getAction,downFile,getFileAccessHttpUrl } from '@/api/man
import Vue from 'vue' import Vue from 'vue'
import { ACCESS_TOKEN, TENANT_ID } from "@/store/mutation-types" import { ACCESS_TOKEN, TENANT_ID } from "@/store/mutation-types"
import store from '@/store' import store from '@/store'
import {Modal} from 'ant-design-vue'
export const JeecgListMixin = { export const JeecgListMixin = {
data(){ data(){
...@@ -94,11 +93,11 @@ export const JeecgListMixin = { ...@@ -94,11 +93,11 @@ export const JeecgListMixin = {
this.ipagination.total = 0; this.ipagination.total = 0;
} }
//update-end---author:zhangyafei Date:20201118 for:适配不分页的数据列表------------ //update-end---author:zhangyafei Date:20201118 for:适配不分页的数据列表------------
} }else{
if(res.code===510){
this.$message.warning(res.message) this.$message.warning(res.message)
} }
this.loading = false; }).finally(() => {
this.loading = false
}) })
}, },
initDictConfig(){ initDictConfig(){
...@@ -296,10 +295,12 @@ export const JeecgListMixin = { ...@@ -296,10 +295,12 @@ export const JeecgListMixin = {
}, },
/* 导入 */ /* 导入 */
handleImportExcel(info){ handleImportExcel(info){
this.loading = true;
if (info.file.status !== 'uploading') { if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList); console.log(info.file, info.fileList);
} }
if (info.file.status === 'done') { if (info.file.status === 'done') {
this.loading = false;
if (info.file.response.success) { if (info.file.response.success) {
// this.$message.success(`${info.file.name} 文件上传成功`); // this.$message.success(`${info.file.name} 文件上传成功`);
if (info.file.response.code === 201) { if (info.file.response.code === 201) {
...@@ -321,11 +322,12 @@ export const JeecgListMixin = { ...@@ -321,11 +322,12 @@ export const JeecgListMixin = {
this.$message.error(`${info.file.name} ${info.file.response.message}.`); this.$message.error(`${info.file.name} ${info.file.response.message}.`);
} }
} else if (info.file.status === 'error') { } else if (info.file.status === 'error') {
this.loading = false;
if (info.file.response.status === 500) { if (info.file.response.status === 500) {
let data = info.file.response let data = info.file.response
const token = Vue.ls.get(ACCESS_TOKEN) const token = Vue.ls.get(ACCESS_TOKEN)
if (token && data.message.includes("Token失效")) { if (token && data.message.includes("Token失效")) {
Modal.error({ this.$error({
title: '登录已过期', title: '登录已过期',
content: '很抱歉,登录已过期,请重新登录', content: '很抱歉,登录已过期,请重新登录',
okText: '重新登录', okText: '重新登录',
......
import { formatDate } from '@/utils/util' import { formatDate } from '@/utils/util'
import Area from '@/components/_util/Area' import Area from '@/components/_util/Area'
import { postAction } from '@/api/manage'
const onlUtil = { const onlUtil = {
data(){ data(){
return { return {
mixin_pca:'' mixin_pca:'',
flowCodePre: 'onl_'
} }
}, },
created(){ created(){
this.mixin_pca = new Area() this.mixin_pca = new Area(this.$Jpcaa)
}, },
methods:{ methods:{
simpleDateFormat(millisecond, format){ simpleDateFormat(millisecond, format){
......
...@@ -4,19 +4,20 @@ import store from './store' ...@@ -4,19 +4,20 @@ import store from './store'
import NProgress from 'nprogress' // progress bar import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style import 'nprogress/nprogress.css' // progress bar style
import notification from 'ant-design-vue/es/notification' import notification from 'ant-design-vue/es/notification'
import { ACCESS_TOKEN,INDEX_MAIN_PAGE_PATH } from '@/store/mutation-types' import { ACCESS_TOKEN,INDEX_MAIN_PAGE_PATH, OAUTH2_LOGIN_PAGE_PATH } from '@/store/mutation-types'
import { generateIndexRouter } from "@/utils/util" import { generateIndexRouter, isOAuth2AppEnv } from '@/utils/util'
NProgress.configure({ showSpinner: false }) // NProgress Configuration NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/user/login', '/user/register', '/user/register-result','/user/alteration'] // no redirect whitelist const whiteList = ['/user/login', '/user/register', '/user/register-result','/user/alteration'] // no redirect whitelist
whiteList.push(OAUTH2_LOGIN_PAGE_PATH)
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar NProgress.start() // start progress bar
if (Vue.ls.get(ACCESS_TOKEN)) { if (Vue.ls.get(ACCESS_TOKEN)) {
/* has token */ /* has token */
if (to.path === '/user/login') { if (to.path === '/user/login' || to.path === OAUTH2_LOGIN_PAGE_PATH) {
next({ path: INDEX_MAIN_PAGE_PATH }) next({ path: INDEX_MAIN_PAGE_PATH })
NProgress.done() NProgress.done()
} else { } else {
...@@ -59,10 +60,18 @@ router.beforeEach((to, from, next) => { ...@@ -59,10 +60,18 @@ router.beforeEach((to, from, next) => {
} }
} else { } else {
if (whiteList.indexOf(to.path) !== -1) { if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入 // 在免登录白名单,如果进入的页面是login页面并且当前是OAuth2app环境,就进入OAuth2登录页面
next() if (to.path === '/user/login' && isOAuth2AppEnv()) {
next({path: OAUTH2_LOGIN_PAGE_PATH})
} else {
// 在免登录白名单,直接进入
next()
}
NProgress.done()
} else { } else {
next({ path: '/user/login', query: { redirect: to.fullPath } }) // 如果当前是在OAuth2APP环境,就跳转到OAuth2登录页面
let path = isOAuth2AppEnv() ? OAUTH2_LOGIN_PAGE_PATH : '/user/login'
next({ path: path, query: { redirect: to.fullPath } })
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
} }
} }
......
...@@ -4,8 +4,6 @@ import Vuex from 'vuex' ...@@ -4,8 +4,6 @@ import Vuex from 'vuex'
import app from './modules/app' import app from './modules/app'
import user from './modules/user' import user from './modules/user'
import permission from './modules/permission' import permission from './modules/permission'
import enhance from './modules/enhance'
import online from './modules/online'
import getters from './getters' import getters from './getters'
Vue.use(Vuex) Vue.use(Vuex)
...@@ -15,8 +13,6 @@ export default new Vuex.Store({ ...@@ -15,8 +13,6 @@ export default new Vuex.Store({
app, app,
user, user,
permission, permission,
enhance,
online
}, },
state: { state: {
......
...@@ -159,6 +159,7 @@ const user = { ...@@ -159,6 +159,7 @@ const user = {
Vue.ls.remove(USER_NAME) Vue.ls.remove(USER_NAME)
Vue.ls.remove(UI_CACHE_DB_DICT_DATA) Vue.ls.remove(UI_CACHE_DB_DICT_DATA)
Vue.ls.remove(CACHE_INCLUDED_ROUTES) Vue.ls.remove(CACHE_INCLUDED_ROUTES)
Vue.ls.remove(TENANT_ID)
//console.log('logoutToken: '+ logoutToken) //console.log('logoutToken: '+ logoutToken)
logout(logoutToken).then(() => { logout(logoutToken).then(() => {
if (process.env.VUE_APP_SSO == 'true') { if (process.env.VUE_APP_SSO == 'true') {
......
...@@ -17,6 +17,7 @@ export const ENCRYPTED_STRING = 'ENCRYPTED_STRING' ...@@ -17,6 +17,7 @@ export const ENCRYPTED_STRING = 'ENCRYPTED_STRING'
export const ENHANCE_PRE = 'enhance_' export const ENHANCE_PRE = 'enhance_'
export const UI_CACHE_DB_DICT_DATA = 'UI_CACHE_DB_DICT_DATA' export const UI_CACHE_DB_DICT_DATA = 'UI_CACHE_DB_DICT_DATA'
export const INDEX_MAIN_PAGE_PATH = '/dashboard/analysis' export const INDEX_MAIN_PAGE_PATH = '/dashboard/analysis'
export const OAUTH2_LOGIN_PAGE_PATH = '/oauth2-app/login'
export const TENANT_ID = 'TENANT_ID' export const TENANT_ID = 'TENANT_ID'
export const ONL_AUTH_FIELDS = 'ONL_AUTH_FIELDS' export const ONL_AUTH_FIELDS = 'ONL_AUTH_FIELDS'
//路由缓存问题,关闭了tab页时再打开就不刷新 #842 //路由缓存问题,关闭了tab页时再打开就不刷新 #842
......
...@@ -49,11 +49,13 @@ export default class signMd5Utils { ...@@ -49,11 +49,13 @@ export default class signMd5Utils {
result = {}; result = {};
// 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username // 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username
//【这边条件没有encode】带条件参数例子:/sys/dict/getDictItems/sys_user,realname,id,username!='admin'%20order%20by%20create_time
let lastpathVariable = url.substring(url.lastIndexOf('/') + 1); let lastpathVariable = url.substring(url.lastIndexOf('/') + 1);
if(lastpathVariable.includes(",")){ if(lastpathVariable.includes(",")){
if(lastpathVariable.includes("?")){ if(lastpathVariable.includes("?")){
lastpathVariable = lastpathVariable.substring(0, lastpathVariable.indexOf("?")); lastpathVariable = lastpathVariable.substring(0, lastpathVariable.indexOf("?"));
} }
//解决Sign 签名校验失败 #2728
result["x-path-variable"] = decodeURI(lastpathVariable); result["x-path-variable"] = decodeURI(lastpathVariable);
} }
if (urlArray && urlArray[1]) { if (urlArray && urlArray[1]) {
......
...@@ -2,7 +2,7 @@ import Vue from 'vue' ...@@ -2,7 +2,7 @@ import Vue from 'vue'
import axios from 'axios' import axios from 'axios'
import store from '@/store' import store from '@/store'
import { VueAxios } from './axios' import { VueAxios } from './axios'
import {Modal, notification} from 'ant-design-vue' import router from '@/router/index'
import { ACCESS_TOKEN, TENANT_ID } from "@/store/mutation-types" import { ACCESS_TOKEN, TENANT_ID } from "@/store/mutation-types"
/** /**
...@@ -28,7 +28,7 @@ const err = (error) => { ...@@ -28,7 +28,7 @@ const err = (error) => {
console.log("------异常响应------",error.response.status) console.log("------异常响应------",error.response.status)
switch (error.response.status) { switch (error.response.status) {
case 403: case 403:
notification.error({ message: '系统提示', description: '拒绝访问',duration: 4}) Vue.prototype.$Jnotification.error({ message: '系统提示', description: '拒绝访问',duration: 4})
break break
case 500: case 500:
console.log("------error.response------",error.response) console.log("------error.response------",error.response)
...@@ -39,40 +39,43 @@ const err = (error) => { ...@@ -39,40 +39,43 @@ const err = (error) => {
break; break;
} }
// update-end- --- author:liusq ------ date:20200910 ---- for:处理Blob情况---- // update-end- --- author:liusq ------ date:20200910 ---- for:处理Blob情况----
//notification.error({ message: '系统提示', description:'Token失效,请重新登录!',duration: 4})
if(token && data.message.includes("Token失效")){ if(token && data.message.includes("Token失效")){
// update-begin- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转---- // update-begin- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
Modal.error({ if (/wxwork|dingtalk/i.test(navigator.userAgent)) {
title: '登录已过期', Vue.prototype.$Jmessage.loading('登录已过期,正在重新登陆', 0)
content: '很抱歉,登录已过期,请重新登录', } else {
okText: '重新登录', Vue.prototype.$Jmodal.error({
mask: false, title: '登录已过期',
onOk: () => { content: '很抱歉,登录已过期,请重新登录',
store.dispatch('Logout').then(() => { okText: '重新登录',
Vue.ls.remove(ACCESS_TOKEN) mask: false,
try { onOk: () => {
let path = window.document.location.pathname store.dispatch('Logout').then(() => {
console.log("location pathname -> "+path) Vue.ls.remove(ACCESS_TOKEN)
if(path!="/" && path.indexOf('/user/login')==-1){ try {
let path = window.document.location.pathname
console.log('location pathname -> ' + path)
if (path != '/' && path.indexOf('/user/login') == -1) {
window.location.reload()
}
} catch (e) {
window.location.reload() window.location.reload()
} }
}catch (e) { })
window.location.reload() }
} })
}) }
}
})
// update-end- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转---- // update-end- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
} }
break break
case 404: case 404:
notification.error({ message: '系统提示', description:'很抱歉,资源未找到!',duration: 4}) Vue.prototype.$Jnotification.error({ message: '系统提示', description:'很抱歉,资源未找到!',duration: 4})
break break
case 504: case 504:
notification.error({ message: '系统提示', description: '网络超时'}) Vue.prototype.$Jnotification.error({ message: '系统提示', description: '网络超时'})
break break
case 401: case 401:
notification.error({ message: '系统提示', description:'未授权,请重新登录',duration: 4}) Vue.prototype.$Jnotification.error({ message: '系统提示', description:'未授权,请重新登录',duration: 4})
if (token) { if (token) {
store.dispatch('Logout').then(() => { store.dispatch('Logout').then(() => {
setTimeout(() => { setTimeout(() => {
...@@ -82,13 +85,19 @@ const err = (error) => { ...@@ -82,13 +85,19 @@ const err = (error) => {
} }
break break
default: default:
notification.error({ Vue.prototype.$Jnotification.error({
message: '系统提示', message: '系统提示',
description: data.message, description: data.message,
duration: 4 duration: 4
}) })
break break
} }
} else if (error.message) {
if (error.message.includes('timeout')) {
Vue.prototype.$Jnotification.error({message: '系统提示', description: '网络超时'})
} else {
Vue.prototype.$Jnotification.error({message: '系统提示', description: error.message})
}
} }
return Promise.reject(error) return Promise.reject(error)
}; };
...@@ -99,6 +108,14 @@ service.interceptors.request.use(config => { ...@@ -99,6 +108,14 @@ service.interceptors.request.use(config => {
if (token) { if (token) {
config.headers[ 'X-Access-Token' ] = token // 让每个请求携带自定义 token 请根据实际情况自行修改 config.headers[ 'X-Access-Token' ] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
} }
// update-begin--author:sunjianlei---date:20200723---for 如果当前在low-app环境,并且携带了appId,就向Header里传递appId
const $route = router.currentRoute
if ($route && $route.name && $route.name.startsWith('low-app') && $route.params.appId) {
config.headers['X-Low-App-ID'] = $route.params.appId
}
// update-end--author:sunjianlei---date:20200723---for 如果当前在low-app环境,并且携带了appId,就向Header里传递appId
//update-begin-author:taoyan date:2020707 for:多租户 //update-begin-author:taoyan date:2020707 for:多租户
let tenantid = Vue.ls.get(TENANT_ID) let tenantid = Vue.ls.get(TENANT_ID)
if (!tenantid) { if (!tenantid) {
......
import Vue from 'vue'
import * as api from '@/api/api' import * as api from '@/api/api'
import { isURL } from '@/utils/validate' import { isURL } from '@/utils/validate'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import onlineCommons from '@jeecg/antd-online-mini' import onlineCommons from '@jeecg/antd-online-mini'
export function timeFix() { export function timeFix() {
...@@ -145,6 +147,7 @@ function generateChildRouters (data) { ...@@ -145,6 +147,7 @@ function generateChildRouters (data) {
component: componentPath, component: componentPath,
//component: resolve => require(['@/' + component+'.vue'], resolve), //component: resolve => require(['@/' + component+'.vue'], resolve),
hidden:item.hidden, hidden:item.hidden,
//component:()=> import(`@/views/${item.component}.vue`),
meta: { meta: {
title:item.meta.title , title:item.meta.title ,
icon: item.meta.icon, icon: item.meta.icon,
...@@ -559,4 +562,32 @@ export function removeArrayElement(array, prod, value) { ...@@ -559,4 +562,32 @@ export function removeArrayElement(array, prod, value) {
if(index>=0){ if(index>=0){
array.splice(index, 1); array.splice(index, 1);
} }
} }
\ No newline at end of file
/** 判断是否是OAuth2APP环境 */
export function isOAuth2AppEnv() {
return /wxwork|dingtalk/i.test(navigator.userAgent)
}
/**
* 获取积木报表打印地址
* @param url
* @param id
* @param open 是否自动打开
* @returns {*}
*/
export function getReportPrintUrl(url, id, open) {
// URL支持{{ window.xxx }}占位符变量
url = url.replace(/{{([^}]+)?}}/g, (s1, s2) => eval(s2))
if (url.includes('?')) {
url += '&'
} else {
url += '?'
}
url += `id=${id}`
url += `&token=${Vue.ls.get(ACCESS_TOKEN)}`
if (open) {
window.open(url)
}
return url
}
<template> <template>
<a-modal :visible="visible" title="修改头像" :maskClosable="false" :confirmLoading="confirmLoading" :width="800"> <a-modal :visible="visible" title="修改头像" :maskClosable="false" :confirmLoading="confirmLoading" :width="800" @cancel="cancelHandel">
<a-row> <a-row>
<a-col :xs="24" :md="12" :style="{height: '350px'}"> <a-col :xs="24" :md="12" :style="{height: '350px'}">
<vue-cropper <vue-cropper
......
...@@ -305,7 +305,7 @@ ...@@ -305,7 +305,7 @@
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :span="12"> <a-col :span="12">
<a-form-model-item label="cron表达式" prop="cronExpression"> <a-form-model-item label="cron表达式" prop="cronExpression">
<j-cron v-model="formData.cronExpression"></j-cron> <j-easy-cron v-model="formData.cronExpression"></j-easy-cron>
</a-form-model-item> </a-form-model-item>
</a-col> </a-col>
</a-row> </a-row>
...@@ -457,6 +457,7 @@ ...@@ -457,6 +457,7 @@
import JSelectMultiple from '@/components/jeecg/JSelectMultiple' import JSelectMultiple from '@/components/jeecg/JSelectMultiple'
import JTreeDict from "../../components/jeecg/JTreeDict.vue"; import JTreeDict from "../../components/jeecg/JTreeDict.vue";
import JCron from "@/components/jeecg/JCron.vue"; import JCron from "@/components/jeecg/JCron.vue";
import JEasyCron from "@/components/jeecg/JEasyCron";
import JTreeSelect from '@/components/jeecg/JTreeSelect' import JTreeSelect from '@/components/jeecg/JTreeSelect'
import JSuperQuery from '@/components/jeecg/JSuperQuery' import JSuperQuery from '@/components/jeecg/JSuperQuery'
import JUpload from '@/components/jeecg/JUpload' import JUpload from '@/components/jeecg/JUpload'
...@@ -489,7 +490,7 @@ ...@@ -489,7 +490,7 @@
JCheckbox, JCheckbox,
JCodeEditor, JCodeEditor,
JDate, JEditor, JEllipsis, JSlider, JSelectMultiple, JDate, JEditor, JEllipsis, JSlider, JSelectMultiple,
JCron, JTreeSelect, JSuperQuery, JMultiSelectTag, JCron, JEasyCron,JTreeSelect, JSuperQuery, JMultiSelectTag,
JSearchSelectTag JSearchSelectTag
}, },
data() { data() {
......
...@@ -214,7 +214,12 @@ ...@@ -214,7 +214,12 @@
this.isorter.order = "ascend" == sorter.order ? "asc" : "desc" this.isorter.order = "ascend" == sorter.order ? "asc" : "desc"
} }
//这种筛选方式只支持单选 //这种筛选方式只支持单选
this.filters.status = filters.status[0];
// update-begin-author:liusq date:20210624 for:前台定时任务无法翻页 #2666
if(filters && Object.keys(filters).length>0 && filters.status){
this.filters.status = filters.status[0];
}
// update-end-author:liusq date:20210624 for:前台定时任务无法翻页 #2666
this.ipagination = pagination; this.ipagination = pagination;
this.loadData(); this.loadData();
}, },
......
...@@ -123,11 +123,6 @@ ...@@ -123,11 +123,6 @@
customRender: (t, r, index) => index + 1 customRender: (t, r, index) => index + 1
}, },
{ {
title: '数据源编码',
align: 'center',
dataIndex: 'code'
},
{
title: '数据源名称', title: '数据源名称',
align: 'center', align: 'center',
dataIndex: 'name' dataIndex: 'name'
...@@ -150,11 +145,6 @@ ...@@ -150,11 +145,6 @@
customRender: (t) => ellipsis(t) customRender: (t) => ellipsis(t)
}, },
{ {
title: '数据库名称',
align: 'center',
dataIndex: 'dbName'
},
{
title: '用户名', title: '用户名',
align: 'center', align: 'center',
dataIndex: 'dbUsername' dataIndex: 'dbUsername'
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
import {getFileAccessHttpUrl} from '@/api/manage'; import {getFileAccessHttpUrl} from '@/api/manage';
export default { export default {
name: "SysOnlineList", name: "SysUserOnlineList",
mixins:[JeecgListMixin, mixinDevice], mixins:[JeecgListMixin, mixinDevice],
components: {}, components: {},
data () { data () {
......
...@@ -291,7 +291,7 @@ ...@@ -291,7 +291,7 @@
superQueryFieldList: [ superQueryFieldList: [
{ type: 'input', value: 'username', text: '用户账号', }, { type: 'input', value: 'username', text: '用户账号', },
{ type: 'input', value: 'realname', text: '用户姓名', }, { type: 'input', value: 'realname', text: '用户姓名', },
{ type: 'select', value: 'sex', text: '性别', dictCode: 'sex' }, { type: 'select', value: 'sex', dbType: 'int', text: '性别', dictCode: 'sex' },
], ],
url: { url: {
syncUser: "/act/process/extActProcess/doSyncUser", syncUser: "/act/process/extActProcess/doSyncUser",
......
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
:disabled="disabled"> :disabled="disabled">
</j-tree-select> </j-tree-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="分类名称" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="name"> <a-form-model-item label="分类名称" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="name">
<a-input v-model="model.name" placeholder="请输入分类名称"></a-input> <a-input v-model="model.name" placeholder="请输入分类名称"></a-input>
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
</a-spin> </a-spin>
</a-modal> </a-modal>
...@@ -36,10 +36,10 @@ ...@@ -36,10 +36,10 @@
import { httpAction,getAction } from '@/api/manage' import { httpAction,getAction } from '@/api/manage'
import JTreeSelect from '@/components/jeecg/JTreeSelect' import JTreeSelect from '@/components/jeecg/JTreeSelect'
export default { export default {
name: "SysCategoryModal", name: "SysCategoryModal",
components: { components: {
JTreeSelect JTreeSelect
}, },
data () { data () {
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
expandedRowKeys:[], expandedRowKeys:[],
pidField:"pid", pidField:"pid",
subExpandedKeys:[] subExpandedKeys:[]
} }
}, },
created () { created () {
...@@ -111,7 +111,8 @@ ...@@ -111,7 +111,8 @@
httpAction(httpurl,this.model,method).then((res)=>{ httpAction(httpurl,this.model,method).then((res)=>{
if(res.success){ if(res.success){
that.$message.success(res.message); that.$message.success(res.message);
that.submitSuccess(this.model) // close的时候清空了表单的值 导致model为空 修改值在列表页没有变 此处需要复制一下model
that.submitSuccess({...this.model})
}else{ }else{
that.$message.warning(res.message); that.$message.warning(res.message);
} }
...@@ -122,7 +123,7 @@ ...@@ -122,7 +123,7 @@
}else{ }else{
return false; return false;
} }
}) })
}, },
handleCancel () { handleCancel () {
......
...@@ -41,12 +41,12 @@ ...@@ -41,12 +41,12 @@
label="数据源地址"> label="数据源地址">
<a-input placeholder="请输入数据源地址" v-decorator="['dbUrl', validatorRules.dbUrl]"/> <a-input placeholder="请输入数据源地址" v-decorator="['dbUrl', validatorRules.dbUrl]"/>
</a-form-item> </a-form-item>
<a-form-item <!-- <a-form-item
:labelCol="labelCol" :labelCol="labelCol"
:wrapperCol="wrapperCol" :wrapperCol="wrapperCol"
label="数据库名称"> label="数据库名称">
<a-input placeholder="请输入数据库名称" v-decorator="['dbName', validatorRules.dbName]"/> <a-input placeholder="请输入数据库名称" v-decorator="['dbName', validatorRules.dbName]"/>
</a-form-item> </a-form-item>-->
<a-form-item <a-form-item
:labelCol="labelCol" :labelCol="labelCol"
:wrapperCol="wrapperCol" :wrapperCol="wrapperCol"
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
dbUrl: { rules: [{ required: true, message: '请输入数据源地址!' }] }, dbUrl: { rules: [{ required: true, message: '请输入数据源地址!' }] },
dbName: { rules: [{ required: true, message: '请输入数据库名称!' }] }, dbName: { rules: [{ required: true, message: '请输入数据库名称!' }] },
dbUsername: { rules: [{ required: true, message: '请输入用户名!' }] }, dbUsername: { rules: [{ required: true, message: '请输入用户名!' }] },
dbPassword: { rules: [{ required: true, message: '请输入密码!' }] } dbPassword: { rules: [{ required: false, message: '请输入密码!' }] }
}, },
url: { url: {
add: '/sys/dataSource/add', add: '/sys/dataSource/add',
...@@ -142,7 +142,25 @@ ...@@ -142,7 +142,25 @@
// marialDB 数据库 // marialDB 数据库
'5': { dbDriver: 'org.mariadb.jdbc.Driver' }, '5': { dbDriver: 'org.mariadb.jdbc.Driver' },
// postgresql 数据库 // postgresql 数据库
'6': { dbDriver: 'org.postgresql.Driver' } '6': { dbDriver: 'org.postgresql.Driver' },
// 达梦 数据库
'7': { dbDriver: 'dm.jdbc.driver.DmDriver' },
// 人大金仓 数据库
'8': { dbDriver: 'com.kingbase8.Driver' },
// 神通 数据库
'9': { dbDriver: 'com.oscar.Driver' },
// SQLite 数据库
'10': { dbDriver: 'org.sqlite.JDBC' },
// DB2 数据库
'11': { dbDriver: 'com.ibm.db2.jcc.DB2Driver' },
// Hsqldb 数据库
'12': { dbDriver: 'org.hsqldb.jdbc.JDBCDriver' },
// Derby 数据库
'13': { dbDriver: 'org.apache.derby.jdbc.ClientDriver' },
// H2 数据库
'14': { dbDriver: 'org.h2.Driver' },
// 其他数据库
'15': { dbDriver: '' }
}, },
dbUrlMap: { dbUrlMap: {
// MySQL 数据库 // MySQL 数据库
...@@ -153,10 +171,28 @@ ...@@ -153,10 +171,28 @@
'2': { dbUrl: 'jdbc:oracle:thin:@127.0.0.1:1521:ORCL' }, '2': { dbUrl: 'jdbc:oracle:thin:@127.0.0.1:1521:ORCL' },
// SQLServer 数据库 // SQLServer 数据库
'3': { dbUrl: 'jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=jeecgboot' }, '3': { dbUrl: 'jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;DatabaseName=jeecgboot' },
// SQLServer 数据库 // Mariadb 数据库
'5': { dbUrl: 'jdbc:mariadb://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useSSL=false' }, '5': { dbUrl: 'jdbc:mariadb://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useSSL=false' },
// SQLServer 数据库 // Postgresql 数据库
'6': { dbUrl: 'jdbc:postgresql://127.0.0.1:5432/jeecg-boot' } '6': { dbUrl: 'jdbc:postgresql://127.0.0.1:5432/jeecg-boot' },
// 达梦 数据库
'7': { dbUrl: 'jdbc:dm://127.0.0.1:5236/?jeecg-boot&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8' },
// 人大金仓 数据库
'8': { dbUrl: 'jdbc:kingbase8://127.0.0.1:54321/jeecg-boot' },
// 神通 数据库
'9': { dbUrl: 'jdbc:oscar://192.168.1.125:2003/jeecg-boot' },
// SQLite 数据库
'10': { dbUrl: 'jdbc:sqlite://opt/test.db' },
// DB2 数据库
'11': { dbUrl: 'jdbc:db2://127.0.0.1:50000/jeecg-boot' },
// Hsqldb 数据库
'12': { dbUrl: 'jdbc:hsqldb:hsql://127.0.0.1/jeecg-boot' },
// Derby 数据库
'13': { dbUrl: 'jdbc:derby://127.0.0.1:1527/jeecg-boot' },
// H2 数据库
'14': { dbUrl: 'jdbc:h2:tcp://127.0.0.1:8082/jeecg-boot' },
// 其他数据库
'15': { dbUrl: '' }
} }
} }
}, },
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
<!--部门分配--> <!--部门分配-->
<a-form-model-item label="部门分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!departDisabled"> <a-form-model-item label="部门分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!departDisabled">
<j-select-depart v-model="model.selecteddeparts" :multi="true" @back="backDepartInfo" :backDepart="true"></j-select-depart> <j-select-depart v-model="model.selecteddeparts" :multi="true" @back="backDepartInfo" :backDepart="true" :treeOpera="true">></j-select-depart>
</a-form-model-item> </a-form-model-item>
<!--租户分配--> <!--租户分配-->
......
...@@ -35,18 +35,18 @@ ...@@ -35,18 +35,18 @@
</template> </template>
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import { ACCESS_TOKEN ,ENCRYPTED_STRING} from "@/store/mutation-types" import { ACCESS_TOKEN, ENCRYPTED_STRING } from '@/store/mutation-types'
import ThirdLogin from './third/ThirdLogin' import ThirdLogin from './third/ThirdLogin'
import LoginSelectTenant from "./LoginSelectTenant" import LoginSelectTenant from './LoginSelectTenant'
import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha' import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
import { encryption , getEncryptedString } from '@/utils/encryption/aesEncrypt' import { getEncryptedString } from '@/utils/encryption/aesEncrypt'
import { timeFix } from "@/utils/util" import { timeFix } from '@/utils/util'
import LoginAccount from './LoginAccount' import LoginAccount from './LoginAccount'
import LoginPhone from './LoginPhone' import LoginPhone from './LoginPhone'
export default { export default {
components: { components: {
LoginSelectTenant, LoginSelectTenant,
TwoStepCaptcha, TwoStepCaptcha,
......
...@@ -50,12 +50,11 @@ ...@@ -50,12 +50,11 @@
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import { getAction,putAction } from '@/api/manage' import { putAction } from '@/api/manage'
import { USER_INFO } from "@/store/mutation-types" import { USER_INFO } from '@/store/mutation-types'
import store from './Login'
export default { export default {
name: 'LoginSelectTenant', name: 'LoginSelectTenant',
data(){ data(){
return { return {
...@@ -111,18 +110,19 @@ ...@@ -111,18 +110,19 @@
this.isMultiDepart = false this.isMultiDepart = false
} }
}, },
bizTenant(ids){ bizTenantList(loginResult) {
if(!ids || ids.length==0){ let tenantList = loginResult.tenantList
this.isMultiTenant = false if (Array.isArray(tenantList)) {
} else if(ids.indexOf(',')<0){ if (tenantList.length === 0) {
this.tenant_id = ids; this.isMultiTenant = false
this.isMultiTenant = false } else if (tenantList.length === 1) {
}else{ this.tenant_id = tenantList[0].id
this.visible = true this.isMultiTenant = false
this.isMultiTenant = true } else {
getAction('/sys/tenant/queryList', {ids: ids}).then(res=>{ this.visible = true
this.tenantList = res.result this.isMultiTenant = true
}) this.tenantList = tenantList
}
} }
}, },
show(loginResult){ show(loginResult){
...@@ -131,8 +131,7 @@ ...@@ -131,8 +131,7 @@
let user = Vue.ls.get(USER_INFO) let user = Vue.ls.get(USER_INFO)
this.username = user.username this.username = user.username
let ids = user.relTenantIds this.bizTenantList(loginResult);
this.bizTenant(ids);
if(this.visible===false){ if(this.visible===false){
this.$store.dispatch('saveTenant', this.tenant_id); this.$store.dispatch('saveTenant', this.tenant_id);
......
<template>
<div>
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在登录 JeecgBoot 低代码平台,请耐心等待</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import { isOAuth2AppEnv, timeFix } from '@/utils/util'
import { INDEX_MAIN_PAGE_PATH } from '@/store/mutation-types'
export default {
name: 'OAuth2Login',
data() {
return {
env: {
thirdApp: false,
wxWork: false,
dingtalk: false,
},
}
},
beforeCreate() {
// 如果当前 不是 OAuth2APP环境,就重定向到 /user/login 页面
if (!isOAuth2AppEnv()) {
this.$router.replace({path: '/user/login'})
}
},
created() {
this.checkEnv()
this.doOAuth2Login()
},
methods: {
...mapActions(['ThirdLogin']),
/** 检测当前的环境 */
checkEnv() {
// 判断当时是否是企业微信环境
if (/wxwork/i.test(navigator.userAgent)) {
this.env.thirdApp = true
this.env.wxWork = true
}
// 判断当时是否是钉钉环境
if (/dingtalk/i.test(navigator.userAgent)) {
this.env.thirdApp = true
this.env.dingtalk = true
}
},
/** 进行OAuth2登录操作 */
doOAuth2Login() {
if (this.env.thirdApp) {
// 判断是否携带了Token,是就说明登录成功
if (this.$route.query.oauth2LoginToken) {
this.thirdType = this.$route.query.thirdType
let token = this.$route.query.oauth2LoginToken
this.doThirdLogin(token)
} else if (this.env.wxWork) {
this.doWechatEnterpriseOAuth2Login()
} else if (this.env.dingtalk) {
this.doDingTalkOAuth2Login()
}
}
},
// 根据token执行登录
doThirdLogin(token) {
let param = {}
param.thirdType = this.thirdType
param.token = token
this.ThirdLogin(param).then(res => {
if (res.success) {
this.loginSuccess()
} else {
this.requestFailed(res)
}
})
},
loginSuccess() {
// 登陆成功,重定向到主页
this.$router.replace({path: INDEX_MAIN_PAGE_PATH})
// TODO 这个提示是否还需要?
this.$notification.success({
message: '欢迎',
description: `${timeFix()},欢迎回来`,
})
},
requestFailed(err) {
this.$error({
title: '登录失败',
content: ((err.response || {}).data || {}).message || err.message || '请求出现错误,请稍后再试',
okText: '重新登陆',
onOk() {
window.location.reload()
},
onCancel() {
window.location.reload()
},
})
},
/** 企业微信OAuth2登录 */
doWechatEnterpriseOAuth2Login() {
this.sysOAuth2Login('wechat_enterprise')
},
/** 钉钉OAuth2登录 */
doDingTalkOAuth2Login() {
this.sysOAuth2Login('dingtalk')
},
/** 后台构造oauth2登录地址 */
sysOAuth2Login(source) {
let url = `${window._CONFIG['domianURL']}/sys/thirdLogin/oauth2/${source}/login`
url += `?state=${encodeURIComponent(window.location.origin)}`
window.location.href = url
},
},
}
</script>
<style scoped>
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment