mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-26 00:06:41 +08:00
Jeecg-Boot 2.2.0 版本发布 | 重磅升级
This commit is contained in:
156
ant-design-vue-jeecg/src/components/jeecg/JAreaLinkage.vue
Normal file
156
ant-design-vue-jeecg/src/components/jeecg/JAreaLinkage.vue
Normal file
@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div v-if="!reloading" class="j-area-linkage">
|
||||
<area-cascader
|
||||
v-if="_type === enums.type[0]"
|
||||
:value="innerValue"
|
||||
:data="pcaa"
|
||||
:level="1"
|
||||
:style="{width}"
|
||||
v-bind="$attrs"
|
||||
v-on="_listeners"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<area-select
|
||||
v-else-if="_type === enums.type[1]"
|
||||
:value="innerValue"
|
||||
:data="pcaa"
|
||||
:level="2"
|
||||
v-bind="$attrs"
|
||||
v-on="_listeners"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<div v-else>
|
||||
<span style="color:red;"> Bad type value: {{_type}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { pcaa } from 'area-data'
|
||||
import Area from '@/components/_util/Area'
|
||||
|
||||
export default {
|
||||
name: 'JAreaLinkage',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required:false
|
||||
},
|
||||
// 组件的类型,可选值:
|
||||
// select 下拉样式
|
||||
// cascader 级联样式(默认)
|
||||
type: {
|
||||
type: String,
|
||||
default: 'cascader'
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pcaa,
|
||||
innerValue: [],
|
||||
usedListeners: ['change'],
|
||||
enums: {
|
||||
type: ['cascader', 'select']
|
||||
},
|
||||
reloading: false,
|
||||
areaData:''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
_listeners() {
|
||||
let listeners = { ...this.$listeners }
|
||||
// 去掉已使用的事件,防止冲突
|
||||
this.usedListeners.forEach(key => {
|
||||
delete listeners[key]
|
||||
})
|
||||
return listeners
|
||||
},
|
||||
_type() {
|
||||
if (this.enums.type.includes(this.type)) {
|
||||
return this.type
|
||||
} else {
|
||||
console.error(`JAreaLinkage的type属性只能接收指定的值(${this.enums.type.join('|')})`)
|
||||
return this.enums.type[0]
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.loadDataByValue(this.value)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.initAreaData();
|
||||
},
|
||||
methods: {
|
||||
/** 通过 value 反推 options */
|
||||
loadDataByValue(value) {
|
||||
if(!value || value.length==0){
|
||||
this.innerValue = []
|
||||
this.reloading = true;
|
||||
setTimeout(()=>{
|
||||
this.reloading = false
|
||||
},100)
|
||||
}else{
|
||||
this.initAreaData();
|
||||
let arr = this.areaData.getRealCode(value);
|
||||
this.innerValue = arr
|
||||
}
|
||||
},
|
||||
/** 通过地区code获取子级 */
|
||||
loadDataByCode(value) {
|
||||
let options = []
|
||||
let data = pcaa[value]
|
||||
if (data) {
|
||||
for (let key in data) {
|
||||
if (data.hasOwnProperty(key)) {
|
||||
options.push({ value: key, label: data[key], })
|
||||
}
|
||||
}
|
||||
return options
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
},
|
||||
/** 判断是否有子节点 */
|
||||
hasChildren(options) {
|
||||
options.forEach(option => {
|
||||
let data = this.loadDataByCode(option.value)
|
||||
option.isLeaf = data.length === 0
|
||||
})
|
||||
},
|
||||
handleChange(values) {
|
||||
let value = values[values.length - 1]
|
||||
this.$emit('change', value)
|
||||
},
|
||||
initAreaData(){
|
||||
if(!this.areaData){
|
||||
this.areaData = new Area();
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
model: { prop: 'value', event: 'change' },
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.j-area-linkage {
|
||||
height:40px;
|
||||
/deep/ .area-cascader-wrap .area-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/deep/ .area-select .area-selected-trigger {
|
||||
line-height: 1.15;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -96,7 +96,7 @@
|
||||
loadRoot(){
|
||||
let param = {
|
||||
pid:this.pid,
|
||||
pcode:this.pcode,
|
||||
pcode:!this.pcode?'0':this.pcode,
|
||||
condition:this.condition
|
||||
}
|
||||
getAction(this.url,param).then(res=>{
|
||||
@ -122,8 +122,6 @@
|
||||
this.treeValue = []
|
||||
}else{
|
||||
getAction(this.view,{ids:this.value}).then(res=>{
|
||||
console.log(124345)
|
||||
console.log(124345,res)
|
||||
if(res.success){
|
||||
let values = this.value.split(',')
|
||||
this.treeValue = res.result.map((item, index) => ({
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-bind="fullScreenParentProps">
|
||||
<a-icon v-if="fullScreen" class="full-screen-icon" type="fullscreen" @click="()=>fullCoder=!fullCoder"/>
|
||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
||||
|
||||
<div class="code-editor-cust full-screen-child">
|
||||
<textarea ref="textarea"></textarea>
|
||||
@ -91,6 +91,7 @@
|
||||
return {
|
||||
// 内部真实的内容
|
||||
code: '',
|
||||
iconType: 'fullscreen',
|
||||
hasCode:false,
|
||||
// 默认的语法类型
|
||||
mode: 'javascript',
|
||||
@ -155,6 +156,15 @@
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
fullCoder:{
|
||||
handler(value) {
|
||||
if(value){
|
||||
this.iconType="fullscreen-exit"
|
||||
}else{
|
||||
this.iconType="fullscreen"
|
||||
}
|
||||
}
|
||||
},
|
||||
// value: {
|
||||
// immediate: false,
|
||||
// handler(value) {
|
||||
@ -408,6 +418,7 @@
|
||||
.full-screen-child {
|
||||
min-height: 120px;
|
||||
max-height: 320px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
},
|
||||
getCalendarContainer: {
|
||||
type: Function,
|
||||
default: () => document.body
|
||||
default: (node) => node.parentNode
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
||||
import 'tinymce/plugins/colorpicker'
|
||||
import 'tinymce/plugins/textcolor'
|
||||
import 'tinymce/plugins/fullscreen'
|
||||
import { uploadAction,getFileAccessHttpUrl } from '@/api/manage'
|
||||
export default {
|
||||
components: {
|
||||
Editor
|
||||
@ -65,8 +66,21 @@
|
||||
menubar: false,
|
||||
toolbar_drawer: false,
|
||||
images_upload_handler: (blobInfo, success) => {
|
||||
const img = 'data:image/jpeg;base64,' + blobInfo.base64()
|
||||
success(img)
|
||||
let formData = new FormData()
|
||||
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
||||
formData.append('biz', "jeditor");
|
||||
formData.append("jeditor","1");
|
||||
uploadAction(window._CONFIG['domianURL']+"/sys/common/upload", formData).then((res) => {
|
||||
if (res.success) {
|
||||
if(res.message == 'local'){
|
||||
const img = 'data:image/jpeg;base64,' + blobInfo.base64()
|
||||
success(img)
|
||||
}else{
|
||||
let img = getFileAccessHttpUrl(res.message)
|
||||
success(img)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
myValue: this.value
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div :class="disabled?'jeecg-form-container-disabled':''">
|
||||
<fieldset disabled>
|
||||
<fieldset :disabled="disabled">
|
||||
<slot name="detail"></slot>
|
||||
</fieldset>
|
||||
<slot name="edit"></slot>
|
||||
@ -46,4 +46,16 @@
|
||||
-ms-pointer-events: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.jeecg-form-container-disabled .ant-upload-select{display:none}
|
||||
.jeecg-form-container-disabled .ant-upload-list{cursor:grabbing}
|
||||
.jeecg-form-container-disabled fieldset[disabled] .ant-upload-list{
|
||||
-ms-pointer-events: auto !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.jeecg-form-container-disabled .ant-upload-list-item-actions .anticon-delete,
|
||||
.jeecg-form-container-disabled .ant-upload-list-item .anticon-close{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@ -1,203 +0,0 @@
|
||||
<template>
|
||||
<div class="gc-canvas" @click="reloadPic">
|
||||
<canvas id="gc-canvas" :width="contentWidth" :height="contentHeight"></canvas>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAction } from '@/api/manage'
|
||||
|
||||
export default {
|
||||
name: 'JGraphicCode',
|
||||
props: {
|
||||
length:{
|
||||
type: Number,
|
||||
default: 4
|
||||
},
|
||||
fontSizeMin: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
fontSizeMax: {
|
||||
type: Number,
|
||||
default: 45
|
||||
},
|
||||
backgroundColorMin: {
|
||||
type: Number,
|
||||
default: 180
|
||||
},
|
||||
backgroundColorMax: {
|
||||
type: Number,
|
||||
default: 240
|
||||
},
|
||||
colorMin: {
|
||||
type: Number,
|
||||
default: 50
|
||||
},
|
||||
colorMax: {
|
||||
type: Number,
|
||||
default: 160
|
||||
},
|
||||
lineColorMin: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
lineColorMax: {
|
||||
type: Number,
|
||||
default: 180
|
||||
},
|
||||
dotColorMin: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
dotColorMax: {
|
||||
type: Number,
|
||||
default: 255
|
||||
},
|
||||
contentWidth: {
|
||||
type: Number,
|
||||
default:136
|
||||
},
|
||||
contentHeight: {
|
||||
type: Number,
|
||||
default: 38
|
||||
},
|
||||
remote:{
|
||||
type:Boolean,
|
||||
default:false,
|
||||
required:false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 生成一个随机数
|
||||
randomNum (min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min)
|
||||
},
|
||||
// 生成一个随机的颜色
|
||||
randomColor (min, max) {
|
||||
let r = this.randomNum(min, max)
|
||||
let g = this.randomNum(min, max)
|
||||
let b = this.randomNum(min, max)
|
||||
return 'rgb(' + r + ',' + g + ',' + b + ')'
|
||||
},
|
||||
drawPic () {
|
||||
this.randomCode().then(()=>{
|
||||
let canvas = document.getElementById('gc-canvas')
|
||||
let ctx = canvas.getContext('2d')
|
||||
ctx.textBaseline = 'bottom'
|
||||
// 绘制背景
|
||||
ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax)
|
||||
ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
|
||||
// 绘制文字
|
||||
for (let i = 0; i < this.code.length; i++) {
|
||||
this.drawText(ctx, this.code[i], i)
|
||||
}
|
||||
this.drawLine(ctx)
|
||||
this.drawDot(ctx)
|
||||
this.$emit("success",this.code)
|
||||
})
|
||||
},
|
||||
drawText (ctx, txt, i) {
|
||||
ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
|
||||
let fontSize = this.randomNum(this.fontSizeMin, this.fontSizeMax)
|
||||
ctx.font = fontSize + 'px SimHei'
|
||||
let padding = 10;
|
||||
let offset = (this.contentWidth-40)/(this.code.length-1)
|
||||
let x=padding;
|
||||
if(i>0){
|
||||
x = padding+(i*offset)
|
||||
}
|
||||
//let x = (i + 1) * (this.contentWidth / (this.code.length + 1))
|
||||
let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
|
||||
if(fontSize>40){
|
||||
y=40
|
||||
}
|
||||
var deg = this.randomNum(-10,10)
|
||||
// 修改坐标原点和旋转角度
|
||||
ctx.translate(x, y)
|
||||
ctx.rotate(deg * Math.PI / 180)
|
||||
ctx.fillText(txt, 0, 0)
|
||||
// 恢复坐标原点和旋转角度
|
||||
ctx.rotate(-deg * Math.PI / 180)
|
||||
ctx.translate(-x, -y)
|
||||
},
|
||||
drawLine (ctx) {
|
||||
// 绘制干扰线
|
||||
for (let i = 0; i <1; i++) {
|
||||
ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
|
||||
ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
|
||||
ctx.stroke()
|
||||
}
|
||||
},
|
||||
drawDot (ctx) {
|
||||
// 绘制干扰点
|
||||
for (let i = 0; i < 100; i++) {
|
||||
ctx.fillStyle = this.randomColor(0, 255)
|
||||
ctx.beginPath()
|
||||
ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI)
|
||||
ctx.fill()
|
||||
}
|
||||
},
|
||||
reloadPic(){
|
||||
this.drawPic()
|
||||
},
|
||||
randomCode(){
|
||||
return new Promise((resolve)=>{
|
||||
if(this.remote==true){
|
||||
getAction("/sys/getCheckCode").then(res=>{
|
||||
console.log("aaaaa",res)
|
||||
if(res.success){
|
||||
this.checkKey = res.result.key
|
||||
this.code = window.atob(res.result.code)
|
||||
resolve();
|
||||
}else{
|
||||
this.$message.error("生成验证码错误,请联系系统管理员")
|
||||
this.code = 'BUG'
|
||||
resolve();
|
||||
}
|
||||
}).catch(()=>{
|
||||
console.log("生成验证码连接服务器异常")
|
||||
this.code = 'BUG'
|
||||
resolve();
|
||||
})
|
||||
}else{
|
||||
this.randomLocalCode();
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
},
|
||||
randomLocalCode(){
|
||||
let random = ''
|
||||
//去掉了I l i o O
|
||||
let str = "QWERTYUPLKJHGFDSAZXCVBNMqwertyupkjhgfdsazxcvbnm1234567890"
|
||||
for(let i = 0; i < this.length; i++) {
|
||||
let index = Math.floor(Math.random()*57);
|
||||
random += str[index];
|
||||
}
|
||||
this.code = random
|
||||
},
|
||||
getLoginParam(){
|
||||
return {
|
||||
checkCode:this.code,
|
||||
checkKey:this.checkKey
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.drawPic()
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
code:"",
|
||||
checkKey:""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@ -44,7 +44,6 @@
|
||||
data(){
|
||||
return {
|
||||
uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
|
||||
urlView:window._CONFIG['staticDomainURL'],
|
||||
uploadLoading:false,
|
||||
picUrl:false,
|
||||
headers:{},
|
||||
@ -103,7 +102,7 @@
|
||||
let fileList = [];
|
||||
let arr = paths.split(",")
|
||||
for(var a=0;a<arr.length;a++){
|
||||
let url = getFileAccessHttpUrl(arr[a],this.urlView,"http");
|
||||
let url = getFileAccessHttpUrl(arr[a]);
|
||||
fileList.push({
|
||||
uid: uidGenerator(),
|
||||
name: getFileName(arr[a]),
|
||||
@ -156,7 +155,7 @@
|
||||
getAvatarView(){
|
||||
if(this.fileList.length>0){
|
||||
let url = this.fileList[0].url
|
||||
return getFileAccessHttpUrl(url,this.urlView,"http")
|
||||
return getFileAccessHttpUrl(url)
|
||||
}
|
||||
},
|
||||
handlePathChange(){
|
||||
|
||||
@ -32,7 +32,12 @@
|
||||
handler:function(){
|
||||
this.initVal();
|
||||
}
|
||||
}
|
||||
},
|
||||
// update-begin author:sunjianlei date:20200225 for:当 type 变化的时候重新计算值 ------
|
||||
type() {
|
||||
this.backValue({ target: { value: this.inputVal } })
|
||||
},
|
||||
// update-end author:sunjianlei date:20200225 for:当 type 变化的时候重新计算值 ------
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
export default {
|
||||
minHeight: '200px',
|
||||
previewStyle: 'vertical',
|
||||
useCommandShortcut: true,
|
||||
useDefaultHTMLSanitizer: true,
|
||||
usageStatistics: false,
|
||||
hideModeSwitch: false,
|
||||
toolbarItems: [
|
||||
'heading',
|
||||
'bold',
|
||||
'italic',
|
||||
'strike',
|
||||
'divider',
|
||||
'hr',
|
||||
'quote',
|
||||
'divider',
|
||||
'ul',
|
||||
'ol',
|
||||
'task',
|
||||
'indent',
|
||||
'outdent',
|
||||
'divider',
|
||||
'table',
|
||||
'image',
|
||||
'link',
|
||||
'divider',
|
||||
'code',
|
||||
'codeblock'
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div :id="id" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
import 'tui-editor/dist/tui-editor.css'
|
||||
import 'tui-editor/dist/tui-editor-contents.css'
|
||||
|
||||
import Editor from 'tui-editor'
|
||||
import defaultOptions from './default-options'
|
||||
|
||||
export default {
|
||||
name: 'JMarkdownEditor',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
required: false,
|
||||
default() {
|
||||
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||
}
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default() {
|
||||
return defaultOptions
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'markdown'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '300px'
|
||||
},
|
||||
language: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'en_US'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editorOptions() {
|
||||
const options = Object.assign({}, defaultOptions, this.options)
|
||||
options.initialEditType = this.mode
|
||||
options.height = this.height
|
||||
options.language = this.language
|
||||
return options
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(newValue, preValue) {
|
||||
if (newValue !== preValue && newValue !== this.editor.getValue()) {
|
||||
this.editor.setValue(newValue)
|
||||
}
|
||||
},
|
||||
language(val) {
|
||||
this.destroyEditor()
|
||||
this.initEditor()
|
||||
},
|
||||
height(newValue) {
|
||||
this.editor.height(newValue)
|
||||
},
|
||||
mode(newValue) {
|
||||
this.editor.changeMode(newValue)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initEditor()
|
||||
},
|
||||
destroyed() {
|
||||
this.destroyEditor()
|
||||
},
|
||||
methods: {
|
||||
initEditor() {
|
||||
this.editor = new Editor({
|
||||
el: document.getElementById(this.id),
|
||||
...this.editorOptions
|
||||
})
|
||||
if (this.value) {
|
||||
this.editor.setValue(this.value)
|
||||
}
|
||||
this.editor.on('change', () => {
|
||||
this.$emit('change', this.editor.getValue())
|
||||
})
|
||||
},
|
||||
destroyEditor() {
|
||||
if (!this.editor) return
|
||||
this.editor.off('change')
|
||||
this.editor.remove()
|
||||
},
|
||||
setValue(value) {
|
||||
this.editor.setValue(value)
|
||||
},
|
||||
getValue() {
|
||||
return this.editor.getValue()
|
||||
},
|
||||
setHtml(value) {
|
||||
this.editor.setHtml(value)
|
||||
},
|
||||
getHtml() {
|
||||
return this.editor.getHtml()
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<a-modal
|
||||
ref="modal"
|
||||
class="j-modal-box"
|
||||
:class="{'fullscreen':innerFullscreen,'no-title':isNoTitle,'no-footer':isNoFooter,}"
|
||||
:class="getClass(modalClass)"
|
||||
:style="getStyle(modalStyle)"
|
||||
:visible="visible"
|
||||
v-bind="_attrs"
|
||||
v-on="$listeners"
|
||||
@ -38,6 +38,8 @@
|
||||
|
||||
<script>
|
||||
|
||||
import { getClass, getStyle } from '@/utils/props-util'
|
||||
|
||||
export default {
|
||||
name: 'JModal',
|
||||
props: {
|
||||
@ -47,13 +49,18 @@
|
||||
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
|
||||
fullscreen: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: false
|
||||
},
|
||||
// 是否允许切换全屏(允许后右上角会出现一个按钮)
|
||||
switchFullscreen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 点击确定按钮的时候是否关闭弹窗
|
||||
okClose: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -73,6 +80,22 @@
|
||||
}
|
||||
return attrs
|
||||
},
|
||||
modalClass() {
|
||||
return {
|
||||
'j-modal-box': true,
|
||||
'fullscreen': this.innerFullscreen,
|
||||
'no-title': this.isNoTitle,
|
||||
'no-footer': this.isNoFooter,
|
||||
}
|
||||
},
|
||||
modalStyle() {
|
||||
let style = {}
|
||||
// 如果全屏就将top设为 0
|
||||
if (this.innerFullscreen) {
|
||||
style['top'] = '0'
|
||||
}
|
||||
return style
|
||||
},
|
||||
isNoTitle() {
|
||||
return !this.title && !this.allSlotsKeys.includes('title')
|
||||
},
|
||||
@ -90,7 +113,7 @@
|
||||
},
|
||||
// 切换全屏的按钮图标
|
||||
fullscreenButtonIcon() {
|
||||
return this.innerFullscreen ? 'fullscreen' : 'fullscreen-exit'
|
||||
return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
@ -105,12 +128,21 @@
|
||||
},
|
||||
methods: {
|
||||
|
||||
getClass(clazz) {
|
||||
return { ...getClass(this), ...clazz }
|
||||
},
|
||||
getStyle(style) {
|
||||
return { ...getStyle(this), ...style }
|
||||
},
|
||||
|
||||
close() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
|
||||
handleOk() {
|
||||
this.close()
|
||||
if (this.okClose) {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
handleCancel() {
|
||||
this.close()
|
||||
@ -167,6 +199,7 @@
|
||||
|
||||
.right {
|
||||
width: 56px;
|
||||
position: inherit;
|
||||
|
||||
.ant-modal-close {
|
||||
right: 56px;
|
||||
@ -180,5 +213,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.j-modal-box.fullscreen {
|
||||
margin: 0;
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,31 +1,37 @@
|
||||
<template>
|
||||
<div class="j-super-query-box">
|
||||
|
||||
<div @click="visible=true">
|
||||
<slot>
|
||||
<a-tooltip v-if="superQueryFlag" :mouseLeaveDelay="0.2">
|
||||
<template slot="title">
|
||||
<span>已有高级查询条件生效</span>
|
||||
<a-divider type="vertical"/>
|
||||
<a @click="handleReset">清空</a>
|
||||
</template>
|
||||
<a-button type="primary">
|
||||
<a-icon type="appstore" theme="twoTone" :spin="true"></a-icon>
|
||||
<slot name="button" :isActive="superQueryFlag" :isMobile="izMobile" :open="handleOpen" :reset="handleReset">
|
||||
<a-tooltip v-if="superQueryFlag" v-bind="tooltipProps" :mouseLeaveDelay="0.2">
|
||||
<!-- begin 不知道为什么不加上这段代码就无法生效 -->
|
||||
<span v-show="false">{{tooltipProps}}</span>
|
||||
<!-- end 不知道为什么不加上这段代码就无法生效 -->
|
||||
<template slot="title">
|
||||
<span>已有高级查询条件生效</span>
|
||||
<a-divider type="vertical"/>
|
||||
<a @click="handleReset">清空</a>
|
||||
</template>
|
||||
<a-button-group>
|
||||
<a-button type="primary" @click="handleOpen">
|
||||
<a-icon type="appstore" theme="twoTone" spin/>
|
||||
<span>高级查询</span>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-button v-else type="primary" icon="filter" @click="visible=true">高级查询</a-button>
|
||||
</slot>
|
||||
</div>
|
||||
<a-button v-if="izMobile" type="primary" icon="delete" @click="handleReset"/>
|
||||
</a-button-group>
|
||||
</a-tooltip>
|
||||
<a-button v-else type="primary" icon="filter" @click="handleOpen">高级查询</a-button>
|
||||
</slot>
|
||||
|
||||
<a-modal
|
||||
<j-modal
|
||||
title="高级查询构造器"
|
||||
:width="1000"
|
||||
:visible="visible"
|
||||
@cancel="handleCancel"
|
||||
:mask="false"
|
||||
:fullscreen="izMobile"
|
||||
class="j-super-query-modal"
|
||||
style="top:5%;max-height: 95%;">
|
||||
style="top:5%;max-height: 95%;"
|
||||
>
|
||||
|
||||
<template slot="footer">
|
||||
<div style="float: left">
|
||||
@ -40,7 +46,7 @@
|
||||
<a-row>
|
||||
<a-col :sm="24" :md="24-5">
|
||||
|
||||
<a-empty v-if="queryParamsModel.length === 0">
|
||||
<a-empty v-if="queryParamsModel.length === 0" style="margin-bottom: 12px;">
|
||||
<div slot="description">
|
||||
<span>没有任何查询条件</span>
|
||||
<a-divider type="vertical"/>
|
||||
@ -50,16 +56,20 @@
|
||||
|
||||
<a-form v-else layout="inline">
|
||||
|
||||
<a-form-item label="过滤条件匹配" style="margin-bottom: 12px;">
|
||||
<a-select v-model="selectValue" :getPopupContainer="node=>node.parentNode">
|
||||
<a-select-option value="and">AND(所有条件都要求匹配)</a-select-option>
|
||||
<a-select-option value="or">OR(条件中的任意一个匹配)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-row style="margin-bottom: 12px;">
|
||||
<a-col :md="12" :xs="24">
|
||||
<a-form-item label="过滤条件匹配" :labelCol="{md: 6,xs:24}" :wrapperCol="{md: 18,xs:24}" style="width: 100%;">
|
||||
<a-select v-model="matchType" :getPopupContainer="node=>node.parentNode" style="width: 100%;">
|
||||
<a-select-option value="and">AND(所有条件都要求匹配)</a-select-option>
|
||||
<a-select-option value="or">OR(条件中的任意一个匹配)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row type="flex" style="margin-bottom:10px" :gutter="16" v-for="(item, index) in queryParamsModel" :key="index">
|
||||
|
||||
<a-col :span="8">
|
||||
<a-col :md="8" :xs="24" style="margin-bottom: 12px;">
|
||||
<a-tree-select
|
||||
showSearch
|
||||
v-model="item.field"
|
||||
@ -75,22 +85,22 @@
|
||||
</a-tree-select>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="4">
|
||||
<a-select placeholder="匹配规则" v-model="item.rule" :getPopupContainer="node=>node.parentNode">
|
||||
<a-col :md="4" :xs="24" style="margin-bottom: 12px;">
|
||||
<a-select placeholder="匹配规则" :value="item.rule" :getPopupContainer="node=>node.parentNode" @change="handleRuleChange(item,$event)">
|
||||
<a-select-option value="eq">等于</a-select-option>
|
||||
<a-select-option value="like">包含</a-select-option>
|
||||
<a-select-option value="right_like">以..开始</a-select-option>
|
||||
<a-select-option value="left_like">以..结尾</a-select-option>
|
||||
<a-select-option value="in">在...中</a-select-option>
|
||||
<a-select-option value="ne">不等于</a-select-option>
|
||||
<a-select-option value="gt">大于</a-select-option>
|
||||
<a-select-option value="ge">大于等于</a-select-option>
|
||||
<a-select-option value="lt">小于</a-select-option>
|
||||
<a-select-option value="le">小于等于</a-select-option>
|
||||
<a-select-option value="right_like">以..开始</a-select-option>
|
||||
<a-select-option value="left_like">以..结尾</a-select-option>
|
||||
<a-select-option value="like">包含</a-select-option>
|
||||
<a-select-option value="in">在...中</a-select-option>
|
||||
</a-select>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="8">
|
||||
<a-col :md="8" :xs="24" style="margin-bottom: 12px;">
|
||||
<template v-if="item.dictCode">
|
||||
<template v-if="item.type === 'table-dict'">
|
||||
<j-popup
|
||||
@ -101,10 +111,14 @@
|
||||
:destFields="item.dictCode"
|
||||
></j-popup>
|
||||
</template>
|
||||
<j-dict-select-tag v-else v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
|
||||
<template v-else>
|
||||
<j-multi-select-tag v-show="allowMultiple(item)" v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
|
||||
<j-dict-select-tag v-show="!allowMultiple(item)" v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
|
||||
</template>
|
||||
</template>
|
||||
<j-popup v-else-if="item.type === 'popup'" :value="item.val" v-bind="item.popup" group-id="superQuery" @input="(e,v)=>handleChangeJPopup(item,e,v)"/>
|
||||
<j-select-multi-user
|
||||
v-else-if="item.type === 'select-user'"
|
||||
v-else-if="item.type === 'select-user' || item.type === 'sel_user'"
|
||||
v-model="item.val"
|
||||
:buttons="false"
|
||||
:multiple="false"
|
||||
@ -112,20 +126,34 @@
|
||||
:returnKeys="['id', item.customReturnField || 'username']"
|
||||
/>
|
||||
<j-select-depart
|
||||
v-else-if="item.type === 'select-depart'"
|
||||
v-else-if="item.type === 'select-depart' || item.type === 'sel_depart'"
|
||||
v-model="item.val"
|
||||
:multi="false"
|
||||
placeholder="请选择部门"
|
||||
:customReturnField="item.customReturnField || 'id'"
|
||||
/>
|
||||
<a-select v-else-if="item.options instanceof Array" v-model="item.val" :options="item.options" allowClear placeholder="请选择"/>
|
||||
<a-select
|
||||
v-else-if="item.options instanceof Array"
|
||||
v-model="item.val"
|
||||
:options="item.options"
|
||||
allowClear
|
||||
placeholder="请选择"
|
||||
:mode="allowMultiple(item)?'multiple':''"
|
||||
/>
|
||||
<j-area-linkage v-model="item.val" v-else-if="item.type==='area-linkage' || item.type==='pca'" style="width: 100%"/>
|
||||
<j-date v-else-if=" item.type=='date' " v-model="item.val" placeholder="请选择日期" style="width: 100%"></j-date>
|
||||
<j-date v-else-if=" item.type=='datetime' " v-model="item.val" placeholder="请选择时间" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"></j-date>
|
||||
<a-time-picker v-else-if="item.type==='time'" :value="item.val ? moment(item.val,'HH:mm:ss') : null" format="HH:mm:ss" style="width: 100%" @change="(time,value)=>item.val=value"/>
|
||||
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
|
||||
<a-input v-else v-model="item.val" placeholder="请输入值"/>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="4">
|
||||
<a-col :md="4" :xs="0" style="margin-bottom: 12px;">
|
||||
<a-button @click="handleAdd" icon="plus"></a-button>
|
||||
<a-button @click="handleDel( index )" icon="minus"></a-button>
|
||||
</a-col>
|
||||
|
||||
<a-col :md="0" :xs="24" style="margin-bottom: 12px;text-align: right;">
|
||||
<a-button @click="handleAdd" icon="plus"></a-button>
|
||||
<a-button @click="handleDel( index )" icon="minus"></a-button>
|
||||
</a-col>
|
||||
@ -142,14 +170,14 @@
|
||||
保存的查询
|
||||
</div>
|
||||
|
||||
<a-empty v-if="treeData.length === 0" class="j-super-query-history-empty" description="没有保存任何查询"/>
|
||||
<a-empty v-if="saveTreeData.length === 0" class="j-super-query-history-empty" description="没有保存任何查询"/>
|
||||
<a-tree
|
||||
v-else
|
||||
class="j-super-query-history-tree"
|
||||
showIcon
|
||||
:treeData="treeData"
|
||||
:treeData="saveTreeData"
|
||||
:selectedKeys="[]"
|
||||
@select="handleTreeSelect"
|
||||
@rightClick="handleTreeRightClick"
|
||||
>
|
||||
</a-tree>
|
||||
</a-card>
|
||||
@ -165,19 +193,24 @@
|
||||
<a-input v-model="prompt.value"></a-input>
|
||||
</a-modal>
|
||||
|
||||
</a-modal>
|
||||
</j-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
import * as utils from '@/utils/util'
|
||||
import { mixinDevice } from '@/utils/mixin'
|
||||
import JDate from '@/components/jeecg/JDate.vue'
|
||||
import JSelectDepart from '@/components/jeecgbiz/JSelectDepart'
|
||||
import JSelectMultiUser from '@/components/jeecgbiz/JSelectMultiUser'
|
||||
import JMultiSelectTag from '@/components/dict/JMultiSelectTag'
|
||||
import JAreaLinkage from '@comp/jeecg/JAreaLinkage'
|
||||
|
||||
export default {
|
||||
name: 'JSuperQuery',
|
||||
components: { JDate, JSelectDepart, JSelectMultiUser },
|
||||
mixins: [mixinDevice],
|
||||
components: { JAreaLinkage, JMultiSelectTag, JDate, JSelectDepart, JSelectMultiUser },
|
||||
props: {
|
||||
/*
|
||||
fieldList: [{
|
||||
@ -208,14 +241,16 @@
|
||||
},
|
||||
|
||||
// 保存查询条件的唯一 code,通过该 code 区分
|
||||
// 默认为 null,代表以当前路由全路径为区分Code
|
||||
saveCode: {
|
||||
type: String,
|
||||
default: 'testSaveCode'
|
||||
default: null
|
||||
}
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
moment,
|
||||
fieldTreeData: [],
|
||||
|
||||
prompt: {
|
||||
@ -224,26 +259,40 @@
|
||||
},
|
||||
|
||||
visible: false,
|
||||
queryParamsModel: [{}],
|
||||
queryParamsModel: [],
|
||||
treeIcon: <a-icon type="file-text"/>,
|
||||
treeData: [],
|
||||
// 保存查询条件的treeData
|
||||
saveTreeData: [],
|
||||
// 保存查询条件的前缀名
|
||||
saveCodeBefore: 'JSuperQuerySaved_',
|
||||
selectValue: 'and',
|
||||
superQueryFlag: false
|
||||
// 查询类型,过滤条件匹配(and、or)
|
||||
matchType: 'and',
|
||||
superQueryFlag: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
izMobile() {
|
||||
return this.device === 'mobile'
|
||||
},
|
||||
tooltipProps() {
|
||||
return this.izMobile ? { visible: false } : {}
|
||||
},
|
||||
fullSaveCode() {
|
||||
let saveCode = this.saveCode
|
||||
if (saveCode == null || saveCode === '') {
|
||||
saveCode = this.$route.fullPath
|
||||
}
|
||||
return this.saveCodeBefore + saveCode
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// 当 saveCode 变化时,重新查询已保存的条件
|
||||
saveCode: {
|
||||
fullSaveCode: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
let list = this.$ls.get(this.saveCodeBefore + val)
|
||||
handler() {
|
||||
let list = this.$ls.get(this.fullSaveCode)
|
||||
if (list instanceof Array) {
|
||||
this.treeData = list.map(item => {
|
||||
item.icon = this.treeIcon
|
||||
return item
|
||||
})
|
||||
this.saveTreeData = list.map(i => this.renderSaveTreeData(i))
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -280,25 +329,35 @@
|
||||
|
||||
methods: {
|
||||
show() {
|
||||
if (!this.queryParamsModel || this.queryParamsModel.length == 0) {
|
||||
this.queryParamsModel = [{}]
|
||||
if (!this.queryParamsModel || this.queryParamsModel.length === 0) {
|
||||
this.resetLine()
|
||||
}
|
||||
this.visible = true
|
||||
},
|
||||
handleOk() {
|
||||
if (!this.isNullArray(this.queryParamsModel)) {
|
||||
let event = {
|
||||
matchType: this.selectValue,
|
||||
params: this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
|
||||
matchType: this.matchType,
|
||||
params: this.removeEmptyObject(this.queryParamsModel)
|
||||
}
|
||||
console.log('---高级查询参数--->', event)
|
||||
this.emitCallback(event.params, event.matchType)
|
||||
// 移动端模式下关闭弹窗
|
||||
if (this.izMobile) {
|
||||
this.visible = false
|
||||
}
|
||||
this.emitCallback(event)
|
||||
} else {
|
||||
this.emitCallback()
|
||||
this.$message.warn("不能查询空条件")
|
||||
}
|
||||
},
|
||||
emitCallback(params, matchType) {
|
||||
this.superQueryFlag = !!params
|
||||
emitCallback(event = {}) {
|
||||
let { params = [], matchType = this.matchType } = event
|
||||
this.superQueryFlag = (params && params.length > 0)
|
||||
for (let param of params) {
|
||||
if (Array.isArray(param.val)) {
|
||||
param.val = param.val.join(',')
|
||||
}
|
||||
}
|
||||
console.debug('---高级查询参数--->', { params, matchType })
|
||||
this.$emit(this.callback, params, matchType)
|
||||
},
|
||||
handleCancel() {
|
||||
@ -309,27 +368,40 @@
|
||||
this.visible = false
|
||||
},
|
||||
handleAdd() {
|
||||
this.queryParamsModel.push({})
|
||||
this.addNewLine()
|
||||
},
|
||||
addNewLine() {
|
||||
this.queryParamsModel.push({ rule: 'eq' })
|
||||
},
|
||||
resetLine() {
|
||||
this.superQueryFlag = false
|
||||
this.queryParamsModel = []
|
||||
this.addNewLine()
|
||||
},
|
||||
handleDel(index) {
|
||||
this.queryParamsModel.splice(index, 1)
|
||||
},
|
||||
handleSelected(node, item) {
|
||||
let { type, options, dictCode, dictTable, customReturnField } = node.dataRef
|
||||
let { type, options, dictCode, dictTable, customReturnField, popup } = node.dataRef
|
||||
item['type'] = type
|
||||
item['options'] = options
|
||||
item['dictCode'] = dictCode
|
||||
item['dictTable'] = dictTable
|
||||
item['customReturnField'] = customReturnField
|
||||
if (popup) {
|
||||
item['popup'] = popup
|
||||
}
|
||||
this.$set(item, 'val', undefined)
|
||||
},
|
||||
handleOpen() {
|
||||
this.show()
|
||||
},
|
||||
handleReset() {
|
||||
this.superQueryFlag = false
|
||||
this.queryParamsModel = [{}]
|
||||
this.resetLine()
|
||||
this.emitCallback()
|
||||
},
|
||||
handleSave() {
|
||||
let queryParams = this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
|
||||
let queryParams = this.removeEmptyObject(this.queryParamsModel)
|
||||
if (this.isNullArray(queryParams)) {
|
||||
this.$message.warning('空条件不能保存')
|
||||
} else {
|
||||
@ -338,56 +410,65 @@
|
||||
}
|
||||
},
|
||||
handlePromptOk() {
|
||||
|
||||
let { value } = this.prompt
|
||||
// 判断有没有重名
|
||||
|
||||
let filterList = this.treeData.filter(i => i.title === value)
|
||||
if(!value){
|
||||
this.$message.warning('保存名称不能为空')
|
||||
return
|
||||
}
|
||||
// 取出查询条件
|
||||
let records = this.removeEmptyObject(this.queryParamsModel)
|
||||
// 判断有没有重名的
|
||||
let filterList = this.saveTreeData.filter(i => i.originTitle === value)
|
||||
if (filterList.length > 0) {
|
||||
this.$confirm({
|
||||
content: `${value} 已存在,是否覆盖?`,
|
||||
onOk: () => {
|
||||
this.prompt.visible = false
|
||||
filterList[0].records = this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
|
||||
filterList[0].records = records
|
||||
this.saveToLocalStore()
|
||||
this.$message.success('保存成功')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 没有重名的,直接添加
|
||||
this.prompt.visible = false
|
||||
this.treeData.push({
|
||||
// 添加到树列表中
|
||||
this.saveTreeData.push(this.renderSaveTreeData({
|
||||
title: value,
|
||||
icon: this.treeIcon,
|
||||
records: this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
|
||||
})
|
||||
matchType: this.matchType,
|
||||
records: records
|
||||
}))
|
||||
// 保存到 LocalStore
|
||||
this.saveToLocalStore()
|
||||
this.$message.success('保存成功')
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
handleTreeSelect(idx, event) {
|
||||
if (event.selectedNodes[0]) {
|
||||
this.queryParamsModel = utils.cloneObject(event.selectedNodes[0].data.props.records)
|
||||
let { matchType, records } = event.selectedNodes[0].data.props
|
||||
// 将保存的matchType取出,兼容旧数据,如果没有保存就还是使用原来的
|
||||
this.matchType = matchType || this.matchType
|
||||
this.queryParamsModel = utils.cloneObject(records)
|
||||
}
|
||||
},
|
||||
handleTreeRightClick(args) {
|
||||
handleRemoveSaveTreeItem(event, vNode) {
|
||||
// 阻止事件冒泡
|
||||
event.stopPropagation()
|
||||
|
||||
this.$confirm({
|
||||
content: '是否删除当前查询?',
|
||||
onOk: () => {
|
||||
let { node: { eventKey } } = args
|
||||
this.treeData.splice(Number.parseInt(eventKey.substring(2)), 1)
|
||||
let { eventKey } = vNode
|
||||
this.saveTreeData.splice(Number.parseInt(eventKey.substring(2)), 1)
|
||||
this.saveToLocalStore()
|
||||
this.$message.success('删除成功')
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
// 将查询保存到 LocalStore 里
|
||||
saveToLocalStore() {
|
||||
this.$ls.set(this.saveCodeBefore + this.saveCode, this.treeData.map(item => {
|
||||
return { title: item.title, records: item.records }
|
||||
}))
|
||||
let saveValue = this.saveTreeData.map(({ originTitle, matchType, records }) => ({ title: originTitle, matchType, records }))
|
||||
this.$ls.set(this.fullSaveCode, saveValue)
|
||||
},
|
||||
|
||||
isNullArray(array) {
|
||||
@ -404,18 +485,70 @@
|
||||
return false
|
||||
},
|
||||
// 去掉数组中的空对象
|
||||
removeEmptyObject(array) {
|
||||
removeEmptyObject(arr) {
|
||||
let array = utils.cloneObject(arr)
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
let item = array[i]
|
||||
if (item == null || Object.keys(item).length <= 0) {
|
||||
array.splice(i--, 1)
|
||||
} else {
|
||||
// 去掉特殊属性
|
||||
delete item.options
|
||||
if (Array.isArray(item.options)) {
|
||||
// 如果有字典属性,就不需要保存 options 了
|
||||
if (item.dictCode) {
|
||||
// 去掉特殊属性
|
||||
delete item.options
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
},
|
||||
|
||||
/** 渲染保存查询条件的 title(加个删除按钮) */
|
||||
renderSaveTreeData(item) {
|
||||
item.icon = this.treeIcon
|
||||
item.originTitle = item['title']
|
||||
item.title = (fn, vNode) => {
|
||||
let { originTitle } = vNode.dataRef
|
||||
return (
|
||||
<div class="j-history-tree-title">
|
||||
<span>{originTitle}</span>
|
||||
|
||||
<div class="j-history-tree-title-closer" onClick={e => this.handleRemoveSaveTreeItem(e, vNode)}>
|
||||
<a-icon type="close-circle"/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return item
|
||||
},
|
||||
|
||||
/** 判断是否允许多选 */
|
||||
allowMultiple(item) {
|
||||
return item.rule === 'in'
|
||||
},
|
||||
|
||||
handleRuleChange(item, newValue) {
|
||||
let oldValue = item.rule
|
||||
this.$set(item, 'rule', newValue)
|
||||
// 上一个规则是否是 in,且type是字典或下拉
|
||||
if (oldValue === 'in') {
|
||||
if (item.dictCode || item.options instanceof Array) {
|
||||
let value = item.val
|
||||
if (typeof item.val === 'string') {
|
||||
value = item.val.split(',')[0]
|
||||
} else if (Array.isArray(item.val)) {
|
||||
value = item.val[0]
|
||||
}
|
||||
this.$set(item, 'val', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleChangeJPopup(item, e, values) {
|
||||
item.val = values[item.popup['destFields']]
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -428,42 +561,76 @@
|
||||
|
||||
.j-super-query-modal {
|
||||
|
||||
.j-super-query-history-card /deep/ {
|
||||
.ant-card-body,
|
||||
.ant-card-head-title {
|
||||
.j-super-query-history-card {
|
||||
/deep/ .ant-card-body,
|
||||
/deep/ .ant-card-head-title {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ant-card-head {
|
||||
/deep/ .ant-card-head {
|
||||
padding: 4px 8px;
|
||||
min-height: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.j-super-query-history-empty /deep/ {
|
||||
.ant-empty-image {
|
||||
.j-super-query-history-empty {
|
||||
/deep/ .ant-empty-image {
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
/deep/ img {
|
||||
width: 80px;
|
||||
height: 65px;
|
||||
}
|
||||
|
||||
.ant-empty-description {
|
||||
/deep/ .ant-empty-description {
|
||||
color: #afafaf;
|
||||
margin: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.j-super-query-history-tree /deep/ {
|
||||
.ant-tree-switcher {
|
||||
.j-super-query-history-tree {
|
||||
|
||||
.j-history-tree-title {
|
||||
width: calc(100% - 24px);
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
&-closer {
|
||||
color: #999999;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s, color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.j-history-tree-title-closer {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/deep/ .ant-tree-switcher {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-tree-node-content-wrapper {
|
||||
/deep/ .ant-tree-node-content-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
57
ant-design-vue-jeecg/src/components/jeecg/JSwitch.vue
Normal file
57
ant-design-vue-jeecg/src/components/jeecg/JSwitch.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<a-switch v-model="checkStatus" :disabled="disabled" @change="handleChange"/>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'JSwitch',
|
||||
props: {
|
||||
value:{
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
disabled:{
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
options:{
|
||||
type:Array,
|
||||
required:false,
|
||||
default:()=>['Y','N']
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
checkStatus: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value:{
|
||||
immediate: true,
|
||||
handler(val){
|
||||
if(!val){
|
||||
this.checkStatus = false
|
||||
this.$emit('change', this.options[1]);
|
||||
}else{
|
||||
if(this.options[0]==val){
|
||||
this.checkStatus = true
|
||||
}else{
|
||||
this.checkStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange(checked){
|
||||
let flag = checked===false?this.options[1]:this.options[0];
|
||||
this.$emit('change', flag);
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -180,7 +180,11 @@
|
||||
},
|
||||
onChange(value){
|
||||
console.log(value)
|
||||
this.$emit('change', value.value);
|
||||
if(!value){
|
||||
this.$emit('change', '');
|
||||
}else{
|
||||
this.$emit('change', value.value);
|
||||
}
|
||||
this.treeValue = value
|
||||
},
|
||||
onSearch(value){
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<a-tree-select
|
||||
allowClear
|
||||
labelInValue
|
||||
:getPopupContainer="(node) => node.parentNode"
|
||||
style="width: 100%"
|
||||
:disabled="disabled"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
|
||||
@ -1,19 +1,43 @@
|
||||
<template>
|
||||
<a-upload
|
||||
name="file"
|
||||
:multiple="true"
|
||||
:action="uploadAction"
|
||||
:headers="headers"
|
||||
:data="{'biz':bizPath}"
|
||||
:fileList="fileList"
|
||||
:beforeUpload="beforeUpload"
|
||||
@change="handleChange"
|
||||
:disabled="disabled"
|
||||
:returnUrl="returnUrl">
|
||||
<a-button>
|
||||
<a-icon type="upload" />{{ text }}
|
||||
</a-button>
|
||||
</a-upload>
|
||||
<div :id="containerId" style="position: relative">
|
||||
|
||||
<!-- ---------------------------- begin 图片左右换位置 ------------------------------------- -->
|
||||
<div class="movety-container" :style="{top:top+'px',left:left+'px',display:moveDisplay}" style="padding:0 8px;position: absolute;z-index: 91;height: 32px;width: 104px;text-align: center;">
|
||||
<div :id="containerId+'-mover'" :class="showMoverTask?'uploadty-mover-mask':'movety-opt'" style="margin-top: 12px">
|
||||
<a @click="moveLast" style="margin: 0 5px;"><a-icon type="arrow-left" style="color: #fff;font-size: 16px"/></a>
|
||||
<a @click="moveNext" style="margin: 0 5px;"><a-icon type="arrow-right" style="color: #fff;font-size: 16px"/></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ---------------------------- end 图片左右换位置 ------------------------------------- -->
|
||||
|
||||
<a-upload
|
||||
name="file"
|
||||
:multiple="true"
|
||||
:action="uploadAction"
|
||||
:headers="headers"
|
||||
:data="{'biz':bizPath}"
|
||||
:fileList="fileList"
|
||||
:beforeUpload="beforeUpload"
|
||||
@change="handleChange"
|
||||
:disabled="disabled"
|
||||
:returnUrl="returnUrl"
|
||||
:listType="complistType"
|
||||
@preview="handlePreview"
|
||||
:class="{'uploadty-disabled':disabled}">
|
||||
<template>
|
||||
<div v-if="isImageComp">
|
||||
<a-icon type="plus" />
|
||||
<div class="ant-upload-text">{{ text }}</div>
|
||||
</div>
|
||||
<a-button v-else-if="buttonVisible">
|
||||
<a-icon type="upload" />{{ text }}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-upload>
|
||||
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
|
||||
<img alt="example" style="width: 100%" :src="previewImage" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -40,10 +64,21 @@
|
||||
data(){
|
||||
return {
|
||||
uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
|
||||
urlDownload:window._CONFIG['staticDomainURL'],
|
||||
headers:{},
|
||||
fileList: [],
|
||||
newFileList: [],
|
||||
uploadGoOn:true,
|
||||
previewVisible: false,
|
||||
//---------------------------- begin 图片左右换位置 -------------------------------------
|
||||
previewImage: '',
|
||||
containerId:'',
|
||||
top:'',
|
||||
left:'',
|
||||
moveDisplay:'none',
|
||||
showMoverTask:false,
|
||||
moverHold:false,
|
||||
currentImg:''
|
||||
//---------------------------- end 图片左右换位置 -------------------------------------
|
||||
}
|
||||
},
|
||||
props:{
|
||||
@ -90,23 +125,48 @@
|
||||
required:false,
|
||||
default: true
|
||||
},
|
||||
number:{
|
||||
type:Number,
|
||||
required:false,
|
||||
default: 0
|
||||
},
|
||||
buttonVisible:{
|
||||
type:Boolean,
|
||||
required:false,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
watch:{
|
||||
value(val){
|
||||
if (val instanceof Array) {
|
||||
if(this.returnUrl){
|
||||
this.initFileList(val.join(','))
|
||||
}else{
|
||||
this.initFileListArr(val);
|
||||
value:{
|
||||
immediate: true,
|
||||
handler() {
|
||||
let val = this.value
|
||||
if (val instanceof Array) {
|
||||
if(this.returnUrl){
|
||||
this.initFileList(val.join(','))
|
||||
}else{
|
||||
this.initFileListArr(val);
|
||||
}
|
||||
} else {
|
||||
this.initFileList(val)
|
||||
}
|
||||
} else {
|
||||
this.initFileList(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
isImageComp(){
|
||||
return this.fileType === FILE_TYPE_IMG
|
||||
},
|
||||
complistType(){
|
||||
return this.fileType === FILE_TYPE_IMG?'picture-card':'text'
|
||||
}
|
||||
},
|
||||
created(){
|
||||
const token = Vue.ls.get(ACCESS_TOKEN);
|
||||
this.headers = {"X-Access-Token":token}
|
||||
//---------------------------- begin 图片左右换位置 -------------------------------------
|
||||
this.headers = {"X-Access-Token":token};
|
||||
this.containerId = 'container-ty-'+new Date().getTime();
|
||||
//---------------------------- end 图片左右换位置 -------------------------------------
|
||||
},
|
||||
|
||||
methods:{
|
||||
@ -117,11 +177,12 @@
|
||||
}
|
||||
let fileList = [];
|
||||
for(var a=0;a<val.length;a++){
|
||||
let url = getFileAccessHttpUrl(val[a].filePath);
|
||||
fileList.push({
|
||||
uid:uidGenerator(),
|
||||
name:val[a].fileName,
|
||||
status: 'done',
|
||||
url: val[a].filePath,
|
||||
url: url,
|
||||
response:{
|
||||
status:"history",
|
||||
message:val[a].filePath
|
||||
@ -141,7 +202,7 @@
|
||||
let fileList = [];
|
||||
let arr = paths.split(",")
|
||||
for(var a=0;a<arr.length;a++){
|
||||
let url = getFileAccessHttpUrl(arr[a],this.urlDownload,"http");
|
||||
let url = getFileAccessHttpUrl(arr[a]);
|
||||
fileList.push({
|
||||
uid:uidGenerator(),
|
||||
name:getFileName(arr[a]),
|
||||
@ -172,15 +233,12 @@
|
||||
this.$emit('change', path);
|
||||
},
|
||||
beforeUpload(file){
|
||||
this.uploadGoOn=true
|
||||
var fileType = file.type;
|
||||
if(fileType===FILE_TYPE_IMG){
|
||||
if(this.fileType===FILE_TYPE_IMG){
|
||||
if(fileType.indexOf('image')<0){
|
||||
this.$message.warning('请上传图片');
|
||||
return false;
|
||||
}
|
||||
}else if(fileType===FILE_TYPE_TXT){
|
||||
if(fileType.indexOf('image')>=0){
|
||||
this.$message.warning('请上传文件');
|
||||
this.uploadGoOn=false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -189,13 +247,19 @@
|
||||
},
|
||||
handleChange(info) {
|
||||
console.log("--文件列表改变--")
|
||||
if(!info.file.status && this.uploadGoOn === false){
|
||||
info.fileList.pop();
|
||||
}
|
||||
let fileList = info.fileList
|
||||
if(info.file.status==='done'){
|
||||
if(this.number>0){
|
||||
fileList = fileList.slice(-this.number);
|
||||
}
|
||||
if(info.file.response.success){
|
||||
fileList = fileList.map((file) => {
|
||||
if (file.response) {
|
||||
let reUrl = file.response.message;
|
||||
file.url = getFileAccessHttpUrl(reUrl,this.urlDownload,"http");
|
||||
file.url = getFileAccessHttpUrl(reUrl);
|
||||
}
|
||||
return file;
|
||||
});
|
||||
@ -213,20 +277,16 @@
|
||||
this.handlePathChange()
|
||||
}else{
|
||||
//returnUrl为false时返回文件名称、文件路径及文件大小
|
||||
fileList = fileList.filter((file) => {
|
||||
if (file.response) {
|
||||
return file.response.success === true;
|
||||
}
|
||||
return false;
|
||||
}).map((file) => {
|
||||
this.newFileList = [];
|
||||
for(var a=0;a<fileList.length;a++){
|
||||
var fileJson = {
|
||||
fileName:file.name,
|
||||
filePath:file.response.message,
|
||||
fileSize:file.size
|
||||
fileName:fileList[a].name,
|
||||
filePath:fileList[a].response.message,
|
||||
fileSize:fileList[a].size
|
||||
};
|
||||
this.newFileList.push(fileJson);
|
||||
this.$emit('change', this.newFileList);
|
||||
});
|
||||
}
|
||||
this.$emit('change', this.newFileList);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -234,6 +294,115 @@
|
||||
//如有需要新增 删除逻辑
|
||||
console.log(file)
|
||||
},
|
||||
handlePreview(file){
|
||||
if(this.fileType === FILE_TYPE_IMG){
|
||||
this.previewImage = file.url || file.thumbUrl;
|
||||
this.previewVisible = true;
|
||||
}else{
|
||||
location.href=file.url
|
||||
}
|
||||
},
|
||||
handleCancel(){
|
||||
this.previewVisible = false;
|
||||
},
|
||||
//---------------------------- begin 图片左右换位置 -------------------------------------
|
||||
moveLast(){
|
||||
//console.log(ev)
|
||||
//console.log(this.fileList)
|
||||
//console.log(this.currentImg)
|
||||
let index = this.getIndexByUrl();
|
||||
if(index==0){
|
||||
this.$message.warn('未知的操作')
|
||||
}else{
|
||||
let curr = this.fileList[index].url;
|
||||
let last = this.fileList[index-1].url;
|
||||
let arr =[]
|
||||
for(let i=0;i<this.fileList.length;i++){
|
||||
if(i==index-1){
|
||||
arr.push(curr)
|
||||
}else if(i==index){
|
||||
arr.push(last)
|
||||
}else{
|
||||
arr.push(this.fileList[i].url)
|
||||
}
|
||||
}
|
||||
this.currentImg = last
|
||||
this.$emit('change',arr.join(','))
|
||||
}
|
||||
},
|
||||
moveNext(){
|
||||
let index = this.getIndexByUrl();
|
||||
if(index==this.fileList.length-1){
|
||||
this.$message.warn('已到最后~')
|
||||
}else{
|
||||
let curr = this.fileList[index].url;
|
||||
let next = this.fileList[index+1].url;
|
||||
let arr =[]
|
||||
for(let i=0;i<this.fileList.length;i++){
|
||||
if(i==index+1){
|
||||
arr.push(curr)
|
||||
}else if(i==index){
|
||||
arr.push(next)
|
||||
}else{
|
||||
arr.push(this.fileList[i].url)
|
||||
}
|
||||
}
|
||||
this.currentImg = next
|
||||
this.$emit('change',arr.join(','))
|
||||
}
|
||||
},
|
||||
getIndexByUrl(){
|
||||
for(let i=0;i<this.fileList.length;i++){
|
||||
if(this.fileList[i].url === this.currentImg || encodeURI(this.fileList[i].url) === this.currentImg){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
const moverObj = document.getElementById(this.containerId+'-mover');
|
||||
moverObj.addEventListener('mouseover',()=>{
|
||||
this.moverHold = true
|
||||
this.moveDisplay = 'block';
|
||||
});
|
||||
moverObj.addEventListener('mouseout',()=>{
|
||||
this.moverHold = false
|
||||
this.moveDisplay = 'none';
|
||||
});
|
||||
let picList = document.getElementById(this.containerId)?document.getElementById(this.containerId).getElementsByClassName('ant-upload-list-picture-card'):[];
|
||||
if(picList && picList.length>0){
|
||||
picList[0].addEventListener('mouseover',(ev)=>{
|
||||
ev = ev || window.event;
|
||||
let target = ev.target || ev.srcElement;
|
||||
if('ant-upload-list-item-info' == target.className){
|
||||
this.showMoverTask=false
|
||||
let item = target.parentElement
|
||||
this.left = item.offsetLeft
|
||||
this.top=item.offsetTop+item.offsetHeight-50;
|
||||
this.moveDisplay = 'block';
|
||||
this.currentImg = target.getElementsByTagName('img')[0].src
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
picList[0].addEventListener('mouseout',(ev)=>{
|
||||
ev = ev || window.event;
|
||||
let target = ev.target || ev.srcElement;
|
||||
//console.log('移除',target)
|
||||
if('ant-upload-list-item-info' == target.className){
|
||||
this.showMoverTask=true
|
||||
setTimeout(()=>{
|
||||
if(this.moverHold === false)
|
||||
this.moveDisplay = 'none';
|
||||
},100)
|
||||
}
|
||||
if('ant-upload-list-item ant-upload-list-item-done' == target.className || 'ant-upload-list ant-upload-list-picture-card'== target.className){
|
||||
this.moveDisplay = 'none';
|
||||
}
|
||||
})
|
||||
//---------------------------- end 图片左右换位置 -------------------------------------
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
@ -242,6 +411,24 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
<style lang="less">
|
||||
.uploadty-disabled{
|
||||
.ant-upload-list-item {
|
||||
.anticon-close{
|
||||
display: none;
|
||||
}
|
||||
.anticon-delete{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------- begin 图片左右换位置 -------------------------------------
|
||||
.uploadty-mover-mask{
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
opacity: .8;
|
||||
color: #fff;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
//---------------------------- end 图片左右换位置 -------------------------------------
|
||||
</style>
|
||||
113
ant-design-vue-jeecg/src/components/jeecg/minipop/JFilePop.vue
Normal file
113
ant-design-vue-jeecg/src/components/jeecg/minipop/JFilePop.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-modal
|
||||
title="文件上传"
|
||||
:width="width"
|
||||
:visible="visible"
|
||||
@ok="ok"
|
||||
cancelText="取消"
|
||||
@cancel="close">
|
||||
<!--style="top: 20px;"-->
|
||||
<j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled"></j-upload>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import JUpload from '@/components/jeecg/JUpload'
|
||||
import { getFileAccessHttpUrl } from '@/api/manage';
|
||||
|
||||
const getFileName=(path)=>{
|
||||
if(path.lastIndexOf("\\")>=0){
|
||||
let reg=new RegExp("\\\\","g");
|
||||
path = path.replace(reg,"/");
|
||||
}
|
||||
return path.substring(path.lastIndexOf("/")+1);
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'JFilePop',
|
||||
components: { JUpload },
|
||||
props:{
|
||||
title:{
|
||||
type:String,
|
||||
default:'',
|
||||
required:false
|
||||
},
|
||||
position:{
|
||||
type:String,
|
||||
default:'right',
|
||||
required:false
|
||||
},
|
||||
height:{
|
||||
type:Number,
|
||||
default:200,
|
||||
required:false
|
||||
},
|
||||
width:{
|
||||
type:Number,
|
||||
default:520,
|
||||
required:false
|
||||
},
|
||||
|
||||
popContainer:{
|
||||
type:String,
|
||||
default:'',
|
||||
required:false
|
||||
},
|
||||
disabled:{
|
||||
type:Boolean,
|
||||
default:false,
|
||||
required:false
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
visible:false,
|
||||
filePath:'',
|
||||
id:'',
|
||||
fileType:'file'
|
||||
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
handleChange(value){
|
||||
this.filePath = value;
|
||||
},
|
||||
show(id,value,flag){
|
||||
this.id = id;
|
||||
this.filePath = value;
|
||||
this.visible=true
|
||||
if(flag === 'img'){
|
||||
this.fileType = 'image'
|
||||
}else{
|
||||
this.fileType = 'file'
|
||||
}
|
||||
|
||||
},
|
||||
ok(){
|
||||
if(!this.filePath){
|
||||
this.$message.error("未上传任何文件")
|
||||
return false;
|
||||
}
|
||||
let arr = this.filePath.split(",")
|
||||
let obj = {
|
||||
name:getFileName(arr[0]),
|
||||
url:getFileAccessHttpUrl(arr[0]),
|
||||
path:this.filePath,
|
||||
status: 'done',
|
||||
id:this.id
|
||||
}
|
||||
this.$emit('ok',obj)
|
||||
this.visible=false
|
||||
},
|
||||
close(){
|
||||
this.visible=false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<a-popover trigger="contextmenu" v-model="visible" :placement="position">
|
||||
<!--"(node) => node.parentNode.parentNode"-->
|
||||
<div slot="title">
|
||||
<span>{{ title }}</span>
|
||||
<span style="float: right" title="关闭">
|
||||
<a-icon type="close" @click="visible=false"/>
|
||||
</span>
|
||||
</div>
|
||||
<a-input :value="inputContent" @change="handleInputChange">
|
||||
<a-icon slot="suffix" type="fullscreen" @click.stop="pop" />
|
||||
</a-input>
|
||||
<div slot="content">
|
||||
<textarea :value="inputContent" @input="handleInputChange" :style="{ height: height + 'px', width: width + 'px' }"></textarea>
|
||||
</div>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'JInputPop',
|
||||
props:{
|
||||
title:{
|
||||
type:String,
|
||||
default:'',
|
||||
required:false
|
||||
},
|
||||
position:{
|
||||
type:String,
|
||||
default:'right',
|
||||
required:false
|
||||
},
|
||||
height:{
|
||||
type:Number,
|
||||
default:200,
|
||||
required:false
|
||||
},
|
||||
width:{
|
||||
type:Number,
|
||||
default:150,
|
||||
required:false
|
||||
},
|
||||
value:{
|
||||
type:String,
|
||||
required:false
|
||||
},
|
||||
popContainer:{
|
||||
type:String,
|
||||
default:'',
|
||||
required:false
|
||||
}
|
||||
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
visible:false,
|
||||
inputContent:''
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
watch:{
|
||||
value:{
|
||||
immediate:true,
|
||||
handler:function(){
|
||||
if(this.value && this.value.length>0){
|
||||
this.inputContent = this.value;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
methods:{
|
||||
handleInputChange(event){
|
||||
this.inputContent = event.target.value
|
||||
this.$emit('change',this.inputContent)
|
||||
},
|
||||
pop(){
|
||||
this.visible=true
|
||||
},
|
||||
getPopupContainer(node){
|
||||
if(!this.popContainer){
|
||||
return node.parentNode
|
||||
}else{
|
||||
return document.getElementById(this.popContainer)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user