JeecgBoot 3.3.0 版本发布,基于代码生成器的企业级低代码平台

This commit is contained in:
zhangdaiscott
2022-07-20 18:09:53 +08:00
parent 55201e82eb
commit 0cbdc092d1
275 changed files with 7013 additions and 40279 deletions

View File

@ -1,7 +1,7 @@
Ant Design Jeecg Vue
====
当前最新版本: 3.1.0发布日期20220301
当前最新版本: 3.3.0发布日期20220725
Overview
----

View File

@ -10,8 +10,8 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"ant-design-vue": "^1.7.2",
"@jeecg/antd-online-mini": "3.1.0-beta",
"ant-design-vue": "^1.7.2",
"@antv/data-set": "^0.11.4",
"viser-vue": "^2.4.8",
"axios": "^0.18.0",
@ -29,7 +29,7 @@
"vue-ls": "^3.2.0",
"vue-router": "^3.0.1",
"vuex": "^3.1.0",
"vue-print-nb-jeecg": "^1.0.9",
"vue-print-nb-jeecg": "^1.0.11",
"clipboard": "^2.0.4",
"vue-photo-preview": "^1.1.3",
"vue-splitpane": "^1.0.4",
@ -45,7 +45,8 @@
"vxe-table": "2.9.13",
"vxe-table-plugin-antd": "1.8.10",
"cron-parser": "^2.10.0",
"qiankun": "^2.5.1"
"qiankun": "^2.5.1",
"xss": "^1.0.13"
},
"devDependencies": {
"@babel/polyfill": "^7.2.5",

View File

@ -69,7 +69,6 @@ export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItem
function getDictItemsFromCache(dictCode) {
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
//console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
return dictItems;
}
}
@ -91,6 +90,7 @@ const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params)
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
//加载我的通告信息
const getUserNoticeInfo= (params)=>getAction("/sys/sysAnnouncementSend/getMyAnnouncementSend",params);
//查询图表数据
const getTransitURL = url => `/sys/common/transitRESTful?url=${encodeURIComponent(url)}`
// 中转HTTP请求
export const transitRESTful = {
@ -101,8 +101,6 @@ export const transitRESTful = {
}
export {
// imgView,
// doMian,
addRole,
editRole,
checkRoleCode,

View File

@ -16,7 +16,9 @@ export default api
export function postAction(url,parameter) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
// update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getTimestamp()};
// update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
return axios({
url: url,
@ -30,7 +32,9 @@ export function postAction(url,parameter) {
export function httpAction(url,parameter,method) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
// update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getTimestamp()};
// update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
return axios({
url: url,
@ -53,7 +57,9 @@ export function putAction(url,parameter) {
export function getAction(url,parameter) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
// update-begin--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getTimestamp()};
// update-end--author:taoyan---date:20220421--for: VUEN-410【签名改造】 X-TIMESTAMP牵扯
return axios({
url: url,
@ -120,13 +126,23 @@ export function saveService(parameter) {
* @param parameter
* @returns {*}
*/
export function downFile(url,parameter){
return axios({
url: url,
params: parameter,
method:'get' ,
responseType: 'blob'
})
export function downFile(url,parameter, method='get'){
if(method=='get'){
return axios({
url: url,
params: parameter,
method: method ,
responseType: 'blob'
})
}else{
return axios({
url: url,
method: method,
data: parameter,
responseType: 'blob'
})
}
}
/**

View File

@ -387,7 +387,7 @@
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownloadFile(id)">
<span><a-icon type="download"/>&nbsp;下载</span>
</a-menu-item>
<a-menu-item v-if="col.allowRemove!==false" @click="handleClickDelFile(id)">
<a-menu-item v-if="col.allowRemove!==false" @click="handleClickDelFile(id, row, col)">
<span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item>
</a-menu>
@ -475,7 +475,7 @@
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownFileByUrl(id)">
<span><a-icon type="download"/>&nbsp;下载</span>
</a-menu-item>
<a-menu-item @click="handleClickDelFile(id)">
<a-menu-item @click="handleClickDelFile(id, row, col)">
<span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item>
<a-menu-item @click="handleMoreOperation(id,col,col)">
@ -532,7 +532,7 @@
<a-menu-item v-if="col.allowDownload!==false" @click="handleClickDownFileByUrl(id)">
<span><a-icon type="download"/>&nbsp;下载</span>
</a-menu-item>
<a-menu-item @click="handleClickDelFile(id)">
<a-menu-item @click="handleClickDelFile(id, row, col)">
<span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item>
<a-menu-item @click="handleMoreOperation(id,'img',col)">
@ -1865,6 +1865,8 @@
})
// 强制更新formValues
this.forceUpdateFormValues()
// 【issues/3828】重新计算统计列
this.recalcAllStatisticsColumns()
},
/**
* 设置单个组件的值
@ -2590,8 +2592,9 @@
return id;
},
handleClickDelFile(id) {
handleClickDelFile(id, row, col) {
this.uploadValues[id] = null
this.elemValueChange(col.type, row, col, null);
},
handleClickDownloadFile(id) {
let { path } = this.uploadValues[id] || {}
@ -3074,7 +3077,11 @@
return false
}
return true;
}
},
// 根据id获取dataSource中的一行数据
getOriginData(id){
return this.dataSource.filter(item=>item.id == id);
},
},
beforeDestroy() {

View File

@ -68,6 +68,9 @@
branding: false,
menubar: false,
toolbar_drawer: false,
//update-begin-author:taoyan date:2022-5-6 for: issues/I4BCC3 富文本编辑器在服务器图片上传是相对路径
convert_urls: false,
//update-end-author:taoyan date:2022-5-6 for: issues/I4BCC3 富文本编辑器在服务器图片上传是相对路径
images_upload_handler: (blobInfo, success) => {
let formData = new FormData()
formData.append('file', blobInfo.blob(), blobInfo.filename());

View File

@ -49,7 +49,8 @@
.jeecg-form-container-disabled .ant-upload-select{display:none}
.jeecg-form-container-disabled .ant-upload-list{cursor:grabbing}
.jeecg-form-container-disabled fieldset[disabled] .ant-upload-list{
.jeecg-form-container-disabled fieldset[disabled] .ant-upload-list,
.jeecg-form-container-disabled fieldset[disabled] iframe{
-ms-pointer-events: auto !important;
pointer-events: auto !important;
}

View File

@ -8,7 +8,7 @@
v-on="$listeners"
@ok="handleOk"
@cancel="handleCancel"
destroyOnClose
:destroyOnClose="destroyOnClose"
>
<slot></slot>
@ -49,13 +49,17 @@
import { getClass, getStyle } from '@/utils/props-util'
import { triggerWindowResizeEvent } from '@/utils/util'
import ModalDragMixins from './ModalDragMixins'
export default {
name: 'JModal',
mixins: [ModalDragMixins],
props: {
title: String,
// 可使用 .sync 修饰符
visible: Boolean,
// 是否开启拖拽
draggable: Boolean,
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
fullscreen: {
type: Boolean,
@ -71,6 +75,11 @@ export default {
type: Boolean,
default: true
},
// 关闭时销毁弹窗内容
destroyOnClose: {
type: Boolean,
default: true
},
},
data() {
return {
@ -162,6 +171,16 @@ export default {
toggleFullscreen() {
this.innerFullscreen = !this.innerFullscreen
triggerWindowResizeEvent()
// 全屏的时候禁止拖动
if (this.innerFullscreen) {
// 还原弹窗的位置为0,0
this.setModalPosition(0, 0, false)
this.dragSettings.headerEl.style.cursor = null
} else {
// 取消全屏的时候,将弹窗移动到上次记录的位置
this.resetModalPosition()
this.dragSettings.headerEl.style.cursor = 'move'
}
},
}

View File

@ -0,0 +1,152 @@
import {getRefPromise} from '@/utils/util'
/** JModal 的拖拽混入 */
export default {
data() {
return {
// 拖动配置
dragSettings: {
// 上次拖动top记录
top: null,
// 上次拖动left记录
left: null,
wrapEl: null,
dragEl: null,
headerEl: null,
},
}
},
watch: {
visible() {
if (!this.visible || !this.draggable) {
return
}
this.handleDrag()
},
draggable() {
if (!this.visible || !this.draggable) {
return
}
this.handleDrag()
},
},
methods: {
async handleDrag() {
let modalRef = await getRefPromise(this, 'modal')
const dragWraps = modalRef.$el.querySelectorAll('.ant-modal-wrap')
let wrapEl = dragWraps[0]
if (!wrapEl) return
this.dragSettings.wrapEl = wrapEl
this.dragSettings.dragEl = wrapEl.querySelector('.ant-modal')
this.dragSettings.headerEl = wrapEl.querySelector('.ant-modal-header')
const display = getStyle(wrapEl, 'display')
const draggable = wrapEl.getAttribute('data-drag')
if (display !== 'none') {
// 拖拽位置
if (draggable === null || this.destroyOnClose) {
this.enableDrag(wrapEl)
}
}
},
/** 启用拖拽 */
enableDrag() {
let {wrapEl, dragEl, headerEl} = this.dragSettings
if (!wrapEl) return
wrapEl.setAttribute('data-drag', this.draggable)
if (!headerEl || !dragEl || !this.draggable) return
// 还原上一次移动的位置
this.resetModalPosition()
headerEl.style.cursor = 'move'
headerEl.onmousedown = (e) => {
if (!e) return
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX
const disY = e.clientY
const screenWidth = document.body.clientWidth // body当前宽度
const screenHeight = document.documentElement.clientHeight // 可见区域高度(应为body高度可某些环境下无法获取)
const dragElWidth = dragEl.offsetWidth // 对话框宽度
const dragElHeight = dragEl.offsetHeight // 对话框高度
const minDragElLeft = dragEl.offsetLeft
const maxDragElLeft = screenWidth - dragEl.offsetLeft - dragElWidth
const minDragElTop = dragEl.offsetTop
const maxDragElTop = screenHeight - dragEl.offsetTop - dragElHeight
// 获取到的值带px 正则匹配替换
const domLeft = getStyle(dragEl, 'left')
const domTop = getStyle(dragEl, 'top')
let styL = +domLeft
let styT = +domTop
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (domLeft.includes('%')) {
styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100)
styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100)
} else {
styL = +domLeft.replace(/px/g, '')
styT = +domTop.replace(/px/g, '')
}
document.onmousemove = (e) => {
// 全屏时不触发移动方法
if (this.innerFullscreen) {
return
}
// 通过事件委托,计算移动的距离
let left = e.clientX - disX
let top = e.clientY - disY
// 边界处理
if (-left > minDragElLeft) {
left = -minDragElLeft
} else if (left > maxDragElLeft) {
left = maxDragElLeft
}
if (-top > minDragElTop) {
top = -minDragElTop
} else if (top > maxDragElTop) {
top = maxDragElTop
}
this.setModalPosition(top + styT, left + styL)
}
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
}
}
},
/**
* 移动弹窗位置
* @param top 顶部位置
* @param left 左侧位置
* @param remember 是否记录位置,默认 true
*/
setModalPosition(top, left, remember = true) {
// 记录移动位置
if (remember) {
this.dragSettings.top = top
this.dragSettings.left = left
}
// 移动当前元素
this.dragSettings.dragEl.style.cssText += `;left:${left}px;top:${top}px;`
},
/**
* 将弹窗移动到上次记录的位置
*/
resetModalPosition() {
this.setModalPosition(this.dragSettings.top, this.dragSettings.left, false)
},
},
}
function getStyle(dom, attr) {
return getComputedStyle(dom)[attr]
}

View File

@ -29,6 +29,7 @@
@cancel="handleCancel"
:mask="false"
:fullscreen="izMobile"
draggable
class="j-super-query-modal"
style="top:5%;max-height: 95%;"
>
@ -163,8 +164,10 @@
<a-time-picker v-else-if="item.type==='time'" :value="item.val ? moment(item.val,'HH:mm:ss') : null" format="HH:mm:ss" style="width: 100%" @change="(time,value)=>item.val=value"/>
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
<a-select v-else-if="item.type=='switch'" placeholder="请选择" v-model="item.val">
<a-select-option value="Y">是</a-select-option>
<a-select-option value="N"></a-select-option>
<!-- update-begin-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时高级查询选择后查询仍然是Y/N -->
<a-select-option :value="item.extendOption[0]"></a-select-option>
<a-select-option :value="item.extendOption[1]">否</a-select-option>
<!-- update-end-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时高级查询选择后查询仍然是Y/N -->
</a-select>
<a-input v-else v-model="item.val" placeholder="请输入值"/>
</a-col>
@ -426,10 +429,17 @@
item['dictCode'] = dictCode
item['dictTable'] = dictTable
item['dictText'] = dictText
//update-begin-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时高级查询选择后查询仍然是Y/N
item['extendOption'] = node.dataRef.extendOption || ['Y', 'N']
//update-begin-author:taoyan for: VUEN-242【online表单 高级查询】开关组件设置扩展参数为[0,1] 时高级查询选择后查询仍然是Y/N
item['customReturnField'] = customReturnField
if (popup) {
item['popup'] = popup
}
// 格式化字符串,一般用于高级查询的日期格式处理
if (node.dataRef.formatStr) {
item['formatStr'] = node.dataRef.formatStr
}
this.$set(item, 'val', undefined)
},
handleOpen() {

View File

@ -71,6 +71,12 @@
let className = target.className || ''
className = typeof className === 'string' ? className : className.toString()
// 获取 td 父级
let td = getParentNodeByTagName(target, 'td');
// 点击的是拖拽排序列,不做处理
if (td && td.querySelector('.j-vxe-ds-icons')) {
return
}
// 点击的是expand不做处理
if (className.includes('vxe-table--expand-btn')) {
return

View File

@ -763,6 +763,8 @@ export default {
console.warn(`JVxeTable.setValues必须传递数组`)
return
}
// 是否更新了数据
let updated = false
values.forEach((item, idx) => {
let {rowKey, values: record} = item
let {row} = this.getIfRowById(rowKey)
@ -775,6 +777,7 @@ export default {
let oldValue = row[colKey]
let newValue = record[colKey]
if (newValue !== oldValue) {
updated = true
this.$set(row, colKey, newValue)
// 触发 valueChange 事件
this.trigger('valueChange', {
@ -791,6 +794,14 @@ export default {
}
})
})
// 【issues/3828】数据更新后重新计算统计列
if (updated && this.statistics.has) {
this.$nextTick(async () => {
let {xTable} = this.$refs.vxe.$refs;
await xTable.updateCache(true);
await xTable.updateData();
});
}
},
/** 获取所有的数据包括values、deleteIds */
@ -1406,7 +1417,7 @@ const fooPatterns = [
{title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/},
{title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/},
{title: '整数', value: 'z', pattern: /^-?\d+$/},
{title: '金额', value: 'money', pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/},
{title: '金额', value: 'money', pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,5}))$/},
]
/** 旧版handler转为新版Validator */

View File

@ -133,6 +133,10 @@
value['message'] = file.response.message || '未知错误'
}
this.innerFile = value
// issues/I5FTO6 JVxeTypes.upload 文件上传的时候,触发不了事件
if (value.path) {
this.handleChangeCommon(fileGetValue(value));
}
},
// handleClickPreviewFile(id) {

View File

@ -1,5 +1,8 @@
import store from '@/store/'
import { randomUUID } from '@/utils/util'
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
// vxe socket
const vs = {
// 页面唯一 id用于标识同一用户不同页面的websocket
@ -52,7 +55,10 @@ const vs = {
const domain = window._CONFIG['domianURL'].replace('https://', 'wss://').replace('http://', 'ws://')
const url = `${domain}/vxeSocket/${userId}/${this.pageId}`
this.ws = new WebSocket(url)
//update-begin-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
let token = Vue.ls.get(ACCESS_TOKEN)
this.ws = new WebSocket(url, [token])
//update-end-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
this.ws.onopen = this.on.open.bind(this)
this.ws.onerror = this.on.error.bind(this)
this.ws.onmessage = this.on.message.bind(this)

View File

@ -7,12 +7,15 @@
<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
import { TENANT_ID } from "@/store/mutation-types"
import PageLayout from '../page/PageLayout'
import RouteView from './RouteView'
import {mixinDevice} from '@/utils/mixin'
export default {
name: "IframePageContent",
inject:['closeCurrent'],
mixins: [mixinDevice],
data () {
return {
url: "",
@ -47,10 +50,21 @@
} else {
this.url = url
}
//update-begin---author:wangshuai ---date:20220711 for[VUEN-1638]菜单tenantId需要动态生成------------
let tenantIdStr = '${tenantId}'
let tenantUrl = this.url
if (tenantUrl.indexOf(tenantIdStr) != -1) {
let tenantId = Vue.ls.get(TENANT_ID)
this.url = tenantUrl.replace(tenantIdStr, tenantId)
}
//update-end---author:wangshuai ---date:20220711 for[VUEN-1638]菜单tenantId需要动态生成--------------
//-----------------------------------------------------------------------------------------
// 是否允许打开外部页面需要非Mobile模式且打开多页签模式
let allowOpen = !this.isMobile() && this.$store.state.app.multipage
/*update_begin author:wuxianquan date:20190908 for:判断打开方式新窗口打开时this.$route.meta.internalOrExternal==true */
if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
if(allowOpen && this.$route.meta.internalOrExternal === true){
this.closeCurrent();
window.open(this.url);
}

View File

@ -70,7 +70,9 @@
/* update_begin author:wuxianquan date:20190828 for: 关闭当前tab页供子页面调用 ->望菜单能配置外链直接弹出新页面而不是嵌入iframe #428 */
provide(){
return{
closeCurrent:this.closeCurrent
closeCurrent:this.closeCurrent,
changeTitle: this.changeTitle,
changeTabTitle: this.changeTabTitle,
}
},
/* update_end author:wuxianquan date:20190828 for: 关闭当前tab页供子页面调用->望菜单能配置外链直接弹出新页面而不是嵌入iframe #428 */
@ -176,6 +178,10 @@
// update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
/**
* 修改当前页面的窗口标题
* @param title 要修改的新标题
*/
changeTitle(title) {
let projectTitle = "Jeecg-Boot 企业级低代码平台"
// 首页特殊处理
@ -185,6 +191,19 @@
document.title = title + ' · ' + projectTitle
}
},
/**
* 修改tab标签的标题
* @param title 要修改的新标题
* @param fullPath 要修改的路由全路径,如果不填就是修改当前路由
*/
changeTabTitle(title, fullPath = '') {
if (title) {
let currentRoute = this.pageList.find((r) => r.fullPath === (fullPath ? fullPath : this.$route.fullPath))
if (currentRoute != null) {
currentRoute.meta = {...currentRoute.meta, title}
}
}
},
// update-end-author:sunjianlei date:20200120 for: 动态更改页面标题
changePage(key) {

View File

@ -81,7 +81,8 @@
import ShowAnnouncement from './ShowAnnouncement'
import store from '@/store/'
import DynamicNotice from './DynamicNotice'
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
export default {
name: "HeaderNotice",
@ -107,6 +108,8 @@
stopTimer:false,
websock: null,
lockReconnect:false,
//websocket错误连接次数
wsConnectErrorTime:1,
heartCheck:null,
formData:{},
openPath:''
@ -201,7 +204,10 @@
var userId = store.getters.userInfo.id;
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://")+"/websocket/"+userId;
//console.log(url);
this.websock = new WebSocket(url);
//update-begin-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
let token = Vue.ls.get(ACCESS_TOKEN)
this.websock = new WebSocket(url, [token]);
//update-end-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
this.websock.onopen = this.websocketOnopen;
this.websock.onerror = this.websocketOnerror;
this.websock.onmessage = this.websocketOnmessage;
@ -213,12 +219,21 @@
//this.heartCheck.reset().start();
},
websocketOnerror: function (e) {
console.log("WebSocket连接发生错误");
console.log("WebSocket连接发生错误,第%s次",this.wsConnectErrorTime);
this.wsConnectErrorTime = this.wsConnectErrorTime + 1;
if(this.wsConnectErrorTime>5){
console.log("WebSocket连接错误超过5次就不再重新连了");
this.lockReconnect = true
return;
}
this.reconnect();
},
websocketOnmessage: function (e) {
console.log("-----接收消息-------",e.data);
var data = eval("(" + e.data + ")"); //解析对象
this.voiceBroadcast(data.msgTxt)
if(data.cmd == "topic"){
//系统通知
this.loadData();
@ -243,7 +258,13 @@
console.log("send failed (" + err.code + ")");
}
},
//语音播报系统通知
voiceBroadcast(text){
var url = "http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&text=" + encodeURI(text); // baidu文字转语音
var voiceContent = new Audio(url);
voiceContent.src = url;
voiceContent.play();
},
openNotification (data) {
var text = data.msgTxt;
const key = `open${Date.now()}`;
@ -275,7 +296,7 @@
console.info("尝试重连...");
that.initWebSocket();
that.lockReconnect = false;
}, 5000);
}, 20000);
},
heartCheckFun(){
var that = this;

View File

@ -1,3 +1,4 @@
import xss from "xss"
<template>
<j-modal
:title="title"
@ -24,6 +25,7 @@
<script>
import {getUserList} from '@/api/api'
import xss from 'xss'
export default {
name: "SysAnnouncementModal",
components: {
@ -70,6 +72,11 @@
}
//update-end---author:wangshuai ---date:20220107 for将其它页面传递过来的用户名改成用户真实姓名
this.visible = true;
//update-begin-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
if(record.msgContent){
record.msgContent = xss(record.msgContent)
}
//update-end-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
this.record = record;
},
handleCancel () {

View File

@ -23,7 +23,9 @@ export const WebsocketMixin = {
this.socketUrl = this.socketUrl + '/'
}
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://") + this.socketUrl + userId + "/" + token;
this.websock = new WebSocket(url);
//update-begin-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
this.websock = new WebSocket(url, [token]);
//update-end-author:taoyan date:2022-4-22 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
this.websock.onopen = this.websocketOnopen;
this.websock.onerror = this.websocketOnerror;
this.websock.onmessage = this.websocketOnmessage;

View File

@ -104,23 +104,35 @@ export default class signMd5Utils {
return paramStr;
};
static getDateTimeToString() {
const date_ = new Date()
const year = date_.getFullYear()
let month = date_.getMonth() + 1
let day = date_.getDate()
if (month < 10) month = '0' + month
if (day < 10) day = '0' + day
let hours = date_.getHours()
let mins = date_.getMinutes()
let secs = date_.getSeconds()
const msecs = date_.getMilliseconds()
if (hours < 10) hours = '0' + hours
if (mins < 10) mins = '0' + mins
if (secs < 10) secs = '0' + secs
if (msecs < 10) secs = '0' + msecs
return year + '' + month + '' + day + '' + hours + '' + mins + '' + secs
/**
* 接口签名用 生成header中的时间戳
* @returns {number}
*/
static getTimestamp(){
return new Date().getTime()
}
// /**
// * 获取客户端时间(签名参数 X_TIMESTAMP
// * @returns {string}
// */
// static getDateTimeToString() {
// const date_ = new Date()
// const year = date_.getFullYear()
// let month = date_.getMonth() + 1
// let day = date_.getDate()
// if (month < 10) month = '0' + month
// if (day < 10) day = '0' + day
// let hours = date_.getHours()
// let mins = date_.getMinutes()
// let secs = date_.getSeconds()
// const msecs = date_.getMilliseconds()
// if (hours < 10) hours = '0' + hours
// if (mins < 10) mins = '0' + mins
// if (secs < 10) secs = '0' + secs
// if (msecs < 10) secs = '0' + msecs
// return year + '' + month + '' + day + '' + hours + '' + mins + '' + secs
// }
// true:数值型的false非数值型
static myIsNaN(value) {
return typeof value === 'number' && !isNaN(value);

View File

@ -113,6 +113,11 @@ service.interceptors.request.use(config => {
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
// lowApp自定义筛选条件
if ($route.params.lowAppFilter) {
config.params = {...config.params, ...$route.params.lowAppFilter}
delete $route.params.lowAppFilter
}
}
// update-end--author:sunjianlei---date:20200723---for 如果当前在low-app环境并且携带了appId就向Header里传递appId

View File

@ -1,10 +1,17 @@
const validateMobile = (rule, value, callback) => {
let reg = /^1(3|4|5|7|8)\d{9}$/
if (!reg.test(value)) {
callback('请输入正确手机号')
} else {
//update-beign-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候触发手机号校验
if(!value && value!=='0'){
callback()
}else{
if (!reg.test(value)) {
callback('请输入正确手机号')
} else {
callback()
}
}
//update-end-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候触发手机号校验
}
const validateEn = (rule, value, callback) => {
let reg = /^[_a-zA-Z0-9]+$/
@ -24,6 +31,7 @@ export const rules = {
message: '请输入手机号',
trigger: 'blur'
}, { validator: validateMobile, trigger: 'blur' }],
mobile2: [{ validator: validateMobile, trigger: 'blur' }],
userName: [{
required: true, message: '请输入用户名', trigger: 'blur'
}, { validator: validateEn }],

View File

@ -206,7 +206,7 @@ export function randomNumber() {
}
if (arguments.length === 1) {
let [length] = arguments
// 生成指定长度的随机数字,首位一定不是 0
// 生成指定长度的随机数字,首位一定不是 0
let nums = [...Array(length).keys()].map((i) => (i > 0 ? random(0, 9) : random(1, 9)))
return parseInt(nums.join(''))
} else if (arguments.length >= 2) {
@ -626,4 +626,64 @@ export function aspectAroundFunction(obj, funcName, callback) {
},
})
}
}
}
/**
* 休眠
* @param ms 毫秒
* @return {Promise<unknown>}
*/
export function sleep(ms) {
return new Promise(function (resolve) {
return setTimeout(resolve, ms);
});
}
/**
* 获取指定的 $refs 对象
* 有时候可能会遇到组件未挂载到页面中的情况,导致无法获取 $refs 中的某个对象
* 这个方法可以等待挂载完成之后再返回 $refs 的对象,避免报错
*
* 用法示例let modalRef = getRefPromise(this, 'modal')
* @param vm vue实例
* @param name 要获取的ref名称
* @param noComment $el 标签不能是注释
**/
export function getRefPromise(vm, name, noComment = true) {
return new Promise((resolve) => {
(function next() {
let ref = vm.$refs[name]
if (ref && (noComment && ref.$el.tagName)) {
resolve(ref)
} else {
setTimeout(() => {
if (noComment) {
vm.$forceUpdate()
}
next()
}, 10)
}
})()
})
}
/**
* 导出文件xlsx的mime-type
* xls: application/vnd.ms-excel
* @type {string}
*/
export const EXPORT_MIME_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
/**
* 导出excel文件后缀
* @type {string}
*/
export const EXPORT_FILE_SUFFIX = ".xlsx";
/**
* 字符串是否为null或null字符串
* @param str
* @return {boolean}
*/
export function stringIsNull(str) {
return str == null || str === 'null' || str === 'undefined';
}

View File

@ -538,6 +538,7 @@
superQuery: {
fieldList: [
{ type: 'input', value: 'name', text: '姓名', },
{ type: 'switch', value: 'switch', text: '开关', },
{ type: 'select', value: 'sex', text: '性别', dictCode: 'sex' },
{ type: 'number', value: 'age', text: '年龄', },
{

View File

@ -24,7 +24,7 @@
</a-col>
<a-col :md="6" :sm="8">
<a-form-item label="模板类型">
<a-input placeholder="输入模板类型" v-model="queryParam.templateType"></a-input>
<j-dict-select-tag placeholder="选择模板类型" v-model="queryParam.templateType" dictCode="msgType"></j-dict-select-tag>
</a-form-item>
</a-col>
</template>
@ -51,7 +51,7 @@
@change="handleImportExcel">
<a-button type="primary" icon="import">导入</a-button>
</a-upload>
<a-dropdown v-if="selectedRowKeys.length > 0">
<!-- <a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel">
<a-icon type="delete"/>
@ -61,7 +61,7 @@
<a-button style="margin-left: 8px"> 批量操作
<a-icon type="down"/>
</a-button>
</a-dropdown>
</a-dropdown>-->
</div>
<!-- table区域-begin -->
@ -91,14 +91,21 @@
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
<a @click="handleMyEdit(record)">编辑</a>
<a-divider type="vertical"/>
<a-dropdown>
<a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
<a-menu slot="overlay">
<a-menu-item>
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
<a @click="handleUse(record)">应用</a>
</a-menu-item>
<a-menu-item>
<a @click="handleNotUse(record)">停用</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
@ -125,14 +132,19 @@
import SysMessageTestModal from './modules/SysMessageTestModal'
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import JEllipsis from "@/components/jeecg/JEllipsis";
import {httpAction} from '@/api/manage'
import { deleteAction } from '@/api/manage'
import JDictSelectTag from '@/components/dict/JDictSelectTag.vue'
export default {
name: "SysMessageTemplateList",
mixins: [JeecgListMixin],
components: {
JEllipsis,
SysMessageTemplateModal,
SysMessageTestModal
SysMessageTestModal,
JDictSelectTag
},
data() {
return {
@ -171,16 +183,22 @@
dataIndex: 'templateType',
customRender: function (text) {
if(text=='1') {
return "短信";
return "文本";
}
if(text=='2') {
return "邮件";
return "富文本";
}
if(text=='3') {
return "微信";
}
if(text=='4') {
return "系统";
}
},
{
title: '是否应用',
align: "center",
dataIndex: 'useStatus',
customRender: function (text) {
if(text=='1') {
return "";
}else{
return '否'
}
}
},
@ -209,8 +227,60 @@
handleTest(record){
this.$refs.testModal.open(record);
this.$refs.testModal.title = "发送测试";
}
},
//update-begin-author:taoyan date:2022-7-8 for: 修改应用状态
updateUseStatus(record, useStatus){
let formData = {
id: record.id, useStatus: useStatus
}
httpAction("/sys/message/sysMessageTemplate/edit", formData, 'put').then((res) => {
if (res.success) {
this.$message.success(res.message);
} else {
this.$message.warning(res.message);
}
}).finally(() => {
this.loadData()
})
},
handleUse(record){
this.updateUseStatus(record, '1')
},
handleNotUse(record){
this.updateUseStatus(record, '0')
},
handleMyEdit(record){
if(record.useStatus == '1'){
this.$message.warning('此模板已被应用,禁止编辑!');
}else{
this.handleEdit(record);
}
},
//update-end-author:taoyan date:2022-7-8 for: 修改应用状态
handleDelete: function (record) {
if(!this.url.delete){
this.$message.error("请设置url.delete属性!")
return
}
if(record.useStatus=='1'){
this.$message.error("该模板已被应用禁止删除!")
return
}
let id = record.id;
var that = this;
deleteAction(that.url.delete, {id: id}).then((res) => {
if (res.success) {
//重新计算分页问题
that.reCalculatePage(1)
that.$message.success(res.message);
that.loadData();
} else {
that.$message.warning(res.message);
}
});
},
}
}
</script>

View File

@ -50,6 +50,17 @@
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="24" >
<a-col :span="24" pull="2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="是否应用"
style="margin-left: -15px">
<j-switch v-decorator="['useStatus', validatorRules.useStatus]" :options="['1', '0']"></j-switch>
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="24">
<a-col :span="24" pull="4">
<a-form-item
@ -85,11 +96,13 @@
import pick from 'lodash.pick'
import { duplicateCheck } from '@/api/api'
import JEditor from '@/components/jeecg/JEditor'
import JSwitch from '@/components/jeecg/JSwitch'
export default {
name: "SysMessageTemplateModal",
components:{
JEditor
JEditor,
JSwitch
},
data() {
return {
@ -111,6 +124,7 @@
templateCode: {rules: [{required: true, message: '请输入模板CODE!' },{validator: this.validateTemplateCode}]},
templateName: {rules: [{required: true, message: '请输入模板标题!'}]},
templateContent: {rules: []},
useStatus:{rules: []},
templateType: {rules: [{required: true, message: '请输入模板类型!'}]},
},
url: {
@ -140,9 +154,9 @@
this.visible = true;
this.$nextTick(() => {
if(this.useEditor){
this.form.setFieldsValue(pick(this.model, 'templateCode', 'templateName', 'templateTestJson', 'templateType'))
this.form.setFieldsValue(pick(this.model, 'useStatus', 'templateCode', 'templateName', 'templateTestJson', 'templateType'))
}else{
this.form.setFieldsValue(pick(this.model, 'templateCode', 'templateContent', 'templateName', 'templateTestJson', 'templateType'))
this.form.setFieldsValue(pick(this.model, 'useStatus', 'templateCode', 'templateContent', 'templateName', 'templateTestJson', 'templateType'))
}
});
},

View File

@ -34,14 +34,15 @@
label="消息类型">
<j-dict-select-tag
v-model="msgType"
type="radio"
placeholder="请选择消息类型"
dictCode="msgType"/>
dictCode="messageType"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="消息接收方">
<a-input placeholder="输入消息接收方" v-model="receiver"/>
<j-select-user-by-dep placeholder="选择消息接收方" v-model="receiver"></j-select-user-by-dep>
</a-form-item>
</a-form>
</a-spin>
@ -50,9 +51,13 @@
<script>
import {httpAction} from '@/api/manage'
import JSelectUserByDep from '@/components/jeecgbiz/JSelectUserByDep'
export default {
name: "SysMessageTestModal",
components:{
JSelectUserByDep
},
data() {
return {
title: "操作",
@ -74,7 +79,7 @@
templateName: "",
templateContent: "",
receiver: "",
msgType: "",
msgType: "system",
testData: "",
sendParams: {}
}
@ -89,7 +94,7 @@
},
close() {
this.receiver = "";
this.msgType = "";
this.msgType = "system";
this.sendParams = {};
this.visible = false;
},

View File

@ -110,10 +110,13 @@
</a-radio-group>
</template>
</a-form-model-item>
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="部门负责人">
<j-select-multi-user v-model="model.directorUserIds" valueKey="id"></j-select-multi-user>
</a-form-model-item>
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="排序">
<a-input-number v-model="model.departOrder" />
</a-form-model-item>
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="手机号">
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="手机号" prop="mobile">
<a-input placeholder="请输入手机号" v-model="model.mobile" />
</a-form-model-item>
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="地址">
@ -149,6 +152,7 @@
import {httpAction, deleteAction} from '@/api/manage'
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import DepartAuthModal from './modules/DepartAuthModal'
import Vue from 'vue'
// 表头
const columns = [
{
@ -236,7 +240,7 @@
departName: [{required: true, message: '请输入机构/部门名称!'}],
orgCode: [{required: true, message: '请输入机构编码!'}],
orgCategory:[{required: true, message: '请输入机构类型!'}],
mobile:[{validator: this.validateMobile}]
mobile: Vue.prototype.rules.mobile2
},
url: {
delete: '/sys/sysDepart/delete',
@ -246,6 +250,7 @@
importExcelUrl: "sys/sysDepart/importExcel",
},
orgCategoryDisabled:false,
oldDirectorUserIds:""
}
},
computed: {
@ -394,7 +399,13 @@
this.model.parentId = record.parentId
this.setValuesToForm(record)
this.$refs.departAuth.show(record.id);
this.oldDirectorUserIds = record.directorUserIds
//update-beign-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候触发手机号校验
this.$nextTick(()=>{
this.$refs.form.validateField('mobile')
})
//update-end-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候触发手机号校验
},
// 触发onSelect事件时,为部门树右侧的form表单赋值
setValuesToForm(record) {
@ -431,6 +442,10 @@
return
}
//update-begin---author:wangshuai ---date:20200308 for[JTC-119]在部门管理菜单下设置部门负责人
this.currSelected.oldDirectorUserIds = this.oldDirectorUserIds
//update-end---author:wangshuai ---date:20200308 for[JTC-119]在部门管理菜单下设置部门负责人
httpAction(this.url.edit, this.currSelected, 'put').then((res) => {
if (res.success) {
this.$message.success('保存成功!')

View File

@ -105,6 +105,9 @@
</a-radio-group>
</template>
</a-form-model-item>
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="部门负责人">
<j-select-multi-user v-model="model.directorUserIds" valueKey="id"></j-select-multi-user>
</a-form-model-item>
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="排序" prop="departOrder">
<a-input-number v-model="model.departOrder"/>
</a-form-model-item>
@ -146,6 +149,7 @@
import DepartAuthModal from './modules/DepartAuthModal'
import { cloneObject } from '@/utils/util'
import JThirdAppButton from '@comp/jeecgbiz/thirdApp/JThirdAppButton'
import Vue from 'vue'
// 表头
const columns = [
{
@ -239,7 +243,7 @@
departName: [{required: true, message: '请输入机构/部门名称!'}],
orgCode: [{required: true, message: '请输入机构编码!'}],
orgCategory: [{required: true, message: '请输入机构类型!'}],
mobile: [{validator: this.validateMobile}]
mobile: Vue.prototype.rules.mobile2
},
url: {
delete: '/sys/sysDepart/delete',
@ -249,6 +253,7 @@
importExcelUrl: "sys/sysDepart/importExcel",
},
orgCategoryDisabled:false,
oldDirectorUserIds:"" //旧的负责人id
}
},
computed: {
@ -435,7 +440,15 @@
this.model.parentId = record.parentId
this.setValuesToForm(record)
this.$refs.departAuth.show(record.id);
//update-begin---author:wangshuai ---date:20220316 for[JTC-119]在部门管理菜单下设置部门负责人
this.oldDirectorUserIds = record.directorUserIds
//update-end---author:wangshuai ---date:20220316 for[JTC-119]在部门管理菜单下设置部门负责人
//update-beign-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候触发手机号校验
this.$nextTick(()=>{
this.$refs.form.validateField('mobile')
})
//update-end-author:taoyan date:20220316 for: VUEN-329【bug】为什么不是失去焦点的时候触发手机号校验
},
// 触发onSelect事件时,为部门树右侧的form表单赋值
setValuesToForm(record) {
@ -478,6 +491,9 @@
let formData = Object.assign(this.currSelected, this.model)
console.log('Received values of form: ', formData)
//update-begin---author:wangshuai ---date:20220316 for[JTC-119]在部门管理菜单下设置部门负责人
formData.oldDirectorUserIds = this.oldDirectorUserIds
//update-end---author:wangshuai ---date:20220316 for[JTC-119]在部门管理菜单下设置部门负责人
httpAction(this.url.edit, formData, 'put').then((res) => {
if (res.success) {
this.$message.success('保存成功!')
@ -598,16 +614,6 @@
}
},
// <!---- author:os_chengtgen -- date:20190827 -- for:切换父子勾选模式 =======------>
// 验证手机号
validateMobile(rule,value,callback){
if (!value || new RegExp(/^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$/).test(value)){
callback();
}else{
callback("您的手机号码格式不正确!");
}
},
onSyncFinally({isToLocal}) {
// 同步到本地时刷新下数据
if (isToLocal) {

View File

@ -63,7 +63,6 @@
<a @click="handleOpen(record)">用户</a>
<a-divider type="vertical"/>
<a-dropdown>
<a class="ant-dropdown-link">
更多 <a-icon type="down"/>
@ -125,7 +124,7 @@
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel2">
<a-icon type="delete"/>
删除
取消关联
</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作
@ -161,8 +160,8 @@
</a>
<a-menu slot="overlay">
<a-menu-item>
<a-popconfirm title="确定删除?" @confirm="() => handleDelete2(record.id)">
<a>删除</a>
<a-popconfirm title="确定取消关联?" @confirm="() => handleDelete2(record.id)">
<a>取消关联</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
@ -453,7 +452,7 @@
var that = this
console.log(this.currentDeptId)
this.$confirm({
title: '确认删除',
title: '确认取消关联',
content: '是否删除选中数据?',
onOk: function() {
deleteAction(that.url.deleteBatch2, { roleId: that.currentRoleId, userIds: ids }).then((res) => {

View File

@ -115,7 +115,7 @@
align:"center",
dataIndex: 'id'
},
{
/*{
title:'开始时间',
align:"center",
dataIndex: 'beginDate'
@ -124,7 +124,7 @@
title:'结束时间',
align:"center",
dataIndex: 'endDate'
},
},*/
{
title:'状态',
align:"center",

View File

@ -66,7 +66,7 @@
<!-- 操作按钮区域 -->
<div class="table-operator" style="border-top: 5px">
<a-button @click="handleAdd" type="primary" icon="plus" >添加用户</a-button>
<a-button type="primary" icon="download" @click="handleExportXls('用户信息')">导出</a-button>
<a-button type="primary" icon="download" @click="handleExportXls('用户信息')">导出</a-button>
<a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
<a-button type="primary" icon="import">导入</a-button>
</a-upload>
@ -156,10 +156,6 @@
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a href="javascript:;" @click="handleAgentSettings(record.username)">代理人</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
@ -378,10 +374,6 @@
handleChangePassword(username) {
this.$refs.passwordmodal.show(username);
},
handleAgentSettings(username){
this.$refs.sysUserAgentModal.agentSettings(username);
this.$refs.sysUserAgentModal.title = "用户代理人设置";
},
passwordModalOk() {
//TODO 密码修改完成 不需要刷新页面可以把datasource中的数据更新一下
},

View File

@ -53,6 +53,9 @@
</a-radio-group>
</template>
</a-form-model-item>
<a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="部门负责人">
<j-select-multi-user v-model="model.directorUserIds" valueKey="id"></j-select-multi-user>
</a-form-model-item>
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"

View File

@ -281,6 +281,10 @@
this.$refs.modalForm.title = "编辑";
this.$refs.modalForm.departDisabled = true;
this.$refs.modalForm.disableSubmit = false;
//update-begin---author:wangshuai ---date:20220315 for[issues/3472]给新建用户赋予角色的逻辑漏洞------------
//部门中角色信息隐藏掉
this.$refs.modalForm.roleDisabled = true
//update-end---author:wangshuai ---date:20220315 for[issues/3472]给新建用户赋予角色的逻辑漏洞------------
this.$refs.modalForm.edit(record);
},
handleAdd: function () {
@ -288,6 +292,10 @@
this.$message.error("请选择一个部门!")
} else {
this.$refs.modalForm.departDisabled = true;
//update-begin---author:wangshuai ---date:20220315 for[issues/3472]给新建用户赋予角色的逻辑漏洞------------
//部门中角色信息隐藏掉
this.$refs.modalForm.roleDisabled = true
//update-end---author:wangshuai ---date:20220315 for[issues/3472]给新建用户赋予角色的逻辑漏洞------------
//初始化负责部门
this.$refs.modalForm.nextDepartOptions=[{value:this.currentDept.key,label:this.currentDept.title}]
this.$refs.modalForm.title = "新增";

View File

@ -164,7 +164,7 @@
param.id = this.model.id
}
if(value){
let reg=new RegExp("[`_~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]")
let reg=new RegExp("[`~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]")
if(reg.test(value)){
callback("数据值不能包含特殊字符!")
}else{

View File

@ -99,7 +99,7 @@
edit: "/sys/annountCement/edit",
},
userType:false,
userIds:[],
userIds:"",
selectedUser:[],
disabled:false,
msgContent:"",
@ -191,16 +191,19 @@
},
resetUser (){
this.userType = false;
this.userIds = [];
//update-begin---author:wangshuai ---date:20220318 for[issues/I4X63V]vue有些页面报错但是在线演示的却没有-----
this.userIds ="";
//update-end---author:wangshuai ---date:20220318 for[issues/I4X63V]vue有些页面报错但是在线演示的却没有-----
this.disabled = false;
this.$refs.UserListModal.edit(null,null);
},
chooseMsgType(e) {
if("USER" == e.target.value) {
this.userType = true;
} else {
this.userType = false;
this.userIds = [];
//update-begin---author:wangshuai ---date:20220318 for[issues/I4X63V]vue有些页面报错但是在线演示的却没有-----
this.userIds = "";
//update-end---author:wangshuai ---date:20220318 for[issues/I4X63V]vue有些页面报错但是在线演示的却没有-----
}
},
startTimeValidate(rule,value,callback){

View File

@ -79,7 +79,7 @@
<script>
import pick from 'lodash.pick'
import { httpAction, postAction } from '@/api/manage'
import { httpAction, postAction,getAction } from '@/api/manage'
import { validateDuplicateValue } from '@/utils/util'
export default {
@ -129,6 +129,7 @@
url: {
add: '/sys/dataSource/add',
edit: '/sys/dataSource/edit',
queryById: '/sys/dataSource/queryById',
},
dbDriverMap: {
// MySQL 数据库
@ -202,9 +203,17 @@
add() {
this.edit({})
},
edit(record) {
async edit(record) {
this.form.resetFields()
this.model = Object.assign({}, record)
//update-begin-author:liusq---date:20220705--for: 编辑时,查询获取解密后的密码 ---
if(record.id){
let res = await getAction(this.url.queryById, {id:record.id});
if (res.success) {
this.model = Object.assign({}, {...res.result})
}
}
//update-end-author:liusq---date:20220705--for: 编辑时,查询获取解密后的密码 ---
this.visible = true
this.$nextTick(() => {
this.form.setFieldsValue(pick(this.model, 'code', 'name', 'remark', 'dbType', 'dbDriver', 'dbUrl', 'dbName', 'dbUsername', 'dbPassword'))

View File

@ -55,6 +55,11 @@
ruleClass: [{ required: true, message: '规则实现类不能为空' }],
ruleParams: [{
validator: (rule, value, callback) => {
//update-begin---author:wangshuai ---date:20220509 for[VUEN-907]规则参数不是必填,如果为空不检验即可------------
if (!value) {
callback()
}
//update-end---author:wangshuai ---date:20220509 for[VUEN-907]规则参数不是必填,如果为空不检验即可--------------
try {
let json = JSON.parse(value)

View File

@ -15,7 +15,7 @@
</a-form-model-item>
</a-col>
<a-col :span="24">
<!-- <a-col :span="24">
<a-form-model-item label="开始时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-date placeholder="请选择开始时间" v-model="model.beginDate" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"/>
</a-form-model-item>
@ -24,7 +24,8 @@
<a-form-model-item label="结束时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-date placeholder="请选择结束时间" v-model="model.endDate" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"/>
</a-form-model-item>
</a-col>
</a-col>-->
<a-col :span="24">
<a-form-model-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-radio-group name="tenantStatus" v-model="model.status">

View File

@ -1,13 +1,13 @@
<template>
<a-drawer
:title="title"
:maskClosable="true"
:width="drawerWidth"
placement="right"
:closable="true"
@close="handleCancel"
:visible="visible"
style="height: 100%;">
:title="title"
:maskClosable="true"
:width="drawerWidth"
placement="right"
:closable="true"
@close="handleCancel"
:visible="visible"
style="height: 100%;">
<template slot="title">
<div style="width: 100%;">
@ -47,17 +47,17 @@
<a-form-model-item label="手机号码" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="phone">
<a-input placeholder="请输入手机号码" v-model="model.phone" />
</a-form-model-item>
<a-form-model-item label="职务" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-select-position placeholder="请选择职务" :multiple="false" v-model="model.post"/>
</a-form-model-item>
<a-form-model-item label="角色分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!roleDisabled" >
<j-multi-select-tag
:disabled="disableSubmit"
v-model="model.selectedroles"
:options="rolesOptions"
placeholder="请选择角色">
:disabled="disableSubmit"
v-model="model.selectedroles"
:options="rolesOptions"
placeholder="请选择角色">
</j-multi-select-tag>
</a-form-model-item>
@ -69,10 +69,10 @@
<!--租户分配-->
<a-form-model-item label="租户分配" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="!departDisabled">
<j-multi-select-tag
:disabled="disableSubmit"
v-model="model.relTenantIds"
:options="tenantsOptions"
placeholder="请选择租户">
:disabled="disableSubmit"
v-model="model.relTenantIds"
:options="tenantsOptions"
placeholder="请选择租户">
</j-multi-select-tag>
</a-form-model-item>
@ -82,12 +82,12 @@
<a-radio :value="2">上级</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="负责部门" :labelCol="labelCol" :wrapperCol="wrapperCol" v-if="departIdShow==true">
<a-form-model-item label="负责部门" :labelCol="labelCol" :wrapperCol="wrapperCol" v-show="departIdShow==true">
<j-multi-select-tag
:disabled="disableSubmit"
v-model="model.departIds"
:options="nextDepartOptions"
placeholder="请选择负责部门">
:disabled="disableSubmit"
v-model="model.departIds"
:options="nextDepartOptions"
placeholder="请选择负责部门">
</j-multi-select-tag>
</a-form-model-item>
@ -97,11 +97,11 @@
<a-form-model-item label="生日" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-date-picker
style="width: 100%"
placeholder="请选择生日"
v-model="model.birthday"
:format="dateFormat"
:getCalendarContainer="node => node.parentNode"/>
style="width: 100%"
placeholder="请选择生日"
v-model="model.birthday"
:format="dateFormat"
:getCalendarContainer="node => node.parentNode"/>
</a-form-model-item>
<a-form-model-item label="性别" :labelCol="labelCol" :wrapperCol="wrapperCol">
@ -162,17 +162,17 @@
dateFormat:"YYYY-MM-DD",
validatorRules:{
username:[{required: true, message: '请输入用户账号!'},
{validator: this.validateUsername,}],
{validator: this.validateUsername,}],
password: [{required: true,pattern:/^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,message: '密码由8位数字大小写字母和特殊符号组成!'},
{validator: this.validateToNextPassword,trigger: 'change'}],
{validator: this.validateToNextPassword,trigger: 'change'}],
confirmpassword: [{required: true, message: '请重新输入登录密码!',},
{ validator: this.compareToFirstPassword,}],
{ validator: this.compareToFirstPassword,}],
realname:[{ required: true, message: '请输入用户名称!' }],
phone: [{required: true, message: '请输入手机号!'}, {validator: this.validatePhone}],
email: [{validator: this.validateEmail}],
roles:{},
workNo:[ { required: true, message: '请输入工号' },
{ validator: this.validateWorkNo }],
{ validator: this.validateWorkNo }],
telephone: [{ pattern: /^0\d{2,3}-[1-9]\d{6,7}$/, message: '请输入正确的座机号码' },]
},
departIdShow:false,
@ -441,11 +441,11 @@
};
duplicateCheck(params).then((res) => {
if (res.success) {
callback()
} else {
callback("用户名已存在!")
}
})
callback()
} else {
callback("用户名已存在!")
}
})
},
validateWorkNo(rule, value, callback){
var params = {
@ -476,9 +476,9 @@
},
identityChange(e){
if(e.target.value===1){
this.departIdShow=false;
this.departIdShow=false;
}else{
this.departIdShow=true;
this.departIdShow=true;
}
}
}

View File

@ -43,8 +43,8 @@
currdatetime: '',
loginType: 0,
model:{
username: '',
password: '',
username: 'admin',
password: '123456',
inputCode: ''
},
validatorRules:{
@ -136,6 +136,11 @@
this.Login(loginParams).then((res) => {
this.$emit('success', res.result)
}).catch((err) => {
//update-begin-author: taoyan date:20220425 for: 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变 #41
if(err && err.code===412){
this.handleChangeCheckCode();
}
//update-end-author: taoyan date:20220425 for: 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变 #41
this.$emit('fail', err)
});
}else{