Jeecg-Boot 2.1.4 版本发布 | 重构较大,较多新功能

This commit is contained in:
zhangdaiscott 2020-02-24 02:44:53 +08:00
parent 06847cd801
commit 4a4f236772
269 changed files with 15734 additions and 24855 deletions

View File

@ -1,13 +1,13 @@
Ant Design Jeecg Vue
====
当前最新版本: 2.1.3发布日期20191226
当前最新版本: 2.0.4发布日期20200224
Overview
----
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Ant Design Pro Vue 版
Jeecg-boot 的前端UI框架采用前后端分离框架,提供强大代码生成器的快速开发平台。
Jeecg-boot 的前段UI框架采用前后端分离方案,提供强大代码生成器的快速开发平台。
前端页面代码和后端功能代码一键生成不需要写任何代码保持jeecg一贯的强大

View File

@ -1,6 +1,6 @@
{
"name": "vue-antd-jeecg",
"version": "2.1.3",
"version": "2.1.4",
"private": true,
"scripts": {
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
@ -10,7 +10,7 @@
},
"dependencies": {
"@antv/data-set": "^0.10.2",
"@jeecg/antd-online-re": "2.1.3",
"@jeecg/antd-online-214": "^2.1.4",
"@tinymce/tinymce-vue": "^2.0.0",
"ant-design-vue": "^1.4.0",
"apexcharts": "^3.6.5",
@ -24,7 +24,7 @@
"lodash.pick": "^4.4.0",
"md5": "^2.2.1",
"nprogress": "^0.2.0",
"tinymce": "^5.0.2",
"tinymce": "^5.1.4",
"viser-vue": "^2.4.4",
"vue": "^2.6.10",
"vue-apexcharts": "^1.3.2",
@ -51,12 +51,12 @@
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.1.0",
"html-webpack-plugin": "^4.0.0-beta.11",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"node-sass": "^4.11.0",
"sass-loader": "^7.0.1",
"vue-template-compiler": "^2.6.10",
"html-webpack-plugin": "^4.0.0-beta.11"
"vue-template-compiler": "^2.6.10"
},
"eslintConfig": {
"root": true,

View File

@ -5,9 +5,9 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Jeecg-Boot 快速开发平台</title>
<title>Jeecg-Boot 企业级快速开发平台</title>
<link rel="icon" href="<%= BASE_URL %>logo.png">
<script src="https://cdn.bootcss.com/babel-polyfill/7.6.0/polyfill.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.2.5/polyfill.js"></script>
<style>
html,
body,
@ -244,8 +244,8 @@
window._CONFIG = {};
window._CONFIG['domianURL'] = 'http://127.0.0.1:8080/jeecg-boot';
window._CONFIG['casPrefixUrl'] = 'http://cas.example.org:8443/cas';
window._CONFIG['imgDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/view';
window._CONFIG['downloadUrl'] = window._CONFIG['domianURL'] + '/sys/common/download';
window._CONFIG['onlinePreviewDomainURL'] = 'http://fileview.jeecg.com/onlinePreview'
window._CONFIG['staticDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/static';
window._CONFIG['pdfDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/pdf/pdfPreviewIframe';
</script>
</head>

View File

@ -25,7 +25,7 @@ const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
//验证用户是否存在
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
//改变密码
const changPassword = (params)=>putAction("/sys/user/changPassword",params);
const changePassword = (params)=>putAction("/sys/user/changePassword",params);
//权限管理
const addPermission= (params)=>postAction("/sys/permission/add",params);
@ -34,6 +34,7 @@ const getPermissionList = (params)=>getAction("/sys/permission/list",params);
/*update_begin author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
/*update_end author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
// const deletePermission = (params)=>deleteAction("/sys/permission/delete",params);
@ -56,6 +57,14 @@ const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",p
const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params);
const deleteByDepartId = (params)=>deleteAction("/sys/sysDepart/delete",params);
//二级部门管理
const queryDepartPermission = (params)=>getAction("/sys/permission/queryDepartPermission",params);
const saveDepartPermission = (params)=>postAction("/sys/permission/saveDepartPermission",params);
const queryTreeListForDeptRole = (params)=>getAction("/sys/sysDepartPermission/queryTreeListForDeptRole",params);
const queryDeptRolePermission = (params)=>getAction("/sys/sysDepartPermission/queryDeptRolePermission",params);
const saveDeptRolePermission = (params)=>postAction("/sys/sysDepartPermission/saveDeptRolePermission",params);
const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params);
//日志管理
//const getLogList = (params)=>getAction("/sys/log/list",params);
const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
@ -94,6 +103,7 @@ const queryUserRoleMap = (params)=>getAction("/sys/user/queryUserRoleMap",params
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
// 加载分类字典
const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params);
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
export {
// imgView,
@ -108,7 +118,7 @@ export {
queryall,
frozenBatch,
checkOnlyUser,
changPassword,
changePassword,
getPermissionList,
addPermission,
editPermission,
@ -142,7 +152,15 @@ export {
queryTreeListForRole,
getSystemMenuList,
getSystemSubmenu,
loadCategoryData
getSystemSubmenuBatch,
loadCategoryData,
checkRuleByCode,
queryDepartPermission,
saveDepartPermission,
queryTreeListForDeptRole,
queryDeptRolePermission,
saveDeptRolePermission,
queryMyDepartTreeList
}

View File

@ -112,3 +112,17 @@ export function downFile(url,parameter){
})
}
/**
* 获取文件访问路径
* @param avatar
* @param imgerver
* @param str
* @returns {*}
*/
export function getFileAccessHttpUrl(avatar,imgerver,subStr) {
if(avatar && avatar.indexOf(subStr) != -1 ){
return avatar;
}else{
return imgerver + "/" + avatar;
}
}

View File

@ -5,7 +5,7 @@
}
/** Button按钮间距 */
.table-operator .ant-btn {
margin-right: 6px
margin: 8px 8px 0 0;
}
/*列表td的padding设置 可以控制列表大小*/
.ant-table-tbody .ant-table-row td {

View File

@ -1,7 +1,7 @@
<template>
<div :style="{ padding: '0 50px 32px 0' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :padding=" padding">
<v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :padding=" padding" :onClick="handleClick">
<v-tooltip/>
<v-legend/>
<v-axis/>
@ -12,9 +12,11 @@
</template>
<script>
import { ChartEventMixins } from './mixins/ChartMixins'
export default {
name: 'BarMultid',
name: 'BarAndLine',
mixins: [ChartEventMixins],
props: {
title: {
type: String,

View File

@ -1,71 +1,83 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart :forceFit="true" :height="254" :data="chartData" :padding="['auto', 'auto', '40', '50']">
<v-tooltip />
<v-axis />
<v-legend />
<v-bar position="x*y" color="type" :adjust="adjust" />
<v-chart :data="data" :height="height" :force-fit="true" :onClick="handleClick">
<v-tooltip/>
<v-axis/>
<v-legend/>
<v-bar position="x*y" color="type" :adjust="adjust"/>
</v-chart>
</div>
</template>
<script>
import { DataSet } from '@antv/data-set'
import { ChartEventMixins } from './mixins/ChartMixins'
const sourceDataConst = [
{ type: 'Jeecg', 'Jan.': 18.9, 'Feb.': 28.8, 'Mar.': 39.3, 'Apr.': 81.4, 'May': 47, 'Jun.': 20.3, 'Jul.': 24, 'Aug.': 35.6 },
{ type: 'Jeebt', 'Jan.': 12.4, 'Feb.': 23.2, 'Mar.': 34.5, 'Apr.': 99.7, 'May': 52.6, 'Jun.': 35.5, 'Jul.': 37.4, 'Aug.': 42.4 },
];
const fieldsConst = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.'];
export default {
name: 'BarMultid',
mixins: [ChartEventMixins],
props: {
title: {
type: String,
default: ''
},
sourceData:{
type:Array,
default:()=>[]
dataSource: {
type: Array,
default: () => [
{ type: 'Jeecg', 'Jan.': 18.9, 'Feb.': 28.8, 'Mar.': 39.3, 'Apr.': 81.4, 'May': 47, 'Jun.': 20.3, 'Jul.': 24, 'Aug.': 35.6 },
{ type: 'Jeebt', 'Jan.': 12.4, 'Feb.': 23.2, 'Mar.': 34.5, 'Apr.': 99.7, 'May': 52.6, 'Jun.': 35.5, 'Jul.': 37.4, 'Aug.': 42.4 }
]
},
fields:{
type:Array,
default:()=>[]
fields: {
type: Array,
default: () => ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.']
},
// 别名需要的格式[{field:'name',alias:'姓名'}, {field:'sex',alias:'性别'}]
aliases: {
type: Array,
default: () => []
},
height: {
type: Number,
default: 254
}
},
data() {
return {
chartData:"",
height: 400,
adjust: [{
type: 'dodge',
marginRatio: 1 / 32,
}],
};
},
watch: {
'sourceData': function () {
this.drawChart();
marginRatio: 1 / 32
}]
}
},
mounted(){
this.drawChart()
},
methods:{
drawChart(){
let temp = sourceDataConst;
if(this.sourceData && this.sourceData.length>0){
temp = this.sourceData
}
const dv = new DataSet.View().source(temp);
computed: {
data() {
const dv = new DataSet.View().source(this.dataSource)
dv.transform({
type: 'fold',
fields:(!this.fields||this.fields.length==0)?fieldsConst:this.fields,
fields: this.fields,
key: 'x',
value: 'y',
});
this.chartData=dv.rows;
value: 'y'
})
// bar 使用不了 - / 所以替换下
let rows = dv.rows.map(row => {
if (typeof row.x === 'string') {
row.x = row.x.replace(/[-/]/g, '_')
}
return row
})
// 替换别名
rows.forEach(row => {
for (let item of this.aliases) {
if (item.field === row.type) {
row.type = item.alias
break
}
}
})
return rows
}
}
}

View File

@ -1,7 +1,7 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart :force-fit="true" :height="height" :data="data" :scale="scale">
<v-chart :force-fit="true" :height="height" :data="data" :scale="scale" :onClick="handleClick">
<v-tooltip/>
<v-axis/>
<v-legend/>
@ -13,9 +13,11 @@
<script>
import { DataSet } from '@antv/data-set'
import { ChartEventMixins } from './mixins/ChartMixins'
export default {
name: 'LineChartMultid',
mixins: [ChartEventMixins],
props: {
title: {
type: String,

View File

@ -1,5 +1,5 @@
<template>
<v-chart :forceFit="true" :height="height" :data="data" :scale="scale">
<v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :onClick="handleClick">
<v-tooltip :showTitle="false" dataKey="item*percent"/>
<v-axis/>
<v-legend dataKey="item"/>
@ -10,8 +10,11 @@
<script>
const DataSet = require('@antv/data-set')
import { ChartEventMixins } from './mixins/ChartMixins'
export default {
name: 'Pie',
mixins: [ChartEventMixins],
props: {
title: {
type: String,

View File

@ -0,0 +1,10 @@
export const ChartEventMixins = {
methods: {
handleClick(event, chart) {
this.handleEvent('click', event, chart)
},
handleEvent(eventName, event, chart) {
this.$emit(eventName, event, chart)
},
}
}

View File

@ -1,10 +1,10 @@
<template>
<a-radio-group v-if="tagType=='radio'" @change="handleInput" :value="value" :disabled="disabled">
<a-radio-group v-if="tagType=='radio'" @change="handleInput" :value="getValueSting" :disabled="disabled">
<a-radio v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio>
</a-radio-group>
<a-select v-else-if="tagType=='select'" :getPopupContainer = "(target) => target.parentNode" :placeholder="placeholder" :disabled="disabled" :value="value" @change="handleInput">
<a-select-option value="">请选择</a-select-option>
<a-select v-else-if="tagType=='select'" :getPopupContainer = "(target) => target.parentNode" :placeholder="placeholder" :disabled="disabled" :value="getValueSting" @change="handleInput">
<a-select-option :value="undefined">请选择</a-select-option>
<a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">
<span style="display: inline-block;width: 100%" :title=" item.text || item.label ">
{{ item.text || item.label }}
@ -23,7 +23,7 @@
placeholder: String,
triggerChange: Boolean,
disabled: Boolean,
value: String,
value: [String, Number],
type: String
},
data() {
@ -50,6 +50,11 @@
//获取字典数据
// this.initDictData();
},
computed: {
getValueSting(){
return this.value ? this.value.toString() : null;
},
},
methods: {
initDictData() {
//根据字典Code, 初始化字典数组

View File

@ -47,10 +47,20 @@ export function filterDictText(dictOptions, text) {
* @return String
*/
export function filterMultiDictText(dictOptions, text) {
//js !text 认为0为空所以做提前处理
if(text === 0 || text === '0'){
for (let dictItem of dictOptions) {
if (text == dictItem.value) {
return dictItem.text
}
}
}
if(!text || !dictOptions || dictOptions.length==0){
return ""
}
let re = "";
text = text.toString()
let arr = text.split(",")
dictOptions.forEach(function (option) {
for(let i=0;i<arr.length;i++){

View File

@ -32,6 +32,8 @@
</a-col>
</a-row>
<slot name="actionButtonAfter" :target="getVM()"/>
<div :id="`${caseId}inputTable`" class="input-table">
<!-- 渲染表头 -->
<div class="thead" ref="thead">
@ -142,7 +144,9 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<input
:id="id"
@ -175,7 +179,9 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@ -211,7 +217,9 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@ -278,19 +286,33 @@
</template>
<div :hidden="uploadValues[id] != null">
<a-upload
name="file"
:data="{'isup':1}"
:multiple="false"
:action="col.action"
:headers="uploadGetHeaders(row,col)"
:showUploadList="false"
v-bind="buildProps(row,col)"
@change="(v)=>handleChangeUpload(v,id,row,col)"
<a-tooltip
:key="i"
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<a-button icon="upload">{{ col.placeholder }}</a-button>
</a-upload>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@mouseout="()=>{handleMouseoutCommono(row,col)}">
<a-upload
name="file"
:data="{'isup':1}"
:multiple="false"
:action="col.action"
:headers="uploadGetHeaders(row,col)"
:showUploadList="false"
v-bind="buildProps(row,col)"
@change="(v)=>handleChangeUpload(v,id,row,col)"
>
<a-button icon="upload">{{ col.placeholder }}</a-button>
</a-upload>
</span>
</a-tooltip>
</div>
</div>
@ -303,7 +325,10 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@mouseout="()=>{handleMouseoutCommono(row,col)}">
@ -359,19 +384,33 @@
</template>
<div :hidden="uploadValues[id] != null">
<a-upload
name="file"
:data="{'isup':1}"
:multiple="false"
:action="getUploadAction(col.action)"
:headers="uploadGetHeaders(row,col)"
:showUploadList="false"
v-bind="buildProps(row,col)"
@change="(v)=>handleChangeUpload(v,id,row,col)"
<a-tooltip
:key="i"
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<a-button icon="upload">{{ col.placeholder }}</a-button>
</a-upload>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@mouseout="()=>{handleMouseoutCommono(row,col)}">
<a-upload
name="file"
:data="{'isup':1}"
:multiple="false"
:action="getUploadAction(col.action)"
:headers="uploadGetHeaders(row,col)"
:showUploadList="false"
v-bind="buildProps(row,col)"
@change="(v)=>handleChangeUpload(v,id,row,col)"
>
<a-button icon="upload">{{ col.placeholder }}</a-button>
</a-upload>
</span>
</a-tooltip>
</div>
</div>
@ -406,19 +445,33 @@
</template>
<div :hidden="uploadValues[id] != null">
<a-upload
name="file"
:data="{'isup':1}"
:multiple="false"
:action="getUploadAction(col.action)"
:headers="uploadGetHeaders(row,col)"
:showUploadList="false"
v-bind="buildProps(row,col)"
@change="(v)=>handleChangeUpload(v,id,row,col)"
<a-tooltip
:key="i"
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<a-button icon="upload">请上传图片</a-button>
</a-upload>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@mouseout="()=>{handleMouseoutCommono(row,col)}">
<a-upload
name="file"
:data="{'isup':1}"
:multiple="false"
:action="getUploadAction(col.action)"
:headers="uploadGetHeaders(row,col)"
:showUploadList="false"
v-bind="buildProps(row,col)"
@change="(v)=>handleChangeUpload(v,id,row,col)"
>
<a-button icon="upload">请上传图片</a-button>
</a-upload>
</span>
</a-tooltip>
</div>
</div>
@ -433,7 +486,10 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@mouseout="()=>{handleMouseoutCommono(row,col)}">
@ -459,7 +515,9 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@ -492,7 +550,9 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@ -526,7 +586,9 @@
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:autoAdjustOverflow="true"
:getPopupContainer="getParentContainer"
>
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@ -693,6 +755,7 @@
}
},
created() {
this.inputValues = []
// 当前显示的tr
this.visibleTrEls = []
this.disabledRowIds = (this.disabledRowIds || [])
@ -771,149 +834,155 @@
dataSource: {
immediate: true,
handler: function (newValue) {
this.initialize()
// 兼容IE
this.getElementPromise('tbody').then(() => {
let rows = []
let checkboxValues = {}
let selectValues = {}
let jdateValues = {}
let slotValues = {}
let uploadValues = {}
let popupValues = {}
let radioValues = {}
let multiSelectValues = {}
let searchSelectValues = {}
this.initialize()
// 禁用行的id
let disabledRowIds = (this.disabledRowIds || [])
newValue.forEach((data, newValueIndex) => {
// 判断源数据是否带有id
if (data.id == null || data.id === '') {
data.id = this.removeCaseId(this.generateId() + newValueIndex)
}
let rows = []
let checkboxValues = {}
let selectValues = {}
let jdateValues = {}
let slotValues = {}
let uploadValues = {}
let popupValues = {}
let radioValues = {}
let multiSelectValues = {}
let searchSelectValues = {}
let value = { id: this.caseId + data.id }
let row = { id: value.id }
let disabled = false
this.columns.forEach(column => {
let inputId = column.key + value.id
let sourceValue = (data[column.key] == null ? '' : data[column.key]).toString()
if (column.type === FormTypes.checkbox) {
// 判断是否设定了customValue自定义值
if (column.customValue instanceof Array) {
let customValue = (column.customValue[0] || '').toString()
checkboxValues[inputId] = (sourceValue === customValue)
} else {
checkboxValues[inputId] = sourceValue
}
} else if (column.type === FormTypes.select) {
if (sourceValue) {
// 判断是否是多选
selectValues[inputId] = (column.props || {})['mode'] === 'multiple' ? sourceValue.split(',') : sourceValue
} else {
selectValues[inputId] = undefined
}
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
jdateValues[inputId] = sourceValue
} else if (column.type === FormTypes.slot) {
if (sourceValue !== 0 && !sourceValue) {
slotValues[inputId] = column.defaultValue
} else {
slotValues[inputId] = sourceValue
}
} else if (column.type === FormTypes.popup) {
popupValues[inputId] = sourceValue
} else if (column.type === FormTypes.radio) {
radioValues[inputId] = sourceValue
} else if (column.type === FormTypes.sel_search) {
searchSelectValues[inputId] = sourceValue
} else if (column.type === FormTypes.list_multi) {
if (sourceValue.length > 0) {
multiSelectValues[inputId] = sourceValue.split(',')
} else {
multiSelectValues[inputId] = []
}
} else if (column.type === FormTypes.upload || column.type === FormTypes.file || column.type === FormTypes.image) {
if (sourceValue) {
let fileName = sourceValue.substring(sourceValue.lastIndexOf('/') + 1)
uploadValues[inputId] = {
name: fileName,
status: 'done',
path: sourceValue
}
}
} else {
value[column.key] = sourceValue
// 禁用行的id
let disabledRowIds = (this.disabledRowIds || [])
newValue.forEach((data, newValueIndex) => {
// 判断源数据是否带有id
if (data.id == null || data.id === '') {
data.id = this.removeCaseId(this.generateId() + newValueIndex)
}
// 解析disabledRows
for (let columnKey in this.disabledRows) {
// 判断是否有该属性
if (this.disabledRows.hasOwnProperty(columnKey) && data.hasOwnProperty(columnKey)) {
if (disabled !== true) {
let temp = this.disabledRows[columnKey]
// 禁用规则可以是一个数组
if (temp instanceof Array) {
disabled = temp.includes(data[columnKey])
} else {
disabled = (temp === data[columnKey])
let value = { id: this.caseId + data.id }
let row = { id: value.id }
let disabled = false
this.columns.forEach(column => {
let inputId = column.key + value.id
let sourceValue = (data[column.key] == null ? '' : data[column.key]).toString()
if (column.type === FormTypes.checkbox) {
// 判断是否设定了customValue自定义值
if (column.customValue instanceof Array) {
let customValue = (column.customValue[0] || '').toString()
checkboxValues[inputId] = (sourceValue === customValue)
} else {
checkboxValues[inputId] = sourceValue
}
} else if (column.type === FormTypes.select) {
if (sourceValue) {
// 判断是否是多选
selectValues[inputId] = (column.props || {})['mode'] === 'multiple' ? sourceValue.split(',') : sourceValue
} else {
selectValues[inputId] = undefined
}
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
jdateValues[inputId] = sourceValue
} else if (column.type === FormTypes.slot) {
if (sourceValue !== 0 && !sourceValue) {
slotValues[inputId] = column.defaultValue
} else {
slotValues[inputId] = sourceValue
}
} else if (column.type === FormTypes.popup) {
popupValues[inputId] = sourceValue
} else if (column.type === FormTypes.radio) {
radioValues[inputId] = sourceValue
} else if (column.type === FormTypes.sel_search) {
searchSelectValues[inputId] = sourceValue
} else if (column.type === FormTypes.list_multi) {
if (sourceValue.length > 0) {
multiSelectValues[inputId] = sourceValue.split(',')
} else {
multiSelectValues[inputId] = []
}
} else if (column.type === FormTypes.upload || column.type === FormTypes.file || column.type === FormTypes.image) {
if (sourceValue) {
let fileName = sourceValue.substring(sourceValue.lastIndexOf('/') + 1)
uploadValues[inputId] = {
name: fileName,
status: 'done',
path: sourceValue
}
if (disabled) {
disabledRowIds.push(row.id)
}
} else {
value[column.key] = sourceValue
}
// 解析disabledRows
for (let columnKey in this.disabledRows) {
// 判断是否有该属性
if (this.disabledRows.hasOwnProperty(columnKey) && data.hasOwnProperty(columnKey)) {
if (disabled !== true) {
let temp = this.disabledRows[columnKey]
// 禁用规则可以是一个数组
if (temp instanceof Array) {
disabled = temp.includes(data[columnKey])
} else {
disabled = (temp === data[columnKey])
}
if (disabled) {
disabledRowIds.push(row.id)
}
}
}
}
}
})
this.inputValues.push(value)
rows.push(row)
})
this.inputValues.push(value)
rows.push(row)
})
this.disabledRowIds = disabledRowIds
this.checkboxValues = checkboxValues
this.selectValues = selectValues
this.jdateValues = jdateValues
this.slotValues = slotValues
this.rows = rows
this.uploadValues = uploadValues
this.popupValues = popupValues
this.radioValues = radioValues
this.multiSelectValues = multiSelectValues
this.searchSelectValues = searchSelectValues
this.disabledRowIds = disabledRowIds
this.checkboxValues = checkboxValues
this.selectValues = selectValues
this.jdateValues = jdateValues
this.slotValues = slotValues
this.rows = rows
this.uploadValues = uploadValues
this.popupValues = popupValues
this.radioValues = radioValues
this.multiSelectValues = multiSelectValues
this.searchSelectValues = searchSelectValues
// 更新form表单的值
this.$nextTick(() => {
this.updateFormValues()
// 更新form表单的值
this.$nextTick(() => {
this.updateFormValues()
})
})
}
},
columns: {
immediate: true,
handler(columns) {
columns.forEach(column => {
if (column.type === FormTypes.select || column.type === FormTypes.list_multi || column.type === FormTypes.sel_search) {
// 兼容 旧版本 options
if (column.options instanceof Array) {
column.options = column.options.map(item => {
if (item) {
return {
...item,
text: item.text || item.title,
title: item.text || item.title
// 兼容IE
this.getElementPromise('tbody').then(() => {
columns.forEach(column => {
if (column.type === FormTypes.select || column.type === FormTypes.list_multi || column.type === FormTypes.sel_search) {
// 兼容 旧版本 options
if (column.options instanceof Array) {
column.options = column.options.map(item => {
if (item) {
return {
...item,
text: item.text || item.title,
title: item.text || item.title
}
}
}
return {}
})
return {}
})
}
if (column.dictCode) {
this._loadDictConcatToOptions(column)
}
}
if (column.dictCode) {
this._loadDictConcatToOptions(column)
}
}
})
})
}
},
@ -923,19 +992,12 @@
}
},
mounted() {
// 获取document element对象
let elements = {};
['inputTable', 'tbody'].forEach(id => {
elements[id] = document.getElementById(this.caseId + id)
})
this.el = elements
let vm = this
/** 监听滚动条事件 */
this.el.inputTable.onscroll = function (event) {
this.getElement('inputTable').onscroll = function (event) {
vm.syncScrollBar(event.target.scrollLeft)
}
this.el.tbody.onscroll = function (event) {
this.getElement('tbody').onscroll = function (event) {
// vm.recalcTrHiddenItem(event.target.scrollTop)
}
@ -955,6 +1017,25 @@
},
methods: {
getElement(id, noCaseId = false) {
if (!this.el[id]) {
this.el[id] = document.getElementById((noCaseId ? '' : this.caseId) + id)
}
return this.el[id]
},
getElementPromise(id, noCaseId = false) {
return new Promise((resolve) => {
let timer = setInterval(() => {
let element = this.getElement(id, noCaseId)
if (element) {
clearInterval(timer)
resolve(element)
}
}, 10)
})
},
/** 初始化列表 */
initialize() {
// inputValues用来存储input表单的值
@ -985,14 +1066,14 @@
this.searchSelectValues = []
this.scrollTop = 0
this.$nextTick(() => {
this.el.tbody.scrollTop = 0
this.getElement('tbody').scrollTop = 0
})
},
/** 同步滚动条状态 */
syncScrollBar(scrollLeft) {
// this.style.tbody.left = `${scrollLeft}px`
// this.el.tbody.scrollLeft = scrollLeft
// this.getElement('tbody').scrollLeft = scrollLeft
},
/** 重置滚动条位置,参数留空则滚动到上次记录的位置 */
resetScrollTop(top) {
@ -1157,7 +1238,7 @@
target: this
})
// 设置滚动条位置
let tbody = this.el.tbody
let tbody = this.getElement('tbody')
let offsetHeight = tbody.offsetHeight
let realScrollTop = tbody.scrollTop + offsetHeight
if (forceScrollToBottom === false) {
@ -1245,13 +1326,14 @@
return true
},
/** 获取表格表单里的值(步版) */
getValuesSync(options = {}) {
/** 获取表格表单里的值(步版) */
getValuesAsync(options = {}, callback) {
let { validate, rowIds } = options
if (typeof validate !== 'boolean') validate = true
if (!(rowIds instanceof Array)) rowIds = null
// console.log('options:', { validate, rowIds })
let asyncCount = 0
let error = 0
let inputValues = cloneObject(this.inputValues)
let tooltips = Object.assign({}, this.tooltips)
@ -1314,7 +1396,7 @@
} else if (column.type === FormTypes.sel_search) {
value[column.key] = this.searchSelectValues[inputId]
} else if (column.type === FormTypes.list_multi) {
if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length == 0) {
if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length === 0) {
value[column.key] = ''
} else {
value[column.key] = this.multiSelectValues[inputId].join(',')
@ -1326,20 +1408,27 @@
// 检查表单验证
if (validate === true) {
let results = this.validateOneInput(value[column.key], value, column, notPassedIds, false, 'getValues')
tooltips[inputId] = results[0]
if (tooltips[inputId].passed === false) {
error++
// if (error++ === 0) {
// let element = document.getElementById(inputId)
// while (element.className !== 'tr') {
// element = element.parentElement
// }
// this.jumpToId(inputId, element)
// }
const handleValidateOneInput = (results) => {
tooltips[inputId] = results[0]
if (tooltips[inputId].passed === false) {
error++
// if (error++ === 0) {
// let element = document.getElementById(inputId)
// while (element.className !== 'tr') {
// element = element.parentElement
// }
// this.jumpToId(inputId, element)
// }
}
tooltips[inputId].visible = false
notPassedIds = results[1]
}
tooltips[inputId].visible = false
notPassedIds = results[1]
asyncCount++
let results = this.validateOneInputAsync(value[column.key], value, column, notPassedIds, false, 'getValues', (results) => {
handleValidateOneInput(results)
asyncCount--
})
handleValidateOneInput(results)
}
})
// 将caseId去除
@ -1352,25 +1441,42 @@
this.tooltips = tooltips
this.notPassedIds = notPassedIds
}
const timer = setInterval(() => {
if (asyncCount === 0) {
clearInterval(timer)
if (typeof callback === 'function') {
callback({ error, values })
}
}
}, 50)
return { error, values }
},
/** 获取表格表单里的值(同步版) */
getValuesSync(options = {}) {
return this.getValuesAsync(options)
},
/** 获取表格表单里的值 */
getValues(callback, validate = true, rowIds) {
let result = this.getValuesSync({ validate, rowIds })
if (typeof callback === 'function') {
callback(result.error, result.values)
}
this.getValuesAsync({ validate, rowIds }, ({ error, values }) => {
if (typeof callback === 'function') {
callback(error, values)
}
})
},
/** getValues的Promise版 */
getValuesPromise(validate = true, rowIds) {
return new Promise((resolve, reject) => {
let { error, values } = this.getValuesSync({ validate, rowIds })
if (error === 0) {
resolve(values)
} else {
reject(VALIDATE_NO_PASSED)
}
this.getValuesAsync({ validate, rowIds }, ({ error, values }) => {
if (error === 0) {
resolve(values)
} else {
reject(VALIDATE_NO_PASSED)
}
})
})
},
/** 获取被删除项的id */
@ -1468,14 +1574,24 @@
// element = document.getElementById(id)
// }
// if (element != null) {
// console.log(this.el.tbody.scrollTop, element.offsetTop)
// this.el.tbody.scrollTop = element.offsetTop
// console.log(this.el.tbody.scrollTop, element.offsetTop)
// console.log(this.getElement('tbody').scrollTop, element.offsetTop)
// this.getElement('tbody').scrollTop = element.offsetTop
// console.log(this.getElement('tbody').scrollTop, element.offsetTop)
// }
// },
/** 验证单个表单 */
validateOneInput(value, row, column, notPassedIds, update = false, validType = 'input') {
/**
* 验证单个表单异步版
*
* @param value 校验的值
* @param row 校验的行
* @param column 校验的列
* @param notPassedIds 没有通过校验的 id
* @param update 是否更新到vue中
* @param validType 校验触发的方式inputblur等
* @param callback
*/
validateOneInputAsync(value, row, column, notPassedIds, update = false, validType = 'input', callback) {
let tooltips = Object.assign({}, this.tooltips)
// let notPassedIds = cloneObject(this.notPassedIds)
let inputId = column.key + row.id
@ -1515,6 +1631,10 @@
if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
element = element.getElementsByTagName('input')[0]
}
// upload .ant-upload .ant-btn 上设置 border-color
if (column.type === FormTypes.upload || column.type === FormTypes.file || column.type === FormTypes.image) {
element = element.getElementsByClassName('ant-upload')[0].getElementsByClassName('ant-btn')[0]
}
element.style.borderColor = borderColor
element.style.boxShadow = boxShadow
if (element.tagName === 'SPAN') {
@ -1527,6 +1647,10 @@
this.notPassedIds = notPassedIds
}
if (typeof callback === 'function') {
callback([tooltips[inputId], notPassedIds])
}
}
if (typeof passed === 'function') {
@ -1547,9 +1671,13 @@
nextThen([passed, message])
}
return [tooltips[inputId], notPassedIds]
},
/** 验证单个表单 */
validateOneInput(value, row, column, notPassedIds, update = false, validType = 'input') {
return this.validateOneInputAsync(value, row, column, notPassedIds, update, validType)
},
/** 通过规则验证值是否正确 */
validateValue(column, value) {
let rules = column.validateRules
@ -1620,7 +1748,7 @@
/** 动态更新表单的值 */
updateFormValues() {
let trs = this.el.tbody.getElementsByClassName('tr')
let trs = this.getElement('tbody').getElementsByClassName('tr')
let trEls = []
for (let tr of trs) {
trEls.push(tr)
@ -1959,7 +2087,7 @@
handleClickDownloadFile(id) {
let { path } = this.uploadValues[id] || {}
if (path) {
let url = window._CONFIG['downloadUrl'] + '/' + path
let url = window._CONFIG['staticDomainURL'] + '/' + path
window.open(url)
}
},
@ -2130,7 +2258,7 @@
getCellImageView(id) {
let currUploadObj = this.uploadValues[id] || null
if (currUploadObj && currUploadObj['path']) {
return window._CONFIG['domianURL'] + '/sys/common/view/' + currUploadObj['path']
return window._CONFIG['staticDomainURL'] + '/' + currUploadObj['path']
} else {
return ''
}
@ -2340,7 +2468,7 @@
.td {
/*flex: 1;*/
padding: 14px 0 14px @spacing;
padding: 14px @spacing 14px 0;
justify-content: center;
&:last-child {

View File

@ -150,7 +150,7 @@
console.log("aaaaa",res)
if(res.success){
this.checkKey = res.result.key
this.code = res.result.code
this.code = window.atob(res.result.code)
resolve();
}else{
this.$message.error("生成验证码错误,请联系系统管理员")

View File

@ -0,0 +1,202 @@
<template>
<a-upload
name="file"
listType="picture-card"
:multiple="isMultiple"
:action="uploadAction"
:headers="headers"
:data="{biz:bizPath}"
:fileList="fileList"
:beforeUpload="beforeUpload"
:disabled="disabled"
:isMultiple="isMultiple"
:showUploadList="isMultiple"
@change="handleChange"
@preview="handlePreview">
<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="height:104px;max-width:300px"/>
<div v-else >
<a-icon :type="uploadLoading ? 'loading' : 'plus'" />
<div class="ant-upload-text">{{ text }}</div>
</div>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
<img alt="example" style="width: 100%" :src="previewImage"/>
</a-modal>
</a-upload>
</template>
<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
import { getFileAccessHttpUrl } from '@/api/manage'
const uidGenerator=()=>{
return '-'+parseInt(Math.random()*10000+1,10);
}
const getFileName=(path)=>{
if(path.lastIndexOf("\\")>=0){
let reg=new RegExp("\\\\","g");
path = path.replace(reg,"/");
}
return path.substring(path.lastIndexOf("/")+1);
}
export default {
name: 'JImageUpload',
data(){
return {
uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
urlView:window._CONFIG['staticDomainURL'],
uploadLoading:false,
picUrl:false,
headers:{},
fileList: [],
previewImage:"",
previewVisible: false,
}
},
props:{
text:{
type:String,
required:false,
default:"上传"
},
/*这个属性用于控制文件上传的业务路径*/
bizPath:{
type:String,
required:false,
default:"temp"
},
value:{
type:[String,Array],
required:false
},
disabled:{
type:Boolean,
required:false,
default: false
},
isMultiple:{
type:Boolean,
required:false,
default: false
}
},
watch:{
value(val){
if (val instanceof Array) {
this.initFileList(val.join(','))
} else {
this.initFileList(val)
}
}
},
created(){
const token = Vue.ls.get(ACCESS_TOKEN);
this.headers = {"X-Access-Token":token}
},
methods:{
initFileList(paths){
if(!paths || paths.length==0){
this.fileList = [];
return;
}
this.picUrl = true;
let fileList = [];
let arr = paths.split(",")
for(var a=0;a<arr.length;a++){
let url = getFileAccessHttpUrl(arr[a],this.urlView,"http");
fileList.push({
uid: uidGenerator(),
name: getFileName(arr[a]),
status: 'done',
url: url,
response:{
status:"history",
message:arr[a]
}
})
}
this.fileList = fileList
},
beforeUpload: function(file){
var fileType = file.type;
if(fileType.indexOf('image')<0){
this.$message.warning('请上传图片');
return false;
}
},
handleChange(info) {
this.picUrl = false;
let fileList = info.fileList
if(info.file.status==='done'){
if(info.file.response.success){
this.picUrl = true;
fileList = fileList.map((file) => {
if (file.response) {
file.url = file.response.message;
}
return file;
});
}
//this.$message.success(`${info.file.name} 上传成功!`);
}else if (info.file.status === 'error') {
this.$message.error(`${info.file.name} 上传失败.`);
}else if(info.file.status === 'removed'){
this.handleDelete(info.file)
}
this.fileList = fileList
if(info.file.status==='done' || info.file.status === 'removed'){
this.handlePathChange()
}
},
// 预览
handlePreview (file) {
this.previewImage = file.url || file.thumbUrl
this.previewVisible = true
},
getAvatarView(){
if(this.fileList.length>0){
let url = this.fileList[0].url
return getFileAccessHttpUrl(url,this.urlView,"http")
}
},
handlePathChange(){
let uploadFiles = this.fileList
let path = ''
if(!uploadFiles || uploadFiles.length==0){
path = ''
}
let arr = [];
if(!this.isMultiple){
arr.push(uploadFiles[uploadFiles.length-1].response.message)
}else{
for(var a=0;a<uploadFiles.length;a++){
arr.push(uploadFiles[a].response.message)
}
}
if(arr.length>0){
path = arr.join(",")
}
this.$emit('change', path);
},
handleDelete(file){
//如有需要新增 删除逻辑
console.log(file)
},
handleCancel() {
this.close();
this.previewVisible = false;
},
close () {
},
},
model: {
prop: 'value',
event: 'change'
}
}
</script>
<style scoped>
</style>

View File

@ -42,6 +42,11 @@
type: String,
default: '',
required: false
},
biz:{
type: String,
default: '',
required: false
}
},
data(){
@ -49,7 +54,8 @@
visible:false,
uploading:false,
fileList:[],
uploadAction:''
uploadAction:'',
foreignKeys:''
}
},
watch: {
@ -67,10 +73,11 @@
handleClose(){
this.visible=false
},
show(){
show(arg){
this.fileList = []
this.uploading = false
this.visible = true
this.foreignKeys = arg;
},
handleRemove(file) {
const index = this.fileList.indexOf(file);
@ -85,6 +92,12 @@
handleImport() {
const { fileList } = this;
const formData = new FormData();
if(this.biz){
formData.append('isSingleTableImport',this.biz);
}
if(this.foreignKeys && this.foreignKeys.length>0){
formData.append('foreignKeys',this.foreignKeys);
}
fileList.forEach((file) => {
formData.append('files[]', file);
});

View File

@ -0,0 +1,209 @@
<template>
<a-modal
ref="modal"
class="j-modal-box"
:class="{'fullscreen':innerFullscreen,'no-title':isNoTitle,'no-footer':isNoFooter,}"
:visible="visible"
v-bind="_attrs"
v-on="$listeners"
@ok="handleOk"
@cancel="handleCancel"
>
<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>
<!-- 处理 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 ACol from 'ant-design-vue/es/grid/Col'
export default {
name: 'JModal',
components: { ACol },
props: {
title: String,
// 可使用 .sync 修饰符
visible: Boolean,
// 是否在弹出时禁止 body 滚动
lockScroll: {
type: Boolean,
default: true
},
// 是否全屏弹窗当全屏时无论如何都会禁止 body 滚动可使用 .sync 修饰符
fullscreen: {
type: Boolean,
default: true
},
// 是否允许切换全屏允许后右上角会出现一个按钮
switchFullscreen: {
type: Boolean,
default: false
},
},
data() {
return {
// 内部使用的 slots 不再处理
usedSlots: ['title'],
// 缓存 body overflow
bodyOverflowCache: '',
innerFullscreen: this.fullscreen,
fullscreenButtonIcon: 'fullscreen-exit',
}
},
computed: {
// 一些未处理的参数或特殊处理的参数绑定到 a-modal
_attrs() {
let attrs = { ...this.$attrs }
// 如果全屏就将宽度设为 100%
if (this.innerFullscreen) {
attrs['width'] = '100%'
}
return attrs
},
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 this.slotsKeys.concat(this.scopedSlotsKeys)
},
// 是否锁定body滚动
lockBodyScroll() {
return this.lockScroll || this.innerFullscreen
}
},
watch: {
visible() {
if (this.visible) {
this.innerFullscreen = this.fullscreen
}
if (this.lockBodyScroll) {
if (this.visible) {
this.bodyOverflowCache = document.body.style.overflow
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = this.bodyOverflowCache
}
}
},
innerFullscreen(val) {
this.$emit('update:fullscreen', val)
},
},
methods: {
close() {
this.$emit('update:visible', false)
},
handleOk() {
this.close()
},
handleCancel() {
this.close()
},
toggleFullscreen() {
if (this.innerFullscreen) {
this.fullscreenButtonIcon = 'fullscreen'
} else {
this.fullscreenButtonIcon = 'fullscreen-exit'
}
this.innerFullscreen = !this.innerFullscreen
},
}
}
</script>
<style lang="scss">
.j-modal-box {
&.fullscreen {
top: 0;
left: 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;
.ant-modal-close {
right: 56px;
color: rgba(0, 0, 0, 0.45);
&:hover {
color: rgba(0, 0, 0, 0.75);
}
}
}
}
/deep/ {
}
}
</style>

View File

@ -1,15 +1,22 @@
<template>
<div class="j-super-query-box">
<slot>
<a-tooltip v-if="superQueryFlag" title="已有高级查询条件生效">
<a-button type="primary" @click="visible=true">
<a-icon type="appstore" theme="twoTone" :spin="true"></a-icon>
<span>高级查询</span>
</a-button>
</a-tooltip>
<a-button v-else type="primary" icon="filter" @click="visible=true">高级查询</a-button>
</slot>
<div @click="visible=true">
<slot>
<a-tooltip v-if="superQueryFlag" :mouseLeaveDelay="0.2">
<template slot="title">
<span>已有高级查询条件生效</span>
<a-divider type="vertical"/>
<a @click="handleReset">清空</a>
</template>
<a-button type="primary">
<a-icon type="appstore" theme="twoTone" :spin="true"></a-icon>
<span>高级查询</span>
</a-button>
</a-tooltip>
<a-button v-else type="primary" icon="filter" @click="visible=true">高级查询</a-button>
</slot>
</div>
<a-modal
title="高级查询构造器"

View File

@ -4,11 +4,12 @@
:multiple="true"
:action="uploadAction"
:headers="headers"
:data="{'isup':1,'bizPath':bizPath}"
:data="{'biz':bizPath}"
:fileList="fileList"
:beforeUpload="beforeUpload"
@change="handleChange"
:disabled="disabled">
:disabled="disabled"
:returnUrl="returnUrl">
<a-button>
<a-icon type="upload" />{{ text }}
</a-button>
@ -19,6 +20,7 @@
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
import { getFileAccessHttpUrl } from '@/api/manage';
const FILE_TYPE_ALL = "all"
const FILE_TYPE_IMG = "image"
@ -38,9 +40,10 @@
data(){
return {
uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
urlDownload:window._CONFIG['domianURL'] + "/sys/common/download/",
urlDownload:window._CONFIG['staticDomainURL'],
headers:{},
fileList: []
fileList: [],
newFileList: [],
}
},
props:{
@ -77,11 +80,25 @@
required: false,
default: false
},
/**
* update -- author:lvdandan -- date:20190219 -- for:Jupload组件增加是否返回url
* true仅返回url
* false返回fileName filePath fileSize
*/
returnUrl:{
type:Boolean,
required:false,
default: true
},
},
watch:{
value(val){
if (val instanceof Array) {
this.initFileList(val.join(','))
if(this.returnUrl){
this.initFileList(val.join(','))
}else{
this.initFileListArr(val);
}
} else {
this.initFileList(val)
}
@ -93,6 +110,26 @@
},
methods:{
initFileListArr(val){
if(!val || val.length==0){
this.fileList = [];
return;
}
let fileList = [];
for(var a=0;a<val.length;a++){
fileList.push({
uid:uidGenerator(),
name:val[a].fileName,
status: 'done',
url: val[a].filePath,
response:{
status:"history",
message:val[a].filePath
}
})
}
this.fileList = fileList
},
initFileList(paths){
if(!paths || paths.length==0){
//return [];
@ -104,11 +141,12 @@
let fileList = [];
let arr = paths.split(",")
for(var a=0;a<arr.length;a++){
let url = getFileAccessHttpUrl(arr[a],this.urlDownload,"http");
fileList.push({
uid:uidGenerator(),
name:getFileName(arr[a]),
status: 'done',
url: this.urlDownload+arr[a],
url: url,
response:{
status:"history",
message:arr[a]
@ -156,12 +194,13 @@
if(info.file.response.success){
fileList = fileList.map((file) => {
if (file.response) {
file.url = this.urlDownload+file.response.message;
let reUrl = file.response.message;
file.url = getFileAccessHttpUrl(reUrl,this.urlDownload,"http");
}
return file;
});
}
this.$message.success(`${info.file.name} 上传成功!`);
//this.$message.success(`${info.file.name} 上传成功!`);
}else if (info.file.status === 'error') {
this.$message.error(`${info.file.name} 上传失败.`);
}else if(info.file.status === 'removed'){
@ -169,7 +208,26 @@
}
this.fileList = fileList
if(info.file.status==='done' || info.file.status === 'removed'){
this.handlePathChange()
//returnUrl为true时仅返回文件路径
if(this.returnUrl){
this.handlePathChange()
}else{
//returnUrl为false时返回文件名称文件路径及文件大小
fileList = fileList.filter((file) => {
if (file.response) {
return file.response.success === true;
}
return false;
}).map((file) => {
var fileJson = {
fileName:file.name,
filePath:file.url,
fileSize:file.size
};
this.newFileList.push(fileJson);
this.$emit('change', this.newFileList);
});
}
}
},
handleDelete(file){

View File

@ -1,5 +1,9 @@
import T from './JFormContainer.vue'
let install = function (Vue) {
Vue.component('JFormContainer',T);
}
export default { install };
import JModal from './JModal'
import JFormContainer from './JFormContainer.vue'
export default {
install(Vue) {
Vue.component('JFormContainer', JFormContainer)
Vue.component(JModal.name, JModal)
}
}

View File

@ -17,9 +17,11 @@
selectable
:selectedKeys="selectedDepIds"
:checkStrictly="true"
@select="onDepSelect"
:dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
:treeData="departTree"
:expandAction="false"
:expandedKeys.sync="expandedKeys"
@select="onDepSelect"
/>
</a-card>
</a-col>
@ -28,7 +30,7 @@
用户账号:
<a-input-search
:style="{width:'150px',marginBottom:'15px'}"
placeholder="请输入用户账号"
placeholder="请输入账号"
v-model="queryParam.username"
@search="onSearch"
></a-input-search>
@ -43,6 +45,7 @@
:dataSource="dataSource"
:pagination="ipagination"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange,type: getType}"
:loading="loading"
@change="handleTableChange">
</a-table>
</a-card>
@ -71,7 +74,7 @@
dataIndex: 'username'
},
{
title: '真实姓名',
title: '用户姓名',
align: 'center',
dataIndex: 'realname'
},
@ -90,14 +93,14 @@
}
},
{
title: '手机号码',
title: '手机',
align: 'center',
dataIndex: 'phone'
},
{
title: '邮箱',
title: '部门',
align: 'center',
dataIndex: 'email'
dataIndex: 'orgCode'
}
],
scrollTrigger: {},
@ -124,60 +127,74 @@
selectedDepIds: [],
departTree: [],
visible: false,
form: this.$form.createForm(this)
form: this.$form.createForm(this),
loading: false,
expandedKeys: [],
}
},
computed: {
// 计算属性的 getter
getType: function () {
console.log("multi: ", this.multi);
return this.multi == true ? 'checkbox' : 'radio';
}
},
watch: {
userIds() {
this.initUserNames()
}
userIds: {
immediate: true,
handler() {
this.initUserNames()
}
},
},
created() {
// 该方法触发屏幕自适应
this.resetScreenSize();
this.loadData().then((res) => {
this.initUserNames();
})
this.loadData()
},
methods: {
initUserNames() {
let names = ''
console.log("props userIds: ", this.userIds)
if (this.userIds) {
let currUserIds = this.userIds
let userIdsArr = currUserIds.split(',');
for (let item of this.dataSource) {
if (userIdsArr.includes(item.username)) {
names += "," + item.realname
// 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询防止后台进行了模糊匹配导致查询结果不准确
let values = this.userIds.split(',') + ','
getUserList({
username: values,
pageNo: 1,
pageSize: values.length
}).then((res) => {
if (res.success) {
let selectedRowKeys = []
let realNames = []
res.result.records.forEach(user => {
realNames.push(user['realname'])
selectedRowKeys.push(user['id'])
})
this.selectedRowKeys = selectedRowKeys
this.$emit('initComp', realNames.join(','))
}
}
if (names) {
names = names.substring(1)
}
this.$emit("initComp", names)
}else{
})
} else {
// JSelectUserByDep组件bug issues/I16634
this.$emit("initComp", "")
this.$emit('initComp', '')
}
},
async loadData(arg) {
if (arg === 1) {
this.ipagination.current = 1;
}
let params = this.getQueryParams();//查询条件
await getUserList(params).then((res) => {
if (res.success) {
this.dataSource = res.result.records;
this.ipagination.total = res.result.total;
}
})
if (this.selectedDepIds && this.selectedDepIds.length > 0) {
await this.initQueryUserByDepId(this.selectedDepIds)
} else {
this.loading = true
let params = this.getQueryParams()//查询条件
await getUserList(params).then((res) => {
if (res.success) {
this.dataSource = res.result.records
this.ipagination.total = res.result.total
}
}).finally(() => {
this.loading = false
})
}
},
// 触发屏幕自适应
resetScreenSize() {
@ -191,6 +208,7 @@
showModal() {
this.visible = true;
this.queryDepartTree();
this.initUserNames()
this.loadData();
this.form.resetFields();
},
@ -234,7 +252,6 @@
handleSubmit() {
let that = this;
this.getSelectUserRows();
console.log(that.selectUserRows)
that.$emit('ok', that.selectUserRows, that.selectUserIds);
that.searchReset(0)
that.close();
@ -270,17 +287,22 @@
},
// 根据选择的id来查询用户信息
initQueryUserByDepId(selectedDepIds) {
queryUserByDepId({id: selectedDepIds.toString()}).then((res) => {
this.loading = true
return queryUserByDepId({id: selectedDepIds.toString()}).then((res) => {
if (res.success) {
this.dataSource = res.result;
this.ipagination.total = res.result.length;
}
}).finally(() => {
this.loading = false
})
},
queryDepartTree() {
queryDepartTreeList().then((res) => {
if (res.success) {
this.departTree = res.result;
// 默认展开父节点
this.expandedKeys = this.departTree.map(item => item.id)
}
})
},

View File

@ -46,7 +46,7 @@
width: 200
},
{
title: '用户真实姓名',
title: '用户姓名',
align: "center",
dataIndex: 'realname',
},

View File

@ -5,6 +5,8 @@
</template>
<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
import PageLayout from '../page/PageLayout'
import RouteView from './RouteView'
@ -40,6 +42,12 @@
/*update_begin author:wuxianquan date:20190908 for:判断打开方式新窗口打开时this.$route.meta.internalOrExternal==true */
if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
this.closeCurrent();
//外部url加入token
let tokenStr = "${token}";
if(url.indexOf(tokenStr)!=-1){
let token = Vue.ls.get(ACCESS_TOKEN);
this.url = url.replace(tokenStr,token);
}
window.open(this.url);
}
/*update_end author:wuxianquan date:20190908 for:判断打开方式新窗口打开时this.$route.meta.internalOrExternal==true */

View File

@ -80,30 +80,41 @@
},
created() {
if (this.$route.path != indexKey) {
this.pageList.push({
name: 'dashboard-analysis',
path: indexKey,
fullPath: indexKey,
meta: {
icon: 'dashboard',
title: '首页'
}
})
this.linkList.push(indexKey)
this.addIndexToFirst()
}
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
let storeKey = 'route:title:' + this.$route.fullPath
let routeTitle = this.$ls.get(storeKey)
if (routeTitle) {
this.$route.meta.title = routeTitle
}
// update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
this.pageList.push(this.$route)
this.linkList.push(this.$route.fullPath)
this.activePage = this.$route.fullPath
},
watch: {
'$route': function(newRoute) {
//console.log("新的路由",newRoute)
this.activePage = newRoute.fullPath
if (!this.multipage) {
this.linkList = [newRoute.fullPath]
this.pageList = [Object.assign({},newRoute)]
} else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
// update-begin-author:taoyan date:20200211 for: TASK #3368 路由缓存首页的缓存设置有问题需要根据后台的路由配置来实现是否缓存
} else if(indexKey==newRoute.fullPath) {
//首页时 判断是否缓存 没有缓存 刷新之
if (newRoute.meta.keepAlive === false) {
this.routeReload()
}
// update-end-author:taoyan date:20200211 for: TASK #3368 路由缓存首页的缓存设置有问题需要根据后台的路由配置来实现是否缓存
}else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
this.linkList.push(newRoute.fullPath)
this.pageList.push(Object.assign({},newRoute))
// update-begin-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由那么就强制刷新一遍
if (newRoute.meta.keepAlive) {
this.routeReload()
}
// update-end-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由那么就强制刷新一遍
} else if (this.linkList.indexOf(newRoute.fullPath) >= 0) {
let oldIndex = this.linkList.indexOf(newRoute.fullPath)
let oldPositionRoute = this.pageList[oldIndex]
@ -114,6 +125,7 @@
let index = this.linkList.lastIndexOf(key)
let waitRouter = this.pageList[index]
this.$router.push(Object.assign({},waitRouter));
this.changeTitle(waitRouter.meta.title)
},
'multipage': function(newVal) {
if(this.reloadFlag){
@ -122,9 +134,44 @@
this.pageList = [this.$route]
}
}
}
},
// update-begin-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
device() {
if (this.multipage && this.linkList.indexOf(indexKey) === -1) {
this.addIndexToFirst()
}
},
// update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
},
methods: {
// update-begin-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
// 将首页添加到第一位
addIndexToFirst() {
this.pageList.splice(0, 0, {
name: 'dashboard-analysis',
path: indexKey,
fullPath: indexKey,
meta: {
icon: 'dashboard',
title: '首页'
}
})
this.linkList.splice(0, 0, indexKey)
},
// update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
changeTitle(title) {
let projectTitle = "Jeecg-Boot 企业级快速开发平台"
// 首页特殊处理
if (this.$route.path === indexKey) {
document.title = projectTitle
} else {
document.title = title + ' · ' + projectTitle
}
},
// update-end-author:sunjianlei date:20200120 for: 动态更改页面标题
changePage(key) {
this.activePage = key
},
@ -236,6 +283,9 @@
let currRouter = this.pageList[keyIndex]
let meta = Object.assign({},currRouter.meta,{title:title})
this.pageList.splice(keyIndex, 1, Object.assign({},currRouter,{meta:meta}))
if (key === this.activePage) {
this.changeTitle(title)
}
}
},
//update-end-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title

View File

@ -17,12 +17,12 @@
<div class="footer">
<div class="links">
<a href="http://jeecg-boot.mydoc.io" target="_blank">帮助</a>
<a href="http://doc.jeecg.com" target="_blank">帮助</a>
<a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">隐私</a>
<a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">条款</a>
<a href="https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE" target="_blank">条款</a>
</div>
<div class="copyright">
Copyright &copy; 2019 <a href="http://www.jeecg.org" target="_blank">JEECG开源社区</a> 出品
Copyright &copy; 2019 <a href="http://www.jeecg.com" target="_blank">JEECG开源社区</a> 出品
</div>
</div>
</div>

View File

@ -1,7 +1,7 @@
<template>
<div class="footer">
<div class="links">
<a href="http://www.jeecg.org" target="_blank">JEECG 首页</a>
<a href="http://www.jeecg.com" target="_blank">JEECG 首页</a>
<a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">
<a-icon type="github"/>
</a>

View File

@ -197,7 +197,7 @@
&.dark {
color: #000000;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
background-color: @primary-color;
background-color: white !important;
}
}

View File

@ -154,6 +154,10 @@
//此处触发动态路由被点击事件
this.findMenuBykey(this.menus,value.key)
this.$emit("dynamicRouterShow",value.key,this.activeMenu.meta.title)
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
let storeKey = 'route:title:' + this.activeMenu.path
this.$ls.set(storeKey, this.activeMenu.meta.title)
// update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
},
findMenuBykey(menus,key){
for(let i of menus){
@ -337,6 +341,10 @@
font-size: 16px;
padding: 4px;
}
.anticon {
color: white;
}
}
}
@ -349,6 +357,10 @@
&:hover {
background: rgba(0, 0, 0, 0.05);
}
.anticon {
color: black;
}
}
}
}

View File

@ -0,0 +1,36 @@
<template>
<component
:is="comp"
:formData="formData"
ref="compModel"
v-if="comp">
</component>
</template>
<script>
export default {
name: 'DynamicNotice',
data () {
return {
compName: this.path
}
},
computed: {
comp: function () {
if(!this.path){
return null;
}
return () => import(`@/views/${this.path}.vue`)
}
},
props: ['path','formData'],
methods: {
detail () {
setTimeout(() => {
if(this.path){
this.$refs.compModel.view(this.formData);
}
}, 200)
},
}
}
</script>

View File

@ -72,6 +72,7 @@
</a-badge>
</span>
<show-announcement ref="ShowAnnouncement" @ok="modalFormOk"></show-announcement>
<dynamic-notice ref="showDynamNotice" :path="openPath" :formData="formData"/>
</a-popover>
</template>
@ -79,11 +80,13 @@
import { getAction,putAction } from '@/api/manage'
import ShowAnnouncement from './ShowAnnouncement'
import store from '@/store/'
import DynamicNotice from './DynamicNotice'
export default {
name: "HeaderNotice",
components: {
DynamicNotice,
ShowAnnouncement,
},
data () {
@ -105,6 +108,8 @@
websock: null,
lockReconnect:false,
heartCheck:null,
formData:{},
openPath:''
}
},
computed:{
@ -172,7 +177,13 @@
}
});
this.hovered = false;
this.$refs.ShowAnnouncement.detail(record);
if(record.openType==='component'){
this.openPath = record.openPage;
this.formData = {id:record.busId};
this.$refs.showDynamNotice.detail(record.openPage);
}else{
this.$refs.ShowAnnouncement.detail(record);
}
},
toMyAnnouncement(){

View File

@ -5,11 +5,14 @@
:visible="visible"
:bodyStyle ="bodyStyle"
@cancel="handleCancel"
destroyOnClose
:footer="null">
destroyOnClose>
<template slot="title">
<a-button icon="fullscreen" class="custom-btn" @click="handleClickToggleFullScreen"/>
</template>
<template slot="footer">
<a-button key="back" @click="handleCancel">关闭</a-button>
<a-button v-if="record.openType==='url'&&record.readFlag!=='1'" type="primary" @click="toHandle">去处理</a-button>
</template>
<a-card class="daily-article" :loading="loading">
<a-card-meta
:title="record.titile"
@ -74,7 +77,14 @@
this.modelStyle.style.top = '50px'
}
this.modelStyle.fullScreen = mode
}
},
toHandle(){
if(this.record.openType==='url'&&this.record.readFlag!== '1'){
this.visible = false;
//链接跳转
this.$router.push({path: this.record.openPage})
}
},
}
}
</script>

View File

@ -5,7 +5,8 @@
<span class="action" @click="showClick">
<a-icon type="search"></a-icon>
</span>
<span v-show="shows" class="borders">
<!-- update-begin author:sunjianlei date:20200219 for: 菜单搜索改为动态组件在手机端呈现出弹出框 -->
<component :is="searchMenuComp" v-show="searchMenuVisible || isMobile()" class="borders" :visible="searchMenuVisible" title="搜索菜单" :footer="null" @cancel="searchMenuVisible=false">
<a-select
class="search-input"
showSearch
@ -13,16 +14,20 @@
placeholder="搜索菜单"
optionFilterProp="children"
:filterOption="filterOption"
:open="isMobile()?true:null"
:getPopupContainer="(node) => node.parentNode"
:style="isMobile()?{width: '100%',marginBottom:'50px'}:{}"
@change="searchMethods"
@blur="hiddenClick"
>
<a-select-option v-for="site in search " :value="site.id">{{site.meta.title}}</a-select-option>
<a-select-option v-for="site in searchMenuOptions" :value="site.id">{{site.meta.title}}</a-select-option>
</a-select>
</span>
<!-- update-end author:sunjianlei date:20191@20 for: 解决全局样式冲突的问题 -->
</component>
<!-- update-end author:sunjianlei date:20200219 for: 菜单搜索改为动态组件在手机端呈现出弹出框 -->
<!-- update-end author:sunjianlei date:20191220 for: 解决全局样式冲突的问题 -->
<!-- update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航 -->
<span class="action">
<a class="logout_title" target="_blank" href="http://jeecg-boot.mydoc.io">
<a class="logout_title" target="_blank" href="http://doc.jeecg.com">
<a-icon type="question-circle-o"></a-icon>
</a>
</span>
@ -95,9 +100,11 @@
mixins: [mixinDevice],
data(){
return{
//菜单搜索
search:[],
shows:false
// update-begin author:sunjianlei date:20200219 for: 头部菜单搜索规范命名 --------------
searchMenuOptions:[],
searchMenuComp: 'span',
searchMenuVisible: false,
// update-begin author:sunjianlei date:20200219 for: 头部菜单搜索规范命名 --------------
}
},
components: {
@ -116,10 +123,8 @@
/* update_begin author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
created() {
let lists = []
console.log("permissionMenuList: ",this.permissionMenuList)
this.searchMenus(lists,this.permissionMenuList)
this.search=[...lists]
console.log(this.search)
this.searchMenuOptions=[...lists]
},
computed: {
...mapState({
@ -129,10 +134,21 @@
})
},
/* update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
watch: {
// update-begin author:sunjianlei date:20200219 for: 菜单搜索改为动态组件在手机端呈现出弹出框
device: {
immediate: true,
handler() {
this.searchMenuVisible = false
this.searchMenuComp = this.isMobile() ? 'a-modal' : 'span'
},
},
// update-end author:sunjianlei date:20200219 for: 菜单搜索改为动态组件在手机端呈现出弹出框
},
methods: {
/* update_begin author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
showClick(){
this.shows = !this.shows
showClick() {
this.searchMenuVisible = true
},
hiddenClick(){
this.shows = false
@ -141,8 +157,8 @@
...mapActions(["Logout"]),
...mapGetters(["nickname", "avatar","userInfo"]),
getAvatar(){
console.log('url = '+ window._CONFIG['imgDomainURL']+"/"+this.avatar())
return window._CONFIG['imgDomainURL']+"/"+this.avatar()
console.log('url = '+ window._CONFIG['staticDomainURL']+"/"+this.avatar())
return window._CONFIG['staticDomainURL']+"/"+this.avatar()
},
handleLogout() {
const that = this
@ -189,10 +205,17 @@
filterOption(input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
searchMethods(value){
let jump = this.search.filter(item=>item.id==value)
this.$router.push({ path:jump[0].path})
// update_begin author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
searchMethods(value) {
let route = this.searchMenuOptions.filter(item => item.id === value)[0]
if (route.meta.internalOrExternal === true || route.component.includes('layouts/IframePageView')) {
window.open(route.meta.url, '_blank')
} else {
this.$router.push({ path: route.path })
}
this.searchMenuVisible = false
}
// update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
/*update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
}
}
@ -203,7 +226,7 @@
/* update-begin author:sunjianlei date:20191220 for: 解决全局样式冲突问题 */
.user-wrapper .search-input {
width: 180px;
color: white;
color: inherit;
/deep/ {
.ant-select-selection {

View File

@ -18,8 +18,8 @@ import VueApexCharts from 'vue-apexcharts'
import preview from 'vue-photo-preview'
import 'vue-photo-preview/dist/skin.css'
import "@jeecg/antd-online-re"
import '@jeecg/antd-online-re/dist/OnlineForm.css'
import "@jeecg/antd-online-214"
import '@jeecg/antd-online-214/dist/OnlineForm.css'
import {
ACCESS_TOKEN,

View File

@ -236,9 +236,9 @@ export const JeecgListMixin = {
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName+'.xls')
window.navigator.msSaveBlob(new Blob([data],{type: 'application/vnd.ms-excel'}), fileName+'.xls')
}else{
let url = window.URL.createObjectURL(new Blob([data]))
let url = window.URL.createObjectURL(new Blob([data],{type: 'application/vnd.ms-excel'}))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
@ -286,7 +286,7 @@ export const JeecgListMixin = {
if(text && text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
return window._CONFIG['imgDomainURL']+"/"+text
return window._CONFIG['staticDomainURL']+"/"+text
},
/* 文件下载 */
uploadFile(text){
@ -297,7 +297,7 @@ export const JeecgListMixin = {
if(text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
window.open(window._CONFIG['domianURL'] + "/sys/common/download/"+text);
window.open(window._CONFIG['staticDomainURL']+ "/"+text);
},
}

View File

@ -0,0 +1,78 @@
export const HrefJump = {
data() {
return {
fieldHrefSlots: [],
hrefComponent: {
model: {
title: '',
width: '100%',
visible: false,
destroyOnClose: true,
style: {
top: 0,
left: 0,
height: '100%',
margin: 0,
padding: 0
},
bodyStyle: { padding: '8px', height: 'calc(100vh - 108px)', overflow: 'auto', overflowX: 'hidden' },
// 隐藏掉取消按钮
cancelButtonProps: { style: { display: 'none' } },
afterClose: () => {
// 恢复body的滚动
document.body.style.overflow = null
}
},
on: {
ok: () => this.hrefComponent.model.visible = false,
cancel: () => this.hrefComponent.model.visible = false
},
is: null,
params: {},
}
}
},
methods: {
//支持链接href跳转
handleClickFieldHref(field, record) {
let href = field.href
let urlPattern = /(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?/
let compPattern = /\.vue(\?.*)?$/
if (typeof href === 'string') {
href = href.trim().replace(/\${([^}]+)?}/g, (s1, s2) => record[s2])
if (urlPattern.test(href)) {
window.open(href, '_blank')
} else if (compPattern.test(href)) {
this.openHrefCompModal(href)
} else {
this.$router.push(href)
}
}
},
openHrefCompModal(href) {
// 解析 href 参数
let index = href.indexOf('?')
let path = href
if (index !== -1) {
path = href.substring(0, index)
let paramString = href.substring(index + 1, href.length)
let paramArray = paramString.split('&')
let params = {}
paramArray.forEach(paramObject => {
let paramItem = paramObject.split('=')
params[paramItem[0]] = paramItem[1]
})
this.hrefComponent.params = params
} else {
this.hrefComponent.params = {}
}
this.hrefComponent.model.visible = true
this.hrefComponent.model.title = '@/views/' + path
this.hrefComponent.is = () => import('@/views/' + (path.startsWith('/')?path.slice(1):path))
// 禁止body滚动防止滚动穿透
setTimeout(() => {
document.body.style.overflow = 'hidden'
}, 300)
},
}
}

View File

@ -120,6 +120,19 @@ const user = {
sessionStorage.setItem(USER_AUTH,JSON.stringify(authData));
sessionStorage.setItem(SYS_BUTTON_AUTH,JSON.stringify(allAuthData));
if (menuData && menuData.length > 0) {
//update--begin--autor:qinfeng-----date:20200109------forJEECG-63 一级菜单的子菜单全部是隐藏路由则一级菜单不显示------
menuData.forEach((item, index) => {
if (item["children"]) {
let hasChildrenMenu = item["children"].filter((i) => {
return !i.hidden || i.hidden == false
})
if (hasChildrenMenu == null || hasChildrenMenu.length == 0) {
item["hidden"] = true
}
}
})
console.log(" menu show json ", menuData)
//update--end--autor:qinfeng-----date:20200109------forJEECG-63 一级菜单的子菜单全部是隐藏路由则一级菜单不显示------
commit('SET_PERMISSIONLIST', menuData)
} else {
reject('getPermissionList: permissions must be a non-null array !')

View File

@ -1,4 +1,3 @@
import { USER_AUTH,SYS_BUTTON_AUTH } from "@/store/mutation-types"
export function disabledAuthFilter(code,formData) {
@ -10,27 +9,30 @@ export function disabledAuthFilter(code,formData) {
}
function nodeDisabledAuth(code,formData){
console.log("页面权限禁用--NODE--开始");
var permissionList = [];
let permissionList = [];
try {
var obj = formData;
//console.log("页面权限禁用--NODE--开始",obj);
if (obj) {
let bpmList = obj.permissionList;
for (var bpm of bpmList) {
if(bpm.type == '2') {
permissionList.push(bpm);
}
}
if (formData) {
let bpmList = formData.permissionList;
permissionList = bpmList.filter(item=>item.type=='2')
// for (let bpm of bpmList) {
// if(bpm.type == '2') {
// permissionList.push(bpm);
// }
// }
}else{
return false;
}
} catch (e) {
//console.log("页面权限异常----", e);
}
if (permissionList === null || permissionList === "" || permissionList === undefined||permissionList.length<=0) {
if (permissionList.length == 0) {
return false;
}
console.log("流程节点页面权限禁用--NODE--开始");
let permissions = [];
for (var item of permissionList) {
for (let item of permissionList) {
if(item.type == '2') {
permissions.push(item.action);
}
@ -39,9 +41,9 @@ function nodeDisabledAuth(code,formData){
if (!permissions.includes(code)) {
return false;
}else{
for (var item2 of permissionList) {
for (let item2 of permissionList) {
if(code === item2.action){
console.log("页面权限禁用--NODE--生效");
console.log("流程节点页面权限禁用--NODE--生效");
return true;
}
}
@ -50,21 +52,21 @@ function nodeDisabledAuth(code,formData){
}
function globalDisabledAuth(code){
console.log("页面禁用权限--Global--开始");
//console.log("全局页面禁用权限--Global--开始");
var permissionList = [];
var allPermissionList = [];
//let authList = Vue.ls.get(USER_AUTH);
let authList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
for (var auth of authList) {
for (let auth of authList) {
if(auth.type == '2') {
permissionList.push(auth);
}
}
//console.log("页面禁用权限--Global--",sessionStorage.getItem(SYS_BUTTON_AUTH));
let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
for (var gauth of allAuthList) {
for (let gauth of allAuthList) {
if(gauth.type == '2') {
allPermissionList.push(gauth);
}
@ -73,7 +75,7 @@ function globalDisabledAuth(code){
var gFlag = false;//禁用命中
var invalidFlag = false;//无效命中
if(allPermissionList != null && allPermissionList != "" && allPermissionList != undefined && allPermissionList.length > 0){
for (var itemG of allPermissionList) {
for (let itemG of allPermissionList) {
if(code === itemG.action){
if(itemG.status == '0'){
invalidFlag = true;
@ -92,7 +94,7 @@ function globalDisabledAuth(code){
return gFlag;
}
let permissions = [];
for (var item of permissionList) {
for (let item of permissionList) {
if(item.type == '2') {
permissions.push(item.action);
}
@ -101,9 +103,9 @@ function globalDisabledAuth(code){
if (!permissions.includes(code)) {
return gFlag;
}else{
for (var item2 of permissionList) {
for (let item2 of permissionList) {
if(code === item2.action){
console.log("页面权限解除禁用--Global--生效");
console.log("全局页面权限解除禁用--Global--生效");
gFlag = false;
}
}
@ -134,12 +136,12 @@ function hasColoum(item,authList){
//权限无效时不做控制有效时控制只能控制 显示不显示
//根据授权码前缀获取未授权的列信息
function getNoAuthCols(pre){
var permissionList = [];
var allPermissionList = [];
let permissionList = [];
let allPermissionList = [];
//let authList = Vue.ls.get(USER_AUTH);
let authList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
for (var auth of authList) {
for (let auth of authList) {
//显示策略有效状态
if(auth.type == '1'&&startWith(auth.action,pre)) {
permissionList.push(substrPre(auth.action,pre));
@ -147,7 +149,7 @@ function getNoAuthCols(pre){
}
//console.log("页面禁用权限--Global--",sessionStorage.getItem(SYS_BUTTON_AUTH));
let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
for (var gauth of allAuthList) {
for (let gauth of allAuthList) {
//显示策略有效状态
if(gauth.type == '1'&&gauth.status == '1'&&startWith(gauth.action,pre)) {
allPermissionList.push(substrPre(gauth.action,pre));

View File

@ -38,7 +38,7 @@ const getUploadFileList=(paths)=>{
uid:uidGenerator(),
name:getFileName(arr[a]),
status: 'done',
url: window._CONFIG['domianURL']+"/sys/common/view/"+arr[a],
url: window._CONFIG['staticDomainURL']+"/"+arr[a],
response:{
status:"history",
message:arr[a]

View File

@ -2,35 +2,37 @@ import { USER_AUTH,SYS_BUTTON_AUTH } from "@/store/mutation-types"
const hasPermission = {
install (Vue, options) {
console.log(options);
//console.log(options);
Vue.directive('has', {
inserted: (el, binding, vnode)=>{
console.log("页面权限控制----");
//console.log("页面权限控制----");
console.time()
//节点权限处理如果命中则不进行全局权限处理
if(!filterNodePermission(el, binding, vnode)){
filterGlobalPermission(el, binding, vnode);
}
console.timeEnd() //计时结束并输出时长
}
});
}
};
/**
* 全局权限控制
* 流程节点权限控制
*/
export function filterNodePermission(el, binding, vnode) {
console.log("页面权限--NODE--");
var permissionList = [];
let permissionList = [];
try {
var obj = vnode.context.$props.formData;
let obj = vnode.context.$props.formData;
if (obj) {
let bpmList = obj.permissionList;
for (var bpm of bpmList) {
for (let bpm of bpmList) {
if(bpm.type != '2') {
permissionList.push(bpm);
}
}
}else{
return false;
}
} catch (e) {
//console.log("页面权限异常----", e);
@ -39,8 +41,10 @@ export function filterNodePermission(el, binding, vnode) {
//el.parentNode.removeChild(el)
return false;
}
console.log("流程节点页面权限--NODE--");
let permissions = [];
for (var item of permissionList) {
for (let item of permissionList) {
if(item.type != '2') {
permissions.push(item.action);
}
@ -51,7 +55,7 @@ export function filterNodePermission(el, binding, vnode) {
//el.parentNode.removeChild(el)
return false;
}else{
for (var item2 of permissionList) {
for (let item2 of permissionList) {
if(binding.value === item2.action){
return true;
}
@ -64,29 +68,29 @@ export function filterNodePermission(el, binding, vnode) {
* 全局权限控制
*/
export function filterGlobalPermission(el, binding, vnode) {
console.log("页面权限--Global--");
console.log("全局页面权限--Global--");
var permissionList = [];
var allPermissionList = [];
let permissionList = [];
let allPermissionList = [];
//let authList = Vue.ls.get(USER_AUTH);
let authList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
for (var auth of authList) {
for (let auth of authList) {
if(auth.type != '2') {
permissionList.push(auth);
}
}
//console.log("页面权限--Global--",sessionStorage.getItem(SYS_BUTTON_AUTH));
let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
for (var gauth of allAuthList) {
for (let gauth of allAuthList) {
if(gauth.type != '2') {
allPermissionList.push(gauth);
}
}
//设置全局配置是否有命中
var invalidFlag = false;//无效命中
let invalidFlag = false;//无效命中
if(allPermissionList != null && allPermissionList != "" && allPermissionList != undefined && allPermissionList.length > 0){
for (var itemG of allPermissionList) {
for (let itemG of allPermissionList) {
if(binding.value === itemG.action){
if(itemG.status == '0'){
invalidFlag = true;
@ -103,7 +107,7 @@ export function filterGlobalPermission(el, binding, vnode) {
return;
}
let permissions = [];
for (var item of permissionList) {
for (let item of permissionList) {
if(item.type != '2'){
permissions.push(item.action);
}

View File

@ -5,9 +5,16 @@ import { VueAxios } from './axios'
import {Modal, notification} from 'ant-design-vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
//自动设置后台服务 baseURL (也可以手工指定写死项目名字)
let baseDomain = window._CONFIG['domianURL'];
let baseProject = baseDomain.substring(baseDomain.lastIndexOf("/"));
console.log("baseDomain= ",baseDomain)
console.log("baseProject= ",baseProject)
// 创建 axios 实例
const service = axios.create({
baseURL: '/jeecg-boot', // api base_url
//baseURL: '/jeecg-boot',
baseURL: baseProject, // api base_url
timeout: 9000 // 请求超时时间
})

View File

@ -257,6 +257,62 @@ export function cssExpand(css, id) {
document.head.appendChild(style)
}
/** 用于js增强事件运行JS代码可以传参 */
// options 所需参数
// 参数名 类型 说明
// vm VueComponent vue实例
// event Object event对象
// jsCode String 待执行的js代码
// errorMessage String 执行出错后的提示控制台
export function jsExpand(options = {}) {
// 绑定到window上的keyName
let windowKeyName = 'J_CLICK_EVENT_OPTIONS'
if (typeof window[windowKeyName] != 'object') {
window[windowKeyName] = {}
}
// 随机生成JS增强的执行id防止冲突
let id = randomString(16, 'qwertyuioplkjhgfdsazxcvbnm'.toUpperCase())
// 封装按钮点击事件
let code = `
(function (o_${id}) {
try {
(function (globalEvent, vm) {
${options.jsCode}
})(o_${id}.event, o_${id}.vm)
} catch (e) {
o_${id}.error(e)
}
o_${id}.done()
})(window['${windowKeyName}']['EVENT_${id}'])
`
// 创建script标签
const script = document.createElement('script')
// 将需要传递的参数挂载到window对象上
window[windowKeyName]['EVENT_' + id] = {
vm: options.vm,
event: options.event,
// 当执行完成时无论如何都会调用的回调事件
done() {
// 执行完后删除新增的 script 标签不会撤销执行结果已产生的结果不会被撤销
script.outerHTML = ''
delete window[windowKeyName]['EVENT_' + id]
},
// 当js运行出错的时候调用的事件
error(e) {
console.group(`${options.errorMessage || '用户自定义JS增强代码运行出错'}${new Date()}`)
console.error(e)
console.groupEnd()
}
}
// 将事件挂载到document中
script.innerHTML = code
document.body.appendChild(script)
}
/**
* 重复值验证工具方法
*
@ -270,12 +326,39 @@ export function cssExpand(css, id) {
* @param callback
*/
export function validateDuplicateValue(tableName, fieldName, fieldVal, dataId, callback) {
let params = { tableName, fieldName, fieldVal, dataId }
api.duplicateCheck(params).then(res => {
res['success'] ? callback() : callback(res['message'])
}).catch(err => {
callback(err.message || err)
})
if (fieldVal) {
let params = { tableName, fieldName, fieldVal, dataId }
api.duplicateCheck(params).then(res => {
res['success'] ? callback() : callback(res['message'])
}).catch(err => {
callback(err.message || err)
})
} else {
callback()
}
}
/**
* 根据编码校验规则code校验传入的值是否合法
*
* 使用示例
* { validator: (rule, value, callback) => validateCheckRule('common', value, callback) }
*
* @param ruleCode 编码校验规则 code
* @param value 被验证的值
* @param callback
*/
export function validateCheckRule(ruleCode, value, callback) {
if (ruleCode && value) {
value = encodeURIComponent(value)
api.checkRuleByCode({ ruleCode, value }).then(res => {
res['success'] ? callback() : callback(res['message'])
}).catch(err => {
callback(err.message || err)
})
} else {
callback()
}
}
/**
@ -295,4 +378,40 @@ export function pushIfNotExist(array, value, key) {
}
array.push(value)
return true
}
/**
* 可用于判断是否成功
* @type {symbol}
*/
export const succeedSymbol = Symbol()
/**
* 可用于判断是否失败
* @type {symbol}
*/
export const failedSymbol = Symbol()
/**
* 使 promise 无论如何都会 resolve除非传入的参数不是一个Promise对象或返回Promise对象的方法
* 一般用在 Promise.all
*
* @param promise 可传Promise对象或返回Promise对象的方法
* @returns {Promise<any>}
*/
export function alwaysResolve(promise) {
return new Promise((resolve, reject) => {
let p = promise
if (typeof promise === 'function') {
p = promise()
}
if (p instanceof Promise) {
p.then(data => {
resolve({ type: succeedSymbol, data })
}).catch(error => {
resolve({ type: failedSymbol, error })
})
} else {
reject('alwaysResolve: 传入的参数不是一个Promise对象或返回Promise对象的方法')
}
})
}

View File

@ -133,7 +133,7 @@
methods: {
...mapGetters(["nickname", "avatar"]),
getAvatar(){
return window._CONFIG['imgDomainURL']+"/"+this.avatar();
return window._CONFIG['staticDomainURL']+"/"+this.avatar();
},
getTeams() {
this.$http.get('/api/workplace/teams')

View File

@ -20,14 +20,14 @@
</chart-card>
</a-col>
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
<chart-card :loading="loading" title="访问" :total="8846 | NumberFormat">
<chart-card :loading="loading" title="订单" :total="8846 | NumberFormat">
<a-tooltip title="指标说明" slot="action">
<a-icon type="info-circle-o" />
</a-tooltip>
<div>
<mini-area />
</div>
<template slot="footer">访问<span> {{ '1234' | NumberFormat }}</span></template>
<template slot="footer">订单<span> {{ '1234' | NumberFormat }}</span></template>
</chart-card>
</a-col>
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
@ -85,7 +85,7 @@
</a-col>
</a-row>
</a-tab-pane>
<a-tab-pane tab="访问量" key="2">
<a-tab-pane tab="销售趋势" key="2">
<a-row>
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
<bar title="销售额趋势" :dataSource="barData"/>
@ -101,10 +101,10 @@
<a-row>
<a-col :span="24">
<a-card :loading="loading" :bordered="false" title="最近一周访问次数统计" :style="{ marginTop: '24px' }">
<a-card :loading="loading" :bordered="false" title="最近一周访问统计" :style="{ marginTop: '24px' }">
<a-row>
<a-col :span="6">
<head-info title="今日访问IP" :content="loginfo.todayIp"></head-info>
<head-info title="今日IP" :content="loginfo.todayIp"></head-info>
</a-col>
<a-col :span="2">
<a-spin class='circle-cust'>
@ -112,7 +112,7 @@
</a-spin>
</a-col>
<a-col :span="6">
<head-info title="今日访问次数" :content="loginfo.todayVisitCount"></head-info>
<head-info title="今日访问" :content="loginfo.todayVisitCount"></head-info>
</a-col>
<a-col :span="2">
<a-spin class='circle-cust'>
@ -120,7 +120,7 @@
</a-spin>
</a-col>
<a-col :span="6">
<head-info title="访问总次数" :content="loginfo.totalVisitCount"></head-info>
<head-info title="总访问量" :content="loginfo.totalVisitCount"></head-info>
</a-col>
<a-col :span="2">
<a-spin class='circle-cust'>

View File

@ -185,7 +185,7 @@
},
created() {
this.user = this.userInfo
this.avatar = window._CONFIG['imgDomainURL'] +"/"+ this.userInfo.avatar
this.avatar = window._CONFIG['staticDomainURL'] +"/"+ this.userInfo.avatar
console.log('this.avatar :'+ this.avatar)
getRoleList().then(res => {

View File

@ -9,7 +9,7 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="性别">
<j-dict-select-tag v-model="formData.sex" title="性别" dictCode="sex"/>
<j-dict-select-tag v-model="formData.sex" title="性别" dictCode="sex" placeholder="请选择性别"/>
<!-- <j-dict-select-tag title="性别" dictCode="sex" disabled/>-->
</a-form-item>
</a-col>
@ -176,34 +176,28 @@
<a-row :gutter="24">
<a-col>
<a-form-item label="最大化弹窗">
<a-button @click="()=>modal.visible=true">最大化弹窗</a-button>
<a-form-item label="JModal弹窗">
<a-button style="margin-right: 8px;" @click="()=>modal.visible=true">点击弹出JModal</a-button>
<span style="margin-right: 8px;">全屏化<a-switch v-model="modal.fullscreen"/></span>
<span style="margin-right: 8px;">允许切换全屏<a-switch v-model="modal.switchFullscreen"/></span>
<span>锁定Body滚动<a-switch v-model="modal.lockScroll"/></span>
</a-form-item>
<a-modal
:visible="modal.visible"
:width="modal.width"
:style="modal.style"
@ok="()=>modal.visible=false"
@cancel="()=>modal.visible=false">
<template slot="title">
<div style="width: 100%;height:20px;padding-right:32px;">
<div style="float: left;">{{ modal.title }}</div>
<div style="float: right;">
<a-button
icon="fullscreen"
style="width:56px;height:100%;border:0"
@click="handleClickToggleFullScreen"/>
</div>
</div>
</template>
<j-modal
:visible.sync="modal.visible"
:width="1200"
:title="modal.title"
:lockScroll="modal.lockScroll"
:fullscreen.sync="modal.fullscreen"
:switchFullscreen="modal.switchFullscreen"
>
<template v-for="(i,k) of 30">
<p :key="k">这是主体内容高度是自适应的</p>
</template>
</a-modal>
</j-modal>
</a-col>
</a-row>
@ -217,10 +211,10 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="树字典">
<j-tree-dict parentCode="B01" />
<j-tree-dict v-model="formData.treeDict" placeholder="请选择树字典" parentCode="A01" />
</a-form-item>
</a-col>
<a-col :span="12"></a-col>
<a-col :span="12">选中的值(v-model){{ formData.treeDict }}</a-col>
</a-row>
<a-row :gutter="24">
@ -262,6 +256,45 @@
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="高级查询">
<j-super-query :fieldList="superQuery.fieldList" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="高级查询(自定义按钮)">
<j-super-query :fieldList="superQuery.fieldList">
<!-- 直接在内部写一个按钮即可点击事件自动添加 -->
<a-button type="primary" ghost icon="clock-circle">高级查询</a-button>
</j-super-query>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="图片上传">
<j-image-upload v-model="imgList"></j-image-upload>
</a-form-item>
</a-col>
<a-col :spapn="12">选中的值(v-model){{ imgList }}</a-col>
</a-row>
<a-row :gutter="24" style="margin-top: 65px;margin-bottom:50px;">
<a-col :span="12">
<a-form-item label="文件上传">
<j-upload v-model="fileList"></j-upload>
</a-form-item>
</a-col>
<a-col :spapn="12">
选中的值(v-model)
<j-ellipsis :value="fileList" :length="30" v-if="fileList.length>0"/>
</a-col>
</a-row>
</a-form>
</div>
@ -286,10 +319,15 @@
import JTreeDict from "../../components/jeecg/JTreeDict.vue";
import JCron from "@/components/jeecg/JCron.vue";
import JTreeSelect from '@/components/jeecg/JTreeSelect'
import JSuperQuery from '@/components/jeecg/JSuperQuery'
import JUpload from '@/components/jeecg/JUpload'
import JImageUpload from '@/components/jeecg/JImageUpload'
export default {
name: 'SelectDemo',
components: {
JImageUpload,
JUpload,
JTreeDict,
JDictSelectTag,
JSelectDepart,
@ -299,7 +337,7 @@
JCheckbox,
JCodeEditor,
JDate, JEditor, JEllipsis, JGraphicCode, JSlider, JSelectMultiple,
JCron, JTreeSelect
JCron, JTreeSelect, JSuperQuery
},
data() {
return {
@ -352,11 +390,20 @@ sayHi('hello, world!')`
modal: {
title: '这里是标题',
visible: false,
width: '100%',
style: { top: '20px' },
fullScreen: true
lockScroll: true,
fullscreen: true,
switchFullscreen: true,
},
cron: '',
superQuery: {
fieldList: [
{ type: 'input', value: 'name', text: '姓名', },
{ type: 'select', value: 'sex', text: '性别', dictCode: 'sex' },
{ type: 'number', value: 'age', text: '年龄', }
]
},
fileList:[],
imgList:[],
}
},
computed: {
@ -399,18 +446,6 @@ sayHi('hello, world!')`
handleJSliderSuccess(value) {
this.jslider.value = value
},
/** 切换全屏显示 */
handleClickToggleFullScreen() {
let mode = !this.modal.fullScreen
if (mode) {
this.modal.width = '100%'
this.modal.style.top = '20px'
} else {
this.modal.width = '1200px'
this.modal.style.top = '50px'
}
this.modal.fullScreen = mode
},
setCorn(data){
this.$nextTick(() => {
this.form.cronExpression = data;

View File

@ -19,11 +19,13 @@
<a-cascader :options="areaOptions" @change="onChange" :showSearch="{filter}" placeholder="Please select" />
</a-form-item>
</a-col>
<a-col :md="24" :sm="24">
<a-form-item :wrapperCol="{ span: 12, offset: 5 }">
<a-button type="primary" htmlType="submit">Submit</a-button>
</a-form-item>
</a-col>
<a-form-item :wrapperCol="{ span: 12, offset: 5 }">
<a-col :md="24" :sm="24">
<a-form-item :wrapperCol="{ span: 12, offset: 5 }">
<a-button type="primary" htmlType="submit">Submit</a-button>
</a-form-item>
</a-col>
</a-form-item>
</a-form>
</a-card>
</template>
@ -68,4 +70,4 @@
})
}
}
</script>
</script>

View File

@ -35,12 +35,13 @@
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="sex">
<a-select v-decorator="['sex', {}]" placeholder="请选择性别">
<a-select-option value="">请选择性别</a-select-option>
<a-select-option value="1">男性</a-select-option>
<a-select-option value="2">女性</a-select-option>
</a-select>
label="性别">
<!-- <a-select v-decorator="['sex', {}]" placeholder="请选择性别">
<a-select-option value="">请选择</a-select-option>
<a-select-option value="1"></a-select-option>
<a-select-option value="2"></a-select-option>
</a-select>-->
<j-dict-select-tag type="radio" v-decorator="['sex', {}]" :trigger-change="true" dictCode="sex"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"

View File

@ -2,7 +2,7 @@
<a-card :bordered="false">
<a-tabs defaultActiveKey="1" @change="callback">
<a-tab-pane tab="柱状图" key="1">
<a-row :gutter="24">
<a-row>
<a-col :span="10">
<a-radio-group :value="barType" @change="statisticst">
<a-radio-button value="year">按年统计</a-radio-button>

View File

@ -43,24 +43,7 @@
:wrapperCol="wrapperCol"
label="身份证扫描件"
hasFeedback>
<a-upload
:action="uploadAction"
listType="picture-card"
:headers="headers"
:fileList="fileList"
@change="handleChange"
@preview="handlePreview"
>
<a-button>
<a-icon type="upload"/>
upload
</a-button>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handlePicCancel">
<img alt="example" style="width: 100%" :src="previewImage"/>
</a-modal>
<br/>
<j-image-upload text="上传" v-model="fileList" :isMultiple="true"></j-image-upload>
</a-form-item>
<a-form-item
:labelCol="labelCol"
@ -88,11 +71,11 @@
import pick from 'lodash.pick'
import Vue from 'vue'
import {ACCESS_TOKEN} from "@/store/mutation-types"
import { getUploadFileList,getFilePaths } from '@/utils/commonUploadFile.js'
import JImageUpload from '../../../../components/jeecg/JImageUpload'
export default {
name: "JeecgOrderCustomerModal",
components: { JImageUpload },
data() {
return {
title: "操作",
@ -177,7 +160,7 @@
add: "/test/order/addCustomer",
edit: "/test/order/editCustomer",
fileUpload: window._CONFIG['domianURL'] + "/sys/common/upload",
imgerver: window._CONFIG['domianURL'] + "/sys/common/view",
imgerver: window._CONFIG['staticDomainURL'],
getOrderCustomerList: "/test/order/listOrderCustomerByMainId",
},
validatorRules: {
@ -222,8 +205,6 @@
this.form.resetFields();
this.orderId = record.orderId;
let currFileList = getUploadFileList(record.idcardPic)
this.fileList = [...currFileList]
this.model = Object.assign({}, record);
if (record.id) {
this.hiding = false;
@ -232,6 +213,9 @@
this.$nextTick(() => {
this.form.setFieldsValue(pick(this.model, 'id', 'name', 'sex', 'idcard','telphone', 'orderId', 'createBy', 'createTime', 'updateBy', 'updateTime'))
});
setTimeout(() => {
this.fileList = record.idcardPic
}, 5)
} else {
this.addStatus = false;
this.editStatus = true;
@ -262,7 +246,7 @@
let formData = Object.assign(this.model, values);
console.log(formData);
formData.orderId = this.orderId;
formData.idcardPic = getFilePaths(this.fileList)
formData.idcardPic = this.fileList;
httpAction(httpurl, formData, method).then((res) => {
if (res.success) {
that.$message.success(res.message);

View File

@ -6,13 +6,13 @@
<a-form layout="inline">
<a-row :gutter="24">
<a-col :md="6" :sm="24">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="表名">
<a-input placeholder="请输入表名" v-model="queryParam.tableName"></a-input>
</a-form-item>
</a-col>
<a-col :md="6" :sm="24">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
@ -25,10 +25,10 @@
<!-- 操作按钮区域 -->
<div class="table-operator">
<a-button @click="doCgformButton" type="primary" icon="highlight" style="margin-left:8px">自定义按钮</a-button>
<a-button @click="doEnhanceJs" type="primary" icon="strikethrough" style="margin-left:8px">JS增强</a-button>
<a-button @click="doEnhanceSql" type="primary" icon="filter" style="margin-left:8px">SQL增强</a-button>
<a-button @click="doEnhanceJava" type="primary" icon="tool" style="margin-left:8px">Java增强</a-button>
<a-button @click="doCgformButton" type="primary" icon="highlight">自定义按钮</a-button>
<a-button @click="doEnhanceJs" type="primary" icon="strikethrough">JS增强</a-button>
<a-button @click="doEnhanceSql" type="primary" icon="filter">SQL增强</a-button>
<a-button @click="doEnhanceJava" type="primary" icon="tool">Java增强</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
@ -37,7 +37,7 @@
删除
</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作
<a-button> 批量操作
<a-icon type="down"/>
</a-button>
</a-dropdown>
@ -348,6 +348,9 @@
}
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>
<style lang="less">
.ant-card-body .table-operator {
margin-bottom: 18px;

View File

@ -6,18 +6,22 @@
<a-form layout="inline">
<a-row :gutter="24">
<a-col :md="6" :sm="24">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="表名">
<a-input placeholder="请输入表名" v-model="queryParam.tableName"></a-input>
</a-form-item>
</a-col>
<a-col :md="6" :sm="24">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="表类型">
<j-dict-select-tag dictCode="cgform_table_type" v-model="queryParam.tableType"/>
</a-form-item>
</a-col>
<a-col :md="6" :sm="24">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="表描述">
<a-input placeholder="请输入表描述" v-model="queryParam.tableTxt"></a-input>
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
@ -31,12 +35,12 @@
<!-- 操作按钮区域 -->
<div class="table-operator">
<a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
<a-button @click="doCgformButton" type="primary" icon="highlight" style="margin-left:8px">自定义按钮</a-button>
<a-button @click="doEnhanceJs" type="primary" icon="strikethrough" style="margin-left:8px">JS增强</a-button>
<a-button @click="doEnhanceSql" type="primary" icon="filter" v-has="'online:sql'" style="margin-left:8px">SQL增强</a-button>
<a-button @click="doEnhanceJava" type="primary" icon="tool" style="margin-left:8px">Java增强</a-button>
<a-button @click="importOnlineForm" type="primary" icon="database" style="margin-left:8px">从数据库导入表单</a-button>
<a-button @click="goGenerateCode" v-has="'online:goGenerateCode'" type="primary" icon="database" style="margin-left:8px">代码生成</a-button>
<a-button @click="doCgformButton" type="primary" icon="highlight">自定义按钮</a-button>
<a-button @click="doEnhanceJs" type="primary" icon="strikethrough">JS增强</a-button>
<a-button @click="doEnhanceSql" type="primary" icon="filter">SQL增强</a-button>
<a-button @click="doEnhanceJava" type="primary" icon="tool">Java增强</a-button>
<a-button @click="importOnlineForm" type="primary" icon="database">从数据库导入表单</a-button>
<a-button @click="goGenerateCode" type="primary" icon="database">代码生成</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
@ -45,7 +49,7 @@
删除
</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作
<a-button> 批量操作
<a-icon type="down"/>
</a-button>
</a-dropdown>
@ -204,8 +208,12 @@
title: '表类型',
align: 'center',
dataIndex: 'tableType',
customRender: (text) => {
return filterDictText(this.tableTypeDictOptions, `${text}`)
customRender: (text, record) => {
let tbTypeText = filterDictText(this.tableTypeDictOptions, `${text}`)
if(record.isTree === 'Y'){
tbTypeText+='()'
}
return tbTypeText;
}
},
{
@ -316,10 +324,14 @@
this.syncFormId = id
},
goPageOnline(rd) {
if(rd.isTree=='Y'){
this.$router.push({ path: '/online/cgformTreeList/' + rd.id })
if(rd.themeTemplate === 'erp'){
this.$router.push({ path: '/online/cgformErpList/' + rd.id })
}else{
this.$router.push({ path: '/online/cgformList/' + rd.id })
if(rd.isTree=='Y'){
this.$router.push({ path: '/online/cgformTreeList/' + rd.id })
}else{
this.$router.push({ path: '/online/cgformList/' + rd.id })
}
}
},
handleOnlineUrlClose() {
@ -438,6 +450,9 @@
}
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>
<style lang="less">
.ant-card-body .table-operator {
margin-bottom: 18px;

View File

@ -40,16 +40,15 @@
<!-- 操作按钮区域 -->
<div class="table-operator">
<a-button v-if="buttonSwitch.add" @click="handleAdd" type="primary" icon="plus">新增</a-button>
<a-button v-if="buttonSwitch.import" @click="handleImportXls" type="primary" icon="upload" style="margin-left:8px">导入</a-button>
<a-button v-if="buttonSwitch.export" @click="handleExportXls" type="primary" icon="download" style="margin-left:8px">导出</a-button>
<a-button v-if="buttonSwitch.import" @click="handleImportXls" type="primary" icon="upload">导入</a-button>
<a-button v-if="buttonSwitch.export" @click="handleExportXls" type="primary" icon="download">导出</a-button>
<template v-if="cgButtonList && cgButtonList.length>0" v-for="(item,index) in cgButtonList">
<a-button
v-if=" item.optType=='js' "
:key=" 'cgbtn'+index "
@click="cgButtonJsHandler(item.buttonCode)"
type="primary"
:icon="item.buttonIcon"
style="margin-left:8px">
:icon="item.buttonIcon">
{{ item.buttonName }}
</a-button>
<a-button
@ -57,8 +56,7 @@
:key=" 'cgbtn'+index "
@click="cgButtonActionHandler(item.buttonCode)"
type="primary"
:icon="item.buttonIcon"
style="margin-left:8px">
:icon="item.buttonIcon">
{{ item.buttonName }}
</a-button>
</template>
@ -69,13 +67,11 @@
:fieldList="superQuery.fieldList"
:saveCode="$route.fullPath"
:loading="table.loading"
style="margin-left: 8px;"
@handleSuperQuery="handleSuperQuery"/>
<a-button
v-if="buttonSwitch.batch_delete"
@click="handleDelBatch"
style="margin-left:8px"
v-show="table.selectedRowKeys.length > 0"
ghost
type="primary"
@ -103,6 +99,16 @@
:scroll="table.scroll"
style="min-height: 300px">
<!-- 支持链接href跳转 -->
<template
v-for="field of fieldHrefSlots"
:slot="field.slotName"
slot-scope="text, record"
>
<a @click="handleClickFieldHref(field,record)">{{ text }}</a>
</template>
<template slot="dateSlot" slot-scope="text">
<span>{{ getFormatDate(text) }}</span>
</template>
@ -149,23 +155,17 @@
更多 <a-icon type="down" />
</a>
<a-menu slot="overlay">
<a-menu-item >
<a-menu-item v-if="buttonSwitch.detail">
<a href="javascript:;" @click="handleDetail(record)">详情</a>
</a-menu-item>
<template v-if="hasBpmStatus">
<template v-if="record.bpm_status == '1'||record.bpm_status == ''|| record.bpm_status == null">
<a-menu-item>
<a href="javascript:;" @click="startProcess(record)">提交流程</a>
</a-menu-item>
<a-menu-item v-if="buttonSwitch.delete">
<a-popconfirm title="确定删除吗?" @confirm="() => handleDeleteOne(record)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</template>
<template v-else>
<a-menu-item @click="handlePreviewPic(record)">审批进度</a-menu-item>
</template>
</template>
<template v-else>
<a-menu-item v-if="buttonSwitch.delete">
@ -175,7 +175,7 @@
</a-menu-item>
</template>
<template v-if="cgButtonLinkList && cgButtonLinkList.length>0" v-for="(btnItem,btnIndex) in cgButtonLinkList">
<a-menu-item :key=" 'cgbtnLink'+btnIndex ">
<a-menu-item :key=" 'cgbtnLink'+btnIndex " v-if="showLinkButton(btnItem,record)">
<a href="javascript:void(0);" @click="cgButtonLinkHandler(record,btnItem.buttonCode,btnItem.optType)">
<a-icon v-if="btnItem.buttonIcon" :type="btnItem.buttonIcon" />
{{ btnItem.buttonName }}
@ -192,20 +192,27 @@
<j-import-modal ref="importModal" :url="getImportUrl()" @ok="importOk"></j-import-modal>
<!-- 跳转Href的动态组件方式 -->
<a-modal v-bind="hrefComponent.model" v-on="hrefComponent.on">
<component :is="hrefComponent.is" v-bind="hrefComponent.params"/>
</a-modal>
</div>
</a-card>
</template>
<script>
import { HrefJump } from '@/mixins/OnlAutoListMixin'
import { postAction,getAction,deleteAction,downFile } from '@/api/manage'
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
import { filterObj } from '@/utils/util';
import { cloneObject, filterObj } from '@/utils/util'
import JImportModal from '@/components/jeecg/JImportModal'
import JSuperQuery from '@comp/jeecg/JSuperQuery'
export default {
name: 'OnlCgFormAutoList',
mixins: [HrefJump],
components: {
JSuperQuery,
JImportModal,
@ -222,7 +229,6 @@
optPre:"/online/cgform/api/form/",
exportXls:'/online/cgform/api/exportXls/',
buttonAction:'/online/cgform/api/doButton',
startProcess: "/process/extActProcess/startMutilProcess",
},
flowCodePre:"onl_",
isorter:{
@ -282,7 +288,8 @@
delete:true,
batch_delete:true,
import:true,
export:true
export:true,
detail:true
},
hasBpmStatus:false,
checkboxFlag:false,
@ -304,8 +311,7 @@
this.cgButtonJsHandler('mounted')
},
watch: {
'$route.path'(newVal,oldVal) {
console.log('$route.path ',oldVal)
'$route'() {
// 刷新参数放到这里去触发就可以刷新相同界面了
this.initAutoList()
}
@ -343,30 +349,6 @@
this.hasBpmStatus = false;
}
},
startProcess: function(record){
var that = this;
this.$confirm({
title:"提示",
content:"确认提交流程吗?",
onOk: function(){
var param = {
flowCode:that.flowCodePre+that.currentTableName,
id:record.id,
formUrl:"modules/bpm/task/form/OnlineFormDetail",
formUrlMobile:"modules/bpm/task/form/OnlineFormDetail"
}
postAction(that.url.startProcess,param).then((res)=>{
if(res.success){
that.$message.success(res.message);
that.loadData();
that.onClearSelected();
}else{
that.$message.warning(res.message);
}
});
}
});
},
initQueryInfo(){
getAction(`${this.url.getQueryInfo}${this.code}`).then((res)=>{
console.log("--onlineList-获取查询条件配置",res);
@ -407,6 +389,7 @@
this.table.pagination = false
}
this.fieldHrefSlots = res.result.fieldHrefSlots
this.dictOptions = res.result.dictOptions
this.formTemplate = res.result.formTemplate
this.description = res.result.description
@ -441,6 +424,8 @@
this.hasBpmStatusFilter();
this.loadData();
this.initQueryInfo();
//加载新路由清空checkbox选中
this.table.selectedRowKeys = [];
}else{
this.$message.warning(res.message)
}
@ -569,6 +554,10 @@
this.cgButtonLinkHandler(record,"beforeEdit","js")
this.$refs.modal.edit(this.formTemplate,record.id);
},
showLinkButton(item,record){
let btn = new ButtonExpHandler(item.exp,record);
return btn.show;
},
handleDetail(record){
this.$refs.modal.detail(this.formTemplate,record.id);
},
@ -604,7 +593,8 @@
dictCode: field.dictCode,
dictTable: field.dictTable,
dictText: field.dictText,
options: field.enum || field.options
options: field.enum || field.options,
order: field.order,
})
}
let fieldList = []
@ -630,6 +620,17 @@
setField(fieldList, field)
}
}
// 冒泡排序
for (let i = 0; i < fieldList.length; i++) {
for (let j = i + 1; j < fieldList.length; j++) {
let temp1 = fieldList[i]
let temp2 = fieldList[j]
if (temp1.order > temp2.order) {
fieldList[i] = temp2
fieldList[j] = temp1
}
}
}
this.superQuery.fieldList = fieldList
}
},
@ -641,7 +642,7 @@
if(text && text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
return window._CONFIG['imgDomainURL']+"/"+text
return window._CONFIG['staticDomainURL']+"/"+text
},
downloadRowFile(text){
if(!text){
@ -651,7 +652,7 @@
if(text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
window.open(window._CONFIG['downloadUrl']+"/"+text);//TODO 下载的方法
window.open(window._CONFIG['staticDomainURL']+"/"+text);//TODO 下载的方法
},
handleDelBatch(){
if(this.table.selectedRowKeys.length<=0){
@ -777,13 +778,15 @@
}
},
initButtonSwitch(hideColumns){
Object.keys(this.buttonSwitch).forEach(key=>{
this.buttonSwitch[key]=true
})
if(hideColumns && hideColumns.length>0){
Object.keys(this.buttonSwitch).forEach(key=>{
if(hideColumns.indexOf(key)>=0){
this.buttonSwitch[key]=false
}
})
}
},
@ -801,6 +804,9 @@
}
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>
<style>
.ant-card-body .table-operator{
margin-bottom: 18px;

View File

@ -98,15 +98,6 @@
<a-menu-item >
<a @click="handleDetail(record)">详情</a>
</a-menu-item>
<a-menu-item v-if="showSubmitFlowButton(record)">
<a @click="startProcess(record)">提交流程</a>
</a-menu-item>
<template v-if="showViewFlowButton(record)">
<a-menu-item @click="handlePreviewPic(record)">审批进度</a-menu-item>
</template>
<a-menu-item v-if="showOptButton('delete',record)">
<a-popconfirm title="确定删除吗?" @confirm="() => handleDeleteOne(record)">
<a>删除</a>
@ -146,7 +137,7 @@
export default {
name: 'OnlCgformTreeList',
components: {
JImportModal
JImportModal,
},
data() {
return {
@ -183,7 +174,6 @@
optPre:"/online/cgform/api/form/",
exportXls:'/online/cgform/api/exportXls/',
buttonAction:'/online/cgform/api/doButton',
startProcess: "/process/extActProcess/startMutilProcess"
},
isorter:{
column: 'create_time',
@ -482,7 +472,7 @@
if(text && text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
return window._CONFIG['imgDomainURL']+"/"+text
return window._CONFIG['staticDomainURL']+"/"+text
},
downloadRowFile(text){
if(!text){
@ -492,7 +482,7 @@
if(text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
window.open(window._CONFIG['downloadUrl']+"/"+text);
window.open(window._CONFIG['staticDomainURL']+"/"+text);
},
/*-------数据格式化-end----------*/
@ -651,14 +641,6 @@
}
return true
},
showSubmitFlowButton(record){
if(this.hasBpmStatus){
if(record.bpm_status ==null || record.bpm_status =='' || record.bpm_status == '1'){
return true
}
}
return false
},
showViewFlowButton(record){
if(this.hasBpmStatus){
if(record.bpm_status !=null && record.bpm_status !='' && record.bpm_status != '1'){
@ -691,6 +673,7 @@
}
});
},
}
}
</script>

View File

@ -0,0 +1,111 @@
<template>
<a-card :bordered="false" style="height: 100%">
<online-common-list
:ref="'onl_'+mainModel.currentTableName"
:code="code"
:model="mainModel"
@seleted="onSelected">
</online-common-list>
<a-tabs defaultActiveKey="0">
<a-tab-pane v-for="(item,index) in subList" :tab="item.description" :key="index+''" :forceRender="true" >
<online-common-list
:ref="item.currentTableName"
:code="item.code"
:model="item"
:main="selectedRow">
</online-common-list>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script>
import { getAction } from '@/api/manage'
export default {
name: 'OnlCgformErpList',
components:{
},
data(){
return {
code:'',
url: {
getColumns: '/online/cgform/api/getErpColumns/',
},
mainModel:{},
subList:[],
mainId:'',
selectedRow:{}
}
},
watch: {
'$route'() {
// 刷新参数放到这里去触发就可以刷新相同界面了
this.initColumnConfig()
}
},
created() {
this.initColumnConfig();
},
methods:{
getSubIndex(index){
return index+1 + ''
},
getSubRef(item){
let ref = item.currentTableName
console.log("ref string",ref)
return ref;
},
initColumnConfig(){
if(!this.$route.params.code){
return false
}
this.code = this.$route.params.code
getAction(`${this.url.getColumns}${this.code}`).then((res)=>{
console.log("erp表单配置",res)
if(res.success){
this.mainModel = res.result.main
this.subList = res.result.subList
this.$nextTick(()=>{
this.$refs['onl_'+this.mainModel.currentTableName].initListByModel();
if(this.subList && this.subList.length>0){
for(let item of this.subList){
this.$refs[item.currentTableName][0].initListByModel();
}
}
});
}
})
},
onSelected(row){
console.log("onSelected",row)
this.selectedRow = row;
}
}
}
</script>
<style>
.ant-card-body .table-operator{
margin-bottom: 18px;
}
.ant-table-tbody .ant-table-row td{
padding-top:15px;
padding-bottom:15px;
}
.anty-row-operator button{margin: 0 5px}
.ant-btn-danger{background-color: #ffffff}
.anty-img-wrap{height:25px;position: relative;}
.anty-img-wrap > img{max-height:100%;}
.ant-modal-cust-warp{height: 100%}
.ant-modal-cust-warp .ant-modal-body{height:calc(100% - 110px) !important;overflow-y: auto}
.ant-modal-cust-warp .ant-modal-content{height:90% !important;overflow-y: hidden}
</style>

View File

@ -109,6 +109,7 @@ export function getMasterTableInitialData() {
// table2
isShowForm: '0',
isShowList: '0',
isReadOnly: '1',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',

View File

@ -31,7 +31,21 @@
@change="handleChange">
<a-button>
<a-icon type="upload"/>
文件上传
OSS文件上传
</a-button>
</a-upload>
<a-upload
name="file"
:multiple="false"
:action="minioUploadAction"
:headers="tokenHeader"
:showUploadList="false"
:beforeUpload="beforeUpload"
@change="handleChange">
<a-button>
<a-icon type="upload"/>
MINIO文件上传
</a-button>
</a-upload>
</div>
@ -58,7 +72,9 @@
@change="handleTableChange">
<span slot="action" slot-scope="text, record">
<a @click="ossDelete(record.id)">删除</a>
<a @click="handlePreview(record)">预览</a>
<a-divider type="vertical"/>
<a @click="ossDelete(record.id)">删除</a>
</span>
</a-table>
@ -108,14 +124,18 @@
url: {
upload: "/oss/file/upload",
list: "/oss/file/list",
delete: "/oss/file/delete"
delete: "/oss/file/delete",
minioUpload: "/sys/upload/uploadMinio"
}
}
},
computed: {
uploadAction() {
return window._CONFIG['domianURL'] + this.url.upload;
}
},
minioUploadAction() {
return window._CONFIG['domianURL'] + this.url.minioUpload;
},
},
methods: {
beforeUpload(file) {
@ -139,10 +159,10 @@
this.loadData()
this.$message.success(`${info.file.name} 上传成功!`);
} else {
this.$message.error(`${info.file.name} 上传失败.`);
this.$message.error(`${info.file.response.message}`);
}
} else if (info.file.status === 'error') {
this.$message.error(`${info.file.name} 上传失败.`);
this.$message.error(`${info.file.response.message}`);
}
},
ossDelete(id) {
@ -154,11 +174,17 @@
that.handleDelete(id)
}
});
},
handlePreview(record) {
if (record && record.url) {
let url = window._CONFIG['onlinePreviewDomainURL'] + '?url=' + encodeURIComponent(record.url)
window.open(url, '_blank')
}
}
}
}
</script>
<style scoped>
@import '~@assets/less/common.less'
@import '~@assets/less/common.less';
</style>

View File

@ -17,8 +17,7 @@
<div style="background: #fff;padding-left:16px;height: 100%; margin-top: 5px">
<a-alert type="info" :showIcon="true">
<div slot="message">
当前选择
<a v-if="this.currSelected.title">{{ getCurrSelectedTitle() }}</a>
当前选择<span v-if="this.currSelected.title">{{ getCurrSelectedTitle() }}</span>
<a v-if="this.currSelected.title" style="margin-left: 10px" @click="onClearSelected">取消选择</a>
</div>
</a-alert>
@ -72,82 +71,90 @@
<!---- author:os_chengtgen -- date:20190827 -- for:切换父子勾选模式 =======------>
</a-col>
<a-col :md="12" :sm="24">
<a-card :bordered="false">
<a-form :form="form">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="机构名称">
<a-input placeholder="请输入机构/部门名称" v-decorator="['departName', validatorRules.departName ]"/>
</a-form-item>
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="上级部门">
<a-tree-select
style="width:100%"
:dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
:treeData="treeData"
:disabled="disable"
v-model="model.parentId"
placeholder="">
</a-tree-select>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="机构编码">
<a-input disabled placeholder="请输入机构编码" v-decorator="['orgCode', validatorRules.orgCode ]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="机构类型">
<template v-if="orgCategoryDisabled">
<a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
<a-radio value="1">
公司
</a-radio>
</a-radio-group>
</template>
<template v-else>
<a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
<a-radio value="2">
部门
</a-radio>
<a-radio value="3">
岗位
</a-radio>
</a-radio-group>
</template>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="排序">
<a-input-number v-decorator="[ 'departOrder',{'initialValue':0}]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="手机号">
<a-input placeholder="请输入手机号" v-decorator="['mobile', {'initialValue':''}]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="地址">
<a-input placeholder="请输入地址" v-decorator="['address', {'initialValue':''}]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="备注">
<a-textarea placeholder="请输入备注" v-decorator="['memo', {'initialValue':''}]"/>
</a-form-item>
</a-form>
<div class="anty-form-btn">
<a-button @click="emptyCurrForm" type="default" htmlType="button" icon="sync">重置</a-button>
<a-button @click="submitCurrForm" type="primary" htmlType="button" icon="form">修改并保存</a-button>
</div>
</a-card>
<a-tabs defaultActiveKey="1">
<a-tab-pane tab="基本信息" key="1" >
<a-card :bordered="false">
<a-form :form="form">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="机构名称">
<a-input placeholder="请输入机构/部门名称" v-decorator="['departName', validatorRules.departName ]"/>
</a-form-item>
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="上级部门">
<a-tree-select
style="width:100%"
:dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
:treeData="treeData"
:disabled="disable"
v-model="model.parentId"
placeholder="">
</a-tree-select>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="机构编码">
<a-input disabled placeholder="请输入机构编码" v-decorator="['orgCode', validatorRules.orgCode ]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="机构类型">
<template v-if="orgCategoryDisabled">
<a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
<a-radio value="1">
公司
</a-radio>
</a-radio-group>
</template>
<template v-else>
<a-radio-group v-decorator="['orgCategory',validatorRules.orgCategory]" placeholder="请选择机构类型">
<a-radio value="2">
部门
</a-radio>
<a-radio value="3">
岗位
</a-radio>
</a-radio-group>
</template>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="排序">
<a-input-number v-decorator="[ 'departOrder',{'initialValue':0}]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="手机号">
<a-input placeholder="请输入手机号" v-decorator="['mobile', {'initialValue':''}]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="地址">
<a-input placeholder="请输入地址" v-decorator="['address', {'initialValue':''}]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="备注">
<a-textarea placeholder="请输入备注" v-decorator="['memo', {'initialValue':''}]"/>
</a-form-item>
</a-form>
<div class="anty-form-btn">
<a-button @click="emptyCurrForm" type="default" htmlType="button" icon="sync">重置</a-button>
<a-button @click="submitCurrForm" type="primary" htmlType="button" icon="form">修改并保存</a-button>
</div>
</a-card>
</a-tab-pane>
<a-tab-pane tab="部门权限" key="2" forceRender>
<depart-auth-modal ref="departAuth"/>
</a-tab-pane>
</a-tabs>
</a-col>
<depart-modal ref="departModal" @ok="loadTree"></depart-modal>
</a-row>
@ -158,6 +165,7 @@
import {queryDepartTreeList, searchByKeywords, deleteByDepartId} from '@/api/api'
import {httpAction, deleteAction} from '@/api/manage'
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import DepartAuthModal from './modules/DepartAuthModal'
// 表头
const columns = [
{
@ -201,6 +209,7 @@
name: 'DepartList',
mixins: [JeecgListMixin],
components: {
DepartAuthModal,
DepartModal
},
data() {
@ -403,7 +412,7 @@
this.selectedKeys = [record.key]
this.model.parentId = record.parentId
this.setValuesToForm(record)
this.$refs.departAuth.show(record.id);
},
// 触发onSelect事件时,为部门树右侧的form表单赋值
@ -425,6 +434,7 @@
this.currSelected = {}
this.form.resetFields()
this.selectedKeys = []
this.$refs.departAuth.departId = ''
},
handleNodeTypeChange(val) {
this.currSelected.nodeType = val

View File

@ -6,7 +6,7 @@
<a-input-search @search="onSearch" style="width:100%;margin-top: 10px" placeholder="请输入部门名称"/>
<!-- -->
<template>
<template v-if="userIdentity === '2' && departTree.length>0">
<!--组织机构-->
<a-tree
@ -16,10 +16,14 @@
@select="onSelect"
:dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
:treeData="departTree"
:autoExpandParent="autoExpandParent"
/>
</template>
<div style="margin-top: 24px;" v-else-if="userIdentity === '2' && departTree.length==0">
<h3><span>您的部门下暂无有效部门信息</span></h3>
</div>
<div style="margin-top: 24px;" v-else><h3>普通员工暂此权限</h3></div>
</div>
</a-card>
</a-col>
@ -30,7 +34,10 @@
<Dept-Base-Info ref="DeptBaseInfo"></Dept-Base-Info>
</a-tab-pane>
<a-tab-pane tab="用户信息" key="2">
<Dept-User-Info ref="DeptUserInfo"></Dept-User-Info>
<Dept-User-Info ref="DeptUserInfo" @clearSelectedDepartKeys="clearSelectedDepartKeys"></Dept-User-Info>
</a-tab-pane>
<a-tab-pane tab="部门角色" key="3" forceRender>
<dept-role-info ref="DeptRoleInfo" @clearSelectedDepartKeys="clearSelectedDepartKeys"/>
</a-tab-pane>
</a-tabs>
</a-card>
@ -40,13 +47,15 @@
<script>
import DeptBaseInfo from './modules/DeptBaseInfo'
import DeptUserInfo from './modules/DeptUserInfo'
import {queryDepartTreeList, searchByKeywords} from '@/api/api'
import {queryMyDepartTreeList, searchByKeywords} from '@/api/api'
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import DeptRoleInfo from './modules/DeptRoleInfo'
export default {
name: 'DepartUserList',
mixins: [JeecgListMixin],
components: {
DeptRoleInfo,
DeptBaseInfo,
DeptUserInfo,
},
@ -85,6 +94,7 @@
nodes: [],
edges: []
},
userIdentity:"",
}
},
methods: {
@ -94,12 +104,19 @@
loadData() {
this.refresh();
},
clearSelectedDepartKeys() {
this.checkedKeys = [];
this.selectedKeys = [];
this.currentDeptId = '';
this.$refs.DeptUserInfo.currentDeptId='';
this.$refs.DeptRoleInfo.currentDeptId='';
},
loadTree() {
var that = this
that.treeData = []
that.departTree = []
queryDepartTreeList().then((res) => {
if (res.success) {
queryMyDepartTreeList().then((res) => {
if (res.success && res.result ) {
for (let i = 0; i < res.result.length; i++) {
let temp = res.result[i]
that.treeData.push(temp)
@ -109,6 +126,7 @@
}
this.loading = false
}
that.userIdentity = res.message
})
},
setThisExpandedKeys(node) {
@ -161,6 +179,7 @@
this.$refs.DeptBaseInfo.open(record);
this.$refs.DeptUserInfo.open(record);
this.$refs.DeptRoleInfo.open(record);
// }
// else {
// this.checkedKeys = [];
@ -180,6 +199,8 @@
this.$refs.DeptBaseInfo.open(record);
this.$refs.DeptUserInfo.onClearSelected();
this.$refs.DeptUserInfo.open(record);
this.$refs.DeptRoleInfo.onClearSelected();
this.$refs.DeptRoleInfo.open(record);
},
},
created() {

View File

@ -30,6 +30,7 @@
<a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
<a-button type="primary" icon="import">导入</a-button>
</a-upload>
<a-button type="primary" icon="sync" @click="refleshCache()">刷新缓存</a-button>
<a-button type="primary" icon="hdd" @click="openDeleteList">回收站</a-button>
</div>
@ -70,6 +71,7 @@
import DictModal from './modules/DictModal'
import DictItemList from './DictItemList'
import DictDeleteList from './DictDeleteList'
import { getAction } from '@/api/manage'
export default {
name: "DictList",
@ -132,6 +134,7 @@
delete: "/sys/dict/delete",
exportXlsUrl: "sys/dict/exportXls",
importExcelUrl: "sys/dict/importExcel",
refleshCache: "sys/dict/refleshCache",
},
}
},
@ -165,9 +168,18 @@
that.queryParam.dictCode = "";
that.loadData(this.ipagination.current);
},
openDeleteList(){
this.$refs.dictDeleteList.show()
},
refleshCache(){
getAction(this.url.refleshCache).then((res) => {
if (res.success) {
this.$message.success("刷新缓存完成!");
}
}).catch(e=>{
this.$message.warn("刷新缓存失败!");
console.log("刷新失败",e)
})
}
},
watch: {

View File

@ -29,7 +29,9 @@
:dataSource="dataSource"
:loading="loading"
@expand="expandSubmenu"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}">
:expandedRowKeys="expandedRowKeys"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@expandedRowsChange="handleExpandedRowsChange">
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
@ -79,7 +81,7 @@
<script>
import PermissionModal from './modules/PermissionModal'
import { getSystemMenuList,getSystemSubmenu } from '@/api/api'
import { getSystemMenuList, getSystemSubmenu, getSystemSubmenuBatch } from '@/api/api'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import PermissionDataRuleList from './PermissionDataRuleList'
import JEllipsis from '@/components/jeecg/JEllipsis'
@ -140,7 +142,7 @@
]
export default {
name: 'PermissionList',
name: 'PermissionListAsync',
mixins: [JeecgListMixin],
components: {
PermissionDataRuleList,
@ -153,6 +155,8 @@
// 表头
columns: columns,
loading: false,
// 展开的行受控属性
expandedRowKeys: [],
url: {
list: '/sys/permission/list',
delete: '/sys/permission/delete',
@ -162,23 +166,45 @@
},
methods: {
loadData() {
this.dataSource = []
this.loading = true
getSystemMenuList().then((res) => {
if (res.success) {
console.log(res.result)
this.dataSource = res.result
return this.loadDataByExpandedRows(this.dataSource)
}
}).finally(()=>{
this.loading = false
})
},
expandSubmenu(expanded, record){
if(expanded){
if (expanded && (!record.children || record.children.length === 0)) {
getSystemSubmenu({parentId:record.id}).then((res) => {
if (res.success) {
record.children = res.result
}
})
}
},
// 根据已展开的行查询数据用于保存后刷新时异步加载子级的数据
loadDataByExpandedRows(dataList) {
if (this.expandedRowKeys.length > 0) {
return getSystemSubmenuBatch({ parentIds: this.expandedRowKeys.join(',') }).then((res) => {
if (res.success) {
let childrenMap = res.result
let fn = (list) => {
list.forEach(data => {
if (this.expandedRowKeys.includes(data.id)) {
data.children = childrenMap[data.id]
fn(data.children)
}
})
}
fn(dataList)
}
})
} else {
return Promise.resolve()
}
},
// 打开数据规则编辑
handleDataRule(record) {
@ -189,10 +215,13 @@
this.$refs.modalForm.localMenuType = 1;
this.$refs.modalForm.disableSubmit = false;
this.$refs.modalForm.edit({status:'1',permsType:'1',route:true,'parentId':record.id});
}
},
handleExpandedRowsChange(expandedRows) {
this.expandedRowKeys = expandedRows
},
}
}
</script>
<style scoped>
@import '~@assets/less/common.less'
@import '~@assets/less/common.less';
</style>

View File

@ -28,7 +28,9 @@
:pagination="false"
:dataSource="dataSource"
:loading="loading"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}">
:expandedRowKeys="expandedRowKeys"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@expandedRowsChange="handleExpandedRowsChange">
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
@ -152,6 +154,8 @@
// 表头
columns: columns,
loading: false,
// 展开的行受控属性
expandedRowKeys: [],
url: {
list: '/sys/permission/list',
delete: '/sys/permission/delete',
@ -178,10 +182,13 @@
this.$refs.modalForm.localMenuType = 1;
this.$refs.modalForm.disableSubmit = false;
this.$refs.modalForm.edit({status:'1',permsType:'1',route:true,'parentId':record.id});
}
},
handleExpandedRowsChange(expandedRows) {
this.expandedRowKeys = expandedRows
},
}
}
</script>
<style scoped>
@import '~@assets/less/common.less'
@import '~@assets/less/common.less';
</style>

View File

@ -67,8 +67,8 @@
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical" />
<a-dropdown>
<a class="ant-dropdown-link">
更多 <a-icon type="down" />

View File

@ -60,26 +60,27 @@
:rowSelection="{selectedRowKeys: selectedRowKeys1, onChange: onSelectChange1, type:'radio'}"
@change="handleTableChange">
<span slot="action" slot-scope="text, record">
<a @click="handleOpen(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 @click="handlePerssion(record.id)">授权</a>
</a-menu-item>
<a-menu-item>
<a @click="handleEdit(record)">编辑</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete1(record.id)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
<a @click="handleOpen(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 @click="handlePerssion(record.id)">授权</a>
</a-menu-item>
<a-menu-item>
<a @click="handleEdit(record)">编辑</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete1(record.id)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
</a-table>
</div>
@ -530,7 +531,7 @@
},
handlePerssion(roleId){
this.$refs.modalUserRole.show(roleId);
}
},
}
}
</script>

View File

@ -0,0 +1,178 @@
<template>
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :md="6" :sm="8">
<a-form-item label="规则名称">
<a-input placeholder="请输入规则名称" v-model="queryParam.ruleName"/>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<a-form-item label="规则Code">
<a-input placeholder="请输入规则Code" v-model="queryParam.ruleCode"/>
</a-form-item>
</a-col>
<template v-if="toggleSearchStatus">
</template>
<a-col :md="6" :sm="8">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
<a @click="handleToggleSearch" style="margin-left: 8px">
{{ toggleSearchStatus ? '收起' : '展开' }}
<a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
</a>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!-- 操作按钮区域 -->
<div class="table-operator">
<a-button @click="handleAdd" type="primary" icon="plus">新增</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>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel">
<a-icon type="delete"/>
删除
</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作
<a-icon type="down"/>
</a-button>
</a-dropdown>
</div>
<!-- table区域-begin -->
<a-alert type="info" showIcon style="margin-bottom: 16px;">
<template slot="message">
<span>已选择</span>
<a style="font-weight: 600;padding: 0 4px;">{{ selectedRowKeys.length }}</a>
<span></span>
<template v-if="selectedRowKeys.length>0">
<a-divider type="vertical"/>
<a @click="onClearSelected">清空</a>
</template>
</template>
</a-alert>
<a-table
ref="table"
size="middle"
bordered
rowKey="id"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@change="handleTableChange">
<template slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical"/>
<a @click="handleTest(record)">功能测试</a>
<a-divider type="vertical"/>
<a-dropdown>
<a class="ant-dropdown-link">
<span>更多</span>
<a-icon type="down"/>
</a>
<a-menu slot="overlay">
<a-menu-item>
<a-popconfirm title="确定删除吗?" @confirm="handleDelete(record.id)">删除</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
</a-table>
<!-- table区域-end -->
<!-- 表单区域 -->
<sys-check-rule-modal ref="modalForm" @ok="modalFormOk"/>
<sys-check-rule-test-modal ref="testModal"/>
</a-card>
</template>
<script>
import JEllipsis from '@/components/jeecg/JEllipsis'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import SysCheckRuleModal from './modules/SysCheckRuleModal'
import SysCheckRuleTestModal from './modules/SysCheckRuleTestModal'
export default {
name: 'SysCheckRuleList',
mixins: [JeecgListMixin],
components: { SysCheckRuleModal, SysCheckRuleTestModal, JEllipsis },
data() {
return {
description: '编码校验规则管理页面',
// 表头
columns: [
{
title: '#',
key: 'rowIndex',
width: 60,
align: 'center',
customRender: (t, r, i) => i + 1
},
{
title: '规则名称',
align: 'center',
dataIndex: 'ruleName'
},
{
title: '规则Code',
align: 'center',
dataIndex: 'ruleCode'
},
{
title: '规则描述',
align: 'center',
dataIndex: 'ruleDescription',
customRender: (t) => (<j-ellipsis value={t} length={48}/>)
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
scopedSlots: { customRender: 'action' },
}
],
url: {
list: '/sys/checkRule/list',
delete: '/sys/checkRule/delete',
deleteBatch: '/sys/checkRule/deleteBatch',
exportXlsUrl: 'sys/checkRule/exportXls',
importExcelUrl: 'sys/checkRule/importExcel',
},
}
},
computed: {
importExcelUrl: function () {
return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
}
},
methods: {
handleTest(record) {
this.$refs.testModal.open(record.ruleCode)
}
}
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>

View File

@ -0,0 +1,194 @@
<template>
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :md="6" :sm="8">
<a-form-item label="数据源名称">
<a-input placeholder="请输入数据源名称" v-model="queryParam.name"/>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<a-form-item label="数据库类型">
<j-dict-select-tag v-model="queryParam.dbType" placeholder="请选择数据库类型" dict-code="database_type"/>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!-- 操作按钮区域 -->
<div class="table-operator">
<a-button @click="handleAdd" type="primary" icon="plus">新增</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>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel">
<a-icon type="delete"/>
删除
</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作
<a-icon type="down"/>
</a-button>
</a-dropdown>
</div>
<!-- table区域-begin -->
<div>
<a-alert type="info" showIcon style="margin-bottom: 16px;">
<template slot="message">
<span>已选择</span>
<a style="font-weight: 600;padding: 0 4px;">{{ selectedRowKeys.length }}</a>
<span></span>
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
</template>
</a-alert>
<a-table
ref="table"
size="middle"
bordered
rowKey="id"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@change="handleTableChange">
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(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>删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
</a-table>
</div>
<!-- table区域-end -->
<!-- 表单区域 -->
<sys-data-source-modal ref="modalForm" @ok="modalFormOk"/>
</a-card>
</template>
<script>
import JEllipsis from '@/components/jeecg/JEllipsis'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import SysDataSourceModal from './modules/SysDataSourceModal'
export default {
name: 'SysDataSourceList',
mixins: [JeecgListMixin],
components: { JEllipsis, SysDataSourceModal },
data() {
let ellipsis = (v, l = 20) => (<j-ellipsis value={v} length={l}/>)
return {
description: '多数据源管理管理页面',
// 表头
columns: [
{
title: '#',
dataIndex: '',
key: 'rowIndex',
width: 60,
align: 'center',
customRender: (t, r, index) => index + 1
},
{
title: '数据源名称',
align: 'center',
dataIndex: 'name'
},
{
title: '数据源编码',
align: 'center',
dataIndex: 'code'
},
{
title: '备注',
align: 'center',
dataIndex: 'remark',
customRender: (t) => ellipsis(t)
},
{
title: '数据库类型',
align: 'center',
dataIndex: 'dbType_dictText'
},
{
title: '驱动类',
align: 'center',
dataIndex: 'dbDriver',
customRender: (t) => ellipsis(t)
},
{
title: '数据源地址',
align: 'center',
dataIndex: 'dbUrl',
customRender: (t) => ellipsis(t)
},
{
title: '数据库名称',
align: 'center',
dataIndex: 'dbName'
},
{
title: '用户名',
align: 'center',
dataIndex: 'dbUsername'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
scopedSlots: { customRender: 'action' },
}
],
url: {
list: '/sys/dataSource/list',
delete: '/sys/dataSource/delete',
deleteBatch: '/sys/dataSource/deleteBatch',
exportXlsUrl: 'sys/dataSource/exportXls',
importExcelUrl: 'sys/dataSource/importExcel',
},
}
},
computed: {
importExcelUrl() {
return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
}
},
methods: {}
}
</script>
<style scoped>
@import '~@assets/less/common.less';
</style>

View File

@ -46,6 +46,7 @@
</span>
</a-table>
<show-announcement ref="ShowAnnouncement"></show-announcement>
<dynamic-notice ref="showDynamNotice" :path="openPath" :formData="formData"/>
</a-card>
</template>
@ -54,11 +55,13 @@
import { getAction,putAction } from '@/api/manage'
import ShowAnnouncement from '@/components/tools/ShowAnnouncement'
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import DynamicNotice from '../../components/tools/DynamicNotice'
export default {
name: "UserAnnouncementList",
mixins: [JeecgListMixin],
components: {
DynamicNotice,
ShowAnnouncement
},
data () {
@ -130,6 +133,7 @@
readAllMsg:"sys/sysAnnouncementSend/readAll",
},
loading:false,
openPath:''
}
},
methods: {
@ -143,7 +147,13 @@
this.loadData();
}
});
this.$refs.ShowAnnouncement.detail(record);
if(record.openType==='component'){
this.openPath = record.openPage;
this.formData = {id:record.busId};
this.$refs.showDynamNotice.detail();
}else{
this.$refs.ShowAnnouncement.detail(record);
}
},
readAll(){
var that = this;

View File

@ -66,10 +66,12 @@
<!-- 操作按钮区域 -->
<div class="table-operator" style="border-top: 5px">
<a-button @click="handleAdd" type="primary" icon="plus">添加用户</a-button>
<a-button @click="handleSyncUser" v-has="'user:syncbpm'" type="primary" icon="plus">同步流程</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>
<a-button type="primary" icon="hdd" @click="recycleBinVisible=true">回收站</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay" @click="handleMenuClick">
<a-menu-item key="1">
@ -171,17 +173,22 @@
<password-modal ref="passwordmodal" @ok="passwordModalOk"></password-modal>
<sys-user-agent-modal ref="sysUserAgentModal"></sys-user-agent-modal>
<!-- 用户回收站 -->
<user-recycle-bin-modal :visible.sync="recycleBinVisible" @ok="modalFormOk"/>
</a-card>
</template>
<script>
import UserModal from './modules/UserModal'
import PasswordModal from './modules/PasswordModal'
import {putAction} from '@/api/manage';
import {putAction,getFileAccessHttpUrl} from '@/api/manage';
import {frozenBatch} from '@/api/api'
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import SysUserAgentModal from "./modules/SysUserAgentModal";
import JInput from '@/components/jeecg/JInput'
import UserRecycleBinModal from './modules/UserRecycleBinModal'
export default {
name: "UserList",
@ -190,12 +197,14 @@
SysUserAgentModal,
UserModal,
PasswordModal,
JInput
JInput,
UserRecycleBinModal
},
data() {
return {
description: '这是用户管理页面',
queryParam: {},
recycleBinVisible: false,
columns: [
/*{
title: '#',
@ -214,7 +223,7 @@
width: 120
},
{
title: '真实姓名',
title: '用户姓名',
align: "center",
width: 100,
dataIndex: 'realname',
@ -237,7 +246,7 @@
{
title: '生日',
align: "center",
width: 180,
width: 100,
dataIndex: 'birthday'
},
{
@ -247,9 +256,10 @@
dataIndex: 'phone'
},
{
title: '邮箱',
title: '部门',
align: "center",
dataIndex: 'email'
width: 180,
dataIndex: 'orgCode'
},
{
title: '状态',
@ -257,13 +267,6 @@
width: 80,
dataIndex: 'status_dictText'
},
/* {
title: '创建时间',
align: "center",
width: 150,
dataIndex: 'createTime',
sorter: true
},*/
{
title: '操作',
dataIndex: 'action',
@ -274,7 +277,7 @@
],
url: {
imgerver: window._CONFIG['domianURL'] + "/sys/common/view",
imgerver: window._CONFIG['staticDomainURL'],
syncUser: "/process/extActProcess/doSyncUser",
list: "/sys/user/list",
delete: "/sys/user/delete",
@ -291,7 +294,7 @@
},
methods: {
getAvatarView: function (avatar) {
return this.url.imgerver + "/" + avatar;
return getFileAccessHttpUrl(avatar,this.url.imgerver,"http")
},
batchFrozen: function (status) {
@ -363,6 +366,8 @@
this.$refs.sysUserAgentModal.agentSettings(username);
this.$refs.sysUserAgentModal.title = "用户代理人设置";
},
handleSyncUser() {
},
passwordModalOk() {
//TODO 密码修改完成 不需要刷新页面可以把datasource中的数据更新一下
}
@ -372,4 +377,4 @@
</script>
<style scoped>
@import '~@assets/less/common.less'
</style>
</style>

View File

@ -1,7 +1,7 @@
<template>
<a-card :loading="cardLoading" :bordered="false" style="height: 100%;">
<a-spin :spinning="loading">
<a-input-search @search="handleSearch" style="width:100%;margin-top: 10px" placeholder="输入组织机构名称进行查询..."/>
<a-input-search @search="handleSearch" style="width:100%;margin-top: 10px" placeholder="输入机构名称查询..." allowClear enterButton />
<a-tree
showLine
@ -67,20 +67,21 @@
promise.then(res => {
if (res.success) {
this.treeDataSource = res.result
// update-begin- --- author:wangshuai ------ date:20200102 ---- for:去除默认选中第一条数据默认展开所有第一级
// 默认选中第一条数据默认展开所有第一级
if (res.result.length > 0) {
this.expandedKeys = []
res.result.forEach((item, index) => {
if (index === 0) {
this.selectedKeys = [item.id]
this.emitInput(item.orgCode)
}
this.expandedKeys.push(item.id)
})
}
// if (res.result.length > 0) {
// this.expandedKeys = []
// res.result.forEach((item, index) => {
// if (index === 0) {
// this.selectedKeys = [item.id]
// this.emitInput(item.orgCode)
// }
// this.expandedKeys.push(item.id)
// })
// }
// update-end- --- author:wangshuai ------ date:20200102 ---- for:去除默认选中第一条数据默认展开所有第一级
} else {
this.$message.warn('组织机构查询失败' + res.message)
this.$message.warn(res.message)
console.error('组织机构查询失败:', res)
}
}).finally(() => {

View File

@ -65,12 +65,6 @@
align: 'center',
customRender: (t, r, i) => parseInt(i) + 1
},
{
title: '部门',
width: '20%',
align: 'center',
dataIndex: 'departName'
},
{
title: '姓名',
width: '15%',
@ -83,6 +77,12 @@
align: 'center',
dataIndex: 'workNo'
},
{
title: '部门',
width: '20%',
align: 'center',
dataIndex: 'departName'
},
{
title: '职务',
width: '15%',
@ -91,7 +91,7 @@
customRender: (text) => (text || '').split(',').map(t => this.positionInfo[t] ? this.positionInfo[t] : t).join(',')
},
{
title: '',
title: '',
width: '15%',
align: 'center',
dataIndex: 'telephone'
@ -130,14 +130,26 @@
methods: {
loadData(pageNum, orgCode) {
if (!orgCode) {
return
}
//加载数据 若传入参数1则加载第一页的内容
if (pageNum === 1) {
this.ipagination.current = 1
}
this.loading = true
if (pageNum === 1) {
this.ipagination.current = 1
}
// update-begin- --- author:wangshuai ------ date:20200102 ---- for:传过来的部门编码为空全查
if (!orgCode) {
getAction(this.url.list, {
...this.getQueryParams()
}).then((res) => {
if (res.success) {
this.dataSource = res.result.records
this.ipagination.total = res.result.total
}
}).finally(() => {
this.loading = false
this.cardLoading = false
})
// update-end- --- author:wangshuai ------ date:20200102 ---- for:传过来的部门编码为空全查
}else{
//加载数据 若传入参数1则加载第一页的内容
getAction(this.url.list, {
orgCode,
...this.getQueryParams()
@ -150,6 +162,7 @@
this.loading = false
this.cardLoading = false
})
}
},
searchQuery() {

View File

@ -0,0 +1,184 @@
<template>
<a-card :bordered="false">
<template v-if="this.departId">
<a-form>
<a-form-item label='所拥有的权限'>
<a-tree
checkable
@check="onCheck"
:checkedKeys="checkedKeys"
:treeData="treeData"
@expand="onExpand"
@select="onTreeNodeSelect"
:selectedKeys="selectedKeys"
:expandedKeys="expandedKeysss"
:checkStrictly="checkStrictly"
style="height:500px;overflow: auto;">
<span slot="hasDatarule" slot-scope="{slotTitle,ruleFlag}">
{{ slotTitle }}
<a-icon v-if="ruleFlag" type="align-left" style="margin-left:5px;color: red;"></a-icon>
</span>
</a-tree>
</a-form-item>
</a-form>
<div class="anty-form-btn">
<a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
<a-menu slot="overlay">
<!-- 简化Tree逻辑使用默认checkStrictly为false的行为即默认父子关联
<a-menu-item key="1" @click="switchCheckStrictly(1)">父子关联</a-menu-item>
<a-menu-item key="2" @click="switchCheckStrictly(2)">取消关联</a-menu-item>
-->
<a-menu-item key="3" @click="checkALL">全部勾选</a-menu-item>
<a-menu-item key="4" @click="cancelCheckALL">取消全选</a-menu-item>
<a-menu-item key="5" @click="expandAll">展开所有</a-menu-item>
<a-menu-item key="6" @click="closeAll">合并所有</a-menu-item>
</a-menu>
<a-button>
树操作 <a-icon type="up" />
</a-button>
</a-dropdown>
<a-button style="float: right" @click="handleSubmit" type="primary" htmlType="button" icon="form">保存</a-button>
</div>
</template>
<div v-else style="height:330px;"><h3>请先选择一个部门!</h3></div>
<depart-datarule-modal ref="datarule"/>
</a-card>
</template>
<script>
import {queryTreeListForRole,queryDepartPermission,saveDepartPermission} from '@/api/api'
import DepartDataruleModal from './DepartDataruleModal'
export default {
name: 'DepartAuthModal',
components: { DepartDataruleModal },
data(){
return {
departId:"",
treeData: [],
defaultCheckedKeys:[],
checkedKeys:[],
halfCheckedKeys:[],
expandedKeysss:[],
allTreeKeys:[],
autoExpandParent: true,
checkStrictly: false,
title:"部门权限配置",
visible: false,
loading: false,
selectedKeys:[]
}
},
methods: {
onTreeNodeSelect(id){
if(id && id.length>0){
this.selectedKeys = id
}
this.$refs.datarule.show(this.selectedKeys[0],this.departId)
},
onCheck (checkedKeys, { halfCheckedKeys }) {
// 保存选中的和半选中的后面保存的时候合并提交
this.checkedKeys = checkedKeys
this.halfCheckedKeys = halfCheckedKeys
},
show(departId){
this.departId=departId
this.loadData();
},
close () {
this.reset()
this.$emit('close');
this.visible = false;
},
onExpand(expandedKeys){
this.expandedKeysss = expandedKeys;
this.autoExpandParent = false
},
reset () {
this.expandedKeysss = []
this.checkedKeys = []
this.defaultCheckedKeys = []
this.loading = false
},
expandAll () {
this.expandedKeysss = this.allTreeKeys
},
closeAll () {
this.expandedKeysss = []
},
checkALL () {
this.checkedKeys = this.allTreeKeys
},
cancelCheckALL () {
this.checkedKeys = []
},
handleCancel () {
this.close()
},
handleSubmit() {
let that = this;
if(!that.departId){
this.$message.warning('请点击选择一个部门!')
}
let checkedKeys = [...that.checkedKeys, ...that.halfCheckedKeys]
const permissionIds = checkedKeys.join(",")
let params = {
departId:that.departId,
permissionIds,
lastpermissionIds:that.defaultCheckedKeys.join(","),
};
that.loading = true;
saveDepartPermission(params).then((res)=>{
if(res.success){
that.$message.success(res.message);
that.loading = false;
that.loadData();
}else {
that.$message.error(res.message);
that.loading = false;
}
})
},
convertTreeListToKeyLeafPairs(treeList, keyLeafPair = []) {
for(const {key, isLeaf, children} of treeList) {
keyLeafPair.push({key, isLeaf})
if(children && children.length > 0) {
this.convertTreeListToKeyLeafPairs(children, keyLeafPair)
}
}
return keyLeafPair;
},
emptyCurrForm() {
this.form.resetFields()
},
loadData(){
queryTreeListForRole().then((res) => {
this.treeData = res.result.treeList
this.allTreeKeys = res.result.ids
const keyLeafPairs = this.convertTreeListToKeyLeafPairs(this.treeData)
queryDepartPermission({departId:this.departId}).then((res)=>{
// 过滤出 leaf node 即可即选中的
// Tree组件中checkStrictly默认为false的时候选中子节点父节点会自动设置选中或半选中
// 保存 checkedKeys 以及 halfCheckedKeys 以便于未做任何操作时提交表单数据
const checkedKeys = [...res.result].filter(key => {
const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
return keyLeafPair && keyLeafPair.isLeaf
})
const halfCheckedKeys = [...res.result].filter(key => {
const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
return keyLeafPair && !keyLeafPair.isLeaf
})
this.checkedKeys = [...checkedKeys];
this.halfCheckedKeys = [...halfCheckedKeys]
this.defaultCheckedKeys = [...halfCheckedKeys, ...checkedKeys];
this.expandedKeysss = this.allTreeKeys;
})
})
}
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,116 @@
<template>
<a-drawer
title="数据规则/按钮权限配置"
width="365"
:closable="false"
@close="onClose"
:visible="visible"
>
<a-tabs defaultActiveKey="1">
<a-tab-pane tab="数据规则" key="1">
<a-checkbox-group v-model="dataruleChecked" v-if="dataruleList.length>0">
<a-row>
<a-col :span="24" v-for="(item,index) in dataruleList" :key=" 'dr'+index ">
<a-checkbox :value="item.id">{{ item.ruleName }}</a-checkbox>
</a-col>
<a-col :span="24">
<div style="width: 100%;margin-top: 15px">
<a-button @click="saveDataruleForRole" type="primary" size="small" icon="save">点击保存</a-button>
</div>
</a-col>
</a-row>
</a-checkbox-group>
<div v-else><h3>无配置信息!</h3></div>
</a-tab-pane>
</a-tabs>
</a-drawer>
</template>
<script>
import ARow from 'ant-design-vue/es/grid/Row'
import ACol from 'ant-design-vue/es/grid/Col'
import { getAction,postAction } from '@/api/manage'
export default {
name: 'DepartDataruleModal',
components: { ACol, ARow },
data(){
return {
functionId:'',
departId:'',
visible:false,
tabList: [{
key: '1',
tab: '数据规则',
}, {
key: '2',
tab: '按钮权限',
}],
activeTabKey: '1',
url:{
datarule:"/sys/sysDepartPermission/datarule",
},
dataruleList:[],
dataruleChecked:[]
}
},
methods:{
loadData(){
getAction(`${this.url.datarule}/${this.functionId}/${this.departId}`).then(res=>{
if(res.success){
this.dataruleList = res.result.datarule
let drChecked = res.result.drChecked
if(drChecked){
this.dataruleChecked = drChecked.split(",")
}
}
})
},
saveDataruleForRole(){
if(!this.dataruleChecked || this.dataruleChecked.length==0){
this.$message.warning("请注意,现未勾选任何数据权限!")
}
let params = {
permissionId:this.functionId,
departId:this.departId,
dataRuleIds:this.dataruleChecked.join(",")
}
postAction(this.url.datarule,params).then(res=>{
if(res.success){
this.$message.success(res.message)
}else{
this.$message.error(res.message)
}
})
},
show(functionId,departId){
this.onReset()
this.functionId = functionId
this.departId = departId
this.visible=true
this.loadData()
},
onClose(){
this.visible=false
this.onReset()
},
onTabChange (key) {
this.activeTabKey = key
},
onReset(){
this.functionId=''
this.departId=''
this.dataruleList=[]
this.dataruleChecked=[]
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,217 @@
<template>
<a-drawer
:title="title"
:maskClosable="true"
width=650
placement="right"
:closable="true"
@close="close"
:visible="visible"
style="height: calc(100% - 55px);overflow: auto;padding-bottom: 53px;">
<a-form>
<a-form-item label='所拥有的部门权限'>
<a-tree
v-if="treeData.length>0"
checkable
@check="onCheck"
:checkedKeys="checkedKeys"
:treeData="treeData"
@expand="onExpand"
@select="onTreeNodeSelect"
:selectedKeys="selectedKeys"
:expandedKeys="expandedKeysss"
:checkStrictly="checkStrictly">
<span slot="hasDatarule" slot-scope="{slotTitle,ruleFlag}">
{{ slotTitle }}<a-icon v-if="ruleFlag" type="align-left" style="margin-left:5px;color: red;"></a-icon>
</span>
</a-tree>
<div v-else><h3>无可配置部门权限!</h3></div>
</a-form-item>
</a-form>
<div class="drawer-bootom-button">
<a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
<a-menu slot="overlay">
<a-menu-item key="3" @click="checkALL">全部勾选</a-menu-item>
<a-menu-item key="4" @click="cancelCheckALL">取消全选</a-menu-item>
<a-menu-item key="5" @click="expandAll">展开所有</a-menu-item>
<a-menu-item key="6" @click="closeAll">合并所有</a-menu-item>
</a-menu>
<a-button>
树操作 <a-icon type="up" />
</a-button>
</a-dropdown>
<a-popconfirm title="确定放弃编辑?" @confirm="close" okText="确定" cancelText="取消">
<a-button style="margin-right: .8rem">取消</a-button>
</a-popconfirm>
<a-button @click="handleSubmit(false)" type="primary" :loading="loading" ghost style="margin-right: 0.8rem">仅保存</a-button>
<a-button @click="handleSubmit(true)" type="primary" :loading="loading">保存并关闭</a-button>
</div>
<dept-role-datarule-modal ref="datarule"></dept-role-datarule-modal>
</a-drawer>
</template>
<script>
import {queryTreeListForDeptRole,queryDeptRolePermission,saveDeptRolePermission} from '@/api/api'
import RoleDataruleModal from './RoleDataruleModal.vue'
import DeptRoleDataruleModal from './DeptRoleDataruleModal'
export default {
name: "DeptRoleAuthModal",
components:{
DeptRoleDataruleModal,
RoleDataruleModal
},
data(){
return {
departId:"",
roleId:"",
treeData: [],
defaultCheckedKeys:[],
checkedKeys:[],
halfCheckedKeys:[],
expandedKeysss:[],
allTreeKeys:[],
autoExpandParent: true,
checkStrictly: false,
title:"部门角色权限配置",
visible: false,
loading: false,
selectedKeys:[]
}
},
methods: {
onTreeNodeSelect(id){
if(id && id.length>0){
this.selectedKeys = id
}
this.$refs.datarule.show(this.selectedKeys[0],this.departId,this.roleId)
},
onCheck (checkedKeys, { halfCheckedKeys }) {
// 保存选中的和半选中的后面保存的时候合并提交
this.checkedKeys = checkedKeys
this.halfCheckedKeys = halfCheckedKeys
},
show(roleId,departId){
this.departId = departId
this.roleId=roleId
this.visible = true;
},
close () {
this.reset()
this.$emit('close');
this.visible = false;
},
onExpand(expandedKeys){
this.expandedKeysss = expandedKeys;
this.autoExpandParent = false
},
reset () {
this.expandedKeysss = []
this.checkedKeys = []
this.defaultCheckedKeys = []
this.loading = false
},
expandAll () {
this.expandedKeysss = this.allTreeKeys
},
closeAll () {
this.expandedKeysss = []
},
checkALL () {
this.checkedKeys = this.allTreeKeys
},
cancelCheckALL () {
this.checkedKeys = []
},
handleCancel () {
this.close()
},
handleSubmit(exit) {
let that = this;
let checkedKeys = [...that.checkedKeys, ...that.halfCheckedKeys]
const permissionIds = checkedKeys.join(",")
let params = {
roleId:that.roleId,
permissionIds,
lastpermissionIds:that.defaultCheckedKeys.join(","),
};
that.loading = true;
console.log("请求参数:",params);
saveDeptRolePermission(params).then((res)=>{
if(res.success){
that.$message.success(res.message);
that.loading = false;
if (exit) {
that.close()
}
}else {
that.$message.error(res.message);
that.loading = false;
if (exit) {
that.close()
}
}
this.loadData();
})
},
convertTreeListToKeyLeafPairs(treeList, keyLeafPair = []) {
for(const {key, isLeaf, children} of treeList) {
keyLeafPair.push({key, isLeaf})
if(children && children.length > 0) {
this.convertTreeListToKeyLeafPairs(children, keyLeafPair)
}
}
return keyLeafPair;
},
loadData(){
queryTreeListForDeptRole({departId:this.departId}).then((res) => {
this.treeData = res.result.treeList
this.allTreeKeys = res.result.ids
const keyLeafPairs = this.convertTreeListToKeyLeafPairs(this.treeData)
queryDeptRolePermission({roleId:this.roleId}).then((res)=>{
// 过滤出 leaf node 即可即选中的
// Tree组件中checkStrictly默认为false的时候选中子节点父节点会自动设置选中或半选中
// 保存 checkedKeys 以及 halfCheckedKeys 以便于未做任何操作时提交表单数据
const checkedKeys = [...res.result].filter(key => {
const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
return keyLeafPair && keyLeafPair.isLeaf
})
const halfCheckedKeys = [...res.result].filter(key => {
const keyLeafPair = keyLeafPairs.filter(item => item.key === key)[0]
return keyLeafPair && !keyLeafPair.isLeaf
})
this.checkedKeys = [...checkedKeys];
this.halfCheckedKeys = [...halfCheckedKeys]
this.defaultCheckedKeys = [...halfCheckedKeys, ...checkedKeys];
this.expandedKeysss = this.allTreeKeys;
})
})
}
},
watch: {
visible () {
if (this.visible ) {
this.loadData();
}
}
}
}
</script>
<style lang="scss" scoped>
.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>

View File

@ -0,0 +1,122 @@
<template>
<a-drawer
title="数据规则/按钮权限配置"
width="365"
:closable="false"
@close="onClose"
:visible="visible"
>
<a-tabs defaultActiveKey="1">
<a-tab-pane tab="数据规则" key="1">
<a-checkbox-group v-model="dataruleChecked" v-if="dataruleList.length>0">
<a-row>
<a-col :span="24" v-for="(item,index) in dataruleList" :key=" 'dr'+index ">
<a-checkbox :value="item.id">{{ item.ruleName }}</a-checkbox>
</a-col>
<a-col :span="24">
<div style="width: 100%;margin-top: 15px">
<a-button @click="saveDataruleForRole" type="primary" size="small" icon="save">点击保存</a-button>
</div>
</a-col>
</a-row>
</a-checkbox-group>
<div v-else><h3>无配置信息!</h3></div>
</a-tab-pane>
<!--<a-tab-pane tab="按钮权限" key="2">敬请期待!!!</a-tab-pane>-->
</a-tabs>
</a-drawer>
</template>
<script>
import ARow from 'ant-design-vue/es/grid/Row'
import ACol from 'ant-design-vue/es/grid/Col'
import { getAction,postAction } from '@/api/manage'
export default {
name: 'DeptRoleDataruleModal',
components: { ACol, ARow },
data(){
return {
departId:'',
functionId:'',
roleId:'',
visible:false,
tabList: [{
key: '1',
tab: '数据规则',
}, {
key: '2',
tab: '按钮权限',
}],
activeTabKey: '1',
url:{
datarule:"/sys/sysDepartRole/datarule",
},
dataruleList:[],
dataruleChecked:[]
}
},
methods:{
loadData(){
getAction(`${this.url.datarule}/${this.functionId}/${this.departId}/${this.roleId}`).then(res=>{
console.log(res)
if(res.success){
this.dataruleList = res.result.datarule
let drChecked = res.result.drChecked
if(drChecked){
this.dataruleChecked = drChecked.split(",")
}
}
})
},
saveDataruleForRole(){
if(!this.dataruleChecked || this.dataruleChecked.length==0){
this.$message.warning("请注意,现未勾选任何数据权限!")
}
let params = {
permissionId:this.functionId,
roleId:this.roleId,
dataRuleIds:this.dataruleChecked.join(",")
}
console.log("保存数据权限",params)
postAction(this.url.datarule,params).then(res=>{
if(res.success){
this.$message.success(res.message)
}else{
this.$message.error(res.message)
}
})
},
show(functionId,departId,roleId){
this.onReset()
this.departId = departId
this.functionId = functionId
this.roleId = roleId
this.visible=true
this.loadData()
},
onClose(){
this.visible=false
this.onReset()
},
onTabChange (key) {
this.activeTabKey = key
},
onReset(){
this.functionId=''
this.roleId=''
this.dataruleList=[]
this.dataruleChecked=[]
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,196 @@
<template>
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<!-- 搜索区域 -->
<a-form layout="inline">
<a-row :gutter="10">
<a-col :md="10" :sm="12">
<a-form-item label="部门角色名称" style="margin-left:8px">
<a-input placeholder="请输入部门角色" v-model="queryParam.roleName"></a-input>
</a-form-item>
</a-col>
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-col :md="6" :sm="24">
<a-button type="primary" @click="searchQuery" icon="search" style="margin-left: 18px">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
</a-col>
</span>
</a-row>
</a-form>
</div>
<!-- 操作按钮区域 -->
<div class="table-operator" :md="24" :sm="24">
<a-button @click="handleAdd" type="primary" icon="plus">部门角色录入</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button>
</a-dropdown>
</div>
<!-- table区域-begin -->
<div>
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
<i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">
{{selectedRowKeys.length }}</a>
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
</div>
<a-table
ref="table"
size="middle"
bordered
rowKey="id"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@change="handleTableChange">
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(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>删除</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a href="javascript:;" @click="handleDetail(record)">详情</a>
</a-menu-item>
<a-menu-item>
<a @click="handlePerssion(record)">授权</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
</a-table>
</div>
<!-- table区域-end -->
<!-- 表单区域 -->
<sys-depart-role-modal ref="modalForm" @ok="modalFormOk"/>
<dept-role-auth-modal ref="modalDeptRole" />
</a-card>
</template>
<script>
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import {getAction} from '@/api/manage'
import SysDepartRoleModal from './SysDepartRoleModal'
import DeptRoleAuthModal from './DeptRoleAuthModal'
export default {
name: 'DeptRoleInfo',
components: { DeptRoleAuthModal, SysDepartRoleModal },
mixins: [JeecgListMixin],
data() {
return {
description: '部门角色信息',
currentDeptId: '',
// 表头
columns: [{
title: '部门角色名称',
align: "center",
dataIndex: 'roleName'
},
{
title: '部门角色编码',
align: "center",
dataIndex: 'roleCode'
},
{
title: '部门',
align: "center",
dataIndex: 'departId_dictText'
},
{
title: '备注',
align: "center",
dataIndex: 'description'
},
{
title: '操作',
dataIndex: 'action',
scopedSlots: {customRender: 'action'},
align: "center",
width: 170
}],
url: {
list: "/sys/sysDepartRole/list",
delete: "/sys/sysDepartRole/delete",
deleteBatch: "/sys/sysDepartRole/deleteBatch",
}
}
},
created() {
},
methods: {
searchReset() {
this.queryParam = {}
this.currentDeptId = '';
this.loadData(1);
this.$emit('clearSelectedDepartKeys')
},
loadData(arg) {
if (!this.url.list) {
this.$message.error("请设置url.list属性!")
return
}
//加载数据 若传入参数1则加载第一页的内容
if (arg === 1) {
this.ipagination.current = 1;
}
let params = this.getQueryParams();//查询条件
params.deptId = this.currentDeptId;
getAction(this.url.list, params).then((res) => {
if (res.success && res.result) {
this.dataSource = res.result.records;
this.ipagination.total = res.result.total;
}
})
},
open(record) {
this.currentDeptId = record.id;
this.loadData(1);
},
clearList() {
this.currentDeptId = '';
this.dataSource = [];
},
hasSelectDept() {
if (this.currentDeptId == '') {
this.$message.error("请选择一个部门!")
return false;
}
return true;
},
handleEdit: function (record) {
this.$refs.modalForm.title = "编辑";
this.$refs.modalForm.departDisabled = true;
this.$refs.modalForm.disableSubmit = false;
this.$refs.modalForm.edit(record,record.departId);
},
handleAdd: function () {
if (this.currentDeptId == '') {
this.$message.error("请选择一个部门!")
} else {
this.$refs.modalForm.departDisabled = true;
this.$refs.modalForm.add(this.currentDeptId);
this.$refs.modalForm.title = "新增";
}
},
handlePerssion: function(record){
this.$refs.modalDeptRole.show(record.id,record.departId);
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,200 @@
<template>
<a-drawer
:title="title"
:maskClosable="true"
width=600
placement="right"
:closable="true"
@close="close"
:visible="visible"
style="height: calc(100% - 55px);overflow: auto;padding-bottom: 53px;">
<a-spin :spinning="confirmLoading">
<a-form :form="form" v-if="designNameOption.length>0">
<a-form-item label=''>
<a-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
<a-card :style="{ marginTop: '12px',height:'auto' }">
<a-checkbox-group @change="designNameChange" v-model="designNameValue" style="width: 100%">
<a-row>
<template v-for="(des) in designNameOption">
<a-col :span="6">
<a-checkbox :value="des.value">{{ des.text }}</a-checkbox>
</a-col>
</template>
</a-row>
</a-checkbox-group>
</a-card>
</a-col>
</a-form-item>
</a-form>
<div v-else><h3>无可配置角色!</h3></div>
</a-spin>
<div class="drawer-bootom-button">
<a-dropdown style="float: left" :trigger="['click']" placement="topCenter">
<a-menu slot="overlay">
<a-menu-item key="1" @click="checkALL">全部勾选</a-menu-item>
<a-menu-item key="2" @click="cancelCheckALL">取消全选</a-menu-item>
</a-menu>
<a-button>
操作 <a-icon type="up" />
</a-button>
</a-dropdown>
<a-popconfirm title="确定放弃编辑?" @confirm="close" okText="确定" cancelText="取消">
<a-button style="margin-right: .8rem">取消</a-button>
</a-popconfirm>
<a-button @click="handleSubmit(true)" type="primary">保存</a-button>
</div>
</a-drawer>
</template>
<script>
import {httpAction, getAction} from '@/api/manage'
import JEllipsis from '@/components/jeecg/JEllipsis'
import {initDictOptions} from '@/components/dict/JDictSelectUtil'
export default {
name: 'DeptRoleUserModal',
components: {
JEllipsis
},
data() {
return {
currentDeptId:"",
title: "部门角色分配",
visible: false,
model: {},
labelCol: {
xs: {span: 24},
sm: {span: 5},
},
wrapperCol: {
xs: {span: 24},
sm: {span: 16},
},
confirmLoading: false,
form: this.$form.createForm(this),
validatorRules: {},
url: {
add: "/sys/sysDepartRole/deptRoleUserAdd",
getDeptRoleList:"/sys/sysDepartRole/getDeptRoleList",
getDeptRoleByUserId:"/sys/sysDepartRole/getDeptRoleByUserId"
},
designNameOption: [],
userId: "",
newRoleId:"",
oldRoleId:"",
designNameValue:[],
desformList: [],
}
},
created() {
},
methods: {
add(record,departId) {
this.userId = record.id;
this.currentDeptId = departId;
this.loadDesformList();
this.edit({});
},
edit(record) {
this.form.resetFields();
this.model = Object.assign({}, record);
this.visible = true;
getAction(this.url.getDeptRoleByUserId,{userId:this.userId}).then((res) => {
if (res.success) {
var designName = [];
for (let value of res.result) {
designName.push(value.droleId)
}
this.oldRoleId=designName.join(",");
this.designNameValue = designName;
this.newRoleId = designName.join(",");
}
});
},
close() {
this.$emit('close');
this.visible = false;
},
handleSubmit() {
const that = this;
// 触发表单验证
that.confirmLoading = true;
let httpurl = this.url.add;
let method = 'post';
let formData = Object.assign(this.model, {});
//时间格式化
formData.userId = this.userId;
formData.newRoleId=this.newRoleId;
formData.oldRoleId=this.oldRoleId;
httpAction(httpurl, formData, method).then((res) => {
if (res.success) {
that.$message.success(res.message);
that.$emit('reload');
that.$emit('ok');
} else {
that.$message.warning(res.message);
}
}).finally(() => {
that.confirmLoading = false;
that.close();
})
},
handleCancel() {
this.designNameOption=[];
this.designNameValue=[];
this.close()
},
designNameChange(selectedValue) {
this.newRoleId=selectedValue.join(",");
},
checkALL(){
var designName = [];
for (let value of this.desformList) {
designName.push(
value.id
)
}
this.designNameValue = designName;
this.newRoleId=designName.join(",");
},
cancelCheckALL(){
this.designNameValue=[];
this.newRoleId="";
},
/** 加载desform */
loadDesformList() {
getAction(this.url.getDeptRoleList, { departId: this.currentDeptId }).then((res) => {
if (res.success) {
this.desformList = res.result
var designName = [];
for (let value of this.desformList) {
designName.push({
value: value.id,
text: value.roleName,
})
}
this.designNameOption = designName;
}
});
},
}
}
</script>
<style scoped>
.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>

View File

@ -7,7 +7,7 @@
<a-row :gutter="10">
<a-col :md="10" :sm="12">
<a-form-item label="用户账号" style="margin-left:8px">
<a-input placeholder="请输入名称查询" v-model="queryParam.username"></a-input>
<a-input placeholder="请输入账号" v-model="queryParam.username"></a-input>
</a-form-item>
</a-col>
<!--<a-col :md="8" :sm="8">-->
@ -25,7 +25,7 @@
</a-form>
</div>
<!-- 操作按钮区域 -->
<div class="table-operator" :md="24" :sm="24" style="margin: -46px 0px 10px 2px">
<div class="table-operator" :md="24" :sm="24" style="margin-top: -15px">
<a-button @click="handleAdd" type="primary" icon="plus" style="margin-top: 16px">用户录入</a-button>
<!--<a-button @click="handleEdit" type="primary" icon="edit" style="margin-top: 16px">用户编辑</a-button>-->
<a-button @click="handleAddUserDepart" type="primary" icon="plus">添加已有用户</a-button>
@ -34,7 +34,7 @@
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel">
<a-icon type="delete"/>
删除关系
取消关联
</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作
@ -80,10 +80,13 @@
</a-menu-item>
<a-menu-item>
<a-popconfirm title="确定要删除关系吗?" @confirm="() => handleDelete(record.id)">
<a>删除关系</a>
<a-popconfirm title="确定取消与选中部门关联吗?" @confirm="() => handleDelete(record.id)">
<a>取消关联</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a href="javascript:;" @click="handleDeptRole(record)">分配部门角色</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
@ -96,6 +99,7 @@
<!-- 表单区域 -->
<user-modal ref="modalForm" @ok="modalFormOk"></user-modal>
<Select-User-Modal ref="selectUserModal" @selectFinished="selectOK"></Select-User-Modal>
<dept-role-user-modal ref="deptRoleUser"></dept-role-user-modal>
</a-card>
</template>
@ -104,11 +108,13 @@
import {getAction, postAction, deleteAction} from '@/api/manage'
import SelectUserModal from './SelectUserModal'
import UserModal from './UserModal'
import DeptRoleUserModal from './DeptRoleUserModal'
export default {
name: "DeptUserInfo",
mixins: [JeecgListMixin],
components: {
DeptRoleUserModal,
SelectUserModal,
UserModal
},
@ -127,6 +133,21 @@
align: "center",
dataIndex: 'realname'
},
{
title: '性别',
align: "center",
dataIndex: 'sex_dictText'
},
{
title: '电话',
align: "center",
dataIndex: 'phone'
},
{
title: '部门',
align: "center",
dataIndex: 'orgCode'
},
{
title: '操作',
dataIndex: 'action',
@ -146,7 +167,12 @@
},
methods: {
searchReset() {
this.queryParam = {}
this.currentDeptId = '';
this.loadData(1);
this.$emit('clearSelectedDepartKeys')
},
loadData(arg) {
if (!this.url.list) {
this.$message.error("请设置url.list属性!")
@ -156,11 +182,11 @@
if (arg === 1) {
this.ipagination.current = 1;
}
if (this.currentDeptId === '') return;
var params = this.getQueryParams();//查询条件
//if (this.currentDeptId === '') return;
let params = this.getQueryParams();//查询条件
params.depId = this.currentDeptId;
getAction(this.url.list, params).then((res) => {
if (res.success) {
if (res.success && res.result) {
this.dataSource = res.result.records;
this.ipagination.total = res.result.total;
}
@ -172,6 +198,11 @@
this.$message.error("请设置url.deleteBatch属性!")
return
}
if (!this.currentDeptId) {
this.$message.error("未选中任何部门,无法取消部门与用户的关联!")
return
}
if (this.selectedRowKeys.length <= 0) {
this.$message.warning('请选择一条记录');
return;
@ -183,12 +214,12 @@
var that = this;
console.log(this.currentDeptId);
this.$confirm({
title: "确认删除",
content: "是否删除选中数据?",
title: "确认取消",
content: "是否取消用户与选中部门的关联?",
onOk: function () {
deleteAction(that.url.deleteBatch, {depId: that.currentDeptId, userIds: ids}).then((res) => {
if (res.success) {
that.$message.success(res.message);
that.$message.success("删除用户与选中部门关系成功!");
that.loadData();
that.onClearSelected();
} else {
@ -204,10 +235,15 @@
this.$message.error("请设置url.delete属性!")
return
}
if (!this.currentDeptId) {
this.$message.error("未选中任何部门,无法取消部门与用户的关联!")
return
}
var that = this;
deleteAction(that.url.delete, {depId: this.currentDeptId, userId: id}).then((res) => {
if (res.success) {
that.$message.success(res.message);
that.$message.success("删除用户与选中部门关系成功!");
if (this.selectedRowKeys.length>0){
for(let i =0; i<this.selectedRowKeys.length;i++){
if (this.selectedRowKeys[i] == id){
@ -232,14 +268,14 @@
this.dataSource = [];
},
hasSelectDept() {
if (this.currentDeptId == null) {
if (this.currentDeptId == '') {
this.$message.error("请选择一个部门!")
return false;
}
return true;
},
handleAddUserDepart() {
if (this.currentDeptId == '') {
if (this.currentDeptId == '' ) {
this.$message.error("请选择一个部门!")
} else {
this.$refs.selectUserModal.visible = true;
@ -277,6 +313,10 @@
this.$message.warning(res.message);
}
})
},
handleDeptRole(record){
this.$refs.deptRoleUser.add(record,this.currentDeptId);
this.$refs.deptRoleUser.title = "部门角色分配";
}
}
}

View File

@ -30,7 +30,7 @@
</template>
<script>
import {changPassword} from '@/api/api'
import {changePassword} from '@/api/api'
export default {
name: "PasswordModal",
@ -96,7 +96,7 @@
if (!err) {
this.confirmLoading = true;
let formData = Object.assign(this.model, values);
changPassword(formData).then((res)=>{
changePassword(formData).then((res)=>{
if(res.success){
this.$message.success(res.message);
this.$emit('ok');

View File

@ -13,13 +13,13 @@
<a-col :span="6">
<a-form-item label="账号">
<a-input placeholder="请输入账号查询" v-model="queryParam.username"></a-input>
<a-input placeholder="请输入账号" v-model="queryParam.username"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item label="性别">
<a-select v-model="queryParam.sex" placeholder="请选择性别查询">
<a-select v-model="queryParam.sex" placeholder="请选择性别">
<a-select-option value="">请选择性别查询</a-select-option>
<a-select-option value="1">男性</a-select-option>
<a-select-option value="2">女性</a-select-option>
@ -31,20 +31,20 @@
<template v-if="toggleSearchStatus">
<a-col :span="6">
<a-form-item label="邮箱">
<a-input placeholder="请输入邮箱查询" v-model="queryParam.email"></a-input>
<a-input placeholder="请输入邮箱" v-model="queryParam.email"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item label="手机号码">
<a-input placeholder="请输入手机号码查询" v-model="queryParam.phone"></a-input>
<a-input placeholder="请输入手机号码" v-model="queryParam.phone"></a-input>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item label="状态">
<a-select v-model="queryParam.status" placeholder="请选择用户状态查询">
<a-select-option value="">请选择用户状态</a-select-option>
<a-select v-model="queryParam.status" placeholder="请选择状态">
<a-select-option value="">请选择状态</a-select-option>
<a-select-option value="1">正常</a-select-option>
<a-select-option value="2">解冻</a-select-option>
</a-select>
@ -101,7 +101,7 @@
fixed:'left',
width:200
},{
title: '真实姓名',
title: '用户名称',
align:"center",
dataIndex: 'realname',
},{

View File

@ -12,12 +12,12 @@
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :span="10">
<a-form-item label="姓名">
<a-input placeholder="请输入姓名" v-model="queryParam.username"></a-input>
<a-form-item label="用户账号">
<a-input placeholder="请输入用户账号" v-model="queryParam.username"></a-input>
</a-form-item>
</a-col>
<a-col :span="8">
@ -83,7 +83,7 @@
{
title: '用户账号',
align: "center",
width: 113,
width: 100,
dataIndex: 'username'
},
{
@ -93,10 +93,22 @@
dataIndex: 'realname'
},
{
title: '状态',
title: '性别',
align: "center",
width: 100,
dataIndex: 'status'
dataIndex: 'sex_dictText'
},
{
title: '电话',
align: "center",
width: 100,
dataIndex: 'phone'
},
{
title: '部门',
align: "center",
width: 150,
dataIndex: 'orgCode'
}
],
columns2: [

View File

@ -12,16 +12,16 @@
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-row class="form-row" :gutter="{ xs: 8, sm: 16, md: 24, lg: 32 }">
<a-col :lg="12">
<a-row style="width: 100%;">
<a-col :span="24/2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="标题">
<a-input placeholder="请输入标题" v-decorator="['titile', validatorRules.title]" :readOnly="disableSubmit" style="width: 90%"/>
<a-input placeholder="请输入标题" v-decorator="['titile', validatorRules.title]" :readOnly="disableSubmit"/>
</a-form-item>
</a-col>
<a-col :lg="12">
<a-col :span="24/2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
@ -30,76 +30,68 @@
v-decorator="[ 'msgCategory', validatorRules.msgCategory]"
placeholder="请选择消息类型"
:disabled="disableSubmit"
:getPopupContainer = "(target) => target.parentNode"
style="width: 80%" >
:getPopupContainer = "(target) => target.parentNode">
<a-select-option value="1">通知公告</a-select-option>
<a-select-option value="2">系统消息</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="24">
<a-col :lg="12">
<a-row style="width: 100%;">
<a-col :span="24/2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="开始时间:"
style="margin-left: 27px">
<j-date v-decorator="[ 'startTime', validatorRules.startTime]" placeholder="请选择开始时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss" ></j-date>
label="开始时间:">
<j-date style="width: 100%" :getCalendarContainer="node => node.parentNode" v-decorator="[ 'startTime', validatorRules.startTime]" placeholder="请选择开始时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss" ></j-date>
</a-form-item>
</a-col>
<a-col :lg="12">
<a-col :span="24/2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="结束时间"
class="endTime">
<j-date v-decorator="[ 'endTime', validatorRules.endTime]" placeholder="请选择结束时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss"></j-date>
<j-date style="width: 100%" :getCalendarContainer="node => node.parentNode" v-decorator="[ 'endTime', validatorRules.endTime]" placeholder="请选择结束时间" showTime dateFormat="YYYY-MM-DD HH:mm:ss"></j-date>
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="32">
<a-col :lg="9">
<a-row style="width: 100%;">
<a-col :span="24/2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="优先级"
style="margin-left: 27px">
label="优先级">
<a-select
v-decorator="[ 'priority', {}]"
placeholder="请选择优先级"
:disabled="disableSubmit"
:getPopupContainer = "(target) => target.parentNode"
style="margin-left: 5px;width: 135%">
:getPopupContainer = "(target) => target.parentNode">
<a-select-option value="L"></a-select-option>
<a-select-option value="M"></a-select-option>
<a-select-option value="H"></a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :lg="15" push="3">
<a-col :span="24/2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="通告对象类型"
style="margin-left: -14px">
label="通告类型">
<a-select
v-decorator="[ 'msgType', validatorRules.msgType]"
placeholder="请选择通告对象类型"
placeholder="请选择通告类型"
:disabled="disableSubmit"
@change="chooseMsgType"
:getPopupContainer = "(target) => target.parentNode"
style="width: 200px;margin-left: 5px">
:getPopupContainer = "(target) => target.parentNode">
<a-select-option value="USER">指定用户</a-select-option>
<a-select-option value="ALL">全体用户</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :lg="24" pull="2">
<a-row style="width: 100%;">
<a-col :span="24/2">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
@ -110,20 +102,19 @@
placeholder="请选择用户"
v-model="selectedUser"
@dropdownVisibleChange="selectUserIds"
style="width: 119%"
>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :lg="24" pull="3">
<a-row style="width: 100%;">
<a-col :span="24">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
:labelCol="labelColX1"
:wrapperCol="wrapperColX1"
label="内容"
style="margin-left: 5px">
<j-editor style="width: 130%" v-decorator="[ 'msgContent', {} ]" triggerChange></j-editor>
class="j-field-content">
<j-editor v-decorator="[ 'msgContent', {} ]" triggerChange></j-editor>
</a-form-item>
</a-col>
</a-row>
@ -153,11 +144,19 @@
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
sm: { span: 18 },
},
labelColX1: {
xs: { span: 24 },
sm: { span: 3 },
},
wrapperColX1: {
xs: { span: 24 },
sm: { span: 21 },
},
confirmLoading: false,

View File

@ -0,0 +1,379 @@
<template>
<a-modal
:title="title"
:width="1000"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
cancelText="关闭">
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="规则名称">
<a-input placeholder="请输入规则名称" v-decorator="['ruleName', validatorRules.ruleName]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="规则Code">
<a-input placeholder="请输入规则Code" v-decorator="['ruleCode', validatorRules.ruleCode]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="规则描述">
<a-textarea placeholder="请输入规则描述" v-decorator="['ruleDescription', {}]"/>
</a-form-item>
</a-form>
<!-- 规则设计 -->
<a-tabs v-model="tabs.activeKey">
<a-tab-pane tab="局部规则" :key="tabs.design.key" forceRender>
<a-alert type="info" showIcon message="局部规则按照你输入的位数有序的校验。"/>
<j-editable-table
ref="designTable"
dragSort
rowNumber
:maxHeight="240"
:columns="tabs.design.columns"
:dataSource="tabs.design.dataSource"
style="margin-top: 8px;"
>
<template #action="props">
<my-action-button :rowEvent="props"/>
</template>
</j-editable-table>
</a-tab-pane>
<a-tab-pane tab="全局规则" :key="tabs.global.key" forceRender>
<j-editable-table
ref="globalTable"
dragSort
rowNumber
actionButton
:maxHeight="240"
:columns="tabs.global.columns"
:dataSource="tabs.global.dataSource"
>
<template #actionButtonAfter>
<a-alert type="info" showIcon message="全局规则可校验用户输入的所有字符;全局规则的优先级比局部规则的要高。" style="margin-bottom: 8px;"/>
</template>
<template #action="props">
<my-action-button :rowEvent="props" allowEmpty/>
</template>
</j-editable-table>
</a-tab-pane>
</a-tabs>
</a-spin>
</a-modal>
</template>
<script>
import pick from 'lodash.pick'
import { httpAction } from '@/api/manage'
import { validateDuplicateValue, alwaysResolve, failedSymbol } from '@/utils/util'
import { FormTypes } from '@/utils/JEditableTableUtil'
import JEditableTable from '@comp/jeecg/JEditableTable'
export default {
name: 'SysCheckRuleModal',
components: {
JEditableTable,
'my-action-button': {
props: { rowEvent: Object, allowEmpty: Boolean },
methods: {
confirmIsShow() {
const { index, allValues: { inputValues } } = this.rowEvent
let value = inputValues[index]
return value.digits || value.pattern
},
handleLineAdd() {
const { target } = this.rowEvent
target.add()
},
handleLineDelete() {
const { rowId, target } = this.rowEvent
target.removeRows(rowId)
},
renderDeleteButton() {
if (this.allowEmpty || this.rowEvent.index > 0) {
if (this.confirmIsShow()) {
return (
<a-popconfirm title="确定要删除吗?" onConfirm={this.handleLineDelete}>
<a-button icon="minus"/>
</a-popconfirm>
)
} else {
return (
<a-button icon="minus" onClick={this.handleLineDelete}/>
)
}
}
return ''
},
},
render() {
return (
<div>
<a-button onClick={this.handleLineAdd} icon="plus"/>
&nbsp;
{this.renderDeleteButton()}
</div>
)
}
}
},
data() {
return {
title: '操作',
visible: false,
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
confirmLoading: false,
form: this.$form.createForm(this),
validatorRules: {
ruleName: { rules: [{ required: true, message: '请输入规则名称!' },] },
ruleCode: {
rules: [
{ required: true, message: '请输入规则Code!' },
{ validator: (rule, value, callback) => validateDuplicateValue('sys_check_rule', 'rule_code', value, this.model.id, callback) }
]
},
},
tabs: {
activeKey: 'design',
global: {
key: 'global',
columns: [
{
title: '优先级',
key: 'priority',
width: '15%',
type: FormTypes.select,
defaultValue: '1',
options: [
{ title: '优先运行', value: '1' },
{ title: '最后运行', value: '0' },
],
validateRules: []
},
{
title: '规则正则表达式',
key: 'pattern',
width: '50%',
type: FormTypes.input,
validateRules: [
{ required: true, message: '规则不能为空' },
{ handler: this.validatePatternHandler },
]
},
{
title: '提示文本',
key: 'message',
width: '20%',
type: FormTypes.input,
validateRules: [
{ required: true, message: '${title}不能为空' },
]
},
{
title: '操作',
key: 'action',
width: '15%',
slotName: 'action',
type: FormTypes.slot
}
],
dataSource: [],
},
design: {
key: 'design',
columns: [
{
title: '位数',
key: 'digits',
width: '15%',
type: FormTypes.inputNumber,
validateRules: [
{ required: true, message: '${title}不能为空' },
{ pattern: /^[1-9]\d*$/, message: '请输入零以上的正整数' },
]
},
{
title: '规则正则表达式',
key: 'pattern',
width: '50%',
type: FormTypes.input,
validateRules: [
{ required: true, message: '规则不能为空' },
{ handler: this.validatePatternHandler }
]
},
{
title: '提示文本',
key: 'message',
width: '20%',
type: FormTypes.input,
validateRules: [
{ required: true, message: '${title}不能为空' },
]
},
{
title: '操作',
key: 'action',
width: '15%',
slotName: 'action',
type: FormTypes.slot
},
],
dataSource: [],
}
},
url: {
add: '/sys/checkRule/add',
edit: '/sys/checkRule/edit',
},
}
},
created() {
},
methods: {
validatePatternHandler(type, value, row, column, callback, target) {
if (type === 'blur' || type === 'getValues') {
try {
new RegExp(value)
callback(true)
} catch (e) {
callback(false, '请输入正确的正则表达式')
}
} else {
callback(true) // 不填写或者填写 null 代表不进行任何操作
}
},
add() {
this.edit({})
},
edit(record) {
this.form.resetFields()
this.tabs.activeKey = this.tabs.design.key
this.tabs.global.dataSource = []
this.tabs.design.dataSource = [{ digits: '', pattern: '', message: '' }]
this.model = Object.assign({}, record)
this.visible = true
this.$nextTick(() => {
this.form.setFieldsValue(pick(this.model, 'ruleName', 'ruleCode', 'ruleDescription'))
// 子表数据
let ruleJson = this.model.ruleJson
if (ruleJson) {
let ruleList = JSON.parse(ruleJson)
// 筛选出全局规则和局部规则
let global = [], design = [], priority = '1'
ruleList.forEach(rule => {
if (rule.digits === '*') {
global.push(Object.assign(rule, { priority }))
} else {
priority = '0'
design.push(rule)
}
})
this.tabs.global.dataSource = global
this.tabs.design.dataSource = design
}
})
},
close() {
this.$emit('close')
this.visible = false
},
handleOk() {
Promise.all([
// 主表单校验
alwaysResolve(new Promise((resolve, reject) => {
this.form.validateFields((error, values) => error ? reject(error) : resolve(values))
})),
// 局部规则子表校验
alwaysResolve(this.$refs.designTable.getValuesPromise),
// 全局规则子表校验
alwaysResolve(this.$refs.globalTable.getValuesPromise),
]).then(results => {
let [mainResult, designResult, globalResult] = results
if (mainResult.type === failedSymbol) {
return Promise.reject('主表校验未通过')
} else if (designResult.type === failedSymbol) {
this.tabs.activeKey = this.tabs.design.key
return Promise.reject('局部规则子表校验未通过')
} else if (globalResult.type === failedSymbol) {
this.tabs.activeKey = this.tabs.global.key
return Promise.reject('全局规则子表校验未通过')
} else {
// 所有校验已通过这一步是整合数据
let mainValues = mainResult.data, globalValues = globalResult.data, designValues = designResult.data
// 整合两个子表的数据
let firstGlobal = [], afterGlobal = []
globalValues.forEach(v => {
v.digits = '*'
if (v.priority === '1') {
firstGlobal.push(v)
} else {
afterGlobal.push(v)
}
})
let concatValues = firstGlobal.concat(designValues).concat(afterGlobal)
let subValues = concatValues.map(i => pick(i, 'digits', 'pattern', 'message'))
// 生成 formData用于传入后台
let ruleJson = JSON.stringify(subValues)
let formData = Object.assign(this.model, mainValues, { ruleJson })
// 判断请求方式和请求地址并发送请求
let method = 'post', httpUrl = this.url.add
if (this.model.id) {
method = 'put'
httpUrl = this.url.edit
}
this.confirmLoading = true
return httpAction(httpUrl, formData, method)
}
}).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warning(res.message)
}
}).catch(e => {
console.error(e)
}).finally(() => {
this.confirmLoading = false
})
},
handleCancel() {
this.close()
},
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,58 @@
<template>
<a-modal
title="功能测试"
:width="800"
:visible="visible"
@ok="visible=false"
@cancel="visible=false"
>
<a-form :form="form">
<a-form-item label="功能测试">
<a-input placeholder="请输入" v-decorator="['test', validatorRules.test]" @change="e=>testValue=e.target.value"/>
</a-form-item>
</a-form>
<a-row type="flex" :gutter="8">
<a-col v-for="(str,index) of testValue">
<a-row>
<a-col>
<a-input :value="str" style="text-align: center;width: 40px;"/>
</a-col>
<a-col style="text-align: center;">{{index+1}}</a-col>
</a-row>
</a-col>
</a-row>
</a-modal>
</template>
<script>
import { validateCheckRule } from '@/utils/util'
export default {
name: 'SysCheckRuleModal',
data() {
return {
title: '操作',
visible: false,
ruleCode: '',
testValue: '',
form: this.$form.createForm(this),
validatorRules: {
test: {
rules: [{ validator: (rule, value, callback) => validateCheckRule(this.ruleCode, value, callback) }]
}
},
}
},
methods: {
open(ruleCode) {
this.ruleCode = ruleCode
this.form.resetFields()
this.testValue = ''
this.visible = true
},
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,227 @@
<template>
<a-modal
:title="title"
:width="800"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
cancelText="关闭">
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="数据源名称">
<a-input placeholder="请输入数据源名称" v-decorator="['name', validatorRules.name]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="数据源编码">
<a-input placeholder="请输入数据源编码" :disabled="!!model.id" v-decorator="['code', validatorRules.code]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="数据库类型">
<j-dict-select-tag placeholder="请选择数据库类型" dict-code="database_type" triggerChange v-decorator="['dbType', validatorRules.dbType]" @change="handleDbTypeChange"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="驱动类">
<a-input placeholder="请输入驱动类" v-decorator="['dbDriver', validatorRules.dbDriver]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="数据源地址">
<a-input placeholder="请输入数据源地址" v-decorator="['dbUrl', validatorRules.dbUrl]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="数据库名称">
<a-input placeholder="请输入数据库名称" v-decorator="['dbName', validatorRules.dbName]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="用户名">
<a-input placeholder="请输入用户名" v-decorator="['dbUsername', validatorRules.dbUsername]"/>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="密码">
<a-row :gutter="8">
<a-col :span="21">
<a-input-password placeholder="请输入密码" v-decorator="['dbPassword', validatorRules.dbPassword]"/>
</a-col>
<a-col :span="3">
<a-button type="primary" size="small" style="width: 100%" @click="handleTest">测试</a-button>
</a-col>
</a-row>
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="备注">
<a-textarea placeholder="请输入备注" v-decorator="['remark', {}]"/>
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</template>
<script>
import pick from 'lodash.pick'
import { httpAction, postAction } from '@/api/manage'
import { validateDuplicateValue } from '@/utils/util'
export default {
name: 'SysDataSourceModal',
components: {},
data() {
return {
title: '操作',
visible: false,
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
confirmLoading: false,
form: this.$form.createForm(this),
validatorRules: {
code: {
validateFirst: true,
rules: [
{ required: true, message: '请输入数据源编码!' },
{
validator: (rule, value, callback) => {
let pattern = /^[a-z|A-Z][a-z|A-Z\d_-]{0,}$/
if (!pattern.test(value)) {
callback('编码必须以字母开头可包含数字下划线横杠')
} else {
validateDuplicateValue('sys_data_source', 'code', value, this.model.id, callback)
}
}
}
]
},
name: { rules: [{ required: true, message: '请输入数据源名称!' }] },
dbType: { rules: [{ required: true, message: '请选择数据库类型!' }] },
dbDriver: { rules: [{ required: true, message: '请输入驱动类!' }] },
dbUrl: { rules: [{ required: true, message: '请输入数据源地址!' }] },
dbName: { rules: [{ required: true, message: '请输入数据库名称!' }] },
dbUsername: { rules: [{ required: true, message: '请输入用户名!' }] },
dbPassword: { rules: [{ required: true, message: '请输入密码!' }] }
},
url: {
add: '/sys/dataSource/add',
edit: '/sys/dataSource/edit',
},
dbDriverMap: {
// MySQL 数据库
'1': { dbDriver: 'com.mysql.jdbc.Driver' },
// Oracle
'2': { dbDriver: 'oracle.jdbc.OracleDriver' },
// SQLServer 数据库
'3': { dbDriver: 'com.microsoft.sqlserver.jdbc.SQLServerDriver' },
}
}
},
created() {
},
methods: {
add() {
this.edit({})
},
edit(record) {
this.form.resetFields()
this.model = Object.assign({}, record)
this.visible = true
this.$nextTick(() => {
this.form.setFieldsValue(pick(this.model, 'code', 'name', 'remark', 'dbType', 'dbDriver', 'dbUrl', 'dbName', 'dbUsername', 'dbPassword'))
})
},
close() {
this.$emit('close')
this.visible = false
},
handleOk() {
// 触发表单验证
this.form.validateFields((err, values) => {
if (!err) {
this.confirmLoading = true
let formData = Object.assign(this.model, values)
let httpUrl = this.url.add, method = 'post'
if (this.model.id) {
httpUrl = this.url.edit
method = 'put'
// 由于编码的特殊性所以不能更改
formData['code'] = undefined
}
httpAction(httpUrl, formData, method).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.$emit('ok')
this.close()
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.confirmLoading = false
})
}
})
},
handleCancel() {
this.close()
},
// 测试数据源配置是否可以正常连接
handleTest() {
let keys = ['dbType', 'dbDriver', 'dbUrl', 'dbName', 'dbUsername', 'dbPassword']
// 获取以上字段的值并清除校验状态
let fieldsValues = this.form.getFieldsValue(keys)
let setFields = {}
keys.forEach(key => setFields[key] = { value: fieldsValues[key], errors: null })
// 清除校验状态目的是可以让错误文字闪烁
this.form.setFields(setFields)
// 重新校验
this.$nextTick(() => {
this.form.validateFields(keys, (errors, values) => {
if (!errors) {
let loading = this.$message.loading('连接中', 0)
postAction('/online/cgreport/api/testConnection', fieldsValues).then(res => {
if (res.success) {
this.$message.success('连接成功')
} else throw new Error(res.message)
}).catch(error => {
this.$warning({ title: '连接失败', content: error.message || error })
}).finally(() => loading())
}
})
})
},
// 数据库类型更改时联动更改数据库驱动
handleDbTypeChange(val) {
let dbDriver = this.dbDriverMap[val]
if (dbDriver) {
this.form.setFieldsValue(dbDriver)
}
},
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,162 @@
<template>
<a-modal
:title="title"
:width="800"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
cancelText="关闭">
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="部门角色名称">
<a-input placeholder="请输入部门角色名称" v-decorator="['roleName', validatorRules.roleName]" />
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="部门角色编码">
<a-input placeholder="请输入部门角色编码" v-decorator="['roleCode', validatorRules.roleCode]" />
</a-form-item>
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="描述">
<a-input placeholder="请输入描述" v-decorator="['description', validatorRules.description]" />
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</template>
<script>
import { httpAction } from '@/api/manage'
import pick from 'lodash.pick'
import {duplicateCheck } from '@/api/api'
export default {
name: "SysDepartRoleModal",
data () {
return {
title:"操作",
visible: false,
model: {},
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
confirmLoading: false,
form: this.$form.createForm(this),
validatorRules:{
roleName:{
rules: [
{ required: true, message: '请输入部门角色名称!' },
{ min: 2, max: 30, message: '长度在 2 30 个字符', trigger: 'blur' }
]},
roleCode:{
rules: [
{ required: true, message: '请输入部门角色编码!'},
{ min: 0, max: 64, message: '长度不超过 64 个字符', trigger: 'blur' },
{ validator: this.validateRoleCode}
]},
description:{
rules: [
{ min: 0, max: 126, message: '长度不超过 126 个字符', trigger: 'blur' }
]}
},
url: {
add: "/sys/sysDepartRole/add",
edit: "/sys/sysDepartRole/edit",
},
}
},
created () {
},
methods: {
add (departId) {
this.edit({},departId);
},
edit (record,departId) {
this.departId = departId;
this.form.resetFields();
this.model = Object.assign({}, record);
this.visible = true;
this.$nextTick(() => {
this.form.setFieldsValue(pick(this.model,'roleName','roleCode','description'))
});
},
close () {
this.$emit('close');
this.visible = false;
},
handleOk () {
const that = this;
// 触发表单验证
this.form.validateFields((err, values) => {
if (!err) {
that.confirmLoading = true;
let httpurl = '';
let method = '';
if(!this.model.id){
httpurl+=this.url.add;
method = 'post';
}else{
httpurl+=this.url.edit;
method = 'put';
}
let formData = Object.assign(this.model, values);
formData.departId = this.departId;
httpAction(httpurl,formData,method).then((res)=>{
if(res.success){
that.$message.success(res.message);
that.$emit('ok');
}else{
that.$message.warning(res.message);
}
}).finally(() => {
that.confirmLoading = false;
that.close();
})
}
})
},
handleCancel () {
this.close()
},
validateRoleCode(rule, value, callback){
if(/[\u4E00-\u9FA5]/g.test(value)){
callback("部门角色编码不可输入汉字!");
}else{
var params = {
tableName: "sys_depart_role",
fieldName: "role_code",
fieldVal: value,
dataId: this.model.id,
};
duplicateCheck(params).then((res)=>{
if(res.success){
callback();
}else{
callback(res.message);
}
});
}
}
}
}
</script>
<style lang="less" scoped>
</style>

View File

@ -36,8 +36,8 @@
</a-form-item>
</template>
<a-form-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" >
<a-input placeholder="请输入用户" v-decorator="[ 'realname', validatorRules.realname]" />
<a-form-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" >
<a-input placeholder="请输入用户" v-decorator="[ 'realname', validatorRules.realname]" />
</a-form-item>
<a-form-item label="工号" :labelCol="labelCol" :wrapperCol="wrapperCol">
@ -71,23 +71,33 @@
<a-button slot="enterButton" icon="search">选择</a-button>
</a-input-search>
</a-form-item>
<a-form-item label="头像" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-upload
listType="picture-card"
class="avatar-uploader"
:showUploadList="false"
:action="uploadAction"
:data="{'isup':1}"
:headers="headers"
:beforeUpload="beforeUpload"
@change="handleChange"
<!-- update--begin--autor:wangshuai-----date:20200108------for新增身份和负责部门------ -->
<a-form-item label="身份" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-radio-group
v-model="identity"
@change="identityChange">
<a-radio value="1">普通用户</a-radio>
<a-radio value="2">上级</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="负责部门" :labelCol="labelCol" :wrapperCol="wrapperCol" v-if="departIdShow==true">
<a-select
mode="multiple"
style="width: 100%"
placeholder="请选择负责部门"
v-model="departIds"
optionFilterProp = "children"
:getPopupContainer = "(target) => target.parentNode"
:dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
>
<img v-if="picUrl" :src="getAvatarView()" alt="头像" style="height:104px;max-width:300px"/>
<div v-else>
<a-icon :type="uploadLoading ? 'loading' : 'plus'" />
<div class="ant-upload-text">上传</div>
</div>
</a-upload>
<a-select-option v-for="item in resultDepartOptions" :key="item.key" :value="item.key"
>{{item.title}}</a-select-option
>
</a-select>
</a-form-item>
<!-- update--end--autor:wangshuai-----date:20200108------for新增身份和负责部门------ -->
<a-form-item label="头像" :labelCol="labelCol" :wrapperCol="wrapperCol">
<j-image-upload class="avatar-uploader" text="上传" v-model="fileList" ></j-image-upload>
</a-form-item>
<a-form-item label="生日" :labelCol="labelCol" :wrapperCol="wrapperCol">
@ -145,10 +155,12 @@
import {addUser,editUser,queryUserRole,queryall } from '@/api/api'
import { disabledAuthFilter } from "@/utils/authFilter"
import {duplicateCheck } from '@/api/api'
import JImageUpload from '../../../components/jeecg/JImageUpload'
export default {
name: "UserModal",
components: {
JImageUpload,
departWindow,
JSelectPosition
},
@ -164,6 +176,7 @@
checkedDepartKeys:[],
checkedDepartNames:[], // 保存部门的名称 =>title
checkedDepartNameString:"", // 保存部门的名称 =>title
resultDepartOptions:[],
userId:"", //保存用户id
disableSubmit:false,
userDepartModel:{userId:'',departIdList:[]}, // 保存SysUserDepart的用户部门中间表数据需要的对象
@ -213,6 +226,8 @@
]
}
},
departIdShow:false,
departIds:[], //负责部门id
title:"操作",
visible: false,
model: {},
@ -233,11 +248,13 @@
picUrl: "",
url: {
fileUpload: window._CONFIG['domianURL']+"/sys/common/upload",
imgerver: window._CONFIG['domianURL']+"/sys/common/view",
imgerver: window._CONFIG['staticDomainURL'],
userWithDepart: "/sys/user/userDepartList", // 引入为指定用户查看部门信息需要的url
userId:"/sys/user/generateUserId", // 引入生成添加用户情况下的url
syncUserByUserName:"/process/extActProcess/doSyncUserByUserName",//同步用户到工作流
},
identity:"1",
fileList:[],
}
},
created () {
@ -287,6 +304,9 @@
this.checkedDepartNames=[];
this.checkedDepartNameString = "";
this.userId=""
this.resultDepartOptions=[];
this.departId=[];
this.departIdShow=false;
},
add () {
this.picUrl = "";
@ -301,7 +321,9 @@
that.form.resetFields();
if(record.hasOwnProperty("id")){
that.loadUserRoles(record.id);
this.picUrl = "Has no pic url yet";
setTimeout(() => {
this.fileList = record.avatar;
}, 5)
}
that.userId = record.id;
that.visible = true;
@ -309,6 +331,14 @@
that.$nextTick(() => {
that.form.setFieldsValue(pick(this.model,'username','sex','realname','email','phone','activitiSync','workNo','telephone','post'))
});
//身份为上级显示负责部门否则不显示
if(this.model.identity=="2"){
this.identity="2";
this.departIdShow=true;
}else{
this.identity="1";
this.departIdShow=false;
}
// 调用查询用户对应的部门信息的方法
that.checkedDepartKeys = [];
that.loadCheckedDeparts();
@ -320,10 +350,25 @@
getAction(that.url.userWithDepart,{userId:that.userId}).then((res)=>{
that.checkedDepartNames = [];
if(res.success){
var depart=[];
var departId=[];
for (let i = 0; i < res.result.length; i++) {
that.checkedDepartNames.push(res.result[i].title);
this.checkedDepartNameString = this.checkedDepartNames.join(",");
that.checkedDepartKeys.push(res.result[i].key);
//新增负责部门选择下拉框
depart.push({
key:res.result[i].key,
title:res.result[i].title
})
departId.push(res.result[i].key)
}
that.resultDepartOptions=depart;
//判断部门id是否存在不存在择直接默认当前所在部门
if(this.model.departIds){
this.departIds=this.model.departIds.split(",");
}else{
this.departIds=departId;
}
that.userDepartModel.departIdList = that.checkedDepartKeys
}else{
@ -341,6 +386,11 @@
this.checkedDepartNameString='';
this.checkedDepartKeys = [];
this.selectedDepartKeys = [];
this.resultDepartOptions=[];
this.departIds=[];
this.departIdShow=false;
this.identity="1";
this.fileList=[];
},
moment,
handleSubmit () {
@ -350,17 +400,22 @@
this.form.validateFields((err, values) => {
if (!err) {
that.confirmLoading = true;
let avatar = that.model.avatar;
if(!values.birthday){
values.birthday = '';
}else{
values.birthday = values.birthday.format(this.dateFormat);
}
let formData = Object.assign(this.model, values);
formData.avatar = avatar;
formData.avatar = that.fileList;
formData.selectedroles = this.selectedRole.length>0?this.selectedRole.join(","):'';
formData.selecteddeparts = this.userDepartModel.departIdList.length>0?this.userDepartModel.departIdList.join(","):'';
formData.identity=this.identity;
//如果是上级择传入departIds,否则为空
if(this.identity==="2"){
formData.departIds=this.departIds.join(",");
}else{
formData.departIds="";
}
// that.addDepartsToUser(that,formData); // 调用根据当前用户添加部门信息的方法
let obj;
if(!this.model.id){
@ -380,7 +435,6 @@
that.confirmLoading = false;
that.checkedDepartNames = [];
that.userDepartModel.departIdList = {userId:'',departIdList:[]};
that.close();
})
@ -528,9 +582,6 @@
}
}
},
getAvatarView(){
return this.url.imgerver +"/"+ this.model.avatar;
},
// 搜索用户对应的部门API
onSearch(){
this.$refs.departWindow.add(this.checkedDepartKeys,this.userId);
@ -543,11 +594,21 @@
this.checkedDepartNameString = '';
this.userId = formData.userId;
this.userDepartModel.userId = formData.userId;
this.departIds=[];
this.resultDepartOptions=[];
var depart=[];
for (let i = 0; i < formData.departIdList.length; i++) {
this.selectedDepartKeys.push(formData.departIdList[i].key);
this.checkedDepartNames.push(formData.departIdList[i].title);
this.checkedDepartNameString = this.checkedDepartNames.join(",");
//新增部门选择如果上面部门选择后不为空直接付给负责部门
depart.push({
key:formData.departIdList[i].key,
title:formData.departIdList[i].title
})
this.departIds.push(formData.departIdList[i].key)
}
this.resultDepartOptions=depart;
this.userDepartModel.departIdList = this.selectedDepartKeys;
this.checkedDepartKeys = this.selectedDepartKeys //更新当前的选择keys
},
@ -560,6 +621,13 @@
this.drawerWidth = 700;
}
},
identityChange(e){
if(e.target.value==="1"){
this.departIdShow=false;
}else{
this.departIdShow=true;
}
}
}
}
</script>

View File

@ -0,0 +1,191 @@
<template>
<a-modal
:width="1000"
:title="title"
:visible="innerVisible"
@cancel="handleCancel"
cancelText="关闭"
:okButtonProps="{style:{display:'none'}}"
>
<a-alert type="info" showIcon style="margin-bottom: 16px;">
<template slot="message">
<span>已选择</span>
<a style="font-weight: 600;padding: 0 4px;">{{ selectedRowKeys.length }}</a>
<span></span>
<template v-if="selectedRowKeys.length>0">
<a-divider type="vertical"/>
<a @click="handleClearSelection">清空选择</a>
<a-divider type="vertical"/>
<a @click="handleRevertBatch">批量还原</a>
<a-divider type="vertical"/>
<a @click="handleDeleteBatch">批量删除</a>
</template>
</template>
</a-alert>
<a-table
ref="table"
rowKey="id"
size="middle"
bordered
:columns="columns"
:loading="loading"
:dataSource="dataSource"
:pagination="false"
:rowSelection="{selectedRowKeys, onChange: handleTableSelectChange}"
>
<!-- 显示头像 -->
<template slot="avatarslot" slot-scope="text, record, index">
<div class="anty-img-wrap">
<a-avatar shape="square" :src="url.getAvatar(record.avatar)" icon="user"/>
</div>
</template>
<span slot="action" slot-scope="text, record">
<a @click="handleRevert([record.id])"><a-icon type="redo"/> 还原用户</a>
<a-divider type="vertical"/>
<a @click="handleDelete([record.id])"><a-icon type="delete"/> 彻底删除</a>
</span>
</a-table>
</a-modal>
</template>
<script>
// 高度封装的请求请务必使用 superRequest.call(this,{}) 的方式调用
function superRequest(options) {
this.loading = !!options.loading
options.promise.then(res => {
if (res.success && typeof options.success === 'function') {
options.success(res)
} else {
throw new Error(res.message)
}
}).catch(e => {
console.error('查询已删除的用户失败', e)
this.$message.warning('查询已删除的用户失败' + (e.message || e))
}).finally(() => {
this.loading = false
})
}
export default {
name: 'UserRecycleBinModal',
props: {
visible: {
type: Boolean,
default: false
},
},
data() {
return {
title: '用户回收站',
loading: false,
innerVisible: false,
selectedRowKeys: [],
dataSource: [],
columns: [
{ title: '#', align: 'center', key: 'rowIndex', width: 80, customRender: (t, r, i) => i + 1 },
{ title: '账号', align: 'center', dataIndex: 'username' },
{ title: '姓名', align: 'center', dataIndex: 'realname', },
{ title: '头像', align: 'center', dataIndex: 'avatar', scopedSlots: { customRender: 'avatarslot' } },
{ title: '部门', align: 'center', dataIndex: 'orgCode' },
{ title: '操作', align: 'center', dataIndex: 'action', width: 200, scopedSlots: { customRender: 'action' } }
],
url: {
getAvatar: (path) => `window._CONFIG['staticDomainURL']/${path}`,
// 回收站操作get = 获取列表put = 取回delete = 彻底删除
recycleBin: '/sys/user/recycleBin',
},
}
},
watch: {
visible: {
immediate: true,
handler(val) {
if (val) {
this.loadData()
}
this.innerVisible = val
}
},
innerVisible(val) {
this.$emit('update:visible', val)
},
},
methods: {
loadData() {
superRequest.call(this, {
loading: true,
promise: this.$http.get(this.url.recycleBin),
success: res => this.dataSource = res.result
})
},
handleOk() {
this.loadData()
this.$emit('ok')
},
handleCancel() {
this.innerVisible = false
},
// 还原用户
handleRevert(userIds) {
this.$confirm({
title: '恢复用户',
content: `您确定要恢复这 ${userIds.length} 个用户吗`,
centered: true,
onOk: () => {
superRequest.call(this, {
loading: true,
promise: this.$http.put(this.url.recycleBin, userIds),
success: () => {
this.handleOk()
this.handleClearSelection()
this.$message.success(`还原 ${userIds.length} 个用户成功`)
}
})
}
})
},
// 彻底删除用户
handleDelete(userIds) {
this.$confirm({
title: '彻底删除用户',
content: (<div>
<p>您确定要彻底删除这 {userIds.length} 个用户吗</p>
<p style="color:red;">注意彻底删除后将无法恢复请谨慎操作</p>
</div>),
centered: true,
onOk: () => {
superRequest.call(this, {
loading: true,
promise: this.$http.delete(this.url.recycleBin + `?userIds=${userIds.join(',')}`),
success: () => {
this.loadData()
this.handleClearSelection()
this.$message.success(`彻底删除 ${userIds.length} 个用户成功`)
}
})
},
})
},
handleRevertBatch() {
this.handleRevert(this.selectedRowKeys)
},
handleDeleteBatch() {
this.handleDelete(this.selectedRowKeys)
},
handleClearSelection() {
this.handleTableSelectChange([], [])
},
handleTableSelectChange(selectedRowKeys, selectionRows) {
this.selectedRowKeys = selectedRowKeys
this.selectionRows = selectionRows
},
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -45,7 +45,8 @@
<a-popconfirm title="确定放弃编辑?" @confirm="close" okText="确定" cancelText="取消">
<a-button style="margin-right: .8rem">取消</a-button>
</a-popconfirm>
<a-button @click="handleSubmit" type="primary" :loading="loading">提交</a-button>
<a-button @click="handleSubmit(false)" type="primary" :loading="loading" ghost style="margin-right: 0.8rem">仅保存</a-button>
<a-button @click="handleSubmit(true)" type="primary" :loading="loading">保存并关闭</a-button>
</div>
<role-datarule-modal ref="datarule"></role-datarule-modal>
@ -134,7 +135,7 @@
handleCancel () {
this.close()
},
handleSubmit(){
handleSubmit(exit) {
let that = this;
let params = {
roleId:that.roleId,
@ -147,18 +148,20 @@
if(res.success){
that.$message.success(res.message);
that.loading = false;
that.close();
if (exit) {
that.close()
}
}else {
that.$message.error(res.message);
that.loading = false;
that.close();
if (exit) {
that.close()
}
}
this.loadData();
})
},
},
watch: {
visible () {
if (this.visible) {
loadData(){
queryTreeListForRole().then((res) => {
this.treeData = res.result.treeList
this.allTreeKeys = res.result.ids
@ -170,6 +173,12 @@
})
})
}
},
watch: {
visible () {
if (this.visible) {
this.loadData();
}
}
}
}

View File

@ -1,13 +1,13 @@
<template>
<a-card :bordered="false" style="width: 160%;text-align: center;margin-left:-25%">
<a-card :bordered="false" style="width: 130%;text-align: center;margin-left:-10%">
<a-steps class="steps" :current="currentTab">
<a-step title="账户信息" />
<a-step title="身份验证" />
<a-step title="更改密码" />
<a-step title="完成" />
<a-step title="用户账户"/>
<a-step title="手机验证"/>
<a-step title="密码"/>
<a-step title="完成"/>
</a-steps>
<div class="content">
<step1 v-if="currentTab === 0" @nextStep="nextStep" />
<step1 v-if="currentTab === 0" @nextStep="nextStep"/>
<step2 v-if="currentTab === 1" @nextStep="nextStep" @prevStep="prevStep" :userList="userList"/>
<step3 v-if="currentTab === 2" @nextStep="nextStep" @prevStep="prevStep" :userList="userList"/>
<step4 v-if="currentTab === 3" @prevStep="prevStep" @finish="finish" :userList="userList"/>
@ -20,6 +20,7 @@
import Step2 from './Step2'
import Step3 from './Step3'
import Step4 from './Step4'
export default {
name: "Alteration",
components: {
@ -28,11 +29,11 @@
Step3,
Step4
},
data () {
data() {
return {
description: '将一个冗长或用户不熟悉的表单任务分成多个步骤指导用户完成',
currentTab: 0,
userList:{},
userList: {},
// form
form: null,
}
@ -40,19 +41,19 @@
methods: {
// handler
nextStep (data) {
this.userList=data;
nextStep(data) {
this.userList = data;
if (this.currentTab < 4) {
this.currentTab += 1
}
},
prevStep (data) {
this.userList=data;
prevStep(data) {
this.userList = data;
if (this.currentTab > 0) {
this.currentTab -= 1
}
},
finish () {
finish() {
this.currentTab = 0
}
}

View File

@ -9,7 +9,7 @@
<a-form-item>
<a-input
size="large"
v-decorator="['username',validatorRules.username,{ validator: this.handleUsernameOrEmail }]"
v-decorator="['username',{initialValue:'admin', rules: validatorRules.username.rules}]"
type="text"
placeholder="请输入帐户名 / jeecg">
<a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }"/>
@ -18,7 +18,7 @@
<a-form-item>
<a-input
v-decorator="['password',validatorRules.password]"
v-decorator="['password',{initialValue:'123456', rules: validatorRules.password.rules}]"
size="large"
type="password"
autocomplete="false"
@ -28,7 +28,7 @@
</a-form-item>
<a-row :gutter="0">
<a-col :span="14">
<a-col :span="16">
<a-form-item>
<a-input
v-decorator="['inputCode',validatorRules.inputCode]"
@ -36,13 +36,13 @@
type="text"
@change="inputCodeChange"
placeholder="请输入验证码">
<a-icon slot="prefix" v-if=" inputCodeContent==verifiedCode " type="smile" :style="{ color: 'rgba(0,0,0,.25)' }"/>
<a-icon slot="prefix" v-else type="frown" :style="{ color: 'rgba(0,0,0,.25)' }"/>
<a-icon slot="prefix" type="smile" :style="{ color: 'rgba(0,0,0,.25)' }"/>
</a-input>
</a-form-item>
</a-col>
<a-col :span="10">
<j-graphic-code @success="generateCode" ref="jgraphicCodeRef" style="float: right" remote></j-graphic-code>
<a-col :span="8" style="text-align: right">
<img style="margin-top: 2px;" :src="randCodeImage" @click="handleChangeCheckCode"/>
<!--<j-graphic-code @success="generateCode" ref="jgraphicCodeRef" style="float: right" remote></j-graphic-code>-->
</a-col>
</a-row>
@ -88,7 +88,7 @@
<router-link :to="{ name: 'alteration'}" class="forge-password" style="float: right;">
忘记密码
</router-link>
<router-link :to="{ name: 'register'}" class="forge-password" style="float: right;margin-right: 10px" >
<router-link :to="{ name: 'register'}" class="forge-password" style="float: right;margin-right: 10px" >
注册账户
</router-link>
</a-form-item>
@ -173,8 +173,7 @@
import Vue from 'vue'
import { ACCESS_TOKEN ,ENCRYPTED_STRING} from "@/store/mutation-types"
import JGraphicCode from '@/components/jeecg/JGraphicCode'
import { putAction } from '@/api/manage'
import { postAction } from '@/api/manage'
import { putAction,postAction,getAction } from '@/api/manage'
import { encryption , getEncryptedString } from '@/utils/encryption/aesEncrypt'
import store from '@/store/'
import { USER_INFO } from "@/store/mutation-types"
@ -202,11 +201,11 @@
smsSendBtn: false,
},
validatorRules:{
username:{rules: [{ required: true, message: '请输入用户名!',validator: 'click'}]},
username:{rules: [{ required: true, message: '请输入用户名!'},{validator: this.handleUsernameOrEmail}]},
password:{rules: [{ required: true, message: '请输入密码!',validator: 'click'}]},
mobile:{rules: [{validator:this.validateMobile}]},
captcha:{rule: [{ required: true, message: '请输入验证码!'}]},
inputCode:{rules: [{ required: true, message: '请输入验证码!'},{validator: this.validateInputCode}]}
inputCode:{rules: [{ required: true, message: '请输入验证码!'}]}
},
verifiedCode:"",
inputCodeContent:"",
@ -216,12 +215,16 @@
departVisible:false,
departSelected:"",
currentUsername:"",
validate_status:""
validate_status:"",
currdatetime:'',
randCodeImage:''
}
},
created () {
this.currdatetime = new Date().getTime();
Vue.ls.remove(ACCESS_TOKEN)
this.getRouterData();
this.handleChangeCheckCode();
// update-begin- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉有点问题
//this.getEncrypte();
// update-end- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉有点问题
@ -257,10 +260,9 @@
loginParams.password = values.password
loginParams.remember_me = values.rememberMe
// update-begin- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉有点问题
let checkParams = this.$refs.jgraphicCodeRef.getLoginParam()
loginParams.captcha = checkParams.checkCode
loginParams.checkKey = checkParams.checkKey
loginParams.captcha = that.inputCodeContent
loginParams.checkKey = that.currdatetime
console.log("登录参数",loginParams)
that.Login(loginParams).then((res) => {
this.departConfirm(res)
}).catch((err) => {
@ -339,6 +341,16 @@
this.stepCaptchaVisible = false
})
},
handleChangeCheckCode(){
this.currdatetime = new Date().getTime();
getAction(`/sys/randomImage/${this.currdatetime}`).then(res=>{
if(res.success){
this.randCodeImage = res.result
}else{
this.$message.error(res.message)
}
})
},
loginSuccess () {
// update-begin- author:sunjianlei --- date:20190812 --- for: 登录成功后不解除禁用按钮防止多次点击
// this.loginBtn = false
@ -384,12 +396,6 @@
},
inputCodeChange(e){
this.inputCodeContent = e.target.value
if(!e.target.value||0==e.target.value){
this.inputCodeNull=true
}else{
this.inputCodeContent = this.inputCodeContent.toLowerCase()
this.inputCodeNull=false
}
},
departConfirm(res){
if(res.success){
@ -452,10 +458,12 @@
},
getRouterData(){
this.$nextTick(() => {
this.form.setFieldsValue({
'username': this.$route.params.username
});
})
if (this.$route.params.username) {
this.form.setFieldsValue({
'username': this.$route.params.username
});
}
})
},
//获取密码加密规则
getEncrypte(){

View File

@ -26,7 +26,7 @@
},
computed: {
email () {
let v = this.form && this.form.username || 'xxx'
let v = this.form ? this.form.username || this.form.mobile : ' XXX '
let title = `你的账户${v} 注册成功`
this.username = v;
return title

View File

@ -1,14 +1,14 @@
<template>
<div class="main">
<a-form style="max-width: 500px; margin: 40px auto 0;" :form="form">
<a-form style="max-width: 500px; margin: 40px auto 0;" :form="form" @keyup.enter.native="nextStep">
<a-form-item>
<a-input
v-decorator="['username',validatorRules.username]"
size="large"
type="text"
autocomplete="false"
placeholder="请输入用户或手机号">
placeholder="请输入用户账号或手机号">
<a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }"/>
</a-input>
</a-form-item>
@ -32,6 +32,7 @@
</a-col>
</a-row>
<a-form-item :wrapperCol="{span: 19, offset: 5}">
<router-link style="float: left;line-height: 40px;" :to="{ name: 'login' }">使用已有账户登录</router-link>
<a-button type="primary" @click="nextStep">下一步</a-button>
</a-form-item>
</a-form>
@ -40,95 +41,99 @@
<script>
import JGraphicCode from '@/components/jeecg/JGraphicCode'
import { getAction } from '@/api/manage'
import {checkOnlyUser } from '@/api/api'
import {getAction} from '@/api/manage'
import {checkOnlyUser} from '@/api/api'
export default {
name: "Step1",
components: {
JGraphicCode
},
data () {
data() {
return {
form: this.$form.createForm(this),
inputCodeContent: "",
inputCodeNull:true,
verifiedCode:"",
inputCodeNull: true,
verifiedCode: "",
validatorRules: {
username:{rules: [{ required: false},{validator: this.validateInputUsername}]},
inputCode:{rules: [{ required: true, message: '请输入验证码!'},{validator: this.validateInputCode}]},
username: {rules: [{required: false}, {validator: this.validateInputUsername}]},
inputCode: {rules: [{required: true, message: '请输入验证码!'}, {validator: this.validateInputCode}]},
},
}
},
methods: {
nextStep () {
nextStep() {
let that = this
this.form.validateFields((err, values) => {
if (!err){
var params={}
var reg=/^[1-9]\d*$|^0$/;
var username=values.username;
if(reg.test(username)==true) {
params.phone=username;
}else{
params.username=username;
if (!err) {
let isPhone = false;
var params = {}
var reg = /^[1-9]\d*$|^0$/;
var username = values.username;
if (reg.test(username) == true) {
params.phone = username;
isPhone = true
} else {
params.username = username;
}
getAction("/sys/user/querySysUser", params).then((res) => {
if (res.success) {
var userList = {
username: res.result.username,
phone: res.result.phone,
isPhone: isPhone
};
setTimeout(function () {
that.$emit('nextStep', userList)
})
}
});
}
getAction("/sys/user/querySysUser",params).then((res)=>{
if(res.success){
var userList={
username:res.result.username,
phone:res.result.phone
};
setTimeout(function () {
that.$emit('nextStep',userList)
})
}
});
}
})
})
},
validateInputCode(rule, value, callback){
validateInputCode(rule, value, callback) {
if (!value || this.verifiedCode == this.inputCodeContent) {
callback();
} else {
callback(new Error("您输入的验证码不正确!"));
}
},
inputCodeChange(e){
inputCodeChange(e) {
this.inputCodeContent = e.target.value;
console.log(this.inputCodeContent)
if(!e.target.value||0==e.target.value){
this.inputCodeNull=true
}else{
if (!e.target.value || 0 == e.target.value) {
this.inputCodeNull = true
} else {
this.inputCodeContent = this.inputCodeContent.toLowerCase()
this.inputCodeNull=false
this.inputCodeNull = false
}
},
generateCode(value){
generateCode(value) {
this.verifiedCode = value.toLowerCase();
console.log(this.verifiedCode);
},
validateInputUsername(rule, value, callback){
validateInputUsername(rule, value, callback) {
console.log(value);
var reg=/^[0-9]+.?[0-9]*/;
if(!value){
var reg = /^[0-9]+.?[0-9]*/;
if (!value) {
callback("请输入用户名和手机号!");
}
//判断用户输入账号还是手机号码
if(reg.test(value)){
if (reg.test(value)) {
var params = {
phone : value,
phone: value,
};
checkOnlyUser(params).then((res) => {
if (res.success) {
callback("用户名不存在!")
} else {
callback()
}
})
}else{
callback("用户名不存在!")
} else {
callback()
}
})
} else {
var params = {
username: value,
};

View File

@ -1,80 +1,79 @@
<template>
<div>
<a-form :form="form" style="max-width: 500px; margin: 40px auto 0;">
<a-form-item
label="账号名"
:labelCol="{span: 5}"
:wrapperCol="{span: 19}"
>
<a-input
type="text"
autocomplete="false"
:style="{width:'310px'}"
:value="accountName"
disabled>
</a-input>
</a-form-item>
<a-form-item
label="手机"
:labelCol="{span: 5}"
:wrapperCol="{span: 19}"
>
<a-input
type="text"
autocomplete="false"
:style="{width:'310px'}"
placeholder="请输入手机号"
:value="phone"
disabled>
<a-icon slot="prefix" type="phone" :style="{ color: 'rgba(0,0,0,.25)'}" />
</a-input>
</a-form-item>
<a-form :form="form" style="max-width: 500px; margin: 40px auto 0;" @keyup.enter.native="nextStep">
<a-form-item
label="账号名"
:labelCol="{span: 5}"
:wrapperCol="{span: 19}"
>
<a-input
type="text"
autocomplete="false"
:style="{width:'310px'}"
:value="accountName"
disabled>
</a-input>
</a-form-item>
<a-form-item
label="手机"
:labelCol="{span: 5}"
:wrapperCol="{span: 19}"
>
<a-input
type="text"
autocomplete="false"
:style="{width:'310px'}"
v-decorator="['phone',{initialValue: defaultPhone, rules: validatorRules.phone.rule}]"
placeholder="请输入手机号">
<a-icon slot="prefix" type="phone" :style="{ color: 'rgba(0,0,0,.25)'}"/>
</a-input>
</a-form-item>
<a-form-item
label="验证码"
:labelCol="{span: 5}"
:wrapperCol="{span: 19}"
v-if="show">
<a-row :gutter="16" style="margin-left: 35px">
<a-col class="gutter-row" :span="10">
<a-input
v-decorator="['captcha',validatorRules.captcha]"
type="text"
placeholder="手机短信验证码" >
</a-input>
</a-col>
<a-col class="gutter-row" :span="8" >
<a-button
tabindex="-1"
size="default"
:disabled="state.smsSendBtn"
@click.stop.prevent="getCaptcha"
v-text="!state.smsSendBtn && '获取验证码' || (state.time+' s')"></a-button>
</a-col>
</a-row>
<a-row :gutter="16" style="margin-left: 2px">
<a-col class="gutter-row" :span="12">
<a-input
v-decorator="['captcha',validatorRules.captcha]"
type="text"
placeholder="手机短信验证码">
</a-input>
</a-col>
<a-col class="gutter-row" :span="8">
<a-button
tabindex="-1"
size="default"
:disabled="state.smsSendBtn"
@click.stop.prevent="getCaptcha"
v-text="!state.smsSendBtn && '获取验证码' || (state.time+' s')"></a-button>
</a-col>
</a-row>
</a-form-item>
<a-form-item :wrapperCol="{span: 19, offset: 5}">
<a-button style="margin-left: 8px" @click="prevStep">上一步</a-button>
<a-button type="primary" @click="nextStep" style="margin-left: 20px">下一步</a-button>
</a-form-item>
<a-button style="margin-left: 8px" @click="prevStep">上一步</a-button>
<a-button type="primary" @click="nextStep" style="margin-left: 20px">下一步</a-button>
</a-form-item>
</a-form>
</div>
</template>
<script>
import { postAction } from '@/api/manage'
import {postAction} from '@/api/manage'
export default {
name: "Step2",
props:['userList'],
data () {
props: ['userList'],
data() {
return {
form: this.$form.createForm(this),
loading: false,
accountName:this.userList.username,
phone:this.userList.phone,
dropList:"0",
accountName: this.userList.username,
dropList: "0",
captcha: "",
show:true,
show: true,
state: {
time: 60,
smsSendBtn: false,
@ -83,58 +82,66 @@
captcha: "",
mobile: "",
},
validatorRules:{
captcha:{rule: [{ required: true, message: '请输入短信验证码!'},{validator:this.validateCaptcha}]},
validatorRules: {
captcha: {rule: [{required: true, message: '请输入短信验证码!'}, {validator: this.validateCaptcha}]},
phone: {rule: [{required: true, message: '请输入手机号码!'}]},
},
}
},
computed: {
defaultPhone: function(){
if(this.userList.isPhone){
return this.userList.phone
}
return null;
}
},
methods: {
nextStep () {
nextStep() {
let that = this
that.loading = true
this.form.validateFields((err, values) => {
console.log(values);
if (!err) {
if(that.dropList=="0"){
if(values.captcha==undefined){
if (that.dropList == "0") {
if (values.captcha == undefined) {
this.cmsFailed("请输入短信验证码!");
}else{
var params={}
params.phone=this.userList.phone;
params.smscode=values.captcha;
postAction("/sys/user/phoneVerification",params).then((res)=>{
if(res.success){
console.log(res);
var userList={
username:this.userList.username,
phone:this.userList.phone,
smscode:res.result
};
setTimeout(function () {
that.$emit('nextStep',userList)
},0)
}else{
this.cmsFailed(res.message);
}
})
} else {
var params = {}
params.phone = this.userList.phone;
params.smscode = values.captcha;
postAction("/sys/user/phoneVerification", params).then((res) => {
if (res.success) {
console.log(res);
var userList = {
username: this.userList.username,
phone: this.userList.phone,
smscode: res.result
};
setTimeout(function () {
that.$emit('nextStep', userList)
}, 0)
} else {
this.cmsFailed(res.message);
}
})
}
}
}
})
}
})
},
prevStep () {
this.$emit('prevStep',this.userList);
prevStep() {
this.$emit('prevStep', this.userList);
},
getCaptcha (e) {
getCaptcha(e) {
e.preventDefault();
let that = this;
this.state.smsSendBtn = true;
let interval = window.setInterval(() => {
if (that.state.time-- <= 0) {
this.state.smsSendBtn = true;
let interval = window.setInterval(() => {
if (that.state.time-- <= 0) {
that.state.time = 60;
that.state.smsSendBtn = false;
window.clearInterval(interval);
@ -147,30 +154,30 @@
smsmode: "2"
};
postAction("/sys/sms", smsParams).then(res => {
if(!res.success ){
setTimeout(hide, 1);
this.cmsFailed(res.message);
}
setTimeout(hide, 500);
})
if (!res.success) {
setTimeout(hide, 1);
this.cmsFailed(res.message);
}
setTimeout(hide, 500);
})
},
cmsFailed(err){
this.$notification[ 'error' ]({
cmsFailed(err) {
this.$notification['error']({
message: "验证错误",
description:err,
description: err,
duration: 4,
});
},
handleChangeSelect(value){
var that=this;
handleChangeSelect(value) {
var that = this;
console.log(value);
if(value==0){
that.dropList="0";
that.show=true;
}else{
that.dropList="1";
that.show=false;
}
if (value == 0) {
that.dropList = "0";
that.show = true;
} else {
that.dropList = "1";
that.show = false;
}
},
}
@ -181,10 +188,11 @@
.stepFormText {
margin-bottom: 24px;
}
.ant-form-item-label,
.ant-form-item-control {
line-height: 22px;
}
.ant-form-item-label,
.ant-form-item-control {
line-height: 22px;
}
.getCaptcha {
display: block;

View File

@ -30,7 +30,6 @@ module.exports = {
.set('@comp', resolve('src/components'))
.set('@views', resolve('src/views'))
.set('@layout', resolve('src/layout'))
.set('@static', resolve('src/static'))
},
css: {

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,7 @@ RUN cd /etc/yum.repos.d/ \
# 前端迁移到系统文件中 默认是80端口 同级目录下的html地址
ADD ant-design-vue-jeecg/dist/ /var/www/html/
# 拷贝相关的jar包
ADD jeecg-boot/jeecg-boot-module-system/target/jeecg-boot-module-system-2.1.1.jar jeecgboot.jar
ADD jeecg-boot/jeecg-boot-module-system/target/jeecg-boot-module-system-2.1.4.jar jeecgboot.jar
EXPOSE 80 8080 81
ENTRYPOINT /bin/sh -c /etc/init.d/start.sh

View File

@ -1,7 +1,7 @@
Jeecg-Boot 快速开发平台
===============
当前最新版本: 2.1.3发布日期20191226
当前最新版本: 2.1.4发布日期20200224
## 后端技术架构
@ -37,11 +37,11 @@ Jeecg-Boot 快速开发平台
## 技术文档
- 在线演示 [http://boot.jeecg.org](http://boot.jeecg.org)
- 在线演示 [http://boot.jeecg.com](http://boot.jeecg.com)
- 在线文档: [http://doc.jeecg.com/1273753](http://doc.jeecg.com/1273753)
- 常见问题: [入门常见问题大全](http://www.jeecg.org/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
- 常见问题: [入门常见问题大全](http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1)
- QQ交流群 ①284271917、②769925425

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More