Compare commits
6 Commits
162a84840c
...
f4c08aab7d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4c08aab7d | ||
|
|
31d8dd05ef | ||
|
|
4ef224fc7a | ||
|
|
f64eb03ccd | ||
|
|
502b4aa154 | ||
|
|
a6edb33f1e |
@@ -4,7 +4,7 @@ NODE_ENV=production
|
||||
VITE_DEV=false
|
||||
|
||||
# 请求路径
|
||||
VITE_BASE_URL='http://localhost:48080'
|
||||
VITE_BASE_URL='http://8.153.195.62:48080'
|
||||
|
||||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
|
||||
VITE_UPLOAD_TYPE=server
|
||||
|
||||
18
package.json
18
package.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "yudao-ui-admin-vue3",
|
||||
"name": "pengchen-ui-vue3-ts",
|
||||
"version": "2.4.2-snapshot",
|
||||
"description": "基于vue3、vite4、element-plus、typesScript",
|
||||
"author": "xingyu",
|
||||
@@ -9,11 +9,11 @@
|
||||
"dev": "vite --mode env.local",
|
||||
"dev-server": "vite --mode dev",
|
||||
"ts:check": "vue-tsc --noEmit",
|
||||
"build:local": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build",
|
||||
"build:dev": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode dev",
|
||||
"build:test": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode test",
|
||||
"build:stage": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode stage",
|
||||
"build:prod": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode prod",
|
||||
"build:local": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build",
|
||||
"build:dev": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode dev",
|
||||
"build:test": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode test",
|
||||
"build:stage": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode stage",
|
||||
"build:prod": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode prod",
|
||||
"serve:dev": "vite preview --mode dev",
|
||||
"serve:prod": "vite preview --mode prod",
|
||||
"preview": "pnpm build:local && vite preview",
|
||||
@@ -145,12 +145,12 @@
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://gitee.com/yudaocode/yudao-ui-admin-vue3"
|
||||
"url": "git+http://47.101.60.131:10082/"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues"
|
||||
"url": "http://47.101.60.131:10082/"
|
||||
},
|
||||
"homepage": "https://gitee.com/yudaocode/yudao-ui-admin-vue3",
|
||||
"homepage": "http://47.101.60.131:10082/",
|
||||
"web-types": "./web-types.json",
|
||||
"engines": {
|
||||
"node": ">= 16.0.0",
|
||||
|
||||
@@ -40,6 +40,7 @@ export const MonitorApi = {
|
||||
deleteMonitor: async (id: number) => {
|
||||
return await request.delete({ url: `/exam/monitor/delete?id=` + id })
|
||||
},
|
||||
|
||||
// 获取学生文件
|
||||
getMonitorStuFileUrl: async (temporaryId: string) => {
|
||||
return await request.get({ url: `/exam/monitor/getMonitorStuFileUrl?temporaryId=` + temporaryId })
|
||||
@@ -56,10 +57,20 @@ export const MonitorApi = {
|
||||
},
|
||||
|
||||
|
||||
updateMonitorStatus:async( data)=>{
|
||||
updateMonitorStatus: async (data) => {
|
||||
return await request.post({ url: `/exam/monitor/updateMonitorStatus` , data })
|
||||
},
|
||||
|
||||
getMonitorTaskPage: async (params: any) => {
|
||||
return await request.get({ url: `/exam/monitorTask/page`, params })
|
||||
},
|
||||
|
||||
stopExamForAdmin: async (params: any) => {
|
||||
return await request.get({ url: `/tool/stopExamForAdmin?userId=`+ params.userId + `&taskId=` + params.taskId + `&paperNum=` + params.paperNum})
|
||||
},
|
||||
|
||||
reStartExamForAdmin: async (data) => {
|
||||
return await request.post({ url: `/tool/reStartExamForAdmin` , data })
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
@@ -209,50 +209,7 @@ const getCount = async () => {
|
||||
// 获取项目数
|
||||
let projects = reactive<Project[]>([])
|
||||
const getProject = async () => {
|
||||
const data = [
|
||||
{
|
||||
name: 'ruoyi-vue-pro',
|
||||
icon: 'akar-icons:github-fill',
|
||||
message: 'https://github.com/YunaiV/ruoyi-vue-pro',
|
||||
personal: 'Spring Boot 单体架构',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'yudao-ui-admin-vue3',
|
||||
icon: 'logos:vue',
|
||||
message: 'https://github.com/yudaocode/yudao-ui-admin-vue3',
|
||||
personal: 'Vue3 + element-plus',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'yudao-ui-admin-vben',
|
||||
icon: 'logos:vue',
|
||||
message: 'https://github.com/yudaocode/yudao-ui-admin-vben',
|
||||
personal: 'Vue3 + vben(antd)',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'yudao-cloud',
|
||||
icon: 'akar-icons:github',
|
||||
message: 'https://github.com/YunaiV/yudao-cloud',
|
||||
personal: 'Spring Cloud 微服务架构',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'yudao-ui-mall-uniapp',
|
||||
icon: 'logos:vue',
|
||||
message: 'https://github.com/yudaocode/yudao-ui-admin-uniapp',
|
||||
personal: 'Vue3 + uniapp',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'yudao-ui-admin-vue2',
|
||||
icon: 'logos:vue',
|
||||
message: 'https://github.com/yudaocode/yudao-ui-admin-vue2',
|
||||
personal: 'Vue2 + element-ui',
|
||||
time: new Date()
|
||||
}
|
||||
]
|
||||
const data = []
|
||||
projects = Object.assign(projects, data)
|
||||
}
|
||||
|
||||
|
||||
@@ -275,7 +275,10 @@ const loginOutAdminPassword = async () => {
|
||||
isTrueLoginForAdminPassWord.value = false
|
||||
}
|
||||
}).catch((err) => {
|
||||
message.error(err.msg)
|
||||
ElMessageBox.alert('管理员密码错误,请重新输入!', '提示', {
|
||||
confirmButtonText: '确认',
|
||||
type: 'error',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -166,12 +166,10 @@ import {
|
||||
} from '@/api/iot/statistics'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
|
||||
// TODO @super:参考下 /Users/yunai/Java/yudao-ui-admin-vue3/src/views/mall/home/index.vue,拆一拆组件
|
||||
|
||||
/** IoT 首页 */
|
||||
defineOptions({ name: 'IoTHome' })
|
||||
|
||||
// TODO @super:使用下 Echart 组件,参考 yudao-ui-admin-vue3/src/views/mall/home/components/TradeTrendCard.vue 等
|
||||
echarts.use([
|
||||
TooltipComponent,
|
||||
LegendComponent,
|
||||
|
||||
@@ -1,21 +1,4 @@
|
||||
<template>
|
||||
<!-- 状态选择弹窗 -->
|
||||
<el-dialog v-model="dialogVisible" title="请选择考试状态" width="400px">
|
||||
<el-form label-width="80px" class="px-4 pt-2">
|
||||
<el-form-item label="考试状态">
|
||||
<el-radio-group v-model="selectedStatus">
|
||||
<el-radio :label="'0'">待考</el-radio>
|
||||
<el-radio :label="'1'">考试中</el-radio>
|
||||
<el-radio :label="'2'">考试完成</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmChange">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="initDialogVisible"
|
||||
title="试卷任务监控列表"
|
||||
@@ -112,9 +95,9 @@
|
||||
<el-select v-model="queryParams.taskName" placeholder="请选择试卷任务" class="!w-240px">
|
||||
<el-option
|
||||
v-for="item in taskList"
|
||||
:key="item.taskName"
|
||||
:label="item.taskName"
|
||||
:value="item.taskName"
|
||||
:key="item?.taskName ?? ''"
|
||||
:label="item?.taskName ?? ''"
|
||||
:value="item?.taskName ?? ''"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -188,27 +171,18 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="试卷任务" align="center" prop="taskName" />
|
||||
<el-table-column label="机器ip" align="center" prop="ip" />
|
||||
<el-table-column label="机器ip" align="center" prop="ip" width="180px"/>
|
||||
<el-table-column
|
||||
label="剩余时间"
|
||||
align="center"
|
||||
prop="remainingTime"
|
||||
:formatter="dateFormatterMin"
|
||||
width="180px"
|
||||
/>
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
align="center"
|
||||
prop="createTime"
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
/>
|
||||
|
||||
/>
|
||||
<el-table-column label="操作" align="center" min-width="120px">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="downloadFile(scope.row)">
|
||||
下载
|
||||
</el-button>
|
||||
<el-button link type="primary" @click="getMonitorInfo(scope.row)"> 详情 </el-button>
|
||||
<el-button link type="primary" @click="downloadFile(scope.row)"> 下载 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -220,7 +194,112 @@
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
<!-- 状态选择弹窗 -->
|
||||
<el-dialog v-model="dialogVisible" title="参数设置" width="400px" center>
|
||||
<strong style="color: chocolate"
|
||||
>*只有状态为考试中的考试才可以增加时间,增加的时间的同时,并勾选考试中.</strong
|
||||
>
|
||||
<el-form label-width="80px" class="px-4 pt-2">
|
||||
<el-form-item label="考试状态">
|
||||
<el-radio-group v-model="selectedStatus">
|
||||
<el-radio :label="'0'">待考</el-radio>
|
||||
<el-radio :label="'1'">考试中</el-radio>
|
||||
<el-radio :label="'2'">考试完成</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="增加时长">
|
||||
<el-time-picker
|
||||
v-model="times"
|
||||
value-format="HH:mm:ss"
|
||||
placeholder="请增加时长"
|
||||
class="ele-fluid"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmChange">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 详情 -->
|
||||
<el-dialog v-model="dialogVisibleForInfo" title="详情" width="600px" center>
|
||||
<el-form ref="formRef" :model="formData" label-width="90px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="姓名:" prop="nickname">
|
||||
{{ formData.nickname }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户名:" prop="username">
|
||||
{{ formData.username }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="班级:" prop="className">
|
||||
{{ formData.className }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="试卷任务:" prop="taskName">
|
||||
{{ formData.taskName }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="试卷编号:" prop="paperNum">
|
||||
{{ formData.paperNum }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="分数:" prop="score">
|
||||
{{ formData.score }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="剩余时间:" prop="remainingTime">
|
||||
{{ formData.remainingTime }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="IP地址:" prop="ip">
|
||||
{{ formData.ip }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开始时间:" prop="startTime">
|
||||
{{ formData.startTime }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="结束时间:" prop="endTime">
|
||||
{{ formData.endTime }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="考试状态:" prop="examStatus">
|
||||
<dict-tag :type="DICT_TYPE.EXAM_STATUS" :value="formData.examStatus" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务模式:" prop="taskType">
|
||||
<dict-tag :type="DICT_TYPE.TASK_TYPE" :value="formData.taskType" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<!-- <MonitorForm ref="formRef" @success="getList" /> -->
|
||||
</template>
|
||||
@@ -233,8 +312,9 @@ import MonitorForm from './MonitorForm.vue'
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import taskMonitor from './task-monitor.vue'
|
||||
import * as ClassApi from '@/api/exam/class'
|
||||
|
||||
const formData = ref<any>({})
|
||||
import { ref } from 'vue'
|
||||
import { getInfo } from '@/api/login'
|
||||
|
||||
const selectedTaskId = ref<string | null>(null)
|
||||
const fixedTaskId = ref('')
|
||||
@@ -250,9 +330,11 @@ defineOptions({ name: 'Monitor' })
|
||||
const initDialogVisible = ref(true)
|
||||
// 弹窗开关
|
||||
const dialogVisible = ref(false)
|
||||
const dialogVisibleForInfo = ref(false)
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { t } = useI18n() // 国际化
|
||||
const selectedStatus = ref<string | null>(null)
|
||||
const selectedStatus = ref<string>('')
|
||||
const times = ref<string>('')
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<MonitorVO[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
@@ -260,7 +342,7 @@ const classNameList = ref()
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
monitorId: undefined,
|
||||
monitorId: '',
|
||||
taskId: '',
|
||||
username: undefined,
|
||||
nickname: undefined,
|
||||
@@ -272,7 +354,8 @@ const queryParams = reactive({
|
||||
taskName: undefined,
|
||||
ip: undefined,
|
||||
remainingTime: [],
|
||||
createTime: []
|
||||
startTime: undefined,
|
||||
endTime: undefined
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
const exportLoading = ref(false) // 导出的加载中
|
||||
@@ -311,11 +394,15 @@ const returnTop = async () => {
|
||||
|
||||
/** 表格选中数据 */
|
||||
const selections = ref([])
|
||||
const taskList = ref([])
|
||||
interface TaskItem {
|
||||
taskName: string
|
||||
[key: string]: any
|
||||
}
|
||||
const taskList = ref<TaskItem[]>([])
|
||||
const handleSelectionChange = (rows) => {
|
||||
selections.value = rows
|
||||
}
|
||||
const dateFormatterMin = (row, column, cellValue) => {
|
||||
const dateFormatterMin = (_row: any, _column: any, cellValue: number) => {
|
||||
if (cellValue == null || isNaN(cellValue)) return '-'
|
||||
|
||||
const hours = Math.floor(cellValue / 3600)
|
||||
@@ -323,7 +410,7 @@ const dateFormatterMin = (row, column, cellValue) => {
|
||||
const seconds = cellValue % 60
|
||||
|
||||
// 补零处理
|
||||
const pad = (n) => n.toString().padStart(2, '0')
|
||||
const pad = (n: number) => n.toString().padStart(2, '0')
|
||||
|
||||
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`
|
||||
}
|
||||
@@ -347,10 +434,10 @@ const openForm = (type: string, id?: number) => {
|
||||
}
|
||||
// 提交状态变更
|
||||
const confirmChange = async () => {
|
||||
if (selectedStatus.value === null) {
|
||||
ElMessage.error('请选择考试状态')
|
||||
return
|
||||
}
|
||||
// if (selectedStatus.value === null) {
|
||||
// ElMessage.error('请选择考试状态')
|
||||
// return
|
||||
// }
|
||||
|
||||
const rows = selections.value
|
||||
|
||||
@@ -358,12 +445,31 @@ const confirmChange = async () => {
|
||||
|
||||
await MonitorApi.updateMonitorStatus({
|
||||
monitorIds, // 这是数组
|
||||
status: selectedStatus.value // 这是 0,1,2
|
||||
status: selectedStatus.value, // 这是 0,1,2
|
||||
times: times.value // 这是 "HH:mm:ss"
|
||||
}).then((res) => {
|
||||
// 清空选择
|
||||
selections.value = []
|
||||
selectedStatus.value = ''
|
||||
times.value = ''
|
||||
console.log(res)
|
||||
if (res.type === 'STOP') {
|
||||
MonitorApi.stopExamForAdmin({
|
||||
stuId: res.stuId,
|
||||
taskId: res.taskId,
|
||||
paperNum: res.paperNum
|
||||
})
|
||||
} else {
|
||||
MonitorApi.reStartExamForAdmin({
|
||||
stuId: res.stuId,
|
||||
taskId: res.taskId,
|
||||
paperId: res.paperNum
|
||||
})
|
||||
}
|
||||
ElMessage.success('更新成功')
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
})
|
||||
|
||||
ElMessage.success('考试状态更新成功')
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
}
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
@@ -378,6 +484,11 @@ const handleDelete = async (id: number) => {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const getMonitorInfo = async (row: any) => {
|
||||
formData.value = row
|
||||
dialogVisibleForInfo.value = true
|
||||
}
|
||||
|
||||
const downloadFile = async (row: any) => {
|
||||
const res = await MonitorApi.getMonitorStuFileUrl(row.temporaryId)
|
||||
console.log(res)
|
||||
|
||||
@@ -139,9 +139,10 @@
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- <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" width="100px">
|
||||
<template #default="scope">
|
||||
@@ -283,7 +284,10 @@
|
||||
<input type="file" id="slideFile" accept=".pptx" />
|
||||
<button @click="getSlideDataInfo">文件解析</button>
|
||||
<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>
|
||||
<el-tree
|
||||
style="max-width: 600px"
|
||||
@@ -294,18 +298,17 @@
|
||||
/>
|
||||
</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>
|
||||
<el-table :data="list" style="width: 100%">
|
||||
<el-table-column prop="contentIn" label="值" width="500px" />
|
||||
|
||||
<el-table-column prop="scoreRate" label="权值" width="100">
|
||||
<el-table-column prop="contentIn" label="值" />
|
||||
<el-table-column prop="scoreRate" label="权值" width="100px">
|
||||
<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>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="100">
|
||||
<el-table-column label="操作" width="100px">
|
||||
<template #default="{ row }">
|
||||
<span
|
||||
@click="removePoint(row)"
|
||||
@@ -318,11 +321,15 @@
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <el-skeleton :rows="5" animated v-if="pptxPointsList.length < 0 && isLoading" />
|
||||
-->
|
||||
</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">
|
||||
<el-tree
|
||||
style="max-width: 600px"
|
||||
@@ -348,6 +355,7 @@ import { defaultProps, handleTree } from '@/utils/tree'
|
||||
import { FormRules } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import FileForm from './components/FileForm.vue'
|
||||
import { ElLoading } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'WpsPptxFrom' })
|
||||
const pptxPointsList = ref<Tree[]>([]) // 树形结构
|
||||
@@ -408,12 +416,12 @@ const formData = ref({
|
||||
|
||||
// 定义 pptxPoints 类型
|
||||
interface PptxPoints {
|
||||
firstName: string;
|
||||
slideIndex: string;
|
||||
function: string;
|
||||
examName: string;
|
||||
examCode: string;
|
||||
method?: string;
|
||||
firstName: string
|
||||
slideIndex: string
|
||||
function: string
|
||||
examName: string
|
||||
examCode: string
|
||||
method?: string
|
||||
}
|
||||
let pptxPointsInfosList: PptxPoints[] = []
|
||||
const removePoint = (row) => {
|
||||
@@ -477,18 +485,29 @@ const handleCheckChange = (data: any, _checked: boolean, _indeterminate: boolean
|
||||
}
|
||||
}
|
||||
const file = ref()
|
||||
|
||||
// 获取slide文件,并使用文件流进行解析
|
||||
const getSlideDataInfo = async () => {
|
||||
const fileInput = document.getElementById('slideFile') as HTMLInputElement
|
||||
if (fileInput != null) {
|
||||
if (fileInput.files && fileInput.files[0]) {
|
||||
file.value = fileInput.files[0]
|
||||
} else {
|
||||
return
|
||||
const loading = ElLoading.service({
|
||||
target: '.tree-wrap', // 只遮罩左侧树区域
|
||||
text: '正在读取考点…',
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,12 +527,21 @@ const handleNodelClick = async (row: any) => {
|
||||
return
|
||||
}
|
||||
// 获取名称
|
||||
chineseName.value = '【' + row.belongTo +'】【' + row.name + '】'
|
||||
chineseName.value = '【' + row.belongTo + '】【' + row.name + '】'
|
||||
textIndex.value = row.index
|
||||
const res = await PptxApi.getSlideByNameList(row.type)
|
||||
pptxPointsInfoList.value = []
|
||||
pptxPointsInfoList.value.push(...handleTree(res))
|
||||
dialogFormVisiblePptxInfos.value = true
|
||||
const loading = ElLoading.service({
|
||||
target: '.dialog-scroll-content', // 只遮罩左侧树区域
|
||||
text: '正在读取详细考点…',
|
||||
background: 'rgba(255,255,255,0.6)'
|
||||
})
|
||||
try {
|
||||
const res = await PptxApi.getSlideByNameList(row.type)
|
||||
pptxPointsInfoList.value = []
|
||||
pptxPointsInfoList.value.push(...handleTree(res))
|
||||
dialogFormVisiblePptxInfos.value = true
|
||||
} finally {
|
||||
loading.close()
|
||||
}
|
||||
}
|
||||
const handleDelete = (row) => {
|
||||
console.log(row)
|
||||
@@ -535,14 +563,14 @@ const submitPptxPoints = async () => {
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
var indexFlag = false
|
||||
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) {
|
||||
// 如果存在相同的数据话 不进入
|
||||
indexFlag = true
|
||||
}
|
||||
}
|
||||
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])
|
||||
}
|
||||
}
|
||||
@@ -576,7 +604,8 @@ const submitPptxPoints = async () => {
|
||||
// pptxPointsList.value = []
|
||||
}
|
||||
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
|
||||
// 左侧试题描述
|
||||
@@ -638,7 +667,7 @@ const deleteUrl = (index: number) => {
|
||||
const handleUploadSuccess = ({ url, fileType }) => {
|
||||
const index = documentList.value.findIndex((item) => item.fileType === fileType)
|
||||
if (index !== -1) {
|
||||
documentList.value[index].url = url1
|
||||
documentList.value[index].url = url
|
||||
}
|
||||
}
|
||||
/** 打开弹窗 */
|
||||
@@ -654,8 +683,8 @@ const open = async (queryParams: any, type: string, id?: number) => {
|
||||
const res = await QuestionApi.getQuestion(id)
|
||||
formData.value = res
|
||||
console.log(formData.value)
|
||||
list.value = formData.value.answerList as any[]
|
||||
documentList.value = res.fileUploads as any[]
|
||||
list.value = formData.value.answerList as any[]
|
||||
documentList.value = res.fileUploads as any[]
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
@@ -976,7 +1005,7 @@ const openPoints = async () => {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
.dialog-scroll-content {
|
||||
height: 400px;
|
||||
height: 350px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -139,9 +139,10 @@
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- <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" width="100px">
|
||||
<template #default="scope">
|
||||
@@ -294,18 +295,17 @@
|
||||
/>
|
||||
</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>
|
||||
<el-table :data="list" style="width: 100%">
|
||||
<el-table-column prop="contentIn" label="值" width="500px" />
|
||||
|
||||
<el-table-column prop="scoreRate" label="权值" width="100">
|
||||
<el-table-column prop="contentIn" label="值" />
|
||||
<el-table-column prop="scoreRate" label="权值" width="100px">
|
||||
<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>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="100">
|
||||
<el-table-column label="操作" width="100px">
|
||||
<template #default="{ row }">
|
||||
<span
|
||||
@click="removePoint(row)"
|
||||
@@ -364,7 +364,15 @@ defineOptions({ name: 'WpsWordFrom' })
|
||||
const wordPointsList = 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 message = useMessage() // 消息弹窗
|
||||
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) => {
|
||||
// list.value.splice(index, 1)
|
||||
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 === '1') return '考试文件'
|
||||
if (cellValue === '2') return '结果文件'
|
||||
@@ -455,33 +472,31 @@ const documentList = ref([
|
||||
const dialogFormVisibleWordInfo = ref(false)
|
||||
const dialogFormVisibleWordInfos = ref(false)
|
||||
const titles = ref('')
|
||||
const filePath = ref('')
|
||||
// 已声明未用,注释掉避免报错
|
||||
// const filePath = ref('')
|
||||
|
||||
const handleCheckChange = (data: Tree, checked: boolean, indeterminate: boolean) => {
|
||||
console.log(data)
|
||||
const wordPoints = {
|
||||
firstName: '',
|
||||
index: '',
|
||||
function: '',
|
||||
examName: '',
|
||||
examCode: ''
|
||||
// Tree 类型补充 any,避免类型报错
|
||||
const handleCheckChange = (data: any, _checked: boolean, _indeterminate: boolean) => {
|
||||
const wordPoints: WordPointsInfo = {
|
||||
firstName: chineseName.value,
|
||||
index: textIndex.value,
|
||||
function: data.functions ?? '',
|
||||
examName: data.chineseName ?? '',
|
||||
examCode: '111',
|
||||
method: data.parameter ?? ''
|
||||
}
|
||||
if (data.functions != null && data.functions != '') {
|
||||
wordPoints.firstName = chineseName.value
|
||||
wordPoints.index = textIndex.value
|
||||
wordPoints.function = data.functions
|
||||
wordPoints.examName = data.chineseName
|
||||
wordPoints.examCode = '111'
|
||||
wordPoints.method = data.parameter
|
||||
if (wordPoints.function) {
|
||||
wordPointsInfosList.push(cloneDeep(wordPoints))
|
||||
}
|
||||
}
|
||||
const file = ref()
|
||||
const file = ref<any>()
|
||||
// 获取docx文件,并使用文件流进行解析
|
||||
const getDocxDataInfo = async () => {
|
||||
const fileInput = document.getElementById('docxFile') as HTMLInputElement
|
||||
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 })
|
||||
wordPointsList.value = []
|
||||
wordPointsList.value.push(...handleTree(res.data))
|
||||
@@ -493,9 +508,9 @@ const addWordForm = async () => {
|
||||
dialogFormVisibleWordInfo.value = true
|
||||
}
|
||||
|
||||
const queryParams = reactive({
|
||||
nodeFunction: undefined
|
||||
})
|
||||
// const queryParams = reactive({
|
||||
// nodeFunction: undefined
|
||||
// })
|
||||
const chineseName = ref('')
|
||||
const textIndex = ref()
|
||||
|
||||
@@ -521,11 +536,11 @@ const handleNodelClick = async (row: any) => {
|
||||
wordPointsInfoList.value.push(...handleTree(res))
|
||||
dialogFormVisibleWordInfos.value = true
|
||||
}
|
||||
const handleDelete = (row) => {
|
||||
console.log(row)
|
||||
const handleDelete = (row: any) => {
|
||||
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)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -550,14 +565,14 @@ const submitWordPoints = async () => {
|
||||
res.data[i].scoreRate='1'
|
||||
var indexFlag = false
|
||||
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
|
||||
}
|
||||
}
|
||||
if (!indexFlag) {
|
||||
res.data[i].sort = list.value.length + 1
|
||||
list.value.push(res.data[i])
|
||||
list.value.push(res.data[i] as any)
|
||||
}
|
||||
}
|
||||
// wordPoints.value = {
|
||||
@@ -590,14 +605,15 @@ const submitWordPoints = async () => {
|
||||
// wordPointsList.value = []
|
||||
}
|
||||
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 leftActiveName = ref('desc')
|
||||
// 右侧tab
|
||||
const rightActiveName = ref('annex')
|
||||
const rightHandleClick = (tab, e) => {
|
||||
const rightHandleClick = (tab: any) => {
|
||||
rightActiveName.value = tab.paneName.value
|
||||
}
|
||||
const selections = ref([])
|
||||
@@ -647,17 +663,16 @@ const deleteUrl = (index: number) => {
|
||||
formData.value.fileUploads[index].fileName = ''
|
||||
}
|
||||
// 媒体文件
|
||||
const mediumList = ref([] as any)
|
||||
const multipleMediumSelection = ref([] as any)
|
||||
const handleMediumSelectionChange = (val: any) => {
|
||||
multipleMediumSelection.value = val
|
||||
}
|
||||
const fileList = []
|
||||
|
||||
const multipleDocumentSelection = ref([] as any)
|
||||
const handleDocumentSelectionChange = (val: any) => {
|
||||
multipleDocumentSelection.value = val
|
||||
}
|
||||
// const mediumList = ref([] as any)
|
||||
// const multipleMediumSelection = ref([] as any)
|
||||
// const handleMediumSelectionChange = (val: any) => {
|
||||
// multipleMediumSelection.value = val
|
||||
// }
|
||||
// const fileList = []
|
||||
// const multipleDocumentSelection = ref([] as any)
|
||||
// const handleDocumentSelectionChange = (val: any) => {
|
||||
// multipleDocumentSelection.value = val
|
||||
// }
|
||||
const handleUploadSuccess = ({ url, fileType }) => {
|
||||
const index = documentList.value.findIndex((item) => item.fileType === fileType)
|
||||
if (index !== -1) {
|
||||
@@ -695,15 +710,15 @@ const open = async (queryParams: any, type: string, id?: number) => {
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
// 转换函数:将大写字母 A-Z 映射为 0-25
|
||||
const mappedNumber = computed(() => {
|
||||
const char = radio.value.toUpperCase()
|
||||
const code = char.charCodeAt(0)
|
||||
if (code >= 65 && code <= 90) {
|
||||
return code - 65
|
||||
} else {
|
||||
return '请输入 A-Z 的字母'
|
||||
}
|
||||
})
|
||||
// const mappedNumber = computed(() => {
|
||||
// const char = radio.value.toUpperCase()
|
||||
// const code = char.charCodeAt(0)
|
||||
// if (code >= 65 && code <= 90) {
|
||||
// return code - 65
|
||||
// } else {
|
||||
// return '请输入 A-Z 的字母'
|
||||
// }
|
||||
// })
|
||||
/** 提交表单 */
|
||||
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||
const submitForm = async () => {
|
||||
@@ -819,7 +834,7 @@ const handleTreeWithLevel = (list, level = 1) => {
|
||||
|
||||
// 只允许点击第三级节点
|
||||
const treeRef = ref() // 引用 el-tree
|
||||
const handleNodeClick = (data, node) => {
|
||||
const handleNodeClick = (data: any) => {
|
||||
if (data.level === 3) {
|
||||
formData.value.pointNames = data.id
|
||||
formData.value.pointNamesVo = data.name
|
||||
|
||||
@@ -139,9 +139,10 @@
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- <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" width="100px">
|
||||
<template #default="scope">
|
||||
@@ -294,18 +295,17 @@
|
||||
/>
|
||||
</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>
|
||||
<el-table :data="list" style="width: 100%">
|
||||
<el-table-column prop="contentIn" label="值" width="500px" />
|
||||
|
||||
<el-table-column prop="scoreRate" label="权值" width="100">
|
||||
<el-table-column prop="contentIn" label="值" />
|
||||
<el-table-column prop="scoreRate" label="权值" width="100px">
|
||||
<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>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="100">
|
||||
<el-table-column label="操作" width="100px">
|
||||
<template #default="{ row }">
|
||||
<span
|
||||
@click="removePoint(row)"
|
||||
@@ -332,12 +332,12 @@
|
||||
@check-change="handleCheckChange"
|
||||
/>
|
||||
|
||||
<!-- 当是单元格类型时,显示可添加/删除的输入框列表 -->
|
||||
<!-- 单元格类型才显示 -->
|
||||
<div v-if="isCellType" style="margin-bottom: 12px">
|
||||
<!-- 上方输入框和添加按钮 -->
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 8px">
|
||||
<!-- 单个输入框(默认) -->
|
||||
<!-- 当是单元格类型时,显示可添加/删除的输入框列表 -->
|
||||
<!-- 单元格类型才显示 -->
|
||||
<div v-if="isCellType" style="margin-bottom: 12px">
|
||||
<!-- 上方输入框和添加按钮 -->
|
||||
<div style="display: flex; gap: 8px; margin-bottom: 8px">
|
||||
<!-- 单个输入框(默认) -->
|
||||
<el-input
|
||||
v-if="selectedType !== 'range'"
|
||||
v-model="cellInputValue"
|
||||
@@ -347,42 +347,30 @@
|
||||
|
||||
<!-- 两个输入框,用冒号拼接 -->
|
||||
<template v-else>
|
||||
<el-input
|
||||
v-model="rangeStart"
|
||||
placeholder="开始单元格"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<el-input v-model="rangeStart" placeholder="开始单元格" style="flex: 1" />
|
||||
<span>:</span>
|
||||
<el-input
|
||||
v-model="rangeEnd"
|
||||
placeholder="结束单元格"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<el-input v-model="rangeEnd" placeholder="结束单元格" style="flex: 1" />
|
||||
</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>
|
||||
|
||||
<!-- 下方列表(多选可删除) -->
|
||||
<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>
|
||||
<el-button type="primary" @click="submitXlsxPoints">确 定</el-button>
|
||||
<el-button @click="dialogFormVisibleXlsxInfos = false">取 消</el-button>
|
||||
@@ -407,26 +395,24 @@ const isCellType = ref(false) // 是否单元格
|
||||
const cellInputValue = ref('') // 上方输入框值
|
||||
const cellValues = ref<{ value: string }[]>([]) // 存储所有添加的数据
|
||||
const selectedRows = ref<{ value: string }[]>([]) // 多选的行
|
||||
const rangeStart = ref(""); // range 开始
|
||||
const rangeEnd = ref(""); // range 结束
|
||||
const rangeStart = ref('') // range 开始
|
||||
const rangeEnd = ref('') // range 结束
|
||||
|
||||
// 添加到列表(带重复判断)
|
||||
const addCellValue = () => {
|
||||
if (selectedType.value === "range") {
|
||||
if (!rangeStart.value || !rangeEnd.value) return;
|
||||
if (selectedType.value === 'range') {
|
||||
if (!rangeStart.value || !rangeEnd.value) return
|
||||
cellValues.value.push({
|
||||
value: rangeStart.value + ":" + rangeEnd.value
|
||||
});
|
||||
rangeStart.value = "";
|
||||
rangeEnd.value = "";
|
||||
value: rangeStart.value + ':' + rangeEnd.value
|
||||
})
|
||||
rangeStart.value = ''
|
||||
rangeEnd.value = ''
|
||||
} else {
|
||||
if (!cellInputValue.value) return;
|
||||
cellValues.value.push({ value: cellInputValue.value });
|
||||
cellInputValue.value = "";
|
||||
if (!cellInputValue.value) return
|
||||
cellValues.value.push({ value: cellInputValue.value })
|
||||
cellInputValue.value = ''
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 表格多选事件
|
||||
const handleSelectionChanges = (rows: any[]) => {
|
||||
@@ -435,15 +421,19 @@ const handleSelectionChanges = (rows: any[]) => {
|
||||
|
||||
// 删除选中项
|
||||
const deleteSelected = () => {
|
||||
cellValues.value = cellValues.value.filter(
|
||||
item => !selectedRows.value.includes(item)
|
||||
)
|
||||
cellValues.value = cellValues.value.filter((item) => !selectedRows.value.includes(item))
|
||||
selectedRows.value = []
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 message = useMessage() // 消息弹窗
|
||||
const loading = ref(false) // 列表的加载中
|
||||
@@ -496,15 +486,25 @@ const formData = ref({
|
||||
]
|
||||
})
|
||||
|
||||
let xlsxPointsInfosList: (typeof xlsxPoints)[] = []
|
||||
const removePoint = (row) => {
|
||||
// 定义 xlsxPointsInfosList 类型,避免 xlsxPoints 未定义报错
|
||||
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++) {
|
||||
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)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
function fileTypeFormatter(row, column, cellValue) {
|
||||
function fileTypeFormatter(_row: any, _column: any, cellValue: string) {
|
||||
if (cellValue === '0') return '素材文件(上传ZIP)'
|
||||
if (cellValue === '1') return '考试文件'
|
||||
if (cellValue === '2') return '结果文件'
|
||||
@@ -533,37 +533,36 @@ const documentList = ref([
|
||||
const dialogFormVisibleXlsxInfo = ref(false)
|
||||
const dialogFormVisibleXlsxInfos = ref(false)
|
||||
const titles = ref('')
|
||||
const filePath = ref('')
|
||||
// 已声明未用,注释掉避免报错
|
||||
// const filePath = ref('')
|
||||
|
||||
const handleCheckChange = (data: Tree, checked: boolean, indeterminate: boolean) => {
|
||||
console.log(data+"handleCheckChange")
|
||||
const xlsxPoints = {
|
||||
firstName: '',
|
||||
index: '',
|
||||
function: '',
|
||||
examName: '',
|
||||
examCode: ''
|
||||
// Tree 类型补充 any,避免类型报错
|
||||
const handleCheckChange = (data: any, _checked: boolean, _indeterminate: boolean) => {
|
||||
// 兼容属性名
|
||||
const xlsxPoints: XlsxPointsInfo = {
|
||||
firstName: chineseName.value,
|
||||
index: textIndex.value,
|
||||
function: data.functions ?? '',
|
||||
examName: data.chineseName ?? '',
|
||||
examCode: '111',
|
||||
method: data.parameter ?? ''
|
||||
}
|
||||
if (data.functions != null && data.functions != '') {
|
||||
xlsxPoints.firstName = chineseName.value
|
||||
xlsxPoints.index = textIndex.value
|
||||
xlsxPoints.function = data.functions
|
||||
xlsxPoints.examName = data.chineseName
|
||||
xlsxPoints.examCode = '111'
|
||||
xlsxPoints.method = data.parameter
|
||||
if (xlsxPoints.function) {
|
||||
xlsxPointsInfosList.push(cloneDeep(xlsxPoints))
|
||||
}
|
||||
}
|
||||
const file = ref()
|
||||
const file = ref<any>()
|
||||
// 获取xlsx文件,并使用文件流进行解析
|
||||
const getXlsxDataInfo = async () => {
|
||||
const fileInput = document.getElementById('xlsxFile') as HTMLInputElement
|
||||
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 })
|
||||
xlsxPointsList.value = []
|
||||
xlsxPointsList.value.push(...handleTree(res.data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打开考点窗口
|
||||
@@ -578,15 +577,16 @@ const selectedType = ref('cell') // 初始值随便设
|
||||
const handleNodelClick = async (row: any) => {
|
||||
// 获取名称
|
||||
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) {
|
||||
selectedType.value = row.type // 点击节点时更新
|
||||
cellInputValue.value ="";
|
||||
cellInputValue.value = ''
|
||||
cellValues.value = [] // 新的 cell 节点清空数据
|
||||
}
|
||||
|
||||
console.log(row.index+"row.indexrow.index")
|
||||
console.log(row.index + 'row.indexrow.index')
|
||||
textIndex.value = row.index
|
||||
const res = await XlsxApi.getXlsxByNameList(row.type)
|
||||
xlsxPointsInfoList.value = []
|
||||
@@ -595,69 +595,66 @@ console.log(row.index+"row.indexrow.index")
|
||||
}
|
||||
|
||||
const getPlaceholder = (type) => {
|
||||
console.log(type+"typetypetype")
|
||||
console.log(type + 'typetypetype')
|
||||
switch (type) {
|
||||
case 'cell':
|
||||
return '请输入单元格(如 A1)';
|
||||
return '请输入单元格(如 A1)'
|
||||
case 'range':
|
||||
return '请输入范围(如 A1:B5)';
|
||||
return '请输入范围(如 A1:B5)'
|
||||
case 'row':
|
||||
return '请输入行号(如 3)';
|
||||
return '请输入行号(如 3)'
|
||||
case 'col':
|
||||
return '请输入列号(如 B)';
|
||||
return '请输入列号(如 B)'
|
||||
default:
|
||||
return '请输入值';
|
||||
return '请输入值'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const handleDelete = (row) => {
|
||||
console.log(row)
|
||||
const handleDelete = (row: any) => {
|
||||
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)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const submitXlsxPoints = async () => {
|
||||
console.log('单元格输入内容:', cellValues.value)
|
||||
console.log('单元格输入内容:', cellValues.value)
|
||||
console.log(xlsxPointsInfosList)
|
||||
const res = await XlsxApi.getXlsxMaster({
|
||||
data: JSON.stringify(xlsxPointsInfosList),
|
||||
file: file.value,
|
||||
cell: cellValues.value.map(item => item.value) // 提取值数组
|
||||
cell: cellValues.value.map((item) => item.value) // 提取值数组
|
||||
})
|
||||
xlsxPointsInfosList = []
|
||||
console.log(res)
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
res.data[i].scoreRate='1'
|
||||
res.data[i].scoreRate = '1'
|
||||
var indexFlag = false
|
||||
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
|
||||
}
|
||||
}
|
||||
if (!indexFlag) {
|
||||
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
|
||||
}
|
||||
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 leftActiveName = ref('desc')
|
||||
// 右侧tab
|
||||
const rightActiveName = ref('annex')
|
||||
const rightHandleClick = (tab, e) => {
|
||||
const rightHandleClick = (tab: any) => {
|
||||
rightActiveName.value = tab.paneName.value
|
||||
}
|
||||
const selections = ref([])
|
||||
@@ -726,7 +723,7 @@ const open = async (queryParams: any, type: string, id?: number) => {
|
||||
const res = await QuestionApi.getQuestion(id)
|
||||
formData.value = res
|
||||
console.log(formData.value)
|
||||
list.value = formData.value.answerList
|
||||
list.value = formData.value.answerList as any[]
|
||||
documentList.value = res.fileUploads
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
@@ -858,7 +855,7 @@ const handleTreeWithLevel = (list, level = 1) => {
|
||||
|
||||
// 只允许点击第三级节点
|
||||
const treeRef = ref() // 引用 el-tree
|
||||
const handleNodeClick = (data, node) => {
|
||||
const handleNodeClick = (data: any) => {
|
||||
if (data.level === 3) {
|
||||
formData.value.pointNames = data.id
|
||||
formData.value.pointNamesVo = data.name
|
||||
|
||||
@@ -76,7 +76,7 @@ export default ({command, mode}: ConfigEnv): UserConfig => {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
echarts: ['echarts'] // 将 echarts 单独打包,参考 https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues/IAB1SX 讨论
|
||||
echarts: ['echarts']
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user