【修改】 wps出题样式优化,错误提示去除

This commit is contained in:
dlaren
2025-09-10 15:12:17 +08:00
parent a6edb33f1e
commit 502b4aa154
3 changed files with 238 additions and 206 deletions

View File

@@ -139,9 +139,10 @@
v-loading="loading" v-loading="loading"
:data="list" :data="list"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
style="width: 100%"
> >
<!-- <el-table-column type="selection" width="55" /> --> <!-- <el-table-column type="selection" width="55" /> -->
<el-table-column label="考点" align="center" prop="contentIn" width="360px" /> <el-table-column label="考点" align="center" prop="contentIn"/>
<el-table-column label="权值" align="center" prop="scoreRate" width="100px" /> <el-table-column label="权值" align="center" prop="scoreRate" width="100px" />
<el-table-column label="操作" align="center" width="100px"> <el-table-column label="操作" align="center" width="100px">
<template #default="scope"> <template #default="scope">
@@ -283,7 +284,10 @@
<input type="file" id="slideFile" accept=".pptx" /> <input type="file" id="slideFile" accept=".pptx" />
<button @click="getSlideDataInfo">文件解析</button> <button @click="getSlideDataInfo">文件解析</button>
<div style="height: 400px; overflow: hidden; display: flex; gap: 16px"> <div style="height: 400px; overflow: hidden; display: flex; gap: 16px">
<div style="flex: 0.5; overflow: auto; border: 1px solid #eee; padding: 8px"> <div
class="tree-wrap"
style="flex: 0.5; overflow: auto; border: 1px solid #eee; padding: 8px"
>
<h3>考点</h3> <h3>考点</h3>
<el-tree <el-tree
style="max-width: 600px" style="max-width: 600px"
@@ -294,18 +298,17 @@
/> />
</div> </div>
<div style="flex: 1.5; overflow: auto; border: 1px solid #eee; padding: 8px"> <div style="flex: 1.5; overflow: auto; border: 1px solid #eee; padding: 8px; width: 90%;">
<h3>考点详情</h3> <h3>考点详情</h3>
<el-table :data="list" style="width: 100%"> <el-table :data="list" style="width: 100%">
<el-table-column prop="contentIn" label="值" width="500px" /> <el-table-column prop="contentIn" label="值" />
<el-table-column prop="scoreRate" label="权值" width="100px">
<el-table-column prop="scoreRate" label="权值" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model="row.scoreRate" size="small" style="width: 40px" /> <el-input v-model="row.scoreRate" size="small" style="width: 50px" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="100"> <el-table-column label="操作" width="100px">
<template #default="{ row }"> <template #default="{ row }">
<span <span
@click="removePoint(row)" @click="removePoint(row)"
@@ -318,11 +321,15 @@
</el-table> </el-table>
</div> </div>
</div> </div>
<!-- <el-skeleton :rows="5" animated v-if="pptxPointsList.length < 0 && isLoading" /> <!-- <el-skeleton :rows="5" animated v-if="pptxPointsList.length < 0 && isLoading" />
--> -->
</el-dialog> </el-dialog>
<el-dialog v-model="dialogFormVisiblePptxInfos" :title="titles" width="300px" class="fixed-dialog-height"> <el-dialog
v-model="dialogFormVisiblePptxInfos"
:title="titles"
width="300px"
class="fixed-dialog-height"
>
<div class="dialog-scroll-content"> <div class="dialog-scroll-content">
<el-tree <el-tree
style="max-width: 600px" style="max-width: 600px"
@@ -348,6 +355,7 @@ import { defaultProps, handleTree } from '@/utils/tree'
import { FormRules } from 'element-plus' import { FormRules } from 'element-plus'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import FileForm from './components/FileForm.vue' import FileForm from './components/FileForm.vue'
import { ElLoading } from 'element-plus'
defineOptions({ name: 'WpsPptxFrom' }) defineOptions({ name: 'WpsPptxFrom' })
const pptxPointsList = ref<Tree[]>([]) // 树形结构 const pptxPointsList = ref<Tree[]>([]) // 树形结构
@@ -408,12 +416,12 @@ const formData = ref({
// 定义 pptxPoints 类型 // 定义 pptxPoints 类型
interface PptxPoints { interface PptxPoints {
firstName: string; firstName: string
slideIndex: string; slideIndex: string
function: string; function: string
examName: string; examName: string
examCode: string; examCode: string
method?: string; method?: string
} }
let pptxPointsInfosList: PptxPoints[] = [] let pptxPointsInfosList: PptxPoints[] = []
const removePoint = (row) => { const removePoint = (row) => {
@@ -477,18 +485,29 @@ const handleCheckChange = (data: any, _checked: boolean, _indeterminate: boolean
} }
} }
const file = ref() const file = ref()
// 获取slide文件并使用文件流进行解析 // 获取slide文件并使用文件流进行解析
const getSlideDataInfo = async () => { const getSlideDataInfo = async () => {
const fileInput = document.getElementById('slideFile') as HTMLInputElement const fileInput = document.getElementById('slideFile') as HTMLInputElement
if (fileInput != null) { if (fileInput != null) {
if (fileInput.files && fileInput.files[0]) { const loading = ElLoading.service({
file.value = fileInput.files[0] target: '.tree-wrap', // 只遮罩左侧树区域
} else { text: '正在读取考点…',
return background: 'rgba(255,255,255,0.6)'
})
try {
if (fileInput.files && fileInput.files[0]) {
file.value = fileInput.files[0]
} else {
loading.close()
return
}
const res = await PptxApi.getSlideDataInfo({ file: file.value })
pptxPointsList.value = []
pptxPointsList.value.push(...handleTree(res.data))
} finally {
loading.close()
} }
const res = await PptxApi.getSlideDataInfo({ file: file.value })
pptxPointsList.value = []
pptxPointsList.value.push(...handleTree(res.data))
} }
} }
@@ -505,10 +524,10 @@ const textIndex = ref()
const handleNodelClick = async (row: any) => { const handleNodelClick = async (row: any) => {
console.log(row) console.log(row)
if (!row.click) { if (!row.click) {
return return
} }
// 获取名称 // 获取名称
chineseName.value = '【' + row.belongTo +'】【' + row.name + '】' chineseName.value = '【' + row.belongTo + '】【' + row.name + '】'
textIndex.value = row.index textIndex.value = row.index
const res = await PptxApi.getSlideByNameList(row.type) const res = await PptxApi.getSlideByNameList(row.type)
pptxPointsInfoList.value = [] pptxPointsInfoList.value = []
@@ -535,14 +554,14 @@ const submitPptxPoints = async () => {
for (let i = 0; i < res.data.length; i++) { for (let i = 0; i < res.data.length; i++) {
var indexFlag = false var indexFlag = false
for (let x = 0; x < list.value.length; x++) { for (let x = 0; x < list.value.length; x++) {
list.value[x].scoreRate='1' list.value[x].scoreRate = '1'
if (res.data[i].content == list.value[x].content) { if (res.data[i].content == list.value[x].content) {
// 如果存在相同的数据话 不进入 // 如果存在相同的数据话 不进入
indexFlag = true indexFlag = true
} }
} }
if (!indexFlag) { if (!indexFlag) {
(res.data[i] as any).sort = list.value.length + 1 ;(res.data[i] as any).sort = list.value.length + 1
list.value.push(res.data[i]) list.value.push(res.data[i])
} }
} }
@@ -576,7 +595,8 @@ const submitPptxPoints = async () => {
// pptxPointsList.value = [] // pptxPointsList.value = []
} }
const formRules = reactive<FormRules>({ const formRules = reactive<FormRules>({
status: [{ required: true, message: '启用状态必填', trigger: 'blur' }] status: [{ required: true, message: '启用状态必填', trigger: 'blur' }],
pointNames: [{ required: true, message: '知识点必填', trigger: 'blur' }]
}) })
const formRef = ref() // 表单 Ref const formRef = ref() // 表单 Ref
// 左侧试题描述 // 左侧试题描述
@@ -638,7 +658,7 @@ const deleteUrl = (index: number) => {
const handleUploadSuccess = ({ url, fileType }) => { const handleUploadSuccess = ({ url, fileType }) => {
const index = documentList.value.findIndex((item) => item.fileType === fileType) const index = documentList.value.findIndex((item) => item.fileType === fileType)
if (index !== -1) { if (index !== -1) {
documentList.value[index].url = url1 documentList.value[index].url = url
} }
} }
/** 打开弹窗 */ /** 打开弹窗 */
@@ -654,8 +674,8 @@ const open = async (queryParams: any, type: string, id?: number) => {
const res = await QuestionApi.getQuestion(id) const res = await QuestionApi.getQuestion(id)
formData.value = res formData.value = res
console.log(formData.value) console.log(formData.value)
list.value = formData.value.answerList as any[] list.value = formData.value.answerList as any[]
documentList.value = res.fileUploads as any[] documentList.value = res.fileUploads as any[]
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@@ -976,7 +996,7 @@ const openPoints = async () => {
padding: 0 20px 20px 20px; padding: 0 20px 20px 20px;
} }
.dialog-scroll-content { .dialog-scroll-content {
height: 400px; height: 350px;
overflow-y: auto; overflow-y: auto;
} }
</style> </style>

View File

@@ -139,9 +139,10 @@
v-loading="loading" v-loading="loading"
:data="list" :data="list"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
style="width: 100%"
> >
<!-- <el-table-column type="selection" width="55" /> --> <!-- <el-table-column type="selection" width="55" /> -->
<el-table-column label="考点" align="center" prop="contentIn" width="360px" /> <el-table-column label="考点" align="center" prop="contentIn"/>
<el-table-column label="权值" align="center" prop="scoreRate" width="100px" /> <el-table-column label="权值" align="center" prop="scoreRate" width="100px" />
<el-table-column label="操作" align="center" width="100px"> <el-table-column label="操作" align="center" width="100px">
<template #default="scope"> <template #default="scope">
@@ -294,18 +295,17 @@
/> />
</div> </div>
<div style="flex: 1.5; overflow: auto; border: 1px solid #eee; padding: 8px"> <div style="flex: 1.5; overflow: auto; border: 1px solid #eee; padding: 8px; width: 90%;">
<h3>考点详情</h3> <h3>考点详情</h3>
<el-table :data="list" style="width: 100%"> <el-table :data="list" style="width: 100%">
<el-table-column prop="contentIn" label="值" width="500px" /> <el-table-column prop="contentIn" label="值" />
<el-table-column prop="scoreRate" label="权值" width="100px">
<el-table-column prop="scoreRate" label="权值" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model="row.scoreRate" size="small" style="width: 40px" /> <el-input v-model="row.scoreRate" size="small" style="width: 50px" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="100"> <el-table-column label="操作" width="100px">
<template #default="{ row }"> <template #default="{ row }">
<span <span
@click="removePoint(row)" @click="removePoint(row)"
@@ -364,7 +364,15 @@ defineOptions({ name: 'WpsWordFrom' })
const wordPointsList = ref<Tree[]>([]) // 树形结构 const wordPointsList = ref<Tree[]>([]) // 树形结构
const wordPointsInfoList = ref<Tree[]>([]) // 树形结构 const wordPointsInfoList = ref<Tree[]>([]) // 树形结构
const list = ref([]) // 列表的数 // 明确 list 类型,避免 never[] 类型报错
interface AnswerItem {
image: string;
content: string;
contentIn: string;
scoreRate: string;
[key: string]: any;
}
const list = ref<AnswerItem[]>([])
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const loading = ref(false) // 列表的加载中 const loading = ref(false) // 列表的加载中
@@ -417,7 +425,16 @@ const formData = ref({
] ]
}) })
let wordPointsInfosList: (typeof wordPoints)[] = [] // 定义 wordPointsInfosList 类型,避免 wordPoints 未定义报错
interface WordPointsInfo {
firstName: string;
index: string;
function: string;
examName: string;
examCode: string;
method?: string;
}
let wordPointsInfosList: WordPointsInfo[] = []
const removePoint = (row) => { const removePoint = (row) => {
// list.value.splice(index, 1) // list.value.splice(index, 1)
for (let i = 0; i < list.value.length; i++) { for (let i = 0; i < list.value.length; i++) {
@@ -426,7 +443,7 @@ const removePoint = (row) => {
} }
} }
} }
function fileTypeFormatter(row, column, cellValue) { function fileTypeFormatter(_row: any, _column: any, cellValue: string) {
if (cellValue === '0') return '素材文件(上传ZIP)' if (cellValue === '0') return '素材文件(上传ZIP)'
if (cellValue === '1') return '考试文件' if (cellValue === '1') return '考试文件'
if (cellValue === '2') return '结果文件' if (cellValue === '2') return '结果文件'
@@ -455,33 +472,31 @@ const documentList = ref([
const dialogFormVisibleWordInfo = ref(false) const dialogFormVisibleWordInfo = ref(false)
const dialogFormVisibleWordInfos = ref(false) const dialogFormVisibleWordInfos = ref(false)
const titles = ref('') const titles = ref('')
const filePath = ref('') // 已声明未用,注释掉避免报错
// const filePath = ref('')
const handleCheckChange = (data: Tree, checked: boolean, indeterminate: boolean) => { // Tree 类型补充 any避免类型报错
console.log(data) const handleCheckChange = (data: any, _checked: boolean, _indeterminate: boolean) => {
const wordPoints = { const wordPoints: WordPointsInfo = {
firstName: '', firstName: chineseName.value,
index: '', index: textIndex.value,
function: '', function: data.functions ?? '',
examName: '', examName: data.chineseName ?? '',
examCode: '' examCode: '111',
method: data.parameter ?? ''
} }
if (data.functions != null && data.functions != '') { if (wordPoints.function) {
wordPoints.firstName = chineseName.value
wordPoints.index = textIndex.value
wordPoints.function = data.functions
wordPoints.examName = data.chineseName
wordPoints.examCode = '111'
wordPoints.method = data.parameter
wordPointsInfosList.push(cloneDeep(wordPoints)) wordPointsInfosList.push(cloneDeep(wordPoints))
} }
} }
const file = ref() const file = ref<any>()
// 获取docx文件并使用文件流进行解析 // 获取docx文件并使用文件流进行解析
const getDocxDataInfo = async () => { const getDocxDataInfo = async () => {
const fileInput = document.getElementById('docxFile') as HTMLInputElement const fileInput = document.getElementById('docxFile') as HTMLInputElement
if (fileInput != null) { if (fileInput != null) {
file.value = fileInput.files[0] if (fileInput.files && fileInput.files.length > 0) {
file.value = fileInput.files[0]
}
const res = await WordApi.getWordDataInfo({ file: file.value }) const res = await WordApi.getWordDataInfo({ file: file.value })
wordPointsList.value = [] wordPointsList.value = []
wordPointsList.value.push(...handleTree(res.data)) wordPointsList.value.push(...handleTree(res.data))
@@ -493,9 +508,9 @@ const addWordForm = async () => {
dialogFormVisibleWordInfo.value = true dialogFormVisibleWordInfo.value = true
} }
const queryParams = reactive({ // const queryParams = reactive({
nodeFunction: undefined // nodeFunction: undefined
}) // })
const chineseName = ref('') const chineseName = ref('')
const textIndex = ref() const textIndex = ref()
@@ -521,11 +536,11 @@ const handleNodelClick = async (row: any) => {
wordPointsInfoList.value.push(...handleTree(res)) wordPointsInfoList.value.push(...handleTree(res))
dialogFormVisibleWordInfos.value = true dialogFormVisibleWordInfos.value = true
} }
const handleDelete = (row) => { const handleDelete = (row: any) => {
console.log(row)
for (let i = 0; i < list.value.length; i++) { for (let i = 0; i < list.value.length; i++) {
if (row.content == list.value[i].content) { if ((row.content ?? row.contentIn) == (list.value[i].content ?? list.value[i].contentIn)) {
list.value.splice(i, 1) list.value.splice(i, 1)
break
} }
} }
} }
@@ -550,14 +565,14 @@ const submitWordPoints = async () => {
res.data[i].scoreRate='1' res.data[i].scoreRate='1'
var indexFlag = false var indexFlag = false
for (let x = 0; x < list.value.length; x++) { for (let x = 0; x < list.value.length; x++) {
if (res.data[i].content == list.value[x].content) { if ((res.data[i].content ?? res.data[i].contentIn) == (list.value[x].content ?? list.value[x].contentIn)) {
// 如果存在相同的数据话 不进入 // 如果存在相同的数据话 不进入
indexFlag = true indexFlag = true
} }
} }
if (!indexFlag) { if (!indexFlag) {
res.data[i].sort = list.value.length + 1 res.data[i].sort = list.value.length + 1
list.value.push(res.data[i]) list.value.push(res.data[i] as any)
} }
} }
// wordPoints.value = { // wordPoints.value = {
@@ -590,14 +605,15 @@ const submitWordPoints = async () => {
// wordPointsList.value = [] // wordPointsList.value = []
} }
const formRules = reactive<FormRules>({ const formRules = reactive<FormRules>({
status: [{ required: true, message: '启用状态必填', trigger: 'blur' }] status: [{ required: true, message: '启用状态必填', trigger: 'blur' }],
pointNames: [{ required: true, message: '知识点必填', trigger: 'blur' }]
}) })
const formRef = ref() // 表单 Ref const formRef = ref() // 表单 Ref
// 左侧试题描述 // 左侧试题描述
const leftActiveName = ref('desc') const leftActiveName = ref('desc')
// 右侧tab // 右侧tab
const rightActiveName = ref('annex') const rightActiveName = ref('annex')
const rightHandleClick = (tab, e) => { const rightHandleClick = (tab: any) => {
rightActiveName.value = tab.paneName.value rightActiveName.value = tab.paneName.value
} }
const selections = ref([]) const selections = ref([])
@@ -647,17 +663,16 @@ const deleteUrl = (index: number) => {
formData.value.fileUploads[index].fileName = '' formData.value.fileUploads[index].fileName = ''
} }
// 媒体文件 // 媒体文件
const mediumList = ref([] as any) // const mediumList = ref([] as any)
const multipleMediumSelection = ref([] as any) // const multipleMediumSelection = ref([] as any)
const handleMediumSelectionChange = (val: any) => { // const handleMediumSelectionChange = (val: any) => {
multipleMediumSelection.value = val // multipleMediumSelection.value = val
} // }
const fileList = [] // const fileList = []
// const multipleDocumentSelection = ref([] as any)
const multipleDocumentSelection = ref([] as any) // const handleDocumentSelectionChange = (val: any) => {
const handleDocumentSelectionChange = (val: any) => { // multipleDocumentSelection.value = val
multipleDocumentSelection.value = val // }
}
const handleUploadSuccess = ({ url, fileType }) => { const handleUploadSuccess = ({ url, fileType }) => {
const index = documentList.value.findIndex((item) => item.fileType === fileType) const index = documentList.value.findIndex((item) => item.fileType === fileType)
if (index !== -1) { if (index !== -1) {
@@ -695,15 +710,15 @@ const open = async (queryParams: any, type: string, id?: number) => {
} }
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
// 转换函数:将大写字母 A-Z 映射为 0-25 // 转换函数:将大写字母 A-Z 映射为 0-25
const mappedNumber = computed(() => { // const mappedNumber = computed(() => {
const char = radio.value.toUpperCase() // const char = radio.value.toUpperCase()
const code = char.charCodeAt(0) // const code = char.charCodeAt(0)
if (code >= 65 && code <= 90) { // if (code >= 65 && code <= 90) {
return code - 65 // return code - 65
} else { // } else {
return '请输入 A-Z 的字母' // return '请输入 A-Z 的字母'
} // }
}) // })
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => { const submitForm = async () => {
@@ -819,7 +834,7 @@ const handleTreeWithLevel = (list, level = 1) => {
// 只允许点击第三级节点 // 只允许点击第三级节点
const treeRef = ref() // 引用 el-tree const treeRef = ref() // 引用 el-tree
const handleNodeClick = (data, node) => { const handleNodeClick = (data: any) => {
if (data.level === 3) { if (data.level === 3) {
formData.value.pointNames = data.id formData.value.pointNames = data.id
formData.value.pointNamesVo = data.name formData.value.pointNamesVo = data.name

View File

@@ -139,9 +139,10 @@
v-loading="loading" v-loading="loading"
:data="list" :data="list"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
style="width: 100%"
> >
<!-- <el-table-column type="selection" width="55" /> --> <!-- <el-table-column type="selection" width="55" /> -->
<el-table-column label="考点" align="center" prop="contentIn" width="360px" /> <el-table-column label="考点" align="center" prop="contentIn" />
<el-table-column label="权值" align="center" prop="scoreRate" width="100px" /> <el-table-column label="权值" align="center" prop="scoreRate" width="100px" />
<el-table-column label="操作" align="center" width="100px"> <el-table-column label="操作" align="center" width="100px">
<template #default="scope"> <template #default="scope">
@@ -294,18 +295,17 @@
/> />
</div> </div>
<div style="flex: 1.5; overflow: auto; border: 1px solid #eee; padding: 8px"> <div style="flex: 1.5; overflow: auto; border: 1px solid #eee; padding: 8px; width: 90%">
<h3>考点详情</h3> <h3>考点详情</h3>
<el-table :data="list" style="width: 100%"> <el-table :data="list" style="width: 100%">
<el-table-column prop="contentIn" label="值" width="500px" /> <el-table-column prop="contentIn" label="值" />
<el-table-column prop="scoreRate" label="权值" width="100px">
<el-table-column prop="scoreRate" label="权值" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model="row.scoreRate" size="small" style="width: 40px" /> <el-input v-model="row.scoreRate" size="small" style="width: 50px" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="100"> <el-table-column label="操作" width="100px">
<template #default="{ row }"> <template #default="{ row }">
<span <span
@click="removePoint(row)" @click="removePoint(row)"
@@ -332,57 +332,45 @@
@check-change="handleCheckChange" @check-change="handleCheckChange"
/> />
<!-- 当是单元格类型时显示可添加/删除的输入框列表 --> <!-- 当是单元格类型时显示可添加/删除的输入框列表 -->
<!-- 单元格类型才显示 --> <!-- 单元格类型才显示 -->
<div v-if="isCellType" style="margin-bottom: 12px"> <div v-if="isCellType" style="margin-bottom: 12px">
<!-- 上方输入框和添加按钮 --> <!-- 上方输入框和添加按钮 -->
<div style="display: flex; gap: 8px; margin-bottom: 8px"> <div style="display: flex; gap: 8px; margin-bottom: 8px">
<!-- 单个输入框默认 --> <!-- 单个输入框默认 -->
<el-input <el-input
v-if="selectedType !== 'range'" v-if="selectedType !== 'range'"
v-model="cellInputValue" v-model="cellInputValue"
:placeholder="getPlaceholder(selectedType)" :placeholder="getPlaceholder(selectedType)"
style="flex: 1" style="flex: 1"
/> />
<!-- 两个输入框用冒号拼接 --> <!-- 两个输入框用冒号拼接 -->
<template v-else> <template v-else>
<el-input <el-input v-model="rangeStart" placeholder="开始单元格" style="flex: 1" />
v-model="rangeStart"
placeholder="开始单元格"
style="flex: 1"
/>
<span>:</span> <span>:</span>
<el-input <el-input v-model="rangeEnd" placeholder="结束单元格" style="flex: 1" />
v-model="rangeEnd"
placeholder="结束单元格"
style="flex: 1"
/>
</template> </template>
<el-button type="primary" @click="addCellValue">确定</el-button> <el-button type="primary" @click="addCellValue">确定</el-button>
</div>
<!-- 下方列表多选可删除 -->
<el-table
:data="cellValues"
border
size="small"
style="width: 100%; margin-bottom: 8px"
@selection-change="handleSelectionChanges"
>
<el-table-column type="selection" width="50" />
<el-table-column prop="value" label="单元格值" />
</el-table>
<el-button type="danger" :disabled="!selectedRows.length" @click="deleteSelected">
删除选中
</el-button>
</div> </div>
<!-- 下方列表多选可删除 -->
<el-table
:data="cellValues"
border
size="small"
style="width: 100%; margin-bottom: 8px"
@selection-change="handleSelectionChanges"
>
<el-table-column type="selection" width="50" />
<el-table-column prop="value" label="单元格值" />
</el-table>
<el-button
type="danger"
:disabled="!selectedRows.length"
@click="deleteSelected"
>
删除选中
</el-button>
</div>
<template #footer> <template #footer>
<el-button type="primary" @click="submitXlsxPoints"> </el-button> <el-button type="primary" @click="submitXlsxPoints"> </el-button>
<el-button @click="dialogFormVisibleXlsxInfos = false"> </el-button> <el-button @click="dialogFormVisibleXlsxInfos = false"> </el-button>
@@ -407,26 +395,24 @@ const isCellType = ref(false) // 是否单元格
const cellInputValue = ref('') // 上方输入框值 const cellInputValue = ref('') // 上方输入框值
const cellValues = ref<{ value: string }[]>([]) // 存储所有添加的数据 const cellValues = ref<{ value: string }[]>([]) // 存储所有添加的数据
const selectedRows = ref<{ value: string }[]>([]) // 多选的行 const selectedRows = ref<{ value: string }[]>([]) // 多选的行
const rangeStart = ref(""); // range 开始 const rangeStart = ref('') // range 开始
const rangeEnd = ref(""); // range 结束 const rangeEnd = ref('') // range 结束
// 添加到列表(带重复判断) // 添加到列表(带重复判断)
const addCellValue = () => { const addCellValue = () => {
if (selectedType.value === "range") { if (selectedType.value === 'range') {
if (!rangeStart.value || !rangeEnd.value) return; if (!rangeStart.value || !rangeEnd.value) return
cellValues.value.push({ cellValues.value.push({
value: rangeStart.value + ":" + rangeEnd.value value: rangeStart.value + ':' + rangeEnd.value
}); })
rangeStart.value = ""; rangeStart.value = ''
rangeEnd.value = ""; rangeEnd.value = ''
} else { } else {
if (!cellInputValue.value) return; if (!cellInputValue.value) return
cellValues.value.push({ value: cellInputValue.value }); cellValues.value.push({ value: cellInputValue.value })
cellInputValue.value = ""; cellInputValue.value = ''
} }
}; }
// 表格多选事件 // 表格多选事件
const handleSelectionChanges = (rows: any[]) => { const handleSelectionChanges = (rows: any[]) => {
@@ -435,15 +421,19 @@ const handleSelectionChanges = (rows: any[]) => {
// 删除选中项 // 删除选中项
const deleteSelected = () => { const deleteSelected = () => {
cellValues.value = cellValues.value.filter( cellValues.value = cellValues.value.filter((item) => !selectedRows.value.includes(item))
item => !selectedRows.value.includes(item)
)
selectedRows.value = [] selectedRows.value = []
} }
// 明确 list 类型,避免 never[] 类型报错
interface AnswerItem {
const list = ref([]) // 列表的数 image: string;
content: string;
contentIn: string;
scoreRate: string;
[key: string]: any;
}
const list = ref<AnswerItem[]>([])
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const loading = ref(false) // 列表的加载中 const loading = ref(false) // 列表的加载中
@@ -496,15 +486,25 @@ const formData = ref({
] ]
}) })
let xlsxPointsInfosList: (typeof xlsxPoints)[] = [] // 定义 xlsxPointsInfosList 类型,避免 xlsxPoints 未定义报错
const removePoint = (row) => { interface XlsxPointsInfo {
firstName: string;
index: string;
function: string;
examName: string;
examCode: string;
method?: string;
}
let xlsxPointsInfosList: XlsxPointsInfo[] = []
const removePoint = (row: any) => {
for (let i = 0; i < list.value.length; i++) { for (let i = 0; i < list.value.length; i++) {
if (row.content == list.value[i].content) { if ((row.content ?? row.contentIn) == (list.value[i].content ?? list.value[i].contentIn)) {
list.value.splice(i, 1) list.value.splice(i, 1)
break
} }
} }
} }
function fileTypeFormatter(row, column, cellValue) { function fileTypeFormatter(_row: any, _column: any, cellValue: string) {
if (cellValue === '0') return '素材文件(上传ZIP)' if (cellValue === '0') return '素材文件(上传ZIP)'
if (cellValue === '1') return '考试文件' if (cellValue === '1') return '考试文件'
if (cellValue === '2') return '结果文件' if (cellValue === '2') return '结果文件'
@@ -533,37 +533,36 @@ const documentList = ref([
const dialogFormVisibleXlsxInfo = ref(false) const dialogFormVisibleXlsxInfo = ref(false)
const dialogFormVisibleXlsxInfos = ref(false) const dialogFormVisibleXlsxInfos = ref(false)
const titles = ref('') const titles = ref('')
const filePath = ref('') // 已声明未用,注释掉避免报错
// const filePath = ref('')
const handleCheckChange = (data: Tree, checked: boolean, indeterminate: boolean) => { // Tree 类型补充 any避免类型报错
console.log(data+"handleCheckChange") const handleCheckChange = (data: any, _checked: boolean, _indeterminate: boolean) => {
const xlsxPoints = { // 兼容属性名
firstName: '', const xlsxPoints: XlsxPointsInfo = {
index: '', firstName: chineseName.value,
function: '', index: textIndex.value,
examName: '', function: data.functions ?? '',
examCode: '' examName: data.chineseName ?? '',
examCode: '111',
method: data.parameter ?? ''
} }
if (data.functions != null && data.functions != '') { if (xlsxPoints.function) {
xlsxPoints.firstName = chineseName.value
xlsxPoints.index = textIndex.value
xlsxPoints.function = data.functions
xlsxPoints.examName = data.chineseName
xlsxPoints.examCode = '111'
xlsxPoints.method = data.parameter
xlsxPointsInfosList.push(cloneDeep(xlsxPoints)) xlsxPointsInfosList.push(cloneDeep(xlsxPoints))
} }
} }
const file = ref() const file = ref<any>()
// 获取xlsx文件并使用文件流进行解析 // 获取xlsx文件并使用文件流进行解析
const getXlsxDataInfo = async () => { const getXlsxDataInfo = async () => {
const fileInput = document.getElementById('xlsxFile') as HTMLInputElement const fileInput = document.getElementById('xlsxFile') as HTMLInputElement
if (fileInput != null) { if (fileInput != null) {
file.value = fileInput.files[0] if (fileInput.files && fileInput.files.length > 0) {
file.value = fileInput.files[0]
}
const res = await XlsxApi.getXlsxDataInfo({ file: file.value }) const res = await XlsxApi.getXlsxDataInfo({ file: file.value })
xlsxPointsList.value = [] xlsxPointsList.value = []
xlsxPointsList.value.push(...handleTree(res.data)) xlsxPointsList.value.push(...handleTree(res.data))
} }
} }
// 打开考点窗口 // 打开考点窗口
@@ -578,15 +577,16 @@ const selectedType = ref('cell') // 初始值随便设
const handleNodelClick = async (row: any) => { const handleNodelClick = async (row: any) => {
// 获取名称 // 获取名称
chineseName.value = '【' + row.name + '】' chineseName.value = '【' + row.name + '】'
// 判断是否是单元格 // 判断是否是单元格
isCellType.value = row.type === 'cell'||row.type === 'range'||row.type === 'row'||row.type === 'col' isCellType.value =
row.type === 'cell' || row.type === 'range' || row.type === 'row' || row.type === 'col'
if (isCellType.value) { if (isCellType.value) {
selectedType.value = row.type // 点击节点时更新 selectedType.value = row.type // 点击节点时更新
cellInputValue.value =""; cellInputValue.value = ''
cellValues.value = [] // 新的 cell 节点清空数据 cellValues.value = [] // 新的 cell 节点清空数据
} }
console.log(row.index+"row.indexrow.index") console.log(row.index + 'row.indexrow.index')
textIndex.value = row.index textIndex.value = row.index
const res = await XlsxApi.getXlsxByNameList(row.type) const res = await XlsxApi.getXlsxByNameList(row.type)
xlsxPointsInfoList.value = [] xlsxPointsInfoList.value = []
@@ -595,69 +595,66 @@ console.log(row.index+"row.indexrow.index")
} }
const getPlaceholder = (type) => { const getPlaceholder = (type) => {
console.log(type+"typetypetype") console.log(type + 'typetypetype')
switch (type) { switch (type) {
case 'cell': case 'cell':
return '请输入单元格(如 A1'; return '请输入单元格(如 A1'
case 'range': case 'range':
return '请输入范围(如 A1:B5'; return '请输入范围(如 A1:B5'
case 'row': case 'row':
return '请输入行号(如 3'; return '请输入行号(如 3'
case 'col': case 'col':
return '请输入列号(如 B'; return '请输入列号(如 B'
default: default:
return '请输入值'; return '请输入值'
} }
} }
const handleDelete = (row: any) => {
const handleDelete = (row) => {
console.log(row)
for (let i = 0; i < list.value.length; i++) { for (let i = 0; i < list.value.length; i++) {
if (row.content == list.value[i].content) { if ((row.content ?? row.contentIn) == (list.value[i].content ?? list.value[i].contentIn)) {
list.value.splice(i, 1) list.value.splice(i, 1)
break
} }
} }
} }
const submitXlsxPoints = async () => { const submitXlsxPoints = async () => {
console.log('单元格输入内容:', cellValues.value) console.log('单元格输入内容:', cellValues.value)
console.log(xlsxPointsInfosList) console.log(xlsxPointsInfosList)
const res = await XlsxApi.getXlsxMaster({ const res = await XlsxApi.getXlsxMaster({
data: JSON.stringify(xlsxPointsInfosList), data: JSON.stringify(xlsxPointsInfosList),
file: file.value, file: file.value,
cell: cellValues.value.map(item => item.value) // 提取值数组 cell: cellValues.value.map((item) => item.value) // 提取值数组
}) })
xlsxPointsInfosList = [] xlsxPointsInfosList = []
console.log(res) console.log(res)
for (let i = 0; i < res.data.length; i++) { for (let i = 0; i < res.data.length; i++) {
res.data[i].scoreRate='1' res.data[i].scoreRate = '1'
var indexFlag = false var indexFlag = false
for (let x = 0; x < list.value.length; x++) { for (let x = 0; x < list.value.length; x++) {
if (res.data[i].content == list.value[x].content) { if ((res.data[i].content ?? res.data[i].contentIn) == (list.value[x].content ?? list.value[x].contentIn)) {
// 如果存在相同的数据话 不进入 // 如果存在相同的数据话 不进入
indexFlag = true indexFlag = true
} }
} }
if (!indexFlag) { if (!indexFlag) {
res.data[i].sort = list.value.length + 1 res.data[i].sort = list.value.length + 1
list.value.push(res.data[i]) list.value.push(res.data[i] as any)
} }
} }
dialogFormVisibleXlsxInfos.value = false dialogFormVisibleXlsxInfos.value = false
} }
const formRules = reactive<FormRules>({ const formRules = reactive<FormRules>({
status: [{ required: true, message: '启用状态必填', trigger: 'blur' }] status: [{ required: true, message: '启用状态必填', trigger: 'blur' }],
pointNames: [{ required: true, message: '知识点必填', trigger: 'blur' }]
}) })
const formRef = ref() // 表单 Ref const formRef = ref() // 表单 Ref
// 左侧试题描述 // 左侧试题描述
const leftActiveName = ref('desc') const leftActiveName = ref('desc')
// 右侧tab // 右侧tab
const rightActiveName = ref('annex') const rightActiveName = ref('annex')
const rightHandleClick = (tab, e) => { const rightHandleClick = (tab: any) => {
rightActiveName.value = tab.paneName.value rightActiveName.value = tab.paneName.value
} }
const selections = ref([]) const selections = ref([])
@@ -726,7 +723,7 @@ const open = async (queryParams: any, type: string, id?: number) => {
const res = await QuestionApi.getQuestion(id) const res = await QuestionApi.getQuestion(id)
formData.value = res formData.value = res
console.log(formData.value) console.log(formData.value)
list.value = formData.value.answerList list.value = formData.value.answerList as any[]
documentList.value = res.fileUploads documentList.value = res.fileUploads
} finally { } finally {
formLoading.value = false formLoading.value = false
@@ -858,7 +855,7 @@ const handleTreeWithLevel = (list, level = 1) => {
// 只允许点击第三级节点 // 只允许点击第三级节点
const treeRef = ref() // 引用 el-tree const treeRef = ref() // 引用 el-tree
const handleNodeClick = (data, node) => { const handleNodeClick = (data: any) => {
if (data.level === 3) { if (data.level === 3) {
formData.value.pointNames = data.id formData.value.pointNames = data.id
formData.value.pointNamesVo = data.name formData.value.pointNamesVo = data.name