<template>
  <ContentWrap>
    <div class="flex gap-x-10px">
      <div class="flex-basis-180px flex-shrink-0">
        <avue-tree
          ref="treeRef"
          v-model="treeForm"
          :option="treeOption"
          :data="treeData"
          :permission="treePermission"
          :before-open="treeBeforeOpen"
          @node-contextmenu="treeNodeContextmenu"
          @node-click="treeNodeClick"
          @update="treeUpdate"
          @save="treeSave"
          @del="treeDel"
        >
        </avue-tree>
      </div>
      <avue-crud
        class="table-content flex-1"
        ref="crudRef"
        v-model="tableForm"
        v-model:page="tablePage"
        v-model:search="tableSearch"
        :table-loading="loading"
        :data="tableData"
        :option="tableOption"
        :permission="permission"
        :before-open="beforeOpen"
        @search-change="searchChange"
        @search-reset="resetChange"
        @row-save="rowSave"
        @row-update="rowUpdate"
        @row-del="rowDel"
        @refresh-change="getTableData"
        @size-change="sizeChange"
        @current-change="currentChange"
        @selection-change="selectionChange"
      >
        <template #menu-left="{ size }">
          <el-button
            type="primary"
            :size="size"
            @click="openOptionJson(null, 'importJson')"
            v-hasPermi="['lideeyunji:desform:create']"
          >
            <Icon :size="14" icon="lucide:file-json" />
            <span class="ml-3px!">导入JSON</span>
          </el-button>
          <el-button
            :size="size"
            type="danger"
            :disabled="!tableSelect.length"
            v-hasPermi="['lideeyunji:desform:delete']"
            @click="rowDel(selectIds)"
          >
            <Icon :size="16" icon="mi:delete" class="mr-3px" />批量删除
          </el-button>
        </template>
        <template #menu="{ size, row }">
          <div class="flex justify-center flex-items-center">
            <el-button
              type="primary"
              text
              :size="size"
              @click="menuHandle({ type: 'form', row })"
              v-hasPermi="['lideeyunji:desform:update']"
            >
              <Icon :size="14" icon="ep:edit-pen"></Icon>
              <span>设计表单</span>
            </el-button>
            <span
              v-if="
                checkPermi(['lideeyunji:desform:update']) &&
                checkPermi([
                  'lideeyunji:desform:create',
                  'lideeyunji:desform:update',
                  'lideeyunji:desform:delete'
                ])
              "
              class="ml-8px mr-8px mt-2px inline-block h-16px w-1px bg-#e8e8e8 .dark:bg-[var(--el-border-color-dark)]"
            ></span>
            <el-dropdown
              @command="menuHandle"
              v-if="
                checkPermi([
                  'lideeyunji:desform:create',
                  'lideeyunji:desform:update',
                  'lideeyunji:desform:delete'
                ])
              "
            >
              <div class="mt--2px cursor-pointer">
                <el-text :size="size" type="primary">
                  更多
                  <Icon :size="16" icon="iconamoon:arrow-down-2-light" />
                </el-text>
              </div>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item
                    v-if="checkPermi(['lideeyunji:desform:update'])"
                    :command="{ type: 'edit', row }"
                  >
                    编辑
                  </el-dropdown-item>
                  <el-dropdown-item
                    :command="{ type: 'copy', row }"
                    v-if="checkPermi(['lideeyunji:desform:create'])"
                  >
                    复制表
                  </el-dropdown-item>
                  <el-dropdown-item
                    :command="{ type: 'json', row }"
                    v-if="checkPermi(['lideeyunji:desform:create'])"
                  >
                    查看配置JSON
                  </el-dropdown-item>
                  <el-dropdown-item :command="{ type: 'routeAddress', row }">
                    路由地址
                  </el-dropdown-item>
                  <el-dropdown-item
                    v-if="row.isOpen == 'Y'"
                    :command="{ type: 'externalAddress', row }"
                  >
                    外部访问链接
                  </el-dropdown-item>
                  <el-dropdown-item
                    v-if="checkPermi(['lideeyunji:desform:update'])"
                    :command="{ type: 'formUnlock', row }"
                  >
                    解除锁定
                  </el-dropdown-item>
                  <el-dropdown-item
                    v-if="checkPermi(['lideeyunji:desform:delete'])"
                    :command="{ type: 'del', row }"
                  >
                    删除
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>
        </template>
      </avue-crud>
    </div>
    <DesignPopup v-model="designPop.dialog" v-bind="designPop.params" :isBodyFull="true">
      <template #default>
        <LowFormDesign :formDesignData="designPop.value" :isShow="designPop.dialog"></LowFormDesign>
      </template>
    </DesignPopup>
    <DesignPopup v-model="MEDialog.value" v-bind="MEDialog.params" :isBodyFull="true">
      <template #default>
        <div class="h-100%">
          <MonacoEditor v-model="MEData.value" v-bind="MEData.params"></MonacoEditor>
        </div>
      </template>
    </DesignPopup>
  </ContentWrap>
</template>
<script lang="ts" setup>
import * as FormApi from '@/api/design/form'
import { ElLoading } from 'element-plus'
import { LowFormDesign } from '@/components/LowFormDesign/index'
import { cloneDeep } from 'lodash-es'
import { useGroup } from '@/hooks/design/useGroup'
import useMEDialog from '@/hooks/design/useMEDialog'
import { checkPermi } from '@/utils/permission'
import { ElButton } from 'element-plus'
import useCopyText from '@/hooks/design/useCopyText'

defineOptions({ name: 'FormDesign' })

const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const { getCurrPermi } = useCrudPermi()
const { copyText } = useCopyText()
const { MEDialog, MEData, openMEDialog } = useMEDialog()

const loading = ref(true) // 列表的加载中
//表格配置
const tableOption = reactive({
  align: 'center',
  headerAlign: 'center',
  searchMenuSpan: 6,
  searchMenuPosition: 'left',
  labelSuffix: ' ',
  selection: true,
  dialogWidth: 800,
  dialogFullscreen: false,
  editBtn: false,
  delBtn: false,
  border: true,
  index: false,
  menuWidth: 180,
  span: 12,
  column: {
    id: {
      label: '表单id',
      display: false,
      search: true
    },
    desformName: {
      label: '表单名称',
      search: true,
      rules: [{ required: true, message: '请输入表单名称', trigger: 'blur' }]
    },
    groupDesformId: {
      label: '分组类型',
      type: 'tree',
      value: '',
      dicData: [],
      filterable: true,
      defaultExpandAll: true,
      props: { label: 'name', value: 'id' },
      hide: true
    },
    updateTime: {
      label: '修改时间',
      type: 'datetime',
      format: 'YYYY-MM-DD HH:mm:ss',
      valueFormat: 'x',
      display: false
    },
    isOpen: {
      label: '外部链接访问',
      type: 'select',
      width: 110,
      search: true,
      searchLabelWidth: 110,
      value: 'N',
      dicData: [
        { label: '禁用', value: 'N' },
        { label: '启用', value: 'Y' }
      ]
    },
    isTemplate: {
      label: '是否作为模板',
      type: 'select',
      width: 110,
      search: true,
      searchLabelWidth: 110,
      value: 'N',
      dicData: [
        { label: '是', value: 'Y' },
        { label: '否', value: 'N' }
      ]
    }
  }
})
const tableForm = ref<any>({})
const tableData = ref([])
const tableSearch = ref({})
const tablePage = ref({
  currentPage: 1,
  pageSize: 10,
  total: 0
})
const tableSelect = ref([])
const designPop = ref({
  value: {},
  dialog: false,
  params: {}
})
const optionJson = ref('')

const crudRef = ref()
const treeRef = ref()

const isUnload = ref(false)

const selectIds = computed(() => {
  return tableSelect.value.map((item) => item['id'])
})
const permission = getCurrPermi(['lideeyunji:desform'])
useCrudHeight(crudRef)
const {
  treeForm,
  treeOption,
  treeData,
  groupValue,
  treePermission,
  treeBeforeOpen,
  treeNodeContextmenu,
  treeNodeClick,
  getTreeData,
  treeUpdate,
  treeSave,
  treeDel
} = useGroup(treeRef, FormApi, () => resetChange())

const menuHandle = async ({ type, row }) => {
  if (type == 'edit') crudRef.value.rowEdit(row)
  else if (type == 'form') openFormDesing(row)
  else if (type == 'copy') copyForm(row)
  else if (type == 'json') openOptionJson(row)
  else if (type.indexOf('Address') != -1) showAddress(type, row)
  else if (type.indexOf('Unlock') !== -1) unlockForm(type, row)
  else if (type == 'del') rowDel(row)
}

const showAddress = (type, row) => {
  let title = '菜单路由地址'
  let urlType = 'view'
  if (type == 'externalAddress') urlType = 'external'
  let htmlArr = [
    { label: `表单填写（默认值启用）`, value: `form/${urlType}/fillout/${row.id}` },
    { label: `表单填写（默认值禁用）`, value: `form/${urlType}/filloutNo/${row.id}` },
    { label: `表单详情查看`, value: `form/${urlType}/detail/${row.id}` }
  ]
  if (type == 'externalAddress') {
    htmlArr = htmlArr.map((item) => {
      item.value = `${window.location.origin}/${item.value}`
      return item
    })
    title = '外部链接访问地址'
  }
  let list: VNode[] = []
  htmlArr.forEach((item) => {
    list.push(
      h('div', { style: { marginBottom: '10px', border: ' 1px solid #eee', padding: '10px' } }, [
        h('div', [
          h('span', { style: { fontWeight: 600, fontSize: '14px' } }, item.label + '：'),
          h(
            ElButton,
            { size: 'small', type: 'primary', onClick: () => copyText(item.value) },
            () => '复制'
          )
        ]),
        h('div', { style: { fontSize: '12px' } }, item.value)
      ])
    )
  })
  message.alert('', title, {
    message: () => {
      return h('div', { width: '100%' }, list)
    },
    confirmButtonText: '关闭',
    dangerouslyUseHTMLString: true,
    customStyle: { width: '100%' },
    customClass: 'form-design-address-box'
  })
}

const openFormDesing = async (row) => {
  loading.value = true
  const data = await FormApi.getFormDetail({ desFormId: row.id, lock: true })
  loading.value = false
  if (data.timeStr) {
    message
      .confirm(
        `<div>
        <div style="font-size:16px"><span style="font-size:14px">当前操作人：</span>${data.userName}</div>
        <div style="font-size:16px"><span style="font-size:14px">开始操作时间：</span>${data.timeStr}</div>
        <div style="color:#E6A23C">注：如果确认没有人正在编辑，可在操作列更多里面解除锁定</div>
      </div>`,
        '当前表单已锁定',
        {
          dangerouslyUseHTMLString: true,
          cancelButtonText: '关闭',
          confirmButtonText: '强制解锁'
        }
      )
      .then(async () => menuHandle({ type: `formUnlockOpen`, row }))
    return
  }
  isUnload.value = true
  designPop.value = {
    value: data,
    dialog: true,
    params: {
      title: `表单设计 【${row.desformName}】（${row.id}）`,
      fullscreen: true,
      width: '90%',
      handleClose: async (done) => {
        await FormApi.unlockForm(row.id)
        isUnload.value = false
        done()
      }
    }
  }
}

const upDateEnhanceFormId = (row, data, oldId, loading?) => {
  const loadingFun = async (id?) => {
    const hideLoading = () => {
      loading()
      loading.value = false
      MEDialog.value.value = false
    }
    if (id) {
      const desform = JSON.parse(data.desformJson)
      if (desform.scssEnhance) {
        const rexp = new RegExp(oldId, 'g')
        desform.scssEnhance = desform.scssEnhance.replace(rexp, id)
        rowUpdate(
          { id, desformJson: JSON.stringify(desform) },
          row.$index,
          hideLoading,
          hideLoading,
          true
        )
      } else hideLoading()
    } else hideLoading()
  }
  return loadingFun
}
const copyForm = (row) => {
  message
    .prompt('新表单名称', '复制表单', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: '',
      inputValidator: (value) => {
        if (!value) return '请输入表单名称'
      }
    })
    .then(async ({ value }) => {
      loading.value = true
      const data = await FormApi.getFormDetail({ desFormId: row.id })
      data.desformName = value
      const oldId = data.id
      const loadingFun = upDateEnhanceFormId(row, data, oldId)
      delete data.id
      rowSave(data, loadingFun, loadingFun, true)
    })
}

const openOptionJson = async (row?, type?) => {
  let title = ''
  let btnOption = {} as any
  optionJson.value = ''
  if (row && !type) {
    loading.value = true
    const res = await FormApi.getFormDetail({ desFormId: row.id }).catch(() => false)
    if (!res) return (loading.value = false)
    const delKeys = [
      'createDept',
      'createTime',
      'createUser',
      'isDeleted',
      'tenantId',
      'updateTime',
      'updateUser'
    ]
    delKeys.forEach((key) => delete res[key])
    if (res.desformJson) res.desformJson = JSON.parse(res.desformJson)
    if (res.i18nData) res.i18nData = JSON.parse(res.i18nData)
    optionJson.value = JSON.stringify(res, null, 2)
    loading.value = false
    title = `【${row.desformName}】的配置JSON`
    btnOption = {
      params: { type: 'primary' },
      name: '复制JSON',
      icon: 'ep:copy-document',
      loading: true,
      clickFun: async (loading) => {
        await copyText(optionJson.value)
        loading()
        MEDialog.value.value = false
      }
    }
  } else if (type == 'importJson') {
    title = '导入自定义表单配置JSON'
    btnOption = {
      params: { type: 'primary' },
      name: '确定导入',
      icon: 'clarity:import-line',
      loading: true,
      clickFun: async (loading) => {
        let errorTip = ''
        const optionData = JSON.parse(MEData.value.value || '{}')
        if (!optionData?.desformName) errorTip = '请提供正确的JSON配置'
        if (errorTip) {
          loading()
          return message.info(errorTip)
        }
        importOptionJson(loading, optionData)
      }
    }
  }
  let params = {
    title,
    fullscreen: false,
    controlType: 'drawer',
    width: '60%',
    language: 'json',
    editorOption: { readOnly: !type },
    footerBtn: [
      btnOption,
      {
        params: {},
        name: '关 闭',
        icon: 'material-symbols:close',
        clickFun: async () => {
          MEDialog.value.value = false
        }
      }
    ]
  }
  openMEDialog({ params }, optionJson.value)
}
const importOptionJson = async (loading, optionData) => {
  const oldId = optionData.id
  delete optionData.id
  const formName = optionData.desformName
  optionData.desformJson = JSON.stringify(optionData.desformJson)
  if (optionData.i18nData) optionData.i18nData = JSON.stringify(optionData.i18nData)
  const promptData = await message
    .prompt('', '请输入表单名称', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      dangerouslyUseHTMLString: true,
      type: '',
      inputValue: formName,
      inputValidator: (value) => {
        if (value === '') return '请输入 表单名称'
      }
    })
    .catch(() => false)
  if (promptData) {
    optionData.desformName = promptData['value']
    const loadingFun = upDateEnhanceFormId({ $index: 0 }, optionData, oldId, loading)
    rowSave(optionData, loadingFun, loadingFun, true)
  } else loading()
}

const unlockForm = (type, row) => {
  message.confirm('是否确认当前表单没有其他人在编辑', '提示').then(async () => {
    loading.value = true
    await FormApi.unlockForm(row.id)
    loading.value = false
    message.success('解锁成功')
    if (type.indexOf('Open') !== -1) menuHandle({ type: `form`, row })
  })
}

const selectionChange = (data) => {
  tableSelect.value = data
}

/** 查询列表 */
const getTableData = async () => {
  loading.value = true
  let searchObj = {
    ...tableSearch.value,
    pageNo: tablePage.value.currentPage,
    pageSize: tablePage.value.pageSize
  }
  if (groupValue.value) searchObj['groupDesformId'] = groupValue.value
  for (let key in searchObj) if (searchObj[key] === '') delete searchObj[key]
  try {
    const data = await FormApi.getFormList(searchObj)
    tableData.value = data.records
    tablePage.value.total = data.total
  } finally {
    loading.value = false
  }
}

/** 搜索按钮操作 */
const searchChange = (params, done) => {
  if (Object.keys(params).length && groupValue.value) {
    treeRef.value.setCurrentKey(0)
    groupValue.value = 0
  }
  tablePage.value.currentPage = 1
  getTableData().finally(() => {
    done()
  })
}

/** 清空按钮操作 */
const resetChange = () => {
  searchChange({}, () => {})
}

const sizeChange = (pageSize) => {
  tablePage.value.pageSize = pageSize
  resetChange()
}

const currentChange = (currentPage) => {
  tablePage.value.currentPage = currentPage
  getTableData()
}

/** 表单打开前 */
const beforeOpen = async (done, type) => {
  const groupData = cloneDeep(treeData.value)
  tableOption.column.groupDesformId.dicData = groupData[0].children
  if (['edit', 'view'].includes(type) && tableForm.value['id']) {
    loading.value = true
    const data = await FormApi.getFormDetail({ desFormId: tableForm.value['id'] })
    tableForm.value = data
    loading.value = false
  }
  if (type == 'add' && groupValue.value) {
    tableForm.value.groupDesformId = groupValue.value
  }
  done()
}

/** 新增操作 */
const rowSave = async (form: object, done, loading, isId?) => {
  const elLoading = ElLoading.service({ fullscreen: true })
  let bool = await FormApi.saveFormData(form).catch(() => false)
  if (bool) {
    message.success(t('common.createSuccess'))
    resetChange()
    if (isId) done(bool)
    else done()
  } else loading()
  elLoading.close()
}

/** 编辑操作 */
const rowUpdate = async (form, index, done, loading, onData?) => {
  let bool = await FormApi.updateFormData(form).catch(() => false)
  if (bool) {
    message.success(t('common.updateSuccess'))
    if (!onData) getTableData()
    done()
  } else loading()
}

/** 删除按钮操作 */
const rowDel = async (data) => {
  try {
    // 删除的二次确认
    await message.delConfirm()
    // 发起删除
    await FormApi.deleteFormData(data instanceof Array ? data : [data.id])
    message.success(t('common.delSuccess'))
    // 刷新列表
    await getTableData()
  } catch {}
}

const beforeUnload = (event) => {
  if (isUnload.value) return (event.returnValue = '您确定要关闭页面吗？')
}

/** 初始化 **/
onMounted(async () => {
  window.addEventListener('beforeunload', beforeUnload)
  getTableData()
  getTreeData()
})

onBeforeUnmount(() => {
  window.removeEventListener('beforeunload', beforeUnload)
})
</script>

<style lang="scss" scoped>
.table-content {
  max-width: calc(100% - 190px);
}
</style>
<style lang="scss">
.form-design-address-box {
  .el-message-box__container {
    display: block;
  }
}
</style>
