|
@@ -1,18 +1,133 @@
|
|
|
-<template>
|
|
|
- 文档上传
|
|
|
+ <template>
|
|
|
+ <div class="w-full h-full flex flex-col">
|
|
|
+ <div class="__hover text-[var(--czr-main-color)] text-[0.88rem] flex items-center ml-[var(--czr-gap)]" @click="$router.push({
|
|
|
+ name: '78430247-a531-4c8f-8a08-c88e93a836e2',
|
|
|
+ params: {
|
|
|
+ id: state.ID
|
|
|
+ }
|
|
|
+ })"><SvgIcon name="czr_arrow" :rotate="180" size="12" :active="true"/>文档列表</div>
|
|
|
+ <div class="bm-main-box mt-[1.25rem]">
|
|
|
+ <div class="flex gap-[1rem]">
|
|
|
+ <CzrButton :type="state.uploadType == UploadTypeEnum.Text ? 'primary' : 'normal'" title="文本文件" @click="state.uploadType = UploadTypeEnum.Text, state.step = 1"/>
|
|
|
+ <CzrButton :type="state.uploadType == UploadTypeEnum.QA ? 'primary' : 'normal'" title="QA问答" @click="state.uploadType = UploadTypeEnum.QA, state.step = 1"/>
|
|
|
+ </div>
|
|
|
+ <div class="mt-[1.75rem] flex justify-center items-center gap-[1rem]">
|
|
|
+ <template v-for="(item, index) in (state.uploadType == UploadTypeEnum.Text ? TextSteps : QASteps)">
|
|
|
+ <div v-if="index > 0" class="step-split" :class="{active: state.step > index }"/>
|
|
|
+ <div class="step-item" :class="{active: state.step > index, current: state.step === index + 1}">
|
|
|
+ <div>{{state.step > index + 1 ? '✔' : index + 1}}</div>
|
|
|
+ {{ item }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <template v-if="state.step == 1">
|
|
|
+ <div class="w-full rounded-[0.25rem] bg-[#F6F8FC] px-[1.5rem] py-[1rem] mt-[1.5rem] flex">
|
|
|
+ <SvgIcon name="czr_tip" color="#fdb648" class="mr-[1rem]"/>
|
|
|
+ <div class="flex flex flex-col gap-[0.5rem] text-[#606266] text-[0.88rem]">
|
|
|
+ <template v-if="state.uploadType == UploadTypeEnum.Text">
|
|
|
+ <div>1、文件上传前,建议规范文件的分段标识</div>
|
|
|
+ <div>2、每次最多上传 {{ UploadConfig.limit }} 个文件,每个文件不超过 {{ UploadConfig.maxSize }}MB</div>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="state.uploadType == UploadTypeEnum.QA">
|
|
|
+ <div class="flex">1、点击下载对应模版并完善信息<CzrButton type="table" title="下载Excel模板"/></div>
|
|
|
+ <div>2、上传的表格文件中每个 sheet 会作为一个文档,sheet名称为文档名称</div>
|
|
|
+ <div>3、每次最多上传 {{ UploadConfig.limit }} 个文件,每个文件不超过 {{ UploadConfig.maxSize }}MB</div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-[1rem] w-full h-[12.5rem] rounded-[0.25rem] bg-[#F6F8FC]">
|
|
|
+ <el-upload
|
|
|
+ class="upload"
|
|
|
+ drag
|
|
|
+ action="#"
|
|
|
+ multiple
|
|
|
+ :accept="AcceptType[state.uploadType].map(v => '.' + v).join(',')"
|
|
|
+ :show-file-list="false"
|
|
|
+ :before-upload="handleBeforeUpload"
|
|
|
+ :http-request="handleHttpRequest"
|
|
|
+ :disabled="state.uploadFiles.size === UploadConfig.limit"
|
|
|
+ >
|
|
|
+ <div class="flex flex-col justify-center items-center text-[#6F7889] text-[0.88rem] gap-[0.5rem]">
|
|
|
+ <SvgIcon name="upload" color="#6F7889" size="40"/>
|
|
|
+ <div>点击或拖拽文件到此区域,或 <span class="text-[var(--czr-main-color)]">选择文件</span></div>
|
|
|
+ <div>支持格式:{{AcceptType[state.uploadType].join('、')}}</div>
|
|
|
+ </div>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ <div class="mt-[1rem] flex-1 grid grid-cols-4 auto-rows-max gap-[1.5rem] overflow-y-auto">
|
|
|
+ <template v-for="[id, file] in state.uploadFiles">
|
|
|
+ <div class="h-[3.13rem] flex items-center gap-[0.25rem] px-[var(--czr-gap)] rounded-[0.25rem] bg-[#F6F8FC]" @mouseenter="file.hover__ = true" @mouseleave="file.hover__ = false">
|
|
|
+ <img src="@/assets/images/file-word.png" class="w-[1.25rem] h-[1.25rem]"/>
|
|
|
+ <div class="flex-1 flex items-center gap-[0.25rem] relative overflow-hidden">
|
|
|
+ <div v-title class="flex-1 text-[#333333] text-[0.88rem]">{{file.name}}</div>
|
|
|
+ <div class="text-[#A7ADB9] text-[0.75rem] h-full ml-auto">
|
|
|
+ <template v-if="file.hover__">
|
|
|
+ <div class="__hover flex items-center gap-[0.25rem]" @click="state.uploadFiles.delete(id)">
|
|
|
+ <SvgIcon name="czr_del" size="14" class="mb-[2px]"/>删除
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <template v-if="file.success">
|
|
|
+ <SvgIcon name="success" color="#1CC78D"/>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ {{file.process}}%
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <template v-if="!file.success">
|
|
|
+ <div class="absolute bottom-[-0.5rem] w-full h-[0.25rem] rounded-[0.25rem]" :style="{backgroundColor: `rgba(var(--czr-main-color-rgb), 0.3)`}">
|
|
|
+ <div class="absolute h-[0.25rem] rounded-[0.25rem]" :style="{backgroundColor: `rgba(var(--czr-main-color-rgb), 1)`, width: `${file.process}%`}"/>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import {getCurrentInstance, onMounted, reactive, ref} from "vue";
|
|
|
-import {useRoute} from "vue-router";
|
|
|
+import {getCurrentInstance, inject, onMounted, reactive, ref} from "vue";
|
|
|
+import {useRoute, useRouter} from "vue-router";
|
|
|
+import {ElMessage} from "element-plus";
|
|
|
+import {axUpload} from "@/api/modules/global/upload";
|
|
|
+import {v4} from "uuid";
|
|
|
|
|
|
const route = useRoute();
|
|
|
+const router = useRouter();
|
|
|
const emits = defineEmits([])
|
|
|
const props = defineProps({})
|
|
|
const {proxy}: any = getCurrentInstance()
|
|
|
+enum UploadTypeEnum {
|
|
|
+ Text = 'text',
|
|
|
+ QA = 'qa',
|
|
|
+}
|
|
|
const state: any = reactive({
|
|
|
- ID: route.params.id
|
|
|
+ ID: route.params.id,
|
|
|
+ uploadType: UploadTypeEnum.Text,
|
|
|
+ step: 1,
|
|
|
+ uploadFiles: new Map(),
|
|
|
})
|
|
|
+const UploadConfig = {
|
|
|
+ limit: 2,
|
|
|
+ maxSize: 100,
|
|
|
+}
|
|
|
+const TextSteps = [
|
|
|
+ '文件上传',
|
|
|
+ '分段及清洗',
|
|
|
+ '处理并完成',
|
|
|
+]
|
|
|
+const QASteps = [
|
|
|
+ '文件上传',
|
|
|
+ '处理并完成',
|
|
|
+]
|
|
|
+const AcceptType = {
|
|
|
+ [UploadTypeEnum.Text]: ['TXT', 'MARKDOWN', 'MDX', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'DOC', 'CSV', 'MD', 'HTM'].map(v => v.toUpperCase()),
|
|
|
+ [UploadTypeEnum.QA]: ['XLS', 'XLSX'].map(v => v.toUpperCase()),
|
|
|
+}
|
|
|
const initDetail = () => {
|
|
|
if (state.ID) {
|
|
|
|
|
@@ -20,10 +135,99 @@ const initDetail = () => {
|
|
|
router.push({name: '4342bfff-1ea8-4f4c-b562-3cdc1fde116f'})
|
|
|
}
|
|
|
}
|
|
|
+const handleBeforeUpload = (file) => {
|
|
|
+ const suffix = file.name.split('.').pop().toUpperCase()
|
|
|
+ const msg = `文件${file.name}上传失败`
|
|
|
+ if (!AcceptType[state.uploadType].includes(suffix)) {
|
|
|
+ ElMessage.warning(`${msg},格式不正确!`)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if ((file.size / 1024 / 1024) > UploadConfig.maxSize) {
|
|
|
+ ElMessage.warning(`${msg},大小不正确!`)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if (state.uploadFiles.size >= UploadConfig.limit) {
|
|
|
+ ElMessage.warning(`${msg},数量已达上限!`)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ state.uploadFiles.set(file.uid, {
|
|
|
+ name: file.name,
|
|
|
+ success: false,
|
|
|
+ process: 0
|
|
|
+ })
|
|
|
+ return true
|
|
|
+}
|
|
|
+const handleHttpRequest = (options) => {
|
|
|
+ const id = options.file.uid
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('file', options.file);
|
|
|
+ axUpload(formData, (process) => {
|
|
|
+ if (state.uploadFiles.get(id)) {
|
|
|
+ state.uploadFiles.get(id).process = process
|
|
|
+ }
|
|
|
+ }).then(res => {
|
|
|
+ if (state.uploadFiles.get(id)) {
|
|
|
+ state.uploadFiles.get(id).success = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
onMounted(() => {
|
|
|
initDetail()
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
+.step-split {
|
|
|
+ width: 16.5rem;
|
|
|
+ height: 2px;
|
|
|
+ background-color: #EAEBEF;
|
|
|
+ &.active {
|
|
|
+ background-color: var(--czr-main-color);
|
|
|
+ }
|
|
|
+}
|
|
|
+.step-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 0.75rem;
|
|
|
+ font-size: 1rem;
|
|
|
+ color: #A7ADB9;
|
|
|
+ >div:first-child {
|
|
|
+ width: 2rem;
|
|
|
+ height: 2rem;
|
|
|
+ border-radius: 2rem;
|
|
|
+ border: 1px solid #A7ADB9;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ &.active {
|
|
|
+ color: #576275;
|
|
|
+ >div:first-child {
|
|
|
+ border-color: var(--czr-main-color);
|
|
|
+ color: var(--czr-main-color);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.current {
|
|
|
+ font-weight: bold;
|
|
|
+ color: #2E3238;
|
|
|
+ >div:first-child {
|
|
|
+ background-color: var(--czr-main-color);
|
|
|
+ border-color: var(--czr-main-color);
|
|
|
+ color: #ffffff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+:deep(.upload) {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ .el-upload {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ .el-upload-dragger {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-color: transparent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|