<template>
    <div v-if="Object.is(editortype, 'linkonly')" class='app-picker'>
        <a @click="openLinkView">{{curvalue}}</a>
    </div>
    <div v-else-if="!Object.is(editortype, 'pickup-no-ac') && !Object.is(editortype, 'dropdown')" class='app-picker'>
        <div class='app-picker'>
            <el-autocomplete class='text-value' :value-key="deMajorField" :disabled="disabled" v-model="curvalue" size='small'
                :trigger-on-focus="true" :fetch-suggestions="(query, callback) => { this.onSearch(query, callback, true) }" @select="onACSelect"
                @input="onInput" @blur="onBlur" style='width:100%;'
                :placeholder="placeholder">
                <template v-slot:default="{item}">
                    <!-- <template v-if="item.isNew">
                        <div v-if="linkview" @click="newAndEdit">{{$t('components.appPicker.newAndEdit')}}</div>
                    </template> -->
                    <template v-if="item.tag">
                        <div @click="clickAction(item.tag)">{{item.caption}}</div>
                    </template>
                    <slot v-else name="default" :item="item"></slot>
                </template>
                <template v-slot:suffix>
                    <i v-if="curvalue && !disabled" class='el-icon-circle-close' @click="onClear"></i>
                    <i v-if="!Object.is(editortype, 'ac') && showButton" class='el-icon-search' @click="openView"></i>
                    <icon v-if="linkview" type="ios-open-outline" @click="openLinkView"/>
                </template>
            </el-autocomplete>
        </div>
    </div>
    <div v-else-if="Object.is(editortype, 'pickup-no-ac')" class='app-picker'>
        <div class='app-picker'>
            <el-input class='text-value' :placeholder="placeholder" :value="curvalue" readonly size='small' :disabled="disabled">
                <template slot='suffix'>
                    <i v-if="curvalue && !disabled" class='el-icon-circle-close' @click="onClear"></i>
                    <i class='el-icon-search' @click="openView"></i>
                    <icon v-if="linkview" type="ios-open-outline" @click="openLinkView"/>
                </template>
            </el-input>
        </div>
    </div>
    <div v-else-if="Object.is(editortype, 'dropdown')" class='app-picker'>
        <el-select ref="appPicker" remote :remote-method="(query) => this.onSearch(query, null, true)" :value="refvalue" size='small' filterable
            @change="onSelect" :disabled="disabled" style='width:100%;' clearable popper-class="app-picker-dropdown"
            @clear="onClear" @visible-change="onSelectOpen"
            :placeholder="placeholder">
            <template v-if="items">
                <template v-for="_item in items">
                    <el-option  v-if="!_item.tag" :key="_item[deKeyField]" :value="_item[deKeyField]" :label="_item[deMajorField]" :disabled="_item.disabled"></el-option>
                    <el-option  v-else :key="_item[deKeyField]" value="action"><span  @click="clickAction(_item.tag)" style="float: left; width: 100%;">{{ _item.caption }}</span></el-option>
                </template>
            </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, Subscription } from 'rxjs';
import { AppModal } from '@/utils';

@Component({
})
export default class AppPicker extends Vue {
    /**
     * 视图上下文
     *
     * @type {*}
     * @memberof AppPicker
     */
    @Prop() public context!: any;

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

    /**
     * AC参数
     *
     * @type {*}
     * @memberof AppPicker
     */
    @Prop({default: () => {}}) public acParams?: any;

    /**
     * 外键值附加数据
     *
     * @type {*}
     * @memberof AppPicker
     */
    @Prop() public pickUpData?: string;

    /**
     * 表单服务
     *
     * @type {*}
     * @memberof AppPicker
     */
    @Prop() public service?: any;

    /**
     * 应用实体主信息属性名称
     *
     * @type {string}
     * @memberof AppPicker
     */
    @Prop({default: 'srfmajortext'}) public deMajorField!: string;

    /**
     * 应用实体主键属性名称
     *
     * @type {string}
     * @memberof AppPicker
     */
    @Prop({default: 'srfkey'}) public deKeyField!: string;

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

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

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

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

    /**
     * 类型
     *
     * @type {string}
     * @memberof AppPicker
     */
    @Prop() public editortype?: string;

    /**
     * 视图参数（如：视图name，title，width，height）
     *
     * @type {*}
     * @memberof AppPicker
     */
    @Prop() public pickupView?: any;

    /**
     * 数据链接参数
     *
     * @type {*}
     * @memberof AppPicker
     */
    @Prop() public linkview?: any;

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

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

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

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

    /**
     * 行为组
     *
     * @type {Array<any>}
     * @memberof AppPicker
     */
    @Prop() public actionDetails?:Array<any>;


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

    /**
     * 占位提示
     * 
     * @type {*}
     * @memberof AppPicker
     */
    @Prop() public placeholder?: string;

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

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

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

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

   /**
     * 当前选择的值
     *
     * @type {string}
     * @memberof AppPicker
     */
    public selectValue = null;

    /**
     * 下拉列表节点元素
     *
     * @type {*}
     * @memberof AppPicker
     */
    public dropdownDom:any = {};

    /**
     * 订阅对象
     *
     * @type {*}
     * @memberof AppPicker
     */
    containerEvent: Subscription | null = null;

    /**
     * 获取关联数据项值
     *
     * @readonly
     * @memberof AppPicker
     */
    get refvalue() {
        if (this.valueitem && this.data) {
            return this.data[this.valueitem];
        }
        return this.curvalue;
    }

    /**
     * 值变化
     *
     * @param {*} newVal
     * @param {*} oldVal
     * @memberof AppPicker
     */
    @Watch('value',{immediate:true})
    public onValueChange(newVal: any, oldVal: any) {
        this.curvalue = newVal;
		this.selectValue = newVal;
        if (Object.is(this.editortype, 'dropdown') && this.valueitem) {
            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});
            }
            if(newVal && value){
                this.onSearch(newVal, null, false);
            }
        }
    }

    /**
     * vue 生命周期
     *
     * @memberof AppPicker
     */
    public created() {
        if(!Object.is(this.editortype, 'pickup-no-ac') && !Object.is(this.editortype, 'dropdown')){
            this.curvalue = this.value;
        }
    }

    /**
     * vue 生命周期
     *
     * @memberof AppPicker
     */
    public mounted() {
        const dropdownDom:any = this.$el.getElementsByClassName('app-picker-dropdown')[0];
        this.dropdownDom = dropdownDom;
    }

    /**
     * 组件销毁
     *
     * @memberof AppPicker
     */
    public destroyed(): void {
        if (this.containerEvent) {
            this.containerEvent.unsubscribe();
        }
    }

    /**
     * 下拉切换回调
     * @param flag 
     */
    public onSelectOpen(flag: boolean): void {
        this.open = flag;
        if (this.open) {
            this.items = [];
            //设置下拉列表的最大宽度
            this.setDropdownWidth();
            this.onSearch(this.curvalue, null, true);
        }
    }

    /**
     * 设置下拉列表最大宽度使下拉列表宽度和编辑器宽度一致
     *
     * @memberof AppPicker
     */
    public setDropdownWidth(){
        const elInput:any = this.$el.getElementsByClassName('el-input__inner')[0];
        this.dropdownDom.style.maxWidth = elInput.offsetWidth+'px';
    }

    /**
     * 执行搜索数据
     * @param query 
     * @param callback 
     */
    public onSearch(query: any, callback: any, other: boolean): void {
        // 公共参数处理
        let data: any = {};
        const bcancel: boolean = this.handlePublicParams(data);
        if (!bcancel) {
            return;
        }
        // 处理搜索参数
        let _context = data.context;
        let _param = data.param;
        query = !query ? '' : query;
        if (!this.inputState && other && Object.is(query, this.value)) {
            query = '';
        }
        this.inputState = false;
        if(this.sort && !Object.is(this.sort, "")) {
            Object.assign(_param, { sort: this.sort });
        }
        Object.assign(_param, { query: query, size: 1000 });
        // 错误信息国际化
        let error: string = (this.$t('components.appPicker.error') as any);
        let miss: string = (this.$t('components.appPicker.miss') as any);
        let requestException: string = (this.$t('components.appPicker.requestException') as any);
        if(!this.service){
            this.$Notice.error({ title: error, desc: miss+'service' });
        } else if(!this.acParams.serviceName) {
            this.$Notice.error({ title: error, desc: miss+'serviceName' });
        } else if(!this.acParams.interfaceName) {
            this.$Notice.error({ title: error, desc: miss+'interfaceName' });
        } else {
          this.service.getItems(this.acParams.serviceName,this.acParams.interfaceName, _context, _param).then((response: any) => {
              if (!response) {
                  this.$Notice.error({ title: error, desc: requestException });
              } else {
                  this.items = [...response];
              }
            //   if(this.acParams && this.linkview){
            //       this.items.push({ isNew :true });
            //   }
             if(this.acParams && this.actionDetails && this.actionDetails.length >0){
                  this.items = [...this.items,...this.actionDetails];
              }
              if (callback) {
                  callback(this.items);
              }
          }).catch((error: any) => {
              if (callback) {
                  callback([]);
              }
          });
        } 
    }

    /**
     * 选中数据回调
     * @param item 
     */
    public onACSelect(item: any): void {
        if (this.valueitem) {
            this.$emit('formitemvaluechange', { name: this.valueitem, value: item[this.deKeyField] });
        }
        if (this.name) {
            this.$emit('formitemvaluechange', { name: this.name, value: item[this.deMajorField] });
        }
        this.fillPickUpData(item);
    }

    /**
     * 下拉选中
     *
     * @param {string} val
     * @memberof AppPicker
     */
    public onSelect(val: string) {
        let index = this.items.findIndex((item) => Object.is(item[this.deKeyField], val));
        if (index >= 0) {
            this.onACSelect(this.items[index]);
        }
    }

    /**
     * 失去焦点事件
     * @param e 
     */
    public onBlur(e: any): void {
        this.curvalue = this.value;
    }

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

    /**
     * 打开视图
     */
    public openView($event: any): void {
        if (this.disabled) {
            return;
        }
        // 公共参数处理
        let data: any = {};
        const bcancel: boolean = this.handlePublicParams(data);
        if (!bcancel) {
            return;
        }
        // 参数处理
        const view = { ...this.pickupView };
        let _context = data.context;
        let _param = data.param;
        _param.selectedData = [{srfkey: this.data[this.valueitem], srfmajortext: this.curvalue }];
        // 判断打开方式
        if (view.placement && !Object.is(view.placement, '')) {
            if (Object.is(view.placement, 'POPOVER')) {
                this.openPopOver($event, view, _context, _param);
            } else {
                this.openDrawer(view, _context, _param);
            }
        } else {
            this.openPopupModal(view, _context, _param);
        }
        
    }

    /**
     * 路由模式打开视图
     *
     * @private
     * @param {string} viewpath
     * @param {*} data
     * @memberof AppPicker
     */
    private openIndexViewTab(view: any, context: any, param: any): void {
        const routePath = this.$viewTool.buildUpRoutePath(this.$route, this.context, view.deResParameters, view.parameters, [context] , param);
        this.$router.push(routePath);
    }

    /**
     * 模态模式打开视图
     *
     * @private
     * @param {*} view
     * @param {*} data
     * @memberof AppPicker
     */
    private openPopupModal(view: any, context: any, param: any): void {
        let container: Subject<any> = this.$appmodal.openModal(view, context, param);
        this.containerEvent = container.subscribe((result: any) => {
            if (!result || !Object.is(result.ret, 'OK')) {
                return;
            }
            this.openViewClose(result);
        });
    }

    /**
     * 抽屉模式打开视图
     *
     * @private
     * @param {*} view
     * @param {*} data
     * @memberof AppPicker
     */
    private openDrawer(view: any, context: any, param: any): void {
        let container: Subject<any> = this.$appdrawer.openDrawer(view, context, param);
        this.containerEvent = container.subscribe((result: any) => {
            if (!result || !Object.is(result.ret, 'OK')) {
                return;
            }
            this.openViewClose(result);
        });
    }

    /**
     * 气泡卡片模式打开
     *
     * @private
     * @param {*} $event
     * @param {*} view
     * @param {*} data
     * @memberof AppPicker
     */
    private openPopOver($event: any, view: any, context: any, param: any): void {
        let container: Subject<any> = this.$apppopover.openPop($event, view, context, param);
        this.containerEvent = container.subscribe((result: any) => {
            if (!result || !Object.is(result.ret, 'OK')) {
                return;
            }
            this.openViewClose(result);
        });
    }

    /**
     * 独立里面弹出
     *
     * @private
     * @param {string} url
     * @memberof AppPicker
     */
    private openPopupApp(url: string): void {
        window.open(url, '_blank');
    }

    /**
     * 打开重定向视图
     *
     * @private
     * @param {*} $event
     * @param {*} view
     * @param {*} data
     * @memberof AppPicker
     */
    private openRedirectView($event: any, view: any, data: any): void {
        this.$http.get(view.url, data).then((response: any) => {
            if (!response || response.status !== 200) {
                this.$Notice.error({ title: (this.$t('components.appPicker.error') as any), desc: (this.$t('components.appPicker.requestException') as any) });
            }
            if (response.status === 401) {
                return;
            }
            const { data: result } = response;

            if (result.viewparams && !Object.is(result.viewparams.srfkey, '')) {
                Object.assign(data, { srfkey: result.viewparams.srfkey });
            }

            if (Object.is(result.openmode, 'POPUPAPP') && result.url && !Object.is(result.url, '')) {
                this.openPopupApp(result.url);
            } else if (Object.is(result.openmode, 'INDEXVIEWTAB') || Object.is(result.openmode, '')) {
                // 所有数据保持在同一级
                if (data.srfparentdata) {
                    Object.assign(data, data.srfparentdata);
                    delete data.srfparentdata;
                }
                this.openIndexViewTab(view, null, data);
            } else if (Object.is(result.openmode, 'POPUPMODAL')) {
                const viewname = this.$util.srfFilePath2(result.viewname);
                const view: any = {
                    viewname: viewname,
                    title: result.title,
                    width: result.width,
                    height: result.height,
                }
                this.openPopupModal(view, null,data);
            } else if (result.openmode.startsWith('DRAWER')) {
                const viewname = this.$util.srfFilePath2(result.viewname);
                const view: any = {
                    viewname: viewname,
                    title: result.title,
                    width: result.width,
                    height: result.height,
                    placement: result.openmode,
                }
                this.openDrawer(view, null, data);
            } else if (Object.is(result.openmode, 'POPOVER')) {
                const viewname = this.$util.srfFilePath2(result.viewname);
                const view: any = {
                    viewname: viewname,
                    title: result.title,
                    width: result.width,
                    height: result.height,
                    placement: result.openmode,
                }
                this.openPopOver($event, view, null, data);
            }
        }).catch((response: any) => {
            if (!response || !response.status || !response.data) {
                this.$Notice.error({ title: (this.$t('components.appPicker.error') as any), desc: (this.$t('components.appPicker.systemException') as any) });
                return;
            }
            if (response.status === 401) {
                return;
            }
        });
    }

    /**
     * 打开链接视图
     *
     * @memberof AppPicker
     */
    public openLinkView($event: any): void {
        if (!this.data || !this.valueitem || !this.data[this.valueitem]) {
            console.error({ title: (this.$t('components.appPicker.error') as any), desc: (this.$t('components.appPicker.valueitemException') as any) });
            return;
        }
        // 公共参数处理
        let data: any = {};
        const bcancel: boolean = this.handlePublicParams(data);
        if (!bcancel) {
            return;
        }
        // 参数处理
        let _context = data.context;
        let _param = data.param;
        Object.assign(_context, { [this.deKeyField]: this.data[this.valueitem] });
        const view = JSON.parse(JSON.stringify(this.linkview));
        const viewname2: string = this.$util.srfFilePath2(view.viewname);
        view.viewname = viewname2;

        if (view.isRedirectView) {
            this.openRedirectView($event, view, data);
        } else if (Object.is(view.placement, 'INDEXVIEWTAB') || Object.is(view.placement, '')) {
            this.openIndexViewTab(view, _context, _param);
        } else if (Object.is(view.placement, 'POPOVER')) {
            this.openPopOver($event, view, _context, _param);
        } else if (Object.is(view.placement, 'POPUPMODAL')) {
            this.openPopupModal(view, _context, _param);
        } else if (view.placement.startsWith('DRAWER')) {
            this.openDrawer(view, _context, _param);
        }
    }

    /**
     * 打开页面关闭
     *
     * @param {*} result
     * @memberof AppPicker
     */
    public openViewClose(result: any) {
        let item: any = {};
        if (result.datas && Array.isArray(result.datas)) {
            Object.assign(item, result.datas[0]);
        }

        if (this.data) {
            if (this.valueitem) {
                this.$emit('formitemvaluechange', { name: this.valueitem, value: item[this.deKeyField]?item[this.deKeyField]:item["srfkey"] });
            }
            if (this.name) {
                this.$emit('formitemvaluechange', { name: this.name, value: item[this.deMajorField]?item[this.deMajorField]:item["srfmajortext"] });
            }
            this.fillPickUpData(item);
        }
    }

    /**
     * 公共参数处理
     *
     * @param {*} arg
     * @returns
     * @memberof AppPicker
     */
    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;
    }

    /**
     * 触发界面行为
     *
     * @param {*} arg
     * @returns
     * @memberof AppPicker
     */
    public clickAction(arg:any){
        this.$emit('editoractionclick',arg);
    }

    /**
     * 创建并编辑
     *
     * @param {*} arg
     * @returns
     * @memberof AppPicker
     */
    public newAndEdit($event:any){
        if (this.disabled) {
            return;
        }
        // 公共参数处理
        let data: any = {};
        const bcancel: boolean = this.handlePublicParams(data);
        if (!bcancel) {
            return;
        }
        // 参数处理
        const view = { ...this.linkview };
        view.viewname = this.$util.srfFilePath2(view.viewname);
        let _context = data.context;
        delete _context[this.deKeyField];
        let _param = data.param;
        // 判断打开方式
        if (view.placement && !Object.is(view.placement, '')) {
            if (Object.is(view.placement, 'POPOVER')) {
                this.openPopOver($event, view, _context, _param);
            } else {
                this.openDrawer(view, _context, _param);
            }
        } else {
            this.openPopupModal(view, _context, _param);
        }
        
    }

    /**
     * 输入过程中
     *
     * @memberof AppPicker
     */
    public onInput($event: any) {
        if (Object.is($event, this.value)) {
            this.inputState = true;
        }
    }

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

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

  /**
   * 填充外键值附加数据
   *
   * @param {item} 数据集
   * @memberof AppPicker
   */
  public fillPickUpData(item?:any){
    if(this.pickUpData){
        let pickUpDataArray:Array<any> = this.pickUpData.split(";")
        if(pickUpDataArray && pickUpDataArray.length >0){
            for(let i=0;i<pickUpDataArray.length;i++){
               if(item){
                    this.$emit("formitemvaluechange", {
                        name: pickUpDataArray[i],
                        value: item[pickUpDataArray[i]],
                    });
               }else{
                    this.$emit("formitemvaluechange", {
                        name: pickUpDataArray[i],
                        value: "",
                    });
               }
            }
        }
    }
  }

    

}
</script>
<style lang="less">
@import './app-picker.less';
</style>