Files
pengchen-exam-vue/src/views/paper/question/MysqlForm.vue
2025-06-03 17:29:49 +08:00

1141 lines
37 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="edit-dialog">
<Dialog v-model="dialogVisible" :title="dialogTitle" width="85%" top="10vh" class="custom-dialog">
<el-scrollbar>
<div class="main">
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="80px"
>
<el-row>
<el-col :span="12">
<el-form-item label="专业" prop="specialtyName">
<el-input v-model="formData.specialtyName" placeholder="请输入专业" disabled/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="知识点" prop="pointNames">
<el-input v-model="formData.pointNames" placeholder="请输入知识点" disabled/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="课程" prop="courseName">
<el-input v-model="formData.courseName" placeholder="请输入课程" disabled/>
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-form-item label="题型难度" prop="quLevel">
<el-input v-model="formData.quLevel" placeholder="请输入题型难度" />
</el-form-item> -->
<el-form-item label="题型难度" prop="quLevel">
<el-select
v-model="formData.quLevel"
placeholder="请选择题型难度"
clearable
>
<el-option label="简单" :value="'0'" />
<el-option label="一般" :value="'1'" />
<el-option label="困难" :value="'2'" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="题型" prop="subjectName">
<el-input v-model="formData.subjectName" placeholder="请输入题型" disabled/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="章节名称" prop="chapteridDictText">
<el-input v-model="formData.chapteridDictText" placeholder="请输入章节名称" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="启用状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio :label="'0'">启用</el-radio>
<el-radio :label="'1'">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="edit-bottom">
<div class="edit-left bottom-common">
<el-tabs v-model="leftActiveName" class="demo-tabs">
<el-tab-pane label="试题描述" name="desc">
<div class="block">
<Editor v-model="formData.content" height="250px" />
</div>
</el-tab-pane>
</el-tabs>
</div>
<div class="edit-right bottom-common">
<el-tabs v-model="rightActiveName" class="demo-tabs" @tab-click="rightHandleClick">
<el-tab-pane label="试题解析" name="analysis">
<div class="block">
<Editor v-model="formData.analysis" height="150px" />
</div>
</el-tab-pane>
<el-tab-pane name="keyword">
<template #label>
<div class="custom-tabs-label">
<p>关键字</p>
<el-dropdown>
<span class="el-dropdown-link" @click.stop="false">
<div class="setting_icon"></div>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="editKeyword('create')">新建</el-dropdown-item>
<el-dropdown-item @click="editKeyword('update')">编辑</el-dropdown-item>
<el-dropdown-item @click="editKeyword('delete')">删除</el-dropdown-item>
<el-dropdown-item @click="editKeyword('deleteall')"
>删除全部</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
<div class="block">
<el-table
:data="keywordList"
style="width: 100%"
@selection-change="handleKeywordSelectionChange"
>
<el-table-column type="index" width="50" />
<el-table-column type="selection" width="55" />
<el-table-column prop="keyword" label="关键字" />
</el-table>
<el-dialog
v-model="keyVisible"
title="编辑关键字"
width="50%"
:before-close="keyDialogClose"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div class="main" style="width: 100%; height: 100%">
<el-input v-model="keyWord" placeholder="请输入关键字" size="large" />
<div class="dialog-footer" style="margin-top: 20px;">
<el-button @click="keyDialogClose">取消</el-button>
<el-button type="primary" @click="confirmKeyDialogVisible">
确定
</el-button>
</div>
</div>
</el-dialog>
</div>
</el-tab-pane>
<el-tab-pane v-if="formType === 'update'" name="point">
<template #label>
<div class="custom-tabs-label">
<p>考点设置</p>
<el-dropdown>
<span class="el-dropdown-link" @click.stop="false">
<div class="setting_icon"></div>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="setKao()">考点设置</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
<div class="block" style="height: 300px;width: 100% ;">
<el-table
:data="kaodianList"
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="score" label="权值" width="60" />
<el-table-column prop="content" label="考点语句" width="800" />
</el-table>
</div>
<!-- 弹框 -->
<el-dialog
title="考点设置"
v-model="kaoDialogVisible"
width="60%"
:close-on-click-modal="false"
class="custom-dialog"
>
<!-- 可滚动容器 -->
<div style="height: 400px; overflow-y: auto;">
<el-table
:data="kaodianList"
style="width: 100%;"
row-key="answerId"
:default-expand-all="false"
@row-contextmenu="(row, column, event) => handleTextRightClick(event, row)"
>
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="score" label="权值" width="60" />
<el-table-column prop="content" label="考点语句" width="600" />
<!-- 展开行 -->
<el-table-column type="expand">
<template #default="props">
<el-table
:data="props.row.examMysqlKeywordList"
style="width: 100%;"
border
size="small"
>
<el-table-column type="index" label="序号" width="50" />
<el-table-column prop="keyword" label="关键词" />
<el-table-column label="权值" width="80">
<template #default="scope">
<el-input
v-model="scope.row.scoreRate"
size="small"
style="width: 70px;"
@input="updateScore(props.row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="text" size="small" @click="removeKeyword(props.row, scope.$index)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
</el-table>
</div>
<!-- 自定义右键菜单 -->
<div
v-if="contextMenuVisible"
class="context-menu"
:style="contextMenuStyle"
>
<div class="context-menu-item" @click="addKaodian(rightClickRow)">
设置此考点
</div>
</div>
<template #footer>
<el-upload
ref="uploadRef"
class="upload"
:action="uploadUrl"
:limit="1"
:before-upload="beforeUpload"
:on-success="handleUploadSuccessFile"
:http-request="httpRequest"
drag
>
<el-button type="primary" style="margin-bottom: 16px;">上传文件</el-button>
</el-upload>
<el-button @click="kaoDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmKao">确定</el-button>
</template>
</el-dialog>
</el-tab-pane>
<!-- <el-tab-pane name="medium">
<template #label>
<div class="custom-tabs-label">
<p>媒体文件</p>
<el-dropdown>
<span class="el-dropdown-link" @click.stop="false">
<div class="setting_icon"></div>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<el-upload
v-model:file-list="fileList"
class="upload-demo"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
>
<el-button>导入</el-button>
</el-upload>
</el-dropdown-item>
<el-dropdown-item>导出</el-dropdown-item>
<el-dropdown-item>播放</el-dropdown-item>
<el-dropdown-item>编辑</el-dropdown-item>
<el-dropdown-item>删除选中</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
<div class="block">
<el-table
:data="mediumList"
style="width: 100%"
@selection-change="handleMediumSelectionChange"
>
<el-table-column type="index" width="50" />
<el-table-column type="selection" width="55" />
<el-table-column prop="type" label="媒体类型" width="80" />
<el-table-column prop="title" label="标题" />
<el-table-column prop="displayIndex" label="显示序号" />
<el-table-column prop="size" label="大小" />
</el-table>
</div>
</el-tab-pane> -->
<el-tab-pane name="annex">
<template #label>
<div class="custom-tabs-label">
<p>试题附件</p>
<!-- <el-dropdown>
<span class="el-dropdown-link" @click.stop="false">
<div class="setting_icon"></div>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>导入单文件</el-dropdown-item>
<el-dropdown-item>导入多文件</el-dropdown-item>
<el-dropdown-item>导出</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
<el-dropdown-item>帮助</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown> -->
</div>
</template>
<!-- 提示 -->
<el-alert type="warning" show-icon :closable="false">
<template #default>
<span>提示文件名称可默认不设置</span>
</template>
</el-alert>
<div class="block">
<el-table :data="formData.fileUploads" style="width: 100%">
<el-table-column type="index" label="#" width="50" />
<el-table-column label="文件名称" width="250">
<template #default="scope">
<el-input
v-model="scope.row.fileName"
size="small"
placeholder="请输入文件名称"
/>
</template>
</el-table-column>
<el-table-column
prop="fileType"
label="类型"
:formatter="fileTypeFormatter"
/>
<el-table-column prop="url" label="地址" width="200">
<template #default="{ row }">
<div
style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"
:title="row.url"
>
{{ row.url }}
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="320">
<template #default="scope">
<el-button
type="primary"
plain
@click="openForm(scope.row.fileType)"
size="small"
>
<Icon icon="ep:upload" class="mr-5px" /> 上传
</el-button>
<el-button
type="success"
plain
@click="downloadFile(scope.row.url)"
size="small"
>
<Icon icon="ep:download" class="mr-5px" /> 下载
</el-button>
<el-button
type="danger"
plain
@click="deleteUrl(scope.$index)"
size="small"
><Icon icon="ep:download" class="mr-5px" />删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</el-scrollbar>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</div>
<!-- 表单弹窗添加/修改 -->
<FileForm ref="FileRef" @success="handleUploadSuccess"/>
</template>
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { FormRules } from 'element-plus'
import * as QuestionApi from '@/api/paper/question'
import FileForm from './components/FileForm.vue';
defineOptions({ name: 'ChoiceForm' })
import type { TabPaneName } from 'element-plus'
import { useUpload } from '@/components/UploadFile/src/useUpload'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const { uploadUrl, httpRequest } = useUpload()
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({
content: '',
specialtyName: '',
courseName: '',
quBankName: '',
required: '',
chapteridDictText: '',
analysis: '',
quLevel: '',
pointNames: '',
subjectName: '',
status: ' ',
keywords: '',
resourceValue: '',
fileUploads: [ {
quId: '',
url: '',
fileType: '1',
fileName: ''
},
{
quId: '',
url: '',
fileType: '2',
fileName: ''
}]
})
// 当前激活的 tab
const activeTab = ref('basic') // 初始 tab name根据实际设置
// formData.value.quId 中包含 quId假设它已有值
const kaodianData = ref({
quId: '', // 你打开编辑弹窗时会赋值
})
const formRules = reactive<FormRules>({
// specialtyName: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
// 左侧试题描述
const leftActiveName = ref('desc')
// 右侧tab
const rightActiveName = ref('analysis')
const rightHandleClick = (tab, e) => {
rightActiveName.value = tab.paneName;
if (tab.paneName === 'point' ) {
// 发起考点请求
QuestionApi.getListByQuId(kaodianData.value.quId).then(res => {
// res 是接口返回的数据数组
kaodianList.value = res.map(item => {
const totalScore = item.examMysqlKeywordList?.reduce((sum, kw) => {
return sum + Number(kw.scoreRate || 0);
}, 0);
return {
...item,
score: isNaN(totalScore) ? 0 : totalScore, // 如果是 NaN 则显示为 0
};
});
});
}
};
function updateScore(parentRow: any) {
parentRow.score = (parentRow.examMysqlKeywordList || []).reduce((sum, kw) => {
const rate = parseFloat(kw.scoreRate);
return sum + (isNaN(rate) ? 0 : rate);
}, 0);
}
//右键菜单状态
const kaoDialogVisible = ref(false) // 测试时默认打开
const kaodianList = ref<any[]>([])
const contextMenuVisible = ref(false)
const contextMenuStyle = ref({ top: '0px', left: '0px' })
const rightClickRow = ref<any>(null)
function handleTextRightClick(event: MouseEvent, row: any) {
event.preventDefault()
const selection = window.getSelection()
const selectedText = selection?.toString().trim()
if (selectedText) {
rightClickRow.value = row // 记录当前行
rightClickRow.value.selectedText = selectedText // 保存选中的文本
contextMenuStyle.value = {
top: `${event.clientY}px`,
left: `${event.clientX}px`
}
contextMenuVisible.value = true
document.addEventListener('click', closeContextMenu)
} else {
contextMenuVisible.value = false
}
}
function closeContextMenu() {
contextMenuVisible.value = false
document.removeEventListener('click', closeContextMenu)
}
// 设置考点:添加到下方
function addKaodian(row: any) {
const targetRow = rightClickRow.value;
const keyword = targetRow.selectedText;
if (!targetRow.examMysqlKeywordList) {
targetRow.examMysqlKeywordList = [];
}
const exists = targetRow.examMysqlKeywordList.find((item: any) => item.keyword === keyword);
if (!exists) {
const newKeyword = {
keyword,
scoreRate: 1,
answerId: targetRow.answerId // 添加 answerId
};
targetRow.examMysqlKeywordList.push(newKeyword);
// 累加关键字权值到语句的总权值
if (!targetRow.score) {
targetRow.score = 0;
}
targetRow.score += newKeyword.scoreRate;
}
contextMenuVisible.value = false;
}
function confirmKao() {
// 构建 questionAnswerList
const questionAnswerList = kaodianList.value.map(item => ({
answerId: item.answerId,
content: item.content,
examMysqlKeywordList: (item.examMysqlKeywordList || []).map(kw => ({
keywordId: kw.keywordId,
answerId: kw.answerId,
keyword: kw.keyword,
scoreRate: kw.scoreRate
}))
}));
const payload = {
quId:kaodianData.value.quId,
questionAnswerList
};
console.log('确认后的结果:', payload)
QuestionApi.saveSelectedKaodian(payload)
kaoDialogVisible.value= false;
}
const handleUploadSuccessFile = (response: any) => {
console.log('上传成功,返回:', response);
const fileUrl = response.data; // 取决于你的后端返回结构
if (fileUrl) {
// 拿到URL后调用你要请求的方法
fetchKaodianByUrl(fileUrl);
} else {
ElMessage.error('上传失败:没有返回文件地址');
}
};
const fetchKaodianByUrl = async (url: string) => {
try {
const params = {
answerPath: url,
shucaiPath: "" // 如果不传可以是空字符串,也可以删除这个字段(根据后端是否必填)
};
const res = await QuestionApi.getMysqlPoint(params);
// 根据返回更新 kaodianList 或弹出提示等
kaodianList.value = res || [];
const sqlList = res || [];
// 将 SQL 字符串数组转换为 kaodianList 所需结构
kaodianList.value = sqlList.map((sql, index) => ({
answerId: index + 1, // 可自定义唯一ID生成逻辑
quId: kaodianData.value.quId, // 如果有题目ID可以在这里设置
content: sql,
examMysqlKeywordList: [] // 默认空关键词列表
}));
ElMessage.success('考点导入成功');
} catch (err) {
ElMessage.error('考点导入失败');
}
};
const beforeUpload = (file: File) => {
const isTxt = file.type === 'text/plain';
const isLt5M = file.size / 1024 / 1024 < 5;
if (!isTxt) {
ElMessage.error('只能上传 TXT 文本文件');
return false;
}
if (!isLt5M) {
ElMessage.error('文件大小不能超过 5MB');
return false;
}
return true;
};
function removeKeyword(parentRow: any, keywordIndex: number) {
parentRow.examMysqlKeywordList.splice(keywordIndex, 1);
updateScore(parentRow); // 删除后更新score
}
const radio = ref('A')
// 关键字
const keywordList = ref([] as any)
const multipleKeywordSelection = ref([] as any)
const handleKeywordSelectionChange = (val: any) => {
multipleKeywordSelection.value = val
}
const keyVisible = ref(false)
const keyEditType = ref('')
const keyWord = ref('')
const editKeyword = (key: string) => {
keyEditType.value = key
if (key === 'create') {
keyWord.value = ''
keyVisible.value = true
} else if (key === 'update') {
if (multipleKeywordSelection.value.length === 0) {
ElMessage.warning('请先选择一个要编辑的关键字')
return
}
keyWord.value = multipleKeywordSelection.value[0].keyword
keyVisible.value = true
} else if (key === 'delete') {
if (multipleKeywordSelection.value.length === 0) {
ElMessage.warning('请先选择要删除的关键字')
return
}
keywordList.value = keywordList.value.filter(
item => !multipleKeywordSelection.value.includes(item)
)
ElMessage.success('已删除选中项')
} else if (key === 'deleteall') {
keywordList.value = []
ElMessage.success('已清空关键字列表')
}
updateKeywordsToForm()
}
const updateKeywordsToForm = () => {
const keywordStr = keywordList.value
.map(item => item.keyword)
.filter(k => k && k.trim() !== '')
.join(',')
formData.value.keywords = keywordStr
console.log(formData.value.keywords+"formData.value.keywords")
}
function setKao() {
kaoDialogVisible.value = true
}
const keyDialogClose = () => {
keyVisible.value = false
}
const confirmKeyDialogVisible = () => {
if (keyEditType.value === 'create') {
keywordList.value.push({
keyword: keyWord.value
})
} else if (keyEditType.value === 'update') {
multipleKeywordSelection.value.forEach(item => {
item.keyword = keyWord.value
})
} else if (keyEditType.value === 'delete') {
keywordList.value = keywordList.value.filter(
item => !multipleKeywordSelection.value.includes(item)
)
} else if (keyEditType.value === 'deleteall') {
keywordList.value = []
}
updateKeywordsToForm()
keyVisible.value = false
}
/** 添加/修改操作 */
const FileRef = ref()
const openForm = (type: string) => {
FileRef.value.open(type)
}
// 媒体文件
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
}
//文件
function fileTypeFormatter(row, column, cellValue) {
if (cellValue === '1') return '考试文件'
if (cellValue === '2') return '结果文件'
return '未知类型'
}
const handleUploadSuccess = ({ url, fileType }) => {
const index = formData.value.fileUploads.findIndex(item => item.fileType === fileType)
if (index !== -1) {
formData.value.fileUploads[index].url = url
}
}
const downloadFile = async (url: string) => {
if (!url) {
ElMessage.warning('暂无可下载的文件地址')
return
}
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error('下载失败')
}
const blob = await response.blob()
const blobUrl = window.URL.createObjectURL(blob)
// 提取文件名
const filename = url.substring(url.lastIndexOf('/') + 1).split('?')[0]
// 创建 a 标签并下载
const a = document.createElement('a')
a.href = blobUrl
a.download = filename
a.style.display = 'none'
document.body.appendChild(a)
a.click()
a.remove()
window.URL.revokeObjectURL(blobUrl)
} catch (err: any) {
ElMessage.error(`下载失败:${err.message}`)
}
}
const deleteUrl = (index: number) => {
formData.value.fileUploads[index].url = ''
formData.value.fileUploads[index].fileName = ''
}
/** 打开弹窗 */
const open = async (queryParams: any ,type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
rightActiveName.value = 'analysis'
// 修改时,设置数据
if (id) {
kaodianData.value.quId=id;
formLoading.value = true
try {
const res = await QuestionApi.getQuestion(id);
// 默认两个类型
const fileTypes = ['1', '2'];
// 后端返回的上传文件列表(可能为空)
const documentList = res.fileUploads ?? [];
// 遍历两种类型,找到对应的上传文件,如果没有就用默认值
const fileUploads = fileTypes.map(type => {
const match = documentList.find(file => file.fileType === type);
return {
quId: match?.quId ?? res.quId ?? '',
url: match?.url ?? '',
fileType: type,
fileName: match?.fileName ?? ''
};
});
formData.value = {
...res,
fileUploads,
};
keywordList.value = res.keywords
? res.keywords.split(',').filter(item => item.trim() !== '').map(item => ({ keyword: item.trim() }))
: []
} finally {
formLoading.value = false
}
} else {
resetForm()
formData.value.specialtyName = queryParams.specialtyName
formData.value.courseName = queryParams.courseName
formData.value.subjectName = queryParams.subjectName
formData.value.pointNames=queryParams.pointNames
formData.value.chapteridDictText=queryParams.chapteridDictText
}
}
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 answerData = ref([]);
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
// 校验表单
if (!formRef) return;
const valid = await formRef.value.validate();
if (!valid) return;
formLoading.value = true;
try {
// 深拷贝一份 formData
const data = JSON.parse(JSON.stringify(formData.value));
// 过滤掉 url 为空的文件项
data.fileUploads = data.fileUploads?.filter(file => file.url && file.url.trim() !== '');
console.log(data, "提交的数据");
if (formType.value === 'create') {
await QuestionApi.addQuestion(data);
message.success(t('common.createSuccess'));
} else {
await QuestionApi.editQuestion(data);
message.success(t('common.updateSuccess'));
}
dialogVisible.value = false;
emit('success');
} finally {
formLoading.value = false;
}
};
/** 重置表单 */
const resetForm = () => {
formData.value = {
content: `<p style="text-align: left;"><span style="font-family: 宋体;">--------------------------------------------------------------------------- </span></p><p style="text-align: left;"><span style="font-family: 宋体;">注意事项:</span></p><p style="text-align: left;"><span style="font-family: 宋体;">请利用图形化管理界面或者MySQL命令行工具在指定的试题数据库中进行答题。 </span></p><p style="text-align: left;"><span style="font-family: 宋体;">MySQL连接地址为localhost</span></p><p style="text-align: left;"><span style="font-family: 宋体;">MySQL登录用户名为root</span></p><p style="text-align: left;"><span style="font-family: 宋体;">MySQL端口号为3306或者6033</span></p><p style="text-align: left;"><span style="font-family: 宋体;">MySQL密码为空</span></p><p style="text-align: left;"><span style="font-family: 宋体;">---------------------------------------------------------------------------</span>`,
specialtyName: '',
courseName: '',
quBankName: '',
required: '',
chapteridDictText: '',
analysis: '',
quLevel: '0',
pointNames: '',
subjectName: '',
status: '0',
keywords: '',
resourceValue: '',
fileUploads: [
{
quId: '',
url: '',
fileType: '1',
fileName: ''
},
{
quId: '',
url: '',
fileType: '2',
fileName: ''
}
]
}
kaodianList.value=[],
keywordList.value=[],
formRef.value?.resetFields()
}
onMounted(() => {
document.addEventListener('click', () => {
contextMenuVisible.value = false
})
})
</script>
<style lang="scss" scoped>
.context-menu {
position: fixed;
background-color: white;
border: 1px solid #ddd;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 9999;
padding: 5px 0;
width: 120px;
}
.context-menu-item {
padding: 6px 12px;
cursor: pointer;
}
.context-menu-item:hover {
background-color: #f5f5f5;
}
.edit-dialog {
:deep(.el-dialog) {
display: flex;
flex-direction: column;
.el-dialog__header {
border-bottom: 1px solid #ededed;
}
.el-dialog__footer {
border-top: 1px solid #ededed;
}
.el-dialog__body {
flex: 1;
overflow: hidden;
.main {
.el-form {
padding: 10px;
.el-row {
justify-content: space-between;
margin-bottom: 10px;
}
.el-form-item {
width: 100%;
margin-bottom: 0;
align-items: center;
}
}
.edit-bottom {
display: flex;
justify-content: space-between;
padding-bottom: 10px;
.bottom-common {
width: calc(50% - 10px);
.el-tabs {
height: 100%;
.el-tabs__content {
flex: 1;
overflow-y: auto;
.block {
width: 100%;
height: 80%;
overflow: auto;
}
.answer {
.tip {
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
padding: 10px 20px;
display: flex;
align-items: center;
> p {
flex-shrink: 0;
}
}
.el-radio-group {
width: 100%;
display: inline-flex;
align-items: flex-start;
font-size: 0;
flex-direction: column;
.options {
width: 100%;
margin-top: 15px;
.content {
display: flex;
.text {
width: 100%;
height: 70px;
border: 1px solid #ededed;
.el-textarea__inner {
resize: none;
}
}
}
.more-btn {
margin-top: 8px;
background-color: #ffffff;
border-color: #007bff;
color: #007bff;
width: auto;
height: auto;
padding: 10px 10px;
}
}
}
}
}
.custom-tabs-label {
display: flex;
align-items: center;
.setting_icon {
width: 16px;
height: 16px;
background: url('@/assets/icon/setting_blue.png') no-repeat center;
background-size: 100%;
margin-left: 3px;
display: none;
}
}
.is-active {
.custom-tabs-label {
.setting_icon {
display: block;
}
}
}
:deep(.ele-pro-table) {
flex: 1;
margin-top: 10px;
.el-table--fit {
height: 100%;
}
}
}
}
}
}
}
}
}
:deep(.tox-tinymce) {
.tox-statusbar {
display: none;
}
}
:deep(.el-table) {
.el-table__header-wrapper {
.el-table__header {
thead {
tr {
th {
background: #ebebeb;
}
}
}
}
}
}
</style>