feat: 新增锁屏、作业模式
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
This commit is contained in:
parent
0fd4d0d39c
commit
adbfc847ec
@ -1,6 +1,12 @@
|
|||||||
|
import { post } from '#/api/http'
|
||||||
|
|
||||||
import { BasicService } from './basic'
|
import { BasicService } from './basic'
|
||||||
|
|
||||||
class ClassService extends BasicService {
|
class ClassService extends BasicService {
|
||||||
|
async lockScreen(data: { classId: any; status: 0 | 1 }) {
|
||||||
|
await post('/school/classScreenLock/lock', data)
|
||||||
|
}
|
||||||
|
|
||||||
protected findPageUrl(): string {
|
protected findPageUrl(): string {
|
||||||
return '/org/class/list'
|
return '/org/class/list'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import MjTable, {
|
|||||||
mj_form_text,
|
mj_form_text,
|
||||||
} from '#/components/mj/mj-table'
|
} from '#/components/mj/mj-table'
|
||||||
import { pattern_phone } from '#/components/mj/mj-table/fmt'
|
import { pattern_phone } from '#/components/mj/mj-table/fmt'
|
||||||
|
import hud from '#/utils/hud'
|
||||||
import obj from '#/utils/obj'
|
import obj from '#/utils/obj'
|
||||||
import { grades } from '#/store/basic-data'
|
import { grades } from '#/store/basic-data'
|
||||||
|
|
||||||
@ -73,6 +74,7 @@ const addFields = [
|
|||||||
'contact',
|
'contact',
|
||||||
'phone',
|
'phone',
|
||||||
'currencyFlag',
|
'currencyFlag',
|
||||||
|
'workMode',
|
||||||
'gradeId',
|
'gradeId',
|
||||||
'masterTeacherId',
|
'masterTeacherId',
|
||||||
]
|
]
|
||||||
@ -148,12 +150,27 @@ const editForm = {
|
|||||||
name: 'VxeSwitch',
|
name: 'VxeSwitch',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'workMode',
|
||||||
|
title: '作业模式',
|
||||||
|
span: 12,
|
||||||
|
itemRender: {
|
||||||
|
name: 'VxeSwitch',
|
||||||
|
props: {
|
||||||
|
openValue: 1,
|
||||||
|
closeValue: 0,
|
||||||
|
openLabel: '已开启',
|
||||||
|
closeLabel: '未开启',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
),
|
),
|
||||||
data: {},
|
data: {},
|
||||||
},
|
},
|
||||||
addFields,
|
addFields,
|
||||||
updateFields: ['id', ...addFields],
|
updateFields: ['id', ...addFields],
|
||||||
beforeSaveOrUpdate(formData: any) {
|
beforeSaveOrUpdate(formData: any) {
|
||||||
|
formData.workMode ??= 0
|
||||||
if (userInfo.value.isOnlyStaff) {
|
if (userInfo.value.isOnlyStaff) {
|
||||||
formData.schoolId = userInfo.value.schoolId
|
formData.schoolId = userInfo.value.schoolId
|
||||||
}
|
}
|
||||||
@ -176,6 +193,7 @@ const editForm = {
|
|||||||
if (userInfo.value.gradeId) {
|
if (userInfo.value.gradeId) {
|
||||||
data.gradeId = userInfo.value.gradeId
|
data.gradeId = userInfo.value.gradeId
|
||||||
}
|
}
|
||||||
|
data.workMode ??= 0
|
||||||
if (edit) {
|
if (edit) {
|
||||||
gridRef.value.hideEditFormItems('schoolName')
|
gridRef.value.hideEditFormItems('schoolName')
|
||||||
return data
|
return data
|
||||||
@ -200,6 +218,13 @@ const searchForm = {
|
|||||||
// 表格
|
// 表格
|
||||||
const grid = {
|
const grid = {
|
||||||
columns: obj.joinObjs<any>(
|
columns: obj.joinObjs<any>(
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 160,
|
||||||
|
slots: {
|
||||||
|
default: 'operation',
|
||||||
|
},
|
||||||
|
},
|
||||||
{ type: 'seq' },
|
{ type: 'seq' },
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'name',
|
||||||
@ -216,6 +241,12 @@ const grid = {
|
|||||||
default: 'currencyFlag',
|
default: 'currencyFlag',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '作业模式',
|
||||||
|
slots: {
|
||||||
|
default: 'workMode',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'contact',
|
field: 'contact',
|
||||||
title: '联系人',
|
title: '联系人',
|
||||||
@ -249,6 +280,35 @@ function currencyFlagChange(row: any) {
|
|||||||
row.currencyFlag = oldFlag
|
row.currencyFlag = oldFlag
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 作业模式
|
||||||
|
function workModeChange(row: any) {
|
||||||
|
const oldMode = row.workMode === 1 ? 0 : 1
|
||||||
|
classService
|
||||||
|
.saveOrUpdate({
|
||||||
|
id: row.id,
|
||||||
|
workMode: row.workMode,
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
row.workMode = oldMode
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateScreenLock(row: any, status: 0 | 1) {
|
||||||
|
const option = status === 1 ? '锁屏' : '解锁'
|
||||||
|
hud.confirmLoad(`确定${option}【${row.name}】吗?`, {
|
||||||
|
task: async () => {
|
||||||
|
await classService.lockScreen({
|
||||||
|
classId: row.id,
|
||||||
|
status,
|
||||||
|
})
|
||||||
|
gridRef.value?.reload()
|
||||||
|
},
|
||||||
|
hideError: true,
|
||||||
|
option,
|
||||||
|
hideSuccess: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -263,12 +323,30 @@ function currencyFlagChange(row: any) {
|
|||||||
:service="classService"
|
:service="classService"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
|
<template #operation="{ row }">
|
||||||
|
<el-button type="danger" @click="updateScreenLock(row, 1)">
|
||||||
|
锁屏
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" @click="updateScreenLock(row, 0)">
|
||||||
|
解锁
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
<template #currencyFlag="{ row }">
|
<template #currencyFlag="{ row }">
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="row.currencyFlag"
|
v-model="row.currencyFlag"
|
||||||
@click="currencyFlagChange(row)"
|
@click="currencyFlagChange(row)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
<template #workMode="{ row }">
|
||||||
|
<vxe-switch
|
||||||
|
v-model="row.workMode"
|
||||||
|
:close-value="0"
|
||||||
|
close-label="未开启"
|
||||||
|
:open-value="1"
|
||||||
|
open-label="已开启"
|
||||||
|
@change="workModeChange(row)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</MjTable>
|
</MjTable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -212,20 +212,41 @@ function resetZoom() {
|
|||||||
|
|
||||||
// ======================== 讲解模式 ========================
|
// ======================== 讲解模式 ========================
|
||||||
const currentIndex = ref(0)
|
const currentIndex = ref(0)
|
||||||
|
const answerExpanded = ref(false)
|
||||||
|
const explanationExpanded = ref(false)
|
||||||
|
|
||||||
const currentQuestion = computed(() => {
|
const currentQuestion = computed(() => {
|
||||||
return paperDetail.value[currentIndex.value] || null
|
return paperDetail.value[currentIndex.value] || null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const hasAnswer = computed(() => Boolean(currentQuestion.value?.xkwTitle?.answer))
|
||||||
|
const hasExplanation = computed(() =>
|
||||||
|
Boolean(currentQuestion.value?.xkwTitle?.explanation),
|
||||||
|
)
|
||||||
|
|
||||||
function getTitleKey(item: any) {
|
function getTitleKey(item: any) {
|
||||||
return (
|
return (
|
||||||
item?.xkwTitle?.titleId ?? item?.titleId ?? item?.xkwTitle?.id ?? item?.id
|
item?.xkwTitle?.titleId ?? item?.titleId ?? item?.xkwTitle?.id ?? item?.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function collapseAnswerAnalysis() {
|
||||||
|
answerExpanded.value = false
|
||||||
|
explanationExpanded.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAnswer() {
|
||||||
|
answerExpanded.value = !answerExpanded.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleExplanation() {
|
||||||
|
explanationExpanded.value = !explanationExpanded.value
|
||||||
|
}
|
||||||
|
|
||||||
async function enterExplaining() {
|
async function enterExplaining() {
|
||||||
initLeftWidth()
|
initLeftWidth()
|
||||||
resetZoom()
|
resetZoom()
|
||||||
|
collapseAnswerAnalysis()
|
||||||
phase.value = 'explaining'
|
phase.value = 'explaining'
|
||||||
currentIndex.value = 0
|
currentIndex.value = 0
|
||||||
await callExplainApi(1)
|
await callExplainApi(1)
|
||||||
@ -250,6 +271,7 @@ async function callExplainApi(status: number, overrideQuestionId?: string) {
|
|||||||
function prevQuestion() {
|
function prevQuestion() {
|
||||||
if (currentIndex.value > 0) {
|
if (currentIndex.value > 0) {
|
||||||
currentIndex.value--
|
currentIndex.value--
|
||||||
|
collapseAnswerAnalysis()
|
||||||
callExplainApi(1)
|
callExplainApi(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,12 +279,14 @@ function prevQuestion() {
|
|||||||
function nextQuestion() {
|
function nextQuestion() {
|
||||||
if (currentIndex.value < paperDetail.value.length - 1) {
|
if (currentIndex.value < paperDetail.value.length - 1) {
|
||||||
currentIndex.value++
|
currentIndex.value++
|
||||||
|
collapseAnswerAnalysis()
|
||||||
callExplainApi(1)
|
callExplainApi(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToQuestion(idx: number) {
|
function goToQuestion(idx: number) {
|
||||||
currentIndex.value = idx
|
currentIndex.value = idx
|
||||||
|
collapseAnswerAnalysis()
|
||||||
callExplainApi(1)
|
callExplainApi(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,8 +426,8 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
<div class="explain-panel-header">
|
<div class="explain-panel-header">
|
||||||
<span class="panel-title">第 {{ currentIndex + 1 }} 题</span>
|
<span class="panel-title">第 {{ currentIndex + 1 }} 题</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="explain-panel-body">
|
<div class="explain-panel-body question-panel-body">
|
||||||
<div class="explain-zoom-layer">
|
<div class="question-zoom-layer">
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
Array.isArray(currentQuestion.xkwTitle?.questionList) &&
|
Array.isArray(currentQuestion.xkwTitle?.questionList) &&
|
||||||
@ -441,24 +465,34 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
<span class="panel-title">答案与解析</span>
|
<span class="panel-title">答案与解析</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="explain-panel-body">
|
<div class="explain-panel-body">
|
||||||
<div class="explain-zoom-layer">
|
<div class="answer-zoom-layer">
|
||||||
<!-- 答案 -->
|
<!-- 答案 -->
|
||||||
<div class="info-section" v-if="currentQuestion.xkwTitle?.answer">
|
<div class="answer-analysis-section">
|
||||||
<div class="info-label">【答案】</div>
|
<div class="answer-analysis-header">
|
||||||
<div class="info-content">
|
<span class="answer-analysis-title">【答案】</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="answerExpanded && hasAnswer" class="info-content">
|
||||||
<latex-text :text="currentQuestion.xkwTitle.answer" />
|
<latex-text :text="currentQuestion.xkwTitle.answer" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="answer-analysis-collapsed">
|
||||||
|
{{ hasAnswer ? '答案已收起,点击底部“展开答案”查看' : '暂无答案' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 解析 -->
|
<!-- 解析 -->
|
||||||
<div
|
<div class="answer-analysis-section">
|
||||||
class="info-section"
|
<div class="answer-analysis-header">
|
||||||
v-if="currentQuestion.xkwTitle?.explanation"
|
<span class="answer-analysis-title">【解析】</span>
|
||||||
>
|
</div>
|
||||||
<div class="info-label">【解析】</div>
|
<div
|
||||||
<div class="info-content">
|
v-if="explanationExpanded && hasExplanation"
|
||||||
|
class="info-content"
|
||||||
|
>
|
||||||
<latex-text :text="currentQuestion.xkwTitle.explanation" />
|
<latex-text :text="currentQuestion.xkwTitle.explanation" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="answer-analysis-collapsed">
|
||||||
|
{{ hasExplanation ? '解析已收起,点击底部“展开解析”查看' : '暂无解析' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 统计数据 -->
|
<!-- 统计数据 -->
|
||||||
@ -531,6 +565,12 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-right">
|
<div class="footer-right">
|
||||||
|
<el-button :disabled="!hasAnswer" @click="toggleAnswer">
|
||||||
|
{{ answerExpanded ? '收起答案' : '展开答案' }}
|
||||||
|
</el-button>
|
||||||
|
<el-button :disabled="!hasExplanation" @click="toggleExplanation">
|
||||||
|
{{ explanationExpanded ? '收起解析' : '展开解析' }}
|
||||||
|
</el-button>
|
||||||
<el-button @click="resetZoom">重置缩放 {{ zoomPercent }}%</el-button>
|
<el-button @click="resetZoom">重置缩放 {{ zoomPercent }}%</el-button>
|
||||||
<el-button type="danger" @click="endExplaining">结束讲解</el-button>
|
<el-button type="danger" @click="endExplaining">结束讲解</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -690,6 +730,7 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
.explain-panel-header {
|
.explain-panel-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
padding: 14px 20px;
|
padding: 14px 20px;
|
||||||
border-bottom: 1px solid #ebeef5;
|
border-bottom: 1px solid #ebeef5;
|
||||||
}
|
}
|
||||||
@ -706,12 +747,22 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
overflow: hidden auto;
|
overflow: hidden auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.explain-zoom-layer {
|
.question-panel-body {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-zoom-layer {
|
||||||
|
width: 100%;
|
||||||
|
transform: scale(var(--explain-zoom-scale));
|
||||||
|
transform-origin: left top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer-zoom-layer {
|
||||||
zoom: var(--explain-zoom-scale);
|
zoom: var(--explain-zoom-scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@supports not (zoom: 1) {
|
@supports not (zoom: 1) {
|
||||||
.explain-zoom-layer {
|
.answer-zoom-layer {
|
||||||
width: calc(100% / var(--explain-zoom-scale));
|
width: calc(100% / var(--explain-zoom-scale));
|
||||||
transform: scale(var(--explain-zoom-scale));
|
transform: scale(var(--explain-zoom-scale));
|
||||||
transform-origin: left top;
|
transform-origin: left top;
|
||||||
@ -727,6 +778,33 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
border-bottom: 1px dashed #ebeef5;
|
border-bottom: 1px dashed #ebeef5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.answer-analysis-section {
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px dashed #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer-analysis-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer-analysis-title {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #246cff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.answer-analysis-collapsed {
|
||||||
|
padding: 18px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #909399;
|
||||||
|
text-align: center;
|
||||||
|
background: #f7f8fa;
|
||||||
|
border: 1px dashed #dcdfe6;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.info-label {
|
.info-label {
|
||||||
min-width: 60px;
|
min-width: 60px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -852,19 +930,24 @@ async function getTitleStudentInfo(titleId: string, markType: number) {
|
|||||||
.footer-center {
|
.footer-center {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
justify-content: center;
|
min-width: 0;
|
||||||
|
margin: 0 16px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.question-nav {
|
.question-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: nowrap;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
justify-content: center;
|
width: max-content;
|
||||||
|
min-width: max-content;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-dot {
|
.nav-dot {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: 32px;
|
min-width: 32px;
|
||||||
|
|||||||
@ -33,8 +33,8 @@ export default defineConfig(async () => {
|
|||||||
open: true,
|
open: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
// target: 'http://43.136.52.196:9053',
|
target: 'http://43.136.52.196:9053',
|
||||||
target: 'https://admin.xuexiaole.com',
|
// target: 'https://admin.xuexiaole.com',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user