<template>
  <div>
    <sd-data-table-ex
      v-if="!appNodeId"
      ref="dataTable"
      form-id="weAppModule"
      page-id="app/appmodule/weAppModule"
      :columns="columns"
      show-selection
      :actions="actions"
      :filter-expressions="expressions"
      :search-fields="['name']"
      @formBtnClick="formBtnClick"
      @recordSaved="recordSaved"
    >
      <!-- 详情表单 -->
      <sd-form-info slot="form" slot-scope="scope" v-bind="{ ...scope, ...$props }" />
      <!-- 名称 -->
      <template slot="name" slot-scope="text, record">
        {{ text }}
        <sd-icon
          v-if="record.formType === '可视化设计' && record.isDbSynch !== 'Y'"
          type="exclamation-circle"
          theme="twoTone"
          two-tone-color="#faad14"
          title="待同步数据库"
        />
      </template>
      <!-- 状态 -->
      <div slot="formStatus" slot-scope="text, record">
        <a-switch
          :loading="changeIds.includes(record.id)"
          :checked="text === '已发布'"
          checked-children="启用"
          un-checked-children="停用"
          @change="changeFormStatus(record)"
        />
      </div>
      <!-- 操作 -->
      <div slot="operate" slot-scope="text, record" :class="$style.operatecol">
        <!-- 按钮最多显示maxBtnNum个，如需显示的按钮超过maxBtnNum个，则第maxBtnNum个开始显示在更多按钮中 -->
        <a-button
          v-for="btn in getCommonButtons(record)"
          :key="btn.type"
          type="link"
          size="small"
          @click="btnClick(btn, record)"
          >{{ btn.title }}</a-button
        >
        <a-dropdown v-if="getMoreButtons(record).length > 0" placement="bottomCenter">
          <a-button type="link" size="small">更多<a-icon type="down"/></a-button>
          <a-menu slot="overlay">
            <a-menu-item
              v-for="btn in getMoreButtons(record)"
              :key="btn.type"
              @click="btnClick(btn, record)"
            >
              {{ btn.title }}
            </a-menu-item>
          </a-menu>
        </a-dropdown>
      </div>
    </sd-data-table-ex>
    <sd-data-table-ex
      v-else
      ref="dataTable"
      form-id="weAppModule"
      page-id="app/appmodule/weAppModule?mode=VIEW"
      :columns="commonAppColumns"
      :actions="commonAppActions"
      :filter-expressions="expressions"
      :search-fields="['name']"
      :modal-props="{ footer: null }"
    >
      <!-- 详情表单 -->
      <sd-form-info slot="form" slot-scope="scope" v-bind="{ ...scope, ...$props }" />
    </sd-data-table-ex>
    <!-- 表单关联 -->
    <sd-form-relation ref="relation" />
    <!-- 代码导出 -->
    <sd-export ref="codeExport" :app-name="appName" />
    <!-- 列表配置 -->
    <sd-form-list-config ref="listConfig" :read-only="!!appNodeId" />
    <!-- 统计配置 -->
    <sd-business-statis-config ref="statisConfig" :read-only="!!appNodeId" />
    <!-- 操作权限 -->
    <sd-action-perm ref="actionPerm" />
    <!-- 导入表单 -->
    <a-modal
      title="导入表单"
      :visible="visible"
      :width="650"
      destroy-on-close
      :mask-closable="false"
      :confirm-loading="importConfirmLoading"
      @ok="importfromfile"
      @cancel="visible = false"
    >
      <sd-form ref="importForm" :init-values="formData">
        <template>
          <sd-form-item name="attachment" />
          <sd-form-item name="appId" hidden />
        </template>
      </sd-form>
    </a-modal>
    <!-- 修订记录 -->
    <sd-revision-history ref="history" />
    <!-- 事件管理 -->
    <sd-events-manage ref="events" />
    <!-- 任务管理 -->
    <sd-task-manage ref="taskMgr" />
    <a-modal
      v-model="showPreviewMobile"
      :footer="null"
      destroy-on-close
      centered
      :dialog-class="$style.previewMobile"
    >
      <sd-phone-frame>
        <sd-mobile-render :fields="previewFormData.fields" :form-props="previewFormData.head" />
      </sd-phone-frame>
    </a-modal>
    <a-modal
      v-model="showPreview"
      :footer="null"
      destroy-on-close
      :dialog-class="$style.preview"
      width="100%"
      :closable="false"
    >
      <sd-render
        :fields="previewFormData.fields"
        :form-props="previewFormData.head"
        @close="showPreview = false"
        @themeChange="themeChange"
      />
    </a-modal>
    <a-modal
      v-model="showNonFlowPreview"
      :width="
        sdGet(previewFormData, 'head?.attrFD?.modalProps?.width') ||
          800 + sdGet(previewFormData, 'head?.attrFD?.columns') * 150
      "
      :title="previewFormData.head && previewFormData.head.tableTxt"
      destroy-on-close
      ok-text="保存"
      @ok="okClick"
    >
      <sd-non-flow-render
        ref="render"
        :fields="previewFormData.fields"
        :form-props="previewFormData.head"
      />
    </a-modal>
    <SdImportConfig
      ref="importConfig"
      mode="form"
      @configOk="(value) => importFormSubmit({ type: 1, fileId, appId, ...value })"
    />
  </div>
</template>

<script>
import { message, Modal } from '@/common/one-ui'
import download from '@/common/services/download'
import moment from 'moment'
import TableActionTypes from '@/common/services/table-action-types'
import TableColumnTypes from '@/common/services/table-column-types'
import PageService from '@/common/services/page-service'
import SdPhoneFrame from '@/form-designer/sd-phone-frame.vue'
import sdMobileRender from '@/form-designer/sd-mobile-render.vue'
import sdRender from '@/form-designer/sd-render.vue'
import sdNonFlowRender from '@/form-designer/sd-non-flow-render.vue'
import SdImportConfig from './components/sd-important-config.vue'
import ApplicationService from './application-service'
import components from './_import-components/sd-form-manage-import'

export default {
  name: 'SdFormManage',
  metaInfo() {
    return {
      title: decodeURIComponent((location.hash + '&').split('&appName=')[1]?.split('&')[0] || ''),
    }
  },
  components: {
    ...components,
    'sd-phone-frame': SdPhoneFrame,
    'sd-mobile-render': sdMobileRender,
    'sd-render': sdRender,
    'sd-non-flow-render': sdNonFlowRender,
    SdImportConfig,
  },
  props: {
    appId: {
      type: String,
      default: '',
    },
    appName: {
      type: String,
      default: '',
    },
    appNodeId: {
      type: String,
      default: undefined,
    },
  },
  data() {
    return {
      columns: [
        {
          title: '表单名称',
          dataIndex: 'name',
          sdClickable: true,
          sorter: true,
          scopedSlots: { customRender: 'name' },
        },
        {
          title: '表单类型',
          dataIndex: 'isFlow',
          width: '100px',
        },
        {
          title: '开发模式',
          dataIndex: 'formType',
          width: '180px',
        },
        {
          title: '状态',
          dataIndex: 'status',
          scopedSlots: { customRender: 'formStatus' },
          width: '100px',
        },
        {
          title: 'formId',
          dataIndex: 'formId',
          sdHidden: true,
        },
        {
          title: 'isDbSynch',
          dataIndex: 'isDbSynch',
          sdHidden: true,
        },
        {
          title: '排序号',
          dataIndex: 'sortNumber',
          sdHidden: true,
          defaultSortOrder: 'ascend',
        },
        {
          title: '创建时间',
          dataIndex: 'creationTime',
          defaultSortOrder: 'descend',
          sorter: true,
          sdRender: TableColumnTypes.dateTime,
          width: '160px',
        },
        {
          title: '操作',
          dataIndex: 'id',
          scopedSlots: { customRender: 'operate' },
          width: '310px',
        },
      ],
      maxBtnNum: 4,
      copying: false,
      syncDbing: false,
      changeIds: [],
      fileId: '',
      currentItem: null,
      visible: false,
      formData: [],
      importConfirmLoading: false,
      isNew: false,
      isAppPublish: false,
      showPreview: false,
      showNonFlowPreview: false,
      showPreviewMobile: false,
      previewFormData: {},
      commonAppActions: [
        {
          label: 'PC端预览',
          id: 'preview',
          type: TableActionTypes.inline,
          permission: null,
          hidden: (record) => {
            return record.formType !== '可视化设计'
          },
          callback: (record) => {
            this.preview(record.formId).then(() => {
              if (this.previewFormData.head.attrFD.type !== 0) {
                this.showPreview = true
              } else {
                this.showNonFlowPreview = true
              }
            })
          },
        },
        {
          label: '移动端预览',
          id: 'previewMobile',
          permission: null,
          type: TableActionTypes.inline,
          hidden: (record) => {
            return record.formType !== '可视化设计' || record.isFlow === '无流程'
          },
          callback: (record) => {
            this.preview(record.formId).then(() => {
              if (this.previewFormData.head.attrFD.type !== 0) {
                this.showPreviewMobile = true
              } else {
                this.showNonFlowPreview = true
              }
            })
          },
        },
        {
          label: '列表配置',
          id: 'listConfig',
          permission: null,
          type: TableActionTypes.inline,
          callback: (record) => {
            this.$refs.listConfig.show({
              id: record.id,
              appId: this.appId,
              isFlow: this.isFlowForm(record),
              isOnline: this.isOnlineForm(record),
            })
          },
        },
        {
          label: '统计配置',
          id: 'statisConfig',
          permission: null,
          type: TableActionTypes.inline,
          callback: (record) => {
            this.$refs.statisConfig.show(record.formId)
          },
        },
      ],
    }
  },
  computed: {
    expressions() {
      const expressions = [
        {
          dataType: 'str',
          name: 'appId',
          op: 'eq',
          stringValue: this.appId,
        },
      ]
      if (this.appNodeId) {
        expressions.push({
          dataType: 'str',
          name: 'appNodeId',
          op: 'eq',
          stringValue: this.appNodeId,
        })
      }
      return expressions
    },
    actions() {
      const actions = [
        {
          label: '新建',
          id: 'new',
          type: TableActionTypes.ex.create,
        },
        {
          label: '删除',
          id: 'delete',
          type: TableActionTypes.batch,
          permission: 'delete',
          callback: this.deleteRows,
        },
      ]
      // 非发布状态（未发布或暂停），可初始化表单
      if (!this.isAppPublish) {
        actions.push({
          label: '初始化',
          id: 'reset',
          type: TableActionTypes.batch,
          permission: null,
          callback: this.resetForm,
        })
      }
      return actions.concat([
        {
          label: '代码导出',
          id: 'codeExport',
          type: TableActionTypes.batch,
          permission: null,
          callback: this.codeExport,
        },
        {
          label: '导出',
          id: 'export',
          type: TableActionTypes.batch,
          permission: null,
          callback: this.exportForm,
        },
        {
          label: '导入',
          id: 'importForm',
          permission: null,
          callback: this.importForm,
        },
      ])
    },
    commonAppColumns() {
      this.columns.find((col) => col.dataIndex === 'creationTime').width = '240px'
      return this.columns.filter((col) => {
        return !['status', 'id'].includes(col.dataIndex)
      })
    },
  },
  created() {
    // 获取应用状态
    PageService.get(
      { id: this.appNodeId || this.appId },
      this.appNodeId ? 'app/appnode/weAppNode' : 'app/app/weApp'
    ).then((res) => {
      this.isAppPublish =
        res.data?.pageFormData?.pageFieldInfos?.find((f) => f.name === 'status').value === '1'
    })
  },
  methods: {
    formBtnClick(evt, btn, { form, recordId }) {
      if (!recordId) {
        this.isNew = true
      } else {
        this.isNew = false
      }
    },
    recordSaved(rowKey) {
      // 新建时，获取新建的数据，直接打开表单设计
      if (this.isNew) {
        PageService.get({ id: rowKey }, 'app/appmodule/weAppModule').then((res) => {
          const fields = res.data?.pageFormData?.pageFieldInfos || []
          // 开发模式：可视化设计的表单，直接打开表单设计
          const formType = fields.filter((item) => item.name === 'formType')[0]?.value
          if (formType === '1') {
            const formId = fields.filter((item) => item.name === 'formId')[0]?.value
            const isFlow =
              fields.filter((item) => item.name === 'isFlow')[0]?.value === '1' ? '流程' : '无流程'
            this.formDesign({ formId, isFlow })
          }
        })
      }
    },
    // 表单设计
    formDesign(item) {
      const { href } = this.$router.resolve({
        path: `/sd-form-designer/${item.formId}`,
        query: {
          type: this.isFlowForm(item) ? 1 : 0,
          appId: this.$route.query.appId,
        },
      })
      window.open(href, item.formId)
    },
    // 同步至数据库
    publish(record) {
      if (!this.syncDbing) {
        Modal.confirm({
          title: '您确定将表单设计同步到数据库吗？',
          content: '同步后不支持对表单字段英文ID进行修改，支持新增、修改字段其他属性',
          onOk: () => {
            this.syncDbing = true
            const key = 'syncdb'
            const duration = 1
            const mhandler = message.loading({ content: '同步中，请稍候...', key, duration: 0 })
            ApplicationService.formSync2DB(record.formId)
              .then(() => {
                message.success({ content: '同步成功！', key, duration })
                this.$refs.dataTable.refresh(true)
              })
              .finally(() => {
                mhandler()
                this.syncDbing = false
              })
          },
        })
      }
    },
    // 复制表单
    copyForm(item) {
      if (!this.copying) {
        this.copying = true
        const key = 'copyform'
        const duration = 1
        message.loading({ content: '复制中，请稍候...', key, duration: 0 })
        const newName = `${item.name}-副本`
        ApplicationService.copyModuleForm({ id: item.id, newName })
          .then(() => {
            message.success({ content: '复制成功！', key, duration })
            this.$refs.dataTable.refresh(false)
          })
          .catch((e) => {
            message.error({ content: '复制表单失败', key, duration })
          })
          .finally(() => {
            this.copying = false
          })
      }
    },
    resetForm(ids, records) {
      const customForm = records.find((item) => !this.isOnlineForm(item))
      if (customForm) {
        message.warning(`"${customForm.formType}"模式的表单不支持初始化`)
        return
      }
      const hasEnable = records.findIndex((item) => item.status === '已发布') !== -1
      if (hasEnable) {
        message.warning('请先停用表单再进行初始化操作')
        return
      }
      return new Promise((resolve) => {
        Modal.confirm({
          title: '您确定初始化选择的表单吗？',
          content: '初始化后，表单对应的所有业务数据均会被删除，无法恢复！您确认要执行此操作吗？',
          okType: 'danger',
          onOk: () => {
            const key = 'resetform'
            const duration = 1
            message.loading({ content: '正在初始化，请稍候...', key, duration: 0 })
            ApplicationService.resetForm(records.map((item) => item.formId))
              .then((res) => {
                if (!res.data?.success) {
                  message.error({ content: res.data?.message || '初始化表单出错', key, duration })
                } else {
                  message.success({ content: '初始化成功！', key, duration })
                }
                this.$refs.dataTable.refresh(true)
                this.$refs.dataTable.clearSelection()
              })
              .catch((e) => {
                message.error({ content: '初始化表单失败', key, duration })
              })
              .finally(() => {
                resolve()
              })
          },
          onCancel: () => {
            resolve()
          },
        })
      })
    },
    // 删除
    deleteRows(keys, records) {
      // 停用的表单才能删除
      const allowDel = records.findIndex((item) => item.status === '已发布') === -1
      if (allowDel) {
        return this.$refs.dataTable.deleteRows(keys)
      } else {
        message.warning('不允许删除"启用"状态的表单，请停用后再删除')
      }
    },
    // 代码导出
    codeExport(keys, records) {
      // 自定义表单才能导出
      const customForm = records.find((item) => !this.isOnlineForm(item))
      if (customForm) {
        message.warning(`"${customForm.formType}"模式的表单不支持代码导出`)
      } else {
        return this.$refs.codeExport.show(
          this.appName,
          records.map((item) => item.formId).filter((item) => item)
        )
      }
    },
    isOnlineForm(item) {
      return item.formType === '可视化设计'
    },
    isFlowForm(item) {
      return item.isFlow === '流程'
    },
    getButtons(item) {
      const btns = []
      if (item) {
        // 表单设计(自定义表单)
        if (this.isOnlineForm(item)) {
          btns.push({ type: 'formDesign', title: '表单设计' })
          // 有表单设计（即绑定了自定义表单）
          if (item.formId) {
            btns.push({ type: 'listConfig', title: '列表配置' })
            btns.push({ type: 'statisConfig', title: '统计配置' })
            btns.push({ type: 'taskMgr', title: '任务管理' })
            btns.push({ type: 'eventsMgr', title: '事件管理' })
            btns.push({ type: 'actionPerm', title: '操作权限' })
            // 同步到数据库
            if (item.isDbSynch !== 'Y') {
              btns.push({ type: 'syncDb', title: '同步到数据库' })
            }
            btns.push({ type: 'relation', title: '表单关联' })
            btns.push({ type: 'copy', title: '复制' })
            btns.push({ type: 'history', title: '修订记录' })
          }
        } else {
          // 代码开发的表单
          if (this.isFlowForm(item)) {
            // 流程类
            btns.push({ type: 'listConfig', title: '列表配置' })
          }
        }
      }
      return btns
    },
    getCommonButtons(item) {
      const buttons = this.getButtons(item)
      if (buttons.length > this.maxBtnNum) {
        return buttons.splice(0, this.maxBtnNum - 1)
      }
      return buttons
    },
    getMoreButtons(item) {
      const buttons = this.getButtons(item)
      if (buttons.length > this.maxBtnNum) {
        buttons.splice(0, this.maxBtnNum - 1)
        return buttons
      }
      return []
    },
    btnClick(btn, item) {
      switch (btn.type) {
        case 'relation':
          this.$refs.relation.show(item)
          break
        case 'formDesign':
          this.formDesign(item)
          break
        case 'syncDb':
          this.publish(item)
          break
        case 'copy':
          this.copyForm(item)
          break
        case 'listConfig': {
          this.$refs.listConfig.show({
            id: item.id,
            appId: this.appId,
            isFlow: this.isFlowForm(item),
            isOnline: this.isOnlineForm(item),
          })
          break
        }
        case 'statisConfig':
          this.$refs.statisConfig.show(item.formId)
          break
        case 'actionPerm':
          this.$refs.actionPerm.show({
            formId: item.formId,
            originType: this.isOnlineForm(item) ? 'onl' : 'vue',
          })
          break
        case 'taskMgr':
          this.$refs.taskMgr.show({
            formId: item.formId,
            moduleId: item.id,
            isFlow: this.isFlowForm(item),
          })
          break
        case 'history':
          this.$refs.history.show(item.formId)
          break
        case 'eventsMgr':
          this.$refs.events.show({
            id: item.id,
            formId: item.formId,
            appId: this.appId,
            isFlow: this.isFlowForm(item),
          })
          break
        default:
          break
      }
    },
    changeFormStatus(record) {
      let formStatus = 0
      let operate = ''
      if (record.status !== '已发布') {
        formStatus = 1
        operate = '启用'
      } else {
        formStatus = 2
        operate = '停用'
      }
      Modal.confirm({
        content: `您确定${operate}该表单吗？`,
        okText: operate,
        okType: formStatus === 2 ? 'danger' : '',
        onOk: () => {
          const headId = record.id
          this.changeIds.push(headId)
          ApplicationService.changeModuleFormStatus({ id: headId, status: formStatus })
            .then((res) => {
              if (res && res.data && res.data.success) {
                message.success({ content: `${operate}表单成功` })
                this.$refs.dataTable.refresh(false)
              } else {
                message.error({
                  content: res.data.message ? res.data.message : `${operate}表单失败`,
                })
              }
            })
            .finally(() => {
              this.changeIds = this.changeIds.filter((item) => item !== headId)
            })
        },
      })
    },
    exportForm(ids, records) {
      const fileName =
        records.map((item) => item.name).join('、') + '-' + moment().format('YYYYMMDD')
      return download(
        `api/framework/v1/we-app-module/export?moduleIds=${ids}`,
        `${fileName}.gz`,
        true
      )
    },
    importForm() {
      this.formData = this.getImportFormData()
      this.visible = true
    },
    getImportFormData() {
      return [
        {
          name: 'appId',
          dataType: 'String',
          caption: '所属应用',
          readonly: false,
          required: false,
          value: this.appId,
        },
        {
          name: 'attachment',
          dataType: 'attachment',
          caption: '附件',
          readonly: false,
          required: true,
          value: '{"value":"' + this.filegroupid() + '"}',
          attr: {
            allowType: '.gz',
            maxLength: 1,
            uploadable: true,
          },
        },
      ]
    },
    filegroupid() {
      return 'form_' + new Date().getTime() + '_' + (Math.floor(Math.random() * 100) + 1)
    },
    importfromfile() {
      this.$refs.importForm.validateFields().then((flag) => {
        if (flag) {
          const data = this.$refs.importForm.getFieldsValue()
          this.fileId = data.fileId = data.attachment?.[0]?.code
          data.type = 0
          delete data.attachment
          this.importFormSubmit(data)
        }
      })
    },
    importFormSubmit(data) {
      this.importConfirmLoading = true
      ApplicationService.importForm(data)
        .then((res) => {
          const msg = res.data?.message
          const data = res.data.data
          const moduleImportParams =
            res.data?.code === 99
              ? data.moduleImportParams.map((param, index) => {
                  param.key = index + 1
                  if (param.flowConfigs) {
                    param.flowConfigs = param.flowConfigs.map((config) => {
                      config.key = param.moduleId + config.configId
                      config.parentKey = index + 1
                      config.disabled = false
                      return config
                    })
                  }
                  return param
                })
              : []
          switch (res.data?.code) {
            case 0:
              Modal.confirm({
                title: msg,
                content: '导航菜单已更新，是否刷新页面？',
                okText: '刷新',
                cancelText: '不刷新',
                onOk: () => {
                  window.location.reload()
                },
              })
              this.$refs.dataTable.refresh(true)
              this.visible = false
              break
            case 2:
              message.warning(msg)
              this.visible = false
              break
            case 3:
              Modal.confirm({
                title: '导入完成！',
                content: msg
                  .split('\r\n')
                  .map((item) => (item ? <div>{item}</div> : ''))
                  .concat([<p>导航菜单已更新，是否刷新页面？</p>]),
                okText: '刷新',
                cancelText: '不刷新',
                onOk: () => {
                  window.location.reload()
                },
              })
              this.$refs.dataTable.refresh(true)
              this.visible = false
              break
            case 99:
              this.$refs.importConfig.show({ moduleImportParams })
              break
            default:
              message.error(msg || '导入出错：原因未知')
              break
          }
        })
        .finally(() => {
          this.importConfirmLoading = false
        })
    },
    preview(formId) {
      return ApplicationService.getFormData(formId).then((data) => {
        // 给附件默认赋个groupId，以防预览时获取附件接口报错
        data.fields.forEach((field) => {
          if (field.dataType === 'attachment') {
            field.value = '{"value":"-1"}'
          }
        })
        this.$set(this.previewFormData, 'fields', data.fields)
        this.$set(this.previewFormData, 'head', data.head)
      })
    },
    themeChange(theme) {
      this.previewFormData.head.attrFD.theme = theme
    },
    okClick() {
      this.$refs.render.validateFields().then((result) => {
        if (result) message.info('此按钮仅供查看视觉效果，并没有实际的功能')
      })
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.operatecol {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  :global(.ant-btn-sm) {
    padding: 0 3px;
  }
  :global(.ant-btn > span + .anticon) {
    margin-left: 4px;
  }
}
.preview-mobile {
  // antd居中有bug，强制覆盖
  /* stylelint-disable-next-line  */
  top: 0 !important;
  :global(.ant-modal-body) {
    max-height: none;
    padding-top: 0;
    padding-bottom: 0;
  }
  :global(.ant-modal-content) {
    background-color: transparent;
    box-shadow: none;
  }

  :global .ant-modal-close {
    top: -20px;
    right: 50px;
    .anticon {
      padding: 5px;
      background-color: $white;
      border-radius: 50%;
    }
  }
}
.preview {
  // antd居中有bug，强制覆盖
  /* stylelint-disable-next-line  */
  top: 0 !important;
  :global(.ant-modal-body) {
    height: 100vh;
    max-height: none;
    padding: 0;
  }
}
</style>
