Files
cdTestPlant3/cdTMP/src/views/project/dut/components/FileInputModal/index.vue
2024-05-30 11:29:44 +08:00

272 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="file-input-container">
<a-modal
v-model:visible="modalVisible"
width="80%"
title="设计需求批量写入"
:unmount-on-close="true"
:mask-closable="false"
ok-text="录入"
:esc-to-close="false"
:on-before-ok="handleModalSubmit"
>
<div class="uploadContainer">
<span :style="{ marginBottom: '10px', flex: '0 1 160px' }">上传设计需求.docx:</span>
<a-upload
:style="{ marginBottom: '10px' }"
:custom-request="handleRquest"
:limit="1"
accept=".docx"
@change="handleUploadChange"
></a-upload>
</div>
<a-alert :style="{ margin: '10px 0' }" type="warning"
>上传录入提示信息硬性要求本辅助程序根据GJB438C文档结构进行解析要求1.功能需求章节必须包含<span
class="important-text"
>CSCI功能需求</span
><span class="important-text">CSCI能力需求</span>文字,且章节级别必须为<span class="important-text"
>2</span
>; 2.外部接口章节必须包含<span class="important-text">CSCI外部接口需求</span
>文字,且章节级别必须为<span class="important-text">2</span
>暂时只能解析这两个章节如果章节号有标识则使用<span class="important-text"
>RQGN01-UART-ZRZL</span
><span class="important-text">(RQGN01-UART-XBRCV)</span>包含在里面</a-alert
>
<div class="operation-container">
<span :style="{ marginRight: '10px', fontWeight: 700 }">操作按钮:</span>
<a-space>
<a-button type="primary" @click="handleCreateAtLatest">新增一条</a-button>
<a-button type="outline" status="warning" @click="handleResetData">重置数据</a-button>
</a-space>
</div>
<a-spin :loading="loading" tip="解析word完成需要时间渲染HTML元素..." :style="{ width: '100%' }">
<div class="demand-container">
<a-list :data="htmlData" :pagination-props="{ defaultPageSize: 15, total: htmlData.length }">
<template #item="{ item, index }">
<a-list-item>
<div class="item-container">
<a-input-group>
<a-input
placeholder="章节号"
v-model="item.chapter"
:style="{ width: '100px' }"
@click.stop.prevent
></a-input>
<a-input
placeholder="标题"
v-model="item.title"
:style="{ width: '300px' }"
@click.stop.prevent
></a-input>
<a-input
placeholder="标识"
v-model="item.ident"
:style="{ width: '200px' }"
@click.stop.prevent
></a-input>
<a-select
:style="{ width: '150px' }"
placeholder="请选择设计需求类型"
@click.stop.prevent
v-model="item.demandType"
>
<a-option v-for="it in demandType" :value="it.key">{{ it.title }}</a-option>
</a-select>
</a-input-group>
<a-button-group>
<a-button
type="primary"
status="success"
size="small"
@click.stop.prevent="handledownCreate(index)"
>
<template #icon>
<icon-plus />
</template>
下方新增
</a-button>
<a-button
type="primary"
status="danger"
size="small"
@click.stop.prevent="handleDelete(index)"
>
<template #icon>
<icon-delete />
</template>
删除该条
</a-button>
</a-button-group>
</div>
<div class="content">
<MaEditor v-model="item.content" />
</div>
</a-list-item>
</template>
</a-list>
</div>
</a-spin>
</a-modal>
</div>
</template>
<script setup>
import { ref, nextTick, watch } from "vue"
import mammoth from "mammoth"
import dictApi from "@/api/system/dict"
import demandApi from "@/api/project/designDemand"
import { useRoute, useRouter } from "vue-router"
import { parseHtmlStringByDemandDut } from "@/views/project/dut/tools/parseHtmlString"
import { useTreeDataStore } from "@/store"
// 其他初始化数据
const route = useRoute()
const router = useRouter()
const treeDataStore = useTreeDataStore()
// ~导入editor组件~tinymce
import MaEditor from "@/components/ma-editor/index.vue"
import { Message } from "@arco-design/web-vue"
// 单个设计需求录入模版
const templateDemandObj = {
chapter: "",
title: "",
ident: "",
demandType: "",
content: ""
}
// 先请求设计需求的dict然后给demandType选项
let demandType = []
const getDictDemandType = async function () {
const res = await dictApi.getDictByCode({ code: "demandType" })
demandType = res.data
}
getDictDemandType()
// 弹窗显示
const modalVisible = ref(false)
// 全部html数据-循环创建折叠项
const htmlData = ref([])
// 数据变化spin显示
const loading = ref(false)
// 当upload组件发生变化时候
const handleUploadChange = (files) => {
files.length ? (files.length = 1) : (htmlData.value = [])
}
// 上传行为函数
const handleRquest = function (options) {
const { onProgress, onError, onSuccess, fileItem } = options
onProgress(0.1)
// 让spin组件先转圈
loading.value = true
// 让Empty组件不显示
htmlData.value.push(templateDemandObj)
// 获取文件
let reader = new FileReader()
reader.readAsArrayBuffer(fileItem.file)
reader.onload = function (loadEvent) {
let arrayBuffer = loadEvent.target.result
mammoth
.convertToHtml({ arrayBuffer: arrayBuffer })
.then((res) => {
// 已经上传到浏览器了,需要解析为列表
onSuccess(1)
const rawHtml = res.value
const finalData = parseHtmlStringByDemandDut(rawHtml)
// 将finalData赋值给响应式数据ref变量htmlData
htmlData.value = finalData
// ~~~~使用nextTick等待DOM更新完成~~~~
nextTick(() => {
loading.value = false
})
})
.catch(function (error) {
console.log("处理错误导致失败,请检查前端代码")
console.log("错误如下:", error)
onError(error)
})
}
}
// 上方按钮:直接在最下新增一条
const handleCreateAtLatest = () => {
const newDemand = JSON.parse(JSON.stringify(templateDemandObj))
htmlData.value.push(newDemand)
}
// 上方按钮:重置数据,点击页面不卡段
const handleResetData = () => {
htmlData.value = []
}
// 点击单条右侧按钮:下方新增 - 深拷贝,并插入到下方
const handledownCreate = (index) => {
const newDemand = JSON.parse(JSON.stringify(templateDemandObj))
htmlData.value.splice(index + 1, 0, newDemand)
}
// 点击单条右侧按钮:删除
const handleDelete = (index) => {
htmlData.value.splice(index, 1)
}
// 打开弹窗并初始化form数据
const open = function () {
// 打开时候传入对象可初始化from
modalVisible.value = true
}
// 为了性能监听modal关闭则清空数据
watch(
() => modalVisible.value,
(newValue) => {
if (!newValue) {
htmlData.value = []
}
}
)
// 提交事件
const handleModalSubmit = async () => {
if (!htmlData.value.length) {
Message.error("请添加设计需求后再提交...")
return false
}
const res = await demandApi.multiSave({
projectId: route.query.id,
key: route.query.key,
data: htmlData.value
})
if (res.code === 200) {
treeDataStore.updateDesignDemandTreeData(res.data, route.query.id)
Message.success("批量新增设计需求成功...")
return true
}
return false
}
// 暴露该组件ref的方法
defineExpose({ open })
</script>
<style lang="less" scoped>
.uploadContainer {
display: flex;
align-items: center;
& span {
font-size: 1em;
font-weight: 700;
}
}
.demand-container {
width: 100%;
height: 55vh;
padding: 5px;
overflow: auto;
}
.operation-container {
margin-bottom: 5px;
}
.important-text {
font-weight: 700;
color: red;
}
.item-container {
width: 100%;
display: flex;
justify-content: space-between;
padding: 5px 5px;
border: 1px solid #ccc;
border-bottom: none;
}
</style>