提交 f984276e authored 作者: matian's avatar matian

updates:新增教学管理和基础管理模块

上级 7595404b
{
"globals": {
"$": true,
"$$": true,
"$computed": true,
"$customRef": true,
"$ref": true,
"$shallowRef": true,
"$toRef": true,
"EffectScope": true,
"asyncComputed": true,
"autoResetRef": true,
"computed": true,
"computedAsync": true,
"computedEager": true,
"computedInject": true,
"computedWithControl": true,
"controlledComputed": true,
"controlledRef": true,
"createApp": true,
"createEventHook": true,
"createGlobalState": true,
"createInjectionState": true,
"createReactiveFn": true,
"createSharedComposable": true,
"createUnrefFn": true,
"customRef": true,
"debouncedRef": true,
"debouncedWatch": true,
"defineAsyncComponent": true,
"defineComponent": true,
"eagerComputed": true,
"effectScope": true,
"extendRef": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"ignorableWatch": true,
"inject": true,
"isDefined": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"logicAnd": true,
"logicNot": true,
"logicOr": true,
"makeDestructurable": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onClickOutside": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onKeyStroke": true,
"onLongPress": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onStartTyping": true,
"onUnmounted": true,
"onUpdated": true,
"pausableWatch": true,
"provide": true,
"reactify": true,
"reactifyObject": true,
"reactive": true,
"reactiveComputed": true,
"reactiveOmit": true,
"reactivePick": true,
"readonly": true,
"ref": true,
"refAutoReset": true,
"refDebounced": true,
"refDefault": true,
"refThrottled": true,
"refWithControl": true,
"resolveComponent": true,
"resolveRef": true,
"resolveUnref": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"syncRef": true,
"syncRefs": true,
"templateRef": true,
"throttledRef": true,
"throttledWatch": true,
"toRaw": true,
"toReactive": true,
"toRef": true,
"toRefs": true,
"triggerRef": true,
"tryOnBeforeMount": true,
"tryOnBeforeUnmount": true,
"tryOnMounted": true,
"tryOnScopeDispose": true,
"tryOnUnmounted": true,
"unref": true,
"unrefElement": true,
"until": true,
"useActiveElement": true,
"useAsyncQueue": true,
"useAsyncState": true,
"useAttrs": true,
"useBase64": true,
"useBattery": true,
"useBluetooth": true,
"useBreakpoints": true,
"useBroadcastChannel": true,
"useBrowserLocation": true,
"useCached": true,
"useClamp": true,
"useClipboard": true,
"useColorMode": true,
"useConfirmDialog": true,
"useCounter": true,
"useCssModule": true,
"useCssVar": true,
"useCssVars": true,
"useCurrentElement": true,
"useCycleList": true,
"useDark": true,
"useDateFormat": true,
"useDebounce": true,
"useDebounceFn": true,
"useDebouncedRefHistory": true,
"useDeviceMotion": true,
"useDeviceOrientation": true,
"useDevicePixelRatio": true,
"useDevicesList": true,
"useDisplayMedia": true,
"useDocumentVisibility": true,
"useDraggable": true,
"useDropZone": true,
"useElementBounding": true,
"useElementByPoint": true,
"useElementHover": true,
"useElementSize": true,
"useElementVisibility": true,
"useEventBus": true,
"useEventListener": true,
"useEventSource": true,
"useEyeDropper": true,
"useFavicon": true,
"useFetch": true,
"useFileDialog": true,
"useFileSystemAccess": true,
"useFocus": true,
"useFocusWithin": true,
"useFps": true,
"useFullscreen": true,
"useGamepad": true,
"useGeolocation": true,
"useIdle": true,
"useImage": true,
"useInfiniteScroll": true,
"useIntersectionObserver": true,
"useInterval": true,
"useIntervalFn": true,
"useKeyModifier": true,
"useLastChanged": true,
"useLocalStorage": true,
"useMagicKeys": true,
"useManualRefHistory": true,
"useMediaControls": true,
"useMediaQuery": true,
"useMemoize": true,
"useMemory": true,
"useMounted": true,
"useMouse": true,
"useMouseInElement": true,
"useMousePressed": true,
"useMutationObserver": true,
"useNavigatorLanguage": true,
"useNetwork": true,
"useNow": true,
"useObjectUrl": true,
"useOffsetPagination": true,
"useOnline": true,
"usePageLeave": true,
"useParallax": true,
"usePermission": true,
"usePointer": true,
"usePointerSwipe": true,
"usePreferredColorScheme": true,
"usePreferredDark": true,
"usePreferredLanguages": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
"useRoute": true,
"useRouter": true,
"useScreenOrientation": true,
"useScreenSafeArea": true,
"useScriptTag": true,
"useScroll": true,
"useScrollLock": true,
"useSessionStorage": true,
"useShare": true,
"useSlots": true,
"useSpeechRecognition": true,
"useSpeechSynthesis": true,
"useStepper": true,
"useStorage": true,
"useStorageAsync": true,
"useStyleTag": true,
"useSwipe": true,
"useTemplateRefsList": true,
"useTextSelection": true,
"useTextareaAutosize": true,
"useThrottle": true,
"useThrottleFn": true,
"useThrottledRefHistory": true,
"useTimeAgo": true,
"useTimeout": true,
"useTimeoutFn": true,
"useTimeoutPoll": true,
"useTimestamp": true,
"useTitle": true,
"useToggle": true,
"useTransition": true,
"useUrlSearchParams": true,
"useUserMedia": true,
"useVModel": true,
"useVModels": true,
"useVibrate": true,
"useVirtualList": true,
"useWakeLock": true,
"useWebNotification": true,
"useWebSocket": true,
"useWebWorker": true,
"useWebWorkerFn": true,
"useWindowFocus": true,
"useWindowScroll": true,
"useWindowSize": true,
"watch": true,
"watchArray": true,
"watchAtMost": true,
"watchDebounced": true,
"watchEffect": true,
"watchIgnorable": true,
"watchOnce": true,
"watchPausable": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"watchThrottled": true,
"watchTriggerable": true,
"watchWithFilter": true,
"whenever": true
}
}
\ No newline at end of file
差异被折叠。
...@@ -84,7 +84,7 @@ export const menus: IMenuItem[] = [ ...@@ -84,7 +84,7 @@ export const menus: IMenuItem[] = [
}, },
{ {
tag: 'v1-backend', tag: 'v1-backend',
name: '教学管理', name: '基础信息',
path: '/admin', path: '/admin',
children: [ children: [
{ {
...@@ -93,6 +93,12 @@ export const menus: IMenuItem[] = [ ...@@ -93,6 +93,12 @@ export const menus: IMenuItem[] = [
name: '讲师管理', name: '讲师管理',
path: '/admin/teacher' path: '/admin/teacher'
}, },
{
tag: 'v1-backend-lecturer-list',
icon: School,
name: '教工用户管理',
path: '/admin/staff'
},
{ {
tag: 'v1-backend-lecturer-list', tag: 'v1-backend-lecturer-list',
icon: User, icon: User,
...@@ -117,18 +123,7 @@ export const menus: IMenuItem[] = [ ...@@ -117,18 +123,7 @@ export const menus: IMenuItem[] = [
name: '学期管理', name: '学期管理',
path: '/admin/semester' path: '/admin/semester'
}, },
{
tag: 'v1-backend-lecturer-list',
icon: QuestionFilled,
name: '问答管理',
path: '/admin/qa'
},
{
tag: 'v1-backend-lecturer-list',
icon: EditPen,
name: '批改试卷',
path: '/admin/exam'
},
{ {
tag: 'v1-backend-category-list', tag: 'v1-backend-category-list',
icon: Filter, icon: Filter,
...@@ -139,12 +134,6 @@ export const menus: IMenuItem[] = [ ...@@ -139,12 +134,6 @@ export const menus: IMenuItem[] = [
icon: Coordinate, icon: Coordinate,
name: '资源审核管理', name: '资源审核管理',
path: '/admin/audit' path: '/admin/audit'
},
{
tag: 'v1-backend-lecturer-list',
icon: DataAnalysis,
name: '数据画像与分析',
path: '/admin/teacher'
} }
] ]
}, },
...@@ -166,5 +155,30 @@ export const menus: IMenuItem[] = [ ...@@ -166,5 +155,30 @@ export const menus: IMenuItem[] = [
path: '/system/cover' path: '/system/cover'
} }
] ]
},
{
tag: 'v1-backend',
name: '教学管理',
path: '/teach',
children: [
{
tag: 'v1-backend-lecturer-list',
icon: QuestionFilled,
name: '问答管理',
path: '/teach/qa'
},
{
tag: 'v1-backend-lecturer-list',
icon: EditPen,
name: '批改试卷',
path: '/teach/exam'
},
{
tag: 'v1-backend-lecturer-list',
icon: DataAnalysis,
name: '数据画像与分析',
path: '/teach/exam'
}
]
} }
] ]
...@@ -98,7 +98,6 @@ const listOptions = computed(() => { ...@@ -98,7 +98,6 @@ const listOptions = computed(() => {
httpRequest: getCategoryList, httpRequest: getCategoryList,
params: { type: 'tree', category_name: '' }, params: { type: 'tree', category_name: '' },
callback(data: ICategory[], params: any) { callback(data: ICategory[], params: any) {
console.log(data, '1111', params)
const list = rebuildData(params.category_name, data) const list = rebuildData(params.category_name, data)
tableData = list tableData = list
tableDataList = flatten(list) tableDataList = flatten(list)
......
<script lang="ts" setup>
import type { FormRules } from 'element-plus'
const emit = defineEmits<Emits>()
const schoolList = [
{
id: '111',
name: '清华'
},
{
id: '222',
name: '北大'
}
]
const form = reactive({
code: '',
name: '',
school: '',
headmaster: '',
major: '',
enter_month: ''
})
const rules = reactive<FormRules>({
code: [{ required: true, message: '请输入专业代码', trigger: 'change' }],
name: [{ required: true, message: '请输入专业名称', trigger: 'blur' }],
school: [{ required: true, message: '请选择所属部门/学校', trigger: 'change' }],
headmaster: [{ required: true, message: '请选择班主任', trigger: 'change' }],
major: [{ required: true, message: '请选择所属专业', trigger: 'blur' }],
enter_month: [{ required: true, message: '请选择入学年份', trigger: 'change' }]
})
const props = defineProps({
isShowClassDialog: {
type: Boolean
},
title: {
type: String
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isShowClassDialog', isShowClassDialog: boolean): void
(e: 'create'): void
}
// 取消
const handleCancel = () => {
emit('update:isShowClassDialog', false)
}
const handleConfirm = () => {
emit('update:isShowClassDialog', false)
emit('create')
}
</script>
<template>
<el-dialog :model-value="isShowClassDialog" draggable :before-close="handleCancel" :title="props.title" width="30%">
<el-form :model="form" label-position="right" label-width="auto" :rules="rules" ref="formRef">
<el-form-item label="班级代码:" prop="code">
<el-input v-model="form.code" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="专业名称:" prop="name">
<el-input v-model="form.name" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="所属部门/学校:" prop="school">
<el-select v-model="form.school" placeholder="请选择所属部门/学校" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="班主任:" prop="headmaster">
<el-select v-model="form.headmaster" placeholder="请选择所属部门/学校" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="所属专业:" prop="major">
<el-select v-model="form.major" placeholder="请选择所属部门/学校" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="入学年份:" prop="enter_month">
<el-date-picker
v-model="form.enter_month"
type="year"
placeholder="请选择入学年份"
:disabled="props.title === '查看详情'"
/>
</el-form-item>
</el-form>
<template #footer>
<span>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
const emit = defineEmits<Emits>()
defineProps({
isAddStuDialog: {
type: Boolean
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isAddStuDialog', isAddStuDialog: boolean): void
}
const listOptions = $computed(() => {
return {
// remote: { httpRequest: getProList, params: { name: '' } },
filters: [{ type: 'input', prop: 'name', label: '学生姓名:', placeholder: '学生姓名' }],
columns: [
{ type: 'selection' },
{ label: '序号', type: 'index', align: 'center' },
{ label: '学号', prop: 'sno', align: 'center' },
{ label: '姓名', prop: 'name', align: 'center' },
{ label: '性别', prop: 'sex', align: 'center' },
{ label: '出生年月', prop: 'birth', align: 'center' },
{ label: '省', prop: 'province', align: 'center' },
{ label: '市', prop: 'city', align: 'center' },
{ label: '县', prop: 'county', align: 'center' },
{ label: '联系电话', prop: 'mobile', align: 'center' },
{ label: '部门/学校', prop: 'school', align: 'center' },
{ label: '专业', prop: 'major', align: 'center' },
{ label: '班级', prop: 'class', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', minWidth: '300', fixed: 'right' }
],
data: [
{
name: 111
},
{
name: 111
},
{
name: 111
},
{
name: 111
}
]
}
})
const handleAddStu = () => {
console.log(111)
}
const handleDel = (row: any) => {
console.log(row)
}
const handleDetail = (row: any) => {
console.log(row)
}
const handleCancel = () => {
emit('update:isAddStuDialog', false)
}
</script>
<template>
<el-dialog
:model-value="isAddStuDialog"
draggable
title="添加班级学生"
width="60%"
center
:before-close="handleCancel"
>
<div style="overflow-y: auto; height: 70vh">
<el-descriptions>
<el-descriptions-item label="班级代码:">kooriookami</el-descriptions-item>
<el-descriptions-item label="班级名称">18100000000</el-descriptions-item>
<el-descriptions-item label="所属部门/学校:">Suzhou</el-descriptions-item>
<el-descriptions-item label="班 主 任:">
<el-tag size="small">School</el-tag>
</el-descriptions-item>
<el-descriptions-item label="所属专业">工商管理</el-descriptions-item>
<el-descriptions-item label="入学年份">2021</el-descriptions-item>
</el-descriptions>
<AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round @click="handleAddStu">关联选择学生</el-button>
<template #table-operate="{ row }">
<el-space>
<el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link plain @click="handleDel(row)">移除</el-link>
</el-space>
</template>
</AppList>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
const emit = defineEmits<Emits>()
const props = defineProps({
isShowTermDialog: {
type: Boolean
},
id: {
type: String
},
title: {
type: String
}
})
interface Emits {
(e: 'update:isShowTermDialog', isShowTermDialog: boolean): void
(e: 'create'): void
}
const form = reactive({
name: '',
start_time: '',
end_time: '',
week: ''
})
const handleCancel = () => {
emit('update:isShowTermDialog', false)
}
const handleConfirm = () => {
emit('update:isShowTermDialog', false)
emit('create')
}
</script>
<template>
<el-dialog
:model-value="isShowTermDialog"
draggable
:title="title"
width="30%"
:before-close="handleCancel"
top="30vh"
>
<el-form :model="form" label-position="right" label-width="auto">
<el-form-item label="学期名称:" prop="name">
<el-input v-model="form.name" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="学期开始日期:" prop="start_time">
<el-input v-model="form.start_time" disabled></el-input>
</el-form-item>
<el-form-item label="学期结束日期:" prop="end_time">
<el-input v-model="form.end_time" disabled></el-input>
</el-form-item>
<el-form-item label="教学周:" prop="week">
<el-input v-model="form.week" disabled></el-input>
</el-form-item>
</el-form>
<template #footer>
<span>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import AddStudentDialog from './AddStudentDialog.vue'
const emit = defineEmits<Emits>()
const isAddStuDialog = ref(false)
defineProps({
isShowClassStuDialog: {
type: Boolean
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isShowClassStuDialog', isShowClassStuDialog: boolean): void
}
const listOptions = $computed(() => {
return {
// remote: { httpRequest: getProList, params: { name: '' } },
filters: [{ type: 'input', prop: 'name', label: '学生姓名:', placeholder: '学生姓名' }],
columns: [
{ label: '序号', type: 'index', align: 'center' },
{ label: '班级代码', prop: 'code', align: 'center' },
{ label: '班级名称', prop: 'name', align: 'center' },
{ label: '所属部门/学校', prop: 'school', align: 'center' },
{ label: '人数', prop: 'number', align: 'center' },
{ label: '班主任', prop: 'headmaster', align: 'center' },
{ label: '专业', prop: 'major', align: 'center' },
{ label: '入学年份', prop: 'enter_month', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', minWidth: '300', fixed: 'right' }
],
data: [
{
name: 111
},
{
name: 111
},
{
name: 111
},
{
name: 111
}
]
}
})
const handleAddStu = () => {
isAddStuDialog.value = true
console.log(111)
}
const handleDel = (row: any) => {
console.log(row)
}
const handleDetail = (row: any) => {
console.log(row)
}
const handleCancel = () => {
emit('update:isShowClassStuDialog', false)
}
</script>
<template>
<el-dialog
:model-value="isShowClassStuDialog"
draggable
title="班级学生"
width="70%"
center
:before-close="handleCancel"
>
<div style="overflow-y: auto; height: 70vh">
<el-descriptions>
<el-descriptions-item label="班级代码:">kooriookami</el-descriptions-item>
<el-descriptions-item label="班级名称">18100000000</el-descriptions-item>
<el-descriptions-item label="所属部门/学校:">Suzhou</el-descriptions-item>
<el-descriptions-item label="班 主 任:">
<el-tag size="small">School</el-tag>
</el-descriptions-item>
<el-descriptions-item label="所属专业">工商管理</el-descriptions-item>
<el-descriptions-item label="入学年份">2021</el-descriptions-item>
</el-descriptions>
<AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round @click="handleAddStu">添加学生</el-button>
<template #table-operate="{ row }">
<el-space>
<el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link plain @click="handleDel(row)">移除</el-link>
</el-space>
</template>
</AppList>
</div>
<AddStudentDialog v-model:isAddStuDialog="isAddStuDialog" v-if="isAddStuDialog === true" />
</el-dialog>
</template>
<script lang="ts" setup>
import AddTermDialog from './AddTermDialog.vue'
const emit = defineEmits<Emits>()
const appList = ref()
const title = ref('')
const id = ref('')
const isShowTermDialog = ref(false)
defineProps({
isRelatingDialog: {
type: Boolean
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isRelatingDialog', isRelatingDialog: boolean): void
}
const listOptions = $computed(() => {
return {
// remote: { httpRequest: getProList, params: { name: '' } },
filters: [{ type: 'input', prop: 'name', label: '学生姓名:', placeholder: '学生姓名' }],
columns: [
{ label: '序号', type: 'index', align: 'center' },
{ label: '学期名称', prop: 'name', align: 'center' },
{ label: '学期开始时间', prop: 'start_time', align: 'center' },
{ label: ' 学期结束时间', prop: 'end_time', align: 'center' },
{ label: '教学周', prop: 'week', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', minWidth: '300', fixed: 'right' }
],
data: [
{
name: 111
},
{
name: 111
},
{
name: 111
},
{
name: 111
}
]
}
})
const handleAddTerm = () => {
isShowTermDialog.value = true
title.value = '添加班级关联学期'
console.log(111)
}
const handleDel = (row: any) => {
console.log(row)
}
const handleDetail = (row: any) => {
isShowTermDialog.value = true
id.value = row.id
title.value = '查看详情'
console.log(row)
}
const handleCancel = () => {
emit('update:isRelatingDialog', false)
}
const handleFresh = () => {
appList.value.refetch()
}
</script>
<template>
<el-dialog :model-value="isRelatingDialog" draggable title="班级关联学期" width="70%" :before-close="handleCancel">
<div style="overflow-y: auto; height: 70vh">
<el-descriptions>
<el-descriptions-item label="班级代码:">kooriookami</el-descriptions-item>
<el-descriptions-item label="班级名称">18100000000</el-descriptions-item>
<el-descriptions-item label="所属部门/学校:">Suzhou</el-descriptions-item>
<el-descriptions-item label="班 主 任:">
<el-tag size="small">School</el-tag>
</el-descriptions-item>
<el-descriptions-item label="所属专业">工商管理</el-descriptions-item>
<el-descriptions-item label="入学年份">2021</el-descriptions-item>
</el-descriptions>
<AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round @click="handleAddTerm">添加学期</el-button>
<template #table-operate="{ row }">
<el-space>
<el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link plain @click="handleDel(row)">移除</el-link>
</el-space>
</template>
</AppList>
</div>
<AddTermDialog
v-model:isShowTermDialog="isShowTermDialog"
v-if="isShowTermDialog === true"
:id="id"
:title="title"
@create="handleFresh"
/>
</el-dialog>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { getProList } from '../api' // import { getProList } from '../api'
import AddClass from '../components/AddClass.vue'
import ClassStudents from '../components/ClassStudents.vue'
import RelatedTerm from '../components/RelatedTerm.vue'
// import { useMapStore } from '@/stores/map' // import { useMapStore } from '@/stores/map'
// const store = useMapStore() // const store = useMapStore()
const appList = ref() const appList = ref()
const id = ref('')
const title = ref('')
const isShowClassDialog = ref(false)
const isShowClassStuDialog = ref(false)
const isRelatingDialog = ref(false)
const listOptions = $computed(() => { const listOptions = $computed(() => {
return { return {
remote: { httpRequest: getProList, params: { name: '' } }, // remote: { httpRequest: getProList, params: { name: '' } },
filters: [ filters: [
{ type: 'input', prop: 'name', label: '班级名称', placeholder: '班级名称' }, { type: 'input', prop: 'name', label: '班级名称:', placeholder: '班级名称' },
{ type: 'input', prop: 'name', label: '所属部门/学校', placeholder: '所属部门/学校' } { type: 'input', prop: 'school', label: '所属部门/学校:', placeholder: '所属部门/学校' }
], ],
columns: [ columns: [
{ label: '序号', type: 'index', align: 'center' }, { label: '序号', type: 'index', align: 'center' },
{ label: '班级代码', prop: 'name', align: 'center' }, { label: '班级代码', prop: 'code', align: 'center' },
{ label: '班级名称', prop: 'name', align: 'center' }, { label: '班级名称', prop: 'name', align: 'center' },
{ label: '所属部门/学校', prop: 'name', align: 'center' }, { label: '所属部门/学校', prop: 'school', align: 'center' },
{ label: '人数', prop: 'name', align: 'center' }, { label: '人数', prop: 'number', align: 'center' },
{ label: '班主任', prop: 'name', align: 'center' }, { label: '班主任', prop: 'headmaster', align: 'center' },
{ label: '专业', prop: 'name', align: 'center' }, { label: '专业', prop: 'major', align: 'center' },
{ label: '入学年份', prop: 'name', align: 'center' }, { label: '入学年份', prop: 'enter_month', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' }, { label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center' } { label: '操作', slots: 'table-operate', align: 'center', minWidth: '300', fixed: 'right' }
],
data: [
{
name: 111
}
] ]
} }
}) })
const handleAddClass = () => {
isShowClassDialog.value = true
title.value = '新增班级'
}
const handleEdit = (row: any) => {
isShowClassDialog.value = true
title.value = '编辑班级'
id.value = row.id
}
const handleDetail = (row: any) => {
isShowClassDialog.value = true
title.value = '查看详情'
id.value = row.id
}
const handleClassStu = (row: any) => {
isShowClassStuDialog.value = true
id.value = row.id
}
// 关联学期
const handleRelating = (row: any) => {
isRelatingDialog.value = true
id.value = row.id
}
</script> </script>
<template> <template>
<AppCard title="班级管理"> <AppCard title="班级管理">
<AppList v-bind="listOptions" ref="appList" border stripe> <AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round>新增班级</el-button> <el-button type="primary" round @click="handleAddClass">新增班级</el-button>
<template #table-operate> <template #table-operate="{ row }">
<el-space> <el-space>
<el-link type="primary" plain>查看</el-link> <el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link type="primary" plain>编辑</el-link> <el-link type="primary" plain @click="handleEdit(row)">编辑</el-link>
<el-link type="primary" plain>班级学生</el-link> <el-link type="primary" plain @click="handleClassStu(row)">班级学生</el-link>
<el-link type="primary" plain @click="handleRelating(row)">关联学期</el-link>
</el-space> </el-space>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<AddClass v-model:isShowClassDialog="isShowClassDialog" v-if="isShowClassDialog === true" :title="title" :id="id" />
<ClassStudents v-model:isShowClassStuDialog="isShowClassStuDialog" v-if="isShowClassStuDialog === true" />
<RelatedTerm v-model:isRelatingDialog="isRelatingDialog" v-if="isRelatingDialog === true" />
</template> </template>
<script setup lang="ts">
import { getProList } from '../api'
// import { useMapStore } from '@/stores/map'
// const store = useMapStore()
const appList = ref()
const listOptions = $computed(() => {
return {
remote: { httpRequest: getProList, params: { name: '' } },
filters: [
{ type: 'select', prop: 'name', label: '所属课程', placeholder: '所属课程' },
{ type: 'select', prop: 'name', label: '所属班级', placeholder: '所属班级' },
{ type: 'select', prop: 'name', label: '所属学生', placeholder: '所属学生' },
{ type: 'input', prop: 'name', label: '问题内容', placeholder: '问题内容' }
],
columns: [
{ label: '序号', type: 'index', align: 'center' },
{ label: '所属课程', prop: 'name', align: 'center' },
{ label: '提问人', prop: 'name', align: 'center' },
{ label: '所属班级', prop: 'name', align: 'center' },
{ label: '问题类型', prop: 'name', align: 'center' },
{ label: '问题标题', prop: 'name', align: 'center' },
{ label: '是否回复', prop: 'name', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center' }
]
}
})
</script>
<template>
<AppCard title="问答管理">
<AppList v-bind="listOptions" ref="appList" border stripe>
<el-button type="primary" round>新增问答</el-button>
<template #table-operate>
<el-space>
<el-link type="primary" plain>添加回复</el-link>
</el-space>
</template>
</AppList>
</AppCard>
</template>
<script lang="ts" setup>
import type { FormRules } from 'element-plus'
const emit = defineEmits<Emits>()
const schoolList = [
{
id: '111',
name: '清华'
},
{
id: '222',
name: '北大'
}
]
const form = reactive({
code: '',
name: '',
category: '',
education: 1,
schoolLength: 1,
degreeCategory: '',
degree: 0
})
const rules = reactive<FormRules>({
code: [{ required: true, message: '请输入专业代码', trigger: 'change' }],
name: [{ required: true, message: '请输入专业名称', trigger: 'blur' }],
category: [{ required: true, message: '请选择专业类别', trigger: 'change' }],
education: [{ required: true, message: '请选择学历', trigger: 'blur' }],
schoolLength: [{ required: true, message: '请选择学制', trigger: 'change' }],
degreeCategory: [{ required: true, message: '请选择学位门类', trigger: 'blur' }],
degree: [{ required: true, message: '请选择学位', trigger: 'blur' }]
})
const props = defineProps({
isShowProDialog: {
type: Boolean
},
title: {
type: String
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isShowProDialog', isShowProDialog: boolean): void
(e: 'create'): void
}
// 取消
const handleCancel = () => {
emit('update:isShowProDialog', false)
}
const handleConfirm = () => {
emit('update:isShowProDialog', false)
emit('create')
}
</script>
<template>
<el-dialog :model-value="isShowProDialog" draggable :before-close="handleCancel" :title="props.title" width="30%">
<el-form :model="form" label-position="right" label-width="auto" :rules="rules" ref="formRef">
<el-form-item label="专业代码:" prop="code">
<el-input v-model="form.code" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="专业名称:" prop="name">
<el-input v-model="form.name" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="专业类别:" prop="category">
<el-select v-model="form.category" placeholder="请选择所属部门/学校" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="学历:" prop="education">
<el-radio-group v-model="form.education" :disabled="props.title === '查看详情'">
<el-radio :label="0">专科</el-radio>
<el-radio :label="1">本科</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="学制:" prop="schoolLength">
<el-radio-group v-model="form.schoolLength" :disabled="props.title === '查看详情'">
<el-radio :label="0">3年</el-radio>
<el-radio :label="1">4年</el-radio>
<el-radio :label="2">5年</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="学位门类:" prop="degreeCategory">
<el-select v-model="form.degreeCategory" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="学位:" prop="degree">
<el-radio-group v-model="form.degree" :disabled="props.title === '查看详情'">
<el-radio :label="0">学士</el-radio>
<el-radio :label="1">硕士</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { getProList } from '../api' // import { getProList } from '../api'
import AddPro from '../components/AddPro.vue'
// import { useMapStore } from '@/stores/map' // import { useMapStore } from '@/stores/map'
// const store = useMapStore() // const store = useMapStore()
const appList = ref() const appList = ref()
const title = ref('')
const id = ref('')
const isShowProDialog = ref(false)
const listOptions = $computed(() => { const listOptions = $computed(() => {
return { return {
remote: { httpRequest: getProList, params: { name: '' } }, // remote: { httpRequest: getProList, params: { name: '' } },
filters: [{ type: 'input', prop: 'name', label: '专业名称', placeholder: '专业名称' }], filters: [{ type: 'input', prop: 'name', label: '专业名称', placeholder: '专业名称' }],
columns: [ columns: [
{ label: '序号', type: 'index', align: 'center' }, { label: '序号', type: 'index', align: 'center' },
{ label: '专业代码', prop: 'name', align: 'center' }, { label: '专业代码', prop: 'code', align: 'center' },
{ label: '专业名称', prop: 'name', align: 'center' }, { label: '专业名称', prop: 'name', align: 'center' },
{ label: '专业类别', prop: 'name', align: 'center' }, { label: '专业类别', prop: 'category', align: 'center' },
{ label: '学历', prop: 'name', align: 'center' }, { label: '学历', prop: 'education', align: 'center' },
{ label: '学制', prop: 'name', align: 'center' }, { label: '学制', prop: 'schoolLength', align: 'center' },
{ label: '学位门类', prop: 'name', align: 'center' }, { label: '学位门类', prop: 'degreeCategory', align: 'center' },
{ label: '学位', prop: 'name', align: 'center' }, { label: '学位', prop: 'degree', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' }, { label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center' } { label: '操作', slots: 'table-operate', align: 'center' }
],
data: [
{
name: 222
}
] ]
} }
}) })
const handleAddPro = () => {
isShowProDialog.value = true
title.value = '新增专业'
}
const handleDetail = (row: any) => {
isShowProDialog.value = true
title.value = '查看详情'
id.value = row.id
}
const handleEdit = (row: any) => {
isShowProDialog.value = true
title.value = '编辑专业'
id.value = row.id
}
const handleFresh = () => {
appList.value.refetch()
}
</script> </script>
<template> <template>
<AppCard title="专业管理"> <AppCard title="专业管理">
<AppList v-bind="listOptions" ref="appList" border stripe> <AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round>新增专业</el-button> <el-button type="primary" round @click="handleAddPro">新增专业</el-button>
<template #table-operate> <template #table-operate="{ row }">
<el-space> <el-space>
<el-link type="primary" plain>查看</el-link> <el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link type="primary" plain>编辑</el-link> <el-link type="primary" plain @click="handleEdit(row)">编辑</el-link>
</el-space> </el-space>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<AddPro
v-if="isShowProDialog === true"
v-model:isShowProDialog="isShowProDialog"
:title="title"
@create="handleFresh"
/>
</template> </template>
<script lang="ts" setup>
const emit = defineEmits<Emits>()
defineProps({
isShowCourse: {
type: Boolean
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isShowCourse', isShowCourse: boolean): void
}
const listOptions = $computed(() => {
return {
// remote: { httpRequest: getProList, params: { name: '' } },
filters: [
{ type: 'select', prop: 'name', label: '课程分类:', placeholder: '课程分类' },
{ type: 'input', prop: 'name', label: '课程名称:', placeholder: '课程名称' }
],
columns: [
{ type: 'selection' },
{ label: '序号', type: 'index', align: 'center' },
{ label: '课程名称', prop: 'name', align: 'center' },
{ label: '课程类型', prop: 'school', align: 'center' },
{ label: '选课类型', prop: 'number', align: 'center' },
{ label: '课程分类', prop: 'headmaster', align: 'center' },
{ label: '课程学分', prop: 'major', align: 'center' },
{ label: '讲师', prop: 'enter_month', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', minWidth: '200', fixed: 'right' }
],
data: [
{
name: 111
},
{
name: 111
},
{
name: 111
},
{
name: 111
}
]
}
})
const handleAddStu = () => {
console.log(111)
}
const handleDetail = (row: any) => {
console.log(row)
}
const handleCancel = () => {
emit('update:isShowCourse', false)
}
</script>
<template>
<el-dialog :model-value="isShowCourse" draggable title="关联选择课程" width="50%" :before-close="handleCancel">
<div style="overflow-y: auto; height: 70vh">
<el-descriptions>
<el-descriptions-item label="学期名称:">kooriookami</el-descriptions-item>
<el-descriptions-item label="所属部门/学校:">18100000000</el-descriptions-item>
<el-descriptions-item label="开始日期:">Suzhou</el-descriptions-item>
<el-descriptions-item label="结束日期:">
<el-tag size="small">School</el-tag>
</el-descriptions-item>
<el-descriptions-item label="教学周">工商管理</el-descriptions-item>
</el-descriptions>
<AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round @click="handleAddStu">关联选择课程</el-button>
<template #table-operate="{ row }">
<el-space>
<el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
</el-space>
</template>
</AppList>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import type { FormRules } from 'element-plus'
const emit = defineEmits<Emits>()
const schoolList = [
{
id: '111',
name: '清华'
},
{
id: '222',
name: '北大'
}
]
const form = reactive({
name: '',
school: '',
start_time: '',
end_time: '',
week: ''
})
const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入学期名称', trigger: 'blur' }],
school: [{ required: true, message: '请选择所属部门/学校', trigger: 'change' }]
})
const props = defineProps({
isShowAddSemDialog: {
type: Boolean
},
title: {
type: String
},
id: {
type: String
},
isEdit: {
type: Boolean
}
})
interface Emits {
(e: 'update:isShowAddSemDialog', isShowAddSemDialog: boolean): void
(e: 'create'): void
}
// 取消
const handleCancel = () => {
emit('update:isShowAddSemDialog', false)
}
const handleConfirm = () => {
emit('update:isShowAddSemDialog', false)
emit('create')
}
</script>
<template>
<el-dialog :model-value="isShowAddSemDialog" draggable :before-close="handleCancel" :title="props.title" width="30%">
<el-form :model="form" label-position="right" label-width="auto" :rules="rules" ref="formRef">
<el-form :model="form" label-position="right" label-width="auto">
<el-form-item label="学期名称:" prop="name">
<el-input v-model="form.name" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="所属部门/学校:" prop="school">
<el-select v-model="form.school" placeholder="请选择所属部门/学校" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="学期开始日期:" prop="start_time">
<el-date-picker
v-model="form.start_time"
type="date"
placeholder="学期开始日期"
:disabled="props.title === '查看详情'"
/>
</el-form-item>
<el-form-item label="学期结束日期:" prop="end_time">
<el-date-picker
v-model="form.end_time"
type="date"
placeholder="学期结束日期"
:disabled="props.title === '查看详情'"
/>
</el-form-item>
<el-form-item label="教学周:" prop="week">
<el-input v-model="form.week" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
</el-form>
</el-form>
<template #footer>
<span>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import AddSemCourse from './AddSemCourse.vue'
const emit = defineEmits<Emits>()
defineProps({
isShowSemCourseDialog: {
type: Boolean
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isShowSemCourseDialog', isShowSemCourseDialog: boolean): void
}
const isShowCourse = ref(false)
const listOptions = $computed(() => {
return {
// remote: { httpRequest: getProList, params: { name: '' } },
filters: [{ type: 'input', prop: 'name', label: '课程名称:', placeholder: '课程名称' }],
columns: [
{ label: '序号', type: 'index', align: 'center' },
{ label: '课程名称', prop: 'name', align: 'center' },
{ label: '课程类型', prop: 'school', align: 'center' },
{ label: '选课类型', prop: 'number', align: 'center' },
{ label: '课程分类', prop: 'headmaster', align: 'center' },
{ label: '课程学分', prop: 'major', align: 'center' },
{ label: '讲师', prop: 'enter_month', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', minWidth: '300', fixed: 'right' }
],
data: [
{
name: 111
},
{
name: 111
},
{
name: 111
},
{
name: 111
}
]
}
})
const handleAddCourse = () => {
isShowCourse.value = true
console.log(111)
}
const handleDel = (row: any) => {
console.log(row)
}
const handleDetail = (row: any) => {
console.log(row)
}
const handleCancel = () => {
emit('update:isShowSemCourseDialog', false)
}
</script>
<template>
<el-dialog
:model-value="isShowSemCourseDialog"
draggable
title="学期关联课程"
width="70%"
:before-close="handleCancel"
>
<div style="overflow-y: auto; height: 70vh">
<el-descriptions>
<el-descriptions-item label="学期名称:">kooriookami</el-descriptions-item>
<el-descriptions-item label="所属部门/学校:">18100000000</el-descriptions-item>
<el-descriptions-item label="开始日期:">Suzhou</el-descriptions-item>
<el-descriptions-item label="结束日期:">
<el-tag size="small">School</el-tag>
</el-descriptions-item>
<el-descriptions-item label="教学周">工商管理</el-descriptions-item>
</el-descriptions>
<AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round @click="handleAddCourse">添加课程</el-button>
<template #table-operate="{ row }">
<el-space>
<el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link plain @click="handleDel(row)">移除</el-link>
</el-space>
</template>
</AppList>
</div>
<AddSemCourse v-model:isShowCourse="isShowCourse" v-if="isShowCourse === true" />
</el-dialog>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { getProList } from '../api' // import { getProList } from '../api'
import AddSemester from '../components/AddSemester.vue'
import SemesterCourse from '../components/SemesterCourse.vue'
// import { useMapStore } from '@/stores/map' // import { useMapStore } from '@/stores/map'
// const store = useMapStore() // const store = useMapStore()
const appList = ref() const appList = ref()
const title = ref('')
const id = ref('')
const isEdit = ref(false)
const isShowAddSemDialog = ref(false)
const isShowSemCourseDialog = ref(false)
const listOptions = $computed(() => { const listOptions = $computed(() => {
return { return {
remote: { httpRequest: getProList, params: { name: '' } }, // remote: { httpRequest: getProList, params: { name: '' } },
filters: [ filters: [
{ type: 'input', prop: 'name', label: '学期名称', placeholder: '学期名称' }, { type: 'input', prop: 'name', label: '学期名称', placeholder: '学期名称' },
{ type: 'input', prop: 'name', label: '所属部门/学校', placeholder: '所属部门/学校' } { type: 'input', prop: 'name', label: '所属部门/学校', placeholder: '所属部门/学校' }
...@@ -20,22 +26,54 @@ const listOptions = $computed(() => { ...@@ -20,22 +26,54 @@ const listOptions = $computed(() => {
{ label: '教学周', prop: 'name', align: 'center' }, { label: '教学周', prop: 'name', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' }, { label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center' } { label: '操作', slots: 'table-operate', align: 'center' }
],
data: [
{
name: '1111'
}
] ]
} }
}) })
const handleAddSemester = () => {
isShowAddSemDialog.value = true
title.value = '新增学期'
}
const handleDetail = (row: any) => {
isShowAddSemDialog.value = true
title.value = '查看详情'
id.value = row.id
}
const handleEdit = (row: any) => {
isShowAddSemDialog.value = true
title.value = '编辑学期'
id.value = row.id
isEdit.value = true
}
const handleCourse = (row: any) => {
isShowSemCourseDialog.value = true
id.value = row.id
}
</script> </script>
<template> <template>
<AppCard title="学期管理"> <AppCard title="学期管理">
<AppList v-bind="listOptions" ref="appList" border stripe> <AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round>新增学期</el-button> <el-button type="primary" round @click="handleAddSemester">新增学期</el-button>
<template #table-operate> <template #table-operate="{ row }">
<el-space> <el-space>
<el-link type="primary" plain>查看</el-link> <el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link type="primary" plain>编辑</el-link> <el-link type="primary" plain @click="handleEdit(row)">编辑</el-link>
<el-link type="primary" plain>关联课程</el-link> <el-link type="primary" plain @click="handleCourse(row)">关联课程</el-link>
</el-space> </el-space>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<AddSemester
v-model:isShowAddSemDialog="isShowAddSemDialog"
v-if="isShowAddSemDialog === true"
:title="title"
:id="title"
:isEdit="isEdit"
/>
<SemesterCourse v-model:isShowSemCourseDialog="isShowSemCourseDialog" v-if="isShowSemCourseDialog === true" />
</template> </template>
import httpRequest from '@/utils/axios' import httpRequest from '@/utils/axios'
// 获取学生列表 // 获取学生列表
export function getProList(params?: { type?: string; page?: number; page_size?: number }) { export function getStudentList(params?: { type?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/psp/backend/video/index', { params })
}
// // 获取学生列表
export function importStudent(params?: { file: any }) {
return httpRequest.get('/api/psp/backend/video/index', { params }) return httpRequest.get('/api/psp/backend/video/index', { params })
} }
<script lang="ts" setup>
import type { FormRules } from 'element-plus'
const emit = defineEmits<Emits>()
const schoolList = [
{
id: '111',
name: '清华'
},
{
id: '222',
name: '北大'
}
]
const form = reactive({
school: '',
name: '',
sex: 0,
mobile: '',
role: 0,
email: ''
})
const rules = reactive<FormRules>({
school: [{ required: true, message: '请选择部门/学校', trigger: 'change' }],
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
sex: [{ required: true, message: '请选择性别', trigger: 'change' }],
mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
role: [{ required: true, message: '请选择角色类型', trigger: 'change' }],
email: [{ required: true, message: '请输入邮箱', trigger: 'blur' }]
})
const props = defineProps({
isShowStaffDialog: {
type: Boolean
},
title: {
type: String
}
})
interface Emits {
(e: 'update:isShowStaffDialog', isShowStaffDialog: boolean): void
(e: 'create'): void
}
// 取消
const handleCancel = () => {
emit('update:isShowStaffDialog', false)
}
const handleConfirm = () => {
emit('update:isShowStaffDialog', false)
emit('create')
}
</script>
<template>
<el-dialog :model-value="isShowStaffDialog" draggable :before-close="handleCancel" :title="props.title" width="30%">
<el-form :model="form" label-position="right" label-width="auto" :rules="rules" ref="formRef">
<el-form-item label="所属部门/学校:" prop="school">
<el-select v-model="form.school" placeholder="请选择所属部门/学校" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="姓名:" prop="name">
<el-input v-model="form.name" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="性别:" prop="sex">
<el-radio-group v-model="form.sex" :disabled="props.title === '查看详情'">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="手机号:" prop="mobile">
<el-input v-model="form.mobile" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="角色类型:" prop="role">
<el-radio-group v-model="form.role" :disabled="props.title === '查看详情'">
<el-radio :label="0">班主任</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="邮箱:" prop="email">
<el-input v-model="form.email" :disabled="props.title === '查看详情'" />
</el-form-item>
</el-form>
<template #footer>
<span>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
...@@ -3,7 +3,7 @@ import AppLayout from '@/components/layout/Index.vue' ...@@ -3,7 +3,7 @@ import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [ export const routes: Array<RouteRecordRaw> = [
{ {
path: '/admin/exam', path: '/admin/staff',
component: AppLayout, component: AppLayout,
children: [{ path: '', component: () => import('./views/List.vue') }] children: [{ path: '', component: () => import('./views/List.vue') }]
} }
......
<script setup lang="ts">
// import { getStudentList } from '../api'
// import { useMapStore } from '@/stores/map'
// const store = useMapStore()
import AddStaff from '../components/AddStaff.vue'
const appList = ref()
const studentId = ref('')
const title = ref('') // 弹框标题
const isShowStaffDialog = ref(false)
const listOptions = $computed(() => {
return {
// remote: { httpRequest: getStudentList, params: { type: '' } },
filters: [
{ type: 'input', prop: 'name', label: '姓名', placeholder: '姓名' },
{ type: 'select', prop: 'office', label: '所属部门/学校', placeholder: '所属部门/学校' }
],
columns: [
{ label: '序号', type: 'index', align: 'center' },
{ label: '所属部门/学校', prop: 'school', align: 'center' },
{ label: '手机号', prop: 'mobile', align: 'center' },
{ label: '姓名', prop: 'name', align: 'center' },
{ label: '性别', prop: 'sex', align: 'center' },
{ label: '邮箱', prop: 'email', align: 'center' },
{ label: '角色类型', prop: 'province', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', fixed: 'right' }
],
data: [{ name: '222' }]
}
})
// 刷新页面
// const handleRefresh = () => {
// appList.value.refetch()
// }
// 新增学生
const handleAddStudent = () => {
isShowStaffDialog.value = true
title.value = '新增教工'
}
// 编辑学生
const handleEdit = (row: any) => {
isShowStaffDialog.value = true
title.value = '编辑教工'
studentId.value = row.id
}
// 查看详情
const handleDetail = (row: any) => {
isShowStaffDialog.value = true
title.value = '查看详情'
studentId.value = row.id
}
</script>
<template>
<AppCard title="教工用户管理">
<AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round @click="handleAddStudent">新增教工</el-button>
<template #table-operate="{ row }">
<el-space>
<el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link type="primary" plain @click="handleEdit(row)">编辑</el-link>
</el-space>
</template>
</AppList>
</AppCard>
<AddStaff v-model:isShowStaffDialog="isShowStaffDialog" :title="title" />
</template>
...@@ -4,3 +4,7 @@ import httpRequest from '@/utils/axios' ...@@ -4,3 +4,7 @@ import httpRequest from '@/utils/axios'
export function getStudentList(params?: { type?: string; page?: number; page_size?: number }) { export function getStudentList(params?: { type?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/psp/backend/video/index', { params }) return httpRequest.get('/api/psp/backend/video/index', { params })
} }
// // 获取学生列表
export function importStudent(params?: { file: any }) {
return httpRequest.get('/api/psp/backend/video/index', { params })
}
<script lang="ts" setup>
import type { FormRules } from 'element-plus'
const emit = defineEmits<Emits>()
const schoolList = [
{
id: '111',
name: '清华'
},
{
id: '222',
name: '北大'
}
]
const classList = [
{
id: '111',
name: 'qq'
},
{
id: '222',
name: 'ww'
}
]
const form = reactive({
sno: '',
name: '',
sex: 0,
mobile: '',
card_type: 0,
card_number: '',
school: '',
major: '',
class: '',
status: 0
})
const rules = reactive<FormRules>({
sno: [{ required: true, message: '请输入学号', trigger: 'blur' }],
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
sex: [{ required: true, message: '请选择性别', trigger: 'change' }],
mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
card_type: [{ required: true, message: '请选择证件类型', trigger: 'change' }],
card_number: [{ required: true, message: '请选择证件号码', trigger: 'blur' }],
school: [{ required: true, message: '请选择部门/学校', trigger: 'change' }],
status: [{ required: true, message: '请选择状态', trigger: 'change' }]
})
const props = defineProps({
isShowAddDialog: {
type: Boolean
},
title: {
type: String
},
id: {
type: String
}
})
interface Emits {
(e: 'update:isShowAddDialog', isShowAddDialog: boolean): void
(e: 'create'): void
}
// 取消
const handleCancel = () => {
emit('update:isShowAddDialog', false)
console.log('999')
}
// 确认
const handleConfirm = () => {
emit('update:isShowAddDialog', false)
emit('create')
}
</script>
<template>
<el-dialog :model-value="isShowAddDialog" draggable :before-close="handleCancel" :title="props.title" width="30%">
<el-form :model="form" label-width="120px" :rules="rules" ref="formRef">
<el-form-item label="学号:" prop="sno">
<el-input v-model="form.name" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="姓名:" prop="name">
<el-input v-model="form.name" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="性别:" prop="sex">
<el-radio-group v-model="form.sex" :disabled="props.title === '查看详情'">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="联系电话:" prop="mobile">
<el-input v-model="form.mobile" :disabled="props.title === '查看详情'"></el-input>
</el-form-item>
<el-form-item label="证件类型:" prop="card_type">
<el-radio-group v-model="form.card_type" :disabled="props.title === '查看详情'">
<el-radio :label="0">身份证</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="证件号码:" prop="card_number">
<el-input v-model="form.card_number" :disabled="props.title === '查看详情'" />
</el-form-item>
<el-form-item label="所属部门/学校:" prop="school">
<el-select v-model="form.school" placeholder="请选择所属部门/学校" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in schoolList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="专业:" prop="major">
<el-input v-model="form.major" :disabled="props.title === '查看详情'" />
</el-form-item>
<el-form-item label="班级:" prop="class">
<el-select v-model="form.class" placeholder="请选择班级" :disabled="props.title === '查看详情'">
<el-option v-for="(item, index) in classList" :key="index" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="系统同步状态:" prop="status">
<el-radio-group v-model="form.status" :disabled="props.title === '查看详情'">
<el-radio :label="0">有效</el-radio>
<el-radio :label="1">无效</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<span>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ElMessage } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'
import { splitStrLast } from '@/utils/util'
import { importStudent } from '../api'
const emit = defineEmits<Emits>()
const upload = ref()
const fileList = ref([]) // 文件列表
defineProps({
isShowImportDialog: {
type: Boolean
}
})
interface Emits {
(e: 'update:isShowImportDialog', isShowImportDialog: boolean): void
(e: 'create'): void
}
// 取消
const handleCancel = () => {
emit('update:isShowImportDialog', false)
console.log('999')
}
const beforeUpload = (file: any) => {
const suffix = splitStrLast(file.name, '.')
if (!['xlsx', 'xls'].includes(suffix)) {
ElMessage.warning('只能上传excel文件')
return false
} else {
return true
}
}
const fetchFileUpload = (data: any) => {
console.log(data, 'data')
return new Promise(() => {
importStudent({ file: data.file }).then((res: any) => {
if (res.code === 0) {
ElMessage.success('导入数据成功')
}
})
})
}
const handleSubmitUpload = () => {
upload.value.submit()
emit('update:isShowImportDialog', false)
emit('create')
}
</script>
<template>
<el-dialog :model-value="isShowImportDialog" draggable :before-close="handleCancel" title="批量导入学生" width="30%">
<el-upload
style="text-align: center"
class="file-import"
ref="upload"
action="#"
accept=".xls,.xlsx"
drag
:auto-upload="false"
:file-list="fileList"
:limit="1"
:before-upload="beforeUpload"
:http-request="fetchFileUpload"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖至此处,点击上传</div>
</el-upload>
<div style="margin-bottom: 10px; text-align: center">
导入模板下载:<a
href="https://webapp-pub.ezijing.com/x-training-new/%E8%80%81%E5%B8%88%E6%A8%A1%E6%9D%BF.xlsx"
download="教师模板"
><el-button type="text">teacher_import.xlsx</el-button></a
>
</div>
<template #footer>
<span>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSubmitUpload">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { getStudentList } from '../api' import AddStudent from '../components/AddStudent.vue'
import ImportStudent from '../components/ImportStudent.vue'
// import { getStudentList } from '../api'
// import { useMapStore } from '@/stores/map' // import { useMapStore } from '@/stores/map'
// const store = useMapStore() // const store = useMapStore()
const appList = ref() const appList = ref()
const id = ref('')
const title = ref('') // 弹框标题
const isShowAddDialog = ref(false)
const isShowImportDialog = ref(false)
const listOptions = $computed(() => { const listOptions = $computed(() => {
return { return {
remote: { httpRequest: getStudentList, params: { type: '' } }, // remote: { httpRequest: getStudentList, params: { type: '' } },
filters: [ filters: [
{ type: 'input', prop: 'name', label: '学生姓名', placeholder: '学生姓名' }, { type: 'input', prop: 'name', label: '学生姓名', placeholder: '学生姓名' },
{ type: 'select', prop: 'office', label: '所属部门/学校', placeholder: '所属部门/学校' } { type: 'select', prop: 'office', label: '所属部门/学校', placeholder: '所属部门/学校' }
], ],
columns: [ columns: [
{ label: '序号', type: 'index', align: 'center' }, { label: '序号', type: 'index', align: 'center' },
{ label: '学号', prop: 'name', align: 'center' }, { label: '学号', prop: 'sno', align: 'center' },
{ label: '姓名', prop: 'name', align: 'center' }, { label: '姓名', prop: 'name', align: 'center' },
{ label: '性别', prop: 'name', align: 'center' }, { label: '性别', prop: 'sex', align: 'center' },
{ label: '出生年月', prop: 'name', align: 'center' }, { label: '出生年月', prop: 'birth', align: 'center' },
{ label: '省', prop: 'name', align: 'center' }, { label: '省', prop: 'province', align: 'center' },
{ label: '市', prop: 'name', align: 'center' }, { label: '市', prop: 'city', align: 'center' },
{ label: '县', prop: 'name', align: 'center' }, { label: '县', prop: 'county', align: 'center' },
{ label: '联系电话', prop: 'name', align: 'center' }, { label: '联系电话', prop: 'mobile', align: 'center' },
{ label: '部门/学校', prop: 'name', align: 'center' }, { label: '部门/学校', prop: 'school', align: 'center' },
{ label: '专业', prop: 'name', align: 'center' }, { label: '专业', prop: 'major', align: 'center' },
{ label: '班级', prop: 'name', align: 'center' }, { label: '班级', prop: 'class', align: 'center' },
{ label: '身份证号', prop: 'name', align: 'center' }, { label: '身份证号', prop: 'idNumber', align: 'center' },
{ label: '状态', prop: 'name', align: 'center' }, { label: '有效状态', prop: 'status', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' }, { label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center' } { label: '操作', slots: 'table-operate', align: 'center', fixed: 'right' }
] ],
data: [{ name: '111' }]
} }
}) })
// 刷新页面
const handleRefresh = () => {
appList.value.refetch()
}
// 新增学生
const handleAddStudent = () => {
isShowAddDialog.value = true
title.value = '新增学生'
}
// 编辑学生
const handleEdit = (row: any) => {
isShowAddDialog.value = true
title.value = '编辑学生'
id.value = row.id
}
// 查看详情
const handleDetail = (row: any) => {
isShowAddDialog.value = true
title.value = '查看详情'
id.value = row.id
}
</script> </script>
<template> <template>
<AppCard title="学生管理"> <AppCard title="学生管理">
<AppList v-bind="listOptions" ref="appList" border stripe> <AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round>新增学生</el-button> <el-button type="primary" round @click="handleAddStudent">新增学生</el-button>
<el-button type="primary" round>批量导入</el-button> <el-button type="primary" round @click="isShowImportDialog = true">批量导入</el-button>
<el-button type="primary" round>导出</el-button> <el-button type="primary" round>导出</el-button>
<template #table-operate> <template #table-operate="{ row }">
<el-space> <el-space>
<el-link type="primary" plain>查看</el-link> <el-link type="primary" plain @click="handleDetail(row)">查看</el-link>
<el-link type="primary" plain>编辑</el-link> <el-link type="primary" plain @click="handleEdit(row)">编辑</el-link>
</el-space> </el-space>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
<!-- 新增学生 -->
<AddStudent
v-if="isShowAddDialog === true"
v-model:isShowAddDialog="isShowAddDialog"
:id="id"
:title="title"
@create="handleRefresh"
/>
<ImportStudent v-if="isShowImportDialog" v-model:isShowImportDialog="isShowImportDialog" @create="handleRefresh" />
</template> </template>
import httpRequest from '@/utils/axios'
// 获取学生列表
export function getProList(params?: { type?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/psp/backend/video/index', { params })
}
/**
* 获取试卷详情
*/
export function getPaperDetails(params?: { exam_id: string; student_id: string }) {
return httpRequest.get('/api/exam/v1/exam/sheet-detail', { params })
}
/**
* 批改试卷
*/
export function submitPaper(data?: {
sheet_id: string
question_item_id: string
question_id: string
score: string
comment: string
}) {
return httpRequest.post('/api/exam/v1/exam/submit-sheet', data)
}
<template>
<el-card class="container">
<template #header>
<span>{{ questionItem.question_item_title }}</span>
</template>
<div class="content">
<template v-for="item in questionItem.question_list">
<div class="sub-content" v-if="item.group_id" :key="item.id">
<div class="title" v-html="item.common_content"></div>
<div class="sub-container">
<QuestionItem
v-for="subItem in item.list"
:key="subItem.id"
:question="{ item: subItem, question_item_id, questionType, sheet_id }"
:question_item_id="question_item_id"
/>
</div>
</div>
<QuestionItem
v-else
:question="{ item, question_item_id, questionType, sheet_id }"
:question_item_id="question_item_id"
:key="item.id"
/>
</template>
</div>
</el-card>
</template>
<script lang="ts" setup>
import QuestionItem from './QuestionItem.vue'
const props = defineProps({
options: {
type: Object,
default() {
return {}
}
},
question_item_id: {
type: String
}
})
const questionItem = computed(() => {
return props.options.item
})
const sheet_id = computed(() => {
return props.options.sheet_id
})
const questionType = computed(() => {
return props.options.item.question_item_type
})
</script>
<style lang="scss" scoped>
.container {
background: #fff;
border: 1px solid #f3f3f3;
margin-bottom: 20px;
border-radius: 6px;
::v-deep .el-card__body {
padding: 10px 20px;
}
.content {
// border:1px solid #f3f3f3;
padding: 10px;
.title {
line-height: 40px;
font-size: 16px;
}
.sub-container {
border: 1px solid #e3e3e3;
padding: 15px 15px 0;
border-radius: 4px;
}
.sub-content {
margin-bottom: 20px;
}
.question-item:last-child {
border: none;
}
}
}
</style>
<template>
<div class="question-item">
<div class="question-item-title" v-html="questionData.content"></div>
<template v-if="questionType === 1 || questionType === 6">
<el-radio-group v-model="questionData.user_answer[0]" :disabled="true" class="question-item-content">
<div class="question-item-option" v-for="subItem in questionData.options" :key="subItem.id">
<el-radio :label="subItem.id">{{ subItem.option }}</el-radio>
</div>
</el-radio-group>
</template>
<template v-if="questionType === 2">
<el-checkbox-group v-model="questionData.user_answer" :disabled="true" class="question-item-content">
<div class="question-item-option" v-for="subItem in questionData.options" :key="subItem.id">
<el-checkbox :label="subItem.id"> {{ subItem.option }} </el-checkbox>
</div>
</el-checkbox-group>
</template>
<template v-if="questionType === 3">
<div class="SAQ">{{ questionData.user_answer[0] || '' }}</div>
<div style="text-align: right">
<el-button
type="primary"
size="small"
plain
@click="showComment = !showComment"
v-permission="'admin_exam_exam_submit_sheet'"
>点击评分</el-button
>
</div>
<div class="comment" v-show="showComment">
<div class="comment-top">
<p>本题{{ questionData.score }}</p>
<div class="get-score">
学生得分:<el-input-number
:disabled="questionData.checked_flag"
v-model="questionData.get_score"
controls-position="right"
:min="0"
:max="questionData.score"
size="small"
></el-input-number>
</div>
</div>
<el-input
type="textarea"
placeholder="请输入评语"
v-model="questionData.comment"
rows="3"
:disabled="questionData.checked_flag"
/>
<div style="text-align: center; padding-top: 10px">
<el-button type="primary" size="small" @click="fetchComment" :disabled="questionData.checked_flag"
>提交点评</el-button
>
</div>
</div>
</template>
<div class="question-item-score">得分:{{ questionData.get_score }}分</div>
</div>
</template>
<script lang="ts" setup>
import { ElMessage } from 'element-plus'
import { submitPaper } from '../api.js'
const bc: any = ref(null)
const questionData: any = ref({})
const showComment = ref(false)
const props = defineProps({
question: {
type: Object,
default() {
return {}
}
},
question_item_id: {
type: String
}
})
const questionType = computed(() => {
// 1单选,2多选,3简答,5案例题, 6判断, 7实操,8情景
const type = questionData.value.type || props.question.questionType || 1
return parseInt(type)
})
const sheet_id = computed(() => {
return props.question.sheet_id
})
onMounted(() => {
questionData.value = JSON.parse(JSON.stringify(props.question.item))
})
onUnmounted(() => {
bc.value && bc.value.close()
})
const fetchComment = () => {
const params: any = {
sheet_id: sheet_id,
question_item_id: props.question_item_id,
question_id: questionData.value.id,
score: questionData.value.get_score,
comment: questionData.value.comment
}
submitPaper(params).then((res: any) => {
if (res.success) {
ElMessage.success('提交点评成功')
} else {
ElMessage.success('提交点评失败')
}
bc.value = new BroadcastChannel('exam')
bc.value.postMessage({ action: 'refetch' })
})
}
</script>
<style lang="scss" scoped>
.question-item {
font-size: 14px;
color: #454545;
border-bottom: 1px solid #f3f3f3;
margin-bottom: 10px;
.question-item-content {
padding-left: 10px;
.question-item-option {
padding-top: 10px;
}
}
.SAQ {
min-height: 60px;
font-size: 14px;
line-height: 24px;
color: #888;
border: 1px solid #eee;
background: #f3f3f3;
margin: 10px 0;
border-radius: 6px;
}
.comment {
border: 1px solid rgba(192, 28, 64, 0.3);
border-radius: 4px;
padding: 10px;
margin-top: 15px;
background: #f9f9f9;
.comment-top {
display: flex;
margin-bottom: 10px;
p {
flex: 1;
}
}
}
.question-item-score {
color: #777;
padding: 10px 0;
}
}
</style>
import type { RouteRecordRaw } from 'vue-router'
import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [
{
path: '/teach/exam',
component: AppLayout,
children: [
{ path: '/teach/exam', component: () => import('./views/List.vue') },
{ path: '/teach/view', component: () => import('./views/View.vue') }
]
}
]
<script setup lang="ts">
// import { getProList } from '../api'
// import { useMapStore } from '@/stores/map'
// const store = useMapStore()
const router = useRouter()
const appList = ref()
const listOptions = $computed(() => {
return {
// remote: { httpRequest: getProList, params: { name: '' } },
filters: [
{ type: 'select', prop: 'course', label: '所属课程:', placeholder: '所属课程' },
{ type: 'select', prop: 'class', label: '所属班级:', placeholder: '所属班级' },
{ type: 'select', prop: 'name', label: '所属学生:', placeholder: '所属学生' },
{ type: 'input', prop: 'exam_name', label: '考试名称:', placeholder: '考试名称' },
{ type: 'input', prop: 'paper_name', label: '试卷名称:', placeholder: '试卷名称' }
],
columns: [
{ label: '序号', type: 'index', align: 'center' },
{ label: '所属课程', prop: 'course', align: 'center' },
{ label: '所属班级', prop: 'class', align: 'center' },
{ label: '学生姓名', prop: 'name', align: 'center' },
{ label: '考试名称', prop: 'exam_name', align: 'center' },
{ label: '试卷名称', prop: 'paper_name', align: 'center' },
{ label: '得分', prop: 'score', align: 'center' },
{ label: '是否批改', prop: 'correct', align: 'center' },
{ label: '更新时间', prop: 'update_time', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center' }
],
data: [
{
name: 111,
exam_id: '6952903190949920768',
student_id: '6953256575158976512'
}
]
}
})
const handleCheckPaper = (row: any) => {
console.log(row)
router.push({ path: '/teach/view', query: { eid: row.exam_id, sid: row.student_id } })
}
</script>
<template>
<AppCard title="批改试卷">
<AppList v-bind="listOptions" ref="appList" border stripe>
<template #table-operate="{ row }">
<el-space>
<el-link type="primary" plain @click="handleCheckPaper(row)">批改试卷</el-link>
</el-space>
</template>
</AppList>
</AppCard>
</template>
<script lang="ts" setup>
import { getPaperDetails } from '../api.js'
import PaperQuestion from '../components/PaperQuestion.vue'
const route = useRoute()
const questionData: any = ref({})
const questionList: any = ref([])
const eid = route.query.eid as string
const sid = route.query.sid as string
onMounted(() => {
getDetail()
})
// 获取试卷详情
const getDetail = () => {
const params: any = { exam_id: eid, student_id: sid }
getPaperDetails(params).then((res: any) => {
questionData.value = res.data.sheet
assembleData()
})
}
const assembleData = () => {
questionList.value = questionData.value.questions.question_items
questionList.value.forEach((item: any) => {
const score = questionData.value.score_item[item.question_item_id]
// 用户答案
const answer = questionData.value.answers ? questionData.value.answers[item.question_item_id] || {} : {}
item.question_list.value.forEach((subItem: any) => {
if (subItem.group_id) {
subItem.list.forEach((it: any) => {
const obj = score[it.id]
it.get_score = obj.score || 0
it.checked_flag = obj.checked_flag || false
if (obj.comment) it.comment = obj.comment
if (it.answer) it.answer = JSON.parse(it.answer)
if (it.options) it.options = JSON.parse(it.options)
it.user_answer = answer[it.id]?.answer || []
})
} else {
const obj = score[subItem.id]
subItem.get_score = obj.score || 0
subItem.checked_flag = obj.checked_flag || false
if (obj.comment) subItem.comment = obj.comment
if (subItem.answer) subItem.answer = JSON.parse(subItem.answer)
if (subItem.options) subItem.options = JSON.parse(subItem.options)
subItem.user_answer = answer[subItem.id]?.answer || []
}
})
})
}
</script>
<template>
<div>
<template v-for="item in questionList" :key="item.question_item_id">
<paper-question
:options="{ item, sheet_id: questionData.sheet_id, question_item_id: item.question_item_id }"
:question_item_id="item.question_item_id"
/>
</template>
</div>
</template>
import type { RouteRecordRaw } from 'vue-router'
export const routes: Array<RouteRecordRaw> = [
{
path: '/teach',
redirect: '/teach/qa'
}
]
...@@ -3,7 +3,7 @@ import AppLayout from '@/components/layout/Index.vue' ...@@ -3,7 +3,7 @@ import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [ export const routes: Array<RouteRecordRaw> = [
{ {
path: '/admin/qa', path: '/teach/qa',
component: AppLayout, component: AppLayout,
children: [{ path: '', component: () => import('./views/List.vue') }] children: [{ path: '', component: () => import('./views/List.vue') }]
} }
......
/**
* 文件下载
* @param {string} fileUrl 文件下载地址
* @param {string} fileName 文件名
* @returns {null}
*/
export function funDownload(fileUrl: any, fileName: any) {
// console.log(fileUrl)
const elink = document.createElement('a') // 创建一个a标签
elink.download = fileName // 设置a标签的下载属性
elink.style.display = 'none' // 将a标签设置为隐藏
elink.href = fileUrl // 把之前处理好的地址赋给a标签的href
document.body.appendChild(elink) // 将a标签添加到body中
elink.click() // 执行a标签的点击方法
// URL.revokeObjectURL(elink.href) // 下载完成释放URL 对象
document.body.removeChild(elink) // 移除a标签
}
/**
* 分割字符串,取得尾部
* @param {string} str 字符串
* @param {string} split 分割符
* @returns {string}
*/
export function splitStrLast(str: any, split: any) {
const fileNameArr = str.split(split)
const last = fileNameArr[fileNameArr.length - 1]
return last
}
...@@ -31,6 +31,12 @@ export default defineConfig(({ mode }) => ({ ...@@ -31,6 +31,12 @@ export default defineConfig(({ mode }) => ({
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/api\/qbs/, '') rewrite: path => path.replace(/^\/api\/qbs/, '')
}, },
'/api/exam': {
target: 'https://x-exam-admin-api.ezijing.com',
// target: 'http://localhost-exam-admin.ezijing.com',
rewrite: path => path.replace(/^\/api\/exam/, '')
},
'/api': 'https://resource-center.ezijing.com' '/api': 'https://resource-center.ezijing.com'
} }
}, },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论