<template>
  <div>
    <portal
      class="sd-attachment-ex-contain"
      :to="`sd-attachment-ex${groupId}`"
      :disabled="!enablePreview"
    >
      <div :class="{ [$style.contain]: true, [$style.attachmentextab]: enablePreview }">
        <a-spin v-if="init === -1">
          <div class="spin-content" />
        </a-spin>
        <a-spin
          v-if="
            computedZwList.length &&
              enablePreview &&
              (computedZwList[0].busy || !computedZwList[0].Completed)
          "
          size="small"
          :class="$style.spin"
        />
        <div v-if="init === 1" :class="$style.buttons">
          <a-button
            v-if="!computedZwList.length && _zwUploadable && !formReadOnly"
            :type="enablePreview ? 'link' : 'primary'"
            icon="plus"
            :loading="copyLoading"
            @click="
              () => {
                copyLoading = true
                // 如有传了自定义方法，则走自己的
                if (customSelectTemplateFun) {
                  customSelectTemplateFun()
                  return
                }
                uploadByTemplateCode().then(() => {
                  copyLoading = false
                  getFileList()
                })
              }
            "
          >
            模板创建</a-button
          >
          <a-upload
            v-if="!computedZwList.length && _zwUploadable && !formReadOnly"
            name="zw"
            :accept="acceptZwType"
            :multiple="false"
            :custom-request="(file) => customRequestZw(file)"
            :file-list="[]"
          >
            <a-button :type="enablePreview ? 'link' : ''" icon="plus" @click="beforeUpload">
              手动上传</a-button
            >
          </a-upload>
          <a-button
            v-if="
              pluginName === 'WPSDOCX' && !computedZwList.length && _zwUploadable && !formReadOnly
            "
            :type="enablePreview ? 'link' : ''"
            icon="form"
            :loading="createZwLoading"
            @click="createZw"
            >在线新建正文</a-button
          >
          <UploadFj v-if="uploadfj && !enablePreview && !formReadOnly" :context="_self" />
          <PlDownload v-if="uploadfj && !enablePreview" :context="_self" />

          <a-tooltip
            v-if="computedZwList[0] && enablePreview"
            placement="top"
            title="点击进入编辑页面"
            :overlay-class-name="computedZwList[0].editable ? '' : 'hide'"
          >
            <a
              :class="$style.filename"
              :disabled="!computedZwList[0].editable || !!busy[computedZwList[0].FileName]"
              @click="OpenMyFile(computedZwList[0].FileName)"
            >
              <a-spin v-if="!!busy[computedZwList[0].FileName]" size="small" :class="$style.spin" />
              {{ computedZwList[0].name }}
            </a>
          </a-tooltip>
          <ActionButtons
            v-if="enablePreview && computedZwList[0]"
            :context="_self"
            :item="computedZwList[0]"
          />
          <a-modal
            v-if="enablePreview && computedZwList[0]"
            :visible="computedZwList[0].doReName"
            title="重命名"
            @ok="UpdateName(computedZwList[0])"
            @cancel="ReName(computedZwList[0], false)"
          >
            <a-input
              v-model="newname"
              :addon-after="getFileType(computedZwList[0].FileName)"
              :max-length="parseInt(filenameMaxLength)"
            />
          </a-modal>
        </div>
        <a-button
          v-if="!enablePreview && versionVisiable"
          icon="sd-desktop"
          type="link"
          title="本电脑相关信息"
          :class="$style.controlinfor"
          @click="showVersionInfo"
        />
        <component
          :is="readerPlugin"
          v-if="enablePreview && computedZwList.length && computedZwList[0].code"
          :key="computedZwList[0].lastModifiedTime"
          :class="$style.reader"
          :filetype="computedZwList[0].suffix"
          :code="computedZwList[0].code"
        />
        <a-empty v-if="computedZwList.length === 0 && enablePreview" :class="$style.wpsEmpty" />
        <div
          v-for="{ list, label, id } in fileClasses.filter((item) => !enablePreview)"
          :key="id"
          class="ant-list ant-list-sm ant-list-split"
        >
          <div v-if="list.length" :class="$style.divider">{{ label }}</div>
          <sd-draggable
            v-if="list.length"
            tag="ul"
            class="ant-list-items"
            handle=".handle"
            :value="list"
            @input="(values) => resort(values, id)"
          >
            <FileListItem
              v-for="item in list"
              :key="item.code"
              :context="_self"
              :item="item"
              :busy="busy"
            />
          </sd-draggable>
        </div>
        <a-tabs
          v-if="
            enablePreview && (attachmentsList.find((item) => item.CatNum !== '-1') || _uploadable)
          "
          size="small"
          :class="$style.tab"
          @tabClick="showTab = true"
        >
          <a-tab-pane
            v-for="{ list, label, id } in fileClasses.filter(
              (item) => item.id !== '_inner' && item.list.length
            )"
            v-show="showTab || !computedZwList.length"
            :key="id"
            :tab="`${label}(${list.length})`"
          >
            <sd-draggable
              tag="ul"
              class="ant-list-items ant-list-sm"
              handle=".handle"
              :value="list"
              @input="(values) => resort(values, id)"
            >
              <FileListItem
                v-for="item in list"
                :key="item.code"
                :context="_self"
                :item="item"
                :busy="busy"
              />
            </sd-draggable>
          </a-tab-pane>

          <a-button
            v-if="versionVisiable"
            slot="tabBarExtraContent"
            icon="sd-desktop"
            type="link"
            title="本电脑相关信息"
            :class="$style.controlinfo"
            @click="showVersionInfo"
          />
          <UploadFj v-show="!formReadOnly" slot="tabBarExtraContent" :context="_self" />
          <PlDownload slot="tabBarExtraContent" :context="_self" />
          <a-button
            v-if="computedZwList.length"
            slot="tabBarExtraContent"
            type="link"
            :title="showTab ? '折叠附件列表' : '打开附件列表'"
            :icon="showTab ? 'up' : 'down'"
            @click="showTab = !showTab"
          />
        </a-tabs>
      </div>
    </portal>
    <SdAttachmentDisplay :enable-preview="enablePreview" :value="value" />
  </div>
</template>

<script>
import cubeServices from '@product/iam/cube/cube-services'
import loginService from '@/login/login-service'
import storeMixin from '@/common/store-mixin'
import axios from '@/common/services/axios-instance'
import { Modal, Message } from 'ant-design-vue'
import attrAccept from 'ant-design-vue/es/vc-upload/src/attr-accept'
import asyncComponent from '@/common/services/async-component'
import systemManage from '@/system-manage/system-manage'
import Vue from 'vue'
import pickValues from '@/common/services/pick-values'
import download from '@/common/services/download'
import sdAttachmentVue from '@/common/components/sd-attachment.vue'
import sdListPickerVue from '@/common/components/sd-list-picker.vue'
import SdAttachmentDisplay from '@/common/components/sd-form/sd-attachment-display.vue'
import { sdLocalStorage } from '@/common/services/storage-service'
import components from './_import-components/xm-attachment-ex-import'
window.fnGetFileLink = (code) => {
  return `${location.origin}${location.pathname}api/framework/v1/task-form-process/download-attachments/${code}`
}

const ActionButtons = {
  props: ['context', 'item'],
  render() {
    return (
      <div class={['ant-list-item-action', this.context.$style.actionbutton]}>
        {this.context.$scopedSlots.actions?.({
          item: this.item,
          waitUntil: (promise) => this.context.waitUntil(this.item, promise),
        })}
        {this.item.Completed && this.context.intelligentReview ? (
          <a-tooltip placement='top' title='智能核稿'>
            <a-button
              icon='sd-eye'
              type='link'
              vOn:click={() => this.context.reviewFile(this.item)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {this.item.Completed && this.item.replacable && !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='替换'>
            <a-upload
              class={this.context.$style.replacefj}
              accept={this.item.CatNum === '-1' ? this.context.acceptZwType : this.context.accept}
              custom-request={(file) => this.context.customRequestZw(file, this.item)}
              show-upload-list={false}
            >
              <a-button icon='retweet' type='link' />
            </a-upload>
          </a-tooltip>
        ) : (
          ''
        )}
        {this.context.onlineWordZw(this.item) &&
        this.context.cleanCopy &&
        !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='清稿'>
            <a-button
              icon='sd-eraser'
              type='link'
              vOn:click={() => this.context.QingGaoFile(this.item.FileName)}
            />
          </a-tooltip>
        ) : (
          ''
        )}

        {this.context.onlineWordZw(this.item) &&
        this.context.redHeader &&
        !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='套打'>
            <a-button
              icon='sd-tile'
              type='link'
              vOn:click={() => this.context.TaoDaFile(this.item.FileName)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {this.context.onlineWordZw(this.item) &&
        this.context.putSealOn &&
        !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='盖章'>
            <a-button
              icon='sd-stamp'
              type='link'
              vOn:click={() => this.context.GaiZhangFile(this.item.FileName)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {!this.sdPlatform.isXC &&
        this.context.onlineWordZw(this.item) &&
        this.context.changeFileFormat &&
        !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='转pdf'>
            <a-button
              icon='file-pdf'
              type='link'
              vOn:click={() => this.context.ConvertPDFFile(this.item.FileName)}
            />
          </a-tooltip>
        ) : (
          ''
        )}

        {this.sdPlatform.isXC &&
        this.context.onlineWordZw(this.item) &&
        this.context.changeFileFormat &&
        !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='转ofd'>
            <a-button
              icon='file-pdf'
              type='link'
              vOn:click={() => this.context.ConvertOFDFile(this.item.FileName)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {this.item.Completed && this.item.deletable && !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='删除'>
            <a-button
              icon='sd-trash2'
              type='link'
              vOn:click={() => this.context.DelFile(this.item)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {this.item.Completed && this.item.renamable && !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='重命名'>
            <a-button
              icon='sd-edit'
              type='link'
              vOn:click={() => this.context.ReName(this.item, true)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {this.context.webflow.FlowData &&
        this.context.webflow.FlowData.attrs['we-flow$attachmentRevert'] &&
        this.item.CatNum === '-4' &&
        !this.context.formReadOnly ? (
          <a-tooltip placement='top' title='还原正文'>
            <a-button
              icon='rollback'
              type='link'
              vOn:click={() => this.context.revertZw(this.item.FileName)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {this.item.Completed ? (
          <a-tooltip placement='top' title='下载'>
            <a-button
              icon='sd-download'
              type='link'
              vOn:click={() => this.context.SaveFile(this.item.FileName)}
            />
          </a-tooltip>
        ) : (
          ''
        )}
        {this.item.CatNum !== '-1' && this.context._sortable && !this.context.formReadOnly ? (
          <a-tooltip placement='right' title='拖拽排序'>
            <a class='handle ant-btn ant-btn-link ant-btn-icon-only' title={null}>
              <a-icon type='sd-swap' />
            </a>
          </a-tooltip>
        ) : (
          ''
        )}
      </div>
    )
  },
}

/**
 * 集成了indidoc和wps控件的组件
 * @displayName SdAttachmentEx 控件附件
 */
export default {
  name: 'XmAttachmentEx',
  components: {
    SdAttachmentDisplay,
    ...components,
    ActionButtons,
    UploadFj: {
      props: ['context'],
      render(h) {
        if (this.context.attachmentsList.length < this.context.max && this.context._uploadable) {
          const createFj =
            this.context.pluginName === 'WPSDOCX' ? (
              <a-button
                type={this.context.enablePreview ? 'link' : ''}
                icon='form'
                loading={this.context.createFjLoading}
                on={{
                  click: this.context.createFj,
                }}
              >
                在线新建附件
              </a-button>
            ) : (
              ''
            )
          return (
            <div class={this.context.$style.multiButton}>
              <a-upload
                multiple={this.context.max > 1}
                custom-request={(file) => this.context.customRequest(file, 0)}
                file-list={[]}
                accept={this.context.accept}
              >
                <a-button type={this.context.enablePreview ? 'link' : ''}>
                  <a-icon type='paper-clip' />
                  上传附件
                </a-button>
              </a-upload>
              {createFj}
            </div>
          )
        }
      },
    },
    PlDownload: {
      props: ['context'],
      render(h) {
        if (this.context.attachmentsList.length > 1) {
          return (
            <a-button
              type={this.context.enablePreview ? 'link' : ''}
              vOn:click={this.context.plsave}
            >
              <a-icon type='download' />
              批量下载
            </a-button>
          )
        }
      },
    },
    FileListItem: {
      props: ['context', 'item', 'busy'],
      components: {
        ActionButtons,
      },
      render() {
        return (
          <a-list-item class={[this.context.$style.list, this.context.$style.actionlist]}>
            {this.busy[this.item.FileName] ? (
              <a-spin size='small' class={this.context.$style.spin} />
            ) : (
              ''
            )}
            <span
              class={this.context.$style.label}
              vOn:click={() => this.context.OpenMyFile(this.item.FileName)}
            >
              {this.context.$scopedSlots['file-icon']?.({
                item: this.item,
              }) || (
                <a-icon
                  theme='filled'
                  type={this.context.getIcon(this.item.FileName)}
                  class={this.context.$style[this.context.getIcon(this.item.FileName)]}
                />
              )}
              {this.item.FileName} ({Vue.filter('sdBytesFormat')(this.item.size)})
              {!this.item.Completed && !['-3', '-4'].includes(this.item.CatNum) ? (
                <a-progress percent={90} show-info={false} size='small' status='active' />
              ) : (
                ''
              )}
            </span>
            <div class={[this.context.$style.rename, this.item.doReName ? '' : 'hide']}>
              <a-input
                vModel={this.context.newname}
                addon-after={this.context.getFileType(this.item.FileName)}
                max-length={parseInt(this.context.filenameMaxLength)}
              />
              <a-button vOn:click={() => this.context.ReName(this.item, false)}>取消</a-button>
              <a-button type='primary' vOn:click={() => this.context.UpdateName(this.item)}>
                确定
              </a-button>
            </div>
            <ActionButtons context={this.context} item={this.item} />
          </a-list-item>
        )
      },
    },
  },
  mixins: [storeMixin, sdAttachmentVue],
  props: {
    /**
     * 获取套打的公文域
     * 返回一个Promise.reject 或 throw new Error可中断套打
     */
    getTaodaValue: {
      type: Function,
      default: () => {},
    },
    /**
     * 获取套打的模板
     */
    getTemplateUrl: {
      type: Function,
      default: () => {},
    },
    /**
     * 获取印章
     */
    getSealUrl: {
      type: Function,
      default: () => {},
    },
    /**
     * @ignore
     */
    listType: {
      type: String,
      default: undefined,
    },
    /**
     * 是否允许清稿
     */
    cleanCopy: {
      type: [Boolean, String],
      default: false,
    },
    /**
     * 是否允许套打
     */
    redHeader: {
      type: [Boolean, String],
      default: false,
    },
    /**
     * 是否允许盖章
     */
    putSealOn: {
      type: [Boolean, String],
      default: false,
    },
    /**
     * 是否允许转版(pdf 或 ofd)
     */
    changeFileFormat: {
      type: [Boolean, String],
      default: false,
    },

    /**
     * 接收的正文类型
     */
    acceptZwType: {
      type: String,
      default: '.doc,.docx,.wps',
    },
    /**
     * 是否留痕
     *
     */
    trackChanges: {
      type: [Boolean, String],
      default: true,
    },
    /**
     * 启用正文一屏预览功能，前提是部署了wps预览服务，并且表单也启用了enablePreview，该参数生效
     * @since 8.0.10
     */
    enableAttachmentExTab: {
      type: Boolean,
      default: true,
    },
    /**
     * 通过控件打开附件时设置水印,第一个参数当前附件属性，第二个属性是当前的操作
     * EditFile表示打开文件操作,QingGao清稿,UpdateRegion套打(只更新域),TaoDa套打,GaiZhang盖章
     * @since 8.0.11
     */
    waterMark: {
      type: Function,
      default: systemManage.getAttachmentWaterMark,
    },
    /**
     * 指定使用的插件，默认预览服务启用WPS在线编辑时是wps中台，否则x86是indidoc,信创环境是wps加载项，可强制在x86环境指定使用wps加载项，不支持在信创环境使用indidoc
     * 参数值只可以设置 INDIDOCX 或者 WPS 或者 WPSDOCX 或者不传
     * @since 8.0.17
     */
    pluginName: {
      type: String,
      default: () => {
        const isXC = document.body.classList.contains('platform-xc')
        const previewCfg = JSON.parse(sdLocalStorage.getItem('commonConfig') || '{}').oaDocPreview
        let fdService, fdMode, isConfig
        if (isXC) {
          fdService = 'xcPreviewServiceType'
          fdMode = 'xcPreviewMode'
          isConfig = previewCfg.environment?.includes('XC')
        } else {
          fdService = 'previewServiceType'
          fdMode = 'previewMode'
          isConfig = previewCfg.environment?.includes('X86')
        }
        isConfig = isConfig && previewCfg[fdMode] === 'EMBED_SINGLE_SCREEN'
        // 启用了预览服务 且 预览服务选择了WPS在线编辑时，控件使用wps中台（WPSDOCX），否则 如是信创环境使用wps，否则使用indidocx
        return isConfig && previewCfg[fdService] === 'WPS_ONLINE_EDIT'
          ? 'WPSDOCX'
          : isXC
          ? 'WPS'
          : 'INDIDOCX'
      },
      validator: function(value) {
        if (['INDIDOCX', 'WPS', 'WPSDOCX'].includes(value)) {
          return true
        } else {
          // eslint-disable-next-line no-console
          console.error('插件名必须是INDIDOCX或WPS或WPSDOCX')
          return false
        }
      },
    },
    /**
     * 是否显示修订痕迹和批注等，true显示，false不显示
     * @since 0.17
     */
    showMark: {
      type: Boolean,
      default: true,
    },
    /**
     * 指定附件到某个分类
     * @since 0.20
     */
    getCategory: {
      type: Function,
      default: () => {},
    },
    /**
     * 扩展附件分类
     * @since 0.20
     */
    categories: {
      type: Array,
      default: () => [],
    },
    /**
     * 不支持的SdAttachment的prop，不显示在帮助文档中
     * @ignore
     */
    downloadBatch: {
      type: Boolean,
      default: false,
    },
    temtype: {
      type: String,
      default: '',
    },
    temdataurl: {
      type: String,
      default: '',
    },
    /**
     * 是否打开正文
     */
    isOpenFile: {
      type: Boolean,
      default: true,
    },
    /**
     * 自定义选择模板
     */
    customSelectTemplateFun: {
      type: Function,
    },
    // 显示上传附件按钮
    uploadfj: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      slCtl: {},
      attachments: [],
      init: -1, // -1加载中 0 失败 1 成功
      newname: '',
      visible: false,
      showTab: false,
      sdLocalStorage: sdLocalStorage,
      readerPlugin: '',
      pluginInstalled: -1,
      copyLoading: false,
      previewConfig: JSON.parse(sdLocalStorage.getItem('commonConfig') || '{}').oaDocPreview,
      defaultCategory: [
        {
          label: '正文',
          order: 100,
          id: '_inner',
        },
        {
          label: '附件',
          order: 200,
          id: 'fj',
        },
        {
          label: '痕迹',
          order: 300,
          id: 'hj',
        },
      ],
      busy: {},
      createZwLoading: false,
      createFjLoading: false,
      intelligentReview: this.webflow?.FlowData.attrs.audit$intelligentReview,
    }
  },
  inject: {
    attachValidate: { default: undefined },
    updateActivedAtt: { default: undefined },
    webflow: { default: () => ({}) },
  },
  computed: {
    fileClasses: {
      // 对文件分类
      get: function() {
        const classes = [...this.defaultCategory, ...this.categories].sort(
          (a, b) => a.order - b.order
        )
        classes.map((item) => {
          item.list = this.attachmentsList.filter(
            (file) => (this.getCategory(file) || this.getDefaultCategory(file)) === item.id
          )
        })
        return classes
      },
    },
    enablePreview() {
      let isConfig = false
      if (this.previewConfig) {
        if (!this.sdPlatform.isXC) {
          isConfig =
            this.previewConfig.environment?.includes('X86') &&
            this.previewConfig.previewMode === 'EMBED_SINGLE_SCREEN'
        } else {
          isConfig =
            this.previewConfig.environment?.includes('XC') &&
            this.previewConfig.xcPreviewMode === 'EMBED_SINGLE_SCREEN'
        }
      }
      return !!(
        isConfig &&
        this.webflow.FlowData &&
        (this.webflow.FlowData?.attrs.stepN !== 0 || this.webflow.FlowData?.attrs.isSubflow) &&
        this.enableAttachmentExTab
      )
    },
    versionVisiable() {
      // 有查看版本信息的api 且 (能上传正文 或 能上传附件 或 有附件)
      return (
        !!this.slCtl.Content?.Control?._getTerminalInfo &&
        (this._zwUploadable ||
          this._uploadable ||
          this.fileClasses.filter((item) => item.list.length > 0).length > 0)
      )
    },
  },
  watch: {
    'computedZwList.0.code': function() {
      // 只有一屏预览才会使用这里的控件
      if (
        ['.pdf', '.ofd'].includes(this.computedZwList?.[0]?.Type) &&
        this.sdPlatform.isXC &&
        this.previewConfig?.standardPreviewMode === 'NPAPI'
      ) {
        // pdf ofd用树科
        this.readerPlugin = asyncComponent(() =>
          import(
            /* webpackChunkName: "sd-suwell-reader" */ '@/common/components/sd-suwell-reader.vue'
          )
        )
      } else {
        // word用wps查看组件，支持napi或请阅读的方式
        this.readerPlugin = asyncComponent(() =>
          import(/* webpackChunkName: "sd-wps-reader" */ '@/common/components/sd-wps-reader.vue')
        )
      }
    },
  },
  created() {
    if (this.enablePreview) {
      this.inTab = this.webflow?.updateAttachmentExTabs?.(this.groupId, true)
    }
    if (this.sdPlatform.isXC && this.pluginName === 'INDIDOCX') {
      // eslint-disable-next-line no-console
      console.error('当前环境是信创环境，不能使用INDIDOCX插件')
    }
  },
  destroyed() {
    if (this.inTab) {
      this.webflow?.updateAttachmentExTabs?.(this.groupId, false)
    }
  },
  methods: {
    // 智能核稿功能
    reviewFile(item) {
      // 检查是否开启参数，或token是否过期
      cubeServices.checkCubeToken('sensitive').then((res) => {
        if (!res) {
          Modal.warning({
            title: '提示',
            content: '未开启CUBE集成功能参数或单点认证失败，请联系管理员',
          })
          return false
        }
        // 更新token，防止过期
        loginService.updateAccessToken().then(() => {
          // 开启了参数，且token正常
          const cubeJson = JSON.parse(sdLocalStorage.getItem('cube') || '{}')
          // 项目修改
          axios.get('api/xcoa-mobile/v1/iamcubecontract/getCubeWebUrl').then((res) => {
            if (res.data !== '') {
              let url =
                res.data +
                `/projects/8/xc-sensitive?file_path=${
                  location.origin
                }/api/framework/v1/task-form-process/download-attachments/${
                  item.code
                }?access_token=${loginService.getTokens().access_token}`
              url += `&access_token=${cubeJson.sensitive_token}`
              url += `&file_id=${item.code}`
              url += `&file_format=${item.suffix}`
              window.open(url)
            }
          })
        })
      })
    },
    resort(values, id) {
      let l = []
      this.fileClasses.forEach((item) => {
        l = l.concat(item.id === id ? values : item.list)
      })
      this.attachments = [
        ...l,
        ...this.attachments.filter((item) => {
          return !this.attachmentsList.find((att) => att.code === item.code)
        }),
      ]
      this.saveFilesSort()
    },
    getDefaultCategory(item) {
      if (item.CatNum + '' === '-1') {
        return '_inner'
      }
      if (['0', '-5', '-6'].includes(item.CatNum + '')) {
        return 'fj'
      }
      if (['-3', '-4'].includes(item.CatNum + '')) {
        return 'hj'
      }
    },
    waitUntil(item, promise) {
      this.markBusy(item.name)
      promise.then(() => {
        this.markBusy(item.name, false)
      })
    },
    onlineWordZw(item) {
      // 非版式文件的在线正文
      return (
        item.Completed &&
        item.CatNum === '-1' &&
        !item.FileName.endsWith('ofd') &&
        !item.FileName.endsWith('pdf')
      )
    },
    customRequestZw(data, item) {
      if (!item || item.CatNum === '-1') {
        if (!attrAccept(data.file, this.acceptZwType)) {
          Message.warn('不支持的文件类型，支持的文件类型有' + this.acceptZwType)
          return
        }
      }
      this.customRequest(data, item?.CatNum || -1, item || '')
    },
    pluginInfo() {
      const lock = sdLocalStorage.getItem(`Lock${this.webflow?.FlowData?.instId}`)
      const lockId = lock && JSON.parse(lock).sessionId
      let lockInfo = ''
      if (lockId) {
        lockInfo = `|lockId=${lockId}`
      }
      const UploadParam = Object.keys(this.infoProperties).map((key) => {
        return `${key}=${this.infoProperties[key] || ''}`
      })
      return {
        UserName: this.userInfo.name,
        UploadParam: `${UploadParam.join('|')}|creatorId=${
          this.userInfo.account
        }${lockInfo}|groupId=${this.groupId}`,
        UploadUrl: `${location.origin}${location.pathname}api/xcoa-mobile/v1/iam-attachment-extend/attachments-upload/indi`,
        ServerUpdateUrl: `${location.origin}${location.pathname}resource/update/{0}`,
        idxV6version: '',
        sid: 'test',
        refresh_token: `${location.origin}${location.pathname}api/refresh|${
          loginService.getTokens().refresh_token
        }`,
        getActivationUrl: `${location.origin}${location.pathname}api/framework/v1/dict-manager/dictvalues?keyId=INDIDOCX`,
        WPSPluginUrl: `${location.origin}${location.pathname}resource/jsplugindir/`,
      }
    },
    loadPlugin(name) {
      const data = this.initValue || this.getFileListFromField?.() || []
      data.forEach((item) => {
        item.FileName = item.name
        item.Completed = 1
        item.CatNum = item.catNum?.toString()
      })
      this.attachments = data
      this.init = 1
      let plugin
      switch (this.pluginName) {
        case 'WPSDOCX':
          plugin = import(/* webpackChunkName: "wpsdocc" */ '../../../lib-external/wpsDocX.js')
          break
        case 'WPS':
          plugin = import(/* webpackChunkName: "wps" */ '../../../lib-external/wps.js')
          break
        case 'INDIDOCX':
          plugin = import(/* webpackChunkName: "indidocx" */ '../../../lib-external/IndiDocX.js')
          break
        default:
          break
      }
      plugin.then((pluginName) => {
        this.slCtl = pluginName.default.createInstance().slCtl
        const template = (
          <div>
            <p>
              第一次使用请
              {!this.sdPlatform.isXC && this.pluginName !== 'WPS' ? (
                <a href='resource/IndiDocX8.0.exe' download='IndiDocX8.0.exe'>
                  安装indidocx控件
                </a>
              ) : (
                <a href='resource/jsplugindir/publish.html' target='_blank'>
                  安装wps控件
                </a>
              )}
            </p>
            <p>
              已安装控件，请尝试
              <a
                vOn:click_stop_prevent={() => {
                  this.initPlugin(true).then((val) => {
                    Modal.destroyAll()
                    Message.info({ content: `重新加载控件${val ? '成功' : '失败'}` })
                  })
                }}
              >
                重新加载控件
              </a>
            </p>
          </div>
        )
        const funs = [
          'EditFile',
          'QingGao',
          'UpdateRegion',
          'TaoDa',
          'GaiZhang',
          'DOCConvertToOFD',
          'SaveFileToLocal',
          'SaveMultiFiles',
          'DOCConvertToPDF',
        ]
        funs.forEach((fun) => {
          const oldfun = this.slCtl.Content.Control[fun]
          if (oldfun) {
            const that = this
            this.slCtl.Content.Control[fun] = function() {
              if (that.pluginInstalled !== 1) {
                Modal.warning({
                  title: '提示',
                  content:
                    that.pluginInstalled === 0
                      ? this.pluginName === 'WPSDOCX'
                        ? 'WPS中台初始化失败'
                        : template
                      : '控件正在加载中，请稍后重试',
                })
                that.attachments.forEach((item) => (item.busy = false)) // 不要busy状态
                that.attachments = [...that.attachments]
                return Promise.reject(new Error('未检测到控件'))
              }
              return oldfun.apply(this, arguments)
            }
          }
        })
        this.getFileList(true, true, true).then(() => {
          this.init = 1
        })
        this.initPlugin()
      })
    },
    initPlugin(flag = false) {
      return this.slCtl
        .checkInstall(this.pluginInfo(), flag)
        .then((val) => {
          if (val) {
            this.pluginInstalled = 1
          } else {
            this.pluginInstalled = 0
          }
          return this.pluginInstalled
        })
        .catch(() => {
          // eslint-disable-next-line no-console
          console.log(this.pluginName + '检测' + this.pluginInstalled)
          this.pluginInstalled = 0
          return this.pluginInstalled
        })
    },
    getFileList(noTriggerCheck = false, updateList = true, fromField = false) {
      let p = Promise.resolve(this.initValue)
      if (!fromField || !Array.isArray(this.initValue)) {
        p = axios
          .get(`api/framework/v1/attachment-extend/attachments-info-perm/${this.groupId}`, {
            params: this.infoProperties,
          })
          .then((res) => res.data)
      }
      return p.then((data) => {
        // 简单做下排序处理，正文 附件 痕迹文件等
        data.forEach((item) => {
          item.properties =
            item.properties + '<completed>1</completed><file_unid>' + item.code + '</file_unid>'
          if (
            item.properties.includes('<RedTemplate>1</RedTemplate>') ||
            item.properties.includes('<FromTemplate>1</FromTemplate>')
          ) {
            // 用filetype标记模板生成的红头文件
            item.properties = item.properties.replace(
              /<filetype>.*<\/filetype>/,
              '<filetype>RedTemplate</filetype>'
            )
          }
        })
        const zw = data.filter((item) => item.properties.includes('<CatNum>-1</CatNum>'))
        const fj = data.filter((item) => item.properties.includes('<CatNum>0</CatNum>'))
        const others = data.filter((item) => !item.properties.match(/<CatNum>(-1|0)<\/CatNum>/))
        data = [...zw, ...fj, ...others]
        this.slCtl.setFileList(data)
        const atts = JSON.parse(JSON.stringify(this.slCtl.Content.Files.FileList))
        atts.forEach((item) => {
          item.code = item.Unid
          item.name = item.FileName
          const file = data.find((i) => item.code === i.code) // 接口返回的附件列表，生成控件要的列表，带上原附件列表的一些属性
          item.querystring = file.properties
          // 兼容没有权限设置的情况，比如非流程表单
          item.deletable = !this.readOnly
          item.editable = !this.readOnly
          item.renamable = !this.readOnly
          item.replacable = !this.readOnly
          if (file.attr) {
            item.deletable = file.attr?.deletable
            item.editable = file.attr?.editable
            item.renamable = file.attr?.renamable
            item.replacable = file.attr?.replacable
          }
          Object.assign(item, file)
        })
        if (updateList) {
          // 如果是上传附件不直接拉列表更新，可能还有没上传玩的附件
          this.attachments = atts
          // 红头模板生成的正文给个标记
          const redtemplatecode = data.find((item) =>
            item.properties.includes('<RedTemplate>1</RedTemplate>')
          )?.code
          if (this.attachments.find((item) => item.Unid === redtemplatecode))
            this.attachments.find((item) => item.Unid === redtemplatecode).RedTemplate = 1
          this.$emit('input', this.attachments)
        } else {
          return atts
        }
        if (!noTriggerCheck && updateList) {
          // 不是第一次加载不触发校验
          this.filesChanged()
        }
      })
    },

    filesChanged() {
      this.$emit('change', this.attachments)
      this.attachValidate?.()
    },
    beforeUpload(event) {
      const zw = this.attachments.find((item) => item.CatNum + '' === '-1')
      if (zw) {
        Message.warn(`已存在正文《${zw.FileName}》`)
        event.preventDefault()
        event.stopPropagation()
      }
    },
    OpenMyFile(fname) {
      loginService.updateAccessToken().then(() => {
        // 因为打开ofd，确保每次打开accesstoken都是有效的
        const item = this.attachmentsList.find((item) => item.name === fname)
        if ((fname.endsWith('ofd') || fname.endsWith('pdf')) && this.sdPlatform.isXC) {
          window.open(
            `${this.$router.resolve('/sd-ofd-view').href}?url=${
              item.Link
            }&readonly=${!item.editable}&querystring=${item.querystring}&groupId=${
              this.groupId
            }&putSealOn=${this.putSealOn}`
          )
          return
        }
        this.markBusy(fname)
        this.updateActivedAtt?.(item.code, !!item.editable)
        this.slCtl.Content.Control.EditFile(
          fname,
          {
            Status: !item.editable ? 2 : this.trackChanges ? 0 : -1,
            AllowPrint: 'true',
            WaterMark: this.waterMark(item, 'EditFile'),
            UseMark: this.showMark.toString(),
          },
          this.pluginInfo()
        )
          .catch((e) => {
            if (e === 'FormatNotSupport') {
              // 不支持的文件，图片直接的打开，其他下载
              if (['jpg', 'png', 'jpeg', 'bmp', 'gif'].includes(item.suffix)) {
                axios({
                  url: `api/framework/v1/task-form-process/download-attachments/` + item.code,
                  responseType: 'blob',
                }).then((res) => {
                  window.open(URL.createObjectURL(res.data))
                })
              } else {
                this.SaveFile(fname)
              }
            }
          })
          .finally(() => {
            this.getFileList(false, false).then((atts) => {
              const index = this.attachments.findIndex((item) => item.catNum === '-1')
              if (index !== -1) {
                this.attachments[index] = atts.find((item) => item.catNum === '-1')
                this.attachments = [...this.attachments]
              }
            })
            this.markBusy(fname, false)
            this.updateActivedAtt?.(item.code, false)
          })
      })
    },
    QingGaoFile(fname, mode) {
      const item = this.attachmentsList.find((item) => item.name === fname)
      loginService.updateRefreshToken().then(() => {
        this.markBusy(fname)
        this.slCtl.Content.Control.QingGao(
          fname,
          { Status: '-1', DeleteNotation: 'true', WaterMark: this.waterMark(item, 'QingGao') },
          this.pluginInfo()
        )?.then(() => {
          this.markBusy(fname, false)
          this.getFileList()
        })
      })
    },
    TaoDaFile(fname) {
      const fnShowTaoDa = (fname) => {
        // 套打过走更新逻辑
        this.attachments = [...this.attachments]
        // var ModelUrl = `${location.origin}${location.pathname}wwwroot/file/红头模板.doc?fileName=红头模板.doc`
        var FileName = fname
        var userFile = this.slCtl.Content.Control.getFileByName(fname)
        if (
          (userFile.TaodaInfo !== '' && userFile.TaodaInfo !== null) ||
          userFile.FileType === 'RedTemplate'
        ) {
          // 只更新公文域
          loginService.updateRefreshToken().then(() => {
            this.markBusy(fname)
            Promise.resolve(this.getTaodaValue())
              .then((values) => {
                this.updateActivedAtt?.(userFile.code, true)
                this.slCtl.Content.Control.UpdateRegion(
                  FileName,
                  values,
                  '',
                  {
                    IsMaximization: this.isOpenFile ? 'true' : 'false',
                    Status: '-1',
                    WaterMark: this.waterMark(userFile, 'UpdateRegion'),
                  },
                  this.pluginInfo()
                )?.finally(() => {
                  this.updateActivedAtt?.(userFile.code, false)
                  this.getFileList()
                  this.markBusy(fname, false)
                })
              })
              .catch(() => {
                this.markBusy(fname, false)
              })
          })
        } else {
          this.getTemplateUrl().then((ModelUrl) => {
            loginService.updateRefreshToken().then(() => {
              this.markBusy(fname)
              Promise.resolve(this.getTaodaValue())
                .then((values) => {
                  this.updateActivedAtt?.(userFile.code, true)
                  this.slCtl.Content.Control.TaoDa(
                    ModelUrl,
                    '正文部分',
                    FileName,
                    { Status: '-1', WaterMark: this.waterMark(userFile, 'TaoDa') },
                    '',
                    values,
                    this.userInfo.name,
                    this.pluginInfo()
                  )?.finally(() => {
                    this.updateActivedAtt?.(userFile.code, false)
                    this.getFileList()
                    this.markBusy(fname, false)
                  })
                })
                .catch(() => {
                  this.markBusy(fname, false)
                })
            })
          })
        }
      }

      Modal.confirm({
        content: '请确认您是否已经做了清稿操作，如果没有，请您点击“取消”按钮返回，先清稿',
        onOk() {
          fnShowTaoDa(fname)
        },
        onCancel() {},
      })
    },
    GaiZhangFile(fname) {
      // 需要印章地址实现

      this.getSealUrl().then((ModelUrl) => {
        const item = this.attachmentsList.find((item) => item.name === fname)
        loginService.updateRefreshToken().then(() => {
          this.markBusy(fname)
          this.updateActivedAtt?.(item.code, true)
          this.slCtl.Content.Control.GaiZhang(
            ModelUrl,
            '印章',
            fname,
            { Status: '-1', WaterMark: this.waterMark(item, 'GaiZhang') },
            '',
            '',
            this.pluginInfo()
          )?.finally(() => {
            this.updateActivedAtt?.(item.code, false)
            this.getFileList()
            this.markBusy(fname, false)
          })
        })
      })
    },
    ConvertPDFFile(filename) {
      // 监听转换完成事件
      Modal.confirm({
        content: '是否将此附件转换为PDF格式？',
        onOk: () => {
          loginService.updateRefreshToken().then(() => {
            this.markBusy(filename)
            this.slCtl.Content.Control.DOCConvertToPDF(filename, {}, this.pluginInfo())?.then(
              () => {
                this.getFileList()
                this.markBusy(filename, false)
              }
            )
          })
        },
        onCancel() {},
      })
    },
    ConvertOFDFile(filename) {
      // 监听转换完成事件
      Modal.confirm({
        content: '是否将此附件转换为OFD格式？',
        onOk: () => {
          loginService.updateRefreshToken().then(() => {
            this.markBusy(filename)
            this.slCtl.Content.Control.DOCConvertToOFD(filename, {}, this.pluginInfo())?.then(
              () => {
                this.getFileList()
                this.markBusy(filename, false)
              }
            )
          })
        },
        onCancel() {},
      })
    },
    SaveFile(fname) {
      // 非INDIDOCX控件使用原生js下载
      if (this.pluginName !== 'INDIDOCX') {
        download(this.attachmentsList.find((item) => item.name === fname).Link, fname)
        return
      }

      loginService.updateRefreshToken().then(() => {
        const item = this.attachmentsList.find((item) => item.name === fname)
        this.markBusy(fname)
        this.slCtl.Content.Control.SaveFileToLocal(
          fname,
          {
            Status: Number(item.attr?.downloadstatus || -1),
          },
          this.pluginInfo()
        ).then((file) => {
          if (file?.fileinfo) {
            Message.success('下载成功')
          }
          this.markBusy(fname, false)
        })
      })
    },
    markBusy(fname, isBusy = true) {
      this.busy = { ...this.busy, [fname]: isBusy }
    },
    plsave() {
      let p
      if (this.attachmentsList.length <= 2) {
        p = Promise.resolve(this.attachmentsList)
      } else {
        // 弹框下载
        p = pickValues(sdListPickerVue, {
          optionValue: 'Unid',
          singleColumn: true,
          loadListData: () => this.attachmentsList,
          value: this.attachmentsList,
        })
      }
      p.then((attachs) => {
        if (attachs) {
          if (attachs.length === 0) {
            Message.warn('请选择需要下载的文件')
            return
          }
          loginService.updateRefreshToken().then(() => {
            const downMulti = this.slCtl?.Content?.Control?.SaveMultiFiles || undefined
            if (downMulti) {
              attachs.forEach((item) => this.markBusy(item.name))
              downMulti(
                attachs.map((item) => item.name).join('|'),
                { Status: Number(attachs[0].attr?.downloadstatus || -1) },
                this.pluginInfo()
              ).then((flag) => {
                if (flag && flag.fileinfo) {
                  Message.success('批量下载成功')
                }
                attachs.forEach((item) => this.markBusy(item.name, false))
              })
            } else {
              // 多附件打包下载
              const tmpArr = attachs[0].FileName.split('.')
              tmpArr.pop()
              const fileName = tmpArr.join('.')
              download(
                `api/framework/v1/attachment-extend/attachments-download/multi?groupId=${
                  this.groupId
                }&codes=${attachs.map((_) => _.code).toString()}`,
                `${fileName}等${attachs.length}个附件.zip`
              )
            }
          })
        }
      })
    },
    uploadByTemplateCode(code, catNum = '-1') {
      if (!this.temtype) {
        this.temdataurl = `api/xcoa-mobile/v1/redhead-manager/doctype/${this.businessTypeId}/redheads`
      }

      let p

      if (code) {
        p = Promise.resolve(code)
      } else {
        const businessTypeId = this.webflow?.FlowData.processFormData.processFormPropertyValues.find(
          (item) => item.name === 'businessTypeId'
        )?.value
        p = axios
          .get(`api/framework/v1/redhead-manager/doctype/${businessTypeId}/redheads`)
          .then((res) => {
            return pickValues(sdListPickerVue, {
              optionValue: 'attachment',
              optionLabel: 'redheadName',
              singleColumn: true,
              loadListData: () => res.data,
              single: true,
            }).then((data) => {
              if (data?.[0]?.attachment) {
                return axios
                  .get(
                    `api/framework/v1/attachment-extend/attachments-info-perm/${data?.[0]?.attachment}`
                  )
                  .then((res) => {
                    return res.data[0].code
                  })
              }
            })
          })
      }
      return p.then((code) => {
        if (code) {
          return axios({
            method: 'post',
            url: `api/framework/v1/attachment-extend/attachment-copy/${code}/${this.groupId}?catNum=${catNum}&fromTemplate=1`,
            params: this.infoProperties,
          })
        }
      })
    },
    revertZw(fname) {
      this.markBusy(fname)
      const lock = sdLocalStorage.getItem(`Lock${this.webflow?.FlowData?.instId}`)
      const lockId = lock && JSON.parse(lock).sessionId
      axios
        .get('api/framework/v1/redhead-manager/revokeReadHead', {
          params: {
            groupId: this.groupId,
            traceManuscriptCode: this.attachments.find((item) => item.CatNum === '-4').code,
            mainBodyCode: this.attachments.find((item) => item.CatNum === '-1').code,
            lockId,
            ...this.infoProperties,
          },
        })
        .then(this.getFileList)
        .finally(() => {
          this.markBusy(fname, false)
        })
    },
    // (新建)在线编辑正文
    createZw() {
      this.createZwLoading = true
      // 创建正文
      this.slCtl.Content.Control.createFile(this.groupId, {
        ...this.infoProperties,
        catNum: -1,
        environment: this.sdPlatform.isXC ? 'xc' : 'x86',
        type: 'docx',
      })
        .then((data) => {
          return this.getFileList().then(() => {
            // 打开编辑
            return this.editFileByUrl(data.fileName, data.url)
          })
        })
        .finally(() => {
          this.createZwLoading = false
        })
    },
    // (新建)在线编辑附件
    createFj() {
      this.createFjLoading = true
      // 创建附件
      this.slCtl.Content.Control.createFile(this.groupId, {
        ...this.infoProperties,
        catNum: 0,
        environment: this.sdPlatform.isXC ? 'xc' : 'x86',
        type: 'docx',
      })
        .then((data) => {
          return this.getFileList().then(() => {
            // 打开编辑
            return this.editFileByUrl(data.fileName, data.url)
          })
        })
        .finally(() => {
          this.createFjLoading = false
        })
    },
    editFileByUrl(fname, url) {
      const item = this.attachmentsList.find((item) => item.name === fname)
      this.markBusy(fname)
      this.updateActivedAtt?.(item.code, !!item.editable)
      return this.slCtl.Content.Control.EditFileByUrl(fname, url).finally(() => {
        this.markBusy(fname, false)
        this.updateActivedAtt?.(item.code, false)
      })
    },
    showVersionInfo() {
      this.slCtl.Content?.Control?._getTerminalInfo?.()
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
@import '@/common/components/sd-attachment.scss';
.attachmentextab {
  position: relative;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 180px);
  background: white;
}
.wps-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
}
.tab {
  top: 10px;
  height: auto;
  :global(.ant-tabs-bar) {
    height: 39px;
  }
  :global(.ant-tabs-extra-content) {
    > span {
      display: inline-block;
      margin-right: 10px;
    }
  }
  :global(.ant-tabs-top-content) {
    max-height: 175px;
    overflow-y: auto;
  }

  overflow: visible;
}
.buttons {
  padding: 6px 0;
  text-align: right;
}

:global(.hide) {
  display: none;
}
.reader {
  height: 100%;
}
.filename {
  float: left;
  &[disabled] {
    color: $text-color;
  }
}
.contain {
  position: relative;
  .controlinfor {
    position: absolute;
    top: 0;
    right: 0;
    z-index: -1;
    display: none;
    padding: 6px 0;
    opacity: 0;
  }
  .controlinfo {
    z-index: -1;
    opacity: 0;
  }
  &:hover {
    .controlinfor,
    .controlinfo {
      z-index: 1;
      opacity: 1;
      transition: all 1s ease 2s;
    }
  }
}
</style>
