<template>
  <div>
    <el-dialog v-model="modelValue" title="文件解析" width="1000px" :show-close="true" :center="true" :close-on-click-modal="false" :before-close="handleClose" >
      <div class="flex align-center">
        <h3>提取文件类型：</h3>
         <el-radio-group v-model="active" @change="changeRadio">
          <el-radio :label="'文件解析'">文件解析</el-radio>
          <el-radio :label="'图片解析'">图片解析</el-radio>
        </el-radio-group>
      </div>
      <!-- 文件解析 -->
      <div v-show="active == '文件解析'">
        <h1>文件文本提取工具</h1>
        <p>上传文件提取文本内容（支持 .txt, .pdf, .docx, mp4 , mp3, wav）</p>

        <div class="container">
          <input type="file" id="file-input" accept=".txt,.pdf,.docx,'.mp4','.mp3','.wav'"/>
          <button @click="chooseFile">选择文件</button>
          <p id="file-info">{{ fileText }}</p>
        </div>

        <button id="extract-btn" disabled>提取文本</button>

        <h3>提取结果：</h3>
        <div id="result">{{ content }}</div>
      </div>
      <!-- 图片解析 -->
      <div v-show="active == '图片解析'" v-loading="loading" element-loading-text="模型加载中......">
        <div class="flex align-center just-between">
          <h1>文件文本提取工具</h1>
          <span title="刷新" class="pointer"  >
            <el-icon color="#0072ff" size="30px" @click="frashJs"><RefreshRight /></el-icon>
            <el-icon color="#23c044" size="14px" v-if="hasLoad"><CircleCheckFilled /></el-icon>
            <el-icon color="#e60e0e" size="14px" v-if="!hasLoad"><CircleCloseFilled /></el-icon>
          </span>
        </div>
        <p>上传文件提取文本内容（支持 .png, .jpg ）</p>
        <div class="container flex" style="height: 248px;">
          <div class="mr10">
            <el-upload :headers="headers" accept=".png,.jpg,jpeg" action="/mosty-api/mosty-base/minio/image/upload/id" :show-file-list="false" :on-success="handlerSuccess" :on-change="onHandleChange" >
              <el-button size="medium" type="primary">上传图片</el-button>
            </el-upload>
            <p id="file-info">{{ files.name || '未选择文件' }} </p>
          </div>
          <div class="box">
            <div class="imd">
              <img :src="image" v-if="image" style="width: 340px; max-height: 200px"/>
              <img :src="image" ref="imageRef" v-show="false" />
            </div>
            <div class="imd" v-show="false">
              <canvas ref="canvasRef"></canvas>
            </div>
          </div>
        </div>
        <h3>提取结果：</h3>
        <div class="textModel noScollLine" v-loading="linadingImg" element-loading-text="图片解析中......">
          <p v-if="texts.length == 0">{{ alertText }}</p>
          <template v-else>
            <p v-for="(text, index) in texts" :key="index">{{ text }}</p>
          </template>
        </div>
      </div>
      <template #footer>
        <el-button @click="handleClose">取消</el-button>
        <el-button type="primary" @click="onComfirm">确认</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import axios from "axios";
import * as ocr from "@paddlejs-models/ocr";
import { drawBox } from "@/utils/ocrUtils";
import { nextTick,reactive, ref,getCurrentInstance, watch } from "vue";
import { useStore } from "vuex";
const store = useStore();
const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false
  }
});

const content = ref('请先上传文件...')
const fileText = ref('未选择文件')

const { proxy } = getCurrentInstance();
const emits = defineEmits(["update:modelValue", "change"]);
const active = ref('文件解析')
const hasLoad = ref(false)
const files = ref({})
const loading = ref(true)
const linadingImg = ref(false)
const image = ref('')
const alertText = ref('请先上传文件...')
const texts = ref([])
const imageRef = ref()
const canvasRef = ref()
const textStyle = reactive({
  width: "",
  height: ""
})
const headers = ref({
  Authorization: store.getters.token
});
const fjdz = ref('') //附件地址
const fjmc = ref('') //附件地址

const initDemo = () =>{
  loading.value = imgIsLoad ? false : true;
  hasLoad.value = imgIsLoad ? true : false;
  nextTick(() => {
    const fileInput = document.getElementById("file-input");
    const extractBtn = document.getElementById("extract-btn");
    let selectedFile = null;
    // 监听文件选择
    fileInput.addEventListener("change", function (e) {
      if (e.target.files.length > 0) {
        selectedFile = e.target.files[0];
        fileText.value = `已选择: ${selectedFile.name} (${( selectedFile.size / 1024 ).toFixed(2)} KB)`;
        extractBtn.disabled = false;
        fjmc.value = selectedFile.name;
        uploadFile(selectedFile); //上传附件
      } else {
        selectedFile = null;
        fileText.value = "未选择文件";
        extractBtn.disabled = true;
      }
      if (selectedFile.type == "video/mp4") {
        upfileOnchange(selectedFile);
      }
    });
    // 提取文本按钮点击事件
    extractBtn.addEventListener("click", async function () {
      if (!selectedFile) return (content.value = "请先选择文件");
      content.value = "正在处理文件...";
      try {
        let text = "";
        const fileType = selectedFile.name.split(".").pop().toLowerCase();
        if (fileType === "txt") {
          // 处理文本文件
          text = await readTextFile(selectedFile);
        } else if (fileType === "pdf") {
          // 处理PDF文件
          text = await extractTextFromPDF(selectedFile);
        } else if (fileType === "docx") {
          // 处理Word文件
          text = await extractTextFromDocx(selectedFile);
        } else if (["mp4", "mp3", "wav"].includes(fileType)) {
          // 处理mp4,mp3,wav文件
          await start();
          text = "数据加载有点慢，请稍等。。。。";
          setTimeout(() => {
            content.value = videoText;
          }, 2000);
        }else {
          throw new Error("不支持的文件类型");
        }
        content.value = text || "未提取到文本内容";
      } catch (error) {
        content.value = `处理失败: ${error.message}`;
      }
    });
  });
}

watch(()=>props.modelValue,val=>{
  if(val) initDemo();
},{immediate:true,deep:true})



// 读取文本文件
function readTextFile(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = (e) => resolve(e.target.result);
    reader.onerror = (e) => reject(new Error("文件读取失败"));
    reader.readAsText(file);
  });
}

// 提取PDF文本
async function extractTextFromPDF(file) {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();

    fileReader.onload = async function () {
      try {
        const typedArray = new Uint8Array(this.result);
        const pdf = await pdfjsLib.getDocument(typedArray).promise;
        let fullText = "";

        for (let i = 1; i <= pdf.numPages; i++) {
          const page = await pdf.getPage(i);
          const textContent = await page.getTextContent();
          const text = textContent.items.map((item) => item.str).join(" ");
          fullText += text + "\n\n";
        }

        resolve(fullText);
      } catch (error) {
        reject(error);
      }
    };

    fileReader.onerror = reject;
    fileReader.readAsArrayBuffer(file);
  });
}

// 提取Word文档文本
async function extractTextFromDocx(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = function (event) {
      const arrayBuffer = event.target.result;
      mammoth.extractRawText({ arrayBuffer: arrayBuffer }).then(function (result) {
        resolve(result.value);
      }).catch(function (error) {
        reject(error);
      });
    };

    reader.onerror = reject;
    reader.readAsArrayBuffer(file);
  });
}

const handlerSuccess = (file) =>{
  fjdz.value = file.data;
}

 /**@Descripttion:图片上传事件*/
const onHandleChange = (file) => {
  fjmc.value = file.name;
  files.value = file;
  image.value = URL.createObjectURL(file.raw);
  linadingImg.value = true;
  alertText.value = '图片文件解析中。。。'
  setTimeout(() => {
    getRecognize();
  }, 600);

}
// 图片解析
const getRecognize = async () => {
  const image = imageRef.value;
  const canvas = canvasRef.value;
  const res = await ocr.recognize(image);
  const { text, points } = res;
  drawBox(points, image, canvas);
  textStyle.width = image.width - 40 + "px";
  texts.value = text;
  linadingImg.value = false;
  alertText.value = '解析失败,请选择清晰一点的图片重试！'
}

// 切换标签
const changeRadio = (val) =>{
  content.value = "请先上传文件...";
  fileText.value = "选择文件";
  files.value = {};
  alertText.value = '请先上传文件...';
  texts.value = [];
  image.value = '';
  fjmc.value = '';
  if (val == '图片解析') {

    if (!imgIsLoad) {
      proxy.$message({ type: "error", message: "加载失败，请刷新页面" })

      // frashJs()
    };

  }
}

// 提交
const onComfirm = () => {
  if(active.value == '文件解析'){
    if(content.value == '请先上传文件...') return proxy.$message({ type: "warning",  message: "请解析文件" });
    emits("change", { text: content.value,fjdz:fjdz.value,fjmc:fjmc.value });
  }else{
    if(texts.value.length == 0) return proxy.$message({ type: "warning",  message: "请解析文件" });
    emits("change", {text:texts.value.join(',\n'),fjdz:fjdz.value,fjmc:fjmc.value});
  }
  handleClose()
};

// 关闭
const handleClose = () => {
  content.value = "请先上传文件";
  fileText.value = "未选择文件";
  files.value = {}
  alertText.value = '请先上传文件...';
  texts.value = []
  image.value = ''
  active.value = '文件解析'
  emits("update:modelValue", false);
};

// 上传附件
const uploadFile = (file) =>{
  let formData = new FormData();
  formData.append("file", file);
  let token = localStorage.getItem('token');
  axios({
    method: 'post',
    url: '/mosty-api/mosty-base/minio/image/upload/id',
    data:formData,
    headers: { "Content-type": "multipart/form-data",'Authorization': token }
  }).then( (res) => {
    fjdz.value = res.data ?  res.data.data : null;
  })
}


// 刷新js
const frashJs = async () =>{
  if(!imgIsLoad){
    try {
      await ocr.init();// 模型初始化
      imgIsLoad = true;
      proxy.$message({ type: "success",  message: "加载成功" });
    } catch (err) {
      proxy.$message({ type: "error",  message: "加载失败，请刷新页面" });
      imgIsLoad = false;
    }
  }
}

const chooseFile = () => {
  document.getElementById("file-input").click();
};
</script>

<style lang="scss" scoped>
.container {
  border: 2px dashed #ccc;
  padding: 20px;
  text-align: center;
  margin-bottom: 20px;
}

#file-input {
  display: none;
}

button {
  background: #0072ff;
  color: white;
  padding: 10px 15px;
  border: none;
  cursor: pointer;
  font-size: 16px;
  border-radius: 4px;
}

button:hover {
  background: #0072ff;
}

#result {
  margin-top: 20px;
  white-space: pre-wrap;
  background: #f9f9f9;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 4px;
  height: 270px;
  overflow-y: auto;
}

#file-info {
  margin: 10px 0;
  font-style: italic;
  color: #666;
}

::v-deep .el-dialog {
  margin-top: 10px;
}


.box{
  display: flex;
  .imd{
    flex: 1;
  }
}

.textModel{
  margin-top: 20px;
  white-space: pre-wrap;
  background: #f9f9f9;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 4px;
  height: 195px;
  overflow-y: auto;
}
</style>
