import { Component, Model, Prop, Vue, Inject } from 'vue-property-decorator'; import { CodeListService } from '@ibizstudio/runtime'; import { LogUtil, Util } from '@ibizstudio/runtime'; import { Subject, Subscription } from 'rxjs'; import { VueLifeCycleProcessing } from '../../../decorators'; import { calcEditorDropdownWidth } from '../utils'; import './tree-dropdown-list.less'; /** * 树形代码表插件类 * * @export * @class TreeDropdownList * @extends {Vue} */ @Component({}) @VueLifeCycleProcessing() export default class TreeDropdownList extends Vue { /** * 当前选中值 * @type {any} * @memberof TreeDropdownList */ @Model('change') readonly itemValue!: any; /** * 代码表标识 * * @type {string} * @memberof TreeDropdownList */ @Prop() tag?: string; /** * 代码表类型 * * @type {string} * @memberof TreeDropdownList */ @Prop() codelistType?: string; /** * 代码表 * * @type {string} * @memberof TreeDropdownList */ @Prop() codeList!: any; /** * 传入表单数据 * * @type {*} * @memberof TreeDropdownList */ @Prop() data?: any; /** * @description 表单状态对象 * @type {Subject} * @memberof TreeDropdownList */ @Inject('formState') formState!: Subject /** * 局部上下文导航参数 * * @type {*} * @memberof TreeDropdownList */ @Prop() localContext!: any; /** * 局部导航参数 * * @type {*} * @memberof TreeDropdownList */ @Prop() localParam!: any; /** * @description 视图上下文 * @type {*} * @memberof TreeDropdownList */ @Prop() declare context: any; /** * @description 视图参数 * @type {*} * @memberof TreeDropdownList */ @Prop() declare viewparams: any; /** * 是否禁用 * @type {any} * @memberof TreeDropdownList * */ @Prop() disabled?: any; /** * @description 只读模式 * @type {boolean} * @memberof TreeDropdownList */ @Prop({ default: false }) readonly?: boolean; /** * 下拉选提示内容 * @type {string} * @memberof TreeDropdownList */ @Prop() placeholder?: string; /** * 属性类型 * * @type {'string' | 'number'} * @memberof TreeDropdownList */ @Prop({ default: 'string' }) valueType!: 'string' | 'number'; /** * 代码表值分隔符 * * @type {string} * @memberof TreeDropdownList */ @Prop({ default: ',' }) valueSeparator!: string; /** * @description 是否多选 * @type {boolean} * @memberof TreeDropdownList */ @Prop({ default: false }) isMultiple!: boolean; /** * 代码表服务对象 * * @type {CodeListService} * @memberof TreeDropdownList */ codeListService: CodeListService = new CodeListService({ $store: this.$store }); /** * 是否有子集 * @type {boolean} * @memberof TreeDropdownList */ hasChildren: boolean = false; /** * @description 过滤词 * @memberof TreeDropdownList */ searchValue: string = ''; /** * @description 选中数据 * @type {*} * @memberof TreeDropdownList */ select: any = null; /** * 代码表 * * @type {any[]} * @memberof TreeDropdownList */ items: any[] = []; /** * @description 临时代码表 * @type {any[]} * @memberof TreeDropdownList */ codeListData: any[] = []; /** * @description 订阅对象 * @protected * @type {(Subscription | undefined)} * @memberof TreeDropdownList */ protected formStateEvent: Subscription | undefined; isSpread: boolean = false; /** * @description 获取值 * @memberof TreeDropdownList */ get currentVal() { if (this.itemValue) { return this.itemValue.split(this.valueSeparator); } else { return []; } } /** * @description 获取值 * @memberof TreeDropdownList */ set currentVal($event: any[]) { const string = $event.join(this.valueSeparator); this.$emit('change', string ? string : null); } /** * @description 当前单选输入值 * @memberof TreeDropdownList */ get curText() { if (this.select && Object.is(this.select.value, this.itemValue)) { return this.select.label; } else { const item = this.codeListData.find(data => Object.is(data.value, this.itemValue)); if (item) { this.select = item; return item.label; } else { return this.searchValue; } } } /** * @description 当前单选输入值 * @memberof TreeDropdownList */ set curText(value: string) { const autoComplete = this.$refs.autoComplete as Vue; const el = (autoComplete?.$refs?.input as Vue)?.$refs?.input; if (el && el === document.activeElement) { this.searchValue = value; } else { this.searchValue = ''; } const item = this.codeListData.find(data => Object.is(data.label, value)); if (item) { this.select = item; this.$emit('change', item.value); } else { this.$emit('change', value); } } /** * vue 生命周期 * * @memberof TreeDropdownList */ created() { if (this.formState) { this.formStateEvent = this.formState.subscribe(({ type, data }) => { if (Object.is('load', type)) { this.handleCodeListItems(); } }); } if (this.itemValue || this.itemValue === 0 || this.itemValue === false) { this.handleCodeListItems(); } } /** * 选项行样式名 * * @type {string} * @memberof DropDownList */ itemClass: string = ''; /** * 选项组样式名 * * @type {string} * @memberof DropDownList */ transferClass: string = 'transferDropdownWidthTreeDropdowmList'; /** * @description 生命周期 * @memberof TreeDropdownList */ destroyed() { if (this.formStateEvent) { this.formStateEvent.unsubscribe(); } } /** * @description 下拉显示控制 * @param {boolean} visible * @memberof TreeDropdownList */ visibleChange(visible: boolean) { this.isSpread = true; if (visible) { const dropdownSelect = this.$refs.dropdownSelect as Vue; if (dropdownSelect) { const popper = dropdownSelect.$refs.popper as Vue; if (popper) { const popperEl = popper.$el as HTMLElement; const el = this.$el as HTMLElement; if (popperEl && el) { popperEl.style.minWidth = `${el.offsetWidth}px`; popperEl.style.maxWidth = `${el.offsetWidth > 700 ? el.offsetWidth : 700}px`; } } } const autoComplete = this.$refs.autoComplete as Vue; if (autoComplete) { const select = autoComplete.$refs.select as Vue; if (select) { const dropdown = select.$refs.dropdown as Vue; if (dropdown) { const dropdownEl = dropdown.$el as HTMLElement; const el = this.$el as HTMLElement; if (dropdownEl && el) { dropdownEl.style.minWidth = `${el.offsetWidth}px`; dropdownEl.style.maxWidth = `${el.offsetWidth > 700 ? el.offsetWidth : 700}px`; } } } } this.handleCodeListItems(); } } /** * 处理代码表 * * @memberof TreeDropdownList */ handleCodeListItems() { if (this.tag && this.codelistType) { let data: any = {}; this.handlePublicParams(data); // 参数处理 let context = data.context; let viewparam = data.param; this.codeListService .getDataItems({ tag: this.tag, type: this.codelistType, data: this.codeList, context: context, viewparam: viewparam }) .then((codelistItems: Array) => { this.codeListData = codelistItems; this.formatCodeList(codelistItems); }) .catch((error: any) => { LogUtil.log(`----${this.tag}----${this.$t('app.commonwords.codenotexist') as string}`); }); } } /** * @description 公共参数处理 * @param {*} arg * @memberof TreeDropdownList */ handlePublicParams(arg: any) { // 合并表单参数 arg.param = this.viewparams ? JSON.parse(JSON.stringify(this.viewparams)) : {}; arg.context = this.context ? JSON.parse(JSON.stringify(this.context)) : {}; // 附加参数处理 if (this.localContext && Object.keys(this.localContext).length > 0) { let _context = this.$util.computedNavData(this.data, arg.context, arg.param, this.localContext); Object.assign(arg.context, _context); } if (this.localParam && Object.keys(this.localParam).length > 0) { let _param = this.$util.computedNavData(this.data, arg.context, arg.param, this.localParam); Object.assign(arg.param, _param); } } /** * 代码表类型和属性匹配 * * @param {*} items * @memberof TreeDropdownList */ formatCodeList(items: Array) { let matching: boolean = false; this.items = []; try { items.forEach((item: any) => { const type = this.$util.typeOf(item.value); if (type != this.valueType) { matching = true; if (type === 'number') { item.value = item.value.toString(); } else { if (type == 'null') { this.valueType == 'number' ? (item.value = 0) : (item.value = ''); } else if (item.value.indexOf('.') == -1) { item.value = parseInt(item.value); } else { item.value = parseFloat(item.value); } } } this.items.push(item); }); if (matching) { LogUtil.warn(`${this.tag}${this.$t('app.commonwords.codelistwarn')}`); } } catch (error) { LogUtil.warn(this.$t('app.commonwords.codelistwarn')); } this.handleLevelCodeList(Util.deepCopy(this.items)); } /** * 处理层级代码表 * * @param {*} items * @memberof TreeDropdownList */ handleLevelCodeList(items: Array) { if (items && items.length > 0) { this.hasChildren = items.some((item: any) => { return item.pvalue; }); if (this.hasChildren) { let list: Array = []; items.forEach((codeItem: any) => { if (!codeItem.pvalue) { let valueField: string = codeItem.value; this.setChildCodeItems(valueField, items, codeItem); list.push(codeItem); } }); this.items = list; } } } /** * 计算子类代码表 * * @param {*} items * @memberof TreeDropdownList */ setChildCodeItems(pValue: string, result: Array, codeItem: any) { result.forEach((item: any) => { if (item.pvalue == pValue) { let valueField: string = item.value; this.setChildCodeItems(valueField, result, item); if (!codeItem.children) { codeItem.children = []; } codeItem.children.push(item); } }); } /** * @description 对数据进行过滤,判断当前项是否显示 * @param {*} data * @param {*} pItems * @return {*} * @memberof TreeDropdownList */ isShow(data: any, pItem: any): boolean { if (Object.is(this.searchValue, '')) { return true; } if (data.text.indexOf(this.searchValue) > -1) { return true; } else { if (data.children) { if (this.findChild(data.children)) { return true; } } if (pItem.text && pItem.text.indexOf(this.searchValue) > -1) { return true; } } return false; } /** * @description 查看子项是否有符合项 * @param {*} data * @param {*} codelistItems * @param {*} word * @return {*} * @memberof TreeDropdownList */ findChild(data: any[]) { const index: number = data.findIndex((item: any) => { if (item.text.indexOf(this.searchValue) > -1) { return true; } else if (item.children) { return this.findChild(item.children); } }); return Object.is(index, -1) ? false : true; } /** * @description 生成树形代码表-下拉单选 * @param {*} items * @memberof TreeDropdownList */ setTreeDropdownList(item: any, pItem: any = {}) { const isShow: boolean = this.isShow(item, pItem); if (item.children) { return isShow ? (
{item.label}
{item.children.map((item: any) => { return this.setTreeDropdownList(item, item); })}
) : null; } else { return isShow ? ( {item.label} ) : null; } } /** * @description 绘制多选下拉树形列表 * @param {*} items * @return {*} * @memberof TreeDropdownList */ setTreeDropdownListMultiple(item: any, pItem: any = {}) { const hidden = this.isShow(item, pItem); if (item.children) { return hidden ? ( {item.children.map((item: any) => { return this.setTreeDropdownListMultiple(item, item); })} ) : null; } else { return hidden ? : null; } } render() { if (this.isMultiple) { return (
this.visibleChange(visible)} default-first-option placeholder={this.placeholder} > {this.items.map((item: any) => { return this.setTreeDropdownListMultiple(item); })}
); } else { return (
this.visibleChange(true)} icon='ios-arrow-down' on-on-blur={() => { this.isSpread = false; }} > {this.items.map((item: any) => { return this.setTreeDropdownList(item); })}
); } } }