Jeecg-Boot 2.1.0 版本发布,Online表单开发&在线代码生成器(迟到的版本)

This commit is contained in:
zhangdaihao
2019-08-24 00:15:45 +08:00
parent 839357789c
commit 5069209093
165 changed files with 13536 additions and 17580 deletions

View File

@ -45,11 +45,11 @@ const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleLi
const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params);
// 部门管理
const queryDepartTreeList = (params)=>getAction("/sysdepart/sysDepart/queryTreeList",params);
const queryIdTree = (params)=>getAction("/sysdepart/sysDepart/queryIdTree",params);
const queryParentName = (params)=>getAction("/sysdepart/sysDepart/queryParentName",params);
const searchByKeywords = (params)=>getAction("/sysdepart/sysDepart/searchBy",params);
const deleteByDepartId = (params)=>deleteAction("/sysdepart/sysDepart/delete",params);
const queryDepartTreeList = (params)=>getAction("/sys/sysDepart/queryTreeList",params);
const queryIdTree = (params)=>getAction("/sys/sysDepart/queryIdTree",params);
const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",params);
const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params);
const deleteByDepartId = (params)=>deleteAction("/sys/sysDepart/delete",params);
//日志管理
//const getLogList = (params)=>getAction("/sys/log/list",params);

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,73 @@
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
import store from '@/store'
/**
* 单点登录
*/
const init = (callback) => {
console.log("-------单点登录开始-------");
let token = Vue.ls.get(ACCESS_TOKEN);
let st = getUrlParam("ticket");
var sevice = "http://"+window.location.host+"/";
if(token){
loginSuccess(callback);
}else{
if(st){
validateSt(st,sevice,callback);
}else{
var serviceUrl = encodeURIComponent(sevice);
window.location.href = window._CONFIG['casPrefixUrl']+"/login?service="+serviceUrl;
}
}
console.log("-------单点登录结束-------");
};
const SSO = {
init: init
};
function getUrlParam(paraName) {
var url = document.location.toString();
var arrObj = url.split("?");
if (arrObj.length > 1) {
var arrPara = arrObj[1].split("&");
var arr;
for (var i = 0; i < arrPara.length; i++) {
arr = arrPara[i].split("=");
if (arr != null && arr[0] == paraName) {
return arr[1];
}
}
return "";
}
else {
return "";
}
}
function validateSt(ticket,service,callback){
let params = {
ticket: ticket,
service:service
};
store.dispatch('ValidateLogin',params).then(res => {
//this.departConfirm(res)
if(res.success){
loginSuccess(callback);
}else{
var sevice = "http://"+window.location.host+"/";
var serviceUrl = encodeURIComponent(sevice);
window.location.href = window._CONFIG['casPrefixUrl']+"/login?service="+serviceUrl;
}
}).catch((err) => {
console.log(err);
//that.requestFailed(err);
});
}
function loginSuccess (callback) {
callback();
}
export default SSO;

View File

@ -39,3 +39,5 @@ UserMenu.vue:首页右上侧的内容
![输入图片说明](https://static.oschina.net/uploads/img/201904/12201226_laQK.png "在这里输入图片标题")
####16.trend包 趋势显示组件(如下图)
![输入图片说明](https://static.oschina.net/uploads/img/201904/12201600_Wo8K.png "在这里输入图片标题")
![corn表达式](https://oscimg.oschina.net/oscnet/661f9ac09016395f9f49286143af3241623.jpg)
![corn控件添加清除按钮](https://oscimg.oschina.net/oscnet/15096e49f2e29bd829e304d56770025d03c.jpg)

View File

@ -32,7 +32,7 @@
type="arc"
:zIndex="1"
:start="arcGuide2Start"
:end="getArcGuide2End"
:end="getArcGuide2End()"
:vStyle="arcGuide2Style"
></v-guide>
<v-guide
@ -88,7 +88,7 @@
}];
const data = [
{ value: 7.0 },
{ value: 0},
];
export default {
@ -96,7 +96,7 @@
props:{
datasource:{
type: Number,
default:7
default:0
},
title: {
type: String,

View File

@ -0,0 +1,68 @@
<template>
<div class="components-input-demo-presuffix">
<a-input @click="openModal" placeholder="corn表达式" v-model="cron" @change="handleOK">
<a-icon slot="prefix" type="schedule" title="corn控件"/>
<a-icon v-if="cron" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
</a-input>
<JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal>
</div>
</template>
<script>
import JCronModal from "./modal/JCronModal";
export default {
name: 'JCron',
components: {
JCronModal
},
props: {
value: {
required: false,
type: String,
default:()=>{
return '* * * * * ? *'
}
}
},
data(){
return {
cron: this.value,
}
},
watch:{
value(val){
this.cron = val
}
},
methods:{
openModal(){
this.$refs.innerVueCron.show();
},
handleOK(val){
this.cron = val;
this.$emit("change", this.cron);
//this.$emit("change", Object.assign({}, this.cron));
},
handleEmpty(){
this.handleOK('')
}
},
model: {
prop: 'value',
event: 'change'
}
}
</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

@ -1,5 +1,5 @@
<!-- JEditableTable -->
<!-- @version 1.4.2 -->
<!-- @version 1.4.4 -->
<!-- @author sjlei -->
<template>
<a-spin :spinning="loading">
@ -26,6 +26,9 @@
<div class="thead" ref="thead">
<div class="tr" :style="{width: this.realTrWidth}">
<!-- 左侧固定td -->
<div v-if="dragSort" class="td td-ds" :style="style.tdLeftDs">
<span></span>
</div>
<div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
<!--:indeterminate="true"-->
<a-checkbox
@ -62,85 +65,95 @@
<div v-if="rows.length===0" class="tr-nodata">
<span>暂无数据</span>
</div>
<!-- 动态生成tr -->
<template v-for="(row,rowIndex) in rows">
<!-- tr 只加载可见的和预加载的总共十条数据 -->
<div
v-if="
<draggable v-model="rows" handle=".td-ds-icons" @end="handleDragMoveEnd">
<!-- 动态生成tr -->
<template v-for="(row,rowIndex) in rows">
<!-- tr 只加载可见的和预加载的总共十条数据 -->
<div
v-if="
rowIndex >= parseInt(`${(scrollTop-rowHeight) / rowHeight}`) &&
(parseInt(`${scrollTop / rowHeight}`) + 9) > rowIndex
"
:id="`${caseId}tbody-tr-${rowIndex}`"
:data-idx="rowIndex"
class="tr"
:class="selectedRowIds.indexOf(row.id) !== -1 ? 'tr-checked' : ''"
:style="buildTrStyle(rowIndex)"
:key="row.id">
<!-- 左侧固定td -->
<div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
<!-- 此 v-for 只是为了拼接 id 字符串 -->
<template v-for="(id,i) in [`${row.id}`]">
<a-checkbox
:id="id"
:key="i"
:checked="selectedRowIds.indexOf(id) !== -1"
@change="handleChangeLeftCheckbox"/>
</template>
</div>
<div v-if="rowNumber" class="td td-num" :style="style.tdLeft">
<span>{{ rowIndex+1 }}</span>
</div>
<!-- 右侧动态生成td -->
<div
class="td"
v-for="col in columns"
v-show="col.type !== formTypes.hidden"
:key="col.key"
:style="buildTdStyle(col)">
:id="`${caseId}tbody-tr-${rowIndex}`"
:data-idx="rowIndex"
class="tr"
:class="selectedRowIds.indexOf(row.id) !== -1 ? 'tr-checked' : ''"
:style="buildTrStyle(rowIndex)"
:key="row.id">
<!-- 左侧固定td -->
<!-- 此 v-for 只是为了拼接 id 字符串 -->
<template v-for="(id,i) in [`${col.key}${row.id}`]">
<div v-if="dragSort" class="td td-ds" :style="style.tdLeftDs">
<div class="td-ds-icons">
<a-icon type="align-left"/>
<a-icon type="align-right"/>
</div>
</div>
<!-- native input -->
<label :key="i" v-if="col.type === formTypes.input || col.type === formTypes.inputNumber">
<a-tooltip
<div v-if="rowSelection" class="td td-cb" :style="style.tdLeft">
<!-- 此 v-for 只是为了拼接 id 字符串 -->
<template v-for="(id,i) in [`${row.id}`]">
<a-checkbox
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:key="i"
:checked="selectedRowIds.indexOf(id) !== -1"
@change="handleChangeLeftCheckbox"/>
</template>
</div>
<div v-if="rowNumber" class="td td-num" :style="style.tdLeft">
<span>{{ rowIndex+1 }}</span>
</div>
<!-- 右侧动态生成td -->
<div
class="td"
v-for="col in columns"
v-show="col.type !== formTypes.hidden"
:key="col.key"
:style="buildTdStyle(col)">
<input
<!-- 此 v-for 只是为了拼接 id 字符串 -->
<template v-for="(id,i) in [`${col.key}${row.id}`]">
<!-- native input -->
<label :key="i" v-if="col.type === formTypes.input || col.type === formTypes.inputNumber">
<a-tooltip
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
<input
:id="id"
v-bind="buildProps(row,col)"
:data-input-number="col.type === formTypes.inputNumber"
:placeholder="replaceProps(col, col.placeholder)"
@input="(e)=>{handleInputCommono(e.target,rowIndex,row,col)}"
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@mouseout="()=>{handleMouseoutCommono(row,col)}"/>
</a-tooltip>
</label>
<!-- checkbox -->
<template v-else-if="col.type === formTypes.checkbox">
<a-checkbox
:key="i"
:id="id"
v-bind="buildProps(row,col)"
:data-input-number="col.type === formTypes.inputNumber"
:placeholder="replaceProps(col, col.placeholder)"
@input="(e)=>{handleInputCommono(e.target,rowIndex,row,col)}"
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@mouseout="()=>{handleMouseoutCommono(row,col)}"/>
</a-tooltip>
</label>
<!-- checkbox -->
<template v-else-if="col.type === formTypes.checkbox">
<a-checkbox
:key="i"
:id="id"
v-bind="buildProps(row,col)"
:checked="checkboxValues[id]"
@change="(e)=>handleChangeCheckboxCommon(e,row,col)"
/>
</template>
<!-- select -->
<template v-else-if="col.type === formTypes.select">
<a-tooltip
:key="i"
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
:checked="checkboxValues[id]"
@change="(e)=>handleChangeCheckboxCommon(e,row,col)"
/>
</template>
<!-- select -->
<template v-else-if="col.type === formTypes.select">
<a-tooltip
:key="i"
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@ -165,17 +178,17 @@
<!--</template>-->
</a-select>
</span>
</a-tooltip>
</template>
<!-- date -->
<template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">
<a-tooltip
:key="i"
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
</a-tooltip>
</template>
<!-- date -->
<template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">
<a-tooltip
:key="i"
:id="id"
placement="top"
:title="(tooltips[id] || {}).title"
:visible="(tooltips[id] || {}).visible || false"
:autoAdjustOverflow="true">
<span
@mouseover="()=>{handleMouseoverCommono(row,col)}"
@ -195,80 +208,81 @@
@change="(v)=>handleChangeJDateCommon(v,id,row,col,col.type === formTypes.datetime)"/>
</span>
</a-tooltip>
</template>
<div v-else-if="col.type === formTypes.upload" :key="i">
<template v-if="uploadValues[id] != null" v-for="(file,fileKey) of [(uploadValues[id]||{})]">
<a-input
:key="fileKey"
:readOnly="true"
:value="file.name"
>
<template slot="addonBefore" style="width: 30px">
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
<a-icon type="loading"/>
</a-tooltip>
<a-tooltip v-else-if="file.status==='done'" title="上传完成">
<a-icon type="check-circle" style="color:#00DB00;"/>
</a-tooltip>
<a-tooltip v-else title="上传失败">
<a-icon type="exclamation-circle" style="color:red;"/>
</a-tooltip>
</template>
<template slot="addonAfter" style="width: 30px">
<a-tooltip title="删除并重新上传">
<a-icon
v-if="file.status!=='uploading'"
type="close-circle"
style="cursor: pointer;"
@click="()=>handleClickDelFile(id)"/>
</a-tooltip>
</template>
</a-input>
</a-tooltip>
</template>
<div :hidden="uploadValues[id] != null">
<div v-else-if="col.type === formTypes.upload" :key="i">
<template v-if="uploadValues[id] != null" v-for="(file,fileKey) of [(uploadValues[id]||{})]">
<a-input
:key="fileKey"
:readOnly="true"
:value="file.name"
>
<template slot="addonBefore" style="width: 30px">
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
<a-icon type="loading"/>
</a-tooltip>
<a-tooltip v-else-if="file.status==='done'" title="上传完成">
<a-icon type="check-circle" style="color:#00DB00;"/>
</a-tooltip>
<a-tooltip v-else title="上传失败">
<a-icon type="exclamation-circle" style="color:red;"/>
</a-tooltip>
</template>
<template slot="addonAfter" style="width: 30px">
<a-tooltip title="删除并重新上传">
<a-icon
v-if="file.status!=='uploading'"
type="close-circle"
style="cursor: pointer;"
@click="()=>handleClickDelFile(id)"/>
</a-tooltip>
</template>
</a-input>
</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-button icon="upload">{{ col.placeholder }}</a-button>
</a-upload>
</div>
<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>
</div>
</div>
<div v-else-if="col.type === formTypes.slot" :key="i">
<slot
:name="(col.slot || col.slotName) || col.key"
:index="rowIndex"
:text="inputValues[rowIndex][col.key]"
:column="col"
:rowId="removeCaseId(row.id)"
:getValue="()=>_getValueForSlot(row.id)"
:target="getVM()"
/>
</div>
<div v-else-if="col.type === formTypes.slot" :key="i">
<slot
:name="(col.slot || col.slotName) || col.key"
:text="inputValues[rowIndex][col.key]"
:column="col"
:rowId="removeCaseId(row.id)"
:getValue="()=>_getValueForSlot(row.id)"
:target="getVM()"
/>
</div>
<!-- else (normal) -->
<span v-else :key="i">{{ inputValues[rowIndex][col.key] }}</span>
</template>
<!-- else (normal) -->
<span v-else :key="i">{{ inputValues[rowIndex][col.key] }}</span>
</template>
</div>
</div>
</div>
<!-- -- tr end -- -->
</template>
<!-- -- tr end -- -->
</template>
</draggable>
</div>
</div>
@ -278,6 +292,7 @@
<script>
import Vue from 'vue'
import Draggable from 'vuedraggable'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil'
import { cloneObject, randomString } from '@/utils/util'
@ -289,7 +304,7 @@
export default {
name: 'JEditableTable',
components: { JDate },
components: { JDate, Draggable },
props: {
// 列信息
columns: {
@ -338,7 +353,16 @@
disabled: {
type: Boolean,
default: false
}
},
// 是否可拖拽排序
dragSort: {
type: Boolean,
default: false
},
dragSortKey: {
type: String,
default: 'orderNum'
},
},
data() {
return {
@ -354,7 +378,8 @@
// 'max-height': '400px'
tbody: { left: '0px' },
// 左侧固定td的style
tdLeft: { 'min-width': '4%', 'max-width': '45px' }
tdLeft: { 'min-width': '4%', 'max-width': '45px' },
tdLeftDs: { 'min-width': '30px', 'max-width': '35px' },
},
// 表单的类型
formTypes: FormTypes,
@ -455,89 +480,92 @@
},
// 侦听器
watch: {
dataSource: function (newValue) {
this.initialize()
dataSource: {
immediate: true,
handler: function (newValue) {
this.initialize()
let rows = []
let checkboxValues = {}
let selectValues = {}
let jdateValues = {}
// 禁用行的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 = {}
// 禁用行的id
let disabledRowIds = (this.disabledRowIds || [])
newValue.forEach((data, newValueIndex) => {
// 判断源数据是否带有id
if (data.id == null || data.id === '') {
data.id = this.removeCaseId(this.generateId() + newValueIndex)
}
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) {
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
}
// 判断是否设定了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.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.date || column.type === FormTypes.datetime) {
jdateValues[inputId] = sourceValue
} else if (column.type === FormTypes.slot) {
if (sourceValue !== 0 && !sourceValue) {
value[column.key] = column.defaultValue
} else {
value[column.key] = sourceValue
}
} else if (column.type === FormTypes.slot) {
if (sourceValue !== 0 && !sourceValue) {
value[column.key] = column.defaultValue
} else {
value[column.key] = sourceValue
}
} else {
value[column.key] = sourceValue
}
// 解析disabledRows
for (let columnKey in this.disabledRows) {
// 判断是否有该属性
if (this.disabledRows.hasOwnProperty(columnKey) && data.hasOwnProperty(columnKey)) {
// row[columnKey] =
// 解析disabledRows
for (let columnKey in this.disabledRows) {
// 判断是否有该属性
if (this.disabledRows.hasOwnProperty(columnKey) && data.hasOwnProperty(columnKey)) {
// row[columnKey] =
if (disabled !== true) {
disabled = this.disabledRows[columnKey] === data[columnKey]
if (disabled) {
disabledRowIds.push(row.id)
if (disabled !== true) {
disabled = this.disabledRows[columnKey] === 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.rows = rows
this.disabledRowIds = disabledRowIds
this.checkboxValues = checkboxValues
this.selectValues = selectValues
this.jdateValues = jdateValues
this.rows = rows
// 更新form表单的值
this.$nextTick(() => {
this.updateFormValues()
})
// 更新form表单的值
this.$nextTick(() => {
this.updateFormValues()
})
}
},
columns: {
immediate: true,
@ -722,6 +750,12 @@
this.selectValues = selectValues
this.jdateValues = jdateValues
if (this.dragSort) {
this.inputValues.forEach((item, index) => {
item[this.dragSortKey] = (index + 1)
})
}
if (update) {
this.rows = rows
this.$nextTick(() => {
@ -751,6 +785,7 @@
},
/** 添加一行 */
add(num = 1, forceScrollToBottom = false) {
if (num < 1) return
// let timestamp = new Date().getTime()
let rows = this.rows
let row
@ -1230,6 +1265,31 @@
}
},
/** 拖动结束交换inputValue中的值 */
handleDragMoveEnd(event) {
let { oldIndex, newIndex } = event
let values = this.inputValues
// 存储旧数据,并删除旧项目
let temp = values[oldIndex]
values.splice(oldIndex, 1)
// 向新项目里添加旧数据
values.splice(newIndex, 0, temp)
values.forEach((item, index) => {
item[this.dragSortKey] = (index + 1)
})
this.forceUpdateFormValues()
// 触发已拖动事件
this.$emit('dragged', {
oldIndex,
newIndex,
target: this
})
},
/* --- common function begin --- */
/** 鼠标移入 */
@ -1355,7 +1415,12 @@
_loadDictConcatToOptions(column) {
initDictOptions(column.dictCode).then((res) => {
if (res.success) {
column.options = (column.options || []).concat(res.result)
let newOptions = (column.options || [])// .concat(res.result)
res.result.forEach(item => {
for (let option of newOptions) if (option.value === item.value) return
newOptions.push(item)
})
column.options = newOptions
} else {
console.group(`JEditableTable 查询字典(${column.dictCode})发生异常`)
console.log(res.message)
@ -1377,14 +1442,46 @@
/** 辅助方法指定a-select 和 j-data 的父容器 */
getParentContainer(node) {
if (this.$el && this.$el.nodeType !== 8) {
return this.$el
let element = (() => {
// nodeType 8 : Comment : 注释
if (this.$el && this.$el.nodeType !== 8) {
return this.$el
}
let doc = document.getElementById(this.caseId + 'inputTable')
if (doc != null) {
return doc
}
return node.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode
})()
// 递归判断是否带有 overflow: hidden的父元素
const ifParent = (child) => {
let currentOverflow = null
if (child['currentStyle']) {
currentOverflow = child['currentStyle']['overflow']
} else if (window.getComputedStyle) {
currentOverflow = window.getComputedStyle(child)['overflow']
}
if (currentOverflow != null) {
if (currentOverflow === 'hidden') {
// 找到了带有 hidden 的标签,判断它的父级是否还有 hidden直到遇到完全没有 hidden 或 body 的时候才停止递归
let temp = ifParent(child.parentNode)
return temp != null ? temp : child.parentNode
} else
// 当前标签没有 hidden ,如果有父级并且父级不是 body 的话就继续递归判断父级
if (child.parentNode && child.parentNode.tagName.toLocaleLowerCase() !== 'body') {
return ifParent(child.parentNode)
} else {
// 直到 body 都没有遇到有 hidden 的标签
return null
}
} else {
return child
}
}
let doc = document.getElementById(this.caseId + 'inputTable')
if (doc != null) {
return doc
}
return node.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode
let temp = ifParent(element)
return (temp != null) ? temp : element
},
/** 辅助方法:替换${...}变量 */
@ -1440,6 +1537,9 @@
props['showSearch'] = true
}
// 判断是否是禁用的列
props['disabled'] = !!col['disabled']
// 判断是否为禁用的行
if (props['disabled'] !== true) {
props['disabled'] = ((this.disabledRowIds || []).indexOf(row.id) !== -1)
@ -1515,6 +1615,38 @@
align-items: center;
}
&.td-ds {
margin-right: 0;
padding-left: 0;
padding-right: 0;
justify-content: center;
align-items: center;
.td-ds-icons {
position: relative;
cursor: move;
width: 100%;
/*padding: 25% 0;*/
height: 100%;
.anticon-align-left,
.anticon-align-right {
position: absolute;
top: 30%;
}
.anticon-align-left {
left: 25%;
}
.anticon-align-right {
right: 25%;
}
}
}
}
}

View File

@ -84,7 +84,7 @@
},
watch: {
value(newValue) {
this.myValue = newValue
this.myValue = (newValue == null ? '' : newValue)
},
myValue(newValue) {
console.log(newValue)

View File

@ -2,30 +2,33 @@
## 参数配置
| 参数 | 类型 | 必填 | 说明 |
|--------------|---------|------|----------------------------------------------------------------|
| columns | array | ✔️ | 表格列的配置描述,具体项见下表 |
| dataSource | array | ✔️ | 表格数据 |
| loading | boolean | | 是否正在加载加载中不会显示任何行默认false |
| actionButton | boolean | | 是否显示操作按钮,包括"新增"、"删除"默认false |
| rowNumber | boolean | | 是否显示行号默认false |
| rowSelection | boolean | | 是否可选择行默认false |
| maxHeight | number | | 设定最大高度(px)默认400 |
| disabledRows | object | | 设定禁用的行,被禁用的行无法被选择和编辑,配置方法可以查看示例 |
| disabled | boolean | | 是否禁用所有行默认false |
| 参数 | 类型 | 必填 | 说明 |
|--------------|---------|------|---------------------------------------------------------------------------------|
| columns | array | ✔️ | 表格列的配置描述,具体项见下表 |
| dataSource | array | ✔️ | 表格数据 |
| loading | boolean | | 是否正在加载加载中不会显示任何行默认false |
| actionButton | boolean | | 是否显示操作按钮,包括"新增"、"删除"默认false |
| rowNumber | boolean | | 是否显示行号默认false |
| rowSelection | boolean | | 是否可选择行默认false |
| dragSort | boolean | | 是否可拖动排序默认false |
| dragSortKey | string | | 拖动排序存储的Key无需定义在columns内也能在getValues()时获取到值默认orderNum |
| maxHeight | number | | 设定最大高度(px)默认400 |
| disabledRows | object | | 设定禁用的行,被禁用的行无法被选择和编辑,配置方法可以查看示例 |
| disabled | boolean | | 是否禁用所有行默认false |
### columns 参数详解
| 参数 | 类型 | 必填 | 说明 |
|---------------|--------|------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| title | string | ✔️ | 表格列头显示的问题 |
| key | string | ✔️ | 列数据在数据项中对应的 key必须是唯一的 |
| type | string | ✔️ | 表单的类型,可以通过`JEditableTableUtil.FormTypes`赋值 |
| width | string | | 列的宽度,可以是百分比,也可以是`px`或其他单位建议设置为百分比且每一列的宽度加起来不应超过100%,否则可能会不能达到预期的效果。留空会自动计算百分比 |
| placeholder | string | | 表单预期值的提示信息,可以使用`${...}`变量替换文本(详见`${...} 变量使用方式` |
| defaultValue | string | | 默认值,在新增一行时生效 |
| validateRules | array | | 表单验证规则,配置方式见[validateRules 配置规则](#validaterules-配置规则) |
| props | object | | 设置添加给表单元素的自定义属性,例如:`props:{title: 'show title'}` |
| 参数 | 类型 | 必填 | 说明 |
|---------------|---------|------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| title | string | ✔️ | 表格列头显示的问题 |
| key | string | ✔️ | 列数据在数据项中对应的 key必须是唯一的 |
| type | string | ✔️ | 表单的类型,可以通过`JEditableTableUtil.FormTypes`赋值 |
| width | string | | 列的宽度,可以是百分比,也可以是`px`或其他单位建议设置为百分比且每一列的宽度加起来不应超过100%,否则可能会不能达到预期的效果。留空会自动计算百分比 |
| placeholder | string | | 表单预期值的提示信息,可以使用`${...}`变量替换文本(详见`${...} 变量使用方式` |
| defaultValue | string | | 默认值,在新增一行时生效 |
| validateRules | array | | 表单验证规则,配置方式见[validateRules 配置规则](#validaterules-配置规则) |
| props | object | | 设置添加给表单元素的自定义属性,例如:`props:{title: 'show title'}` |
| disabled | boolean | | 是否禁用当前列默认false |
#### 当 type=checkbox 时所需的参数
@ -40,7 +43,7 @@
|------------|---------|------|----------------------------------------------------|
| options | array | ✔️ | 下拉选项列表,详见下表 |
| allowInput | boolean | | 是否允许用户输入内容,并创建新的内容 |
| dictCode | String | | 数据字典Code若options也有值则拼接options后面 |
| dictCode | String | | 数据字典Code若options也有值则拼接options后面 |
##### options 所需参数
@ -75,11 +78,12 @@
## 事件
| 事件名 | 触发时机 | 参数 |
|-----------------|----------------------------------------------------|-------------------------------|
| added | 当添加行操作完成后触发 | |
| deleted | 当删除行操作完成后触发(批量删除操作只会触发一次) | `deleteIds` 被逻辑删除的id |
| selectRowChange | 当行被选中或取消选中时触发 | `selectedRowIds` 被选中行的id |
| 事件名 | 触发时机 | 参数 |
|-----------------|----------------------------------------------------|--------------------------------------------------|
| added | 当添加行操作完成后触发 | |
| deleted | 当删除行操作完成后触发(批量删除操作只会触发一次) | `deleteIds` 被逻辑删除的id |
| selectRowChange | 当行被选中或取消选中时触发 | `selectedRowIds` 被选中行的id |
| valueChange | 当数据发生改变的时候触发的事件 | `{ type, row, column, value, target }` Event对象 |
## 方法
@ -490,6 +494,7 @@ this.$refs.editableTable.getValues((error, values) => {
/* a 标签的点击事件,删除当前选中的行 */
handleDelete(props) {
// 参数解释
// props.index :当前行的下标
// props.text 当前值可能是defaultValue定义的值也可能是从dataSource中取出的值
// props.rowId 当前选中行的id如果是新增行则是临时id
// props.column :当前操作的列

View File

@ -0,0 +1,928 @@
<template>
<a-modal
title="corn表达式"
:width="modalWidth"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="close"
cancelText="关闭">
<div class="card-container">
<a-tabs type="card">
<a-tab-pane key="1" type="card">
<span slot="tab"><a-icon type="schedule" /> 秒</span>
<a-radio-group v-model="result.second.cronEvery">
<a-row>
<a-radio value="1">每一秒钟</a-radio>
</a-row>
<a-row>
<a-radio value="2">每隔
<a-input-number size="small" v-model="result.second.incrementIncrement" :min="1" :max="60"></a-input-number>
秒执行 从
<a-input-number size="small" v-model="result.second.incrementStart" :min="0" :max="59"></a-input-number>
秒开始
</a-radio>
</a-row>
<a-row>
<a-radio value="3">具体秒数(可多选)</a-radio>
<a-select style="width:354px;" size="small" mode="multiple" v-model="result.second.specificSpecific">
<a-select-option v-for="(val,index) in 60" :key="index" :value="index">{{ index }}</a-select-option>
</a-select>
</a-row>
<a-row>
<a-radio value="4">周期从
<a-input-number size="small" v-model="result.second.rangeStart" :min="1" :max="60"></a-input-number>
<a-input-number size="small" v-model="result.second.rangeEnd" :min="0" :max="59"></a-input-number>
</a-radio>
</a-row>
</a-radio-group>
</a-tab-pane>
<a-tab-pane key="2">
<span slot="tab"><a-icon type="schedule" />分</span>
<div class="tabBody">
<a-radio-group v-model="result.minute.cronEvery">
<a-row>
<a-radio value="1">每一分钟</a-radio>
</a-row>
<a-row>
<a-radio value="2">每隔
<a-input-number size="small" v-model="result.minute.incrementIncrement" :min="1" :max="60"></a-input-number>
分执行 从
<a-input-number size="small" v-model="result.minute.incrementStart" :min="0" :max="59"></a-input-number>
分开始
</a-radio>
</a-row>
<a-row>
<a-radio value="3">具体分钟数(可多选)</a-radio>
<a-select style="width:340px;" size="small" mode="multiple" v-model="result.minute.specificSpecific">
<a-select-option v-for="(val,index) in Array(60)" :key="index" :value="index"> {{ index }}</a-select-option>
</a-select>
</a-row>
<a-row>
<a-radio value="4">周期从
<a-input-number size="small" v-model="result.minute.rangeStart" :min="1" :max="60"></a-input-number>
<a-input-number size="small" v-model="result.minute.rangeEnd" :min="0" :max="59"></a-input-number>
</a-radio>
</a-row>
</a-radio-group>
</div>
</a-tab-pane>
<a-tab-pane key="3">
<span slot="tab"><a-icon type="schedule" /> 时</span>
<div class="tabBody">
<a-radio-group v-model="result.hour.cronEvery">
<a-row>
<a-radio value="1">每一小时</a-radio>
</a-row>
<a-row>
<a-radio value="2">每隔
<a-input-number size="small" v-model="result.hour.incrementIncrement" :min="0" :max="23"></a-input-number>
小时执行 从
<a-input-number size="small" v-model="result.hour.incrementStart" :min="0" :max="23"></a-input-number>
小时开始
</a-radio>
</a-row>
<a-row>
<a-radio class="long" value="3">具体小时数(可多选)</a-radio>
<a-select style="width:340px;" size="small" mode="multiple" v-model="result.hour.specificSpecific">
<a-select-option v-for="(val,index) in Array(24)" :key="index" >{{ index }}</a-select-option>
</a-select>
</a-row>
<a-row>
<a-radio value="4">周期从
<a-input-number size="small" v-model="result.hour.rangeStart" :min="0" :max="23"></a-input-number>
<a-input-number size="small" v-model="result.hour.rangeEnd" :min="0" :max="23"></a-input-number>
小时
</a-radio>
</a-row>
</a-radio-group>
</div>
</a-tab-pane>
<a-tab-pane key="4">
<span slot="tab"><a-icon type="schedule" /> 天</span>
<div class="tabBody">
<a-radio-group v-model="result.day.cronEvery">
<a-row>
<a-radio value="1">每一天</a-radio>
</a-row>
<a-row>
<a-radio value="2">每隔
<a-input-number size="small" v-model="result.week.incrementIncrement" :min="1" :max="7"></a-input-number>
周执行 从
<a-select size="small" v-model="result.week.incrementStart">
<a-select-option v-for="(val,index) in Array(7)" :key="index" :value="index+1">{{ weekDays[index] }}</a-select-option>
</a-select>
开始
</a-radio>
</a-row>
<a-row>
<a-radio value="3">每隔
<a-input-number size="small" v-model="result.day.incrementIncrement" :min="1" :max="31"></a-input-number>
天执行 从
<a-input-number size="small" v-model="result.day.incrementStart" :min="1" :max="31"></a-input-number>
天开始
</a-radio>
</a-row>
<a-row>
<a-radio class="long" value="4">具体星期几(可多选)</a-radio>
<a-select style="width:340px;" size="small" mode="multiple" v-model="result.week.specificSpecific">
<a-select-option v-for="(val,index) in Array(7)" :key="index" :value="index+1">{{ weekDays[index] }}</a-select-option>
</a-select>
</a-row>
<a-row>
<a-radio class="long" value="5">具体天数(可多选)</a-radio>
<a-select style="width:354px;" size="small" mode="multiple" v-model="result.day.specificSpecific">
<a-select-option v-for="(val,index) in Array(31)" :key="index" :value="index+1">{{ index+1 }}</a-select-option>
</a-select>
</a-row>
<a-row>
<a-radio value="6">在这个月的最后一天</a-radio>
</a-row>
<a-row>
<a-radio value="7">在这个月的最后一个工作日</a-radio>
</a-row>
<a-row>
<a-radio value="8">在这个月的最后一个
<a-select size="small" v-model="result.day.cronLastSpecificDomDay">
<a-select-option v-for="(val,index) in Array(7)" :key="index" :value="index+1">{{ weekDays[index] }}</a-select-option>
</a-select>
</a-radio>
</a-row>
<a-row>
<a-radio value="9">
在本月底前
<a-input-number size="small" v-model="result.day.cronDaysBeforeEomMinus" :min="1" :max="31"></a-input-number>
</a-radio>
</a-row>
<a-row>
<a-radio value="10">最近的工作日(周一至周五)至本月
<a-input-number size="small" v-model="result.day.cronDaysNearestWeekday" :min="1" :max="31"></a-input-number>
</a-radio>
</a-row>
<a-row>
<a-radio value="11">在这个月的第
<a-input-number size="small" v-model="result.week.cronNthDayNth" :min="1" :max="5"></a-input-number>
<a-select size="small" v-model="result.week.cronNthDayDay">
<a-select-option v-for="(val,index) in Array(7)" :key="index" :value="index+1">{{ weekDays[index] }}</a-select-option>
</a-select>
</a-radio>
</a-row>
</a-radio-group>
</div>
</a-tab-pane>
<a-tab-pane key="5">
<span slot="tab"><a-icon type="schedule" /> 月</span>
<div class="tabBody">
<a-radio-group v-model="result.month.cronEvery">
<a-row>
<a-radio value="1">每一月</a-radio>
</a-row>
<a-row>
<a-radio value="2">每隔
<a-input-number size="small" v-model="result.month.incrementIncrement" :min="0" :max="12"></a-input-number>
月执行 从
<a-input-number size="small" v-model="result.month.incrementStart" :min="0" :max="12"></a-input-number>
月开始
</a-radio>
</a-row>
<a-row>
<a-radio class="long" value="3">具体月数(可多选)</a-radio>
<a-select style="width:354px;" size="small" filterable mode="multiple" v-model="result.month.specificSpecific">
<a-select-option v-for="(val,index) in Array(12)" :key="index" :value="index+1">{{ index+1 }}</a-select-option>
</a-select>
</a-row>
<a-row>
<a-radio value="4">从
<a-input-number size="small" v-model="result.month.rangeStart" :min="1" :max="12"></a-input-number>
<a-input-number size="small" v-model="result.month.rangeEnd" :min="1" :max="12"></a-input-number>
月之间的每个月
</a-radio>
</a-row>
</a-radio-group>
</div>
</a-tab-pane>
<a-tab-pane key="6">
<span slot="tab"><a-icon type="schedule" /> 年</span>
<div class="tabBody">
<a-radio-group v-model="result.year.cronEvery">
<a-row>
<a-radio value="1">每一年</a-radio>
</a-row>
<a-row>
<a-radio value="2">每隔
<a-input-number size="small" v-model="result.year.incrementIncrement" :min="1" :max="99"></a-input-number>
年执行 从
<a-input-number size="small" v-model="result.year.incrementStart" :min="2019" :max="2119"></a-input-number>
年开始
</a-radio>
</a-row>
<a-row>
<a-radio class="long" value="3">具体年份(可多选)</a-radio>
<a-select style="width:354px;" size="small" filterable mode="multiple" v-model="result.year.specificSpecific">
<a-select-option v-for="(val,index) in Array(100)" :key="index" :value="2019+index">{{ 2019+index }}</a-select-option>
</a-select>
</a-row>
<a-row>
<a-radio value="4">从
<a-input-number size="small" v-model="result.year.rangeStart" :min="2019" :max="2119"></a-input-number>
<a-input-number size="small" v-model="result.year.rangeEnd" :min="2019" :max="2119"></a-input-number>
年之间的每一年
</a-radio>
</a-row>
</a-radio-group>
</div>
</a-tab-pane>
</a-tabs>
<div class="bottom">
<span class="value">{{this.cron }}</span>
</div>
</div>
</a-modal>
</template>
<script>
export default {
name:'VueCron',
props:['data'],
data(){
return {
visible: false,
confirmLoading:false,
size:'large',
weekDays:['天','一','二','三','四','五','六'].map(val=>'星期'+val),
result: {
second:{},
minute:{},
hour:{},
day:{},
week:{},
month:{},
year:{}
},
defaultValue: {
second:{
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:1,
rangeEnd:0,
specificSpecific:[],
},
minute:{
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:1,
rangeEnd:'0',
specificSpecific:[],
},
hour:{
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:'0',
rangeEnd:'0',
specificSpecific:[],
},
day:{
cronEvery:'',
incrementStart:1,
incrementIncrement:'1',
rangeStart:'',
rangeEnd:'',
specificSpecific:[],
cronLastSpecificDomDay:1,
cronDaysBeforeEomMinus:1,
cronDaysNearestWeekday:1,
},
week:{
cronEvery:'',
incrementStart:1,
incrementIncrement:1,
specificSpecific:[],
cronNthDayDay:1,
cronNthDayNth:1,
},
month:{
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:1,
rangeEnd:1,
specificSpecific:[],
},
year:{
cronEvery:'',
incrementStart:2017,
incrementIncrement:1,
rangeStart:2019,
rangeEnd: 2019,
specificSpecific:[],
},
label:''
}
}
},
computed: {
modalWidth(){
return 608;
},
secondsText() {
let seconds = '';
let cronEvery=this.result.second.cronEvery||'';
switch (cronEvery.toString()){
case '1':
seconds = '*';
break;
case '2':
seconds = this.result.second.incrementStart+'/'+this.result.second.incrementIncrement;
break;
case '3':
this.result.second.specificSpecific.map(val=> {seconds += val+','});
seconds = seconds.slice(0, -1);
break;
case '4':
seconds = this.result.second.rangeStart+'-'+this.result.second.rangeEnd;
break;
}
return seconds;
},
minutesText() {
let minutes = '';
let cronEvery=this.result.minute.cronEvery||'';
switch (cronEvery.toString()){
case '1':
minutes = '*';
break;
case '2':
minutes = this.result.minute.incrementStart+'/'+this.result.minute.incrementIncrement;
break;
case '3':
this.result.minute.specificSpecific.map(val=> {
minutes += val+','
});
minutes = minutes.slice(0, -1);
break;
case '4':
minutes = this.result.minute.rangeStart+'-'+this.result.minute.rangeEnd;
break;
}
return minutes;
},
hoursText() {
let hours = '';
let cronEvery=this.result.hour.cronEvery||'';
switch (cronEvery.toString()){
case '1':
hours = '*';
break;
case '2':
hours = this.result.hour.incrementStart+'/'+this.result.hour.incrementIncrement;
break;
case '3':
this.result.hour.specificSpecific.map(val=> {
hours += val+','
});
hours = hours.slice(0, -1);
break;
case '4':
hours = this.result.hour.rangeStart+'-'+this.result.hour.rangeEnd;
break;
}
return hours;
},
daysText() {
let days='';
let cronEvery=this.result.day.cronEvery||'';
switch (cronEvery.toString()){
case '1':
break;
case '2':
case '4':
case '11':
days = '?';
break;
case '3':
days = this.result.day.incrementStart+'/'+this.result.day.incrementIncrement;
break;
case '5':
this.result.day.specificSpecific.map(val=> {
days += val+','
});
days = days.slice(0, -1);
break;
case '6':
days = "L";
break;
case '7':
days = "LW";
break;
case '8':
days = this.result.day.cronLastSpecificDomDay + 'L';
break;
case '9':
days = 'L-' + this.result.day.cronDaysBeforeEomMinus;
break;
case '10':
days = this.result.day.cronDaysNearestWeekday+"W";
break
}
return days;
},
weeksText() {
let weeks = '';
let cronEvery=this.result.day.cronEvery||'';
switch (cronEvery.toString()){
case '1':
case '3':
case '5':
weeks = '?';
break;
case '2':
weeks = this.result.week.incrementStart+'/'+this.result.week.incrementIncrement;
break;
case '4':
this.result.week.specificSpecific.map(val=> {
weeks += val+','
});
weeks = weeks.slice(0, -1);
break;
case '6':
case '7':
case '8':
case '9':
case '10':
weeks = "?";
break;
case '11':
weeks = this.result.week.cronNthDayDay+"#"+this.result.week.cronNthDayNth;
break;
}
return weeks;
},
monthsText() {
let months = '';
let cronEvery=this.result.month.cronEvery||'';
switch (cronEvery.toString()){
case '1':
months = '*';
break;
case '2':
months = this.result.month.incrementStart+'/'+this.result.month.incrementIncrement;
break;
case '3':
this.result.month.specificSpecific.map(val=> {
months += val+','
});
months = months.slice(0, -1);
break;
case '4':
months = this.result.month.rangeStart+'-'+this.result.month.rangeEnd;
break;
}
return months;
},
yearsText() {
let years = '';
let cronEvery=this.result.year.cronEvery||'';
switch (cronEvery.toString()){
case '1':
years = '*';
break;
case '2':
years = this.result.year.incrementStart+'/'+this.result.year.incrementIncrement;
break;
case '3':
this.result.year.specificSpecific.map(val=> {
years += val+','
});
years = years.slice(0, -1);
break;
case '4':
years = this.result.year.rangeStart+'-'+this.result.year.rangeEnd;
break;
}
return years;
},
cron(){
return `${this.secondsText||'*'} ${this.minutesText||'*'} ${this.hoursText||'*'} ${this.daysText||'*'} ${this.monthsText||'*'} ${this.weeksText||'?'} ${this.yearsText||'*'}`
},
},
watch:{
visible:{
handler() {
// if(this.data){
// //this. result = Object.keys(this.data.value).length>0?this.deepCopy(this.data.value):this.deepCopy(this.defaultValue);
// //this.result = Object.keys(this.data.value).length>0?clone(this.data.value):clone(this.defaultValue);
// //this.result = Object.keys(this.data.value).length>0?clone(JSON.parse(this.data.value)):clone(this.defaultValue);
// this.result = Object.keys(this.data.value).length>0?JSON.parse(this.data.value):JSON.parse(JSON.stringify(this.defaultValue));
// }else{
// //this.result = this.deepCopy(this.defaultValue);
// //this.result = clone(this.defaultValue);
// this.result = JSON.parse(JSON.stringify(this.defaultValue));
// }
let label = this.data;
if(label){
this.secondsReverseExp(label)
this.minutesReverseExp(label);
this.hoursReverseExp(label);
this.daysReverseExp(label);
this.daysReverseExp(label);
this.monthsReverseExp(label);
this.yearReverseExp(label);
JSON.parse(JSON.stringify(label));
}else {
this.result = JSON.parse(JSON.stringify(this.defaultValue));
}
}
}
},
methods: {
show(){
this.visible = true;
// console.log('secondsReverseExp',this.secondsReverseExp(this.data));
// console.log('minutesReverseExp',this.minutesReverseExp(this.data));
// console.log('hoursReverseExp',this.hoursReverseExp(this.data));
// console.log('daysReverseExp',this.daysReverseExp(this.data));
// console.log('monthsReverseExp',this.monthsReverseExp(this.data));
// console.log('yearReverseExp',this.yearReverseExp(this.data));
},
handleSubmit(){
this.$emit('ok',this.cron);
this.close();
this.visible = false;
},
close(){
this.visible = false;
},
secondsReverseExp(seconds) {
let val = seconds.split(" ")[0];
//alert(val);
let second = {
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:1,
rangeEnd:0,
specificSpecific:[]
};
switch (true) {
case val.includes('*'):
second.cronEvery = '1';
break;
case val.includes('/'):
second.cronEvery = '2';
second.incrementStart = val.split('/')[0];
second.incrementIncrement = val.split('/')[1];
break;
case val.includes(','):
second.cronEvery = '3';
second.specificSpecific = val.split(',').map(Number).sort();
break;
case val.includes('-'):
second.cronEvery = '4';
second.rangeStart = val.split('-')[0];
second.rangeEnd = val.split('-')[1];
break;
default:
second.cronEvery = '1';
}
this.result.second = second;
},
minutesReverseExp(minutes) {
let val = minutes.split(" ")[1];
let minute = {
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:1,
rangeEnd:0,
specificSpecific:[],
}
switch (true) {
case val.includes('*'):
minute.cronEvery = '1';
break;
case val.includes('/'):
minute.cronEvery = '2';
minute.incrementStart = val.split('/')[0];
minute.incrementIncrement = val.split('/')[1];
break;
case val.includes(','):
minute.cronEvery = '3';
minute.specificSpecific = val.split(',').map(Number).sort();
break;
case val.includes('-'):
minute.cronEvery = '4';
minute.rangeStart = val.split('-')[0];
minute.rangeEnd = val.split('-')[1];
break;
default:
minute.cronEvery = '1';
}
this.result.minute = minute;
},
hoursReverseExp(hours) {
let val = hours.split(" ")[2];
let hour ={
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:1,
rangeEnd:'0',
specificSpecific:[],
};
switch (true) {
case val.includes('*'):
hour.cronEvery = '1';
break;
case val.includes('/'):
hour.cronEvery = '2';
hour.incrementStart = val.split('/')[0];
hour.incrementIncrement = val.split('/')[1];
break;
case val.includes(','):
hour.cronEvery = '3';
hour.specificSpecific = val.split(',').map(Number).sort();
break;
case val.includes('-'):
hour.cronEvery = '4';
hour.rangeStart = val.split('-')[0];
hour.rangeEnd = val.split('-')[1];
break;
default:
hour.cronEvery = '1';
}
this.result.hour = hour;
},
daysReverseExp(cron) {
let days = cron.split(" ")[3];
let weeks = cron.split(" ")[5];
let day ={
cronEvery:'',
incrementStart:1,
incrementIncrement:1,
rangeStart:1,
rangeEnd:1,
specificSpecific:[],
cronLastSpecificDomDay:1,
cronDaysBeforeEomMinus:1,
cronDaysNearestWeekday:1,
};
let week = {
cronEvery:'',
incrementStart:1,
incrementIncrement:1,
specificSpecific:[],
cronNthDayDay:1,
cronNthDayNth:'1',
};
if (!days.includes('?')) {
switch (true) {
case days.includes('*'):
day.cronEvery = '1';
break;
case days.includes('?'):
// 2、4、11
break;
case days.includes('/'):
day.cronEvery = '3';
day.incrementStart = days.split('/')[0];
day.incrementIncrement = days.split('/')[1];
break;
case days.includes(','):
day.cronEvery = '5';
day.specificSpecific = days.split(',').map(Number).sort();
// day.specificSpecific.forEach(function (value, index) {
// day.specificSpecific[index] = value -1;
// });
break;
case days.includes('LW'):
day.cronEvery = '7';
break;
case days.includes('L-'):
day.cronEvery = '9';
day.cronDaysBeforeEomMinus = days.split('L-')[1];
break;
case days.includes('L'):
//alert(days);
if(days.len == 1){
day.cronEvery = '6';
day.cronLastSpecificDomDay = '1';
}
else
{
day.cronEvery = '8';
day.cronLastSpecificDomDay = Number(days.split('L')[0]);
}
break;
case days.includes('W'):
day.cronEvery = '10';
day.cronDaysNearestWeekday = days.split('W')[0];
break;
default:
day.cronEvery = '1';
}
}else {
switch (true){
case weeks.includes('/'):
day.cronEvery = '2';
week.incrementStart = weeks.split("/")[0];
week.incrementIncrement = weeks.split("/")[1];
break;
case weeks.includes(','):
day.cronEvery = '4';
week.specificSpecific = weeks.split(',').map(Number).sort();
break;
case '#':
day.cronEvery = '11';
week.cronNthDayDay = weeks.split("#")[0];
week.cronNthDayNth = weeks.split("#")[1];
break;
default:
day.cronEvery = '1';
week.cronEvery = '1';
}
}
this.result.day = day;
this.result.week = week;
},
monthsReverseExp(cron) {
let months = cron.split(" ")[4];
let month = {
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:1,
rangeEnd:1,
specificSpecific:[],
};
switch (true){
case months.includes('*'):
month.cronEvery = '1';
break;
case months.includes('/'):
month.cronEvery = '2';
month.incrementStart = months.split('/')[0];
month.incrementIncrement = months.split('/')[1];
break;
case months.includes(','):
month.cronEvery = '3';
month.specificSpecific = months.split(',').map(Number).sort();
break;
case months.includes('-'):
month.cronEvery = '4';
month.rangeStart = months.split('-')[0];
month.rangeEnd = months.split('-')[1];
break;
default:
month.cronEvery = '1';
}
this.result.month = month;
},
yearReverseExp(cron) {
let years = cron.split(" ")[6];
let year = {
cronEvery:'',
incrementStart:3,
incrementIncrement:5,
rangeStart:2019,
rangeEnd:2019,
specificSpecific:[],
};
switch (true){
case years.includes('*'):
year.cronEvery = '1';
break;
case years.includes('/'):
year.cronEvery = '2';
year.incrementStart = years.split('/')[0];
year.incrementIncrement = years.split('/')[1];
break;
case years.includes(','):
year.cronEvery = '3';
year.specificSpecific = years.split(',').map(Number).sort();
break;
case years.includes('-'):
year.cronEvery = '4';
year.rangeStart = years.split('-')[0];
year.rangeEnd = years.split('-')[1];
break;
default:
year.cronEvery = '1';
}
this.result.year = year;
}
}
}
</script>
<style lang="scss">
.card-container {
background: #fff;
overflow: hidden;
padding: 12px;
position: relative;
width: 100%;
.ant-tabs{
border:1px solid #e6ebf5;
padding: 0;
.ant-tabs-bar {
margin: 0;
outline: none;
border-bottom: none;
.ant-tabs-nav-container{
margin: 0;
.ant-tabs-tab {
padding: 0 24px!important;
background-color: #f5f7fa!important;
margin-right: 0px!important;
border-radius: 0;
line-height: 38px;
border: 1px solid transparent!important;
border-bottom: 1px solid #e6ebf5!important;
}
.ant-tabs-tab-active.ant-tabs-tab{
color: #409eff;
background-color: #fff!important;
border-right:1px solid #e6ebf5!important;
border-left:1px solid #e6ebf5!important;
border-bottom:1px solid #fff!important;
font-weight: normal;
transition:none!important;
}
}
}
.ant-tabs-tabpane{
padding: 15px;
.ant-row{
margin: 10px 0;
}
.ant-select,.ant-input-number{
width: 100px;
}
}
}
}
</style>
<style lang="scss" scoped>
.container-widthEn{
width: 755px;
}
.container-widthCn{
width: 608px;
}
.language{
text-align: center;
position: absolute;
right: 13px;
top: 13px;
border: 1px solid transparent;
height: 40px;
line-height: 38px;
font-size: 16px;
color: #409eff;
z-index: 1;
background: #f5f7fa;
outline: none;
width: 47px;
border-bottom: 1px solid #e6ebf5;
border-radius: 0;
}
.card-container{
.bottom{
display: flex;
justify-content: center;
padding: 10px 0 0 0;
.cronButton{
margin: 0 10px;
line-height: 40px;
}
}
}
.tabBody{
.a-row{
margin: 10px 0;
.long{
.a-select{
width:354px;
}
}
.a-input-number{
width: 110px;
}
}
}
</style>

View File

@ -58,6 +58,16 @@
watch:{
departId(){
this.initDepartComponent()
},
visible: {
handler() {
if (this.departId) {
this.checkedKeys = this.departId.split(",");
console.log('this.departId', this.departId)
} else {
this.checkedKeys = [];
}
}
}
},
methods:{

View File

@ -148,11 +148,28 @@
<style lang="scss">
.ant-menu.ant-menu-root {
& > .ant-menu-item:first-child {
background-color: white;
background-color: transparent;
& > a, & > a:hover {
color: rgba(0, 0, 0, 0.65);
}
&.ant-menu-item-selected {
& > a, & > a:hover {
color: #1890ff;
}
}
}
&.ant-menu-dark > .ant-menu-item:first-child {
& > a, & > a:hover {
color: rgba(255, 255, 255, 0.65);
}
&.ant-menu-item-selected {
& > a, & > a:hover {
color: rgba(255, 255, 255, 1);
}
}
}
}

View File

@ -153,9 +153,10 @@
</a-alert>
</div>
</div>
<div class="setting-drawer-index-handle" @click="toggle">
<a-icon type="setting" v-if="!visible"/>
<a-icon type="close" v-else/>
<div class="setting-drawer-index-handle" @click="toggle" v-if="visible">
<!-- <a-icon type="setting" v-if="!visible"/>-->
<!-- <a-icon type="close" v-else/>-->
<a-icon type="close" />
</div>
</a-drawer>
</div>

View File

@ -1,6 +1,6 @@
<template>
<a-modal
:title="title"
:title="currTitle"
:width="450"
:visible="visible"
:closable="false"
@ -41,6 +41,9 @@
<script>
import { getAction,putAction } from '@/api/manage'
import Vue from 'vue'
import store from '@/store/'
import { USER_INFO } from "@/store/mutation-types"
export default {
name: 'DepartSelect',
@ -70,6 +73,7 @@
},
data(){
return {
currTitle:this.title,
visible:false,
departList:[],
departSelected:"",
@ -100,7 +104,7 @@
this.departSelected = orgCode
this.departList = departs
if(this.currDepartName){
this.title ="部门切换当前部门 : "+this.currDepartName+""
this.currTitle ="部门切换当前部门 : "+this.currDepartName+""
}
}
@ -122,6 +126,10 @@
}
putAction("/sys/selectDepart",obj).then(res=>{
if(res.success){
const userInfo = res.result.userInfo;
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000);
store.commit('SET_INFO', userInfo);
//console.log("---切换组织机构---userInfo-------",store.getters.userInfo.orgCode);
this.departClear()
}
})

View File

@ -78,6 +78,7 @@
<script>
import { getAction,putAction } from '@/api/manage'
import ShowAnnouncement from './ShowAnnouncement'
import store from '@/store/'
export default {
name: "HeaderNotice",
@ -89,7 +90,8 @@
loadding: false,
url:{
listCementByUser:"/sys/annountCement/listByUser",
editCementSend:"/system/sysAnnouncementSend/editByAnntIdAndUserId",
editCementSend:"/sys/sysAnnouncementSend/editByAnntIdAndUserId",
queryById:"/sys/annountCement/queryById",
},
hovered: false,
announcement1:[],
@ -98,6 +100,7 @@
msg2Count:"0",
msg1Title:"通知(3)",
msg2Title:"",
stopTimer:false,
}
},
computed:{
@ -105,15 +108,25 @@
return parseInt(this.msg1Count)+parseInt(this.msg2Count);
}
},
created() {
mounted() {
this.loadData();
this.timer();
//this.timerFun();
this.initWebSocket();
},
destroyed: function () { // 离开页面生命周期函数
this.websocketclose();
},
methods: {
timer() {
return setInterval(()=>{
timerFun() {
this.stopTimer = false;
let myTimer = setInterval(()=>{
// 停止定时器
if (this.stopTimer == true) {
clearInterval(myTimer);
return;
}
this.loadData()
},60000)
},6000)
},
loadData (){
try {
@ -127,8 +140,14 @@
this.msg2Count = res.result.sysMsgTotal;
this.msg2Title = "系统消息(" + res.result.sysMsgTotal + ")";
}
}).catch(error => {
console.log("系统消息通知异常",error);//这行打印permissionName is undefined
this.stopTimer = true;
console.log("清理timer");
});
} catch (err) {
this.stopTimer = true;
console.log("通知异常",err);
}
},
fetchNotice () {
@ -163,6 +182,74 @@
this.hovered = visible;
},
initWebSocket: function () {
// 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);
this.websock = new WebSocket(url);
this.websock.onopen = this.websocketonopen;
this.websock.onerror = this.websocketonerror;
this.websock.onmessage = this.websocketonmessage;
this.websock.onclose = this.websocketclose;
},
websocketonopen: function () {
console.log("WebSocket连接成功");
},
websocketonerror: function (e) {
console.log("WebSocket连接发生错误");
},
websocketonmessage: function (e) {
console.log("-----接收消息-------",e.data);
var data = eval("(" + e.data + ")"); //解析对象
this.loadData();
//if(data.cmd == "topic"){
//系统通知
this.openNotification(data);
//}else if(data.cmd == "user"){
//用户消息
// this.openNotification(data);
//}
},
websocketclose: function (e) {
console.log("connection closed (" + e.code + ")");
},
openNotification (data) {
var text = data.msgTxt;
const key = `open${Date.now()}`;
this.$notification.open({
message: '消息提醒',
placement:'bottomRight',
description: text,
key,
btn: (h)=>{
return h('a-button', {
props: {
type: 'primary',
size: 'small',
},
on: {
click: () => this.showDetail(key,data)
}
}, '查看详情')
},
});
},
showDetail(key,data){
this.$notification.close(key);
var id = data.msgId;
getAction(this.url.queryById,{id:id}).then((res) => {
if (res.success) {
var record = res.result;
this.showAnnouncement(record);
}
})
},
}
}
</script>

View File

@ -1,15 +1,23 @@
<template>
<div class="logo">
<router-link :to="{name:'dashboard'}">
<img src="~@/assets/logo.svg" alt="logo">
<!-- update-begin- author:sunjianlei --- date:20190814 --- for: logo颜色根据主题颜色变化 -->
<img v-if="navTheme === 'dark'" src="~@/assets/logo-white.png" alt="logo">
<img v-else src="~@/assets/logo.svg" alt="logo">
<!-- update-begin- author:sunjianlei --- date:20190814 --- for: logo颜色根据主题颜色变化 -->
<h1 v-if="showTitle">{{ title }}</h1>
</router-link>
</div>
</template>
<script>
import { mixin } from '@/utils/mixin.js'
export default {
name: 'Logo',
mixins: [mixin],
props: {
title: {
type: String,

View File

@ -1,20 +1,23 @@
<template>
<a-modal
width="60%"
class="announcementCustomModal"
:width="modelStyle.width"
:visible="visible"
:bodyStyle ="bodyStyle"
@cancel="handleCancel"
destroyOnClose
:footer="null">
<a-card style="width: 100%;height: 100%" class="daily-article" :loading="loading">
<template slot="title">
<a-button icon="fullscreen" class="custom-btn" @click="handleClickToggleFullScreen"/>
</template>
<a-card class="daily-article" :loading="loading">
<a-card-meta
:title="record.titile"
:description="'发布人'+record.sender + ' 发布时间 ' + record.sendTime"/>
:description="'发布人'+record.sender + ' 发布时间 ' + record.sendTime">
</a-card-meta>
<a-divider />
<span v-html="record.msgContent" class="article-content"></span>
</a-card>
</a-modal>
</template>
@ -40,8 +43,14 @@
bodyStyle:{
padding: "0",
height:(window.innerHeight*0.8)+"px",
"overflow-y":"auto"
"overflow-y":"auto",
},
modelStyle:{
width: '60%',
style: { top: '20px' },
fullScreen: false
}
}
},
created () {
@ -54,33 +63,68 @@
handleCancel () {
this.visible = false;
},
/** 切换全屏显示 */
handleClickToggleFullScreen() {
let mode = !this.modelStyle.fullScreen
if (mode) {
this.modelStyle.width = '100%'
this.modelStyle.style.top = '20px'
} else {
this.modelStyle.width = '60%'
this.modelStyle.style.top = '50px'
}
this.modelStyle.fullScreen = mode
}
}
}
</script>
<style lang="less">
.announcementCustomModal{
.ant-modal-header {
border: none;
display: inline-block;
position: absolute;
z-index: 1;
right: 56px;
padding: 0;
.ant-modal-title{
.custom-btn{
width: 56px;
height: 56px;
border: none;
box-shadow: none;
}
}
}
.daily-article{
border-bottom: 0;
}
}
</style>
<style scoped lang="less">
.daily-article {
.article-button {
font-size: 1.2rem !important;
.article-button {
font-size: 1.2rem !important;
}
.ant-card-body {
padding: 18px !important;
}
.ant-card-head {
padding: 0 1rem;
}
.ant-card-meta {
margin-bottom: 1rem;
}
.article-content {
p {
word-wrap: break-word;
word-break: break-all;
text-overflow: initial;
white-space: normal;
font-size: .9rem !important;
margin-bottom: .8rem;
}
}
}
.ant-card-body {
padding: 18px !important;
}
.ant-card-head {
padding: 0 1rem;
}
.ant-card-meta {
margin-bottom: 1rem;
}
.article-content {
p {
word-wrap: break-word;
word-break: break-all;
text-overflow: initial;
white-space: normal;
font-size: .9rem !important;
margin-bottom: .8rem;
}
}
}
</style>
</style>

View File

@ -24,11 +24,15 @@
<span>账户设置</span>
</router-link>
</a-menu-item>
<a-menu-item key="2" @click="updatePassword">
<a-menu-item key="3" @click="systemSetting">
<a-icon type="tool"/>
<span>系统设置</span>
</a-menu-item>
<a-menu-item key="4" @click="updatePassword">
<a-icon type="setting"/>
<span>密码修改</span>
</a-menu-item>
<a-menu-item key="3" @click="updateCurrentDepart">
<a-menu-item key="5" @click="updateCurrentDepart">
<a-icon type="cluster"/>
<span>切换部门</span>
</a-menu-item>
@ -53,12 +57,14 @@
</span>
<user-password ref="userPassword"></user-password>
<depart-select ref="departSelect" :closable="true" title="部门切换"></depart-select>
<setting-drawer ref="settingDrawer" :closable="true" title="系统设置"></setting-drawer>
</div>
</template>
<script>
import HeaderNotice from './HeaderNotice'
import UserPassword from './UserPassword'
import SettingDrawer from "@/components/setting/SettingDrawer";
import DepartSelect from './DepartSelect'
import { mapActions, mapGetters } from 'vuex'
import { mixinDevice } from '@/utils/mixin.js'
@ -69,7 +75,8 @@
components: {
HeaderNotice,
UserPassword,
DepartSelect
DepartSelect,
SettingDrawer
},
props: {
theme: {
@ -112,6 +119,9 @@
},
updateCurrentDepart(){
this.$refs.departSelect.show()
},
systemSetting(){
this.$refs.settingDrawer.showDrawer()
}
}
}

View File

@ -323,30 +323,6 @@ export const constantRouterMap = [
]
},
// {
// path: '/',
// name: 'index',
// component: TabLayout,
// meta: {title: '首页'},
// redirect: '/dashboard/workplace',
// children: [
// {
// path: '/online',
// name: 'online',
// redirect: '/online',
// component: RouteView,
// meta: {title: '在线开发', icon: 'dashboard', permission: ['dashboard']},
// children: [
// {
// path: '/online/auto/:code',
// name: 'report',
// component: () => import('@/views/modules/online/cgreport/OnlCgreportAutoList')
// },
// ]
// },
// ]
// },
{
path: '/test',
component: BlankLayout,

View File

@ -18,6 +18,9 @@ import VueApexCharts from 'vue-apexcharts'
import preview from 'vue-photo-preview'
import 'vue-photo-preview/dist/skin.css'
import "@jeecg/antd-onine"
import '@jeecg/antd-onine/dist/OnlineForm.css'
import {
ACCESS_TOKEN,

View File

@ -3,6 +3,7 @@ import { login, logout, phoneLogin } from "@/api/login"
import { ACCESS_TOKEN, USER_NAME,USER_INFO,USER_AUTH,SYS_BUTTON_AUTH } from "@/store/mutation-types"
import { welcome } from "@/utils/util"
import { queryPermissionsByUser } from '@/api/api'
import { getAction } from '@/api/manage'
const user = {
state: {
@ -36,6 +37,30 @@ const user = {
},
actions: {
// CAS验证登录
ValidateLogin({ commit }, userInfo) {
return new Promise((resolve, reject) => {
getAction("/cas/client/validateLogin",userInfo).then(response => {
console.log("----cas 登录--------",response);
if(response.success){
const result = response.result
const userInfo = result.userInfo
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
commit('SET_TOKEN', result.token)
commit('SET_INFO', userInfo)
commit('SET_NAME', { username: userInfo.username,realname: userInfo.realname, welcome: welcome() })
commit('SET_AVATAR', userInfo.avatar)
resolve(response)
}else{
resolve(response)
}
}).catch(error => {
reject(error)
})
})
},
// 登录
Login({ commit }, userInfo) {
return new Promise((resolve, reject) => {
@ -115,6 +140,9 @@ const user = {
Vue.ls.remove(ACCESS_TOKEN)
//console.log('logoutToken: '+ logoutToken)
logout(logoutToken).then(() => {
//var sevice = "http://"+window.location.host+"/";
//var serviceUrl = encodeURIComponent(sevice);
//window.location.href = window._CONFIG['casPrefixUrl']+"/logout?service="+serviceUrl;
resolve()
}).catch(() => {
resolve()

View File

@ -78,9 +78,11 @@ service.interceptors.request.use(config => {
config.headers[ 'X-Access-Token' ] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
}
if(config.method=='get'){
config.params = {
_t: Date.parse(new Date())/1000,
...config.params
if(config.url.indexOf("sys/dict/getDictItems")<0){
config.params = {
_t: Date.parse(new Date())/1000,
...config.params
}
}
}
return config

View File

@ -232,4 +232,23 @@ export function showDealBtn(bpmStatus){
return true;
}
return false;
}
/**
* 增强CSS可以在页面上输出全局css
* @param css 要增强的css
* @param id style标签的id可以用来清除旧样式
*/
export function cssExpand(css, id) {
let style = document.createElement('style')
style.type = "text/css"
style.innerHTML = `@charset "UTF-8"; ${css}`
// 清除旧样式
if (id) {
let $style = document.getElementById(id)
if ($style != null) $style.outerHTML = ''
style.id = id
}
// 应用新样式
document.head.appendChild(style)
}

View File

@ -209,10 +209,10 @@
})
getVisitInfo().then(res=>{
if(res.success){
console.log("aaaaaa",res.result)
this.visitInfo = res.result;
}
})
console.log("aaaaaa",res.result)
this.visitInfo = res.result;
}
})
},
}
}

View File

@ -1,307 +1,37 @@
<template>
<div>
<a-card :borderd="false">
<a-card :bordered="false">
<a-tabs>
<a-button @click="handleTableCheck" type="primary">表单验证</a-button>
<span style="padding-left:8px;"></span>
<a-tooltip placement="top" title="获取值,忽略表单验证" :autoAdjustOverflow="true">
<a-button @click="handleTableGet" type="primary">获取值</a-button>
</a-tooltip>
<span style="padding-left:8px;"></span>
<a-tooltip placement="top" title="模拟加载1000条数据" :autoAdjustOverflow="true">
<a-button @click="handleTableSet" type="primary">设置值</a-button>
</a-tooltip>
<a-tab-pane tab="普通列表" key="1">
<default-table/>
</a-tab-pane>
<a-tab-pane tab="只读列表" key="2">
<read-only-table/>
</a-tab-pane>
<j-editable-table
ref="editableTable"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:rowNumber="true"
:rowSelection="true"
:actionButton="true"
style="margin-top: 8px;"
@selectRowChange="handleSelectRowChange">
<a-tab-pane tab="三级联动" key="3">
<three-linkage/>
</a-tab-pane>
<template v-slot:action="props">
<a @click="handleDelete(props)">{{ props.text }}</a>
</template>
</a-tabs>
</j-editable-table>
</a-card>
<br>
<a-card title="只读列表">
<j-editable-table
:columns="columns1"
:dataSource="dataSource1"
:rowNumber="true"
:rowSelection="true"
:maxHeight="200"
:disabled="true"
/>
</a-card>
</div>
</a-card>
</template>
<script>
import moment from 'moment'
import JEditableTable from '@/components/jeecg/JEditableTable'
import { FormTypes } from '@/utils/JEditableTableUtil'
import { randomUUID, randomNumber } from '@/utils/util'
import DefaultTable from './modules/JEditableTable/DefaultTable'
import ReadOnlyTable from './modules/JEditableTable/ReadOnlyTable'
import ThreeLinkage from './modules/JEditableTable/ThreeLinkage'
export default {
name: 'JeecgEditableTableExample',
components: {
JEditableTable
},
components: { DefaultTable, ReadOnlyTable, ThreeLinkage },
data() {
return {
loading: false,
columns: [
{
title: '字段名称',
key: 'dbFieldName',
// width: '19%',
width: '300px',
type: FormTypes.input,
defaultValue: '',
placeholder: '请输入${title}',
validateRules: [
{
required: true, // 必填
message: '请输入${title}' // 显示的文本
},
{
pattern: /^[a-z|A-Z][a-z|A-Z\d_-]{0,}$/, // 正则
message: '${title}必须以字母开头可包含数字下划线横杠'
}
]
},
{
title: '文件域',
key: 'upload',
type: FormTypes.upload,
// width: '19%',
width: '300px',
placeholder: '点击上传',
token: true,
responseName: 'message',
action: window._CONFIG['domianURL'] + '/sys/common/upload'
},
{
title: '字段类型',
key: 'dbFieldType',
// width: '18%',
width: '300px',
type: FormTypes.select,
options: [ // 下拉选项
{ title: 'String', value: 'string' },
{ title: 'Integer', value: 'int' },
{ title: 'Double', value: 'double' },
{ title: 'Boolean', value: 'boolean' }
],
allowInput: true,
defaultValue: '',
placeholder: '请选择${title}',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '性别字典',
key: 'sex_dict',
width: '300px',
type: FormTypes.select,
options: [],
dictCode: 'sex',
placeholder: '请选择${title}',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '多选测试',
key: 'multipleSelect',
// width: '18%',
width: '300px',
type: FormTypes.select,
props: { 'mode': 'multiple' }, // 支持多选
options: [
{ title: 'String', value: 'string' },
{ title: 'Integer', value: 'int' },
{ title: 'Double', value: 'double' },
{ title: 'Boolean', value: 'boolean' }
],
defaultValue: ['int', 'boolean'], // 多个默认项
// defaultValue: 'string,double,int', // 也可使用这种方式
placeholder: '这里可以多选',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '字段长度',
key: 'dbLength',
// width: '8%',
width: '100px',
type: FormTypes.inputNumber,
defaultValue: 32,
placeholder: '${title}',
validateRules: [{ required: true, message: '请输入${title}' }]
},
{
title: '日期',
key: 'datetime',
// width: '22%',
width: '320px',
type: FormTypes.datetime,
defaultValue: '2019-4-30 14:52:22',
placeholder: '请选择${title}',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '可以为空',
key: 'isNull',
// width: '8%',
width: '100px',
type: FormTypes.checkbox,
customValue: ['Y', 'N'], // true ,false
defaultChecked: false
},
{
title: '操作',
key: 'action',
// width: '8%',
width: '100px',
type: FormTypes.slot,
slotName: 'action',
defaultValue: '删除'
}
],
dataSource: [],
selectedRowIds: [],
// table2
columns1: [
{
title: '输入框',
key: 'input',
type: FormTypes.input,
placeholder: '清输入'
},
{
title: '下拉框',
key: 'select',
type: FormTypes.select,
options: [
{ title: 'String', value: 'string' },
{ title: 'Integer', value: 'int' },
{ title: 'Double', value: 'double' },
{ title: 'Boolean', value: 'boolean' }
],
placeholder: '请选择'
},
{
title: '多选框',
key: 'checkbox',
type: FormTypes.checkbox,
customValue: [true, false]
},
{
title: '日期',
key: 'datetime',
type: FormTypes.datetime
}
],
dataSource1: []
}
return {}
},
created() {
},
mounted() {
this.randomData(23, false)
this.dataSource1 = [
{ input: 'hello', select: 'int', checkbox: true, datetime: '2019-6-17 14:50:48' },
{ input: 'world', select: 'string', checkbox: false, datetime: '2019-6-16 14:50:48' },
{ input: 'one', select: 'double', checkbox: true, datetime: '2019-6-17 15:50:48' },
{ input: 'two', select: 'boolean', checkbox: false, datetime: '2019-6-14 14:50:48' },
{ input: 'three', select: '', checkbox: false, datetime: '2019-6-13 14:50:48' }
]
},
methods: {
/** 表单验证 */
handleTableCheck() {
this.$refs.editableTable.getValues((error) => {
if (error === 0) {
this.$message.success('验证通过')
} else {
this.$message.error('验证未通过')
}
})
},
/** 获取值,忽略表单验证 */
handleTableGet() {
this.$refs.editableTable.getValues((error, values) => {
console.log('values:', values)
}, false)
console.log('deleteIds:', this.$refs.editableTable.getDeleteIds())
this.$message.info('获取值成功请看控制台输出')
},
/** 模拟加载1000条数据 */
handleTableSet() {
this.randomData(1000, true)
},
handleSelectRowChange(selectedRowIds) {
this.selectedRowIds = selectedRowIds
},
/* 随机生成数据 */
randomData(size, loading = false) {
if (loading) {
this.loading = true
}
let randomDatetime = () => {
let time = parseInt(randomNumber(1000, 9999999999999))
return moment(new Date(time)).format('YYYY-MM-DD HH:mm:ss')
}
let begin = Date.now()
let values = []
for (let i = 0; i < size; i++) {
values.push({
id: randomUUID(),
dbFieldName: `name_${i + 1}`,
// dbFieldTxt: randomString(10),
multipleSelect: ['string', ['int', 'double', 'boolean'][randomNumber(0, 2)]],
dbFieldType: ['string', 'int', 'double', 'boolean'][randomNumber(0, 3)],
dbLength: randomNumber(0, 233),
datetime: randomDatetime(),
isNull: ['Y', 'N'][randomNumber(0, 1)]
})
}
this.dataSource = values
let end = Date.now()
let diff = end - begin
if (loading && diff < size) {
setTimeout(() => {
this.loading = false
}, size - diff)
}
},
handleDelete(props) {
let { rowId, target } = props
target.removeRows(rowId)
}
}
methods: {}
}
</script>

View File

@ -49,7 +49,7 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="选择部门">
<j-select-depart v-model="departId"></j-select-depart>
<j-select-depart v-model="departId" :multi="true"></j-select-depart>
</a-form-item>
</a-col>
<a-col :span="12">选中的部门ID(v-model):{{ departId }}</a-col>
@ -217,10 +217,8 @@
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="cron表达式">
<a-input @click="openModal" placeholder="corn表达式" v-model="cron.label" readOnly >
<a-icon slot="prefix" type="schedule" title="corn控件"/>
</a-input>
<VueCron ref="innerVueCron" :data="cron" @change="changeCron" ></VueCron>
<j-cron ref="innerVueCron" v-decorator="['cronExpression', {'initialValue':'0/1 * * * * ?'}]" @change="setCorn"></j-cron>
<!-- <j-cron ref="innerVueCron" v-model="cron" @change="setCorn"></j-cron>-->
</a-form-item>
</a-col>
</a-row>
@ -245,7 +243,7 @@
import JSlider from '@/components/jeecg/JSlider'
import JSelectMultiple from '@/components/jeecg/JSelectMultiple'
import JTreeDict from "../../components/jeecg/JTreeDict.vue";
import VueCron from "./modules/VueCronModal.vue";
import JCron from "@/components/jeecg/JCron.vue";
export default {
name: 'SelectDemo',
components: {
@ -257,7 +255,7 @@
JCheckbox,
JCodeEditor,
JDate, JEditor, JEllipsis, JGraphicCode, JSlider, JSelectMultiple,
VueCron
JCron
},
data() {
return {
@ -314,10 +312,7 @@ sayHi('hello, world!')`
style: { top: '20px' },
fullScreen: true
},
cron: {
label: '',
value: {}
}
cron: '',
}
},
computed: {
@ -372,14 +367,12 @@ sayHi('hello, world!')`
}
this.modal.fullScreen = mode
},
openModal(){
this.$refs.innerVueCron.show()
},
changeCron(val){
this.cron=val;
console.log(val);
}
setCorn(data){
this.$nextTick(() => {
this.form.cronExpression = data;
})
}
}
}
</script>

View File

@ -0,0 +1,91 @@
<template>
<a-card :bordered="false">
<a-table
rowKey="id"
bordered
:columns="columns"
:dataSource="dataSource"
:pagination="false"
>
</a-table>
</a-card>
</template>
<script>
export default {
name: 'TableTotal',
data() {
return {
columns: [
{
title: '#',
width: '180px',
align: 'center',
dataIndex: 'rowIndex',
customRender: function (text, r, index) {
return (text !== '合计') ? (parseInt(index) + 1) : text
}
},
{
title: '姓名',
dataIndex: 'name',
},
{
title: '贡献点',
dataIndex: 'point',
},
{
title: '等级',
dataIndex: 'level',
},
{
title: '更新时间',
dataIndex: 'updateTime',
},
],
dataSource: [
{ name: '张三', point: 23, level: 3, updateTime: '2019-8-14' },
{ name: '小王', point: 6, level: 1, updateTime: '2019-8-13' },
{ name: '李四', point: 53, level: 8, updateTime: '2019-8-12' },
{ name: '小红', point: 44, level: 5, updateTime: '2019-8-11' },
{ name: '王五', point: 97, level: 10, updateTime: '2019-8-10' },
{ name: '小明', point: 33, level: 2, updateTime: '2019-8-10' },
]
}
},
mounted() {
this.tableAddTotalRow(this.columns, this.dataSource)
},
methods: {
/** 表格增加合计行 */
tableAddTotalRow(columns, dataSource) {
let numKey = 'rowIndex'
let totalRow = { [numKey]: '合计' }
columns.forEach(column => {
let { key, dataIndex } = column
if (![key, dataIndex].includes(numKey)) {
let total = 0
dataSource.forEach(data => {
total += /^\d+\.?\d?$/.test(data[dataIndex]) ? Number.parseInt(data[dataIndex]) : Number.NaN
console.log(data[dataIndex], ':', (/^\d+\.?\d?$/.test(data[dataIndex]) ? Number.parseInt(data[dataIndex]) : Number.NaN))
})
if (Number.isNaN(total)) {
total = '-'
}
totalRow[dataIndex] = total
}
})
dataSource.push(totalRow)
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,250 @@
<template>
<div>
<a-button @click="handleTableCheck" type="primary">表单验证</a-button>
<span style="padding-left:8px;"></span>
<a-tooltip placement="top" title="获取值,忽略表单验证" :autoAdjustOverflow="true">
<a-button @click="handleTableGet" type="primary">获取值</a-button>
</a-tooltip>
<span style="padding-left:8px;"></span>
<a-tooltip placement="top" title="模拟加载1000条数据" :autoAdjustOverflow="true">
<a-button @click="handleTableSet" type="primary">设置值</a-button>
</a-tooltip>
<j-editable-table
ref="editableTable"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:rowNumber="true"
:rowSelection="true"
:actionButton="true"
:dragSort="true"
style="margin-top: 8px;"
@selectRowChange="handleSelectRowChange">
<template v-slot:action="props">
<a @click="handleDelete(props)">{{ props.text }}</a>
</template>
</j-editable-table>
</div>
</template>
<script>
import moment from 'moment'
import { FormTypes } from '@/utils/JEditableTableUtil'
import { randomUUID, randomNumber } from '@/utils/util'
import JEditableTable from '@/components/jeecg/JEditableTable'
export default {
name: 'DefaultTable',
components: { JEditableTable },
data() {
return {
loading: false,
columns: [
{
title: '字段名称',
key: 'dbFieldName',
// width: '19%',
width: '300px',
type: FormTypes.input,
defaultValue: '',
placeholder: '请输入${title}',
validateRules: [
{
required: true, // 必填
message: '请输入${title}' // 显示的文本
},
{
pattern: /^[a-z|A-Z][a-z|A-Z\d_-]{0,}$/, // 正则
message: '${title}必须以字母开头可包含数字下划线横杠'
}
]
},
{
title: '文件域',
key: 'upload',
type: FormTypes.upload,
// width: '19%',
width: '300px',
placeholder: '点击上传',
token: true,
responseName: 'message',
action: window._CONFIG['domianURL'] + '/sys/common/upload'
},
{
title: '字段类型',
key: 'dbFieldType',
// width: '18%',
width: '300px',
type: FormTypes.select,
options: [ // 下拉选项
{ title: 'String', value: 'string' },
{ title: 'Integer', value: 'int' },
{ title: 'Double', value: 'double' },
{ title: 'Boolean', value: 'boolean' }
],
allowInput: true,
defaultValue: '',
placeholder: '请选择${title}',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '性别字典',
key: 'sex_dict',
width: '300px',
type: FormTypes.select,
options: [],
dictCode: 'sex',
placeholder: '请选择${title}',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '多选测试',
key: 'multipleSelect',
// width: '18%',
width: '300px',
type: FormTypes.select,
props: { 'mode': 'multiple' }, // 支持多选
options: [
{ title: 'String', value: 'string' },
{ title: 'Integer', value: 'int' },
{ title: 'Double', value: 'double' },
{ title: 'Boolean', value: 'boolean' }
],
defaultValue: ['int', 'boolean'], // 多个默认项
// defaultValue: 'string,double,int', // 也可使用这种方式
placeholder: '这里可以多选',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '字段长度',
key: 'dbLength',
// width: '8%',
width: '100px',
type: FormTypes.inputNumber,
defaultValue: 32,
placeholder: '${title}',
validateRules: [{ required: true, message: '请输入${title}' }]
},
{
title: '日期',
key: 'datetime',
// width: '22%',
width: '320px',
type: FormTypes.datetime,
defaultValue: '2019-4-30 14:52:22',
placeholder: '请选择${title}',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '可以为空',
key: 'isNull',
// width: '8%',
width: '100px',
type: FormTypes.checkbox,
customValue: ['Y', 'N'], // true ,false
defaultChecked: false
},
{
title: '操作',
key: 'action',
// width: '8%',
width: '100px',
type: FormTypes.slot,
slotName: 'action',
defaultValue: '删除'
}
],
dataSource: [],
selectedRowIds: []
}
},
mounted() {
this.randomData(23, false)
},
methods: {
/** 表单验证 */
handleTableCheck() {
this.$refs.editableTable.getValues((error) => {
if (error === 0) {
this.$message.success('验证通过')
} else {
this.$message.error('验证未通过')
}
})
},
/** 获取值,忽略表单验证 */
handleTableGet() {
this.$refs.editableTable.getValues((error, values) => {
console.log('values:', values)
}, false)
console.log('deleteIds:', this.$refs.editableTable.getDeleteIds())
this.$message.info('获取值成功请看控制台输出')
},
/** 模拟加载1000条数据 */
handleTableSet() {
this.randomData(1000, true)
},
handleSelectRowChange(selectedRowIds) {
this.selectedRowIds = selectedRowIds
},
/* 随机生成数据 */
randomData(size, loading = false) {
if (loading) {
this.loading = true
}
let randomDatetime = () => {
let time = parseInt(randomNumber(1000, 9999999999999))
return moment(new Date(time)).format('YYYY-MM-DD HH:mm:ss')
}
let begin = Date.now()
let values = []
for (let i = 0; i < size; i++) {
values.push({
id: randomUUID(),
dbFieldName: `name_${i + 1}`,
// dbFieldTxt: randomString(10),
multipleSelect: ['string', ['int', 'double', 'boolean'][randomNumber(0, 2)]],
dbFieldType: ['string', 'int', 'double', 'boolean'][randomNumber(0, 3)],
dbLength: randomNumber(0, 233),
datetime: randomDatetime(),
isNull: ['Y', 'N'][randomNumber(0, 1)]
})
}
this.dataSource = values
let end = Date.now()
let diff = end - begin
if (loading && diff < size) {
setTimeout(() => {
this.loading = false
}, size - diff)
}
},
handleDelete(props) {
let { rowId, target } = props
target.removeRows(rowId)
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,70 @@
<template>
<j-editable-table
:columns="columns"
:dataSource="dataSource"
:rowNumber="true"
:rowSelection="true"
:maxHeight="400"
:disabled="true"
/>
</template>
<script>
import { FormTypes } from '@/utils/JEditableTableUtil'
import JEditableTable from '@/components/jeecg/JEditableTable'
export default {
name: 'ReadOnlyTable',
components: { JEditableTable },
data() {
return {
columns: [
{
title: '输入框',
key: 'input',
type: FormTypes.input,
placeholder: '清输入'
},
{
title: '下拉框',
key: 'select',
type: FormTypes.select,
options: [
{ title: 'String', value: 'string' },
{ title: 'Integer', value: 'int' },
{ title: 'Double', value: 'double' },
{ title: 'Boolean', value: 'boolean' }
],
placeholder: '请选择'
},
{
title: '多选框',
key: 'checkbox',
type: FormTypes.checkbox,
customValue: [true, false]
},
{
title: '日期',
key: 'datetime',
type: FormTypes.datetime
}
],
dataSource: [
{ input: 'hello', select: 'int', checkbox: true, datetime: '2019-6-17 14:50:48' },
{ input: 'world', select: 'string', checkbox: false, datetime: '2019-6-16 14:50:48' },
{ input: 'one', select: 'double', checkbox: true, datetime: '2019-6-17 15:50:48' },
{ input: 'two', select: 'boolean', checkbox: false, datetime: '2019-6-14 14:50:48' },
{ input: 'three', select: '', checkbox: false, datetime: '2019-6-13 14:50:48' }
]
}
},
mounted() {
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,129 @@
<template>
<j-editable-table
:columns="columns"
:dataSource="dataSource"
:rowNumber="true"
:actionButton="true"
:rowSelection="true"
:maxHeight="400"
@valueChange="handleValueChange"
/>
</template>
<script>
import { FormTypes } from '@/utils/JEditableTableUtil'
import JEditableTable from '@/components/jeecg/JEditableTable'
export default {
name: 'ThreeLinkage',
components: { JEditableTable },
data() {
return {
columns: [
{
title: '/直辖市/自治区',
key: 's1',
type: FormTypes.select,
width: '240px',
options: [],
placeholder: '请选择${title}'
},
{
title: '市',
key: 's2',
type: FormTypes.select,
width: '240px',
options: [],
placeholder: '请选择${title}'
},
{
title: '/',
key: 's3',
type: FormTypes.select,
width: '240px',
options: [],
placeholder: '请选择${title}'
}
],
dataSource: [],
mockData: [
{ label: '北京市', value: '110000', parent: null },
{ label: '天津市', value: '120000', parent: null },
{ label: '河北省', value: '130000', parent: null },
{ label: '上海市', value: '310000', parent: null },
{ label: '北京市', value: '110100', parent: '110000' },
{ label: '天津市市', value: '120100', parent: '120000' },
{ label: '石家庄市', value: '130100', parent: '130000' },
{ label: '唐山市', value: '130200', parent: '130000' },
{ label: '秦皇岛市', value: '130300', parent: '130000' },
{ label: '上海市', value: '310100', parent: '310000' },
{ label: '东城区', value: '110101', parent: '110100' },
{ label: '西城区', value: '110102', parent: '110100' },
{ label: '朝阳区', value: '110105', parent: '110100' },
{ label: '和平区', value: '120101', parent: '120000' },
{ label: '河东区', value: '120102', parent: '120000' },
{ label: '河西区', value: '120103', parent: '120000' },
{ label: '黄浦区', value: '310101', parent: '310100' },
{ label: '徐汇区', value: '310104', parent: '310100' },
{ label: '长宁区', value: '310105', parent: '310100' },
{ label: '长安区', value: '130102', parent: '130100' },
{ label: '桥西区', value: '130104', parent: '130100' },
{ label: '新华区', value: '130105', parent: '130100' },
{ label: '路南区', value: '130202', parent: '130200' },
{ label: '路北区', value: '130203', parent: '130200' },
{ label: '古冶区', value: '130204', parent: '130200' },
{ label: '海港区', value: '130302', parent: '130300' },
{ label: '山海关区', value: '130303', parent: '130300' },
{ label: '北戴河区', value: '130304', parent: '130300' },
]
}
},
mounted() {
// 初始化数据
this.columns[0].options = this.request(null)
},
methods: {
request(parentId) {
return this.mockData.filter(i => i.parent === parentId)
},
/** 当选项被改变时,联动其他组件 */
handleValueChange(event) {
const { type, row, column, value, target } = event
if (type === FormTypes.select) {
// 第一列
if (column.key === 's1') {
// 设置第二列的 options
this.columns[1].options = this.request(value)
// 清空后两列的数据
target.setValues([{
rowKey: row.id,
values: { s2: '', s3: '' }
}])
this.columns[2].options = []
} else
// 第二列
if (column.key === 's2') {
this.columns[2].options = this.request(value)
target.setValues([{
rowKey: row.id,
values: { s3: '' }
}])
}
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -486,7 +486,7 @@
days = this.result.day.cronLastSpecificDomDay + 'L';
break;
case '9':
days = 'L-' + this.day.cronDaysBeforeEomMinus;
days = 'L-' + this.result.day.cronDaysBeforeEomMinus;
break;
case '10':
days = this.result.day.cronDaysNearestWeekday+"W";

View File

@ -0,0 +1,435 @@
<template>
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="24">
<a-col :md="6" :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-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">
<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 @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-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">
<template 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 v-if="record.isDbSynch!='Y'">
<a @click="openSyncModal(record.id)">同步数据库</a>
</a-menu-item>
<template v-if="record.isDbSynch=='Y' && record.tableType !== 3">
<a-menu-item>
<a @click="goPageOnline(record)">功能测试</a>
</a-menu-item>
<a-menu-item>
<a @click="handleOnlineUrlShow(record)">配置地址</a>
</a-menu-item>
</template>
<a-menu-item>
<a @click="handleRemoveRecord(record.id)">移除</a>
</a-menu-item>
<a-menu-item>
<a @click="handleDelete(record.id)">删除</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
<template slot="dbsync" slot-scope="text">
<span v-if="text==='Y'" style="color:limegreen">已同步</span>
<span v-if="text==='N'" style="color:red">未同步</span>
</template>
</a-table>
</div>
<!-- table区域-end -->
<!-- 表单区域 -->
<onl-cgform-head-modal ref="modalForm" @ok="modalFormOk"></onl-cgform-head-modal>
<!-- 同步数据库提示框 -->
<a-modal
:width="500"
:height="300"
title="同步数据库"
:visible="syncModalVisible"
@cancel="handleCancleDbSync"
style="top:5%;height: 95%;">
<template slot="footer">
<a-button @click="handleCancleDbSync">关闭</a-button>
<a-button type="primary" :loading="syncLoading" @click="handleDbSync">
确定
</a-button>
</template>
<a-radio-group v-model="synMethod">
<a-radio style="display: block;width: 30px;height: 30px" value="normal">普通同步(保留表数据)</a-radio>
<a-radio style="display: block;width: 30px;height: 30px" value="force">强制同步(删除表,重新生成)</a-radio>
</a-radio-group>
</a-modal>
<!-- 提示online报表链接 -->
<a-modal
:title="onlineUrlTitle"
:visible="onlineUrlVisible"
@cancel="handleOnlineUrlClose">
<template slot="footer">
<a-button @click="handleOnlineUrlClose">关闭</a-button>
<a-button type="primary" class="copy-this-text" :data-clipboard-text="onlineUrl" @click="onCopyUrl">复制</a-button>
</template>
<p>{{ onlineUrl }}</p>
</a-modal>
<enhance-js ref="ehjs"></enhance-js>
<enhance-sql ref="ehsql"></enhance-sql>
<enhance-java ref="ehjava"></enhance-java>
<trans-db2-online ref="transd2o" @ok="transOk"></trans-db2-online>
<code-generator ref="cg"></code-generator>
<onl-cgform-button-list ref="btnList"></onl-cgform-button-list>
</a-card>
</template>
<script>
import { initDictOptions, filterDictText } from '@/components/dict/JDictSelectUtil'
import { deleteAction, postAction } from '@/api/manage'
import JDictSelectTag from '../../../../components/dict/JDictSelectTag.vue'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import Clipboard from 'clipboard'
export default {
name: 'OnlCgformHeadList',
mixins: [JeecgListMixin],
components: {
JDictSelectTag,
},
data() {
return {
description: 'Online表单开发管理页面',
// 表头
columns: [
{
title: '#',
dataIndex: '',
key: 'rowIndex',
width: 60,
align: 'center',
customRender: function(t, r, index) {
return parseInt(index) + 1
}
},
{
title: '表类型',
align: 'center',
dataIndex: 'tableType',
customRender: (text) => {
return filterDictText(this.tableTypeDictOptions, `${text}`)
}
},
{
title: '表名',
align: 'center',
dataIndex: 'tableName'
},
{
title: '表描述',
align: 'center',
dataIndex: 'tableTxt'
},
{
title: '版本',
align: 'center',
dataIndex: 'tableVersion'
},
{
title: '同步数据库状态',
align: 'center',
dataIndex: 'isDbSynch',
scopedSlots: { customRender: 'dbsync' }
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
scopedSlots: { customRender: 'action' }
}
],
url: {
list: '/online/cgform/head/list',
delete: '/online/cgform/head/delete',
deleteBatch: '/online/cgform/head/deleteBatch',
doDbSynch: '/online/cgform/api/doDbSynch/',
removeRecord: '/online/cgform/head/removeRecord'
},
tableTypeDictOptions: [],
sexDictOptions: [],
syncModalVisible: false,
syncFormId: '',
synMethod: 'normal',
syncLoading: false,
onlineUrlTitle: '',
onlineUrlVisible: false,
onlineUrl: '',
selectedRowKeys: [],
selectedRows: []
}
},
created() {
//初始化字典 - 表类型
initDictOptions('cgform_table_type').then((res) => {
if (res.success) {
this.tableTypeDictOptions = res.result
}
})
this.loadData()
},
methods: {
doDbSynch(id) {
postAction(this.url.doDbSynch + id, { synMethod: '1' }).then((res) => {
if (res.success) {
this.$message.success(res.message)
this.loadData()
} else {
this.$message.warning(res.message)
}
})
},
handleCancleDbSync() {
this.syncModalVisible = false
},
handleDbSync() {
this.syncLoading = true
postAction(this.url.doDbSynch + this.syncFormId + '/' + this.synMethod).then((res) => {
this.syncModalVisible = false
this.syncLoading = false
if (res.success) {
this.$message.success(res.message)
this.loadData()
} else {
this.$message.warning(res.message)
}
})
},
openSyncModal(id) {
this.syncModalVisible = true
this.syncFormId = id
},
goPageOnline(rd) {
if(rd.isTree=='Y'){
this.$router.push({ path: '/online/cgformTreeList/' + rd.id })
}else{
this.$router.push({ path: '/online/cgformList/' + rd.id })
}
},
handleOnlineUrlClose() {
this.onlineUrlTitle = ''
this.onlineUrlVisible = false
},
handleOnlineUrlShow(record) {
if(record.isTree=='Y'){
this.onlineUrl = `/online/cgformTreeList/${record.id}`
}else{
this.onlineUrl = `/online/cgformList/${record.id}`
}
this.onlineUrlVisible = true
this.onlineUrlTitle = '菜单链接[' + record.tableTxt + ']'
},
handleRemoveRecord(id) {
let that = this
this.$confirm({
title: '确认要移除此记录?',
onOk() {
deleteAction(that.url.removeRecord, { id: id }).then((res) => {
if (res.success) {
that.$message.success('移除成功')
that.loadData()
} else {
that.$message.warning(res.message)
}
})
},
onCancel() {
}
})
},
doEnhanceJs() {
if (!this.selectedRowKeys || this.selectedRowKeys.length != 1) {
this.$message.warning('请先选中一条记录')
return
}
this.$refs.ehjs.show(this.selectedRowKeys[0])
},
doEnhanceSql() {
if (!this.selectedRowKeys || this.selectedRowKeys.length != 1) {
this.$message.warning('请先选中一条记录')
return
}
this.$refs.ehsql.show(this.selectedRowKeys[0])
},
doEnhanceJava() {
if (!this.selectedRowKeys || this.selectedRowKeys.length != 1) {
this.$message.warning('请先选中一条记录')
return
}
this.$refs.ehjava.show(this.selectedRowKeys[0])
},
doCgformButton() {
if (!this.selectedRowKeys || this.selectedRowKeys.length != 1) {
this.$message.warning('请先选中一条记录')
return
}
this.$refs.btnList.show(this.selectedRowKeys[0])
//this.$router.push({ path: '/online/cgformButton/' + this.selectedRowKeys[0] })
},
importOnlineForm() {
this.$refs.transd2o.show()
},
transOk() {
this.loadData()
},
goGenerateCode() {
if (!this.selectedRowKeys || this.selectedRowKeys.length != 1) {
this.$message.warning('请先选中一条记录')
return
}
let row = this.selectedRows[0]
if (!row.isDbSynch || row.isDbSynch == 'N') {
this.$message.warning('请先同步数据库!')
return
}
if (row.tableType == 3) {
this.$message.warning('请选中该表对应的主表生成代码')
return
}
this.$refs.cg.show(this.selectedRowKeys[0])
},
onSelectChange(keys, rows) {
this.selectedRowKeys = keys
this.selectedRows = rows
},
onCopyUrl(){
var clipboard = new Clipboard('.copy-this-text')
clipboard.on('success', () => {
clipboard.destroy()
this.$message.success('复制成功')
this.handleOnlineUrlClose()
})
clipboard.on('error', () => {
this.$message.error('该浏览器不支持自动复制')
clipboard.destroy()
})
}
}
}
</script>
<style lang="less">
.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
}
.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
}
.valid-error-cust{
.ant-select-selection{
border:2px solid #f5222d;
}
}
</style>

View File

@ -0,0 +1,619 @@
<template>
<a-card :bordered="false" style="height: 100%">
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="24" v-if="queryInfo && queryInfo.length>0">
<template v-for="(item,index) in queryInfo">
<template v-if=" item.hidden==='1' ">
<a-col v-if="item.view=='datetime'" :md="12" :sm="16" :key=" 'query'+index " v-show="toggleSearchStatus">
<online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
</a-col>
<a-col v-else :md="6" :sm="8" :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 v-if="item.view=='datetime'" :md="12" :sm="16" :key=" 'query'+index ">
<online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
</a-col>
<a-col v-else :md="6" :sm="8" :key=" 'query'+index ">
<online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
</a-col>
</template>
</template>
<a-col :md="6" :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="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>
<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">
{{ item.buttonName }}
</a-button>
<a-button
v-else-if=" item.optType=='action' "
:key=" 'cgbtn'+index "
@click="cgButtonActionHandler(item.buttonCode)"
type="primary"
:icon="item.buttonIcon"
style="margin-left:8px">
{{ item.buttonName }}
</a-button>
</template>
<a-button
v-if="buttonSwitch.batch_delete"
@click="handleDelBatch"
style="margin-left:8px"
v-show="table.selectedRowKeys.length > 0"
ghost
type="primary"
icon="delete">批量删除</a-button>
</div>
<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>
</div>
<a-table
ref="cgformAutoList"
bordered
size="middle"
rowKey="id"
:columns="table.columns"
:dataSource="table.dataSource"
:pagination="table.pagination"
:loading="table.loading"
:rowSelection="{selectedRowKeys:table.selectedRowKeys, onChange: handleChangeInTableSelect}"
@change="handleTableChange"
style="min-height: 300px">
<template slot="dateSlot" slot-scope="text">
<span>{{ getFormatDate(text) }}</span>
</template>
<template slot="htmlSlot" slot-scope="text">
<div v-html="text"></div>
</template>
<template slot="imgSlot" slot-scope="text">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无此图片</span>
<img v-else :src="getImgView(text)" height="25px" alt="图片不存在" style="max-width:80px;font-size: 12px;font-style: italic;"/>
</template>
<template slot="fileSlot" slot-scope="text">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无此文件</span>
<a-button
v-else
:ghost="true"
type="primary"
icon="download"
size="small"
@click="uploadFile(text)">
下载
</a-button>
</template>
<span slot="action" slot-scope="text, record">
<template v-if="hasBpmStatus">
<template v-if="record.bpm_status == '1'||record.bpm_status == ''|| record.bpm_status == null">
<template v-if="buttonSwitch.update">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical"/>
</template>
</template>
</template>
<template v-else>
<template v-if="buttonSwitch.update">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical"/>
</template>
</template>
<a-dropdown>
<a class="ant-dropdown-link">
更多 <a-icon type="down" />
</a>
<a-menu slot="overlay">
<a-menu-item >
<a href="javascript:;" @click="handleDetail(record)">详情</a>
</a-menu-item>
<template v-if="hasBpmStatus">
</template>
<template v-else>
<a-menu-item v-if="buttonSwitch.delete">
<a-popconfirm title="确定删除吗?" @confirm="() => handleDeleteOne(record)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</template>
<template v-if="cgButtonLinkList && cgButtonLinkList.length>0" v-for="(btnItem,btnIndex) in cgButtonLinkList">
<a-menu-item :key=" 'cgbtnLink'+btnIndex ">
<a href="javascript:void(0);" @click="cgButtonLinkHandler(record,btnItem.buttonCode,btnItem.optType)">
<a-icon v-if="btnItem.buttonIcon" :type="btnItem.buttonIcon" />
{{ btnItem.buttonName }}
</a>
</a-menu-item>
</template>
</a-menu>
</a-dropdown>
</span>
</a-table>
<OnlCgformAutoModal @success="handleFormSuccess" ref="modal" :code="code"></OnlCgformAutoModal>
<j-import-modal ref="importModal" :url="getImportUrl()" @ok="importOk"></j-import-modal>
</div>
</a-card>
</template>
<script>
import { postAction,getAction,deleteAction,downFile } from '@/api/manage'
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
import { filterObj } from '@/utils/util';
import JImportModal from '@/components/jeecg/JImportModal'
export default {
name: 'OnlCgFormAutoList',
components: {
JImportModal
},
data() {
return {
code: '',
description: '在线报表功能测试页面',
currentTableName:"",
url: {
getQueryInfo:'/online/cgform/api/getQueryInfo/',
getColumns: '/online/cgform/api/getColumns/',
getData: '/online/cgform/api/getData/',
optPre:"/online/cgform/api/form/",
exportXls:'/online/cgform/api/exportXls/',
buttonAction:'/online/cgform/api/doButton',
},
flowCodePre:"onl_",
isorter:{
column: 'createTime',
order: 'desc',
},
//dictOptions:{fieldName:[]}
dictOptions:{
},
cgButtonLinkList:[],
cgButtonList:[],
queryInfo:[],
queryParam:{
},
toggleSearchStatus:false,
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
}
},
actionColumn:{
title: '操作',
dataIndex: 'action',
scopedSlots: { customRender: 'action' },
fixed:"right",
align:"center",
width:150
},
formTemplate:"99",
EnhanceJS:'',
hideColumns:[],
buttonSwitch:{
add:true,
update:true,
delete:true,
batch_delete:true,
import:true,
export:true
},
hasBpmStatus:false,
}
},
created() {
this.initAutoList();
},
mounted(){
this.cgButtonJsHandler('mounted')
},
watch: {
'$route'() {
// 刷新参数放到这里去触发,就可以刷新相同界面了
this.initAutoList()
}
},
methods: {
hasBpmStatusFilter(){
var columnObjs = this.table.columns;
let columns = [];
for (var item of columnObjs) {
columns.push(item.dataIndex);
}
if(columns.includes('bpm_status')||columns.includes('BPM_STATUS')){
this.hasBpmStatus = true;
}else{
this.hasBpmStatus = false;
}
},
initQueryInfo(){
getAction(`${this.url.getQueryInfo}${this.code}`).then((res)=>{
console.log("--onlineList-获取查询条件配置",res);
if(res.success){
this.queryInfo = res.result
}else{
this.$message.warning(res.message)
}
})
},
initAutoList(){
if(!this.$route.params.code){
return false
}
this.table.loading = true
this.code = this.$route.params.code
getAction(`${this.url.getColumns}${this.code}`).then((res)=>{
console.log("--onlineList-加载动态列>>",res);
if(res.success){
this.dictOptions = res.result.dictOptions
this.formTemplate = res.result.formTemplate
this.description = res.result.description
this.currentTableName = res.result.currentTableName
this.initCgButtonList(res.result.cgButtonList)
this.initCgEnhanceJs(res.result.enhanceJs)
this.initButtonSwitch(res.result.hideColumns)
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);
}
}
}
currColumns.push(this.actionColumn);
this.table.columns = [...currColumns]
this.hasBpmStatusFilter();
this.loadData();
this.initQueryInfo();
}else{
this.$message.warning(res.message)
}
})
},
loadData(arg){
if(arg==1){
this.table.pagination.current=1
}
let params = this.getQueryParams();//查询条件
console.log("--onlineList-查询条件-->",params)
getAction(`${this.url.getData}${this.code}`,params).then((res)=>{
console.log("--onlineList-列表数据",res)
if(res.success){
let result = res.result;
if(Number(result.total)>0){
this.table.pagination.total = Number(result.total)
this.table.dataSource = result.records
}else{
this.table.pagination.total=0;
this.table.dataSource=[]
//this.$message.warning("查无数据")
}
}else{
this.$message.warning(res.message)
}
this.table.loading = false
})
},
getQueryParams() {
let param = Object.assign({}, this.queryParam,this.isorter);
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
},
handleTableChange(pagination, filters, sorter){
//TODO 筛选
if (Object.keys(sorter).length>0){
this.isorter.column = sorter.field;
this.isorter.order = "ascend"==sorter.order?"asc":"desc"
}
this.table.pagination = pagination;
this.loadData();
},
handleAdd(){
this.cgButtonJsHandler('beforeAdd')
this.$refs.modal.add(this.formTemplate);
},
handleImportXls(){
this.$refs.importModal.show()
},
importOk(){
this.loadData(1)
},
handleExportXls2(){
let param = this.queryParam;
if(this.table.selectedRowKeys && this.table.selectedRowKeys.length>0){
param['selections'] = this.table.selectedRowKeys.join(",")
}
let paramsStr = encodeURI(JSON.stringify(param));
console.log('paramsStr: ' + paramsStr)
let url = window._CONFIG['domianURL']+this.url.exportXls+this.code+"?paramsStr="+paramsStr
window.location.href = url;
},
handleExportXls(){
let param = this.queryParam;
if(this.table.selectedRowKeys && this.table.selectedRowKeys.length>0){
param['selections'] = this.table.selectedRowKeys.join(",")
}
console.log("导出参数",param)
let paramsStr = JSON.stringify(filterObj(param));
downFile(this.url.exportXls+this.code,{paramsStr:paramsStr}).then((data)=>{
if (!data) {
this.$message.warning("文件下载失败")
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), this.description+'.xls')
}else{
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', this.description+'.xls')
document.body.appendChild(link)
link.click()
document.body.removeChild(link); //下载完成移除元素
window.URL.revokeObjectURL(url); //释放掉blob对象
}
})
},
handleEdit(record){
this.cgButtonLinkHandler(record,"beforeEdit","js")
this.$refs.modal.edit(this.formTemplate,record.id);
},
handleDetail(record){
this.$refs.modal.detail(this.formTemplate,record.id);
},
handleDeleteOne(record){
this.cgButtonLinkHandler(record,"beforeDelete","js")
this.handleDelete(record.id)
},
handleDelete(id){
deleteAction(this.url.optPre+this.code+"/"+id).then((res)=>{
if(res.success){
this.$message.success(res.message)
this.loadData()
}else{
this.$message.warning(res.message)
}
})
},
handleFormSuccess(){
this.loadData()
},
onClearSelected(){
this.table.selectedRowKeys = []
this.table.selectionRows = []
},
getImgView(text){
if(text && text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
return window._CONFIG['imgDomainURL']+"/"+text
},
uploadFile(text){
if(!text){
this.$message.warning("未知的文件")
return;
}
if(text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
window.open(window._CONFIG['imgDomainURL']+"/"+text);//TODO 下载的方法
},
handleDelBatch(){
if(this.table.selectedRowKeys.length<=0){
this.$message.warning('请选择一条记录!');
return false;
}else{
let ids = "";
let that = this;
that.table.selectedRowKeys.forEach(function(val) {
ids+=val+",";
});
that.$confirm({
title:"确认删除",
content:"是否删除选中数据?",
onOk: function(){
that.handleDelete(ids)
that.onClearSelected();
}
});
}
},
searchByquery(){
this.loadData(1);
},
searchReset(){
this.queryParam = {}
this.loadData(1);
},
handleToggleSearch(){
this.toggleSearchStatus = !this.toggleSearchStatus;
},
getFormatDate(text){
if(!text){
return ''
}
let a = text;
if(a.length>10){
a = a.substring(0,10);
}
return a;
},
getImportUrl(){
return '/online/cgform/api/importXls/'+this.code
},
initCgEnhanceJs(enhanceJs){
//console.log("--onlineList-js增强",enhanceJs)
if(enhanceJs){
let Obj = eval ("(" + enhanceJs + ")");
this.EnhanceJS = new Obj(getAction,postAction,deleteAction);
this.cgButtonJsHandler('created')
}else{
this.EnhanceJS = ''
}
},
initCgButtonList(btnList){
let linkArr = []
let buttonArr = []
if(btnList && btnList.length>0){
for(let i=0;i<btnList.length;i++){
let temp = btnList[i]
if(temp.buttonStyle=='button'){
buttonArr.push(temp)
}else if(temp.buttonStyle=='link'){
linkArr.push(temp)
}
}
}
this.cgButtonLinkList = [...linkArr]
this.cgButtonList=[...buttonArr]
},
cgButtonJsHandler(buttonCode){
if(this.EnhanceJS[buttonCode]){
this.EnhanceJS[buttonCode](this)
}
},
cgButtonActionHandler(buttonCode){
//处理自定义button的 需要配置该button自定义sql
if(!this.table.selectedRowKeys || this.table.selectedRowKeys.length==0){
this.$message.warning("请先选中一条记录")
return false
}
if(this.table.selectedRowKeys.length>1){
this.$message.warning("请只选中一条记录")
return false
}
let params = {
formId:this.code,
buttonCode:buttonCode,
dataId:this.table.selectedRowKeys[0]
}
console.log("自定义按钮请求后台参数",params)
postAction(this.url.buttonAction,params).then(res=>{
if(res.success){
this.loadData()
this.$message.success("处理完成!")
}else{
this.$message.warning("处理失败!")
}
})
},
cgButtonLinkHandler(record,buttonCode,optType){
if(optType=="js"){
if(this.EnhanceJS[buttonCode]){
this.EnhanceJS[buttonCode](this,record)
}
}else if(optType=="action"){
let params = {
formId:this.code,
buttonCode:buttonCode,
dataId:record.id
}
console.log("自定义按钮link请求后台参数",params)
postAction(this.url.buttonAction,params).then(res=>{
if(res.success){
this.loadData()
this.$message.success("处理完成!")
}else{
this.$message.warning("处理失败!")
}
})
}
},
initButtonSwitch(hideColumns){
if(hideColumns && hideColumns.length>0){
Object.keys(this.buttonSwitch).forEach(key=>{
if(hideColumns.indexOf(key)>=0){
this.buttonSwitch[key]=false
}
})
}
}
}
}
</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

@ -0,0 +1,638 @@
<template>
<a-card :bordered="false" style="height: 100%">
<!-- 操作按钮区域 -->
<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>
<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">
{{ item.buttonName }}
</a-button>
<a-button
v-else-if=" item.optType=='action' "
:key=" 'cgbtn'+index "
@click="cgButtonActionHandler(item.buttonCode)"
type="primary"
:icon="item.buttonIcon"
style="margin-left:8px">
{{ item.buttonName }}
</a-button>
</template>
<a-button
v-if="buttonSwitch.batch_delete"
@click="handleDelBatch"
style="margin-left:8px"
v-show="selectedRowKeys.length > 0"
ghost
type="primary"
icon="delete">批量删除</a-button>
</div>
<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">{{ selectedRowKeys.length }}</a>项&nbsp;&nbsp;
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
</div>
<a-table
ref="cgformTreeList"
size="middle"
rowKey="id"
:columns="columns"
:dataSource="dataSource"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
v-bind="tableProps"
@expand="handleExpand"
style="min-height: 300px"
:expandedRowKeys="expandedRowKeys">
<template slot="dateSlot" slot-scope="text">
<span>{{ getDateNoTime(text) }}</span>
</template>
<template slot="htmlSlot" slot-scope="text">
<div v-html="text"></div>
</template>
<template slot="imgSlot" slot-scope="text">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无此图片</span>
<img v-else :src="getImgView(text)" height="25px" alt="图片不存在" style="max-width:80px;font-size: 12px;font-style: italic;"/>
</template>
<template slot="fileSlot" slot-scope="text">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无此文件</span>
<a-button
v-else
:ghost="true"
type="primary"
icon="download"
size="small"
@click="uploadFile(text)">
下载
</a-button>
</template>
<span slot="action" slot-scope="text, record">
<template v-if="buttonSwitch.update">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical"/>
</template>
<a-dropdown>
<a class="ant-dropdown-link">
更多 <a-icon type="down" />
</a>
<a-menu slot="overlay">
<a-menu-item >
<a @click="handleDetail(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 v-if="cgButtonLinkList && cgButtonLinkList.length>0" v-for="(btnItem,btnIndex) in cgButtonLinkList">
<a-menu-item :key=" 'cgbtnLink'+btnIndex ">
<a href="javascript:void(0);" @click="cgButtonLinkHandler(record,btnItem.buttonCode,btnItem.optType)">
<a-icon v-if="btnItem.buttonIcon" :type="btnItem.buttonIcon" />
{{ btnItem.buttonName }}
</a>
</a-menu-item>
</template>
</a-menu>
</a-dropdown>
</span>
</a-table>
<onl-cgform-auto-modal @success="handleFormSuccess" ref="modal" :code="code"></onl-cgform-auto-modal>
<j-import-modal ref="importModal" :url="getImportUrl()" @ok="importOk"></j-import-modal>
</div>
</a-card>
</template>
<script>
import { getAction,postAction,deleteAction,downFile } from '@/api/manage'
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
import { filterObj } from '@/utils/util';
import JImportModal from '@/components/jeecg/JImportModal'
export default {
name: 'OnlCgformTreeList',
components: {
JImportModal
},
data() {
return {
code: '87b55a515d3441b6b98e48e5b35474a6',
description: '在线报表功能测试页面',
currentTableName:"",
pidField:"",
hasChildrenField:"",
textField:'',
loading: false,
// 表头
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
},
url: {
getColumns: '/online/cgform/api/getColumns/',
getTreeData: '/online/cgform/api/getTreeData/',
optPre:"/online/cgform/api/form/",
exportXls:'/online/cgform/api/exportXls/',
buttonAction:'/online/cgform/api/doButton',
startProcess: "/process/extActProcess/startMutilProcess",
},
isorter:{
column: 'create_time',
order: 'desc',
},
dictOptions:{
},
queryParam:{
},
actionColumn:{
title: '操作',
dataIndex: 'action',
scopedSlots: { customRender: 'action' },
fixed:"right",
align:"center",
width:150
},
formTemplate:"99",
/*自定义按钮-link*/
cgButtonLinkList:[],
/*自定义按钮-button*/
cgButtonList:[],
/*JS增强*/
EnhanceJS:'',
/*操作按钮权限*/
buttonSwitch:{
add:true,
update:true,
delete:true,
batch_delete:true,
import:true,
export:true
},
expandedRowKeys:[]
}
},
created() {
this.initAutoListConfig().then(()=>{
this.loadData(1)
}).catch(msg=>{
console.log(msg)
})
},
mounted(){
//this.cgButtonJsHandler('mounted')
},
watch: {
'$route'() {
// 刷新参数放到这里去触发,就可以刷新相同界面了
this.initAutoListConfig().then(()=>{
this.loadData(1)
}).catch(msg=>{
console.log(msg)
})
}
},
computed: {
tableProps() {
let _this = this
return {
// 列表项是否可选择
// https://vue.ant.design/components/table-cn/#rowSelection
rowSelection: {
selectedRowKeys: _this.selectedRowKeys,
onChange: (selectedRowKeys) => _this.selectedRowKeys = selectedRowKeys
}
}
}
},
methods: {
resetData(){
this.description=''
this.currentTableName=''
this.pidField=''
this.hasChildrenField=''
this.textField=''
this.columns = []
this.dataSource = []
this.selectedRowKeys=[]
this.selectionRows=[]
},
initAutoListConfig() {
return new Promise((resolve, reject) => {
if (!this.$route.params.code) {
reject("列表加载需要参数CODE为空!")
} else {
this.resetData()
this.loading = true
this.code = this.$route.params.code
getAction(`${this.url.getColumns}${this.code}`)
.then(res => {
console.log("--onlineList-加载动态列>>", res);
if(res.success){
this.configInfohandler(res)
resolve();
}else{
reject("onlineList-加载表配置信息失败")
}
this.loading = false
})
.catch(err => {
reject(err)
})
}
})
},
configInfohandler(res){
this.dictOptions = res.result.dictOptions
this.formTemplate = res.result.formTemplate
this.description = res.result.description
this.currentTableName = res.result.currentTableName
this.pidField = res.result.pidField
this.hasChildrenField = res.result.hasChildrenField
this.textField = res.result.textField
//自定义按钮
this.initCgButtonList(res.result.cgButtonList)
//JS增强
this.initCgEnhanceJs(res.result.enhanceJs)
//操作按钮权限
this.initButtonSwitch(res.result.hideColumns)
let currColumns = res.result.columns
let textFieldIndex = -1
for(let a=0;a<currColumns.length;a++){
currColumns[a].align = 'left'
if(this.textField==currColumns[a].dataIndex){
textFieldIndex = a
}
if(currColumns[a].customRender){
let dictCode = currColumns[a].customRender;
currColumns[a].customRender=(text)=>{
return filterMultiDictText(this.dictOptions[dictCode], text);
}
}
}
if(textFieldIndex!=-1){
let textFieldColumn = currColumns.splice(textFieldIndex,1)
currColumns.unshift(textFieldColumn[0])
}
currColumns.push(this.actionColumn);
this.columns = [...currColumns]
},
//加载根节点
loadData(arg){
if(arg==1){
this.pagination.current=1
}
this.loading = true
this.expandedRowKeys=[]
let params = this.getQueryParams();//查询条件
params[this.pidField]='0'
console.log("--onlineList-查询条件-->",params)
getAction(`${this.url.getTreeData}${this.code}`,params).then((res)=>{
console.log("--onlineList-列表数据",res)
if(res.success){
let result = res.result;
if(Number(result.total)>0){
this.pagination.total = Number(result.total)
let dataSource = res.result.records.map(item => {
// 判断是否标记了带有子级
if (item[this.hasChildrenField] === true || item[this.hasChildrenField]=='1') {
let loadChild = { id: `${item.id}_loadChild`, name: 'loading...', isLoading: true }
item.children = [loadChild]
}
return item
})
this.dataSource = dataSource
}else{
this.pagination.total=0;
this.dataSource=[]
}
}else{
this.$message.warning(res.message)
}
this.loading = false
})
},
//加载叶子节点
handleExpand(expanded, record) {
// 判断是否是展开状态
if (expanded) {
this.expandedRowKeys.push(record.id)
if (record.children.length>0 && record.children[0].isLoading === true) {
let params = this.getQueryParams();//查询条件
params[this.pidField] = record.id
getAction(`${this.url.getTreeData}${this.code}`,params).then((res)=>{
if(res.success){
if(Number(res.result.total)>0){
let dataSource = res.result.records.map(item => {
// 判断是否标记了带有子级
if (item[this.hasChildrenField] === true || item[this.hasChildrenField]=='1') {
let loadChild = { id: `${item.id}_loadChild`, name: 'loading...', isLoading: true }
item.children = [loadChild]
}
return item
})
record.children = dataSource
}else{
record.children=''
record.hasChildrenField='0'
}
}else{
this.$message.warning(res.message)
}
})
}
}else{
let keyIndex = this.expandedRowKeys.indexOf(record.id)
if(keyIndex>=0){
this.expandedRowKeys.splice(keyIndex, 1);
}
}
},
getQueryParams() {
let param = Object.assign({}, this.queryParam,this.isorter);
param.pageNo = this.pagination.current;
param.pageSize = this.pagination.pageSize;
return filterObj(param);
},
initCgButtonList(btnList){
let linkArr = []
let buttonArr = []
if(btnList && btnList.length>0){
for(let i=0;i<btnList.length;i++){
let temp = btnList[i]
if(temp.buttonStyle=='button'){
buttonArr.push(temp)
}else if(temp.buttonStyle=='link'){
linkArr.push(temp)
}
}
}
this.cgButtonLinkList = [...linkArr]
this.cgButtonList=[...buttonArr]
},
initCgEnhanceJs(enhanceJs){
//console.log("--onlineList-js增强",enhanceJs)
if(enhanceJs){
let Obj = eval ("(" + enhanceJs + ")");
this.EnhanceJS = new Obj(getAction,postAction,deleteAction);
this.cgButtonJsHandler('created')
}else{
this.EnhanceJS = ''
}
},
initButtonSwitch(hideColumns){
if(hideColumns && hideColumns.length>0){
Object.keys(this.buttonSwitch).forEach(key=>{
if(hideColumns.indexOf(key)>=0){
this.buttonSwitch[key]=false
}
})
}
},
onClearSelected(){
this.selectedRowKeys = []
this.selectionRows = []
},
handleTableChange(pagination, filters, sorter){
//TODO 筛选
if (Object.keys(sorter).length>0){
this.isorter.column = sorter.field;
this.isorter.order = "ascend"==sorter.order?"asc":"desc"
}
this.pagination = pagination;
this.loadData();
},
/*-------数据格式化-begin----------*/
getDateNoTime(text){
if(!text){
return ''
}
let a = text;
if(a.length>10){
a = a.substring(0,10);
}
return a;
},
getImgView(text){
if(text && text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
return window._CONFIG['imgDomainURL']+"/"+text
},
uploadFile(text){
if(!text){
this.$message.warning("未知的文件")
return;
}
if(text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
window.open(window._CONFIG['domianURL'] + "/sys/common/download/"+text);
},
/*-------数据格式化-end----------*/
/*-------功能按钮触发事件-begin----------*/
handleEdit(record){
this.cgButtonLinkHandler(record,"beforeEdit","js")
this.$refs.modal.edit(this.formTemplate,record.id);
},
handleDetail(record){
this.$refs.modal.detail(this.formTemplate,record.id);
},
handleDeleteOne(record){
this.cgButtonLinkHandler(record,"beforeDelete","js")
this.handleDelete(record.id)
},
handleDelete(id){
deleteAction(this.url.optPre+this.code+"/"+id).then((res)=>{
if(res.success){
this.$message.success(res.message)
this.loadData()
}else{
this.$message.warning(res.message)
}
})
},
handleAdd(){
this.cgButtonJsHandler('beforeAdd')
this.$refs.modal.add(this.formTemplate);
},
handleFormSuccess(){
this.loadData()
},
handleImportXls(){
this.$refs.importModal.show()
},
importOk(){
this.loadData(1)
},
getImportUrl(){
return '/online/cgform/api/importXls/'+this.code
},
handleExportXls(){
let param = this.queryParam;
if(this.selectedRowKeys && this.selectedRowKeys.length>0){
param['selections'] = this.selectedRowKeys.join(",")
}
console.log("导出参数",param)
let paramsStr = JSON.stringify(filterObj(param));
downFile(this.url.exportXls+this.code,{paramsStr:paramsStr}).then((data)=>{
if (!data) {
this.$message.warning("文件下载失败")
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), this.description+'.xls')
}else{
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', this.description+'.xls')
document.body.appendChild(link)
link.click()
document.body.removeChild(link); //下载完成移除元素
window.URL.revokeObjectURL(url); //释放掉blob对象
}
})
},
handleDelBatch(){
if(this.selectedRowKeys.length<=0){
this.$message.warning('请选择一条记录!');
return false;
}else{
let ids = "";
let that = this;
that.selectedRowKeys.forEach(function(val) {
ids+=val+",";
});
that.$confirm({
title:"确认删除",
content:"是否删除选中数据?",
onOk: function(){
that.handleDelete(ids)
that.onClearSelected();
}
});
}
},
/*-------功能按钮触发事件-begin----------*/
/*-------JS增强-begin----------*/
cgButtonLinkHandler(record,buttonCode,optType){
if(optType=="js"){
if(this.EnhanceJS[buttonCode]){
this.EnhanceJS[buttonCode](this,record)
}
}else if(optType=="action"){
let params = {
formId:this.code,
buttonCode:buttonCode,
dataId:record.id
}
console.log("自定义按钮link请求后台参数",params)
postAction(this.url.buttonAction,params).then(res=>{
if(res.success){
this.loadData()
this.$message.success("处理完成!")
}else{
this.$message.warning("处理失败!")
}
})
}
},
cgButtonJsHandler(buttonCode){
if(this.EnhanceJS[buttonCode]){
this.EnhanceJS[buttonCode](this)
}
},
cgButtonActionHandler(buttonCode){
//处理自定义button的 需要配置该button自定义sql
if(!this.selectedRowKeys || this.selectedRowKeys.length==0){
this.$message.warning("请先选中一条记录")
return false
}
if(this.selectedRowKeys.length>1){
this.$message.warning("请只选中一条记录")
return false
}
let params = {
formId:this.code,
buttonCode:buttonCode,
dataId:this.selectedRowKeys[0]
}
console.log("自定义按钮请求后台参数",params)
postAction(this.url.buttonAction,params).then(res=>{
if(res.success){
this.loadData()
this.$message.success("处理完成!")
}else{
this.$message.warning("处理失败!")
}
})
},
/*-------JS增强-end----------*/
}
}
</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

@ -0,0 +1,268 @@
/**
* 同步列表,可以同步新增、修改、删除
* @author sunjianlei
* */
export function syncAllTable(vm, table1) {
vm.$refs.editableTable.resetScrollTop()
let deleteIds = table1.$refs.editableTable.getDeleteIds()
let table1Value
table1.$refs.editableTable.getValuesPromise(false).then((values) => {
table1Value = values
return vm.$refs.editableTable.getValuesPromise(false)
}).then((values) => {
table1Value.forEach(value => {
let flag = false
values.forEach((thisValue) => {
if (value.id === thisValue.id) {
// 判断是否修改了值
let dbFieldName = thisValue['dbFieldName']
let dbFieldTxt = thisValue['dbFieldTxt']
// return
if (value.dbFieldName !== dbFieldName
|| value.dbFieldTxt !== dbFieldTxt) {
// 修改了
vm.$refs.editableTable.setValues([{
rowKey: thisValue.id,
values: {
dbFieldName: value.dbFieldName,
dbFieldTxt: value.dbFieldTxt
}
}])
}
flag = true
} else {
// id不匹配则有可能是新增也有可能是删除了的
// 遍历传进来的 deleteIds 进行对比
deleteIds.forEach(delId => {
// 对比成功,则删除该条数据
if (delId === thisValue.id) {
vm.$refs.editableTable.removeRows(vm.$refs.editableTable.caseId + delId)
flag = true
}
})
}
})
// return
// 判断是否操作了该条数据,若没有操作则代表要执行新增操作
if (!flag) {
let record = Object.assign({}, value)
vm.columns.forEach(column => {
if (
column.dataIndex !== 'dbFieldName' &&
column.dataIndex !== 'dbFieldTxt'
) {
record[column.dataIndex] = column.defaultValue
}
})
vm.$refs.editableTable.push(record)
}
})
})
}
/**
* 将数据分类并Set进dataSource
* @author sunjianlei
**/
export function setDataSource(vm, queryData) {
let dataSource = []
// 遍历查询出来的数据
queryData.forEach(value => {
let data = { id: value['id'] }
vm.columns.forEach(column => {
let key = column.key
if (key) {
data[key] = value[key]
// 由于多选下拉框返回的是一个数组,所以需要改成 [1,2,3] 数组的形式,否则组件不识别
// if (key === 'indexField') {
// data[key] = value[key].split(',')
// }
}
})
dataSource.push(data)
})
vm.dataSource = dataSource
}
/** 获取主表的初始化数据 */
export function getMasterTableInitialData() {
return [
{
dbFieldName: 'id',
dbFieldTxt: '主键',
dbLength: 36,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '1',
dbIsNull: '0',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 1
},
{
dbFieldName: 'create_by',
dbFieldTxt: '创建人',
dbLength: 50,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 2
},
{
dbFieldName: 'create_time',
dbFieldTxt: '创建日期',
dbLength: 20,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'Date',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'datetime',
fieldLength: '120',
queryMode: 'single',
orderNum: 3
},
{
dbFieldName: 'update_by',
dbFieldTxt: '更新人',
dbLength: 50,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 4
},
{
dbFieldName: 'update_time',
dbFieldTxt: '更新日期',
dbLength: 20,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'Date',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'datetime',
fieldLength: '120',
queryMode: 'single',
orderNum: 5
},{
dbFieldName: 'sys_org_code',
dbFieldTxt: '所属部门',
dbLength: 64,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 6
}
// {
// dbFieldName: 'sys_org_code',
// dbFieldTxt: '所属部门',
// dbLength: 50,
// dbPointLength: 0,
// dbDefaultVal: '',
// dbType: 'string',
// dbIsKey: false,
// dbIsNull: true
// }, {
// dbFieldName: 'sys_company_code',
// dbFieldTxt: '所属公司',
// dbLength: 50,
// dbPointLength: 0,
// dbDefaultVal: '',
// dbType: 'string',
// dbIsKey: false,
// dbIsNull: true
// }, {
// dbFieldName: 'bpm_status',
// dbFieldTxt: '流程状态',
// dbLength: 32,
// dbPointLength: 0,
// dbDefaultVal: '',
// dbType: 'string',
// dbIsKey: false,
// dbIsNull: true
// }
]
}
/** 获取树的初始化数据 */
export function getTreeNeedFields() {
return [{
dbFieldName: 'pid',
dbFieldTxt: '父级节点',
dbLength: 32,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '1',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 7
},{
dbFieldName: 'has_child',
dbFieldTxt: '是否有子节点',
dbLength: 3,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'list',
fieldLength: '120',
queryMode: 'single',
orderNum: 8,
// table3
dictField:"yn"
}]
}

View File

@ -205,11 +205,11 @@
mobile: {rules: [{validator: this.validateMobile}]}
},
url: {
delete: '/sysdepart/sysDepart/delete',
edit: '/sysdepart/sysDepart/edit',
deleteBatch: '/sysdepart/sysDepart/deleteBatch',
exportXlsUrl: "sysdepart/sysDepart/exportXls",
importExcelUrl: "sysdepart/sysDepart/importExcel",
delete: '/sys/sysDepart/delete',
edit: '/sys/sysDepart/edit',
deleteBatch: '/sys/sysDepart/deleteBatch',
exportXlsUrl: "sys/sysDepart/exportXls",
importExcelUrl: "sys/sysDepart/importExcel",
},
}
},
@ -292,7 +292,7 @@
var that = this
this.$confirm({
title: '确认删除',
content: '确定要删除所选中的 ' + this.checkedKeys.length + ' 条数据?',
content: '确定要删除所选中的 ' + this.checkedKeys.length + ' 条数据,以及子节点数据吗?',
onOk: function () {
deleteAction(that.url.deleteBatch, {ids: ids}).then((res) => {
if (res.success) {

View File

@ -148,9 +148,9 @@
selectedRowKeys: [],
selectedRows: [],
url: {
list: "/sysdepart/sysDepart/list",
delete: "/sysdepart/sysDepart/delete",
deleteBatch: "/sysdepart/sysDepart/deleteBatch",
list: "/sys/sysDepart/list",
delete: "/sys/sysDepart/delete",
deleteBatch: "/sys/sysDepart/deleteBatch",
},
}

View File

@ -19,7 +19,7 @@
</a-form-item>
</a-col>
<a-col :md="8" :sm="10">
<a-col :md="6" :sm="10">
<a-form-item label="创建时间" :labelCol="labelCol" :wrapperCol="wrapperCol">
<a-range-picker
style="width: 210px"
@ -31,14 +31,19 @@
/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="10" >
<span style="float: right;" class="table-page-search-submitButtons">
<a-button type="primary" style="left: -35px" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px;left: -35px">重置</a-button>
</span>
<a-col :md="5" :sm="8" v-if="tabKey === '2'">
<a-form-item label="操作类型" style="left: 10px">
<j-dict-select-tag v-model="queryParam.operateType" placeholder="请选择操作类型" dictCode="operate_type"/>
</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" style="left: 10px" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px;left: 10px">重置</a-button>
</a-col>
</span>
</a-row>
</a-form>
</div>
@ -58,7 +63,10 @@
<div style="margin-bottom: 5px"><a-badge status="success" style="vertical-align: middle;"/><span style="vertical-align: middle;">请求方法:{{ record.method }}</span></div>
<div><a-badge status="processing" style="vertical-align: middle;"/><span style="vertical-align: middle;">请求参数:{{ record.requestParam }}</span></div>
</div>
<!-- 字符串超长截取省略号显示-->
<span slot="logContent" slot-scope="text, record">
<j-ellipsis :value="text" :length="40"/>
</span>
</a-table>
<!-- table区域-end -->
</a-card>
@ -67,10 +75,14 @@
<script>
import { filterObj } from '@/utils/util';
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import JEllipsis from '@/components/jeecg/JEllipsis'
export default {
name: "LogList",
mixins:[JeecgListMixin],
components: {
JEllipsis
},
data () {
return {
description: '这是日志管理页面',
@ -81,6 +93,7 @@
logType:'1',
keyWord:'',
},
tabKey: "1",
// 表头
columns: [
{
@ -96,6 +109,7 @@
title: '日志内容',
align:"left",
dataIndex: 'logContent',
scopedSlots: { customRender: 'logContent' },
sorter: true
},
{
@ -143,6 +157,12 @@
sorter: true
}
],
operateColumn:
{
title: '操作类型',
dataIndex: 'operateType_dictText',
align:"center",
},
labelCol: {
xs: { span: 1 },
sm: { span: 2 },
@ -177,6 +197,17 @@
},
// 日志类型
callback(key){
// 动态添加操作类型列
if (key == 2) {
this.tabKey = '2';
this.columns.splice(7, 0, this.operateColumn);
}else if(this.columns.length == 9)
{
this.tabKey = '1';
this.columns.splice(7,1);
}
let that=this;
that.queryParam.logType=key;
that.loadData();

View File

@ -98,7 +98,7 @@
} else if (text == 1) {
return '菜单'
} else if (text == 2) {
return '按钮'
return '按钮/权限'
} else {
return text
}

View File

@ -68,13 +68,13 @@
@change="handleTableChange">
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
<a v-if="record.sendStatus == 0" @click="handleEdit(record)">编辑</a>
<a-divider type="vertical"/>
<a-divider type="vertical" v-if="record.sendStatus == 0"/>
<a-dropdown>
<a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
<a-menu slot="overlay">
<a-menu-item>
<a-menu-item v-if="record.sendStatus != 1">
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
<a>删除</a>
</a-popconfirm>

View File

@ -125,9 +125,9 @@
scopedSlots: { customRender: 'action' },
}],
url: {
list: "/system/sysAnnouncementSend/getMyAnnouncementSend",
editCementSend:"system/sysAnnouncementSend/editByAnntIdAndUserId",
readAllMsg:"system/sysAnnouncementSend/readAll",
list: "/sys/sysAnnouncementSend/getMyAnnouncementSend",
editCementSend:"sys/sysAnnouncementSend/editByAnntIdAndUserId",
readAllMsg:"sys/sysAnnouncementSend/readAll",
},
loading:false,
}

View File

@ -3,7 +3,7 @@
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-form layout="inline" @submit.prevent="searchQuery">
<a-row :gutter="24">
<a-col :md="6" :sm="12">
@ -117,8 +117,9 @@
</template>
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical"/>
<a @click="handleEdit(record)" v-has="'user:edit'">编辑</a>
<a-divider type="vertical" v-has="'user:edit'"/>
<a-dropdown>
<a class="ant-dropdown-link">
@ -140,13 +141,13 @@
</a-menu-item>
<a-menu-item v-if="record.status==1">
<a-popconfirm title="确定冻结吗?" @confirm="() => handleFrozen(record.id,2)">
<a-popconfirm title="确定冻结吗?" @confirm="() => handleFrozen(record.id,2,record.username)">
<a>冻结</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="record.status==2">
<a-popconfirm title="确定解冻吗?" @confirm="() => handleFrozen(record.id,1)">
<a-popconfirm title="确定解冻吗?" @confirm="() => handleFrozen(record.id,1,record.username)">
<a>解冻</a>
</a-popconfirm>
</a-menu-item>
@ -297,6 +298,16 @@
} else {
let ids = "";
let that = this;
let isAdmin = false;
that.selectionRows.forEach(function (row) {
if (row.username == 'admin') {
isAdmin = true;
}
});
if (isAdmin) {
that.$message.warning('管理员账号不允许此操作,请重新选择!');
return;
}
that.selectedRowKeys.forEach(function (val) {
ids += val + ",";
});
@ -326,8 +337,13 @@
this.batchFrozen(1);
}
},
handleFrozen: function (id, status) {
handleFrozen: function (id, status, username) {
let that = this;
//TODO 后台校验管理员角色
if ('admin' == username) {
that.$message.warning('管理员账号不允许此操作!');
return;
}
frozenBatch({ids: id, status: status}).then((res) => {
if (res.success) {
that.$message.success(res.message);

View File

@ -105,7 +105,7 @@
mobile:{rules: [{validator:this.validateMobile}]}
},
url: {
add: "/sysdepart/sysDepart/add",
add: "/sys/sysDepart/add",
},
}
},

View File

@ -213,7 +213,7 @@
component:{rules: [{ required: this.show, message: '请输入前端组件!' }]},
url:{rules: [{ required: this.show, message: '请输入菜单路径!' }]},
permsType:{rules: [{ required: true, message: '请输入授权策略!' }]},
sortNo:{rules: [{initialValue:1.0,validator: this.validateNumber}]},
sortNo:{initialValue:1.0,rules: [{validator: this.validateNumber}]},
}
}
},

View File

@ -8,7 +8,7 @@
@cancel="handleCancel"
okText="保存并安排任务"
cancelText="关闭">
<a-spin :spinning="confirmLoading">
<a-form :form="form">
@ -23,11 +23,12 @@
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="cron表达式">
<a-input placeholder="请输入cron表达式" v-decorator="['cronExpression', {'initialValue':'0/1 * * * * ?',rules: [{ required: true, message: '请输入任务类名!' }]}]" />
<a target="_blank" href="http://cron.qqe2.com/">
<a-icon type="share-alt" />
在线cron表达式生成
</a>
<!-- <a-input placeholder="请输入cron表达式" v-decorator="['cronExpression', {'initialValue':'0/1 * * * * ?',rules: [{ required: true, message: '请输入任务类名!' }]}]" />-->
<!-- <a target="_blank" href="http://cron.qqe2.com/">-->
<!-- <a-icon type="share-alt" />-->
<!-- 在线cron表达式生成-->
<!-- </a>-->
<j-cron ref="innerVueCron" v-decorator="['cronExpression', {'initialValue':'0/1 * * * * ?',rules: [{ required: true, message: '请输入cron表达式!' }]}]" @change="setCorn"></j-cron>
</a-form-item>
<a-form-item
:labelCol="labelCol"
@ -52,7 +53,7 @@
<a-radio-button :value="-1">停止</a-radio-button>
</a-radio-group>
</a-form-item>
</a-form>
</a-spin>
</a-modal>
@ -60,11 +61,15 @@
<script>
import { httpAction } from '@/api/manage'
import JCron from "@/components/jeecg/JCron.vue";
import pick from 'lodash.pick'
import moment from "moment"
export default {
name: "QuartzJobModal",
components: {
JCron
},
data () {
return {
title:"操作",
@ -78,10 +83,18 @@
xs: { span: 24 },
sm: { span: 16 },
},
cron: {
label: '',
value: ''
},
confirmLoading: false,
form: this.$form.createForm(this),
validatorRules:{
validatorRules: {
cron: {
rules: [{
required: true, message: '请输入cron表达式!'
}]
}
},
url: {
add: "/sys/quartzJob/add",
@ -96,8 +109,7 @@
this.edit({});
},
edit (record) {
this.form.resetFields();
this.model = Object.assign({}, record);
this.model = Object.assign({},record);
console.log(this.model)
this.visible = true;
this.$nextTick(() => {
@ -113,7 +125,13 @@
const that = this;
// 触发表单验证
this.form.validateFields((err, values) => {
console.log('values',values)
if (!err) {
// if (typeof values.cronExpression == "undefined" || Object.keys(values.cronExpression).length==0 ) {
// this.$message.warning('请输入cron表达式!');
// return false;
// }
that.confirmLoading = true;
let httpurl = '';
let method = '';
@ -122,12 +140,12 @@
method = 'post';
}else{
httpurl+=this.url.edit;
method = 'put';
method = 'put';
}
let formData = Object.assign(this.model, values);
//时间格式化
console.log(formData)
console.log('提交参数',formData)
httpAction(httpurl,formData,method).then((res)=>{
if(res.success){
that.$message.success(res.message);
@ -146,7 +164,24 @@
handleCancel () {
this.close()
},
setCorn(data){
console.log('data)',data);
this.$nextTick(() => {
this.model.cronExpression = data;
})
// console.log(Object.keys(data).length==0);
// if (Object.keys(data).length==0) {
// this.$message.warning('请输入cron表达式!');
// }
},
validateCron(rule, value, callback){
if(!value){
callback()
}else if (Object.keys(value).length==0) {
callback("请输入cron表达式!");
}
},
}
}

View File

@ -196,8 +196,12 @@
getQueryParams(){
let param = Object.assign({}, this.queryParam,this.isorter);
param.field = this.getQueryField();
param.current = this.ipagination.current;
//--update-begin----author:scott---date:20190818------for:新建公告时指定特定用户翻页错误SelectUserListModal #379----
// param.current = this.ipagination.current;
// param.pageSize = this.ipagination.pageSize;
param.pageNo = this.ipagination.current;
param.pageSize = this.ipagination.pageSize;
//--update-end----author:scott---date:20190818------for:新建公告时指定特定用户翻页错误SelectUserListModal #379---
return filterObj(param);
},
getQueryField(){

View File

@ -99,9 +99,9 @@
endTime:{rules: [{ required: true, message: '请输入代理结束时间!' }]},
},
url: {
add: "/system/sysUserAgent/add",
edit: "/system/sysUserAgent/edit",
queryByUserName:"/system/sysUserAgent/queryByUserName",
add: "/sys/sysUserAgent/add",
edit: "/sys/sysUserAgent/edit",
queryByUserName:"/sys/sysUserAgent/queryByUserName",
},
}
},

View File

@ -45,6 +45,7 @@
mode="multiple"
style="width: 100%"
placeholder="请选择用户角色"
optionFilterProp = "children"
v-model="selectedRole">
<a-select-option v-for="(role,roleindex) in roleList" :key="roleindex.toString()" :value="role.id">
{{ role.roleName }}
@ -411,7 +412,7 @@
if(!value){
callback()
}else{
if(new RegExp(/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/).test(value)){
if(new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/).test(value)){
var params = {
tableName: 'sys_user',
fieldName: 'email',

View File

@ -1,5 +1,5 @@
<template>
<a-card :bordered="false">
<a-card :bordered="false" style="width: 160%;text-align: center;margin-left:-25%">
<a-steps class="steps" :current="currentTab">
<a-step title="账户信息" />
<a-step title="身份验证" />

View File

@ -85,12 +85,12 @@
<a-form-item>
<a-checkbox v-model="formLogin.rememberMe">自动登陆</a-checkbox>
<router-link :to="{ name: 'alteration'}" class="forge-password" style="float: right;">
<!-- <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>
</router-link>-->
</a-form-item>
<a-form-item style="margin-top:24px">
@ -176,6 +176,8 @@
import { putAction } from '@/api/manage'
import { postAction } from '@/api/manage'
import { encryption , getEncryptedString } from '@/utils/encryption/aesEncrypt'
import store from '@/store/'
import { USER_INFO } from "@/store/mutation-types"
export default {
components: {
@ -342,7 +344,9 @@
})
},
loginSuccess () {
this.loginBtn = false
// update-begin- author:sunjianlei --- date:20190812 --- for: 登录成功后不解除禁用按钮,防止多次点击
// this.loginBtn = false
// update-end- author:sunjianlei --- date:20190812 --- for: 登录成功后不解除禁用按钮,防止多次点击
this.$router.push({ name: "dashboard" })
this.$notification.success({
message: '欢迎',
@ -425,6 +429,10 @@
}
putAction("/sys/selectDepart",obj).then(res=>{
if(res.success){
const userInfo = res.result.userInfo;
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000);
store.commit('SET_INFO', userInfo);
//console.log("---切换组织机构---userInfo-------",store.getters.userInfo.orgCode);
this.departClear()
this.loginSuccess()
}else{

View File

@ -41,7 +41,7 @@
<script>
import JGraphicCode from '@/components/jeecg/JGraphicCode'
import { getAction } from '@/api/manage'
import {duplicateCheck } from '@/api/api'
import {checkOnlyUser } from '@/api/api'
export default {
name: "Step1",
components: {
@ -116,14 +116,12 @@
callback("请输入用户名和手机号");
}
//判断用户输入账号还是手机号码
if(reg.test(value)){
var params = {
tableName: 'sys_user',
fieldName: 'phone',
fieldVal: value,
dataId: null
phone : value,
};
duplicateCheck(params).then((res) => {
checkOnlyUser(params).then((res) => {
if (res.success) {
callback("用户名不存在!")
} else {
@ -132,18 +130,15 @@
})
}else{
var params = {
tableName: 'sys_user',
fieldName: 'username',
fieldVal: value,
dataId: null
username: value,
};
duplicateCheck(params).then((res) => {
checkOnlyUser(params).then((res) => {
if (res.success) {
callback("用户名不存在!")
} else {
callback()
}
})
callback("用户名不存在!")
} else {
callback()
}
})
}
},

View File

@ -30,22 +30,22 @@
</a-input>
</a-form-item>
<a-form-item
label="验证码"
:labelCol="{span: 5}"
:wrapperCol="{span: 19}"
style="margin-left:106px"
v-if="show">
<a-row :gutter="16" >
<a-col class="gutter-row" :span="16">
<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="请输入验证码" >
placeholder="手机短信验证码" >
</a-input>
</a-col>
<a-col class="gutter-row" :span="8" >
<a-button
class="getCaptcha"
tabindex="-1"
size="default"
:disabled="state.smsSendBtn"
@click.stop.prevent="getCaptcha"
v-text="!state.smsSendBtn && '获取验证码' || (state.time+' s')"></a-button>