<template>
  <div>
    <a-spin :spinning="loading">
      <a-collapse v-if="listData.length > 0" v-model="activeKey">
        <a-collapse-panel v-for="category in listData" :key="category.id">
          <template v-slot:header> {{ category.name }}({{ category.data.length }}) </template>
          <a-list
            :grid="{ gutter: 16, column: 4 }"
            :data-source="category.data"
            :class="$style.listclass"
          >
            <a-list-item
              slot="renderItem"
              key="item.title"
              slot-scope="item"
              :class="$style.cardcontent"
              @click="clickCard(item)"
            >
              <a-card :class="$style.editclass" hoverable>
                <div :class="appStateInfo(item).class">{{ appStateInfo(item).text }}</div>
                <template slot="actions" class="ant-card-actions">
                  <!-- 按钮最多显示4个，如需显示的按钮超过4个，则第4个开始显示在更多按钮中 -->
                  <a-icon
                    v-for="btn in getCommonButtons(item)"
                    :key="btn.type"
                    :type="btn.iconType"
                    :class="$style.iconBotton"
                    :title="btn.title"
                    @click.stop="btnClick(btn, item)"
                  />
                  <a-dropdown v-if="getMoreButtons(item).length > 0">
                    <a-icon type="ellipsis" title="更多" :class="$style.iconBotton" @click.stop />
                    <a-menu slot="overlay">
                      <a-menu-item
                        v-for="btn in getMoreButtons(item)"
                        :key="btn.type"
                        @click="btnClick(btn, item)"
                        >{{ btn.title }}</a-menu-item
                      >
                    </a-menu>
                  </a-dropdown>
                </template>
                <a-card-meta>
                  <h4 slot="title" :class="$style.appnameclass">{{ item.appName }}</h4>
                  <template slot="description">
                    <div :class="$style.desccontainer" :style="descStyle">{{
                      item.appDesc ? item.appDesc : '无描述'
                    }}</div>
                  </template>
                  <sd-icon
                    slot="avatar"
                    :type="item && item.iconObj && item.iconObj.name"
                    :theme="item && item.iconObj && item.iconObj.theme"
                    :class="$style.avatarclass"
                    :style="'color:' + item.iconColor"
                  />
                </a-card-meta>
              </a-card>
            </a-list-item>
          </a-list>
        </a-collapse-panel>
      </a-collapse>
      <a-empty v-else />
    </a-spin>

    <!-- 编辑应用信息 -->
    <sd-detail-modal
      ref="appDetail"
      :record-id="appId"
      :page-id="pageId"
      :modal-props="{ width: 800 }"
      @saved="appSaved"
    >
      <sd-application-info-form slot-scope="scope" v-bind="scope" :application-type="listType" />
    </sd-detail-modal>
  </div>
</template>

<script>
import { Message, Modal } from 'ant-design-vue'
import download from '@/common/services/download'
import PageService from '@/common/services/page-service'
import ApplicationService from './application-service'
import components from './_import-components/sd-application-list-import'

const STATE_PUBLISH = '已发布'
const STATE_STOP = '暂停'
const STATE_NOPUBLISH = '未发布'

export default {
  name: 'SdApplicationList',
  components,
  props: {
    listType: {
      type: String,
      default: 'all',
    },
    filterExpressions: {
      type: Array,
      default: () => [],
    },
    formId: {
      type: String,
      default: 'weApp',
    },
  },
  data() {
    return {
      appId: null,
      newApp: {
        id: '',
      },
      listData: [],
      descStyle: {
        display: '-webkit-box',
        '-webkit-box-orient': 'vertical',
        '-webkit-line-clamp': 3,
        overflow: 'hidden',
      },
      actTotal: 0,
      maxActionBtns: 4,
      activeKey: [],
      loading: false,
    }
  },
  computed: {
    pageId() {
      return `app/${this.formId === 'weAppNode' ? 'appnode' : 'app'}/${this.formId}`
    },
  },
  watch: {
    filterExpressions() {
      this.queryAppList()
    },
  },
  created() {
    this.queryAppList(true)
  },
  methods: {
    appStateInfo(app) {
      const stateInfo = {
        text: app.status,
      }
      switch (app.status) {
        case STATE_PUBLISH:
          stateInfo.class = this.$style.publishstate
          break
        case STATE_STOP:
          stateInfo.class = this.$style.stopstate
          break
        case STATE_NOPUBLISH:
          stateInfo.class = this.$style.nopublishstate
          break
      }
      return stateInfo
    },
    appSaved(data) {
      this.queryAppList()
    },
    queryAppList(initd) {
      const paramsCate = {
        columns: 'id,name',
        orderBy: 'sortNumber asc',
        formId: 'weAppGroup',
        maxResults: -1,
        startPosition: 0,
      }
      const params = {
        columns:
          'id,creationTime,appName,appDesc,iconCode,status,appGroupId,appGroupName,origAppId',
        orderBy: 'creationTime desc',
        formId: this.formId,
        maxResults: -1,
        startPosition: 0,
        expressions: this.filterExpressions,
      }
      var colorArr = ['#65CCC9', '#86D076', '#DECD60', '#E69D6A', '#E5736F', '#5BA7EF']
      this.loading = true
      Promise.all([PageService.getList(paramsCate), PageService.getList(params)])
        .then((items) => {
          // 应用分类（分类按排序号升序）
          const formatData = items[0].data.data.map((item) => ({
            id: item.id,
            name: item.name,
            data: [],
          }))
          // 未分类显示在最前面
          formatData.unshift({ id: '_null', name: '未分类', data: [] })
          // 将应用按分类归类
          items[1].data.data
            .map((data, index) => {
              data.iconObj = JSON.parse(data.iconCode)
              data.iconColor = colorArr[index % colorArr.length]
              return data
            })
            .forEach((item) => {
              const id = item.appGroupId || '_null'
              formatData.find((d) => d.id === id)?.data.push(item)
            })
          // 过滤掉应用为空的分类
          this.listData = formatData.filter((d) => d.data.length > 0)
          // 默认分类都展开
          if (initd) {
            this.activeKey = this.listData.map((d) => d.id)
          }
        })
        .finally(() => {
          this.loading = false
        })
    },
    clickCard(item) {
      // 下放应用取origAppId
      const query = {
        appId: item.origAppId || item.id,
        appName: item.appName,
      }
      if (item.origAppId) {
        query.appNodeId = item.id
      }
      this.$router.push({ path: 'sd-application-manage', query })
    },
    editApp(item) {
      this.appId = item.id
      this.$refs.appDetail.show()
    },
    delApp(item, type) {
      const params = {
        ids: item.id,
      }
      Modal.confirm({
        title: '您确定删除该应用吗？',
        content:
          '删除后此应用下的所有表单、流程、导航等配置及业务数据将会被一并删除，此操作不可逆！',
        okText: '删除',
        okType: 'danger',
        onOk: () => {
          const key = 'releaseApp'
          const loadingMsg = Message.loading({
            content: `正在删除【${item.appName}】`,
            key,
            duration: 0,
          })
          PageService.delete(params, this.formId)
            .then((res) => {
              Message.success({ content: '删除应用成功', key })
              this.queryAppList()
              this.$emit('appDeleted')
            })
            .catch((e) => {
              loadingMsg()
              throw e
            })
        },
      })
    },
    releaseApp(item, type) {
      let status, text
      if (type === 'publish') {
        text = '发布'
        status = 1
      } else {
        text = '暂停'
        status = 2
      }
      const params = {
        id: item.id,
        status,
      }
      Modal.confirm({
        title: `您确定${text}该应用吗？`,
        content:
          '此操作会清空所有用户的导航缓存，导致所有用户导航要重新生成一次，导航生成时间可能会较长',
        okText: text,
        okType: type === 'stop' ? 'danger' : '',
        onOk: () => {
          const key = 'releaseApp'
          const loadingMsg = Message.loading({
            content: `正在${text}【${item.appName}】，请稍候...`,
            key,
            duration: 0,
          })
          ApplicationService.releaseApp(params, this.listType)
            .then((res) => {
              if (res.status === 200) {
                Message.success({ content: `${text}成功`, key })
                // 启用/停用 完成后刷新当前页面（导航菜单会更新）
                window.location.reload()
              }
            })
            .catch((e) => {
              loadingMsg()
              throw e
            })
        },
      })
    },
    refresh() {
      this.queryAppList()
    },
    appExport(item) {
      download(`api/framework/v1/we-app/export?appId=${item.id}`, `${item.appName}.gz`, true)
    },
    getButtons(item) {
      const btns = []
      if (item) {
        // 编辑
        btns.push({ type: 'edit', title: '编辑', iconType: 'edit' })
        // 已发布/停用
        if (item.status === STATE_PUBLISH) {
          btns.push({ type: 'stop', title: '暂停', iconType: 'stop' })
        } else {
          btns.push({ type: 'publish', title: '发布', iconType: 'check-circle' })
        }
        if (this.listType === 'share') {
          return btns
        }
        // 应用导出
        btns.push({ type: 'app-export', title: '应用导出', iconType: 'upload' })
        // 应用未发布
        if (item.status !== STATE_PUBLISH) {
          // 删除
          btns.push({ type: 'delete', title: '删除', iconType: 'delete' })
        }
      }
      return btns
    },
    getCommonButtons(item) {
      const buttons = this.getButtons(item)
      if (buttons.length > this.maxActionBtns) {
        return buttons.splice(0, this.maxActionBtns - 1)
      }
      return buttons
    },
    getMoreButtons(item) {
      const buttons = this.getButtons(item)
      if (buttons.length > this.maxActionBtns) {
        buttons.splice(0, this.maxActionBtns - 1)
        return buttons
      }
      return []
    },
    btnClick(btn, item) {
      switch (btn.type) {
        case 'delete':
          this.delApp(item, btn.type)
          break
        case 'edit':
          this.editApp(item)
          break
        case 'publish':
        case 'stop':
          this.releaseApp(item, btn.type)
          break
        case 'app-export':
          this.appExport(item)
          break
        default:
          break
      }
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
%app-state {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 0 8px;
  font-size: $font-size-base * 0.75;
  border: 1px solid;
  border-radius: 4px;
}
.nopublishstate {
  @extend %app-state;

  color: $normal-color;
  border-color: $normal-color;
}
.publishstate {
  @extend %app-state;

  color: $success-color;
  border-color: $success-color;
}
.stopstate {
  @extend %app-state;

  color: $error-color;
  border-color: $error-color;
}
.avatarclass {
  font-size: $font-size-base * 3;
}
.cardcontent {
  cursor: pointer;
  :global(.ant-card-meta-avatar) {
    float: none;
    width: 64px;
    padding: 8px;
    border: 1px solid #e8e8e8;
    border-radius: 10px;
    box-shadow: 0 0 10px rgb(0 0 0 / 9%);
  }
  :global(.ant-card-meta-title) {
    position: absolute;
    top: 25px;
    left: 96px;
    max-width: calc(100% - 115px);
  }
  :global(.ant-card-meta-description) {
    margin-top: 12px;
    font-size: $font-size-base * 0.9;
  }
}
.cardcontent .icon-botton {
  float: right;
  margin-left: 6px;
}
.cardclass {
  height: 222px;
  border: 0;
}
.createplusclass {
  position: relative;
  margin-top: 55px;
  color: $link-color;
  text-align: center;
}
.plusicondiv {
  position: relative;
  left: calc((100% - 50px) / 2);
  width: 50px;
  height: 50px;
  margin-bottom: 6px;
  border-style: dashed;
  border-width: 1px;
  border-radius: 50%;
}
.pulusclass {
  position: relative;
  top: calc((100% - 24px) / 2);
}
.appnameclass {
  margin-top: 10px;
  overflow: hidden;
  line-height: $font-size-base * 1.5;
  text-overflow: ellipsis;
}
.listclass {
  :global(.ant-spin-container .ant-row) {
    display: flex;
    flex-wrap: wrap;
  }
  :global(.ant-col > .ant-list-item) {
    border: 1px solid #e8e8e8;
  }
}
.editclass {
  :global(.ant-card-body) {
    height: 175px;
    padding: 20px;
    .listitemclass {
      position: relative;
      height: 100%;
    }
  }
}
</style>
