Jeecg Boot 2.2.1 版本发布,低代码平台

This commit is contained in:
zhangdaiscott
2020-07-11 12:54:57 +08:00
parent cb7ae9ca6f
commit 109a95a96b
191 changed files with 28087 additions and 26880 deletions

View File

@ -7,7 +7,7 @@
<a-radio-button v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio-button>
</a-radio-group>
<a-select v-else-if="tagType=='select'" :getPopupContainer = "(target) => target.parentNode" :placeholder="placeholder" :disabled="disabled" :value="getValueSting" @change="handleInput">
<a-select v-else-if="tagType=='select'" :getPopupContainer = "getPopupContainer" :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 ">
@ -28,7 +28,11 @@
triggerChange: Boolean,
disabled: Boolean,
value: [String, Number],
type: String
type: String,
getPopupContainer:{
type: Function,
default: (node) => node.parentNode
}
},
data() {
return {
@ -56,7 +60,10 @@
},
computed: {
getValueSting(){
return this.value != null ? this.value.toString() : null;
// update-begin author:wangshuai date:20200601 for: 不显示placeholder的文字 ------
// 当有null或“” placeholder不显示
return this.value != null ? this.value.toString() : undefined;
// update-end author:wangshuai date:20200601 for: 不显示placeholder的文字 ------
},
},
methods: {

View File

@ -36,15 +36,20 @@ export async function initDictOptions(dictCode) {
*/
export function filterDictText(dictOptions, text) {
// --update-begin----author:sunjianlei---date:20200323------for: 字典翻译 text 允许逗号分隔 ---
if (text != null && dictOptions instanceof Array) {
if (text != null && Array.isArray(dictOptions)) {
let result = []
// 允许多个逗号分隔
let splitText = text.toString().trim().split(',')
// 允许多个逗号分隔,允许传数组对象
let splitText
if (Array.isArray(text)) {
splitText = text
} else {
splitText = text.toString().trim().split(',')
}
for (let txt of splitText) {
let dictText = txt
for (let dictItem of dictOptions) {
if (txt === dictItem.value.toString()) {
dictText = dictItem.text
if (txt.toString() === dictItem.value.toString()) {
dictText = (dictItem.text || dictItem.title || dictItem.label)
break
}
}

View File

@ -1,7 +1,10 @@
<template>
<div v-if="!reloading" class="j-area-linkage">
<div class="j-area-linkage">
<div v-if="reloading">
<span> Reloading... </span>
</div>
<area-cascader
v-if="_type === enums.type[0]"
v-else-if="_type === enums.type[0]"
:value="innerValue"
:data="pcaa"
:level="1"
@ -90,19 +93,23 @@
this.initAreaData();
},
methods: {
/** 重新加载组件 */
reload() {
this.reloading = true
this.$nextTick(() => this.reloading = false)
},
/** 通过 value 反推 options */
loadDataByValue(value) {
if(!value || value.length==0){
if (!value || value.length === 0) {
this.innerValue = []
this.reloading = true;
setTimeout(()=>{
this.reloading = false
},100)
}else{
this.initAreaData();
let arr = this.areaData.getRealCode(value);
} else {
this.initAreaData()
let arr = this.areaData.getRealCode(value)
this.innerValue = arr
}
this.reload()
},
/** 通过地区code获取子级 */
loadDataByCode(value) {

View File

@ -196,9 +196,14 @@
if(!value){
this.$emit('change', '');
this.treeValue = ''
} else if (value instanceof Array) {
//this.$emit('change', value.map(item => item.value).join(','))
//this.treeValue = value
} else if (Array.isArray(value)) {
let labels = []
let values = value.map(item => {
labels.push(item.label)
return item.value
})
this.backValue(values.join(','), labels.join(','))
this.treeValue = value
} else {
this.backValue(value.value,value.label)
this.treeValue = value

View File

@ -46,6 +46,8 @@
import 'codemirror/mode/swift/swift.js'
import 'codemirror/mode/vue/vue.js'
import { isIE11, isIE } from '@/utils/browser'
// 尝试获取全局实例
const CodeMirror = window.CodeMirror || _CodeMirror
@ -85,7 +87,21 @@
zIndex: {
type: [Number, String],
default: 999
}
},
// 是否自适应高度可以传String或Boolean
// 传 String 类型只能写"!ie"
// 填写这个字符串,代表其他浏览器自适应高度
// 唯独IE下不自适应高度因为IE下不支持min、max-height样式
// 如果填写的不是"!ie"就视为true
autoHeight: {
type: [String, Boolean],
default: true
},
// 不自适应高度的情况下生效的固定高度
height: {
type: [String, Number],
default: '240px'
},
},
data () {
return {
@ -217,14 +233,30 @@
hintOptions: this.options.hintOptions
}
},
fullScreenParentProps(){
isAutoHeight() {
let {autoHeight} = this
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
autoHeight = !(isIE() || isIE11())
} else {
autoHeight = true
}
return autoHeight
},
fullScreenParentProps() {
let props = {
class: ['full-screen-parent', this.fullCoder ? 'full-screen' : ''],
class: {
'full-screen-parent': true,
'full-screen': this.fullCoder,
'auto-height': this.isAutoHeight
},
style: {}
}
if (this.fullCoder) {
props.style['z-index'] = this.zIndex
}
if (!this.isAutoHeight) {
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
}
return props
}
},
@ -240,7 +272,8 @@
// 编辑器赋值
if(this.value||this.code){
this.hasCode=true
this.coder.setValue(this.value || this.code)
//this.coder.setValue(this.value || this.code)
this.setCodeContent(this.value || this.code)
}else{
this.coder.setValue('')
this.hasCode=false
@ -408,6 +441,7 @@
top: 12px;
right: 12px;
}
.full-screen-child {
height: 100%;
max-height: 100%;
@ -416,9 +450,22 @@
}
.full-screen-child {
min-height: 120px;
max-height: 320px;
overflow:hidden;
height: 100%;
}
&.auto-height {
.full-screen-child {
min-height: 120px;
max-height: 320px;
height: unset;
overflow: hidden;
}
&.full-screen .full-screen-child {
height: 100%;
max-height: 100%;
min-height: 100%;
}
}
}

View File

@ -1,5 +1,6 @@
<template>
<a-date-picker
dropdownClassName="j-date-picker"
:disabled="disabled || readOnly"
:placeholder="placeholder"
@change="handleDateChange"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
<template>
<div class="tinymce-editor">
<editor
v-if="!reloading"
v-model="myValue"
:init="init"
:disabled="disabled"
@ -23,7 +24,9 @@
import 'tinymce/plugins/colorpicker'
import 'tinymce/plugins/textcolor'
import 'tinymce/plugins/fullscreen'
import 'tinymce/icons/default'
import { uploadAction,getFileAccessHttpUrl } from '@/api/manage'
import { getVmParentByName } from '@/utils/util'
export default {
components: {
Editor
@ -83,21 +86,51 @@
})
}
},
myValue: this.value
myValue: this.value,
reloading: false,
}
},
mounted() {
tinymce.init({})
this.initATabsChangeAutoReload()
},
methods: {
reload() {
this.reloading = true
this.$nextTick(() => this.reloading = false)
},
onClick(e) {
this.$emit('onClick', e, tinymce)
},
//可以添加一些自己的自定义事件,如清空内容
clear() {
this.myValue = ''
}
},
/**
* 自动判断父级是否是 <a-tabs/> 组件然后添加事件监听自动触发reload()
*
* 由于 tabs 组件切换会导致 tinymce 无法输入,
* 只有重新加载才能使用无论是vue版的还是jQuery版tinymce都有这个通病
*/
initATabsChangeAutoReload() {
// 获取父级
let tabs = getVmParentByName(this, 'ATabs')
let tabPane = getVmParentByName(this, 'ATabPane')
if (tabs && tabPane) {
// 用户自定义的 key
let currentKey = tabPane.$vnode.key
// 添加事件监听
tabs.$on('change', (key) => {
// 切换到自己时执行reload
if (currentKey === key) {
this.reload()
}
})
}
},
},
watch: {
value(newValue) {

View File

@ -86,6 +86,9 @@
} else {
this.initFileList(val)
}
if(!val || val.length==0){
this.picUrl = false;
}
}
},
created(){

View File

@ -0,0 +1,30 @@
export default {
minHeight: '200px',
previewStyle: 'vertical',
useCommandShortcut: true,
useDefaultHTMLSanitizer: true,
usageStatistics: false,
hideModeSwitch: false,
toolbarItems: [
'heading',
'bold',
'italic',
'strike',
'divider',
'hr',
'quote',
'divider',
'ul',
'ol',
'task',
'indent',
'outdent',
'divider',
'table',
'image',
'link',
'divider',
'code',
'codeblock'
]
}

View File

@ -0,0 +1,134 @@
<template>
<div class="j-markdown-editor" :id="id"/>
</template>
<script>
import 'codemirror/lib/codemirror.css'
import '@toast-ui/editor/dist/toastui-editor.css';
import '@toast-ui/editor/dist/i18n/zh-cn';
import Editor from '@toast-ui/editor';
import defaultOptions from './default-options'
export default {
name: 'JMarkdownEditor',
props: {
value: {
type: String,
default: ''
},
id: {
type: String,
required: false,
default() {
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
}
},
options: {
type: Object,
default() {
return defaultOptions
}
},
mode: {
type: String,
default: 'markdown'
},
height: {
type: String,
required: false,
default: '300px'
},
language: {
type: String,
required: false,
default: 'zh-CN'
}
},
data() {
return {
editor: null
}
},
computed: {
editorOptions() {
const options = Object.assign({}, defaultOptions, this.options)
options.initialEditType = this.mode
options.height = this.height
options.language = this.language
return options
}
},
watch: {
value(newValue, preValue) {
if (newValue !== preValue && newValue !== this.editor.getMarkdown()) {
this.editor.setMarkdown(newValue)
}
},
language(val) {
this.destroyEditor()
this.initEditor()
},
height(newValue) {
this.editor.height(newValue)
},
mode(newValue) {
this.editor.changeMode(newValue)
}
},
mounted() {
this.initEditor()
},
destroyed() {
this.destroyEditor()
},
methods: {
initEditor() {
this.editor = new Editor({
el: document.getElementById(this.id),
...this.editorOptions
})
if (this.value) {
this.editor.setMarkdown(this.value)
}
this.editor.on('change', () => {
this.$emit('change', this.editor.getMarkdown())
})
},
destroyEditor() {
if (!this.editor) return
this.editor.off('change')
this.editor.remove()
},
setMarkdown(value) {
this.editor.setMarkdown(value)
},
getMarkdown() {
return this.editor.getMarkdown()
},
setHtml(value) {
this.editor.setHtml(value)
},
getHtml() {
return this.editor.getHtml()
}
},
model: {
prop: 'value',
event: 'change'
}
}
</script>
<style scoped lang="less">
.j-markdown-editor {
/deep/ .tui-editor-defaultUI {
.te-mode-switch,
.tui-scrollsync
{
line-height: 1.5;
}
}
}
</style>

View File

@ -39,6 +39,7 @@
<script>
import { getClass, getStyle } from '@/utils/props-util'
import { triggerWindowResizeEvent } from '@/utils/util'
export default {
name: 'JModal',
@ -151,6 +152,7 @@
/** 切换全屏 */
toggleFullscreen() {
this.innerFullscreen = !this.innerFullscreen
triggerWindowResizeEvent()
},
}
@ -165,7 +167,12 @@
left: 0;
padding: 0;
height: 100vh;
// 兼容1.6.2版本的antdv
& .ant-modal {
top: 0;
padding: 0;
height: 100vh;
}
& .ant-modal-content {
height: 100vh;
@ -189,7 +196,6 @@
height: 100%;
}
}
}
.j-modal-title-row {
@ -208,12 +214,9 @@
&:hover {
color: rgba(0, 0, 0, 0.75);
}
}
}
}
}
@media (max-width: 767px) {

View File

@ -0,0 +1,205 @@
<template>
<div class="components-input-demo-presuffix" v-if="avalid">
<!---->
<a-input @click="openModal" :placeholder="placeholder" v-model="showText" readOnly :disabled="disabled">
<a-icon slot="prefix" type="cluster" :title="title"/>
<a-icon v-if="showText" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
</a-input>
<j-popup-onl-report
ref="jPopupOnlReport"
:code="code"
:multi="multi"
:groupId="uniqGroupId"
@ok="callBack"
/>
</div>
</template>
<script>
import JPopupOnlReport from './modal/JPopupOnlReport'
export default {
name: 'JPopup',
components: {
JPopupOnlReport
},
props: {
code: {
type: String,
default: '',
required: false
},
field: {
type: String,
default: '',
required: false
},
orgFields: {
type: String,
default: '',
required: false
},
destFields: {
type: String,
default: '',
required: false
},
width: {
type: Number,
default: 1200,
required: false
},
placeholder: {
type: String,
default: '请选择',
required: false
},
value: {
type: String,
required: false
},
triggerChange: {
type: Boolean,
required: false,
default: false
},
disabled: {
type: Boolean,
required: false,
default: false
},
multi: {
type: Boolean,
required: false,
default: false
},
/** 分组ID用于将多个popup的请求合并到一起不传不分组 */
groupId: String
},
data() {
return {
showText: '',
title: '',
avalid: true
}
},
computed: {
uniqGroupId() {
if (this.groupId) {
let { groupId, code, field, orgFields, destFields } = this
return `${groupId}_${code}_${field}_${orgFields}_${destFields}`
}
}
},
watch: {
value: {
immediate: true,
handler: function(val) {
if (!val) {
this.showText = ''
} else {
this.showText = val
}
}
}
},
created() {
},
mounted() {
if (!this.orgFields || !this.destFields || !this.code) {
this.$message.error('popup参数未正确配置!')
this.avalid = false
}
if (this.destFields.split(',').length != this.orgFields.split(',').length) {
this.$message.error('popup参数未正确配置,原始值和目标值数量不一致!')
this.avalid = false
}
},
methods: {
openModal() {
if (this.disabled === false) {
this.$refs.jPopupOnlReport.show()
}
},
handleEmpty() {
this.showText = ''
let destFieldsArr = this.destFields.split(',')
if (destFieldsArr.length === 0) {
return
}
let res = {}
for (let i = 0; i < destFieldsArr.length; i++) {
res[destFieldsArr[i]] = ''
}
if (this.triggerChange) {
this.$emit('callback', res)
} else {
this.$emit('input', '', res)
}
},
callBack(rows) {
// update--begin--autor:lvdandan-----date:20200630------for多选时未带回多个值------
let orgFieldsArr = this.orgFields.split(',')
let destFieldsArr = this.destFields.split(',')
let resetText = false
if (this.field && this.field.length > 0) {
this.showText = ''
resetText = true
}
let res = {}
if (orgFieldsArr.length > 0) {
for (let i = 0; i < orgFieldsArr.length; i++) {
let tempDestArr = []
for(let rw of rows){
let val = rw[orgFieldsArr[i]]
if(!val){
val = ""
}
tempDestArr.push(val)
}
res[destFieldsArr[i]] = tempDestArr.join(",")
}
if (resetText === true) {
let tempText = []
for(let rw of rows){
let val = rw[orgFieldsArr[destFieldsArr.indexOf(this.field)]]
if(!val){
val = ""
}
tempText.push(val)
}
this.showText = tempText.join(",")
}
// update--end--autor:lvdandan-----date:20200630------for多选时未带回多个值------
}
if (this.triggerChange) {
//v-dec时即triggerChange为true时 将整个对象给form页面 让他自己setFieldsValue
this.$emit('callback', res)
} else {
//v-model时 需要传一个参数field 表示当前这个字段 从而根据这个字段的顺序找到原始值
// this.$emit("input",row[orgFieldsArr[destFieldsArr.indexOf(this.field)]])
this.$emit('input', this.showText, res)
}
}
}
}
</script>
<style scoped>
.components-input-demo-presuffix .anticon-close-circle {
cursor: pointer;
color: #ccc;
transition: color 0.3s;
font-size: 12px;
}
.components-input-demo-presuffix .anticon-close-circle:hover {
color: #f5222d;
}
.components-input-demo-presuffix .anticon-close-circle:active {
color: #666;
}
</style>

View File

@ -145,6 +145,10 @@
<j-date v-else-if=" item.type=='datetime' " v-model="item.val" placeholder="请选择时间" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"></j-date>
<a-time-picker v-else-if="item.type==='time'" :value="item.val ? moment(item.val,'HH:mm:ss') : null" format="HH:mm:ss" style="width: 100%" @change="(time,value)=>item.val=value"/>
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
<a-select v-else-if="item.type=='switch'" placeholder="请选择" v-model="item.val">
<a-select-option value="Y">是</a-select-option>
<a-select-option value="N">否</a-select-option>
</a-select>
<a-input v-else v-model="item.val" placeholder="请输入值"/>
</a-col>
@ -508,8 +512,17 @@
renderSaveTreeData(item) {
item.icon = this.treeIcon
item.originTitle = item['title']
item.title = (fn, vNode) => {
let { originTitle } = vNode.dataRef
item.title = (arg1, arg2) => {
let vNode
// 兼容旧版的Antdv
if (arg1.dataRef) {
vNode = arg1
} else if (arg2.dataRef) {
vNode = arg2
} else {
return <span style="color:red;">Antdv版本不支持</span>
}
let {originTitle} = vNode.dataRef
return (
<div class="j-history-tree-title">
<span>{originTitle}</span>

View File

@ -1,5 +1,12 @@
<template>
<a-switch v-model="checkStatus" :disabled="disabled" @change="handleChange"/>
<div>
<a-select v-if="query" style="width: 100%" @change="handleSelectChange">
<a-select-option v-for="(item, index) in queryOption" :key="index" :value="item.value">
{{ item.text }}
</a-select-option>
</a-select>
<a-switch v-else v-model="checkStatus" :disabled="disabled" @change="handleChange"/>
</div>
</template>
<script>
@ -7,7 +14,7 @@
name: 'JSwitch',
props: {
value:{
type: String,
type: String | Number,
required: false
},
disabled:{
@ -19,6 +26,11 @@
type:Array,
required:false,
default:()=>['Y','N']
},
query:{
type: Boolean,
required: false,
default: false
}
},
data () {
@ -30,23 +42,37 @@
value:{
immediate: true,
handler(val){
if(!val){
this.checkStatus = false
this.$emit('change', this.options[1]);
}else{
if(this.options[0]==val){
this.checkStatus = true
}else{
if(!this.query){
if(!val){
this.checkStatus = false
this.$emit('change', this.options[1]);
}else{
if(this.options[0]==val){
this.checkStatus = true
}else{
this.checkStatus = false
}
}
}
}
}
},
computed:{
queryOption(){
let arr = []
arr.push({value:this.options[0],text:'是'})
arr.push({value:this.options[1],text:'否'})
return arr;
}
},
methods: {
handleChange(checked){
let flag = checked===false?this.options[1]:this.options[0];
this.$emit('change', flag);
},
handleSelectChange(value){
this.$emit('change', value);
}
},
model: {

View File

@ -121,7 +121,6 @@
getAction(this.url_root,param).then(res=>{
if(res.success){
this.handleTreeNodeValue(res.result)
console.log("aaaa",res.result)
this.treeData = [...res.result]
}else{
this.$message.error(res.message)

View File

@ -236,7 +236,6 @@
}else{
try {
let test=JSON.parse(mycondition);
console.log("aaaaasdsdd",typeof test)
if(typeof test == 'object' && test){
resolve()
}else{

View File

@ -225,7 +225,13 @@
let arr = [];
for(var a=0;a<uploadFiles.length;a++){
arr.push(uploadFiles[a].response.message)
// update-begin-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时控制台报错
if(uploadFiles[a].status === 'done' ) {
arr.push(uploadFiles[a].response.message)
}else{
return;
}
// update-end-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时控制台报错
}
if(arr.length>0){
path = arr.join(",")
@ -279,12 +285,18 @@
//returnUrl为false时返回文件名称、文件路径及文件大小
this.newFileList = [];
for(var a=0;a<fileList.length;a++){
var fileJson = {
fileName:fileList[a].name,
filePath:fileList[a].response.message,
fileSize:fileList[a].size
};
this.newFileList.push(fileJson);
// update-begin-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时控制台报错
if(fileList[a].status === 'done' ) {
var fileJson = {
fileName:fileList[a].name,
filePath:fileList[a].response.message,
fileSize:fileList[a].size
};
this.newFileList.push(fileJson);
}else{
return;
}
// update-end-author:lvdandan date:20200603 for:【TESTA-514】【开源issue】多个文件同时上传时控制台报错
}
this.$emit('change', this.newFileList);
}

View File

@ -0,0 +1,65 @@
# JPopup 弹窗选择组件
## 参数配置
| 参数 | 类型 | 必填 |说明|
|--------------|---------|----|---------|
| placeholder |string | | placeholder |
| code |string | | online报表编码 |
| orgFields |string | | online报表中显示的列,多个以逗号隔开 |
| destFields |string | | 回调对象的属性,多个以逗号隔开,其顺序和orgFields一一对应 |
| field |string | | v-model模式专用,表示从destFields中选择一个属性的值返回给当前组件 |
| triggerChange |Boolean | | v-decorator模式下需设置成true |
| callback(事件) |function | | 回调事件,v-decorator模式下用到,用于设置form控件的值 |
使用示例
----
```vue
<template>
<a-form :form="form">
<a-form-item label="v-model模式指定一个值返回至当前组件" style="width: 300px">
<j-popup
v-model="selectValue"
code="user_msg"
org-fields="username,realname"
dest-fields="popup,other"
field="popup"/>
{{ selectValue }}
</a-form-item>
<a-form-item label="v-decorator模式支持回调多个值至当前表单" style="width: 300px">
<j-popup
v-decorator="['one']"
:trigger-change="true"
code="user_msg"
org-fields="username,realname"
dest-fields="one,two"
@callback="popupCallback"/>
{{ getFormFieldValue('one') }}
</a-form-item>
<a-form-item label="v-decorator模式被回调的值" style="width: 300px">
<a-input v-decorator="['two']"></a-input>
</a-form-item>
</a-form >
</template>
<script>
export default {
data() {
return {
form: this.$form.createForm(this),
selectValue:"",
}
},
methods:{
getFormFieldValue(field){
return this.form.getFieldValue(field)
},
popupCallback(row){
this.form.setFieldsValue(row)
}
}
}
</script>

View File

@ -1,9 +1,11 @@
import JModal from './JModal'
import JFormContainer from './JFormContainer.vue'
import JPopup from './JPopup.vue'
export default {
install(Vue) {
Vue.component('JFormContainer', JFormContainer)
Vue.component('JPopup', JPopup)
Vue.component(JModal.name, JModal)
}
}

View File

@ -1,5 +1,5 @@
<template>
<a-popover trigger="contextmenu" v-model="visible" :placement="position">
<a-popover trigger="contextmenu" v-model="visible" :placement="position" overlayClassName="j-input-pop">
<!--"(node) => node.parentNode.parentNode"-->
<div slot="title">
<span>{{ title }}</span>
@ -7,11 +7,11 @@
<a-icon type="close" @click="visible=false"/>
</span>
</div>
<a-input :value="inputContent" @change="handleInputChange">
<a-input :value="inputContent" :disabled="disabled" @change="handleInputChange">
<a-icon slot="suffix" type="fullscreen" @click.stop="pop" />
</a-input>
<div slot="content">
<textarea :value="inputContent" @input="handleInputChange" :style="{ height: height + 'px', width: width + 'px' }"></textarea>
<textarea :value="inputContent" :disabled="disabled" @input="handleInputChange" :style="{ height: height + 'px', width: width + 'px' }"></textarea>
</div>
</a-popover>
</template>
@ -48,7 +48,11 @@
type:String,
default:'',
required:false
}
},
disabled: {
type: Boolean,
default: false,
},
},
data(){

View File

@ -0,0 +1,326 @@
<template>
<j-modal
:title="title"
:width="modalWidth"
:visible="visible"
:confirmLoading="confirmLoading"
switchFullscreen
wrapClassName="j-popup-modal"
@ok="handleSubmit"
@cancel="handleCancel"
cancelText="关闭">
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchByquery">
<a-row :gutter="24" v-if="showSearchFlag">
<template v-for="(item,index) in queryInfo">
<template v-if=" item.hidden==='1' ">
<a-col :md="8" :sm="24" :key=" 'query'+index " v-show="toggleSearchStatus">
<online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
</a-col>
</template>
<template v-else>
<a-col :md="8" :sm="24" :key=" 'query'+index ">
<online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
</a-col>
</template>
</template>
<a-col :md="8" :sm="8">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchByquery" 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="ant-alert ant-alert-info" style="margin-bottom: 16px;">
<i class="anticon anticon-info-circle ant-alert-icon"></i>
已选择&nbsp;<a style="font-weight: 600">{{ table.selectedRowKeys.length }}</a>项&nbsp;&nbsp;
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
<a v-if="!showSearchFlag" style="margin-left: 24px" @click="onlyReload">刷新</a>
</div>
<a-table
ref="table"
size="middle"
bordered
:rowKey="combineRowKey"
:columns="table.columns"
:dataSource="table.dataSource"
:pagination="table.pagination"
:loading="table.loading"
:rowSelection="{fixed:true,selectedRowKeys: table.selectedRowKeys, onChange: handleChangeInTableSelect}"
@change="handleChangeInTable"
style="min-height: 300px"
:scroll="tableScroll"
:customRow="clickThenCheck">
</a-table>
</j-modal>
</template>
<script>
import { getAction } from '@/api/manage'
import {filterObj} from '@/utils/util'
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
import { httpGroupRequest } from '@/api/GroupRequest.js'
const MODAL_WIDTH = 1200;
export default {
name: 'JPopupOnlReport',
props: ['multi', 'code', 'groupId'],
components:{
},
data(){
return {
visible:false,
title:"",
confirmLoading:false,
queryInfo:[],
toggleSearchStatus:false,
queryParam:{
},
dictOptions: {},
url: {
getColumns: '/online/cgreport/api/getRpColumns/',
getData: '/online/cgreport/api/getData/',
getQueryInfo: '/online/cgreport/api/getQueryInfo/'
},
table: {
loading: true,
// 表头
columns: [],
//数据集
dataSource: [],
// 选择器
selectedRowKeys: [],
selectionRows: [],
// 分页参数
pagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '30'],
showTotal: (total, range) => {
return range[0] + '-' + range[1] + ' 共' + total + '条'
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
}
},
cgRpConfigId:"",
modalWidth:MODAL_WIDTH,
tableScroll:{x:MODAL_WIDTH-100}
}
},
mounted() {
this.loadColumnsInfo()
},
watch: {
code() {
this.loadColumnsInfo()
}
},
computed:{
showSearchFlag(){
return this.queryInfo && this.queryInfo.length>0
}
},
methods:{
loadColumnsInfo(){
let url = `${this.url.getColumns}${this.code}`
//缓存key
let groupIdKey
if (this.groupId) {
groupIdKey = this.groupId + url
}
httpGroupRequest(() => getAction(url), groupIdKey).then(res => {
if(res.success){
this.initDictOptionData(res.result.dictOptions);
this.cgRpConfigId = res.result.cgRpConfigId
this.title = res.result.cgRpConfigName
let currColumns = res.result.columns
for(let a=0;a<currColumns.length;a++){
if(currColumns[a].customRender){
let dictCode = currColumns[a].customRender;
currColumns[a].customRender=(text)=>{
return filterMultiDictText(this.dictOptions[dictCode], text+"");
}
}
}
this.table.columns = [...currColumns]
this.initQueryInfo()
this.loadData(1)
}
})
},
initQueryInfo() {
let url = `${this.url.getQueryInfo}${this.cgRpConfigId}`
//缓存key
let groupIdKey
if (this.groupId) {
groupIdKey = this.groupId + url
}
httpGroupRequest(() => getAction(url), groupIdKey).then((res) => {
// console.log("获取查询条件", res);
if (res.success) {
this.queryInfo = res.result
} else {
this.$message.warning(res.message)
}
})
},
loadData(arg) {
if (arg == 1) {
this.table.pagination.current = 1
}
let params = this.getQueryParams();//查询条件
this.table.loading = true
let url = `${this.url.getData}${this.cgRpConfigId}`
//缓存key
let groupIdKey
if (this.groupId) {
groupIdKey = this.groupId + url + JSON.stringify(params)
}
httpGroupRequest(() => getAction(url, params), groupIdKey).then(res => {
this.table.loading = false
// console.log("daa",res)
let data = res.result
if (data) {
this.table.pagination.total = Number(data.total)
this.table.dataSource = data.records
} else {
this.table.pagination.total = 0
this.table.dataSource = []
}
})
},
getQueryParams() {
let param = Object.assign({}, this.queryParam, this.sorter);
param.pageNo = this.table.pagination.current;
param.pageSize = this.table.pagination.pageSize;
return filterObj(param);
},
handleChangeInTableSelect(selectedRowKeys, selectionRows) {
this.table.selectedRowKeys = selectedRowKeys
this.table.selectionRows = selectionRows
},
handleChangeInTable(pagination, filters, sorter) {
//分页、排序、筛选变化时触发
if (Object.keys(sorter).length > 0) {
this.sorter.column = sorter.field
this.sorter.order = 'ascend' == sorter.order ? 'asc' : 'desc'
}
this.table.pagination = pagination
this.loadData()
},
handleCancel() {
this.close()
},
handleSubmit() {
if(!this.multi){
if(this.table.selectionRows && this.table.selectionRows.length>1){
this.$message.warning("请选择一条记录")
return false
}
}
if(!this.table.selectionRows || this.table.selectionRows.length==0){
this.$message.warning("请选择一条记录")
return false
}
this.$emit('ok', this.table.selectionRows);
this.close()
},
close() {
this.$emit('close');
this.visible = false;
this.onClearSelected()
},
show(){
this.visible = true;
},
handleToggleSearch(){
this.toggleSearchStatus = !this.toggleSearchStatus;
},
searchByquery(){
this.loadData(1);
},
onlyReload(){
this.loadData();
},
searchReset(){
Object.keys(this.queryParam).forEach(key=>{
this.queryParam[key]=""
})
this.loadData(1);
},
onClearSelected(){
this.table.selectedRowKeys = []
this.table.selectionRows = []
},
combineRowKey(record){
let res = ''
Object.keys(record).forEach(key=>{
res+=record[key]
})
if(res.length>50){
res = res.substring(0,50)
}
return res
},
clickThenCheck(record){
return {
on: {
click: () => {
let rowKey = this.combineRowKey(record)
if(!this.table.selectedRowKeys || this.table.selectedRowKeys.length==0){
let arr1=[],arr2=[]
arr1.push(record)
arr2.push(rowKey)
this.table.selectedRowKeys=arr2
this.table.selectionRows=arr1
}else{
if(this.table.selectedRowKeys.indexOf(rowKey)<0){
this.table.selectedRowKeys.push(rowKey)
this.table.selectionRows.push(record)
}else{
let rowKey_index = this.table.selectedRowKeys.indexOf(rowKey)
this.table.selectedRowKeys.splice(rowKey_index,1);
this.table.selectionRows.splice(rowKey_index,1);
}
}
}
}
}
},
//防止字典中有垃圾数据
initDictOptionData(dictOptions){
let obj = { }
Object.keys(dictOptions).map(k=>{
obj[k] = dictOptions[k].filter(item=>{
return item!=null
});
});
this.dictOptions = obj
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,9 +1,10 @@
<template>
<a-modal
<j-modal
centered
:title="name + '选择'"
:width="width"
:visible="visible"
switchFullscreen
@ok="handleOk"
@cancel="close"
cancelText="关闭">
@ -32,7 +33,7 @@
</div>
<a-table
size="small"
size="middle"
bordered
:rowKey="rowKey"
:columns="innerColumns"
@ -49,7 +50,7 @@
<a-col :span="8">
<a-card :title="'已选' + name" :bordered="false" :head-style="{padding:0}" :body-style="{padding:0}">
<a-table size="small" :rowKey="rowKey" bordered v-bind="selectedTable">
<a-table size="middle" :rowKey="rowKey" bordered v-bind="selectedTable">
<span slot="action" slot-scope="text, record, index">
<a @click="handleDeleteSelected(record, index)">删除</a>
</span>
@ -58,7 +59,7 @@
</a-card>
</a-col>
</a-row>
</a-modal>
</j-modal>
</template>
<script>

View File

@ -118,10 +118,12 @@
deep: true,
handler(val) {
let rows = val.map(key => this.dataSourceMap[key])
this.$emit('select', rows)
let data = val.join(',')
this.$emit('input', data)
this.$emit('change', data)
if (data !== this.value) {
this.$emit('select', rows)
this.$emit('input', data)
this.$emit('change', data)
}
}
}
},

View File

@ -76,6 +76,18 @@
methods:{
initComp(departNames){
this.departNames = departNames
//update-begin-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
//TODO 当返回字段为部门名称时会有问题,因为部门名称不唯一
//返回字段不为id时根据返回字段获取id
if(this.customReturnField !== 'id' && this.value){
const dataList = this.$refs.innerDepartSelectModal.dataList;
console.log('this.value',this.value)
this.departIds = this.value.split(',').map(item => {
const data = dataList.filter(d=>d[this.customReturnField] === item)
return data.length > 0 ? data[0].id : ''
}).join(',')
}
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
},
openModal(){
this.$refs.innerDepartSelectModal.show()

View File

@ -19,7 +19,7 @@
import JSelectBizComponent from './JSelectBizComponent'
export default {
name: 'JSelectMultiUser',
name: 'JSelectRole',
components: { JSelectBizComponent },
props: ['value'],
data() {

View File

@ -1,11 +1,12 @@
<template>
<a-modal
<j-modal
title="选择部门"
:width="modalWidth"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="handleCancel"
switchFullscreen
cancelText="关闭">
<a-spin tip="Loading..." :spinning="false">
<a-input-search style="margin-bottom: 1px" placeholder="请输入部门名称按回车进行搜索" @search="onSearch" />
@ -31,7 +32,7 @@
</a-tree>
</a-spin>
</a-modal>
</j-modal>
</template>
<script>

View File

@ -1,13 +1,13 @@
<template>
<a-modal
<j-modal
:width="modalWidth"
:visible="visible"
:title="title"
switchFullscreen
@ok="handleSubmit"
@cancel="close"
style="top:50px"
cancelText="关闭"
style="margin-top: -70px"
wrapClassName="ant-modal-cust-warp"
>
<a-row :gutter="10" style="background-color: #ececec; padding: 10px; margin: -10px">
<a-col :md="6" :sm="24">
@ -51,7 +51,7 @@
</a-card>
</a-col>
</a-row>
</a-modal>
</j-modal>
</template>
<script>

View File

@ -82,16 +82,19 @@
if (this.$route.path != indexKey) {
this.addIndexToFirst()
}
// 复制一个route对象出来不能影响原route
let currentRoute = Object.assign({}, this.$route)
currentRoute.meta = Object.assign({}, currentRoute.meta)
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
let storeKey = 'route:title:' + this.$route.fullPath
let storeKey = 'route:title:' + currentRoute.fullPath
let routeTitle = this.$ls.get(storeKey)
if (routeTitle) {
this.$route.meta.title = routeTitle
currentRoute.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
this.pageList.push(currentRoute)
this.linkList.push(currentRoute.fullPath)
this.activePage = currentRoute.fullPath
},
mounted() {
},
@ -126,8 +129,11 @@
'activePage': function(key) {
let index = this.linkList.lastIndexOf(key)
let waitRouter = this.pageList[index]
this.$router.push(Object.assign({},waitRouter));
this.changeTitle(waitRouter.meta.title)
// 【TESTA-523】修复不允许重复跳转路由异常
if (waitRouter.fullPath !== this.$route.fullPath) {
this.$router.push(Object.assign({}, waitRouter))
this.changeTitle(waitRouter.meta.title)
}
},
'multipage': function(newVal) {
if(this.reloadFlag){
@ -352,7 +358,7 @@
}
.ant-tabs {
.tab-layout-tabs.ant-tabs {
&.ant-tabs-card .ant-tabs-tab {
@ -380,7 +386,7 @@
}
.ant-tabs.ant-tabs-card > .ant-tabs-bar {
.tab-layout-tabs.ant-tabs.ant-tabs-card > .ant-tabs-bar {
.ant-tabs-tab {
border: none !important;
border-bottom: 1px solid transparent !important;

View File

@ -43,6 +43,7 @@
</div>
</div>
</a-layout-header>
</template>
@ -58,7 +59,7 @@
components: {
UserMenu,
SMenu,
Logo
Logo,
},
mixins: [mixin],
props: {
@ -96,7 +97,8 @@
topNavHeader: {},
headerIndexRight: {},
topSmenuStyle: {}
}
},
chatStatus: '',
}
},
watch: {

View File

@ -131,10 +131,10 @@
//this.menus = this.mainRouters.find((item) => item.path === '/').children;
this.menus = this.permissionMenuList
// 根据后台配置菜单,重新排序加载路由信息
console.log('----加载菜单逻辑----')
console.log(this.mainRouters)
console.log(this.permissionMenuList)
console.log('----navTheme------'+this.navTheme)
//console.log('----加载菜单逻辑----')
//console.log(this.mainRouters)
//console.log(this.permissionMenuList)
//console.log('----navTheme------'+this.navTheme)
//--update-end----author:scott---date:20190320------for:根据后台菜单配置判断是否路由菜单字段动态选择是否生成路由为了支持参数URL菜单------
},
methods: {

View File

@ -124,7 +124,7 @@
// this.heartCheckFun();
},
destroyed: function () { // 离开页面生命周期函数
this.websocketclose();
this.websocketOnclose();
},
methods: {
timerFun() {
@ -186,10 +186,8 @@
}
},
toMyAnnouncement(){
this.$router.push({
path: '/isps/userAnnouncement',
name: 'isps-userAnnouncement'
path: '/isps/userAnnouncement'
});
},
modalFormOk(){
@ -202,7 +200,7 @@
// WebSocket与普通的请求所用协议有所不同ws等同于httpwss等同于https
var userId = store.getters.userInfo.id;
var url = window._CONFIG['domianURL'].replace("https://","wss://").replace("http://","ws://")+"/websocket/"+userId;
console.log(url);
//console.log(url);
this.websock = new WebSocket(url);
this.websock.onopen = this.websocketOnopen;
this.websock.onerror = this.websocketOnerror;
@ -232,7 +230,10 @@
//this.heartCheck.reset().start();
},
websocketOnclose: function (e) {
console.log("connection closed (" + e.code + ")");
console.log("connection closed (" + e + ")");
if(e){
console.log("connection closed (" + e.code + ")");
}
this.reconnect();
},
websocketSend(text) { // 数据发送

View File

@ -62,6 +62,10 @@
<a-icon type="cluster"/>
<span>切换部门</span>
</a-menu-item>
<a-menu-item key="6" @click="clearCache">
<a-icon type="sync"/>
<span>清理缓存</span>
</a-menu-item>
<!-- <a-menu-item key="2" disabled>
<a-icon type="setting"/>
<span>测试</span>
@ -94,7 +98,9 @@
import DepartSelect from './DepartSelect'
import { mapActions, mapGetters,mapState } from 'vuex'
import { mixinDevice } from '@/utils/mixin.js'
import { getFileAccessHttpUrl } from "@/api/manage"
import { getFileAccessHttpUrl,getAction } from "@/api/manage"
import Vue from 'vue'
import { UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
export default {
name: "UserMenu",
@ -168,7 +174,9 @@
content: '真的要注销登录吗 ?',
onOk() {
return that.Logout({}).then(() => {
window.location.href="/";
// update-begin author:wangshuai date:20200601 for: 退出登录跳转登录页面
that.$router.push({ path: '/user/login' });
// update-end author:wangshuai date:20200601 for: 退出登录跳转登录页面
//window.location.reload()
}).catch(err => {
that.$message.error({
@ -214,9 +222,28 @@
this.$router.push({ path: route.path })
}
this.searchMenuVisible = false
}
},
// update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
/*update_end author:zhaoxin date:20191129 for: 做头部菜单栏导航*/
/*update_begin author:liushaoqian date:20200507 for: 刷新缓存*/
clearCache(){
getAction("sys/dict/refleshCache").then((res) => {
if (res.success) {
//重新加载缓存
getAction("sys/dict/queryAllDictItems").then((res) => {
if (res.success) {
Vue.ls.remove(UI_CACHE_DB_DICT_DATA)
Vue.ls.set(UI_CACHE_DB_DICT_DATA, res.result, 7 * 24 * 60 * 60 * 1000)
}
})
this.$message.success("刷新缓存完成");
}
}).catch(e=>{
this.$message.warn("刷新缓存失败");
console.log("刷新失败",e)
})
}
/*update_end author:liushaoqian date:20200507 for: 刷新缓存*/
}
}
</script>

View File

@ -64,7 +64,7 @@ const updateTheme = primaryColor => {
const lessConfigNode = document.createElement('script');
const lessScriptNode = document.createElement('script');
lessStyleNode.setAttribute('rel', 'stylesheet/less');
lessStyleNode.setAttribute('href', '/color.less');
lessStyleNode.setAttribute('href', __webpack_public_path__ + 'color.less')
lessConfigNode.innerHTML = `
window.less = {
async: true,