<template>
  <el-drawer v-model="showDrawer" size="90%" :show-close="false" :close-on-press-escape="false"
    :close-on-click-modal="false">
    <template #header>
      <div class="flex justify-between items-center">
        <span class="text-lg">{{ props.title }}</span>
        <div>
          <el-button type="primary" style="width: 120px;" @click="handleFormSubmit">确 定</el-button>
          <el-button @click="handleFormClose">取 消</el-button>
        </div>
      </div>
    </template>
    <div v-loading="fullscreenLoading">
      <div class="gva-form-box">
        <div v-if="showErrMessage != ''">
          {{ showErrMessage }}
        </div>
        <el-form v-else ref="elEditFormRef" label-position="top" :model="editForm" :rules="formRules">
          <el-row :gutter="10">
            <el-col :span="17">
              <el-row :gutter="10">
                <el-col :span="24">
                  <el-form-item label="标题" prop="title">
                    <el-input v-model="editForm.title" autocomplete="off" :show-word-limit="true" maxlength="50" />
                  </el-form-item>
                </el-col>
                <el-col :span="16">
                  <el-form-item label="副标题" prop="subtitle">
                    <el-input v-model="editForm.subtitle" autocomplete="off" :show-word-limit="true" maxlength="50" />
                  </el-form-item>
                </el-col>
                <el-col :span="8">
                  <el-form-item label="文章类型" prop="articleType">
                    <el-select v-model="editForm.articleType" placeholder="请选择">
                      <el-option v-for="item in articleTypeOptions" :key="item.key" :label="item.label"
                        :value="item.key" />
                    </el-select>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="10">
                <el-col :span="12">
                  <el-form-item label="所属栏目" prop="channels">
                    <el-cascader v-model="channelIdList" :options="channelOptions" style="width:100%"
                      :props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
                      :collapse-tags="true" :collapse-tags-tooltip="true" :max-collapse-tags="3" filterable />
                  </el-form-item>
                </el-col>
                <el-col :span="12">
                  <el-form-item label="文章分类" prop="categories">
                    <el-cascader v-model="categoryIdList" :options="categoryOptions" style="width:100%"
                      :props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
                      :collapse-tags="true" :collapse-tags-tooltip="true" :max-collapse-tags="2" filterable />
                  </el-form-item>
                </el-col>
              </el-row>
              <el-form-item label="文章内容" prop="content">
                <div v-if="showDrawer">
                  <RichEdit v-model="editForm.content" media-category="article_content_imgs" style="height: 50rem;" />
                </div>
              </el-form-item>
            </el-col>
            <el-col :span="1" align="center">
              <el-divider direction="vertical" style="height: 100%" />
            </el-col>
            <el-col :span="6">
              <el-form-item label="摘要" prop="desc">
                <el-input v-model="editForm.desc" type="textarea" rows="7" :show-word-limit="true" maxlength="100"
                  autocomplete="off" resize="none" />
              </el-form-item>
              <el-form-item label="作者" prop="author">
                <el-input v-model="editForm.author" autocomplete="off" />
              </el-form-item>
              <el-form-item label="来源" prop="source">
                <el-select v-model="editForm.source" placeholder="请选择" allow-create clearable filterable>
                  <el-option v-for="item in sourceOptions" :key="item" :label="item" :value="item" />
                </el-select>
              </el-form-item>
              <el-form-item label="跳转链接" prop="url">
                <el-input v-model="editForm.url" autocomplete="off" placeholder="https://" clearable />
              </el-form-item>
              <el-form-item label="发布时间">
                <el-date-picker v-model="editForm.publishDate" type="datetime" placeholder="请选择" style="width:100%" />
              </el-form-item>
              <el-form-item label="文章标签" prop="tags">
                <div class="flex flex-wrap gap-2">
                  <el-tag v-for="(item, index) in tagList" :key="index" type="info" closable size="large"
                    @close="tagList.splice(index, 1)">
                    {{ item }}
                  </el-tag>
                  <el-select v-model="selectTag" filterable remote allow-create reserve-keyword placeholder="请输入"
                    :remote-method="loadRemoteTag" :loading="loadingTag" style="width: 100px" @change="handleSelectTag">
                    <el-option v-for="item in tagOptions" :key="item" :label="item" :value="item" />
                  </el-select>
                </div>
              </el-form-item>
              <el-form-item label="图片（首张图可用来做栏目列表用）" prop="imgs">
                <ChooseImg ref="chooseImg" category="article_imgs" size="800px" @on-select="handleSelectImg" />
                <template #label>
                  <div style="margin-bottom: 10px;">图片（首张图可用来做栏目列表用）</div>
                  <div class="flex gap-3">
                    <el-button type="success" plain icon="folder" @click="handleChooseImg">媒体库</el-button>
                    <upload-common class="upload-btn-media-library" category="article_imgs"
                      @on-success="handleImgUpload" />
                    <el-tooltip effect="dark" content="图片超过 512K 或者 长宽 > 1080 会自动压缩后再上传" placement="top-start">
                      <upload-image :file-size="512" :max-w-h="1080" category="article_imgs"
                        @on-success="handleImgUpload" />
                    </el-tooltip>
                  </div>
                </template>
                <div class="media">
                  <div v-for="(item, key) in imgFileList" :key="key" class="media-box">
                    <div class="img-box-list">
                      <el-image :key="key" :src="getUrl(item.url)" fit="cover" :preview-src-list="[getUrl(item.url)]"
                        hide-on-click-modal style="width: 138px; height: 138px;">
                        <template #error>
                          <div class="img-box-list">
                            <el-icon>
                              <picture />
                            </el-icon>
                          </div>
                        </template>
                      </el-image>
                    </div>
                    <div class="img-title">
                      <el-button size="small" type="default" icon="delete" @click="handleImgRemove(item)">删除</el-button>
                    </div>
                  </div>
                </div>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
      </div>
    </div>
  </el-drawer>
</template>

<script setup>
import { getUrl } from '@/utils/image'
import { reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import RichEdit from '@/components/richtext/rich-edit.vue'
import { getSourceList } from '@/api/source'
import { getCategoryTree } from '@/api/category'
import { getChannelTree } from '@/api/channel'
import { getTagList } from '@/api/tag'
import ChooseImg from '@/components/chooseImg/index.vue'
import UploadCommon from '@/components/upload/common.vue'
import UploadImage from '@/components/upload/image.vue'
import {
  addArticle,
  updateArticle,
  getArticleById,
} from '@/api/article'
import { importFetcherArticleById } from '@/api/fetcher'
import { isUrl } from '@/utils/validator'
import { articleTypeOptions } from '@/utils/options'

// 组件定义
defineOptions({
  name: 'ArticleEdit',
})
const emit = defineEmits(['on-save', 'on-close'])
const props = defineProps({
  title: { type: String, default: '' }
})

const showDrawer = ref(false)
const showErrMessage = ref('')
const fullscreenLoading = ref(true)
const isEdit = ref(false) // 确定是修改还是增加 isEdit = true 为修改，否则为增加
const fetcherArticleId = ref(0) // 记录从抓取库导入的文章id
const elEditFormRef = ref()
const checkCategories = (rule, value, callback) => {
  if (categoryIdList.value.length === 0) {
    callback(new Error(rule.message))
  } else {
    callback()
  }
}
const checkChannels = (rule, value, callback) => {
  if (channelIdList.value.length === 0) {
    callback(new Error(rule.message))
  } else {
    callback()
  }
}
const formRules = reactive({
  articleType: [
    { required: true, message: '请输选择文章类型', trigger: 'blur' }
  ],
  title: [
    { required: true, message: '请输入文章名称', trigger: 'blur' }
  ],
  subtitle: [
    { required: true, message: '请输入文章副标题', trigger: 'blur' }
  ],
  categories: [
    { validator: checkCategories, message: '请选择文章分类', trigger: 'blur' }
  ],
  channels: [
    { validator: checkChannels, message: '请选择所属栏目', trigger: 'blur' }
  ],
  content: [
    { required: true, message: '请输入文章内容', trigger: 'blur' }
  ],
  url: [
    { validator: isUrl, message: '请输入正确的跳转地址', trigger: 'blur' }
  ]
})

const editForm = ref({
  ID: 0,
  articleType: '',
  title: '',
  subtitle: '',
  author: '',
  channels: [],
  categories: [],
  desc: '',
  source: '',
  url: '',
  publishDate: '',
  articleTime: '',
  tags: '',
  imgs: '',
})
// options 相关
const initOptions = (data, optionsData) => {
  data &&
    data.forEach(item => {
      if (item.children && item.children.length) {
        const option = {
          title: item.title,
          ID: String(item.ID),
          children: []
        }
        initOptions(
          item.children,
          option.children,
        )
        optionsData.push(option)
      } else {
        const option = {
          title: item.title,
          ID: String(item.ID),
        }
        optionsData.push(option)
      }
    })
}

// 以下为 options 使用
const channelOptions = ref([])
const categoryOptions = ref([])
const sourceOptions = ref([])

const getCategoryData = async () => {
  categoryOptions.value = []
  const res = await getCategoryTree()
  if (res.code === 0) {
    initOptions(res.data.categoryTree, categoryOptions.value, false)
  }
}
const getChannelData = async () => {
  channelOptions.value = []
  const res = await getChannelTree()
  if (res.code === 0) {
    initOptions(res.data.channelTree, channelOptions.value, false)
  }
}
const getSourceData = async () => {
  sourceOptions.value = []
  const res = await getSourceList({ page: 1, pageSize: 999 })
  if (res.code === 0) {
    sourceOptions.value = res.data.list && res.data.list.map(item => item.name)
  }
}

const emptyForm = () => {
  channelIdList.value = []
  categoryIdList.value = []
  imgFileList.value = []
  tagList.value = []
  editForm.value = {
    ID: 0,
    articleType: '',
    title: '',
    subtitle: '',
    author: '',
    channels: [],
    categories: [],
    desc: '',
    source: '',
    url: '',
    publishDate: '',
    articleTime: '',
    tags: '',
    imgs: '',
  }
}

// 初始化方法
const openPage = async (params) => {
  showDrawer.value = true
  isEdit.value = false

  emptyForm()
  getCategoryData()
  getChannelData()
  getSourceData()

  // 建议通过url传参获取目标数据ID 调用 find方法进行查询数据操作 从而决定本页面是create还是update 以下为id作为url参数示例
  if (params.articleId && params.articleId > 0) {
    // 从文章库编辑
    isEdit.value = true
    initFormByArticle(params.articleId)
  } else if (params.fetcherId && params.fetcherId > 0) {
    // 从爬虫库导入
    initFormByFetcher(params.fetcherId)
  } else {
    // 新建
    fullscreenLoading.value = false
  }
}

const initFormByArticle = async (id) => {
  const res = await getArticleById({ ID: id })
  if (res.code === 0) {
    // 初始化表单数据
    editForm.value = res.data.article
    // 初始化关联数据
    const { categories, channels, imgs, tags } = res.data.article
    categoryIdList.value = categories && categories.map(item => String(item.ID))
    channelIdList.value = channels && channels.map(item => String(item.ID))
    if (imgs && (imgs !== '')) {
      imgFileList.value = JSON.parse(imgs)
    }
    if (tags !== '') {
      tagList.value = tags.split(',')
    }
    fullscreenLoading.value = false
  } else {
    ElMessage({
      type: 'error',
      message: '获取数据失败'
    })
    showErrMessage.value = '获取数据失败'
  }
  fullscreenLoading.value = false
}

// 从爬虫数据中获取内容并填充至文章内容中
const initFormByFetcher = async (id) => {
  const res = await importFetcherArticleById({ ID: id })
  if (res.code === 0 && res.data && res.data.article) {
    fetcherArticleId.value = id
    const { title, author, source, content, publicTime } = res.data.article
    editForm.value.title = title
    editForm.value.subtitle = title
    editForm.value.author = author
    editForm.value.source = source
    editForm.value.content = content
    editForm.value.publishDate = publicTime
    editForm.value.articleTime = publicTime
    editForm.value.articleType = 1
  } else {
    ElMessage({
      type: 'error',
      message: '获取数据失败'
    })
    showErrMessage.value = '获取数据失败'
  }
  fullscreenLoading.value = false
}

// ----  以下为图片相关操作  ----
const chooseImg = ref(null)
const imgFileList = ref([])
const handleChooseImg = () => {
  chooseImg.value.open()
  return false
}
const handleSelectImg = (file) => {
  imgFileList.value.push({
    key: file.key,
    name: file.name,
    url: file.url,
  })
}
const handleImgRemove = (file) => {
  imgFileList.value = imgFileList.value.filter(item => item.key !== file.key)
}
const handleImgUpload = (file) => {
  imgFileList.value.push({
    key: file.key,
    name: file.name,
    url: file.url,
  })
}

// ----  以下为tag相关操作  ----
const tagInputFlag = ref(false)
const selectTag = ref('')
const tagList = ref([])
const tagOptions = ref([])
const loadingTag = ref(false)
const loadRemoteTag = (query) => {
  if (query) {
    loadingTag.value = true
    setTimeout(async () => {
      const res = await getTagList({ page: 1, pageSize: 30, keyword: query })
      if (res.code === 0) {
        tagOptions.value = res.data.list.map(item => item.name)
      }
      loadingTag.value = false
    }, 200)
  } else {
    tagOptions.value = []
  }
}
const handleSelectTag = (val) => {
  if (!tagList.value.includes(val)) {
    tagList.value.push(val)
  }
  tagInputFlag.value = false
  selectTag.value = ''
}
const categoryIdList = ref([])
const channelIdList = ref([])

// 添加/保存修改
const handleFormSubmit = async valid => {
  if (editForm.value.publishDate === '') {
    editForm.value.publishDate = null
  }
  if (editForm.value.articleTime === '') {
    editForm.value.articleTime = null
  }
  elEditFormRef.value.validate(async valid => {
    if (!valid) {
      return
    }
    const rel = {
      categoryIds: categoryIdList.value.map(item => parseInt(item, 10)),
      channelIds: channelIdList.value.map(item => parseInt(item, 10)),
      imgList: imgFileList.value,
      tagList: tagList.value,
      fetcherArticleId: fetcherArticleId.value
    }
    let res
    if (isEdit.value) {
      res = await updateArticle({ article: editForm.value, rel: rel })
    } else {
      res = await addArticle({ article: editForm.value, rel: rel })
    }
    if (res.code === 0) {
      ElMessage({
        type: 'success',
        message: isEdit.value ? '修改成功' : '添加成功!'
      })
      showDrawer.value = false
      emit('on-save')
    }
  })
}

// 返回按钮
const handleFormClose = () => {
  showDrawer.value = false
  emit('on-close')
}

// 对外暴露方法
defineExpose({ openPage })
</script>

<style type="scss">
.admin-box .el-table td .cell {
  line-height: 28px;
}

.text-truncate .cell {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
}

.img-item {
  width: 90px;
  height: 90px;
}
</style>
