<template>
  <n-drawer
    class="top0"
    to="#main"
    :show="show"
    width="5.2rem"
    :mask-closable="false"
  >
    <n-drawer-content>
      <template #header>
        <div class="head">
          <p>{{ mode ? basicData.name : '新增活动' }}</p>
          <n-space>
            <n-button size="small" @click="closeDrawer">取消</n-button>
            <template v-if="mode === 'view'">
              <n-button type="error" size="small" @click="mode = 'modify'">
                编辑
              </n-button>
              <n-button type="primary" size="small" @click="handleExport">
                <template #icon>
                  <n-icon size=".12rem">
                    <svg-icon :data="exportIcon" original />
                  </n-icon>
                </template>
                导出
              </n-button>
            </template>
            <n-button v-else type="primary" size="small" @click="submit">
              完成
            </n-button>
          </n-space>
        </div>
      </template>
      <div class="content" :class="{ 'view-mode': mode === 'view' }">
        <div>
          <p class="title">基本信息</p>
          <n-form
            ref="basicRef"
            :model="basicData"
            :rules="rules"
            size="small"
            label-placement="top"
          >
            <n-grid :cols="24" :x-gap="12">
              <n-form-item-gi :span="12" label="活动名称" path="name">
                <p v-if="mode === 'view'">{{ basicData.name }}</p>
                <n-input v-else v-model:value="basicData.name" />
              </n-form-item-gi>
              <n-form-item-gi :span="12" label="标签类别" path="type">
                <p v-if="mode === 'view'">
                  {{
                    typeOptions.find((e) => e.value === basicData.type)?.label
                  }}
                </p>
                <n-select
                  v-else
                  v-model:value="basicData.type"
                  :options="typeOptions"
                />
              </n-form-item-gi>
              <n-form-item-gi
                :span="24"
                :label="`党组织名称${
                  mode === 'view' ? '' : '（下拉或输入关键字选择）'
                }`"
                path="orgName"
              >
                <p v-if="mode === 'view'">
                  {{
                    orgOptions.find((e) => e.value === basicData.orgName)?.label
                  }}
                </p>
                <n-select
                  v-else
                  v-model:value="basicData.orgName"
                  :options="orgOptions"
                  filterable
                />
              </n-form-item-gi>
              <n-form-item-gi :span="12" label="活动日期" path="date">
                <p v-if="mode === 'view'">
                  {{ dayjs(basicData.date).format('ll') }}
                </p>
                <n-date-picker
                  v-else
                  v-model:value="basicData.date"
                  style="width: 100%"
                />
              </n-form-item-gi>
              <n-form-item-gi
                :span="24"
                :label="`活动地址${
                  mode === 'view'
                    ? ''
                    : '（请具体填写，如“XX区XX路XX号XX中心”）'
                }`"
                path="address"
              >
                <p v-if="mode === 'view'">{{ basicData.address }}</p>
                <n-input v-else v-model:value="basicData.address" />
              </n-form-item-gi>
            </n-grid>
          </n-form>
        </div>
        <div>
          <p class="title">
            人员参与情况
            <span>
              党员总数：
              <span>{{ totalPerson }}人</span>
            </span>
          </p>
          <n-form
            ref="memberRef"
            :model="memberData"
            :rules="rules"
            size="small"
            label-placement="top"
          >
            <n-grid :cols="24" :x-gap="12">
              <n-form-item-gi :span="12" label="实际参与人数" path="count">
                <p v-if="mode === 'view'">{{ memberData.count }}人</p>
                <n-input-number
                  v-else
                  v-model:value="memberData.count"
                  size="small"
                  :show-button="false"
                  :validator="checkMemberCount"
                >
                  <template #suffix>人</template>
                </n-input-number>
              </n-form-item-gi>
              <n-form-item-gi
                :span="12"
                label="不计入参与活动党员人数"
                path="excludeCount"
              >
                <p v-if="mode === 'view'">{{ memberData.excludeCount }}人</p>
                <n-input-number
                  v-else
                  v-model:value="memberData.excludeCount"
                  size="small"
                  :show-button="false"
                  :validator="checkMemberCount"
                >
                  <template #suffix>人</template>
                </n-input-number>
              </n-form-item-gi>
              <n-form-item-gi
                :span="24"
                :label="`电子表格或签到照片${
                  mode === 'view' ? '' : '（大小20M以内）'
                }`"
                path="fileType"
              >
                <n-select
                  v-if="mode !== 'view'"
                  v-model:value="memberData.fileType"
                  :options="fileOptions"
                  placeholder="请选择上传类型"
                />
              </n-form-item-gi>
              <n-form-item-gi
                v-if="memberData.fileType === 'file'"
                :span="24"
                path="attachment"
                class="no-label"
                :style="mode === 'view' ? 'margin-top:-0.9rem' : null"
              >
                <n-upload
                  :default-file-list="memberData.attachment || []"
                  style="width: 100%"
                  accept=".docx,.doc,.xlsx,.xls,.csv,.txt"
                  :on-change="(e) => onFileChange(e, 'memberData.attachment')"
                  :show-remove-button="mode !== 'view'"
                  @before-upload="beforeUpload"
                >
                  <n-button v-if="mode !== 'view'"> 上传附件 </n-button>
                </n-upload>
              </n-form-item-gi>
              <n-form-item-gi
                v-if="memberData.fileType === 'photo'"
                :span="24"
                path="attachmentPhoto"
                class="no-label"
                :style="mode === 'view' ? 'margin-top:-0.6rem' : null"
              >
                <n-upload
                  style="width: 100%"
                  :default-file-list="memberData.attachmentPhoto || []"
                  accept="image/jpg,image/jpeg,image/png,image/img"
                  list-type="image-card"
                  :show-remove-button="mode !== 'view'"
                  :on-change="
                    (e) => onFileChange(e, 'memberData.attachmentPhoto')
                  "
                  @before-upload="beforeUpload"
                  @preview="handlePreview"
                >
                  点击上传
                </n-upload>
              </n-form-item-gi>
            </n-grid>
          </n-form>
        </div>
        <div>
          <p class="title">活动详情</p>
          <n-form
            ref="detailRef"
            :model="detailData"
            :rules="rules"
            size="small"
            label-placement="top"
          >
            <n-grid :cols="24" :x-gap="12">
              <n-form-item-gi
                :span="24"
                :label="`活动内容描述或描述照片${
                  mode === 'view' ? '' : '（大小20M以内）'
                }`"
                path="describeType"
              >
                <template v-if="mode === 'view'">
                  <p v-if="detailData.describeType === 'text'">
                    {{ detailData.attachment }}
                  </p>
                </template>
                <n-select
                  v-else
                  v-model:value="detailData.describeType"
                  :options="describeOptions"
                  placeholder="请选择上传类型"
                />
              </n-form-item-gi>
              <n-form-item-gi
                v-if="detailData.describeType === 'text' && mode !== 'view'"
                :span="24"
                path="attachment"
                class="no-label"
              >
                <n-input
                  v-model:value="detailData.attachment"
                  type="textarea"
                />
              </n-form-item-gi>
              <n-form-item-gi
                v-if="detailData.describeType === 'photo'"
                :span="24"
                path="attachmentPhoto"
                class="no-label"
              >
                <n-upload
                  style="width: 100%"
                  :default-file-list="detailData.attachmentPhoto || []"
                  accept="image/jpg,image/jpeg,image/png,image/img"
                  list-type="image-card"
                  :show-remove-button="mode !== 'view'"
                  :on-change="
                    (e) => onFileChange(e, 'detailData.attachmentPhoto')
                  "
                  @before-upload="beforeUpload"
                  @preview="handlePreview"
                >
                  点击上传
                </n-upload>
              </n-form-item-gi>
              <n-form-item-gi
                :span="24"
                :label="`活动照片${
                  mode === 'view'
                    ? ''
                    : '（格式为jpg、jpeg、png、img， 大小20M以内）'
                }`"
                path="photoList"
              >
                <n-upload
                  style="width: 100%"
                  :default-file-list="detailData.photoList || []"
                  accept="image/jpg,image/jpeg,image/png,image/img"
                  list-type="image-card"
                  :show-remove-button="mode !== 'view'"
                  :on-change="(e) => onFileChange(e, 'detailData.photoList')"
                  @before-upload="beforeUpload"
                  @preview="handlePreview"
                >
                  点击上传
                </n-upload>
              </n-form-item-gi>
            </n-grid>
          </n-form>
        </div>
      </div>
    </n-drawer-content>
  </n-drawer>
  <n-modal
    v-model:show="showPhoto"
    preset="card"
    style="width: 30%"
    title="照片预览"
  >
    <img :src="previewImageUrl" style="width: 100%" />
  </n-modal>
</template>

<script lang="ts" setup>
import store from '@/store'
import { computed, onMounted, PropType, ref, watch } from 'vue'
import { FormRules, NForm, useMessage } from 'naive-ui'
import exportIcon from '@images/export.svg'
import { activity } from '@/util/tags'
import { useFetchOrg, usePostActivity, usePutActivity } from '@/hooks/useFetch'
import dayjs from '@/util/dayjs'
import useAliOss from '@/hooks/useAliOss'
import useExportDocx from '@/hooks/useExportDocx'

const message = useMessage()
const props = defineProps({
  data: {
    type: Object as PropType<{ [key: string]: any }>,
    default: null,
  },
  cb: {
    type: Function as PropType<(query?: string) => unknown>,
    default: null,
  },
})
const mode = ref<string | null>(null)

const orgOptions = ref<any[]>([])
onMounted(async () => {
  orgOptions.value = (
    await useFetchOrg({
      a: 'id,count',
      keys: '党组织名称,是否虚拟组织',
      q: `paths @ "党组织编号" && string @ "${store.state.auth.code}"`,
    })
  )
    ?.filter((item: any) => !item['是否虚拟组织'])
    ?.map((item: any) => ({
      label: item['党组织名称'],
      value: item['党组织名称'],
    }))
})

const show = computed(() => store.state.showNewActivityDrawer)
const closeDrawer = () => {
  store.commit('SET_NEW_ACTIVITY_DRAWER', false)
  basicData.value = {}
  memberData.value = {}
  detailData.value = {}
  mode.value = null
}

const typeOptions = computed(() => {
  return activity.map((item) => ({
    label: item.name,
    value: item.name,
  }))
})
const fileOptions = [
  { label: '电子表格（docx、doc、xlsx、xls、csv、txt）', value: 'file' },
  { label: '签到照片（jpg、jpeg、png、img）', value: 'photo' },
]
const describeOptions = [
  { label: '活动内容描述', value: 'text' },
  { label: '描述照片（jpg、jpeg、png、img）', value: 'photo' },
]

const basicRef = ref<typeof NForm | null>(null)
const memberRef = ref<typeof NForm | null>(null)
const detailRef = ref<typeof NForm | null>(null)
const basicData = ref<any>({})
const memberData = ref<any>({})
const detailData = ref<any>({})

watch(
  () => props.data,
  (data) => {
    if (!data) {
      basicData.value = {}
      memberData.value = {}
      detailData.value = {}
      return
    }
    getOrgInfo(data['党组织名称'])
    basicData.value = {
      name: data['活动名称'],
      type: data['标签类别'],
      orgName: data['党组织名称'],
      date: +(data['活动日期'] + '000') || null,
      address: data['活动地址'],
    }
    const isFile = data['签到表文件'] && data['签到表文件'].length > 0
    const isPhoto = data['签到表照片'] && data['签到表照片'].length > 0
    const fileType = isFile ? 'file' : isPhoto ? 'photo' : null
    memberData.value = {
      count: data['实际参与人数'],
      excludeCount: data['不计入参与活动党员人数'],
      fileType,
      attachment:
        fileType === 'file'
          ? data['签到表文件'].map((url: string, i: number) => ({
              id: i,
              url,
              name: decodeURIComponent(url.split('_').pop() || '未命名'),
              status: 'finished',
            }))
          : [],
      attachmentPhoto:
        fileType === 'photo'
          ? (data['签到表照片'] || []).map((url: string, i: number) => ({
              id: i,
              url,
              name: decodeURIComponent(url.split('_').pop() || '未命名'),
              status: 'finished',
            }))
          : [],
    }

    const isText = data['活动内容描述']
    const isImage = data['台账记录照片'] && data['台账记录照片'].length > 0
    const describeType = isText ? 'text' : isImage ? 'photo' : null
    detailData.value = {
      describeType,
      attachment: describeType === 'text' ? data['活动内容描述'] : '',
      attachmentPhoto:
        describeType === 'photo'
          ? (data['台账记录照片'] || []).map((url: string, i: number) => ({
              id: i,
              url,
              name: decodeURIComponent(url.split('_').pop() || '未命名'),
              status: 'finished',
            }))
          : [],
      photoList:
        (data['活动照片'] || []).map((url: string, i: number) => ({
          id: i,
          url,
          name: decodeURIComponent(url.split('_').pop() || '未命名'),
          status: 'finished',
        })) || [],
    }
    mode.value = data._mode || null
  },
  { immediate: true },
)

const rules: FormRules = {
  name: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请输入活动名称',
  },
  type: {
    required: true,
    trigger: ['blur', 'change'],
    message: '请选择标签类别',
  },
  orgName: {
    required: true,
    trigger: ['blur', 'change'],
    message: '请选择党组织',
  },
  date: {
    type: 'number',
    required: true,
    trigger: ['blur', 'change'],
    message: '请选择活动日期',
  },
  address: {
    required: true,
    trigger: ['blur', 'input'],
    message: '请输入活动地址',
  },
  count: [
    {
      type: 'number',
      required: true,
      trigger: ['blur', 'input'],
      message: '请输入实际参与人数',
    },
    {
      type: 'number',
      validator: (_, val) => checkMemberCount(val),
      message: '不能大于党员总数',
      trigger: ['blur', 'input'],
    },
  ],
  excludeCount: [
    {
      type: 'number',
      required: true,
      trigger: ['blur', 'input'],
      message: '请输入不计入参与活动党员人数',
    },
    {
      type: 'number',
      validator: (_, val) => checkMemberCount(val),
      message: '不能大于党员总数',
      trigger: ['blur', 'input'],
    },
    {
      type: 'number',
      validator: (_, val) => val + memberData.value.count <= totalPerson.value,
      message: '与实际参与人数之合不能大于党员总数',
      trigger: ['blur', 'input'],
    },
  ],
  fileType: [
    {
      required: true,
      trigger: ['blur', 'change'],
      message: '请选择上传类型',
    },
    {
      validator: (_, val) => {
        if (val !== 'file') return true
        if (
          !memberData.value.attachment ||
          memberData.value.attachment.length === 0
        ) {
          return false
        }
        return true
      },
      message: '请上传附件',
    },
    {
      validator: (_, val) => {
        if (val !== 'photo') return true
        if (
          !memberData.value.attachmentPhoto ||
          memberData.value.attachmentPhoto.length === 0
        ) {
          return false
        }
        return true
      },
      message: '请上传签到照片',
    },
  ],
  describeType: [
    {
      required: true,
      trigger: ['blur', 'change'],
      message: '请选择描述类型',
    },
    {
      validator: (_, val) => {
        if (val !== 'text') return true
        if (!detailData.value.attachment) return false
        return true
      },
      message: '请输入活动内容描述',
    },
    {
      validator: (_, val) => {
        if (val !== 'photo') return true
        if (
          !detailData.value.attachmentPhoto ||
          detailData.value.attachmentPhoto.length === 0
        )
          return false
        return true
      },
      message: '请上传描述照片',
    },
  ],
  photoList: {
    type: 'array',
    required: true,
    trigger: ['blur', 'change'],
    message: '请上传活动照片',
  },
}

const submit = () => {
  let noError = true
  basicRef.value?.validate((errors: any) => {
    if (errors) noError = false
    memberRef.value?.validate((errors: any) => {
      if (errors) noError = false
      detailRef.value?.validate(async (errors: any) => {
        if (errors) noError = false
        if (!noError) return

        const { name, type, orgName, date, address } = basicData.value
        const { count, excludeCount, attachment, attachmentPhoto, fileType } =
          memberData.value
        const {
          attachment: detailAttachment,
          attachmentPhoto: detailAttachmentPhoto,
          describeType,
          photoList,
        } = detailData.value
        const data: any = {
          活动名称: name,
          标签类别: type,
          党组织名称: orgName,
          活动日期: +(date + '').slice(0, 10), // 截掉10位后的0，不然这接口会认为不是时间戳
          活动地址: address,
          实际参与人数: count,
          不计入参与活动党员人数: excludeCount,
          活动照片: photoList?.map((item: any) => item.url) || [],
          上海2000经度: location.value[0],
          上海2000纬度: location.value[1],
          党组织编号: orgCode.value,
          出席率:
            totalPerson.value === excludeCount
              ? 0
              : getPercent(
                  Math.round(
                    (count / (totalPerson.value - excludeCount)) * 100,
                  ),
                ),
        }
        if (fileType === 'file') {
          data['签到表文件'] = attachment?.map((item: any) => item.url) || []
          data['签到表照片'] = []
        } else if (fileType === 'photo') {
          data['签到表照片'] =
            attachmentPhoto?.map((item: any) => item.url) || []
          data['签到表文件'] = []
        }
        if (describeType === 'text') {
          data['活动内容描述'] = detailAttachment
          data['台账记录照片'] = []
        } else if (describeType === 'photo') {
          data['台账记录照片'] =
            detailAttachmentPhoto?.map((item: any) => item.url) || []
          data['活动内容描述'] = ''
        }
        if (mode.value === 'modify') {
          await usePutActivity({
            separate: [
              {
                id: props.data.id,
                extra: data,
              },
            ],
          })
          closeDrawer()
          props.cb && props.cb()
          message.success('活动修改成功')
        } else {
          await usePostActivity({
            extra: data,
          })
          closeDrawer()
          props.cb && props.cb()
          message.success('活动新增成功')
        }
      })
    })
  })
}

const previewImageUrl = ref('')
const showPhoto = ref(false)
function handlePreview({ url }: any) {
  previewImageUrl.value = url
  showPhoto.value = true
}

function getPercent(val: number) {
  if (val > 100) return 100
  return val
}

function beforeUpload(options: any) {
  if (!options || !options.file) return false
  if (options.file.file.size >= 20000000) {
    message.error('不能上传超过20MB的文件')
    return false
  }
  return true
}

async function onFileChange(options: any, type: string) {
  if (!options) return
  if (!options.event) {
    // 删除
    const { url } = options.file
    switch (type) {
      case 'memberData.attachment':
        memberData.value.attachment.splice(
          memberData.value.attachment.findIndex((e: any) => e?.url === url),
          1,
        )
        break
      case 'memberData.attachmentPhoto':
        memberData.value.attachmentPhoto.splice(
          memberData.value.attachmentPhoto.findIndex(
            (e: any) => e?.url === url,
          ),
          1,
        )
        break
      case 'detailData.attachmentPhoto':
        detailData.value.attachmentPhoto.splice(
          detailData.value.attachmentPhoto.findIndex(
            (e: any) => e?.url === url,
          ),
          1,
        )
        break
      case 'detailData.photoList':
        detailData.value.photoList.splice(
          detailData.value.photoList.findIndex((e: any) => e?.url === url),
          1,
        )
        break
      default:
        break
    }
    return
  }
  if (!options.file) return

  if (options.file.file.size >= 20000000) return

  const url = { url: await useAliOss(options.file.file) }

  switch (type) {
    case 'memberData.attachment':
      if (!memberData.value.attachment) {
        memberData.value.attachment = []
        memberData.value.attachment.push(url)
      } else {
        memberData.value.attachment.push(url)
      }
      break
    case 'memberData.attachmentPhoto':
      if (!memberData.value.attachmentPhoto) {
        memberData.value.attachmentPhoto = []
        memberData.value.attachmentPhoto.push(url)
      } else {
        memberData.value.attachmentPhoto.push(url)
      }
      break
    case 'detailData.attachmentPhoto':
      if (!detailData.value.attachmentPhoto) {
        detailData.value.attachmentPhoto = []
        detailData.value.attachmentPhoto.push(url)
      } else {
        detailData.value.attachmentPhoto.push(url)
      }
      break
    case 'detailData.photoList':
      if (!detailData.value.photoList) {
        detailData.value.photoList = []
        detailData.value.photoList.push(url)
      } else {
        detailData.value.photoList.push(url)
      }
      break
    default:
      break
  }
}

const totalPerson = ref(0)
const location = ref<number[]>([])
const orgCode = ref('')
async function getOrgInfo(name: string) {
  if (!name) return
  const res = (
    await useFetchOrg({
      keys: '党员数量,上海2000经度,上海2000纬度,党组织编号',
      q: `paths @ "党组织名称" && string == "${name}"`,
    })
  )?.[0]
  totalPerson.value = res?.['党员数量'] || 0
  location.value = [res?.['上海2000经度'] || 0, res?.['上海2000纬度'] || 0]
  orgCode.value = res?.['党组织编号'] || ''
}
watch(
  () => basicData.value.orgName,
  (name) => {
    getOrgInfo(name)
  },
  { immediate: true },
)

function checkMemberCount(val: number) {
  return val >= 0 && val <= totalPerson.value
}
const handleExport = async () => {
  const { name, type, orgName, date, address } = basicData.value
  const { count, excludeCount, attachment, attachmentPhoto } = memberData.value
  const {
    attachment: detailAttachment,
    attachmentPhoto: detailAttachmentPhoto,
    photoList,
  } = detailData.value
  const data = [
    {
      活动名称: name,
      标签类别: type,
      党组织名称: orgName,
      活动日期: dayjs(date).format('ll'), // 截掉10位后的10，不然这接口会认为不是时间戳
      活动地址: address,
    },
    {
      实际参与人数: count,
      不计入参与活动党员人数: excludeCount,
      出席率:
        totalPerson.value === excludeCount
          ? '0%'
          : getPercent(
              Math.round((count / (totalPerson.value - excludeCount)) * 100),
            ) + '%',
    },
    {
      活动内容描述: detailAttachment,
      活动照片: photoList,
    },
  ]
  if (attachment && attachment.length > 0) {
    data[1]['签到表文件'] = attachment
  }
  if (attachmentPhoto && attachmentPhoto.length > 0) {
    data[1]['签到表照片'] = attachmentPhoto
  }
  if (detailAttachment) {
    data[2]['活动内容描述'] = detailAttachment
  }
  if (detailAttachmentPhoto && detailAttachmentPhoto.length > 0) {
    data[2]['台账记录照片'] = detailAttachmentPhoto
  }

  await useExportDocx(
    [
      {
        _title: '基本信息',
        ...data[0],
      },
      {
        _title: '人员参与情况',
        ...data[1],
      },
      {
        _title: '活动详情',
        ...data[2],
      },
    ],
    '_title',
    basicData.value.name,
  )
}
</script>

<style lang="stylus" scoped>
@import '../../components/MyComponent/main.styl'
.head
  width 100%
  $flex-align()
  justify-content space-between
.content
  height 100%
  overflow-y auto
  background #f7f7f7
  padding .08rem .1rem
  box-sizing border-box
  p
    font-size .11rem
    padding-left .02rem
  >div
    background $white-bg
    border-radius .04rem
    margin-bottom .08rem
    padding .08rem
    overflow hidden
    box-sizing border-box
    .title
      font-family $font-ping-medium
      margin-bottom .1rem
      font-size .14rem
      $flex-align()
      &:before
        content ''
        display inline-block
        width .02rem
        height .14rem
        background $red
        margin-right .06rem
      >span
        flex 1
        text-align right
        font-family $font-ping
        font-size .1rem
        >span
          color $blue
</style>
<style lang="stylus">
@import '../../components/MyComponent/main.styl'
.n-drawer.n-drawer--right-placement.top0
  top 0
  .n-drawer-header__main
    width 100%
  .n-input-number
    width 100%
    .n-input-wrapper
      padding-right 0
    .n-input__suffix
      background #f3f4f7
      border-left .01rem solid $light-gray
      padding 0 .1rem

.content
  .n-upload
    .n-upload-file-list.n-upload-file-list--grid
      min-height .7rem
  &.view-mode
    .n-upload__trigger.n-upload__trigger--image-card
      display none !important
  .no-label
    margin-top -0.2rem
</style>
