<!--
 * @Author: zhaojinfeng 121016171@qq.com
 * @Date: 2023-08-14 11:07:15
 * @LastEditors: zhaojinfeng 121016171@qq.com
 * @LastEditTime: 2023-12-14 16:08:04
 * @FilePath: \vue3\packages\select-transfer-modal\index.vue
 * @Description:
 *
-->
<template>
  <span v-if="!hideButton" @click="openDialog">
    <slot>
      <el-button type="primary" plain>点击选择</el-button>
    </slot>
  </span>
  <el-config-provider :locale="locale">
    <el-dialog
      v-model="showDialog" class="select-transfer-modal" :title="title" :width="width" append-to-body
      :z-index="zIndex" @open="getList" @closed="closed"
    >
      <div flex>
        <slot name="left" />
        <div grow>
          <el-form ref="queryRef" :model="queryParams" inline>
            <el-form-item v-for="formItem in formItems" :key="formItem.prop" :label="formItem.label" :prop="formItem.prop">
              <el-select v-if="formItem.selectOptions" :placeholder="formItem.placeholder">
                <el-option v-for="option in formItem.selectOptions" :key="option.value" :value="option.value">
                  {{ option.label }}
                </el-option>
              </el-select>
              <el-input v-else v-model="queryParams[formItem.prop]" :placeholder="formItem.placeholder" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" :loading="loading" @click="handleQuery">
                查询
              </el-button>
              <el-button :loading="loading" @click="resetQuery">
                重置
              </el-button>
            </el-form-item>
          </el-form>
          <el-transfer
            v-model="transferValue"
            v-loading="loading"
            inline-block
            text-left
            style="--el-transfer-panel-width:25vw"
            :titles="['待选项', '已选项']"
            :button-texts="['移除', '添加']"
            :format="{
              noChecked: '${total}',
              hasChecked: '${checked}/${total}',
            }"
            :data="data"
            :filter-method="filterMethod"
            :props="props"
          >
            <template #default="{ option }">
              <slot name="transfer" :option="option">
                {{ option[props.label] }}
              </slot>
            </template>
            <template #left-footer>
              <el-pagination
                v-if="!hidePagination && total > queryParams.pageSize" v-model:current-page="queryParams.pageNum"
                v-model:page-size="queryParams.pageSize" background small layout="total, sizes, prev, next, jumper" mt-9px
                :page-sizes="pageSizes" :pager-count="pagerCount" :total="total" @size-change="handleSizeChange"
                @current-change="getList"
              />
            </template>
          </el-transfer>
        </div>
      </div>

      <template #footer>
        <el-space>
          <el-button type="primary" @click="confirm">
            确定
          </el-button>
          <el-button @click="showDialog = false">
            取消
          </el-button>
        </el-space>
      </template>
    </el-dialog>
  </el-config-provider>
</template>

<script lang="ts" setup name="ThSelectTransferModal">
import type { FormInstance, TransferDataItem, TransferKey, TransferPropsAlias } from 'element-plus'
import locale from 'element-plus/es/locale/lang/zh-cn'

const properties = withDefaults(
  defineProps<{
    value?: any[]
    show?: boolean
    defaultParams?: Record<string, any>
    formItems?: FormItem[]
    request: (args: any) => Promise<Page>
    pageSizes?: number[]
    pagerCount?: number
    /** 禁用按钮 */
    disabledButton?: boolean
    hideButton?: boolean
    hidePagination?: boolean
    title?: string
    width?: string | number
    zIndex?: number
    props?: TransferPropsAlias
    lockList?: TransferKey[]
    formattter?: (row: Record<string, any>) => any
  }>(),
  {
    props: () => ({ key: 'id', label: 'name', disabled: 'disabled' }),
    show: false,
    defaultParams: () => ({}),
    pageSizes: () => [20, 50, 100, 200],
    pagerCount: document.body.clientWidth < 992 ? 5 : 7,
    hidePagination: false,
    title: '选择',
    width: '70%',
    zIndex: 2023,
    formattter: (row: Record<string, any>) => {
      return { ...row }
    },
  },
)
const emit = defineEmits<{
  (event: 'update:show', show: boolean): void
  (event: 'update:value', value: any[]): void
  (event: 'confirm', rows: Record<string, any>[], keys: TransferKey[]): void
}>()

const showDialog = ref(false)

let transferValue = $ref<TransferKey[]>([])

let temp = $ref({})

let currentKeyList = $ref<TransferKey[]>([])

function filterMethod(_query: string, item: TransferDataItem) {
  const { key = 'id' } = properties.props
  return currentKeyList.includes(item[key]) || transferValue.includes(item[key])
}

const queryParams = reactive({
  pageNum: 1,
  pageSize: properties.pageSizes[0] || 10,
})

const data = computed(() => {
  const all: any[] = []
  const { props: { disabled = 'disabled', key = 'id' }, lockList } = properties
  for (const i in temp) {
    all.push({
      ...temp[i],
      [disabled]: lockList?.includes(temp[i][key]),
    })
  }

  return all
})

let total = $ref(0)
let loading = $ref(false)

/* 表单绑定的ref */
const queryRef = $ref<FormInstance>(null)

function handleQuery() {
  queryParams.pageNum = 1
  return getList()
}

/** 查询表格数据 */
async function getList() {
  loading = true
  try {
    const response = await properties.request({
      ...properties.defaultParams,
      ...queryParams,
    })
    const { key = 'id' } = properties.props
    currentKeyList = response.rows.map((e) => {
      temp[e[key]] = e
      return e[key]
    })
    total = response.total
  }
  finally {
    loading = false
  }
}
function openDialog() {
  if (properties.disabledButton)
    return

  if (properties.hideButton)
    emit('update:show', true)
  else
    showDialog.value = true
}

function closeDialog() {
  if (properties.hideButton)
    emit('update:show', false)
  else
    showDialog.value = false
}

function confirm() {
  const selections = transferValue.map(key => properties.formattter(temp[key]))
  emit('update:value', selections)
  emit('confirm', selections, [...transferValue])
  closeDialog()
}

function closed() {
  queryRef?.resetFields()
  queryParams.pageNum = 1
  currentKeyList = []
  closeDialog()
}

/** 重置按钮操作 */
function resetQuery() {
  queryRef?.resetFields()
  handleQuery()
}

function handleSizeChange(val: number) {
  if (queryParams.pageNum * val > total)
    queryParams.pageNum = 1
}

function transferValueInit() {
  const { value = [] } = properties
  const { key = 'id' } = properties.props
  const newTemp = {}
  transferValue = value.map((e) => {
    newTemp[e[key]] = e
    return e[key]
  })
  temp = newTemp
}

transferValueInit()

watch(() => properties.defaultParams, handleQuery, { deep: true })
watch(() => properties.value, transferValueInit)
watch(() => properties.show, (show) => {
  showDialog.value = show
})
</script>

<style lang="scss">
.select-transfer-modal {
  .el-checkbox:last-of-type {
    margin-right: 30px;
  }
}
</style>
