Compare commits

...

2 Commits

46 changed files with 1064 additions and 163 deletions

View File

@@ -66,3 +66,7 @@ export const deleteTenant = (id: number) => {
export const exportTenant = (params: TenantExportReqVO) => {
return request.download({ url: '/system/tenant/export-excel', params })
}
export const resetPassword = (data) => {
return request.post({url: '/system/tenant/reset-password', data,})
}

View File

@@ -271,6 +271,13 @@ const loginOutAdminPassword = async () => {
}
LoginApi.refreshLogout(data).then((res) => {
if (res) {
if (res === '900002') {
ElMessageBox.alert('管理员密码错误,请重新输入!', '提示', {
confirmButtonText: '确认',
type: 'error',
})
return
}
message.success(res)
isTrueLoginForAdminPassWord.value = false
}

View File

@@ -172,6 +172,12 @@
</el-table-column>
<el-table-column label="试卷任务" align="center" prop="taskName" />
<el-table-column label="机器ip" align="center" prop="ip" width="180px"/>
<el-table-column
label="更新时间"
align="center"
prop="updateTime"
:formatter="dateFormatter"
/>
<el-table-column
label="剩余时间"
align="center"

View File

@@ -200,7 +200,7 @@
</div>
<!-- 弹框 -->
<el-dialog
<Dialog
title="考点设置"
v-model="kaoDialogVisible"
width="60%"
@@ -208,6 +208,15 @@
class="custom-dialog"
draggable
>
<div
style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 6px; max-height: 100%; overflow: hidden;"
>
<h3 style="margin: 0 0 8px 0;">试题内容</h3>
<el-scrollbar height="200px">
<!-- 支持富文本渲染 -->
<div v-html="formData.content" style="white-space: pre-wrap;"></div>
</el-scrollbar>
</div>
<!-- 可滚动容器 -->
<div style="height: 400px; overflow-y: auto;">
<el-table
@@ -299,7 +308,7 @@
<el-button @click="confimKaoFalse">取消</el-button>
<el-button type="primary" @click="confirmKao">确定</el-button>
</template>
</el-dialog>
</Dialog>

View File

@@ -152,11 +152,26 @@
<el-input v-model="scope.row.scoreRate" placeholder="请输入权值" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100px">
<template #default="scope">
<el-button type="primary" link @click="handleDelete(scope.row)">
<Icon icon="ep:delete" />删除
</el-button>
<el-table-column label="操作" align="center" width="140px">
<template #default="{ row }">
<el-button
:icon="ArrowUp"
circle
size="small"
@click="moveUp(row)"
title="上移"
/>
<el-button
:icon="ArrowDown"
circle
size="small"
@click="moveDown(row)"
title="下移"
/>
<el-button
@click="handleDelete(row)"
></el-button
>
</template>
</el-table-column>
</el-table>
@@ -287,11 +302,52 @@
<el-dialog
v-model="dialogFormVisibleWordInfo"
title="邮件设置"
width="1500px"
width="80%"
style="overflow: scroll"
@close="handleEmailForm"
>
<!-- 外层容器 -->
<div
style="
display: flex;
height: 75vh; /* 占用弹窗可视区域 */
gap: 16px;
box-sizing: border-box;
"
>
<!-- 右边试题内容 -->
<div
style="
flex: 2;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
overflow: auto; /* ✅ 同样可以滚动 */
"
>
<h3 style="margin-bottom: 10px;">试题内容</h3>
<div
v-html="formData.content"
style="
white-space: pre-wrap;
line-height: 1.6;
"
></div>
</div>
<!-- 左边WindowsSystemSetting -->
<div
style="
flex: 4;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
overflow: auto; /* ✅ 关键点 */
"
>
<Email />
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
@@ -305,7 +361,7 @@ import * as SpecialtyApi from '@/api/points'
import { defaultProps, handleTree } from '@/utils/tree'
import { cloneDeep } from 'lodash-es'
import { useEmailStore } from '@/store/modules/email'
import { ArrowUp, ArrowDown, Delete } from '@element-plus/icons-vue'
const emailStore = useEmailStore()
defineOptions({ name: 'WpsWordFrom' })
@@ -397,6 +453,30 @@ const addEmailInfo = async () => {
const handleEmailForm = () => {
list.value = [...emailStore.emailFormList]
// emailStore.clearEmailData() // 如果需要清空数据,可以取消注释
}
// 上移
function moveUp(row) {
const index = list.value.findIndex(item => item === row);
if (index > 0) {
[list.value[index - 1], list.value[index]] = [list.value[index], list.value[index - 1]];
}
updateSort()
}
// 下移
function moveDown(row) {
const index = list.value.findIndex(item => item === row);
if (index !== -1 && index < list.value.length - 1) {
[list.value[index + 1], list.value[index]] = [list.value[index], list.value[index + 1]];
}
updateSort()
}
// 更新 sort 字段
const updateSort = () => {
list.value.forEach((item, index) => {
item.sort = index + 1
})
}
const handleDelete = (row) => {
console.log(row)

View File

@@ -250,7 +250,7 @@
</div>
<!-- 弹框 -->
<el-dialog
<Dialog
title="考点设置"
v-model="kaoDialogVisible"
width="60%"
@@ -258,6 +258,15 @@
class="custom-dialog"
draggable
>
<div
style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 6px; max-height: 100%; overflow: hidden;"
>
<h3 style="margin: 0 0 8px 0;">试题内容</h3>
<el-scrollbar height="200px">
<!-- 支持富文本渲染 -->
<div v-html="formData.content" style="white-space: pre-wrap;"></div>
</el-scrollbar>
</div>
<!-- 可滚动容器 -->
<div style="height: 400px; overflow-y: auto;">
<el-table
@@ -346,7 +355,7 @@
<el-button @click="kaoDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmKao">确定</el-button>
</template>
</el-dialog>
</Dialog>

View File

@@ -202,7 +202,7 @@
</div>
<!-- 弹框 -->
<el-dialog
<Dialog
title="考点设置"
v-model="kaoDialogVisible"
width="60%"
@@ -210,6 +210,16 @@
class="custom-dialog"
draggable
>
<!-- 新增题干展示区 -->
<div
style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 6px; max-height: 100%; overflow: hidden;"
>
<h3 style="margin: 0 0 8px 0;">试题内容</h3>
<el-scrollbar height="200px">
<!-- 支持富文本渲染 -->
<div v-html="formData.content" style="white-space: pre-wrap;"></div>
</el-scrollbar>
</div>
<!-- 可滚动容器 -->
<div style="height: 400px; overflow-y: auto;width:100%;">
<el-table
@@ -321,7 +331,7 @@
<el-button @click="kaoDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmKao">确定</el-button>
</template>
</el-dialog>
</Dialog>

View File

@@ -249,7 +249,7 @@
</div>
<!-- 弹框 -->
<el-dialog
<Dialog
title="考点设置"
v-model="kaoDialogVisible"
width="60%"
@@ -257,6 +257,16 @@
class="custom-dialog"
draggable
>
<!-- 新增题干展示区 -->
<div
style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 6px; max-height: 250px; overflow: hidden;"
>
<h3 style="margin: 0 0 8px 0;">试题内容</h3>
<el-scrollbar height="200px">
<!-- 支持富文本渲染 -->
<div v-html="formData.content" style="white-space: pre-wrap;"></div>
</el-scrollbar>
</div>
<!-- 可滚动容器 -->
<div style="height: 400px; overflow: hidden; display: flex; gap: 16px;">
<div style="flex: 1; overflow: auto; border: 1px solid #eee; padding: 8px;">
@@ -277,8 +287,8 @@
<div style="flex: 1; overflow: auto; border: 1px solid #eee; padding: 8px;">
<h3>考生表格右侧</h3>
<el-table :data="flatPointList" style="width: 100%; min-width: 300px;" :row-key="(row) => row.id">
<el-table-column prop="sort" label="序号" />
<el-table-column prop="label" label="" />
<el-table-column prop="rate" label="权值">
<template #default="{ row }">
<el-input
@@ -288,14 +298,26 @@
/>
</template>
</el-table-column>
<el-table-column prop="sort" label="排序" />
<el-table-column label="操作" width="60">
<template #default="{ $index }">
<span
@click="removePoint($index)"
style="cursor: pointer; font-weight: bold; font-size: 18px;"
title="点击删除"
>—</span>
<el-table-column label="操作" width="140px">
<template #default="{ row }">
<el-button
:icon="ArrowUp"
circle
size="small"
@click="moveUp(row)"
title="上移"
/>
<el-button
:icon="ArrowDown"
circle
size="small"
@click="moveDown(row)"
title="下移"
/>
<el-button
@click="removePoint(row)"
>—</el-button
>
</template>
</el-table-column>
</el-table>
@@ -313,7 +335,7 @@
<el-button @click="kaoDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmKao">确定</el-button>
</template>
</el-dialog>
</Dialog>
@@ -569,6 +591,9 @@ const kaodianData = ref({
const answerList = ref([]); // 从接口赋值
const pointList = ref([]); // 从接口赋值
const kaodianList = ref([]); // 从接口赋值
// 定义右侧表格数据,初始时根据 pointList 构造
const flatPointList = ref<{ key: string; label: string; rate: number ,sort:number,index:number}[]>([]);
const flatkaodianList = ref<{ key: string; label: string; rate: number }[]>([]);
const treeProps = {
label: 'key',
@@ -595,8 +620,14 @@ console.log(answerList)
QuestionApi.setPsPoint(payload);
QuestionApi.setPsPoint(payloadAnswer);
// const res = await QuestionApi.getListByQuId(kaodianData.value.quId);
// kaodianList.value = res;
flatkaodianList.value = flatPointList.value.map(item => ({
key: item.key,
label: item.label,
rate: item.rate,
sort: item.sort
}));
kaoDialogVisible.value = false;
};
@@ -630,9 +661,7 @@ function buildTreeFromFlatList(flatList) {
return root;
}
// 定义右侧表格数据,初始时根据 pointList 构造
const flatPointList = ref<{ key: string; label: string; rate: number ,sort:number}[]>([]);
const flatkaodianList = ref<{ key: string; label: string; rate: number }[]>([]);
function flattenPsVoList(list, parentPath = '') {
@@ -642,7 +671,7 @@ function flattenPsVoList(list, parentPath = '') {
if (item.children && item.children.length > 0) {
result.push(...flattenPsVoList(item.children, currentPath));
} else {
const symbol = item.value === true ? '✅' : item.value === false ? '❌' : item.value;
const symbol = item.value === 'true' ? '✅' : item.value === 'false' ? '❌' : item.value;
result.push({
key: item.key, // 一定要有 key
label: `${currentPath}: ${symbol}`,
@@ -651,6 +680,11 @@ function flattenPsVoList(list, parentPath = '') {
});
}
});
// 添加 index 字段
result.forEach((item, idx) => {
item.index = idx;
});
return result;
}
function flattenPsVoListOther(list, parentPath = '') {
@@ -1096,6 +1130,30 @@ const handleNodeClick = (data, node) => {
// 可选:关闭弹窗
dialogVisiblePoints.value = false;
};
// 上移
function moveUp(row) {
const index = flatPointList.value.findIndex(item => item === row);
if (index > 0) {
[flatPointList.value[index - 1], flatPointList.value[index]] = [flatPointList.value[index], flatPointList.value[index - 1]];
}
updateSort()
}
// 下移
function moveDown(row) {
const index = flatPointList.value.findIndex(item => item === row);
if (index !== -1 && index < flatPointList.value.length - 1) {
[flatPointList.value[index + 1], flatPointList.value[index]] = [flatPointList.value[index], flatPointList.value[index + 1]];
}
updateSort()
}
// 更新 sort 字段
const updateSort = () => {
flatPointList.value.forEach((item, index) => {
item.sort = index + 1
})
}
const removePoint = (index: number) => {
flatPointList.value.splice(index, 1);
};

View File

@@ -147,11 +147,26 @@
<el-input v-model="scope.row.scoreRate" placeholder="请输入权值" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100px">
<template #default="scope">
<el-button type="primary" link @click="handleDelete(scope.row)">
<Icon icon="ep:delete" />删除
</el-button>
<el-table-column label="操作" align="center" width="140px">
<template #default="{ row }">
<el-button
:icon="ArrowUp"
circle
size="small"
@click="moveUp(row)"
title="上移"
/>
<el-button
:icon="ArrowDown"
circle
size="small"
@click="moveDown(row)"
title="下移"
/>
<el-button
@click="handleDelete(row)"
></el-button
>
</template>
</el-table-column>
</el-table>
@@ -213,14 +228,55 @@
</div>
<!-- 表单弹窗添加/修改 -->
<FileForm ref="FileRef" @success="handleUploadSuccess" />
<el-dialog
<Dialog
v-model="dialogFormVisibleWordInfo"
title="考点设置"
width="1100px"
width="80%"
@close="handleFrom"
>
<!-- 外层容器 -->
<div
style="
display: flex;
height: 75vh; /* 占用弹窗可视区域 */
gap: 16px;
box-sizing: border-box;
"
>
<!-- 右边试题内容 -->
<div
style="
flex: 2;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
overflow: auto; /* ✅ 同样可以滚动 */
"
>
<h3 style="margin-bottom: 10px;">试题内容</h3>
<div
v-html="formData.content"
style="
white-space: pre-wrap;
line-height: 1.6;
"
></div>
</div>
<!-- 左边WindowsSystemSetting -->
<div
style="
flex: 4;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
overflow: auto; /* ✅ 关键点 */
"
>
<Setting />
</el-dialog>
</div>
</div>
</Dialog>
</template>
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
@@ -231,6 +287,7 @@ import Setting from '@/components/Setting/index.vue'
import * as SpecialtyApi from '@/api/points'
import { handleTree } from '@/utils/tree'
import { useSettingStore } from '@/store/modules/settings'
import { ArrowUp, ArrowDown, Delete } from '@element-plus/icons-vue'
const settingStore = useSettingStore()
// import { emitter } from '@/utils/eventBus'
@@ -322,7 +379,30 @@ const dialogFormVisibleWordInfo = ref(false)
const addWordInfo = async () => {
dialogFormVisibleWordInfo.value = true
}
// 上移
function moveUp(row) {
const index = list.value.findIndex(item => item === row);
if (index > 0) {
[list.value[index - 1], list.value[index]] = [list.value[index], list.value[index - 1]];
}
updateSort()
}
// 下移
function moveDown(row) {
const index = list.value.findIndex(item => item === row);
if (index !== -1 && index < list.value.length - 1) {
[list.value[index + 1], list.value[index]] = [list.value[index], list.value[index + 1]];
}
updateSort()
}
// 更新 sort 字段
const updateSort = () => {
list.value.forEach((item, index) => {
item.sort = index + 1
})
}
const handleDelete = (row) => {
for (let i = 0; i < list.value.length; i++) {
if (row.content == list.value[i].content) {

View File

@@ -133,11 +133,26 @@
<el-input v-model="scope.row.scoreRate" placeholder="请输入权值" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100px">
<template #default="scope">
<el-button type="danger" plain @click="handleDelete(scope.row)" link>
删除
</el-button>
<el-table-column label="操作" align="center" width="140px">
<template #default="{ row }">
<el-button
:icon="ArrowUp"
circle
size="small"
@click="moveUp(row)"
title="上移"
/>
<el-button
:icon="ArrowDown"
circle
size="small"
@click="moveDown(row)"
title="下移"
/>
<el-button
@click="handleDelete(row)"
></el-button
>
</template>
</el-table-column>
</el-table>
@@ -156,14 +171,56 @@
</div>
<!-- 表单弹窗添加/修改 -->
<FileForm ref="FileRef" @success="handleUploadSuccess" />
<el-dialog
<Dialog
v-model="dialogFormVisibleWindowsSystemInfo"
title="Windows系统设置考点"
width="1100px"
width="80%"
@close="handleFrom"
>
<WindowsSystemSetting />
</el-dialog>
<!-- 外层容器 -->
<div
style="
display: flex;
height: 75vh; /* 占用弹窗可视区域 */
gap: 16px;
box-sizing: border-box;
"
>
<!-- 右边试题内容 -->
<div
style="
flex: 2;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
overflow: auto; /* ✅ 同样可以滚动 */
"
>
<h3 style="margin-bottom: 10px;">试题内容</h3>
<div
v-html="formData.content"
style="
white-space: pre-wrap;
line-height: 1.6;
"
></div>
</div>
<!-- 左边WindowsSystemSetting -->
<div
style="
flex: 4;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
overflow: auto; /* ✅ 关键点 */
"
>
<h3 style="margin-bottom: 10px;">系统设置</h3>
<WindowsSystemSetting />
</div>
</div>
</Dialog>
</template>
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
@@ -174,6 +231,7 @@ import WindowsSystemSetting from '@/components/WindowsSystemSetting/index.vue'
import * as SpecialtyApi from '@/api/points'
import { handleTree } from '@/utils/tree'
import { useSettingStore } from '@/store/modules/settings'
import { ArrowUp, ArrowDown, Delete } from '@element-plus/icons-vue'
const settingStore = useSettingStore()
defineOptions({ name: 'WindowsSystemSettingForm' })
@@ -260,7 +318,30 @@ const dialogFormVisibleWindowsSystemInfo = ref(false)
const addWindowsSystemInfo = async () => {
dialogFormVisibleWindowsSystemInfo.value = true
}
// 上移
function moveUp(row) {
const index = list.value.findIndex(item => item === row);
if (index > 0) {
[list.value[index - 1], list.value[index]] = [list.value[index], list.value[index - 1]];
}
updateSort()
}
// 下移
function moveDown(row) {
const index = list.value.findIndex(item => item === row);
if (index !== -1 && index < list.value.length - 1) {
[list.value[index + 1], list.value[index]] = [list.value[index], list.value[index + 1]];
}
updateSort()
}
// 更新 sort 字段
const updateSort = () => {
list.value.forEach((item, index) => {
item.sort = index + 1
})
}
const handleDelete = (row) => {
for (let i = 0; i < list.value.length; i++) {
if (row.content == list.value[i].content) {

View File

@@ -280,9 +280,18 @@
<!-- 表单弹窗添加/修改 -->
<FileForm ref="FileRef" @success="handleUploadSuccess" />
<el-dialog v-model="dialogFormVisiblePptxInfo" title="考点设置" width="70%">
<Dialog v-model="dialogFormVisiblePptxInfo" title="考点设置" width="70%">
<input type="file" id="slideFile" accept=".pptx" />
<button @click="getSlideDataInfo">文件解析</button>
<div
style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 6px; max-height: 100%; overflow: hidden;"
>
<h3 style="margin: 0 0 8px 0;">试题内容</h3>
<el-scrollbar height="200px">
<!-- 支持富文本渲染 -->
<div v-html="formData.content" style="white-space: pre-wrap;"></div>
</el-scrollbar>
</div>
<div style="height: 400px; overflow: hidden; display: flex; gap: 16px">
<div
class="tree-wrap"
@@ -308,13 +317,25 @@
</template>
</el-table-column>
<el-table-column label="操作" width="100px">
<el-table-column label="操作" width="140px">
<template #default="{ row }">
<span
<el-button
:icon="ArrowUp"
circle
size="small"
@click="moveUp(row)"
title="上移"
/>
<el-button
:icon="ArrowDown"
circle
size="small"
@click="moveDown(row)"
title="下移"
/>
<el-button
@click="removePoint(row)"
style="cursor: pointer; font-weight: bold; font-size: 18px"
title="点击删除"
></span
></el-button
>
</template>
</el-table-column>
@@ -323,7 +344,7 @@
</div>
<!-- <el-skeleton :rows="5" animated v-if="pptxPointsList.length < 0 && isLoading" />
-->
</el-dialog>
</Dialog>
<el-dialog
v-model="dialogFormVisiblePptxInfos"
:title="titles"
@@ -356,7 +377,7 @@ import { FormRules } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import FileForm from './components/FileForm.vue'
import { ElLoading } from 'element-plus'
import { ArrowUp, ArrowDown, Delete } from '@element-plus/icons-vue'
defineOptions({ name: 'WpsPptxFrom' })
const pptxPointsList = ref<Tree[]>([]) // 树形结构
const pptxPointsInfoList = ref<Tree[]>([]) // 树形结构
@@ -424,6 +445,30 @@ interface PptxPoints {
method?: string
}
let pptxPointsInfosList: PptxPoints[] = []
// 上移
function moveUp(row) {
const index = list.value.findIndex(item => item === row);
if (index > 0) {
[list.value[index - 1], list.value[index]] = [list.value[index], list.value[index - 1]];
}
updateSort()
}
// 下移
function moveDown(row) {
const index = list.value.findIndex(item => item === row);
if (index !== -1 && index < list.value.length - 1) {
[list.value[index + 1], list.value[index]] = [list.value[index], list.value[index + 1]];
}
updateSort()
}
// 更新 sort 字段
const updateSort = () => {
list.value.forEach((item, index) => {
item.sort = index + 1
})
}
const removePoint = (row) => {
// list.value.splice(index, 1)
for (let i = 0; i < list.value.length; i++) {

View File

@@ -280,9 +280,19 @@
<!-- 表单弹窗添加/修改 -->
<FileForm ref="FileRef" @success="handleUploadSuccess" />
<el-dialog v-model="dialogFormVisibleWordInfo" title="考点设置" width="70%">
<Dialog v-model="dialogFormVisibleWordInfo" title="考点设置" width="70%">
<input type="file" id="docxFile" accept=".docx" />
<button @click="getDocxDataInfo">文件解析</button>
<!-- 新增题干展示区 -->
<div
style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 6px; max-height: 100%; overflow: hidden;"
>
<h3 style="margin: 0 0 8px 0;">试题内容</h3>
<el-scrollbar height="200px">
<!-- 支持富文本渲染 -->
<div v-html="formData.content" style="white-space: pre-wrap;"></div>
</el-scrollbar>
</div>
<div style="height: 400px; overflow: hidden; display: flex; gap: 16px">
<div style="flex: 0.5; overflow: auto; border: 1px solid #eee; padding: 8px">
<h3>考点</h3>
@@ -305,13 +315,25 @@
</template>
</el-table-column>
<el-table-column label="操作" width="100px">
<el-table-column label="操作" width="140px">
<template #default="{ row }">
<span
<el-button
:icon="ArrowUp"
circle
size="small"
@click="moveUp(row)"
title="上移"
/>
<el-button
:icon="ArrowDown"
circle
size="small"
@click="moveDown(row)"
title="下移"
/>
<el-button
@click="removePoint(row)"
style="cursor: pointer; font-weight: bold; font-size: 18px"
title="点击删除"
></span
></el-button
>
</template>
</el-table-column>
@@ -321,7 +343,7 @@
<!-- <el-skeleton :rows="5" animated v-if="wordPointsList.length < 0 && isLoading" />
-->
</el-dialog>
</Dialog>
<el-dialog v-model="dialogFormVisibleWordInfos" :title="titles" width="300px">
<el-tree
style="max-width: 600px"
@@ -359,7 +381,7 @@ import { defaultProps, handleTree } from '@/utils/tree'
import { FormRules } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import FileForm from './components/FileForm.vue'
import { ArrowUp, ArrowDown, Delete } from '@element-plus/icons-vue'
defineOptions({ name: 'WpsWordFrom' })
const wordPointsList = ref<Tree[]>([]) // 树形结构
const wordPointsInfoList = ref<Tree[]>([]) // 树形结构
@@ -435,6 +457,30 @@ interface WordPointsInfo {
method?: string;
}
let wordPointsInfosList: WordPointsInfo[] = []
// 上移
function moveUp(row) {
const index = list.value.findIndex(item => item === row);
if (index > 0) {
[list.value[index - 1], list.value[index]] = [list.value[index], list.value[index - 1]];
}
updateSort()
}
// 下移
function moveDown(row) {
const index = list.value.findIndex(item => item === row);
if (index !== -1 && index < list.value.length - 1) {
[list.value[index + 1], list.value[index]] = [list.value[index], list.value[index + 1]];
}
updateSort()
}
// 更新 sort 字段
const updateSort = () => {
list.value.forEach((item, index) => {
item.sort = index + 1
})
}
const removePoint = (row) => {
// list.value.splice(index, 1)
for (let i = 0; i < list.value.length; i++) {

View File

@@ -280,9 +280,18 @@
<!-- 表单弹窗添加/修改 -->
<FileForm ref="FileRef" @success="handleUploadSuccess" />
<el-dialog v-model="dialogFormVisibleXlsxInfo" title="考点设置" width="70%">
<Dialog v-model="dialogFormVisibleXlsxInfo" title="考点设置" width="70%">
<input type="file" id="xlsxFile" accept=".xlsx" />
<button @click="getXlsxDataInfo">文件解析</button>
<div
style="border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 6px; max-height: 100%; overflow: hidden;"
>
<h3 style="margin: 0 0 8px 0;">试题内容</h3>
<el-scrollbar height="200px">
<!-- 支持富文本渲染 -->
<div v-html="formData.content" style="white-space: pre-wrap;"></div>
</el-scrollbar>
</div>
<div style="height: 400px; overflow: hidden; display: flex; gap: 16px">
<div style="flex: 0.5; overflow: auto; border: 1px solid #eee; padding: 8px">
<h3>考点</h3>
@@ -305,13 +314,25 @@
</template>
</el-table-column>
<el-table-column label="操作" width="100px">
<el-table-column label="操作" width="140px">
<template #default="{ row }">
<span
<el-button
:icon="ArrowUp"
circle
size="small"
@click="moveUp(row)"
title="上移"
/>
<el-button
:icon="ArrowDown"
circle
size="small"
@click="moveDown(row)"
title="下移"
/>
<el-button
@click="removePoint(row)"
style="cursor: pointer; font-weight: bold; font-size: 18px"
title="点击删除"
></span
></el-button
>
</template>
</el-table-column>
@@ -321,7 +342,7 @@
<!-- <el-skeleton :rows="5" animated v-if="XlsxPointsList.length < 0 && isLoading" />
-->
</el-dialog>
</Dialog>
<el-dialog v-model="dialogFormVisibleXlsxInfos" :title="titles" width="300px">
<el-tree
style="max-width: 600px"
@@ -336,22 +357,42 @@
<!-- 单元格类型才显示 -->
<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"
:placeholder="getPlaceholder(selectedType)"
style="flex: 1"
/>
<!-- 两个输入框用冒号拼接 -->
<template v-else>
<el-input v-model="rangeStart" placeholder="开始单元格" style="flex: 1" />
<span>:</span>
<el-input v-model="rangeEnd" placeholder="结束单元格" style="flex: 1" />
<div style="display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px;">
<!-- cell 类型两个输入框 -->
<template v-if="selectedType === 'cell'">
<div style="display: flex; gap: 8px; align-items: center;">
<el-input
v-model="cellInputValue"
:placeholder="getPlaceholder(selectedType)"
style="flex: 1"
/>
<el-button type="primary" @click="addCellValue">确定</el-button>
</div>
<el-input
v-model="cellImportValue"
placeholder="输入关键字"
style="flex: 1"
clearable
/>
</template>
<!-- range 类型 -->
<template v-else-if="selectedType === 'range'">
<el-input v-model="rangeStart" placeholder="开始单元格 (如 A1)" style="flex: 1" />
<span>:</span>
<el-input v-model="rangeEnd" placeholder="结束单元格 (如 C5)" style="flex: 1" />
<el-button type="primary" @click="addCellValue">确定</el-button>
</template>
<!-- 其他类型 -->
<template v-else>
<el-input
v-model="cellInputValue"
:placeholder="getPlaceholder(selectedType)"
style="flex: 1"
/>
<el-button type="primary" @click="addCellValue">确定</el-button>
</template>
<el-button type="primary" @click="addCellValue">确定</el-button>
</div>
<!-- 下方列表多选可删除 -->
@@ -386,13 +427,14 @@ import { defaultProps, handleTree } from '@/utils/tree'
import { FormRules } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import FileForm from './components/FileForm.vue'
import { ArrowUp, ArrowDown, Delete } from '@element-plus/icons-vue'
defineOptions({ name: 'WpsXlsxFrom' })
const xlsxPointsList = ref<Tree[]>([]) // 树形结构
const xlsxPointsInfoList = ref<Tree[]>([]) // 树形结构
const isCellType = ref(false) // 是否单元格
const cellInputValue = ref('') // 上方输入框值
const cellImportValue = ref('') // 上方输入框值
const cellValues = ref<{ value: string }[]>([]) // 存储所有添加的数据
const selectedRows = ref<{ value: string }[]>([]) // 多选的行
const rangeStart = ref('') // range 开始
@@ -496,6 +538,30 @@ interface XlsxPointsInfo {
method?: string;
}
let xlsxPointsInfosList: XlsxPointsInfo[] = []
// 上移
function moveUp(row) {
const index = list.value.findIndex(item => item === row);
if (index > 0) {
[list.value[index - 1], list.value[index]] = [list.value[index], list.value[index - 1]];
}
updateSort()
}
// 下移
function moveDown(row) {
const index = list.value.findIndex(item => item === row);
if (index !== -1 && index < list.value.length - 1) {
[list.value[index + 1], list.value[index]] = [list.value[index], list.value[index + 1]];
}
updateSort()
}
// 更新 sort 字段
const updateSort = () => {
list.value.forEach((item, index) => {
item.sort = index + 1
})
}
const removePoint = (row: any) => {
for (let i = 0; i < list.value.length; i++) {
if ((row.content ?? row.contentIn) == (list.value[i].content ?? list.value[i].contentIn)) {
@@ -547,9 +613,27 @@ const handleCheckChange = (data: any, _checked: boolean, _indeterminate: boolean
examCode: '111',
method: data.parameter ?? ''
}
if (xlsxPoints.function) {
xlsxPointsInfosList.push(cloneDeep(xlsxPoints))
// 查找当前节点是否已存在于列表中(根据 function 或 examName 唯一标识)
const existIndex = xlsxPointsInfosList.findIndex(
(item) => item.function === xlsxPoints.function && item.examName === xlsxPoints.examName
)
if (_checked) {
// ✅ 选中时添加(若已存在则不重复添加)
if (existIndex === -1) {
xlsxPointsInfosList.push(cloneDeep(xlsxPoints))
}
} else {
// ❌ 取消选中时删除
if (existIndex !== -1) {
xlsxPointsInfosList.splice(existIndex, 1)
}
}
console.log('📦 当前选中数据:', xlsxPointsInfosList)
// if (xlsxPoints.function) {
// xlsxPointsInfosList.push(cloneDeep(xlsxPoints))
// }
}
const file = ref<any>()
// 获取xlsx文件并使用文件流进行解析
@@ -584,6 +668,7 @@ const handleNodelClick = async (row: any) => {
selectedType.value = row.type // 点击节点时更新
cellInputValue.value = ''
cellValues.value = [] // 新的 cell 节点清空数据
cellImportValue.value=''
}
console.log(row.index + 'row.indexrow.index')
@@ -620,12 +705,13 @@ const handleDelete = (row: any) => {
}
const submitXlsxPoints = async () => {
console.log('单元格输入内容:', cellValues.value)
console.log('单元格输入内容:', cellImportValue.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), // 提取值数组
keyWords:cellImportValue.value
})
xlsxPointsInfosList = []
console.log(res)

View File

@@ -20,15 +20,36 @@
:inline="true"
label-width="68px"
>
<!-- <el-form-item label="用户名称" prop="username">-->
<!-- <el-input-->
<!-- v-model="queryParams.username"-->
<!-- placeholder="请输入用户名称"-->
<!-- clearable-->
<!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="试题编号" prop="quNum">
<el-input
v-model="queryParams.quNum"
placeholder="请输入试题编号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="题干" prop="content">
<el-input
v-model="queryParams.content"
placeholder="请输入题干"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="examStatus">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
class="!w-240px"
>
<el-option label="启用" :value="0" />
<el-option label="禁用" :value="1" />
</el-select>
</el-form-item>
<!-- <el-form-item label="手机号码" prop="mobile">-->
<!-- <el-input-->
<!-- v-model="queryParams.mobile"-->
@@ -59,7 +80,7 @@
<el-radio-button :label="''">全部</el-radio-button>
<el-radio-button :label="'0'">审核通过</el-radio-button>
<el-radio-button :label="'1'">未审核</el-radio-button>
<el-radio-button :label="'2'">待审核</el-radio-button>
<!-- <el-radio-button :label="'2'">待审核</el-radio-button> -->
<el-radio-button :label="'3'">审核未通过</el-radio-button>
</el-radio-group>
</el-form-item>
@@ -75,7 +96,7 @@
<!-- </el-form-item>-->
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" />搜索</el-button>
<!-- <el-button @click="resetQuery"><Icon icon="ep:refresh" />重置</el-button> -->
<el-button @click="resetQuery"><Icon icon="ep:refresh" />重置</el-button>
<el-button
type="danger"
class="ele-btn-del"
@@ -127,7 +148,15 @@
plain
@click="handleAuditTrue('True')"
>
<Icon icon="ep:plus" /> 审核试题
<Icon icon="ep:check" /> 审核通过试题
</el-button>
<el-button
v-if="queryParams.audit === '1' && audioTrue"
type="primary"
plain
@click="handleAuditTrue('False')"
>
<Icon icon="ep:close-bold" /> 审核不通过试题
</el-button>
<el-button
v-if="queryParams.audit === '' || queryParams.audit === '0'"
@@ -150,6 +179,11 @@
prop="quNum"
:show-overflow-tooltip="true"
/>
<el-table-column label="题干" align="center" prop="content" width="120">
<template #default="{ row }">
{{ getFirstNChineseChars(row.content, 5) }}
</template>
</el-table-column>
<el-table-column label="专业" align="center" prop="specialtyName" width="120" />
<el-table-column
label="课程"
@@ -233,12 +267,17 @@
:show-overflow-tooltip="true"
/>
<el-table-column
label="创建时间"
:label="tenantId === 1 ? '创建时间' : '更新时间'"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180"
/>
>
<template #default="scope">
<span>
{{ dateFormatter(scope.row, null, tenantId === 1 ? scope.row.createTime : scope.row.updateTime) }}
</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160">
<template #default="scope">
<div class="flex items-center justify-center">
@@ -372,9 +411,10 @@ import { handleTree } from '@/utils/tree'
import * as SpecialtyApi from '@/api/points'
import { useSettingStore } from '@/store/modules/settings'
import { TaskStatusEnum } from '@/api/bpm/task'
import { status } from 'nprogress'
const settingStore = useSettingStore()
defineOptions({ name: 'SystemUser' })
const tenantId = getTenantId()
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
@@ -392,7 +432,10 @@ const queryParams = reactive({
chapteridDictText: '',
pageNo: 1,
pageSize: 10,
audit: ''
audit: '',
status:'',
quNum:'',
content:''
})
const queryFormRef = ref() // 搜索的表单
const specialtyList = ref<Tree[]>([]) // 树形结构
@@ -887,6 +930,24 @@ const handleRole = (row: UserApi.UserVO) => {
assignRoleFormRef.value.open(row)
}
function getFirstNChineseChars(htmlStr) {
if (!htmlStr) return ''
// 将 HTML 转为纯文本
const tempDiv = document.createElement('div')
tempDiv.innerHTML = htmlStr
let text = tempDiv.textContent || tempDiv.innerText || ''
// 去掉空格和换行
text = text.replace(/\s+/g, '')
// 匹配汉字
const match = text.match(/[\u4e00-\u9fa5]/g)
if (!match) return ''
return match.slice(0, 6).join('')
}
/** 初始化 */
onMounted(() => {
getList()

View File

@@ -7,8 +7,8 @@
:rules="formRules"
label-width="120px"
>
<el-form-item label="学校用户名" prop="name">
<el-input v-model="formData.name" placeholder="请输入学校用户名" />
<el-form-item label="学校名" prop="name">
<el-input v-model="formData.name" placeholder="请输入学校名" />
</el-form-item>
<el-form-item label="学校用户权限" prop="packageId">
<el-select v-model="formData.packageId" clearable placeholder="请选择学校用户权限">
@@ -26,13 +26,13 @@
<el-form-item label="联系手机" prop="contactMobile">
<el-input v-model="formData.contactMobile" placeholder="请输入联系手机" />
</el-form-item>
<el-form-item v-if="formData.id === undefined" label="用户名称" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名称" />
<el-form-item v-if="formData.id === undefined" label="管理员账号" prop="username">
<el-input v-model="formData.username" placeholder="管理员账号" />
</el-form-item>
<el-form-item v-if="formData.id === undefined" label="用户密码" prop="password">
<el-form-item v-if="formData.id === undefined" label="管理员密码" prop="password">
<el-input
v-model="formData.password"
placeholder="请输入用户密码"
placeholder="请输入管理员密码"
show-password
type="password"
/>
@@ -54,8 +54,8 @@
value-format="x"
/>
</el-form-item>
<el-form-item label="绑定域名" prop="website">
<el-input v-model="formData.website" placeholder="请输入绑定域名" />
<el-form-item label="绑定MAC地址" prop="website">
<el-input v-model="formData.website" placeholder="请输入绑定MAC地址" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
@@ -111,14 +111,14 @@ const formData = ref({
password: undefined
})
const formRules = reactive({
name: [{ required: true, message: '学校用户名不能为空', trigger: 'blur' }],
name: [{ required: true, message: '学校名不能为空', trigger: 'blur' }],
packageId: [{ required: true, message: '学校用户权限不能为空', trigger: 'blur' }],
contactName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
expireTime: [{ required: true, message: '过期时间不能为空', trigger: 'blur' }],
website: [{ required: true, message: '绑定域名不能为空', trigger: 'blur' }],
username: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }],
password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }]
website: [{ required: true, message: '绑定MAC地址不能为空', trigger: 'blur' }],
username: [{ required: true, message: '管理员账号不能为空', trigger: 'blur' }],
password: [{ required: true, message: '管理员密码不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
const packageList = ref([] as TenantPackageApi.TenantPackageVO[]) // 租户套餐

View File

@@ -10,10 +10,10 @@
:inline="true"
label-width="68px"
>
<el-form-item label="学校用户名" prop="name">
<el-form-item label="学校名" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入学校用户名"
placeholder="请输入学校名"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
@@ -125,7 +125,8 @@
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="绑定域名" align="center" prop="website" width="180" />
<el-table-column label="绑定MAC地址" align="center" prop="website" width="180" />
<el-table-column label="管理员账号" align="center" prop="username" width="180" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
@@ -138,20 +139,20 @@
width="180"
:formatter="dateFormatter"
/>
<el-table-column
<!-- <el-table-column
label="连接状态(需点击状态刷新)"
align="center"
prop="websiteStatus"
width="180"
/>
/> -->
<el-table-column label="操作" align="center" min-width="110" fixed="right">
<template #default="scope">
<el-button
link
type="primary"
@click="openStatus(scope.row)"
@click="setPassword(scope.row.contactUserId)"
>
状态
重置密码
</el-button>
<el-button
link
@@ -260,6 +261,55 @@ const openStatus = (row: any) => {
}
})
}
const setPassword = async (id) => {
if (!id) return
try {
// 1⃣ 弹出输入框,让管理员输入新密码
const { value: newPassword } = await ElMessageBox.prompt('请输入新的密码:', '重置密码', {
confirmButtonText: '下一步',
cancelButtonText: '取消',
inputType: 'password',
inputPlaceholder: '请输入新密码',
inputValidator: (val) => {
if (!val) return '密码不能为空'
if (val.length < 4) return '密码至少 4 位'
return true
},
})
// 2⃣ 再次确认是否要重置
await ElMessageBox.confirm(
`确认将该用户密码重置为:${newPassword}`,
'确认操作',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}
)
// 3⃣ 调用后端接口发请求
const data = {
id,
password: newPassword,
}
const res = await TenantApi.resetPassword(data) d
// 4⃣ 显示成功提示
ElMessage.success(res?.msg || '密码重置成功!')
} catch (err) {
if (err === 'cancel' || err === 'close') {
// 用户取消操作
return
}
console.error('重置密码失败:', err)
ElMessage.error('操作失败,请重试')
}
}
/** 获取时分秒 */
const getTimeWithAmPm = (): string => {
const now = new Date()

View File

@@ -27,6 +27,16 @@
/>
</el-form-item>
<!-- 顶部全选复选框 -->
<el-checkbox
v-model="checkAllStatus"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
:disabled="isChoice"
>
全选
</el-checkbox>
<!-- 题型 -->
<el-form-item label="题型" prop="spName">
<el-select v-model="form.spName" placeholder="请选择题型" clearable :disabled="isUpdate">
@@ -305,6 +315,24 @@ const calcSubtotal = () => {
form.value.subtotalScore = n * s
}
const isChoice = ref(false); // 示例状态
const checkAllStatus = ref(true);
const isIndeterminate = ref(false);
// 点击“全选/全不选”复选框
const handleCheckAllChange = async () => {
await nextTick() // 等树加载完成再执行,避免空指针
if (!treeRef.value) return
if (checkAllStatus.value) {
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
form.value.pointName = allKeys
treeRef.value?.setCheckedKeys(allKeys)
} else {
form.value.pointName = []
treeRef.value.setCheckedKeys([])
}
isIndeterminate.value = false
}
/** 选中回调 */
const handleCheckChange = () => {
form.value.pointName = treeRef.value.getCheckedKeys()

View File

@@ -12,13 +12,13 @@
label-width="120px"
@submit.prevent=""
>
<el-form-item label="试卷ID" prop="taskId">
<!-- <el-form-item label="试卷ID" prop="taskId">
<el-input clearable v-model="form.taskId" placeholder="请输入试卷ID" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="批次" prop="batch">
<!-- <el-form-item label="批次" prop="batch">
<el-input clearable v-model="form.batch" placeholder="请输入批次" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="考试时长" prop="answerTime">
<el-time-picker
v-model="form.answerTime"

View File

@@ -55,6 +55,17 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否共享" prop="share">
<el-radio-group v-model="form.share">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.SYS_YES_NO)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
@@ -103,7 +114,8 @@ const [form, resetFields, assignFields] = useFormData({
updateTime: '',
updateBy: '',
deptId: '',
userId: ''
userId: '',
share:1
})
/** 表单验证规则 */

View File

@@ -76,7 +76,7 @@ const queryParams = reactive({
pageSize: 10,
status: '0',
isTemplate: '0',
taskType:'1'
});
// 获取数据

View File

@@ -84,6 +84,11 @@
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.isTemplate" />
</template>
</el-table-column>
<el-table-column label="是否共享" align="center" prop="share" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.share" />
</template>
</el-table-column>
<el-table-column label="启用状态" align="center" prop="status" width="120">
<template #default="scope">
<el-switch

View File

@@ -27,6 +27,16 @@
/>
</el-form-item>
<!-- 顶部全选复选框 -->
<el-checkbox
v-model="checkAllStatus"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
:disabled="isChoice"
>
全选
</el-checkbox>
<!-- 题型 -->
<el-form-item label="题型" prop="spName">
<el-select v-model="form.spName" placeholder="请选择题型" clearable :disabled="isUpdate">
@@ -305,6 +315,24 @@ const calcSubtotal = () => {
form.value.subtotalScore = n * s
}
const isChoice = ref(false); // 示例状态
const checkAllStatus = ref(true);
const isIndeterminate = ref(false);
// 点击“全选/全不选”复选框
const handleCheckAllChange = async () => {
await nextTick() // 等树加载完成再执行,避免空指针
if (!treeRef.value) return
if (checkAllStatus.value) {
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
form.value.pointName = allKeys
treeRef.value?.setCheckedKeys(allKeys)
} else {
form.value.pointName = []
treeRef.value.setCheckedKeys([])
}
isIndeterminate.value = false
}
/** 选中回调 */
const handleCheckChange = () => {
form.value.pointName = treeRef.value.getCheckedKeys()

View File

@@ -12,13 +12,13 @@
label-width="120px"
@submit.prevent=""
>
<el-form-item label="试卷ID" prop="taskId">
<!-- <el-form-item label="试卷ID" prop="taskId">
<el-input clearable v-model="form.taskId" placeholder="请输入试卷ID" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="批次" prop="batch">
<!-- <el-form-item label="批次" prop="batch">
<el-input clearable v-model="form.batch" placeholder="请输入批次" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="考试时长" prop="answerTime">
<el-time-picker
v-model="form.answerTime"

View File

@@ -55,6 +55,17 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否共享" prop="share">
<el-radio-group v-model="form.share">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.SYS_YES_NO)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
@@ -103,7 +114,8 @@ const [form, resetFields, assignFields] = useFormData({
updateTime: '',
updateBy: '',
deptId: '',
userId: ''
userId: '',
share:1
})
/** 表单验证规则 */

View File

@@ -76,7 +76,6 @@ const queryParams = reactive({
pageSize: 10,
status: '0',
isTemplate: '0',
taskType:'2'
});
// 获取数据

View File

@@ -85,6 +85,11 @@
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.isTemplate" />
</template>
</el-table-column>
<el-table-column label="是否共享" align="center" prop="share" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.share" />
</template>
</el-table-column>
<el-table-column label="启用状态" align="center" prop="status" width="120">
<template #default="scope">

View File

@@ -27,6 +27,16 @@
/>
</el-form-item>
<!-- 顶部全选复选框 -->
<el-checkbox
v-model="checkAllStatus"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
:disabled="isChoice"
>
全选
</el-checkbox>
<!-- 题型 -->
<el-form-item label="题型" prop="spName">
<el-select v-model="form.spName" placeholder="请选择题型" clearable :disabled="isUpdate">
@@ -306,6 +316,26 @@ const calcSubtotal = () => {
form.value.subtotalScore = n * s
}
const isChoice = ref(false); // 示例状态
const checkAllStatus = ref(true);
const isIndeterminate = ref(false);
// 点击“全选/全不选”复选框
const handleCheckAllChange = async () => {
await nextTick() // 等树加载完成再执行,避免空指针
if (!treeRef.value) return
if (checkAllStatus.value) {
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
form.value.pointName = allKeys
treeRef.value?.setCheckedKeys(allKeys)
} else {
form.value.pointName = []
treeRef.value.setCheckedKeys([])
}
isIndeterminate.value = false
}
/** 选中回调 */
const handleCheckChange = () => {
form.value.pointName = treeRef.value.getCheckedKeys()

View File

@@ -12,13 +12,13 @@
label-width="120px"
@submit.prevent=""
>
<el-form-item label="试卷ID" prop="taskId">
<!-- <el-form-item label="试卷ID" prop="taskId">
<el-input clearable v-model="form.taskId" placeholder="请输入试卷ID" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="批次" prop="batch">
<!-- <el-form-item label="批次" prop="batch">
<el-input clearable v-model="form.batch" placeholder="请输入批次" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="考试时长" prop="answerTime">
<el-time-picker
v-model="form.answerTime"

View File

@@ -55,6 +55,17 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否共享" prop="share">
<el-radio-group v-model="form.share">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.SYS_YES_NO)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
@@ -103,7 +114,8 @@ const [form, resetFields, assignFields] = useFormData({
updateTime: '',
updateBy: '',
deptId: '',
userId: ''
userId: '',
share:1
})
/** 表单验证规则 */

View File

@@ -76,7 +76,6 @@ const queryParams = reactive({
pageSize: 10,
status: '0',
isTemplate: '0',
taskType:'5'
});
// 获取数据

View File

@@ -86,6 +86,11 @@
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.isTemplate" />
</template>
</el-table-column>
<el-table-column label="是否共享" align="center" prop="share" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.share" />
</template>
</el-table-column>
<el-table-column label="启用状态" align="center" prop="status" width="120">
<template #default="scope">
<el-switch

View File

@@ -27,6 +27,16 @@
/>
</el-form-item>
<!-- 顶部全选复选框 -->
<el-checkbox
v-model="checkAllStatus"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
:disabled="isChoice"
>
全选
</el-checkbox>
<!-- 题型 -->
<el-form-item label="题型" prop="spName">
<el-select v-model="form.spName" placeholder="请选择题型" clearable :disabled="isUpdate">
@@ -304,6 +314,24 @@ const calcSubtotal = () => {
form.value.subtotalScore = n * s
}
const isChoice = ref(false); // 示例状态
const checkAllStatus = ref(true);
const isIndeterminate = ref(false);
// 点击“全选/全不选”复选框
const handleCheckAllChange = async () => {
await nextTick() // 等树加载完成再执行,避免空指针
if (!treeRef.value) return
console.log(checkAllStatus.value+"checkAllStatus.value")
if (checkAllStatus.value) {
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
form.value.pointName = allKeys
treeRef.value?.setCheckedKeys(allKeys)
} else {
form.value.pointName = []
treeRef.value.setCheckedKeys([])
}
isIndeterminate.value = false
}
/** 选中回调 */
const handleCheckChange = () => {
form.value.pointName = treeRef.value.getCheckedKeys()

View File

@@ -12,13 +12,13 @@
label-width="120px"
@submit.prevent=""
>
<el-form-item label="试卷ID" prop="taskId">
<!-- <el-form-item label="试卷ID" prop="taskId">
<el-input clearable v-model="form.taskId" placeholder="请输入试卷ID" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="批次" prop="batch">
<!-- <el-form-item label="批次" prop="batch">
<el-input clearable v-model="form.batch" placeholder="请输入批次" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="考试时长" prop="answerTime">
<el-time-picker
v-model="form.answerTime"

View File

@@ -55,6 +55,17 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否共享" prop="share">
<el-radio-group v-model="form.share">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.SYS_YES_NO)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
@@ -103,7 +114,8 @@ const [form, resetFields, assignFields] = useFormData({
updateTime: '',
updateBy: '',
deptId: '',
userId: ''
userId: '',
share:1
})
/** 表单验证规则 */

View File

@@ -76,7 +76,6 @@ const queryParams = reactive({
pageSize: 10,
status: '0',
isTemplate: '0',
taskType:'4'
});
// 获取数据

View File

@@ -86,6 +86,11 @@
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.isTemplate" />
</template>
</el-table-column>
<el-table-column label="是否共享" align="center" prop="share" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.share" />
</template>
</el-table-column>
<el-table-column label="启用状态" align="center" prop="status" width="120">
<template #default="scope">
<el-switch

View File

@@ -26,6 +26,15 @@
@check="handleCheckChange"
/>
</el-form-item>
<!-- 顶部全选复选框 -->
<el-checkbox
v-model="checkAllStatus"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
:disabled="isChoice"
>
全选
</el-checkbox>
<!-- 题型 -->
<el-form-item label="题型" prop="spName">
@@ -306,6 +315,26 @@ const calcSubtotal = () => {
form.value.subtotalScore = n * s
}
const isChoice = ref(false); // 示例状态
const checkAllStatus = ref(true);
const isIndeterminate = ref(false);
// 点击“全选/全不选”复选框
const handleCheckAllChange = async () => {
await nextTick() // 等树加载完成再执行,避免空指针
if (!treeRef.value) return
console.log(checkAllStatus.value+"checkAllStatus.value")
if (checkAllStatus.value) {
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
form.value.pointName = allKeys
treeRef.value?.setCheckedKeys(allKeys)
} else {
form.value.pointName = []
treeRef.value.setCheckedKeys([])
}
isIndeterminate.value = false
}
/** 选中回调 */
const handleCheckChange = () => {
form.value.pointName = treeRef.value.getCheckedKeys()

View File

@@ -12,13 +12,13 @@
label-width="120px"
@submit.prevent=""
>
<el-form-item label="试卷ID" prop="taskId">
<!-- <el-form-item label="试卷ID" prop="taskId">
<el-input clearable v-model="form.taskId" placeholder="请输入试卷ID" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="批次" prop="batch">
<!-- <el-form-item label="批次" prop="batch">
<el-input clearable v-model="form.batch" placeholder="请输入批次" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="考试时长" prop="answerTime">
<el-time-picker
v-model="form.answerTime"

View File

@@ -54,6 +54,17 @@
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否共享" prop="share">
<el-radio-group v-model="form.share">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.SYS_YES_NO)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
@@ -103,7 +114,8 @@ const [form, resetFields, assignFields] = useFormData({
updateTime: '',
updateBy: '',
deptId: '',
userId: ''
userId: '',
share: 1
})
/** 表单验证规则 */

View File

@@ -76,7 +76,6 @@ const queryParams = reactive({
pageSize: 10,
status: '0',
isTemplate: '0',
taskType:'3'
});
// 获取数据

View File

@@ -86,6 +86,11 @@
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.isTemplate" />
</template>
</el-table-column>
<el-table-column label="是否共享" align="center" prop="share" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.share" />
</template>
</el-table-column>
<el-table-column label="启用状态" align="center" prop="status" width="120">
<template #default="scope">
<el-switch

View File

@@ -26,6 +26,15 @@
@check="handleCheckChange"
/>
</el-form-item>
<!-- 顶部全选复选框 -->
<el-checkbox
v-model="checkAllStatus"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
:disabled="isChoice"
>
全选
</el-checkbox>
<!-- 题型 -->
<el-form-item label="题型" prop="spName">
@@ -305,6 +314,26 @@ const calcSubtotal = () => {
form.value.subtotalScore = n * s
}
const isChoice = ref(false); // 示例状态
const checkAllStatus = ref(true);
const isIndeterminate = ref(false);
// 点击“全选/全不选”复选框
const handleCheckAllChange = async () => {
await nextTick() // 等树加载完成再执行,避免空指针
if (!treeRef.value) return
console.log(checkAllStatus.value+"checkAllStatus.value")
if (checkAllStatus.value) {
const allKeys = getAllTreeKeys(pointOptions.value).map(String)
form.value.pointName = allKeys
treeRef.value?.setCheckedKeys(allKeys)
} else {
form.value.pointName = []
treeRef.value.setCheckedKeys([])
}
isIndeterminate.value = false
}
/** 选中回调 */
const handleCheckChange = () => {
form.value.pointName = treeRef.value.getCheckedKeys()

View File

@@ -12,13 +12,13 @@
label-width="120px"
@submit.prevent=""
>
<el-form-item label="试卷ID" prop="taskId">
<!-- <el-form-item label="试卷ID" prop="taskId">
<el-input clearable v-model="form.taskId" placeholder="请输入试卷ID" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="批次" prop="batch">
<!-- <el-form-item label="批次" prop="batch">
<el-input clearable v-model="form.batch" placeholder="请输入批次" disabled/>
</el-form-item>
</el-form-item> -->
<el-form-item label="考试时长" prop="answerTime">
<el-time-picker
v-model="form.answerTime"

View File

@@ -55,6 +55,17 @@
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否共享" prop="share">
<el-radio-group v-model="form.share">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.SYS_YES_NO)"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleCancel">取消</el-button>
@@ -102,7 +113,8 @@ const [form, resetFields, assignFields] = useFormData({
updateTime: '',
updateBy: '',
deptId: '',
userId: ''
userId: '',
share: 1
})
/** 表单验证规则 */

View File

@@ -76,7 +76,6 @@ const queryParams = reactive({
pageSize: 10,
status: '0',
isTemplate: '0',
taskType:'0'
});
// 获取数据

View File

@@ -86,6 +86,11 @@
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.isTemplate" />
</template>
</el-table-column>
<el-table-column label="是否共享" align="center" prop="share" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYS_YES_NO" :value="scope.row.share" />
</template>
</el-table-column>
<el-table-column label="启用状态" align="center" prop="status" width="120">
<template #default="scope">
<el-switch