<template> <div :id='elId' class="selectBoxPlus" style='width:100%;height:100%;'> <div class="contarnBox" style='width:100%;height:100%;'> <div class="selectTitle" v-show="configData.title">{{configData.title}}</div> <div class="selectCurr" style='width:100%;height:100%;'> <el-select :allow-create='configData.allowCreate' :default-first-option='configData.defaultFirstOption' style="width:100%" :class="{'noneStyle':isReadOnly1,'noneStyle2':isReadOnly2}" :size='configData.size' @clear="clear_select" :collapse-tags="configData.collapse_tags" :multiple="configData.multiple" :disabled="isReadOnly" :clearable="configData.clearable" ref="select_demo" @change="change" @focus="select_focus" v-model="value_inner" :filterable="configData.filterable" :remote="configData.remote" :remote-method="remoteMethod_" :placeholder="configData.placeholder" > <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> <el-tooltip v-if='linkBtnUiVis' el-tooltip content="主表" placement="bottom" effect="light"> <el-button size="mini" @click='jumpSelect' circle icon="el-icon-s-promotion"></el-button> </el-tooltip> </div> </div> <jsoneditor v-model='jsoneditorVisible' :elInfo='elInfo' :jsoneditorData='editData' :jsoneditorCloseAfter='jsoneditorCloseAfter' :jsoneditorOpenAfter='jsoneditorOpenAfter' > </jsoneditor> <dialogIframe @closeDialog='closeDialog' v-if='linkBtnUiVis' @linkBtnUiBack='linkBtnUiBack' v-model="dialogIframeVisible" :src='dialogIframeSrc'></dialogIframe> </div> </template> <script> import uuidv1 from 'uuid/v1' import jsoneditor from '../common/jsoneditor' import mockData from '../common/initDbConfigDataJson' import ucComponent from '../ucClass/uc_component' import _ from 'lodash' import commonUtility from '../funTools/commonUtility' import dialogIframe from '../common/dialogTemplate/dialogIframe' export default { mixins: [ucComponent], name: 'hsSelectPlus', components: { jsoneditor, dialogIframe }, props: { remoteMethod: { type: Function, default() { } }, containerType: {}, elInfo: { type: Object, default() { return {} } }, allSourceData: { type: Object, default() { return {} } }, jsoneditorCloseAfter: { type: Function, default() { return () => {} } }, jsoneditorOpenAfter: { type: Function, default() { return () => {} } }, value: '', writeBackObject: { default() { return {} } }, readonly: { default: false } }, data() { return { options: [], value_inner: this.multiple ? [] : '', filterable: false, remote: false, // url_static: 'commonUtilAPI/ref/items/', // url_dynamic: 'commonUtilAPI/ref/table/', url_static: 'commonUtilAPI/', url_dynamic: 'commonUtilAPI/ref/table/', url_ipCommonAPI: 'ipCommonAPI/', real_url: '', elId: '', chart: null, jsoneditorVisible: false, // 是否显示动态配置的弹框 editData: { config: {}, sourceData: [], sql: '' }, configData: { url: '', ref: { const_id: '', table_name: '', columns: '', remote_condition: '', displayfield: '', // 默认值 writebackfield: [] }, multiple: false, collapse_tags: true, disabled: false, size: 'mini', clearable: true, title: '', value: '', label: '', parms: {}, placeholder: '请选择', is_computed: false, remote: false, filterable: false }, emptyList: [undefined, 'undefined', null, 'null', ''], number: 0, menuGlobalParams: {}, focus: false, writeBackObject_: {}, dialogIframeSrc: '', dialogIframeVisible: false, linkBtnUiVis: false, linkUiBtnTxt: '调整' } }, computed: { dialogIfameVis: function() { const linkBtnUi = !!this.configData.linkBtnUi return linkBtnUi }, isReadOnly: function() { return this.readonly || this.configData.disabled }, isReadOnly1: function() { if (this.containerType !== 'editArea' && (this.readonly || this.configData.disabled)) { return true } }, isReadOnly2: function() { // 是编辑框 if (this.containerType === 'editArea' && (this.readonly || this.configData.disabled)) { return true } } }, watch: { writeBackObject: { handler(newValue, oldValue) { const linkProp = this.configData.linkProp const displayfield = this.configData.ref.displayfield const remote_condition = this.configData.ref.remote_condition const newData = newValue[linkProp] const oldData = this.writeBackObject_[linkProp] if (linkProp && newData !== oldData) { this.value_inner = '' this.$emit('input', '') this.writeBackObject[displayfield] = '' if (remote_condition) { this.remoteMethod_() } } this.writeBackObject_ = _.cloneDeep(newValue) }, deep: true }, value: { handler(newValue, oldValue) { this.initValue(newValue) }, deep: true }, allSourceData: { handler: function(newVal, oldVal) { this.number += 1 if (this.number <= 1) { this.initData(newVal) this.initValue(this.value) } }, deep: true } }, created() { this.elId = uuidv1() // 获取随机id }, mounted() { this.$nextTick(() => { this.placeholder = this.elInfo.placeholder this.title = this.elInfo.title this.initData(this.allSourceData) this.initValue(this.value) }) }, methods: { closeDialog() { this.dialogIframeVisible = false }, linkBtnUiBack(data) { debugger const linkBtnUi = this.configData.linkBtnUi if (!linkBtnUi) return const writeProp = linkBtnUi.writeProp || {} for (const key in writeProp) { const value = writeProp[key] this.$set(this.writeBackObject, key, data[value]) } this.dialogIframeVisible = false }, jumpSelect() { const item = this.configData.linkBtnUi const { url, dyncQueryParms, newDefault } = item const newDefaultStr = JSON.stringify(newDefault) const parms = _.cloneDeep(dyncQueryParms || {}) parms.newDefault = newDefaultStr const href = location.href const startUrl = href.split('#')[0] let url_ = url const parseQuery = commonUtility.parseUrlQueryString() const { db_name } = parseQuery if (db_name) { parms.db_name = db_name } if (item.url.includes('?')) { url_ = url + '&fromMenu=1' } else { url_ = url + '?fromMenu=1' } let parmsStr = '' for (const key in parms) { parmsStr += `&${key}=${parms[key]}` } const url__ = `${startUrl}#${url_}` + parmsStr + '&isInnerDialog=1' this.dialogIframeSrc = url__ this.dialogIframeVisible = true }, disAbledFun() { return this.readonly || this.configData.disabled }, initValue(value) { if (!Object.keys(this.allSourceData.config || {}).length) return const is_computed = this.configData.is_computed const { multiple } = this.configData if (is_computed) { // 计算模式 this.value_inner = this.ten_twe_tans(value) } else { if (multiple) { this.value_inner = value ? value.split(',') : [] } else { this.value_inner = value } if (value === null || value === 'null') { this.value_inner = '' } this.setDefault() } }, getSysParams() { const { db_name, is_mock, db_code } = commonUtility.parseUrlQueryString() const { appCode, pagename } = commonUtility.parseUrlQueryBIDyncAppcodePageName() const isMock = this.emptyList.includes(is_mock) ? 1 : is_mock const dbName = db_name || '' const obj = _.cloneDeep({ dbName, appCode, page: pagename, isMock, db_code }) return obj }, mergeCinfig(config1, config2) { Object.assign(config1, config2) }, initConfig(config) { this.mergeCinfig(this.configData, _.cloneDeep(config)) if (this.configData.ref) { this.configData.remote = !!this.configData.ref.remote_condition this.configData.filterable = !!this.configData.ref.remote_condition } const linkBtnUi = this.configData.linkBtnUi this.linkBtnUiVis = !!linkBtnUi if (this.linkBtnUiVis) { this.linkUiBtnTxt = this.configData.linkBtnUi.label } }, async initData(allSourceData) { const { config, sourceData, is_mock } = _.cloneDeep(allSourceData) this.is_mock = is_mock if (!sourceData) { this.initMockData() } else { this.initConfig(config) this.dealWithData(sourceData) } }, autoAddNullValue(data) { const sourceData = _.cloneDeep(data) if (Array.isArray(sourceData)) { const list = sourceData.map(item => { if (item.value !== '') { return Number(item.value) } }) const hasNaN = list.find(item => isNaN(item)) const zeroTarget = list.find(item => item === 0 || item === '0') let hasZero = false if (zeroTarget === 0 || hasZero === '0') { hasZero = true } if (!hasZero && !hasNaN) { sourceData.unshift({ value: '0', label: ' ' }) } } return sourceData }, dealWithData(data) { const sourceData = this.autoAddNullValue(data) const sourceData_ = _.cloneDeep(sourceData) this.options = Array.isArray(sourceData_) ? this.tansLate(sourceData_) : this.translate_json(sourceData_) }, setDefault() { const { value, multiple, ref } = this.configData const displayfield = ref && ref.displayfield const writebackfield = ref.writebackfield || [] // 查找一下默认值,如果不存在就设置display_field const t = this.options.find(xs => { if (xs[value] === this.value && this.value !== undefined) { return xs[value] === this.value } }) let displayfield_value = '' displayfield_value = this.writeBackObject[displayfield] if (!t && displayfield_value && displayfield_value !== 'null') { // 不存在就设置默认值 this.value_inner = multiple ? displayfield_value.split(',') : displayfield_value } const targetItem = this.options.find(item => item.value === this.value_inner) if (targetItem) { for (const item of writebackfield) { const [key, value] = item.split('=') const result = value ? targetItem[value] : targetItem[key] if (result !== undefined) { this.$set( this.writeBackObject, key, result ) } } } }, initMockData() { this.initMockSelectData(this.elInfo.el) }, // 折线图的模拟数据 initMockSelectData(type) { const mockData_ = mockData[type] if (!mockData_) return this.editData.config = mockData_.config this.editData.sourceData = mockData_.sourceData this.options = mockData_.sourceData }, checkUndefinedOrNullOrStr(val) { const result = [undefined, null, ''] return result.includes(val) }, // 复合值转换成2进制 ten_twe_tans(val) { const list = parseInt(val) .toString(2) .split('') .reverse() const result = [] list.forEach((x, index) => { if (typeof this.value === 'number') { x.toString() === '1' ? result.push(2 ** index) : '' } else { x.toString() === '1' ? result.push((2 ** index).toString()) : '' } }) return result }, // 节流 remoteMethodsDebounce: _.debounce(async function(query) { if (this.is_mock) return const data = await this.remoteMethod(query, this.configData) this.options = this.tansLate(data || []) }, 1000), async remoteMethod_(query) { await this.remoteMethodsDebounce(query, this.configData) }, clear_select() { const { ref, linkBtnUi, cleared, changed } = this.configData const { writebackfield } = ref if (Array.isArray(writebackfield)) { for (const item of writebackfield) { const [key] = item.split('=') this.$set(this.writeBackObject, key, '') } } if (linkBtnUi) { const writeProp = linkBtnUi.writeProp || {} for (const key in writeProp) { this.$set(this.writeBackObject, key, '') } } this.$emit('input', '') this.$emit('clear_callback', '') this.$nextTick(() => { this.exectAction(cleared) this.exectAction(changed) }) }, select_focus(event) { const { remote_condition } = this.configData.ref if (remote_condition && !this.is_mock) { this.remoteMethod_() } }, exectAction(action) { const type = typeof action if (type === 'function') { action(this.value, this.writeBackObject) } }, change(val) { const is_computed = this.configData.is_computed if (is_computed) { // 计算模式 const s = val.reduce((prve, next) => { return Number(prve) + Number(next) }, 0) this.$emit('input', typeof this.value === 'number' ? s : s.toString()) } else { const { multiple, ref } = this.configData const { writebackfield } = ref if (multiple) { const f_list = this.options.filter(xs => val.includes(xs.value)) if (writebackfield) { if (Array.isArray(writebackfield)) { for (const item of writebackfield) { const [key, value] = item.split('=') const r = f_list.map(xs => { return value ? xs[value] : xs[key] }) this.$set(this.writeBackObject, key, r.join()) } } else { const f_label = f_list.map(xs => { return xs.label }) this.$set(this.writeBackObject, writebackfield, f_label.join()) } } this.$emit('input', val.join()) const return_obj = { val, data: this.writeBackObject ? this.writeBackObject : {} } this.$emit('change_callback', return_obj) } else { // 单选模式 const target = this.options.find(xs => val === xs.value) if (val === '0' || (target && target.label === ' ')) { this.$emit('input', '') this.value_inner = '' } if (val && this.configData.allowCreate) { this.$emit('input', val) this.value_inner = val } if (writebackfield && target) { if (Array.isArray(writebackfield)) { for (const item of writebackfield) { const [key, value] = item.split('=') if (value && !value.startsWith('$')) { const result = value ? target[value] : target[key] if (!value.startsWith('$')) { // 取下拉里面的值 if (result !== undefined) { this.$set( this.writeBackObject, key, result ) } } else { // 直接设置值 const str = val.substr(1, length) this.$set( this.writeBackObject, key, str ) } } } } else { this.$set(this.writeBackObject, writebackfield, target.label) } } const return_obj = { val, data: this.writeBackObject ? this.writeBackObject : {} } if (target.label !== ' ') { this.$emit('input', val) this.$emit('change_callback', return_obj) } } } const changed = this.configData.changed this.$nextTick(() => { this.exectAction(changed) }) // setTimeout(() => { // this.exectAction(changed) // }, 1) }, tansLate(data) { const arr = data const list = [] const { value, label } = this.configData arr.forEach(element => { const parm = {} for (const pro in element) { if (pro === value && value === label) { parm.value = element[pro] parm.label = element[pro] } else if (pro === value) { parm.value = element[pro] } else if (pro === label) { parm.label = element[label] } parm[pro] = element[pro] } list.push(parm) }) return list }, tansLateParm(obj) { const { url } = this.configData let str if (url.includes('/?')) { str = '&' } else { str = '?' } for (const prop in obj) { if (obj[prop]) { str += `${prop}=${obj[prop]}&` } } return str === '?' ? '' : str }, translate_json(data = {}) { const list = [] for (const prop in data) { const parm = {} parm.value = data[prop] parm.label = prop list.push(parm) } return list }, initRealUrl() { const { url, ref } = this.configData const { const_id, table_name, columns, remote_condition } = ref if (remote_condition) { if (table_name) { return `${this.url_dynamic}${table_name}/${columns}/` } else { return `${this.url_ipCommonAPI}${url}` } } else { if (const_id) { return const_id } else if (table_name) { return `${table_name}/${columns}` } else { return url } } } } } </script> <style scoped> .contarnBox{ display: flex; } .selectTitle{ flex:1; display: flex; justify-content: center; align-items: center; } .selectCurr{ flex: 3; display: flex; justify-content: center; align-items: center; } .noneStyle >>> .el-input__inner{ background: inherit; border: none; color: inherit; } .noneStyle >>>.el-input__suffix-inner{ display: none } .noneStyle2 >>> .el-input__inner{ /* background: inherit; border: none; color: inherit; */ } .noneStyle2 >>>.el-input__suffix-inner{ display: none } /* .selectBoxPlus>>> .el-select>.el-input{ height: 100%; } .selectBoxPlus>>>.el-select .el-input__inner{ height: 100%; } */ </style>