<template>
    <div class="page_item end_item generate_review_code">
        <div class=" page_search">
            <div class="search_content">
                <div class="content_left">
                    <FormSearchGroup :searchList="searchList" @searchChange="HandleSelectSearchChange"></FormSearchGroup>
                </div>
                <div class="content_right">
                    <el-button :loading="exportPdfLoading" class="button_refresh"  @click="HandleExportPdf">导出 PDF</el-button>
                    <el-button :loading="exportExcelLoading" class="button_refresh"  @click="HandleExportExcel">导出 Excel</el-button>
                    <el-button :class="[store.state.evaluationManageStepData.isAllowDeleteOrEdit ?  'button_border' : 'is-disabled']" 
                        @click="store.state.evaluationManageStepData.isAllowDeleteOrEdit ?  GoToReviewAccountConfig() : ''">重新生成</el-button>
                    <el-button :class="[store.state.evaluationManageStepData.isAllowDeleteOrEdit ? 'button_background' : 'is-disabled']" 
                        @click="store.state.evaluationManageStepData.isAllowDeleteOrEdit ? FinishReviewAccount() : ''">完成</el-button>
                </div>
            </div>
        </div>
        <div class="page_jg_20"></div>
        <Table 
            :currentPage="currentPage" 
            :pageSize="pageSize"  
            :tableData="tableData" 
            :tableColumns="generateCodeTableColumns" 
            :totalNum="totalNum"
            @paginationChange="HandlePaginationChange"
        >
            <template #num="{row,currentIndex}">
                {{ currentIndex + pageSize * (currentPage - 1) }}
            </template>

            <template #requestUrl="{row}">
                <div class="request_url">
                    <img class="qr_code" :src="row?.qrCode" @click="downloadQRCode(row?.qrCode)" alt="QR Code" />
                    {{ row.requestUrl }}
                </div>
            </template>
        </Table>
    </div>
</template>   


<script setup lang="ts">
import { ref,watch } from 'vue';
import { useStore } from 'vuex';
import { useRoute,useRouter } from 'vue-router';
import ExcelJS from 'exceljs';


// 1. 引入 jsPDF 和 AutoTable 插件
import { jsPDF } from 'jspdf';
import autoTable from 'jspdf-autotable';

// 字体文件 (确保该 WOFF/TTF 路径可以被正确 fetch 或 import)
import STXIHEIFont from '/font/STXIHEI.TTF';


import FormSearchGroup from '@/baseComponents/FormSearchGroup.vue';
import Table from '@/baseComponents/Table.vue';
import {makeQRCode,downloadQRCode } from '@/utils/makeQRCode'

import { searchList } from './formSearchGroup';
import { generateCodeTableColumns } from './table';

import {
    generateReviewCodeListApi,finishReviewAccountApi,getReviewAccountListApi,
    getGradeAndClassListApi,
} from '@/api/reviewAccountComponent'
import { onMounted } from 'vue';

const router = useRouter()
const route = useRoute()

// store.state.evaluationManageStepData.isGenerateAccountByGender // //按男女生成
const store = useStore()
const GoToReviewAccountConfig = ()=>{
   router.push(`reviewAccount?id=${route.query.id}`)
}


// 1. 生成评价账号 
const GenerateReviewCode = async ()=>{
    let paramsStr = sessionStorage.getItem('reviewAccountOptionData')  //是否需要生成评价码 的 标识
    let reviewAccountOptionData =  JSON.parse(paramsStr || '{}')
    if(paramsStr){
        // 有生成评价码的传参 _需要生成评价码
        let res = undefined
        try{
            res = await generateReviewCodeListApi(reviewAccountOptionData)
        }catch{}
        if(res?.code == 200){
            sessionStorage.removeItem('reviewAccountOptionData')   // 评价码生成后清除传参
            sessionStorage.removeItem('reviewAccountMsg') // 评价码生成成功，配置状态的旧数据 不再需要保留
            return true
        }else{
            return false
        }
    }else{
        // 没有生成评价码的传参 _不需要生成评价码
        return true
    }
}


// .2. 评价码数据获取 
const tableData = ref([])
const currentPage = ref(1)
const pageSize = ref(20)
const totalNum = ref(0)
// 获取评价码
const GetReviewCode = async ()=>{
    // 获取评价码信息
    let params = {
        evaluationId: route.query.id,
        evaluationGradeId: searchParams.value.evaluationGradeId == 'all' ? '' : JSON.parse(searchParams.value.evaluationGradeId || '{}')?.id,
        evaluationClassId:searchParams.value.evaluationClassId == 'all' ? '' : searchParams.value.evaluationClassId ,
        gender:searchParams.value.gender == 'all' ? '' : searchParams.value.gender,
        pageNum: currentPage.value,
        pageSize: pageSize.value
    }
    let res = await getReviewAccountListApi(params)
    if(res?.code == 200){
        const {codeDataList} = res.data
        tableData.value = await Promise.all(codeDataList.records.map(async item=>{
            return {
                ...item,
                qrCode:await makeQRCode(item.requestUrl)
            }
        }))

        totalNum.value = codeDataList.total
    }
}
// 表格分页切换
const HandlePaginationChange = async (params)=>{
    const {type,val} = params
    if(type == 'currentPage'){
        currentPage.value = val
    }
   await GetReviewCode()
}

//3. 查询参数变更
const searchParams = ref({
    evaluationGradeId:'all',  //年级
    evaluationClassId:'all',   //班级
    gender:'all',          //性别
})

// 获取 评价账号 年级/班级 筛选下拉
const GetGradeAndClassListOption = async ()=>{
    let res = await getGradeAndClassListApi(route.query.id)
    if(res?.code == 200){
        let gradeOptions = res.data?.map(item=>{
            return {
                label:item.gradeName,
                value:JSON.stringify({
                    id:item.id,
                    classData:item.classData
                })
            }
        }) || []
        // 初始赋值,班级只展示 [全部] 项
        let classOptions = [
            {
                label:'全部班级',
                value:'all'
            }
        ]
        searchList.value = searchList.value.map(item=>{
            if(item.key == 'evaluationGradeId'){
                item.options = [
                    {
                        label:'全部年级',
                        value:'all'
                    },
                    ...gradeOptions
                ]
            }else if(item.key == 'evaluationClassId'){
                item.options = classOptions
            }
            return item
        })
    }
}

// 搜索项下拉列表变更
const HandleSelectSearchChange = async (params,key)=>{
    console.log('查询搜素项参数__',params)
    searchParams.value = {...searchParams.value,...params}
    searchList.value = searchList.value.map(item=>{
        switch(item.key){
            case 'evaluationClassId':{
                // 当前触发的是年级下拉变更
                if(key == 'evaluationGradeId'){
                    // 重置班级的默认值
                    searchParams.value.evaluationClassId = 'all'
                    if(params.evaluationGradeId == 'all'){
                        // 班级下拉置空,只剩全部
                        item.options = [{label:'全部班级', value:'all' }]
                    }else{
                        // 班级下拉 动态变更
                        let classOptions = (JSON.parse(params.evaluationGradeId || '{}')?.classData || [])?.map(item=>{
                            return {
                                label:item.name,
                                value:item.id
                            }
                        })
                        item.options = [{label:'全部班级', value:'all'},
                                        ...classOptions]
                    }
                }
                break
            }
        }
        return {
            ...item,
            defaultValue:searchParams.value[item.key]
        }
    })

    // 调用查询接口
    await GetReviewCode()

}



// 4. 完成评价账号
const FinishReviewAccount = async()=>{
    let res = await finishReviewAccountApi(route.query.id)
    if(res?.code == 200){
        // 更新全局状态 
        await store.dispatch('updateEvaluationManageStepData',route.query.id)
        store.commit('updateEvaluationManageStepData',{currentActiveStepName:'parameterSetting'})  //更新全局活跃路由
        router.push(`parameterSetting?id=${route.query.id}`)
    }
}

// 导出Excel 或者 pdf 时 使用的数据（全部评价码）
const exportTableData = ref([])
const exportExcelLoading = ref(false)
const exportPdfLoading = ref(false)

// 获取 导出时使用的数据
 const GetExcelOrPdfReviewCode = async ()=>{
    // 获取评价码信息
    let params = {
        evaluationId: route.query.id,
        evaluationGradeId: searchParams.value.evaluationGradeId == 'all' ? '' : JSON.parse(searchParams.value.evaluationGradeId || '{}')?.id,
        evaluationClassId:searchParams.value.evaluationClassId == 'all' ? '' : searchParams.value.evaluationClassId ,
        gender:searchParams.value.gender == 'all' ? '' : searchParams.value.gender,
        pageNum: 1,
        pageSize: 100000
    }
    let res = await getReviewAccountListApi(params)
    if(res?.code == 200){
        const {codeDataList} = res.data
        exportTableData.value = await Promise.all(codeDataList.records.map(async item=>{
            return {
                ...item,
                qrCode:await makeQRCode(item.requestUrl)
            }
        }))
    }
}

// 导出 Excel
const HandleExportExcel = async () => {
    exportExcelLoading.value = true
    try{
        await GetExcelOrPdfReviewCode()
    }catch{
        exportExcelLoading.value = false
        return
    }
    // 1. 初始化sheet列表
    let finalTableColumn = generateCodeTableColumns.value.slice(1).filter(column => !column.hidden)
    let finalTableData = exportTableData.value

    let sheetName = '评价码'

    // 2. 创建工作簿 和 工作表
    const workbook = new ExcelJS.Workbook();
    const worksheet = workbook.addWorksheet(sheetName);

    // 3. 添加表头行
    let headers = finalTableColumn.map(column => column.label || column.name)
    let headerRow = worksheet.addRow(headers)
    //4. 定义表头样式
    headerRow.eachCell((cell) => {
        cell.style = {
        font: { name: 'Microsoft YaHei', size: 12, bold: true, color: { argb: 'FF333333' } },
        fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4F6F8' } },
        border: {
            top: { style: 'thin', color: { argb: 'FFD9D9D9' } },
            left: { style: 'thin', color: { argb: 'FFD9D9D9' } },
            bottom: { style: 'thin', color: { argb: 'FFD9D9D9' } },
            right: { style: 'thin', color: { argb: 'FFD9D9D9' } },
        },
        alignment: { vertical: 'middle', horizontal: 'center', wrapText: true },
        }
    })

    // 5. 添加数据行和二维码图片
    for (let i = 0; i < finalTableData.length; i++) {
        const row = finalTableData[i];
        const rowData = finalTableColumn.map(column => {
            const cellValue = row[column.name];
            return cellValue || '-'
        })
        const excelRow = worksheet.addRow(rowData);
        
        // 设置行高以适应二维码
        excelRow.height = 100;
        
        // 6. 定义数据行样式
        excelRow.eachCell({ includeEmpty: true }, (cell) => {
            cell.style = {
                font: { name: 'Microsoft YaHei', size: 12, color: { argb: 'FF333333' } },
                border: {
                    top: { style: 'thin', color: { argb: 'FFD9D9D9' } },
                    left: { style: 'thin', color: { argb: 'FFD9D9D9' } },
                    bottom: { style: 'thin', color: { argb: 'FFD9D9D9' } },
                    right: { style: 'thin', color: { argb: 'FFD9D9D9' } },
                },
                alignment: { vertical: 'middle', horizontal: 'center', wrapText: true },
            };
        });
        
        // 插入二维码图片
        const qrCodeColumnIndex = finalTableColumn.findIndex(column => column.name === 'requestUrl');
        if (qrCodeColumnIndex !== -1 && row.qrCode) {
            // 移除 DataURL 的前缀（如 data:image/png;base64,）
            const base64Data = row.qrCode.split(',')[1];
            const imageId = workbook.addImage({
                base64: base64Data,
                extension: 'png',
            });
            
            // 计算图片位置，在 requestUrl 列旁边插入图片
            const colLetter = worksheet.getColumn(qrCodeColumnIndex + 1).letter;
            const rowNum = i + 2; // i 从 0 开始，第 1 行是表头
            
            // 添加图片，设置图片的位置和大小
            worksheet.addImage(imageId, {
                tl: { col: qrCodeColumnIndex + 1, row: rowNum - 1 },
                ext: { width: 80, height: 80 },
            });
        }
    };

    // 5. 设置列宽
    worksheet.columns = finalTableColumn.map((column, index) => {
        if (column.name === 'requestUrl') {
            return { width: 35 };
        }
        return { width: 25 };
    });
    // 设置表头的第一行固定
    worksheet.views = [{ state: 'frozen', ySplit: 1 }];


    // 6. 导出文件
    const buffer = await workbook.xlsx.writeBuffer();
    const blob = new Blob([buffer], { 
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 
    });
    
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `评价码列表.xlsx`;
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
    exportExcelLoading.value = false
};

// 导出 pdf
const HandleExportPdf = async () => {
    exportPdfLoading.value = true
    try{
        await GetExcelOrPdfReviewCode()
    }catch{
        exportPdfLoading.value = false
        return
    }

  let finalTableColumn = generateCodeTableColumns.value.slice(1).filter(column => !column.hidden)
    // 表格内容
    let finalTableData = exportTableData.value

  // 1. 表头数据 (注意：在 header 后面，我们要手动加一列用来放二维码，避免 URL 文本和二维码重合)
  const headers = [...finalTableColumn.map(column => column.label || column.name), '快捷扫码'];

  // 2. 格式化表格数据
  const body = finalTableData.map(row => {
    // 留空给最后一列绘制二维码图片
    return [...finalTableColumn.map(item=>row[item.name]),'']
  });

  // 3. 创建 PDF 实例
  const doc = new jsPDF('p', 'mm', 'a4');

  try {
    // 4. 加载中文字体以防乱码
    const fontBase64 = await convertFontToBase64(STXIHEIFont);
    // 注册字体 (文件名，字体名，样式)
    doc.addFileToVFS('STXIHEI.ttf', fontBase64);
    doc.addFont('STXIHEI.ttf', 'STXIHEI', 'normal');
    doc.setFont('STXIHEI'); // 应用字体
  } catch (error) {
    console.error('字体加载失败，中文可能会显示乱码', error);
  }

  // 5. 使用 autoTable 渲染表格
  autoTable(doc, {
    head: [headers],
    body: body,
    styles: {
      font: 'STXIHEI', // 单元格使用中文字体
      fontStyle: 'normal',
      halign: 'center',
      valign: 'middle'
    },
    // 手动调整列宽，给二维码列留出足够位置
    columnStyles: {
     [finalTableColumn.length - 1]: { cellWidth: 70 }, // 网址
     [finalTableColumn.length]:{ cellWidth: 35 },  // 二维码,
    },
    // 核心：在单元格渲染完毕后，利用钩子函数将二维码图片画进最后一列
    didDrawCell: (data) => {
      // 判断是否是最后一列且为数据行（非表头）
      if (data.column.index === finalTableColumn.length && data.cell.section === 'body') {
        const rowIndex = data.row.index;
        const qrCodeDataUrl = finalTableData[rowIndex]?.qrCode;
        if (qrCodeDataUrl) {
          // 在单元格内部计算二维码居中的坐标和大小
          const padding = 2;
          const size = Math.min(data.cell.width, data.cell.height) - padding * 2;
          const x = data.cell.x + (data.cell.width - size) / 2;
          const y = data.cell.y + (data.cell.height - size) / 2;
          
          // 绘制二维码图片
          doc.addImage(qrCodeDataUrl, 'PNG', x, y, size, size);
        }
      }
    },
    // 适当增加行高，保证二维码不会太小
    rowPageBreak: 'avoid',
    bodyStyles: { minCellHeight: 32 } 
  });

  // 6. 保存 PDF 文件
  doc.save('评价码列表.pdf');
  exportPdfLoading.value = false

}
// 辅助函数：将字体文件转为 Base64 以便 jsPDF 加载
const convertFontToBase64 = async (url: string): Promise<string> => {
  const response = await fetch(url);
  const blob = await response.blob();
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onloadend = () => {
      const base64String = reader.result as string;
      // 截取掉 data:application/font-woff;base64, 等前缀
      resolve(base64String.split(',')[1]);
    };
    reader.readAsDataURL(blob);
  });
};

// 根据是否按照性别生成评价码 控制 表格项和搜索项的显隐
watch(()=>store.state.evaluationManageStepData.isGenerateAccountByGender,(newVal)=>{
    generateCodeTableColumns.value = generateCodeTableColumns.value.map(item=>{
        if(item.name == 'genderName'){
            item.hidden = newVal ? false :true
        }
        return item
    })
    searchList.value = searchList.value.map(item=>{
        if(item.key == 'gender'){
            item.hidden = newVal ? false :true
        }
        return item 
    })
},{immediate:true})

onMounted(async ()=>{
    let generateFlag = await GenerateReviewCode()
    if(generateFlag){  // 这一步成功 才执行下一步
        await GetGradeAndClassListOption()
        await GetReviewCode()
    }else{
        // 评价码生成失败 返回配置页
        router.push(`reviewAccount?id=${route.query.id}`)
    }
})
</script>


<style lang="scss" scoped>
.generate_review_code{
    height: 100%;
    .page_search .content_right{
        flex-wrap: wrap;
        height: auto;
    }
}
.request_url{
    display: flex;
    gap:16px;
    justify-content: center;
    align-items: center;
    .qr_code{
        width: 24px;
        height: 24px;
    }
}
</style>
