<script>
import { Switch, Modal } from 'ant-design-vue'
import qs from 'qs'
import axios from '@/common/services/axios-instance'
import crossWindowWatcher from '@/common/services/cross-window-watcher'
import sdDataTableMixin from '@/common/components/sd-table/sd-data-table-mixin'
import SdDataTable from './xm-data-table'
import SdDetailModal from '@/common/components/sd-detail-modal'
import form from '@/common/components/sd-icon-library/icons/outline/form'
import { message } from '@/common/one-ui'
import booleanUtil from '@/common/services/boolean-util'

/**
 * <p>为了项目上能快速实现一个增删查改的模块，我们提供了组件 SdDataTableEx</p>
 * <p>该组件需要配合固定格式的接口实现</p>
 * <ul>
 * <li>获取列表 <pre>api/framework/v1/page/businessList</pre></li>
 * <li>获取详情 <pre>api/framework/v1/page/wp/${pageId}?id={beanId}</pre></li>
 * <li>保存数据 <pre>api/framework/v1/page/handleData</pre></li>
 * <li>删除数据 <pre>api/framework/v1/page/${formId}?ids={beanId1},{beanId2}</pre></li>
 * <li>权限控制 <pre>api/framework/v1/form-perm/my-authed-perms</pre></li>
 * </ul>

 * @displayName SdDataTableEx 高级数据表格
 * @since 8.0.12
 */
export default {
  name: 'XmDataTableEx',
  mixins: [sdDataTableMixin],
  inheritAttrs: false,
  props: {
    projectlist: {
      type: Boolean,
      default: false,
    },
    /**
     * framework/v1/page/businessList 接口中的 formId
     */
    formId: {
      type: String,
      required: true,
    },
    /**
     * framework/v1/page/wp 接口中的 pageId
     */
    pageId: {
      type: String,
      default: function() {
        return this.formId
      },
    },
    /**
     * framework/v1/page/wp 接口中的 extParams
     * @since 8.1.0.29
     */
    extParams: {
      type: Object,
      default: undefined,
    },
    /**
     * 获取表格数据 API的url
     */
    dataUrl: {
      type: String,
      default: 'api/xcoa-mobile/v1/iam-page/businessList',
    },
    /**
     * 传给详情 modal 的 props，可以用于设置样式等
     */
    modalProps: {
      type: Object,
      default: undefined,
    },
    /***
     * 请求过滤方法
     */
    processReq: {
      type: Function,
      default: undefined,
    },
    /**
     * 选择列表单选或者复选 add by zzb 20220224
     */
    checkType: {
      type: String,
      default: 'checkbox',
    },
    /***
     * 是否显示高级搜索按钮
     */
    showAdvanceQuery: {
      type: Boolean,
      default: false,
    },
    /***
     * 当前页面是否显示操作按钮
     */
    editnode: {
      type: Boolean,
      default: true,
    },
    /**
     * 自定义删除方法
     */
    customDeleteFun: {
      type: Function,
      requier: false,
    },
    /** 自定义行 */
    customRow: {
      type: Function,
      requier: false,
    },
    // 加载样式
    fnonloadsum: {
      type: Function,
      default: null,
    },
  },
  data() {
    return {
      recordId: undefined,
      localPageId: this.pageId,
      loadingSwitchs: [],
      isWindowOpen: false,
    }
  },
  computed: {
    // 把新建和删除按钮转换为标准格式
    computedActions() {
      const actions = this.actions.map((act) => {
        const action = { ...act }
        if (action.type === 'delete') {
          action.type = 'batch'
          if (this.customDeleteFun) {
            action.callback = this.customDeleteFun
          } else {
            action.callback = this.deleteRows
            action.permission = 'delete'
          }
        } else if (action.type === 'create') {
          action.type = 'primary'
          action.permission = 'create'
          action.callback = this.create
        }

        if (action.permission) {
          if (action.permission.startsWith(this.formId + '-')) {
            // eslint-disable-next-line no-console
            console.warn(
              `按钮 "${act.label}" 的 permission 属性请去掉 "${this.formId}-" 部分，formId 会自动添加`
            )
          } else {
            if (!action.permission.includes('-')) {
              action.permission = `${this.formId}-${action.permission}`
            }
          }
        }

        return action
      })
      return actions
    },
    formatedColumns() {
      const columns = this.columns.map((col) => {
        if (col.sdRender === 'switch') {
          // 行内的切换按钮
          col.customRender = (text, record, index, column) => {
            return (
              <Switch
                checked={booleanUtil.isTruthy(text)}
                loading={this.loadingSwitchs.indexOf(record.id) > -1}
                onChange={() => this.onSwitchChange(record, column)}
              />
            )
          }
        }
        return col
      })
      return columns
    },
  },
  // 加载分级授权获取部门下拉框 add by zzb
  mounted() {
    this.isWindowOpen = !this.$scopedSlots.form
    let tree = this.$parent.$children.find((item) => {
      return item.$options._componentTag === 'audit-tree'
    })
    if (!tree) {
      tree = this.$parent.$parent.$children.find((item) => {
        return (
          (item.$options._componentTag === 'audit-tree') |
          (item.$options._componentTag === 'audit-matters-catalog-tree') |
          (item.$options._componentTag === 'mtx-process-catalog-tree') |
          (item.$options._componentTag === 'mtx-version-catalog-tree') |
          (item.$options._componentTag === 'risk-category-tree')
        )
      })
    }
    // 如果还是找不到树组件，则直接退出
    if (!tree) {
      if (tree?.initTreeData) {
        tree.initTreeData()
      }
      return
    }
    const table = this.$parent.$children.find((item) => {
      return (
        (item.$options._componentTag === 'sd-data-table-ex') |
        (item.$options._componentTag === 'sd-oa-table')
      )
    })
    if (!table) {
      const acard = this.$parent.$children.find((item) => {
        return item.$options._componentTag === 'a-card'
      })
      let intable
      if (acard) {
        intable = acard.$parent.$children.find((item) => {
          return item.$options._componentTag === 'sd-data-table-ex'
        })
      } else {
        intable = this.$parent.$children.find((item) => {
          return item.$options._componentTag === 'sd-data-table-ex'
        })
      }
      // 显示下拉框才初始化
      if (tree.isSelectDep) {
        tree.initDeptList(intable.formId)
      } else if (tree.checkNodeEdit) {
        // 如果需要检查节点权限
        if (tree?.beforeInitTreeData) {
          tree.beforeInitTreeData(intable.formId)
        }
      } else {
        // 正常加载
        tree.initTreeData()
      }
    } else {
      // 显示下拉框才初始化
      if (tree.isSelectDep) {
        tree.initDeptList(table.formId)
      } else if (tree.checkNodeEdit) {
        // 如果需要检查节点权限
        if (tree?.beforeInitTreeData) {
          tree.beforeInitTreeData(table.formId)
        }
      } else {
        // 正常加载
        tree.initTreeData()
      }
    }
  },
  methods: {
    addMonitor() {
      window.addEventListener('message', this.eventListener, false)
    },
    removeMonitor() {
      window.removeEventListener('message', this.eventListener, false)
    },
    eventListener(event) {
      // 格式为{type:'', data: {}}
      if (event.data?.type === 'recordSaved') {
        const data = event.data.data
        if (data.formId === this.formId) {
          this.refresh()
          this.$emit('recordSaved', data.recordId)
        }
      }
    },
    rowClick(record) {
      this.showDetailModal(record.id, this.pageId)
    },
    create() {
      this.showDetailModal(null, this.pageId)
    },
    showDetailWindow(recordId = null, pageId = this.pageId) {
      crossWindowWatcher.subscribeChange({
        url:
          '/sd-webform?' +
          qs.stringify({
            id: recordId,
            pageId,
            // 新建时，传extParams，用于设置默认值
            extParams: !recordId && this.extParams ? JSON.stringify(this.extParams) : undefined,
          }),
        callback: (data) => {
          this.refresh()
          this.$emit('recordSaved', recordId || data?.pageFormData?.beanId)
        },
      })
    },
    /**
     * 获取详情对话框，可以通过它调用操作字段的API
     * 详情信息以Modal方式打开时有效
     * @public
     */
    getDetailModal() {
      return this.$refs.detail
    },
    /**
     * 隐藏详情对话框
     * 详情信息以Modal方式打开时有效
     * @public
     */
    hideDetailModal() {
      this.$refs.detail.hide()
    },
    /**
     * 显示详情对话框(Modal或新窗口方式)
     * @public
     * @param {string} recordId 要显示的记录ID，不传此参数表示新建
     * @param {string} pageId 用哪个page显示，默认为组件pageId prop的值
     */
    showDetailModal(recordId = null, pageId = this.pageId) {
      if (this.isWindowOpen) {
        this.showDetailWindow(recordId, pageId)
      } else {
        this.recordId = recordId
        this.localPageId = pageId
        this.$refs.detail.show()
      }
      /**
       * 详情对话框显示时触发8.1.0.27添加纪录id
       */
      this.$emit('detailModalShow', recordId)
    },
    deleteRows(selectedRowKeys) {
      return new Promise((resolve) => {
        // 判断是否起草环节
        const rows = this.$refs.dataTable.getSelectedRows()
        let flag = true
        let surl = 'api/framework/v1/page/' + this.formId
        if (rows[0].instId === undefined || rows[0].instId === null) {
          surl = 'api/xcoa-mobile/v1/iam-page/' + this.formId
        } else {
          // 流程类的 判断是否是起草环节
          rows.forEach((r) => {
            if (r.endType) {
              if (r.endType !== 0) {
                flag = false
              }
            }
          })
        }
        if (!flag) {
          Modal.error({
            title: '删除失败：存在不是起草状态的数据',
          })
          resolve()
        } else {
          Modal.confirm({
            title: '您确定删除这项内容吗？',
            content: '删除这条数据后，就无法恢复初始的状态。',
            okText: '删除',
            cancelText: '取消',
            okType: 'danger',
            onOk: () => {
              axios({
                // url: 'api/framework/v1/page/' + this.formId,
                url: surl,
                method: 'delete',
                params: {
                  ids: selectedRowKeys.join(','),
                },
              })
                .then((res) => {
                  if (res.status === 200) {
                    this.clearSelection()
                    this.refresh()
                    message.success('删除成功')
                    /**
                     * 数据删除成功后触发
                     * @property {Array} rowKeys 已删除的记录ids
                     */
                    this.$emit('recordsDeleted', selectedRowKeys)
                  } else {
                    if (res.errors) {
                      message.error(res.errors)
                    } else {
                      message.error('删除失败，请联系管理员')
                    }
                  }
                })
                .catch((e) => {
                  let messageinfo = '删除失败，请联系管理员'
                  if (e.response?.data?.code === '-1') {
                    messageinfo = e.response?.data?.message
                  } else if (['403', '401'].includes(e.response?.data?.code)) {
                    messageinfo = '您没有访问权限'
                  } else if (e.response?.data?.code === '405') {
                    if (e.response.data && e.response.data.errors) {
                      messageinfo = e.response.data.errors
                    }
                  } else {
                    messageinfo = '处理失败，请联系管理员'
                  }
                  message.error(messageinfo)
                })
                .finally(resolve)
            },
            onCancel: () => {
              resolve()
            },
          })
        }
      })
    },
    /**
     * 获取当前选中的记录(仅包含rowKey)
     * @public
     * @returns {Array}
     */
    getSelectedRowKeys() {
      return this.$refs.dataTable.getSelectedRowKeys()
    },
    /**
     * 获取当前选中的记录
     * @public
     * @returns {Object[]}
     */
    getSelectedRows() {
      return this.$refs.dataTable.getSelectedRows()
    },
    /**
     * 刷新表格
     * @public
     * @param {boolean} toFirstPage 是否返回第一页
     */
    refresh(toFirstPage) {
      return this.$refs.dataTable.refresh(toFirstPage)
    },
    clearSelection() {
      this.$refs.dataTable.clearSelection()
    },
    // 行内的切换按钮。先读取详情，再保存
    onSwitchChange(record, column) {
      this.loadingSwitchs.push(record.id)
      axios({
        url: 'api/framework/v1/page/wp/' + this.pageId,
        method: 'get',
        params: {
          id: record.id,
        },
      })
        .then((res) => {
          const resJson = res.data
          const data = {
            eventId: 'save',
            inputs: resJson.pageFormData.pageFieldInfos.map((v) => ({
              name: v.name,
              value: v.name === column.dataIndex ? booleanUtil.getOppositeValue(v.value) : v.value,
            })),
            pageFlowId: resJson.attrs.pageflowId,
            pagePath: resJson.attrs.pagePath,
          }
          return axios({
            url: 'api/framework/v1/page/handleData',
            method: 'post',
            data,
          })
        })
        .then((res) => {
          this.refresh()
          /**
           * 数据保存成功后触发
           * @property {String} rowKey 已保存的记录id
           */
          this.$emit('recordSaved', record.id)
        })
        .finally(() => {
          const index = this.loadingSwitchs.indexOf(record.id)
          if (index > -1) {
            this.loadingSwitchs.splice(index, 1)
          }
        })
    },
    /**
     * 导出Excel
     * @public
     * @since 0.15
     * @returns {Promise}
     */
    exportExcel() {
      return this.$refs.dataTable.exportExcel()
    },
    /**
     * 重新计算各列的宽度，容器宽度发生变化时，可以调用
     * @public
     * @since 0.15
     */
    handleResize() {
      return this.$refs.dataTable.handleResize()
    },
  },
  /**
   * 详情表单内容
   * @slot form
   * @binding {object} model 整个表单的数据，可用于 v-model 绑定
   * @binding {object} fields 后台返回的字段定义
   * @binding {string} pageId 当前显示详情页使用的pageId，可以为不同pageId画不同的表单
   * @binding {object} formData 当前显示详情页的整个formData（8.1.0.24新增）
   */
  render() {
    const { form: formSlot, ...columnSlots } = this.$scopedSlots
    const { columns, ...restProps } = this.$props

    return (
      <div>
        <SdDataTable
          {...{
            attrs: {
              ...restProps,
              projectlist: this.projectlist,
              editnode: this.editnode,
              columns: this.formatedColumns,
              dataUrl: this.dataUrl,
              actions: this.computedActions,
              processReq: (req) => {
                req.data.formId = this.formId
                if (this.processReq) {
                  req = this.processReq(req)
                }
                return req
              },
            },
            ref: 'dataTable',
            on: {
              rowClick: this.rowClick,
              dataLoaded: (pagination) => {
                /**
                 * 表格数据加载完成时触发
                 * @property {Object} pagination 分页信息{current,pageSize,total}
                 */
                this.$emit('tableDataLoaded', pagination)
              },
              onChange: (pagination, filters, sorter) => {
                this.$emit('onChange', pagination, filters, sorter)
              },
              searchbtnClick: () => {
                this.$emit('searchbtnClick')
              },
              selectedRowsChanged: (selectedRows) => {
                this.$emit('selectedRowsChanged', selectedRows)
              },
              fnonloadsum: () => {
                if (this.fnonloadsum !== null) {
                  this.fnonloadsum()
                }
              },
            },
            scopedSlots: { ...columnSlots },
          }}
        ></SdDataTable>
        {formSlot ? (
          <SdDetailModal
            ref='detail'
            pageId={this.localPageId}
            recordId={this.recordId}
            extParams={this.extParams}
            onSaved={(data) => {
              this.refresh()
              message.success('保存成功')
              this.$emit('recordSaved', this.recordId || data?.pageFormData?.beanId)
            }}
            onActionBtnClick={(evt, btn) => {
              /**
               * 详情表单内的操作按钮点击时触发
               *
               * @property {event} evt 事件对象，可以用来取消默认操作等
               * @property {object} btn 点击的按钮
               * @property {object} context 上下文信息，其中包括：
               * form：详情对话框
               * recordId：当前记录ID
               */
              this.$emit('formBtnClick', evt, btn, {
                form: this.$refs.detail,
                recordId: this.recordId,
              })
            }}
            scopedSlots={{ default: formSlot }}
            modalProps={this.modalProps}
          />
        ) : (
          ''
        )}
      </div>
    )
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
</style>
