<template>
    <transition name="fade">
        <div 
            ref="selectWrapper" 
            v-transfer-dom 
            :data-transfer="transfer" 
            :class="prefixCls" 
            :style="{'z-index': transferIndex}"
            v-show="value">
            <transition name="move-up">
                <div ref="selectFrame"
                    v-show="value"
                    :class="`${prefixCls}-wrapper`" 
                    :style="position">
                    <div :class="`${prefixCls}-header`">
                        <div ref="dragBar" :class="`${prefixCls}-header-title`">
                            {{title || (selectType === 'member' ? t('selectMember.title') : t('selectMember.titleRange'))}}
                        </div>
                        <div :class="[`${prefixCls}-header-search`, {keyword}]">
                            <input
                                ref="searchInput"
                                :class="searchClasses"
                                :placeholder="t('selectMember.enterKeywordToSearch')"
                                v-model.trim="keyword" 
                                type="text" 
                                @keydown.enter="handleSearch">
                            <!-- <span @click="handleFocus" 
                                :class="`${prefixCls}-header-search-icon`">
                                <Icon size="14px" type="search"/>
                            </span> -->
                            <span @click="handleSearchClear">
                                <Icon type="sousuoqingkong" :class="`${prefixCls}-header-search-clear`" size="14px"/>
                            </span>
                            <span @click="handleSearch">
                                <Icon type="search" :class="`${prefixCls}-header-search-icon`" size="14px"/>
                            </span>
                            <!-- <YYInput type="text">
                                <Icon type="search" size="14px" style="width: 16px;display: block;" slot="suffix"/>
                            </YYInput> -->
                        </div>
                        <span v-if="closeable" 
                            :class="`${prefixCls}-header-close`" 
                            @click="handleCancel">
                            <Icon size="14px" type="close"/>
                        </span>
                    </div>
                    <div :class="`${prefixCls}-body`">
                        <keep-alive v-if="keepAlive">
                            <Section 
                                v-if="value"
                                ref="section"
                                :tabs="tabs"
                                :customTabs="customTabs"
                                :defaultActiveTab="defaultActiveTab"
                                :insearch="insearch"
                                :excludeDepts="excludeDepts"
                                :forceWithMembers="forceWithMembers"
                                @handleSelected="handleSelected" />
                        </keep-alive>
                        <template v-else>
                            <Section 
                                v-if="value"
                                ref="section"
                                :tabs="tabs"
                                :customTabs="customTabs"
                                :defaultActiveTab="defaultActiveTab"
                                :insearch="insearch"
                                :excludeDepts="excludeDepts"
                                :forceWithMembers="forceWithMembers"
                                @handleSelected="handleSelected" />
                        </template>
                        <Selected 
                            @handleSelected="handleSelected" 
                            :selected="selected"
                            :limit="limit" />
                    </div>
                    <div :class="`${prefixCls}-footer`">
                        <p :class="`${prefixCls}-footer-warning`">
                            <span v-if="selectedCount >= limit">
                                <span v-if="language === 'zhs'">最多选择{{this.limit}}条数据</span>
                                <span v-if="language === 'zht'">最多選擇{{this.limit}}條數據</span>
                                <span v-if="language === 'en'">Select up to {{this.limit}} data</span>
                            </span>
                        </p>
                        <div>
                            <YYButton type="default" @click="handleCancel">
                                {{t('selectMember.cancel')}}
                            </YYButton>
                            <YYButton :loading="loading" type="primary" :style="{ marginLeft: '4px' }" @click="handleOk">
                                {{t('selectMember.ok')}}
                            </YYButton>
                        </div>
                    </div>
                    <div v-if="enableResize" ref="resizeBar" class="resize-bar resize-br"></div>
                </div>
            </transition>
        </div>
    </transition>
</template>
<script>
    import Selected from './selected'
    import Section from './section'
    import YYButton from '../../base/button/'
    import Icon from '../../base/icon/'
    import Locale from '../../../mixins/locale'
    import { on, off } from '../../../utils/dom'
    import { oneOf, deepCopy } from '../../../utils/assist'
    import { transferIndex, transferIncrease } from '../../../utils/transfer-queue'
    import { getLang } from '../../../locale/'
    import TransferDom from '../../../directives/transfer-dom'
    import ScrollbarMixins from '../../../mixins/scrollbar'
    import Keydown from '../../../mixins/keydown'

    const prefixCls = 'yy-select-member-153'
    const host = `${window.location.protocol}//${window.location.host}`
    const types = {
        0: {
            key: 'member',
            id: 'memberId',
            yhtUserId: 'yhtUserId'
        },
        1: {
            key: 'dept',
            id: 'deptId'
        },
        2: {
            key: 'out',
            id: 'classId'
        },
        3: {
            key: 'group',
            id: 'gid'
        },
        4: {
            key: 'team',
            id: 'id'
        },
        5: {
            key: 'list',
            id: 'id'
        },
        6: {
            key: 'role',
            id: 'roleId'
        }
    }
    const source = {
        member: {}, // type 为0
        dept: {}, // type 为1
        out: {}, // type 为2
        group: {}, // type 为3
        team: {}, // type 为4
        list: {}, // type 为5
        role: {} // type 为6
    }
    export default {
        name: 'YYSelectMember',
        mixins: [Locale, ScrollbarMixins, Keydown],
        components: {
            Selected,
            Section,
            YYButton,
            Icon
        },
        directives: {
            TransferDom
        },
        provide() {
            return {
                root: this
            }
        },
        props: {
            /**
             * v-model value，是否开启选人对话框
             */
            value: {
                type: Boolean,
                default: true
            },
            /**
             * 用于customList禁止缓存
             */
            keepAlive: {
                type: Boolean,
                default: true
            },
            /**
             * v-transfer-dom指令，用于解决如果当前组件所在位置某一父级使用了 ViewBox 组件
             * 或者直接使用了 Safari 的 overflowScrolling:touch带来的 z-index 失效问题
             */
            transfer: {
                type: Boolean,
                default: true
            },
            /**
             * 是否显示右上角关闭按钮
             */
            closeable: {
                type: Boolean,
                default: true
            },
            /**
             * 空间id
             */
            qzId: {
                type: [String, Number],
                required: true
            },
            /**
             * 组织id
             */
            orgId: {
                type: [String, Number],
                default: 0
            },
            /**
             * 租户id
             * 用于角色岗位职务
             */
            tenantId: {
                type: [String, Number]
            },
            /**
             * 根组织列表 
             * [{deptId: 0, deptName: '用友网络科技股份有限公司'}]
             */
            deptList: { 
                type: Array
            },
            /** 
             * 选择组织类型 
             * @values 0-全部， 1-仅部门， 2-仅组织 
             * */
            chooseDeptType: { 
                validator: function(value) {
                    return oneOf(value, [0, 1, 2, '0', '1', '2'])
                },
                default: 0
            },
            /** 
             * 选择组织下人员类型 
             * @values 0-当前组织下全部人员， 1-只属于当前组织人员
             * */
            chooseDeptMemberType: { 
                validator: function(value) {
                    return oneOf(value, [0, 1, '0', '1'])
                },
                default: 0
            },
            /**
             * 接口地址 支持自定义 
             * ckaoke: http://ezone.yyuap.com:6058/
             * daily: https://ezone-daily.yyuap.com/
             * u8c-daily: https://ezone-u8c-daily.yyuap.com/
             * 预发布: https://ezone.esn.ren/
             * 线上:   https://ezone.yonyoucloud.com/
             */
            host: {
                type: String,
                default: host
            },
            /**
             * 标题
             */
            title: {
                type: String
            },
            /**
             * 人数限制
             */
            limit: {
                type: Number,
                default: 1500
            },
            /**
             * 是否使用友互通id
             */
            isUseYhtUserId: {
                type: Boolean,
                default: false
            },
            /**
             * 是否允许选择组织
             */
            enableOrg: {
                type: Boolean,
                default: true
            },
            /**
             * 是否启用包含下级按钮
             */
            enableContainChild: {
                type: Boolean,
                default: false
            },
            /**
             * 是否启用包含下级组织按钮
             */
            enableContainChildOrg: {
                type: Boolean,
                default: false
            },
            /**
             * 是否允许缓存
             */
            enableCatche: {
                type: Boolean,
                default: false
            },
            /**
             * 缓存名称
             */
            catchName: {
                type: String,
                default: 'YYSelectMemberData'
            },
            /**
             * 是否允许拖拽
             */
            enableDrag: {
                type: Boolean,
                default: true
            },
            /**
             * 是否允许改变窗口大小
             */
            enableResize: {
                type: Boolean,
                default: true
            },
            /**
             * 选择类型
             * @values member-人员， range-范围
             */
            selectType: {
                validator: function(value) {
                    return oneOf(value, ['member', 'range'])
                },
                default: 'member'
            },
            /**
             * 允许选择的deptId集合
             */
            enableDeptIds: {
                type: Array
            },
            /**
             * 查询分类
             * wiki地址：https://wiki.upesn.com/pages/viewpage.action?pageId=9044607
             * @values r1-IM, 审批, r2-动态/投票, r3-公告
             */
            outUserTag: {
                type: String
            },
            /**
             * 自定义已存在页签
             * 支持的数组元素类型 string， Object, 可混用
             * 对于string类型tab标题将使用默认标题
             * 对象类型支持三个属性
             * code： 值与String类型相同
             * title: 自定义标签标题
             * sort： 自定义标签排序
             * @values ['recentMember', 'dept', 'member', 'group', 'team', deptMember', 'member', 'groupMember', 'teamMember', 'out', 'outMember']， [{code:'dept', title: '院属单位', sort: 1}, ...]
             */
            defineTabs: {
                type: Array
            },
            /**
             * 自定义页签扩展
             * @values [
                {
                    title: '单据相关人员',
                    key: 'defineMembers',
                    type: 'member',
                    onLoad: (callback) => { },
                    hasMore: false,
                    data: [
                        {
                            memberId: 123,
                            userName: 'nizhja',
                            type: 0,
                            checked: true
                        }
                    ]
                },
                {
                    title: '单据相关组织',
                    key: 'defineDepts',
                    type: 'dept',
                    onLoad: (callback) => { },
                    hasMore: false,
                    data: [
                        {
                            deptId: 123,
                            deptName: 'nizhja',
                            haveSub: true,
                            expand: false,
                            type: 1,
                            checked: true
                        }
                    ]
                },
            ]
             */ 
            
            customTabs: {
                type: Array,
                default() {
                    return []
                }
            },
            /**
             * 默认激活页签
             */
            defaultActiveTab: {
                type: String
            },
            /**
             * 回显数据 当开启缓存回显时失效
             */
            haveSelected: {
                type: Object,
                default: function() {
                    return deepCopy(source)
                }
            },
            /**
             * security值将会作为defineTabs请求的参数
             */
            security: {
                type: Boolean,
                default: false
            },
            /**
             * withSecurity
             */
            withSecurity: {
                type: Boolean,
                default: false
            },
            /**
             * 是否需要排序如果需要排序，返回的字段和回显的字段需要在id之前加一个m
             */
            sortable: {
                type: Boolean,
                default: false
            },
            /**
             * 请求的参数token
             */
            token: {
                type: String
            },
            /**
             * 强制deptMemer的withMember=1
             */
            forceWithMembers: {
                type: Boolean,
                default: false
            },
            /**
             * /depts接口的参数
             */
            deptFirst: {
                type: Boolean,
                default: false
            },
            /**
             * 排除的deptId列表
             */
            excludeDepts: {
                type: Array,
                default() {
                    return []
                }
            },
            /**
             * 是否使用组织简称
             */
            useShortName: {
                type: Boolean,
                default: false
            },
            showMyDept: {
                type: Boolean,
                default: true
            },
            showMemberOrg: {
                type: Boolean,
                default: true
            },
            enableSelectAll: {
                type: Boolean,
                default: false
            },
            showRoleCode: {
                type: Boolean,
                default: false
            },
            showSelectedDeptParentName: {
                type: Boolean,
                default: false
            },
            enableScrollControl: {
                type: Boolean,
                default: true
            },
            enableTeamDept: {
                type: Boolean,
                default: false
            },
            showDeptParentName: {
                type: Boolean,
                default: false
            }
        },
        data() {
            return {
                prefixCls: prefixCls,
                selected: deepCopy(source),
                position: null,
                keyword: '',
                language: getLang(),
                isFocus: false,
                insearch: false,
                selectedCount: 0,
                transferIndex: 0,
                loading: false
            }
        },
        computed: {
            searchClasses() {
                return [
                    `${prefixCls}-header-search-input`,
                    {
                        [`${prefixCls}-header-search-input-focused`]: this.isFocus
                    }
                ]
            },
            tabs() {
                if(this.defineTabs) return this.defineTabs
                if(this.selectType === 'member') {
                    const tabs = [
                        // 'recentMember',
                        'deptMember',
                        'member',
                        'groupMember',
                        'teamMember',
                    ]
                    if (this.tenantId) tabs.push('roleMember')
                    return tabs
                }
                const tabs = [
                    'dept',
                    'member',
                    'group',
                    'team'
                ]
                if (this.tenantId) tabs.push('role')
                return tabs
            }
        },
        watch: {
            value: function(newValue) { // 监听是否打开组件
                if (newValue) {
                    this.loading = false
                    this.handleGetIndex()
                    if (this.enableScrollControl) this.addScrollEffect()
                    on(window, 'keydown', this.handleKeydown)
                    this.$nextTick(() => {
                        this.init()
                    })
                } else {
                    off(window, 'keydown', this.handleKeydown)
                    this.removeScrollEffect()
                    this.handleClear()
                }
                if (this.enableCatche && !newValue) {
                    return localStorage.setItem(this.catchName, JSON.stringify(this.selected))
                }
                const selected = this.setSelectedType()
                if (this.enableCatche) { // 允许缓存直接从缓存拿
                    const catchSelected = JSON.parse(localStorage.getItem(this.catchName))
                    this.$set(this, 'selected', {
                        ...this.selected,
                        ...catchSelected || deepCopy(selected)
                    })
                } else {
                    this.$set(this, 'selected', {
                        ...this.selected,
                        ...deepCopy(selected)
                    })
                }
                this.insearch = false 
                this.isFocus = false
                this.keyword = ''
                this.setSelectedCount()
            }
        },
        methods: {
            setSelectedType() { // 设置已选type类型
                let selected = deepCopy(this.haveSelected)
                let newSelected = deepCopy(source)
                const types = {
                    member: 0,
                    dept: 1,
                    out: 2,
                    group: 3,
                    team: 4,
                    list: 5,
                    role: 6
                }
                for(let k in selected) {
                    for(let j in selected[k]) {
                        if(this.sortable) {
                            newSelected[k][j] = selected[k][j]
                            newSelected[k][j].type = types[k]
                        } else {
                            newSelected[k]['m' + j] = selected[k][j]
                            newSelected[k]['m' + j].type = types[k]
                        }
                    }
                }
                return newSelected
            },
            setSelectedCount() { // 设置当前已选数量
                const selected = this.selected
                let count = 0
                Object.keys(selected).forEach((key)=>{
                    count += Object.keys(selected[key]).length
                })
                this.selectedCount = count
                return count
            },
            handleRadioSelected(data) { // 提供单选
                this.selected = deepCopy(source)
                const key = types[data.type].key
                const id = 'm' + data[types[data.type].id]
                if(data.checked) {
                    this.$set(this.selected[key], id, data)
                    this.setSelectedCount()
                }
            },
            handleSelected(data) {
                if(data.checked && this.selectedCount === 1 && this.limit == 1 ) {
                    return this.handleRadioSelected(data)
                }
                if(data.checked && this.selectedCount >= this.limit) return
                const key = types[data.type].key
                const id = 'm' + data[types[data.type][data.type == '0' && this.isUseYhtUserId ? 'yhtUserId' : 'id']]
                
                if(data.checked) {
                    this.$set(this.selected[key], id, data)
                    this.setSelectedCount()
                    return
                }

                let param = this.selected[key][id]
                if(param && param.type === 0 && param.parent && !data.checked) {
                    param.parent.indeterminate = false
                }
                this.$set(this.selected[key], id, null)
                delete this.selected[key][id]
                this.setSelectedCount()
            },
            handleClear() {
                this.selectedCount = 0
                Object.keys(this.selected.member).forEach((key)=>{
                    let member = this.selected.member[key]
                    if(member.parent) {
                        member.parent.indeterminate = false
                    }
                })
                Object.keys(this.selected).forEach(k => {
                    Object.keys(this.selected[k]).forEach(j => {
                        const data = this.selected[k][j]
                        data.checked = false
                        this.handleSelected(data)
                    })
                })
                this.$set(this, 'selected', deepCopy(source))

                if (this.$refs.section && typeof this.$refs.section.handleClearIndeterminate === 'function') {
                    this.$refs.section.handleClearIndeterminate()
                }
            },
            handleFocus() {
                this.isFocus = !this.isFocus
                if(this.isFocus) this.$refs.searchInput.focus()
                if(!this.isFocus) {
                    this.insearch = false 
                    this.keyword = ''
                    const searchTabs = ['recentMember', 'deptMember', 'member', 'groupMember', 'teamMember']
                    if(searchTabs.indexOf(this.$refs.section.activeTab) === -1) {
                        /**
                         * 
                         * @args keyword
                         */
                        return this.$emit('on-search', this.keyword)
                    }
                }
            },
            handleSearchClear() {
                this.insearch = false 
                this.keyword = ''
                const searchTabs = ['recentMember', 'deptMember', 'member', 'groupMember', 'teamMember']
                if(searchTabs.indexOf(this.$refs.section.activeTab) === -1) {
                    /**
                     * 
                     * @args keyword
                     */
                    return this.$emit('on-search', this.keyword)
                }
            },
            handleSearch() {
                this.insearch = true
            },
            handleCancel() {
                this.$emit('input', false)
            },
            deepCopy(source) { // 只拷贝一层
                const targetObj = source.constructor === Array ? [] : {}
                for (let keys in source) { 
                    if (source.hasOwnProperty(keys)) {
                        if (keys != 'parent' && keys != 'children') { // 避免循环引用JSON.stringify报错
                            targetObj[keys] = source[keys]
                        }
                    }
                }

                return targetObj;
            },
            handleOk() { // 点击确定
                this.loading = true
                let responseSelected = deepCopy(source)
                for (let i in this.selected) {
                    for (let j in this.selected[i]) {
                        if(this.sortable) {
                            responseSelected[i][j] = this.deepCopy(this.selected[i][j])
                        } else {
                            responseSelected[i][j.replace('m', '')] = this.deepCopy(this.selected[i][j])
                        }
                    }
                }
                setTimeout(()=>{
                    this.$emit('input', false)
                    /**
                     * 确定事件
                     * @property {object} 已选择的数据，{dept: {}， group: {}, team: {}. member: {}, list: {}, out: {}}
                     */
                    this.$emit('on-ok', responseSelected)
                }, 200)
            },
            setFramePosition(position) { // 设置当前窗体位置
                if(position.left || position.top) {
                    this.position['marginLeft'] = 0
                    this.position['marginTop'] = 0
                }
                this.position = {
                    ...this.position,
                    ...position
                }
            },
            initDrag() { // 初始化拖拽移动窗口
                if(!this.enableDrag) return
                const frame = this.$refs.selectFrame
                const handle = this.$refs.dragBar
                const docElement = document.documentElement
                const _this = this
                handle.onmousedown = function(event) {
                    let dEvent = event || window.event
                    let disX = dEvent.clientX - frame.offsetLeft
                    let disY = dEvent.clientY - frame.offsetTop

                    document.onmousemove = function(event) {
                        let mEvent = event || window.event
                        let iL = mEvent.clientX - disX
                        let iT = mEvent.clientY - disY
                        let maxL = docElement.clientWidth - frame.offsetWidth
                        let maxT = docElement.clientHeight - frame.offsetHeight
                        iL <= 0 && (iL = 0)
                        iT <= 0 && (iT = 0)
                        iL >= maxL && (iL = maxL)
                        iT >= maxT && (iT = maxT)
                
                        _this.setFramePosition({
                            left: iL + "px",
                            top: iT + "px",
                        })
                        return false
                    }

                    document.onmouseup = function() {
                        document.onmousemove = null;
                        document.onmouseup = null;
                    }
                    return false
                }
            },
            initResize() { // 初始化拖拽改变窗口大小
                if(!this.enableResize) return
                const frame = this.$refs.selectFrame
                const resizeBar = this.$refs.resizeBar
                const _this = this
                let position = {
                    ...this.position
                }
                function resize(frame, handle, isLeft, isTop, lockX, lockY) {
                    handle.onmousedown = function(event) {
                        let dEvent = event || window.event
                        let disX = dEvent.clientX - handle.offsetLeft
                        let disY = dEvent.clientY - handle.offsetTop

                        let iParentTop = frame.offsetTop
                        let iParentLeft = frame.offsetLeft
                        let iParentWidth = frame.offsetWidth
                        let iParentHeight = frame.offsetHeight
                        let lastHeight = 0;

                        document.onmousemove = function(event) {
                            let mEvent = event || window.event
                            let iL = mEvent.clientX - disX
                            let iT = mEvent.clientY - disY

                            let maxW = document.documentElement.clientWidth - frame.offsetLeft - 2
                            let maxH = document.documentElement.clientHeight - frame.offsetTop - 2;
                            let maxL = document.documentElement.clientWidth - parseInt(position.width) - 2
                            let maxT = document.documentElement.clientHeight - parseInt(position.height) - 2

                            let iW = isLeft ? iParentWidth - iL : handle.offsetWidth + iL
                            mEvent.clientY > 0 && (lastHeight = iParentHeight - iT)
                            let iH = isTop ? (mEvent.clientY <= 0 ? lastHeight : iParentHeight - iT) : handle.offsetHeight + iT
                            isLeft && (position.left = Math.min((iParentLeft + iL), maxL) + "px")
                            isTop && (position.top = Math.max(Math.min((iParentTop + iT), maxT), 0) + "px")

                            iW < parseInt(position.minWidth) && (iW = parseInt(position.minWidth))
                            iW > maxW && (iW = maxW)
                            lockX || (position.width = iW + "px")
                            iH < parseInt(position.minHeight) && (iH = parseInt(position.minHeight))
                            iH > maxH && (iH = maxH)
                            lockY || (position.height = iH + "px")
                            if((isLeft && iW == parseInt(position.minWidth)) || (isTop && iH == parseInt(position.minHeight))) {
                                document.onmousemove = null
                            }
                           
                            _this.setFramePosition({
                                width: position.width,
                                height: position.height
                            })
                            return false
                        };

                        document.onmouseup = function() {
                            document.onmousemove = null
                            document.onmouseup = null
                        };
                        return false
                    }
                }

                const onresize = function() {
                    if(!_this.value) return
                    _this.initPostion()
                    resize(frame, resizeBar, false, false, false, false)
                    const docElement = document.documentElement
                    position.left = (docElement.clientWidth - 800) / 2 + "px";
                    position.top = (docElement.clientHeight - parseInt(_this.position.height)) / 2 + "px";
                    _this.setFramePosition({
                        width: '800px',
                        height: `${parseInt(_this.position.height)}px`,
                        left: position.left,
                        top: position.top
                    })
                }

                window.onresize = onresize
                onresize()
            },
            handleGetIndex () {
                transferIncrease()
                this.transferIndex = transferIndex
            },
            initRevert() {
                if(!this.enableResize) return
                const handle = this.$refs.dragBar
                const _this = this
                let last = {}
                let isMax = false
                handle.ondblclick = function() {
                    if(!isMax) {
                        last = _this.position
                        isMax = true
                        _this.setFramePosition({
                            left: '0',
                            top: '0',
                            width: '100%',
                            height: '100%',
                        }) 

                    } else {
                        isMax = false
                        _this.setFramePosition(last) 
                    }
                }
            },
            initPostion() {
                const wrapper = this.$refs.selectWrapper
                const wrapperHeight = wrapper.offsetHeight > 750 ? 750 : wrapper.offsetHeight
                const position = {
                    width: '800px',
                    height: `${wrapperHeight * .8}px`,
                    minWidth: '800px',
                    minHeight: `${wrapperHeight * .8}px`,
					left: '50%',
                    top: '50%',
                    marginLeft: '-400px',
                    marginTop: `-${wrapperHeight * .8/2}px`
                }
                this.position = position
                
            },
            init() {
                this.initPostion()
                this.initDrag()
                this.initResize()
                this.initRevert()
            }
        },
        mounted() {
            // this.init()
        }
    }
</script>


