JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台

This commit is contained in:
zhangdaiscott
2020-11-28 17:20:10 +08:00
parent 35ef0eff90
commit a004acee4b
614 changed files with 206292 additions and 29220 deletions

View File

@ -59,7 +59,7 @@
v-show="col.type !== formTypes.hidden"
class="td"
:key="col.key"
:style="buildTdStyle(col)">
:style="buildTdStyle(col,true)">
<span>{{ col.title }}</span>
</div>
@ -375,7 +375,7 @@
<a-menu-item @click="handleClickDelFile(id)">
<span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item>
<a-menu-item @click="handleMoreOperation(id)">
<a-menu-item @click="handleMoreOperation(id,col,col)">
<span><a-icon type="bars" /> 更多</span>
</a-menu-item>
</a-menu>
@ -410,7 +410,7 @@
<a-icon type="loading"/>
</template>
<template v-else-if="uploadValues[id]['path']">
<img class="j-editable-image" :src="getCellImageView(id)" alt="无图片" @click="handleMoreOperation(id,'img')"/>
<img class="j-editable-image" :src="getCellImageView(id)" alt="无图片" @click="handleMoreOperation(id,'img',col)"/>
</template>
<template v-else>
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError(id)"/>
@ -443,7 +443,7 @@
<a-menu-item @click="handleClickDelFile(id)">
<span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item>
<a-menu-item @click="handleMoreOperation(id,'img')">
<a-menu-item @click="handleMoreOperation(id,'img',col)">
<span><a-icon type="bars" /> 更多</span>
</a-menu-item>
</a-menu>
@ -612,7 +612,7 @@
</div>
</div>
<j-file-pop ref="filePop" @ok="handleFileSuccess"></j-file-pop>
<j-file-pop ref="filePop" @ok="handleFileSuccess" :number="number"></j-file-pop>
</div>
</a-spin>
</template>
@ -774,6 +774,7 @@
currentEditRows: {},
// 上次push数据的事件用于判断是否点击过快
lastPushTimeMap: new Map(),
number:0,
}
},
created() {
@ -1203,6 +1204,12 @@
this.inputValues.splice(insertIndex, 0, value)
}
}
//update-begin-author:lvdandan date:20201105 for:LOWCOD-987 【online】js增强的问题--数据对象带有id且和现有数据一致时替换患有数据
if(-1 !== rows.findIndex(item => item.id === row.id)){
added = true
this.inputValues = this.inputValues.map(item => item.id === row.id ? value : item)
}
//update-begin-author:lvdandan date:20201105 for:LOWCOD-987 【online】js增强的问题--数据对象带有id且和现有数据一致时替换患有数据
if (!added) {
rows.push(row)
this.inputValues.push(value)
@ -2143,8 +2150,12 @@
}
target.value = value
}
// 做单个表单验证
this.validateOneInput(value, row, column, this.notPassedIds, true, 'blur')
//update--begin--autor:lvdandan-----date:20201126------forLOWCOD-1088 JEditableTable输入校验提示框位置偏移 #2005
setTimeout(()=>{
// 做单个表单验证
this.validateOneInput(value, row, column, this.notPassedIds, true, 'blur')
}, 100)
//update--end--autor:lvdandan-----date:20201126------forLOWCOD-1088 JEditableTable输入校验提示框位置偏移 #2005
},
handleChangeCheckboxCommon(event, row, column) {
let { id, checked } = event.target
@ -2201,7 +2212,18 @@
// 触发valueChange 事件
this.elemValueChange(column.type, row, column, value)
},
handleMoreOperation(id,flag){
handleMoreOperation(id,flag,column){
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if(column.number){
this.number = column.number;
}else{
this.number = 0;
}
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if(column && column.fieldExtendJson){
let json = JSON.parse(column.fieldExtendJson);
this.number = json.uploadnum?json.uploadnum:0;
}
//console.log("this.uploadValues[id]",this.uploadValues[id])
let path = ''
if(this.uploadValues && this.uploadValues[id]){
@ -2440,7 +2462,7 @@
}
},
/** view辅助方法构建 td style */
buildTdStyle(col) {
buildTdStyle(col,isTitle) {
const isEmptyWidth = (column) => (column.type === FormTypes.hidden || column.width === '0px' || column.width === '0' || column.width === 0)
let style = {}
@ -2452,6 +2474,17 @@
} else {
style['width'] = '120px'
}
//update-begin-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
//是否为标题如果是时间控件设为200时间控件的标题设为240 时间
if(col.type === FormTypes.datetime){
if(true === isTitle){
style['width'] = '240px'
}else{
style['width'] = '200px'
}
}
//update-end-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
// checkbox 居中显示
let isCheckbox = col.type === FormTypes.checkbox
if (isCheckbox) {
@ -3061,4 +3094,4 @@
}
</style>
</style>

View File

@ -80,18 +80,29 @@
type:Boolean,
required:false,
default: false
},
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 新增number属性用于判断上传数量
number:{
type:Number,
required:false,
default:0
}
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 新增number属性用于判断上传数量
},
watch:{
value(val){
if (val instanceof Array) {
this.initFileList(val.join(','))
} else {
this.initFileList(val)
}
if(!val || val.length==0){
this.picUrl = false;
}
value: {
handler(val,oldValue) {
if (val instanceof Array) {
this.initFileList(val.join(','))
} else {
this.initFileList(val)
}
if(!val || val.length==0){
this.picUrl = false;
}
},
//立刻执行handler
immediate: true
}
},
created(){
@ -132,6 +143,11 @@
handleChange(info) {
this.picUrl = false;
let fileList = info.fileList
//update-begin-author:wangshuai date:20201022 for:LOWCOD-969 判断number是否大于0和是否多选返回选定的元素。
if(this.number>0 && this.isMultiple){
fileList = fileList.slice(-this.number);
}
//update-end-author:wangshuai date:20201022 for:LOWCOD-969 判断number是否大于0和是否多选返回选定的元素。
if(info.file.status==='done'){
if(info.file.response.success){
this.picUrl = true;
@ -217,4 +233,4 @@
/deep/ .imgupload .ant-upload.ant-upload-select-picture-card{ width:120px;height: 120px;}
/deep/ .imgupload .iconp{padding:32px;}
/* update--end--autor:lvdandan-----date:20201016------forj-image-upload图片组件单张图片详情回显空白*/
</style>
</style>

View File

@ -21,7 +21,6 @@ export default {
'outdent',
'divider',
'table',
'image',
'link',
'divider',
'code',

View File

@ -1,5 +1,28 @@
<template>
<div class="j-markdown-editor" :id="id"/>
<div>
<div class="j-markdown-editor" :id="id"/>
<div v-if="isShow">
<j-modal
title="图片上传"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose"
@ok="handleOk">
<a-tabs default-active-key="1" @change="handleChange">
<a-tab-pane tab="本地图片上传" key="1" :forceRender="true">
<j-upload v-model="fileList" :number="1"></j-upload>
<div style="margin-top: 20px">
<a-input v-model="remark" placeholder="请填写备注"></a-input>
</div>
</a-tab-pane>
<a-tab-pane tab="网络图片地址" key="2" :forceRender="true">
<a-input v-model="networkPic" placeholder="请填写网络图片地址"></a-input>
<a-input style="margin-top: 20px" v-model="remark" placeholder="请填写备注"></a-input>
</a-tab-pane>
</a-tabs>
</j-modal>
</div>
</div>
</template>
<script>
@ -9,9 +32,14 @@ import '@toast-ui/editor/dist/i18n/zh-cn';
import Editor from '@toast-ui/editor';
import defaultOptions from './default-options'
import JUpload from '@/components/jeecg/JUpload'
import { getFileAccessHttpUrl } from '@/api/manage'
export default {
name: 'JMarkdownEditor',
components: {
JUpload,
},
props: {
value: {
type: String,
@ -47,7 +75,16 @@ export default {
},
data() {
return {
editor: null
editor: null,
isShow:false,
activeIndex:"1",
dialogVisible:false,
index:"1",
fileList:[],
remark:"",
imageName:"",
imageUrl:"",
networkPic:""
}
},
computed: {
@ -94,6 +131,40 @@ export default {
this.editor.on('change', () => {
this.$emit('change', this.editor.getMarkdown())
})
//--begin 添加自定义上传按钮
/*
* 添加自定义按钮
*/
//获取编辑器上的功能条
let toolbar = this.editor.getUI().getToolbar();
let fileDom = this.$refs.files;
//添加图片点击事件
this.editor.eventManager.addEventType('isShowClickEvent');
this.editor.eventManager.listen('isShowClickEvent', () => {
this.isShow = true
this.dialogVisible = true
});
//addImageBlobHook图片上传、剪切、拖拽都会走此方法
// 删除默认监听事件
this.editor.eventManager.removeEventHandler('addImageBlobHook')
// 添加自定义监听事件
this.editor.eventManager.listen('addImageBlobHook', (blob, callback) => {
this.upload(blob, url => {
callback(url)
})
})
// 添加自定义按钮 第二个参数代表位置,不传默认放在最后
toolbar.insertItem(15,{
type: 'button',
options:{
name: 'customize',
className: 'tui-image tui-toolbar-icons',
event: 'isShowClickEvent',
tooltip: '上传图片',
}
//
});
//--end 添加自定义上传按钮
},
destroyEditor() {
if (!this.editor) return
@ -111,7 +182,57 @@ export default {
},
getHtml() {
return this.editor.getHtml()
}
},
handleOk(){
if(this.index=='1'){
this.imageUrl = getFileAccessHttpUrl(this.fileList)
if(this.remark){
this.addImgToMd(this.imageUrl,this.remark)
}else{
this.addImgToMd(this.imageUrl,"")
}
}else{
if(this.remark){
this.addImgToMd(this.networkPic,this.remark)
}else{
this.addImgToMd(this.networkPic,"")
}
}
this.index="1"
this.fileList=[]
this.imageName="";
this.imageUrl="";
this.remark=""
this.networkPic=""
this.dialogVisible=false
this.isShow=false;
},
handleClose(done) {
done();
},
handleChange(val){
this.fileList=[]
this.remark=""
this.imageName=""
this.imageUrl=""
this.networkPic=""
this.index=val
},
//添加图片到markdown
addImgToMd(data,name) {
let editor = this.editor.getCodeMirror();
let editorHtml = this.editor.getCurrentModeEditor();
let isMarkdownMode = this.editor.isMarkdownMode();
if (isMarkdownMode) {
editor.replaceSelection(`![${name}](${data})`);
} else {
let range = editorHtml.getRange();
let img = document.createElement('img');
img.src = `${data}`;
img.alt = name;
range.insertNode(img);
}
},
},
model: {
prop: 'value',

View File

@ -11,6 +11,7 @@
:code="code"
:multi="multi"
:groupId="uniqGroupId"
:param="param"
@ok="callBack"
/>
@ -75,6 +76,12 @@
required: false,
default: false
},
//popup动态参数 支持系统变量语法
param:{
type: Object,
required: false,
default: ()=>{}
},
/** 分组ID用于将多个popup的请求合并到一起不传不分组 */
groupId: String

View File

@ -181,6 +181,13 @@ export default {
if (column.cellRender) {
Object.assign(column.cellRender, renderOptions)
}
// update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
if (column.$type === JVXETypes.file || column.$type === JVXETypes.image) {
if (column.width && column.width.endsWith('px')) {
column.width = Number.parseInt(column.width.substr(0,column.width.length-2))+Number.parseInt(1)+'px';
}
}
// update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
})
return this._innerColumns
},
@ -727,6 +734,11 @@ export default {
newData.forEach(row => delete row.id)
return newData
},
/** 仅获取新增的数据,带有id */
getNewDataWithId() {
let newData = cloneObject(this.$refs.vxe.getInsertRecords())
return newData
},
/** 根据ID获取行新增的行也能查出来 */
getIfRowById(id) {
let row = this.getRowById(id), isNew = false
@ -760,8 +772,8 @@ export default {
* @param rows
* @return
*/
async addRows(rows = {}) {
return this._addOrInsert(rows, -1, 'added')
async addRows(rows = {}, isOnlJs) {
return this._addOrInsert(rows, -1, 'added', isOnlJs)
},
/**
@ -1005,7 +1017,7 @@ export default {
return await xTable.updateData()
},
async _addOrInsert(rows = {}, index, triggerName) {
async _addOrInsert(rows = {}, index, triggerName, isOnlJs) {
let {xTable} = this.$refs.vxe.$refs
let records
if (Array.isArray(rows)) {
@ -1017,14 +1029,19 @@ export default {
records.forEach(record => this._createRow(record))
let result = await this.pushRows(records, {index: index, setActive: true})
// 遍历插入的行
for (let i = 0; i < result.rows.length; i++) {
let row = result.rows[i]
this.trigger(triggerName, {
row: row,
$table: xTable,
target: this,
})
// update--begin--autor:lvdandan-----date:20201117------for:LOWCOD-987 【新行编辑】js增强附表内置方法调用问题 #1819
// online js增强时以传过来值为准不再赋默认值
if (isOnlJs != true) {
for (let i = 0; i < result.rows.length; i++) {
let row = result.rows[i]
this.trigger(triggerName, {
row: row,
$table: xTable,
target: this,
})
}
}
// update--end--autor:lvdandan-----date:20201117------for:LOWCOD-987 【新行编辑】js增强附表内置方法调用问题 #1819
return result
},
// 创建新行,自动添加默认值
@ -1035,7 +1052,7 @@ export default {
let col = column.own
if (record[col.key] == null || record[col.key] === '') {
// 设置默认值
let createValue = getEnhancedMixins(col.$type, 'createValue')
let createValue = getEnhancedMixins(col.$type || col.type, 'createValue')
record[col.key] = createValue({row: record, column, $table: xTable})
}
})

View File

@ -258,7 +258,7 @@ export default {
components: { JTreeTable },
data() {
return {
url: '/api/asynTreeList',
url: '/mock/api/asynTreeList',
columns: [
{ title: '菜单名称', dataIndex: 'name' },
{ title: '组件', dataIndex: 'component' },

View File

@ -1,11 +1,41 @@
import JModal from './JModal'
import JFormContainer from './JFormContainer.vue'
import JPopup from './JPopup.vue'
import JMarkdownEditor from './JMarkdownEditor'
import JCodeEditor from './JCodeEditor.vue'
import JEditor from './JEditor.vue'
import JEditableTable from './JEditableTable.vue'
import JAreaLinkage from './JAreaLinkage.vue'
import JSuperQuery from './JSuperQuery.vue'
import JUpload from './JUpload.vue'
import JTreeSelect from './JTreeSelect.vue'
import JCategorySelect from './JCategorySelect.vue'
import JImageUpload from './JImageUpload.vue'
import JTreeDict from './JTreeDict.vue'
import JCheckbox from './JCheckbox.vue'
import JCron from './JCron.vue'
import JSelectMultiple from './JSelectMultiple.vue'
import JPopupOnlReport from './modal/JPopupOnlReport.vue'
export default {
install(Vue) {
Vue.component('JFormContainer', JFormContainer)
Vue.component('JPopup', JPopup)
Vue.component(JModal.name, JModal)
Vue.component('JMarkdownEditor', JMarkdownEditor)
Vue.component('JEditor', JEditor)
Vue.component('JCodeEditor', JCodeEditor)
Vue.component('JEditableTable', JEditableTable)
Vue.component('JAreaLinkage', JAreaLinkage)
Vue.component('JSuperQuery', JSuperQuery)
Vue.component('JUpload', JUpload)
Vue.component('JTreeSelect', JTreeSelect)
Vue.component('JCategorySelect', JCategorySelect)
Vue.component('JImageUpload', JImageUpload)
Vue.component('JTreeDict', JTreeDict)
Vue.component('JCheckbox', JCheckbox)
Vue.component('JCron', JCron)
Vue.component('JPopupOnlReport', JPopupOnlReport)
Vue.component('JSelectMultiple', JSelectMultiple)
}
}

View File

@ -8,7 +8,7 @@
cancelText="取消"
@cancel="close">
<!--style="top: 20px;"-->
<j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled"></j-upload>
<j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled" :number="number"></j-upload>
</a-modal>
</div>
</template>
@ -59,6 +59,11 @@
type:Boolean,
default:false,
required:false
},
number:{
type:Number,
required:false,
default: 0
}
},
data(){

View File

@ -78,7 +78,7 @@
const MODAL_WIDTH = 1200;
export default {
name: 'JPopupOnlReport',
props: ['multi', 'code', 'groupId'],
props: ['multi', 'code', 'groupId', 'param'],
components:{
},
data(){
@ -121,16 +121,24 @@
},
cgRpConfigId:"",
modalWidth:MODAL_WIDTH,
tableScroll:{x:MODAL_WIDTH-100}
tableScroll:{x:MODAL_WIDTH-100},
dynamicParam:{}
}
},
mounted() {
this.loadColumnsInfo()
//this.loadColumnsInfo()
},
watch: {
code() {
this.loadColumnsInfo()
},
param:{
deep:true,
handler(){
this.dynamicParamHandler()
this.loadData();
},
}
},
computed:{
@ -162,7 +170,6 @@
}
this.table.columns = [...currColumns]
this.initQueryInfo()
this.loadData(1)
}
})
},
@ -176,12 +183,43 @@
httpGroupRequest(() => getAction(url), groupIdKey).then((res) => {
// console.log("获取查询条件", res);
if (res.success) {
this.dynamicParamHandler(res.result)
this.queryInfo = res.result
//查询条件加载后再请求数据
this.loadData(1)
} else {
this.$message.warning(res.message)
}
})
},
//处理动态参数
dynamicParamHandler(arr){
if(arr && arr.length>0){
//第一次加载查询条件前 初始化queryParam为空对象
let queryTemp = {}
for(let item of arr){
if(item.mode==='single'){
queryTemp[item.field] = ''
}
}
this.queryParam = {...queryTemp}
}
let dynamicTemp = {}
if(this.param){
Object.keys(this.param).map(key=>{
let str = this.param[key]
if(key in this.queryParam){
if(str && str.startsWith("'") && str.endsWith("'")){
str = str.substring(1,str.length-1)
}
//如果查询条件包含参数 设置值
this.queryParam[key]=str
}
dynamicTemp[key] = this.param[key]
})
}
this.dynamicParam = {...dynamicTemp}
},
loadData(arg) {
if (arg == 1) {
this.table.pagination.current = 1
@ -208,7 +246,14 @@
})
},
getQueryParams() {
let param = Object.assign({}, this.queryParam, this.sorter);
let paramTarget = {}
if(this.dynamicParam){
//处理自定义参数
Object.keys(this.dynamicParam).map(key=>{
paramTarget['self_'+key] = this.dynamicParam[key]
})
}
let param = Object.assign(paramTarget, this.queryParam, this.sorter);
param.pageNo = this.table.pagination.current;
param.pageSize = this.table.pagination.pageSize;
return filterObj(param);
@ -272,7 +317,8 @@
this.onClearSelected()
},
show(){
this.visible = true;
this.visible = true
this.loadColumnsInfo()
},
handleToggleSearch(){
this.toggleSearchStatus = !this.toggleSearchStatus;