app-upicker.vue 8.6 KB
<template>
    <div class='app-upicker'>
        <el-select ref="appUpicker" :value="refvalue" size='small' filterable
            @change="onSelect" :disabled="disabled" style='width:100%;' clearable
            @clear="onClear" @visible-change="onSelectOpen">
            <template v-if="items">
                <el-option v-for="(_item,index) in items" :key="index" :value="_item.value" :label="_item.label"></el-option>
            </template>
        </el-select>
		<span style='position: absolute;right: 5px;color: #c0c4cc;top:0;font-size: 13px;'>
            <i v-show="open" class='el-icon-arrow-up' @click="closeDropdown"></i> 
			<i v-show="!open" class='el-icon-arrow-down' @click="openDropdown"></i> 
        </span>
    </div>
</template>

<script lang = 'ts'>
import { Component, Vue, Prop, Model, Watch } from 'vue-property-decorator';
import { Subject } from 'rxjs';
import { AppModal } from '@/utils';

@Component({
})
export default class AppUpicker extends Vue {

	/**
	 * 请求到的数据
	 * @type {any[]}
	 * @memberof AppUpicker
	 */
	public itemList: any[] = []

	/**
	 * 列表项请求路径
	 *
	 * @type {string}
	 * @memberof AppUpicker
	 */
	public url: string = '';

	/**
	 * 请求参数和请求数据的映射关系
	 *
	 * @type {*}
	 * @memberof AppUpicker
	 */
	public interaction:any = {};

	/**
	 * 编辑器参数
	 *
	 * @type {*}
	 * @memberof AppUpicker
	 */
	@Prop() public itemParams?: any;

    /**
     * 视图上下文
     *
     * @type {*}
     * @memberof AppUpicker
     */
    @Prop() public context!: any;

    /**
     * 视图参数
     *
     * @type {*}
     * @memberof AppUpicker
     */
    @Prop() public viewparams!: any;

    /**
     * 表单数据
     *
     * @type {*}
     * @memberof AppUpicker
     */
    @Prop() public data!: any;

    /**
     * 属性项名称
     *
     * @type {string}
     * @memberof AppUpicker
     */
    @Prop() public name!: string;

    /**
     * 是否启用
     *
     * @type {boolean}
     * @memberof AppUpicker
     */
    @Prop() public disabled?: boolean;

    /**
     * 是否显示按钮
     *
     * @type {boolean}
     * @memberof AppUpicker
     */
    @Prop({default:true}) public showButton?: boolean;

    /**
     * 局部上下文导航参数
     * 
     * @type {any}
     * @memberof AppUpicker
     */
    @Prop() public localContext!:any;

    /**
     * 局部导航参数
     * 
     * @type {any}
     * @memberof AppUpicker
     */
    @Prop() public localParam!:any;

    /**
     * 值项名称
     *
     * @type {string}
     * @memberof AppUpicker
     */
    @Prop() public valueitem!: string;

    /**
     * 排序
     *
     * @type {string}
     * @memberof AppUpicker
     */
    @Prop() public sort?: string;

    /**
     * 值
     *
     * @type {*}
     * @memberof AppUpicker
     */
    @Model('change') public value?: any;

    /**
     * 当前值
     *
     * @type {string}
     * @memberof AppUpicker
     */
    public curvalue: string = '';

    /**
     * 下拉数组
     * @type {any[]}
     * @memberof AppUpicker
     */
    public items: any[] = [];

    /** 
     * 下拉图标指向状态管理
     * @type {boolean}
     * @memberof AppUpicker 
     */
    public open: boolean = false;

    /**
     * 输入状态
     *
     * @type {boolean}
     * @memberof AppUpicker
     */
    public inputState: boolean = false;

    /**
     * vue 生命周期
     *
     * @memberof AppUpicker
     */
    public created() {
		this.analysis(this.itemParams);
    }
    /**
     * 获取关联数据项值
     *
     * @readonly
     * @memberof AppUpicker
     */
    get refvalue() {
        if (this.valueitem && this.data) {
            return this.data[this.valueitem];
        }
        return this.curvalue;
    }

    /**
     * 展开下拉
     *
     * @memberof AppUpicker
     */
    public openDropdown() {
        const appUpicker: any = this.$refs.appUpicker;
        if(appUpicker) {
            appUpicker.focus();
        }
    }

    /**
     * 收起下拉
     *
     * @memberof AppUpicker
     */
    public closeDropdown() {
        const appUpicker: any = this.$refs.appUpicker;
        if(appUpicker) {
            appUpicker.blur();
        }
    }

    /**
     * 下拉切换回调
     * @param flag 
     * 
     * @memberof AppUpicker
     */
    public onSelectOpen(flag: boolean): void {
        this.open = flag;
        if (this.open) {
			this.fectchItemList(this.url);
        }
    }

    /**
     * 下拉选中
     *
     * @param {string} val
     * @memberof AppUpicker
     */
    public onSelect(val: string) {
        let index = this.items.findIndex((item) => Object.is(item.value, val));
        if (index >= 0) {
            let item:any = this.items[index];
            if (this.valueitem) {
                this.$emit('formitemvaluechange', { name: this.valueitem, value: item.value });
            }
            if (this.name) {
                this.$emit('formitemvaluechange', { name: this.name, value: item.label });
            }
        }
    }

    /**
     * 清除
     * 
     * @memberof AppUpicker
     */
    public onClear($event: any): void {
        if (this.valueitem) {
            this.$emit('formitemvaluechange', { name: this.valueitem, value: '' });
        }
        if (this.name) {
            this.$emit('formitemvaluechange', { name: this.name, value: '' });
        }
        this.$forceUpdate();
    }

    /**
     * 值变化
     *
     * @param {*} newVal
     * @param {*} oldVal
     * @memberof AppUpicker
     */
    @Watch('value',{immediate:true})
    public onValueChange(newVal: any, oldVal: any) {
        this.analysis(this.itemParams);
        if(newVal){
            this.curvalue = newVal;
            const value = this.data[this.valueitem];
            const index = this.items.findIndex((item: any) => Object.is(item.value, value));
            if (index !== -1) {
                return;
            }
            this.items = [];
            if (value) {
                this.items.push({text: newVal, value: value});
            }
        }
    }
	
	/**
	 * 解析编辑器参数
	 * @param {*} itemparams
     * 
	 * @memberof AppUpicker
	 */
    public analysis(itemparams:any) {
		Object.keys(itemparams).forEach((param)=>{
			if(param==='path'){
				this.url = itemparams[param]
			}else{
				this.interaction[param] = itemparams[param]
			}
        })
    }

	/**
	 * 请求下拉列表数据
	 * @param {string} url
     * 
	 * @memberof AppUpicker
	 */
	public fectchItemList(url:string) {
        let arg:any = {};
        this.handlePublicParams(arg);
		this.$http
			.get(url,arg.param)
			.then((response: any) => {
				if (response && response.status==200 && response.data) {
					this.itemList = response.data;
					// 提取需要的值(value,label)
					this.extractItem(this.itemList,this.items);
				}
			})
			.catch((response: any) => {
				if (!response || !response.status || !response.data) {
					this.$Notice.error({
						title: this.$t("app.commonWords.error") as string,
						desc: this.$t("app.commonWords.sysException") as string,
					});
					return;
				}
			});
	}

	/**
	 * 解析下拉列表数据
	 * @param {any[]} itemList 请求到的数据
	 * @param {any[]} items 下拉数组
     * 
     * @memberof AppUpicker
	 */
	public extractItem(itemList:any[],items:any[]) {
		this.items = [];
		itemList.forEach((item) => {
			this.items.push({
				label: item[this.interaction.label],
				value: item[this.interaction.value],
			});
        });
	}

    /**
     * 公共参数处理
     *
     * @param {*} arg
     * @returns
     * @memberof AppUpicker
     */
    public handlePublicParams(arg: any): boolean {
        if (!this.data) {
            this.$Notice.error({ title: (this.$t('components.appPicker.error') as any), desc: (this.$t('components.appPicker.formdataException') as any) });
            return false;
        }
        // 合并表单参数
        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.param,arg.param,this.localParam);
            Object.assign(arg.param,_param);
        }
        return true;
    }
}
</script>
<style lang="less">
@import './app-upicker.less';
</style>