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

chore:项目优化

上级 db49a9f4
......@@ -49,3 +49,7 @@ export function getRelationSemCourse(params?: {
export function relationSemCourse(data: { semester_id: string; courses_id: string; type: string }) {
return httpRequest.post('/api/resource/v1/learning/semester/add-courses', data)
}
// 设置课程别名
export function setAliasName(data: { semester_id: string; course_id: string; alias_name: string }) {
return httpRequest.post('/api/resource/v1/learning/semester/set-course-alias-name', data)
}
......@@ -41,7 +41,7 @@ const listOptions = $computed(() => {
columns: [
{ type: 'selection' },
{ label: '序号', type: 'index', align: 'center' },
{ label: '课程名称/别名', prop: 'name', align: 'center', width: '200' },
{ label: '课程名称', prop: 'name', align: 'center', width: '200' },
{ label: '课程类型', prop: 'online_type_name', align: 'center', width: '200' },
{ label: '选课类型', prop: 'elective_type_name', align: 'center' },
{ label: '课程分类', prop: 'classification_name', align: 'center', width: '310' },
......
<script lang="ts" setup>
import { ElMessage, ElMessageBox } from 'element-plus'
import AddSemCourse from './AddSemCourse.vue'
import { getSemCourse, relationSemCourse } from '../api'
import { getSemCourse, relationSemCourse, setAliasName } from '../api'
const emit = defineEmits<Emits>()
const props = defineProps({
isShowSemCourseDialog: {
......@@ -32,6 +32,7 @@ const listOptions = $computed(() => {
columns: [
{ label: '序号', type: 'index', align: 'center' },
{ label: '课程名称', prop: 'name', align: 'center' },
{ label: '别名', prop: 'alias_name', slots: 'alias_name', align: 'center', width: '200' },
{ label: '课程类型', prop: 'online_type_name', align: 'center' },
{ label: '选课类型', prop: 'elective_type_name', align: 'center' },
{ label: '课程分类', prop: 'classification_name', align: 'center' },
......@@ -76,6 +77,17 @@ const handleCancel = () => {
const handleFresh = () => {
appList.value.refetch()
}
// 课程设置别名
const handleChangeName = (row: any) => {
const params: any = {
semester_id: props.id,
course_id: row.id,
alias_name: row.alias_name
}
setAliasName(params).then(() => {
ElMessage.success('课程别名设置成功')
})
}
</script>
<template>
<el-dialog
......@@ -97,6 +109,9 @@ const handleFresh = () => {
</el-descriptions>
<AppList v-bind="listOptions" ref="appList" border stripe style="margin-top: 30px">
<el-button type="primary" round @click="handleAddCourse">添加课程</el-button>
<template #alias_name="{ row }">
<el-input v-model="row.alias_name" @blur="handleChangeName(row)"></el-input>
</template>
<template #table-operate="{ row }">
<el-space>
<router-link :to="`/course/my/view??id=${row.id}`" target="_blank">
......
......@@ -38,7 +38,7 @@ const form: any = reactive({
name: '',
gender: '1',
mobile: '',
role: '2',
role: [],
email: '',
status: '1'
})
......@@ -70,6 +70,7 @@ const handleConfirm = async (formEl: FormInstance | undefined) => {
await formEl.validate(valid => {
if (valid) {
if (props.isEdit === '0') {
form.role = form.role.toString()
const params: any = Object.assign({}, form)
if (userStore.roles[0].name === '部门管理员') {
params.organ_id = userStore.organization?.id
......@@ -80,6 +81,8 @@ const handleConfirm = async (formEl: FormInstance | undefined) => {
emit('create')
})
} else if (props.isEdit === '1') {
console.log(form.role, 'form.role ')
form.role = form.role.toString()
const params: any = Object.assign({ id: props.id }, form)
updateStaff(params).then(() => {
ElMessage.success('更新教工成功')
......@@ -100,6 +103,7 @@ if (props.isEdit === '2' || props.isEdit === '1') {
Object.keys(form).forEach(key => {
form[key] = res.data[key]
})
form.role = res.data.role.split(',')
})
}
</script>
......@@ -131,9 +135,9 @@ if (props.isEdit === '2' || props.isEdit === '1') {
<el-input v-model="form.mobile" :disabled="props.isEdit === '2' || props.isEdit === '1'"></el-input>
</el-form-item>
<el-form-item label="角色类型" prop="role">
<el-radio-group v-model="form.role" :disabled="props.isEdit === '2'">
<el-radio v-for="(item, index) in roleList" :key="index" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
<el-checkbox-group v-model="form.role" :disabled="props.isEdit === '2'">
<el-checkbox v-for="(item, index) in roleList" :key="index" :label="item.value">{{ item.label }}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" :disabled="props.isEdit === '2'" />
......
......@@ -233,3 +233,7 @@ export function setOpenRules(data: {
export function setDownload(data: { course_id: string; information_id: string; can_download: string }) {
return httpRequest.post('/api/resource/v1/course/course/set-course-information-can-download ', data)
}
// 助教搜索
export function searchAssistant(params: { name: string; page?: string; 'per-page'?: string }) {
return httpRequest.get('/api/resource/v1/course/course/search-teacher', { params })
}
<script setup lang="ts">
import { searchAssistant } from '../../api'
import type { Lecturer } from '../../types'
import { uniqBy } from 'lodash-es'
interface Props {
modelValue: Lecturer[]
}
const props = withDefaults(defineProps<Props>(), { modelValue: () => [] })
const emit = defineEmits<{
(e: 'update:modelValue', modelValue: Lecturer[]): void
}>()
const listOptions = computed(() => {
return {
columns: [
{ label: '头像', slots: 'table-avatar', align: 'center' },
{ label: '姓名', prop: 'name', align: 'center' },
{ label: '操作', slots: 'table-operate', align: 'center', fixed: 'right' }
],
data: props.modelValue
}
})
// 弹窗
const dialogVisible = ref(false)
// 选中的值
const selectList = ref<Lecturer[]>([])
// 远程搜索
const loading = ref(false)
const options = ref<Lecturer[]>([])
const remoteMethod = (query: string) => {
if (!query) return
loading.value = true
searchAssistant({ name: query, 'per-page': '100' }).then((res: any) => {
loading.value = false
options.value = res.data.list
})
}
watch(
dialogVisible,
() => {
// 清空已选数据
selectList.value = []
},
{ immediate: true }
)
// 删除
const handelRemove = (id: string) => {
emit(
'update:modelValue',
props.modelValue.filter((item: any) => item.id !== id)
)
}
// 确认
const handlePrimary = () => {
const list = [...selectList.value, ...props.modelValue]
// 去重
emit('update:modelValue', uniqBy(list, 'id'))
dialogVisible.value = false
}
</script>
<template>
<div>
<el-button type="primary" @click="dialogVisible = true">添加助教</el-button>
<AppList v-bind="listOptions" ref="appList">
<template #table-avatar="{ row }">
<img
:src="row.avatar || 'https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png'"
style="width: 50px; height: 50px; display: block; margin: 0 auto"
/>
</template>
<template #table-summarize="{ row }">
<div v-html="row.summarize"></div>
</template>
<template #table-operate="{ row }">
<el-button plain @click="handelRemove(row.id)">删除</el-button>
</template>
</AppList>
<el-dialog v-model="dialogVisible" width="400px" title="添加助教" append-to-body>
<el-form label-suffix=":" label-position="left">
<el-form-item label="助教姓名">
<el-select
v-model="selectList"
multiple
filterable
remote
placeholder="请输入助教姓名"
value-key="id"
:reserve-keyword="false"
:remote-method="remoteMethod"
:loading="loading"
style="width: 100%"
>
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="handlePrimary">确认</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { setDownload } from '../../api'
import AddVideoDialog from '../stepTwoComponents/AddVideoDialog.vue'
const emit = defineEmits<Emits>()
const dataList: any = ref([])
const isShowAddDialog = ref(false)
interface Emits {
(e: 'information', dataList: any): void
}
const props = defineProps({
data: {
type: Array,
required: true
},
id: {
type: String
}
})
watch(
() => props.data,
value => {
if (value?.length > 0) {
dataList.value = [...props.data]
} else {
dataList.value = []
}
},
{ immediate: true }
)
watch(
() => dataList.value,
value => {
if (value?.length > 0) {
emit('information', dataList.value)
}
}
)
const handleAddData = () => {
isShowAddDialog.value = true
}
const handleAdd = (val: any) => {
dataList.value.push({ id: val.id, name: val.name, can_download: val.can_download, url: val.url, type: val.type })
console.log(dataList.value, 'dataList.value')
emit('information', dataList.value)
}
const listOptions = $computed(() => {
return {
columns: [
{ label: '资料名称', prop: 'name', slots: 'table-name' },
{ label: '能否下载', prop: 'can_download', slots: 'table-status' },
{ label: '操作', slots: 'table-operate', align: 'center', width: 200, fixed: 'right' }
],
data: dataList.value.length > 0 ? dataList.value : []
}
})
const handleDetail = (row: any) => {
window.open(row.url)
}
const handleDel = (row: any) => {
dataList.value.splice(row, 1)
emit('information', dataList.value)
}
const imgUrl = (val: any) => {
if (val.type === 'zip') {
return 'https://webapp-pub.ezijing.com/center_resource/zip_img.png'
} else if (val.type === 'pdf') {
return 'https://webapp-pub.ezijing.com/center_resource/pdf_img.png'
} else if (val.type === 'png' || val.type === 'jpeg' || val.type === 'jpg') {
return 'https://webapp-pub.ezijing.com/center_resource/jpg_img.png'
} else if (val.type === 'xls' || val.type === 'xlsx') {
return 'https://webapp-pub.ezijing.com/center_resource/xls_img.png'
} else if (val.type === 'docx' || val.type === 'doc') {
return 'https://webapp-pub.ezijing.com/center_resource/docx_img.png'
} else if (val.type === 'mp4') {
return 'https://webapp-pub.ezijing.com/center_resource/mp4_img.png'
} else if (val.type === 'mp3') {
return 'https://webapp-pub.ezijing.com/center_resource/mp3_img.png'
} else if (val.type === 'rar') {
return 'https://webapp-pub.ezijing.com/center_resource/rar_img.png'
} else if (val.type === 'pptx' || val.type === 'ppt') {
return 'https://webapp-pub.ezijing.com/center_resource/pptx_img.png'
}
}
const handleChangeStatus = (row: any) => {
console.log(row.id, '1111')
if (row.id !== undefined && dataList.length > 0) {
const params: any = {
course_id: props.id,
information_id: row.id,
can_download: row.can_download
}
setDownload(params).then(() => {
ElMessage.success('设置课程资料能否下载成功')
})
}
}
</script>
<template>
<div>
<el-button type="primary" @click="handleAddData">添加课程资料</el-button>
<AppList v-bind="listOptions" ref="appList">
<template #table-name="{ row }">
<img :src="imgUrl(row)" alt="" style="width: 13px; height: 100%; margin-right: 13px" />
<span class="node_type">资料</span>
<span class="node_title">{{ row.name }}</span>
</template>
<template #table-status="{ row }">
<el-switch
size="large"
v-model="row.can_download"
active-value="1"
inactive-value="0"
inline-prompt
style="--el-switch-on-color: #aa1941"
@change="handleChangeStatus(row)"
></el-switch>
</template>
<template #table-operate="{ row }">
<el-button plain @click="handleDetail(row)" :disabled="row.can_download === '0'">查阅</el-button>
<el-button type="primary" plain @click="handleDel(row)">删除</el-button>
</template>
</AppList>
<!-- 添加资源 -->
<AddVideoDialog
v-if="isShowAddDialog === true"
v-model:isShowAddDialog="isShowAddDialog"
:chapterName="''"
:chapterID="''"
:course_id="'0'"
:btnInfo="{ btn_name: '课程资料', resource_type: '4' }"
@create="handleAdd"
/>
</div>
</template>
<style>
.node_type {
background: #bf9d6b;
border-radius: 20px;
line-height: 1;
font-size: 12px;
font-weight: 400;
color: #ffffff;
text-align: center;
padding: 4px 8px;
margin-right: 14px;
}
</style>
......@@ -21,7 +21,6 @@ const props = defineProps({
type: String,
required: true
},
chapterName: {
type: String,
required: true
......@@ -37,7 +36,7 @@ const props = defineProps({
})
interface Emits {
(e: 'update:isShowAddDialog', isShowVideoDialog: boolean): void
(e: 'create'): void
(e: 'create', val: any): void
}
// 筛选下拉选择tree 视频分类
let { list: selectTree }: any = useGetCategoryList()
......@@ -65,12 +64,18 @@ const listOptions = computed(() => {
return {
remote: {
httpRequest: getHttpRequest,
beforeRequest(params: any) {
if (params.course_id === '0') {
params.course_id === ''
}
return params
},
callback(data: any) {
data.list.forEach((item: any) => (item.check_status = false))
tableData = data
return { list: data.list, total: data.total }
},
params: { tab: tabValue, status: '1', authorized: '', name: '', course_id: props.course_id }
params: { tab: tabValue, status: '1', authorized: '', name: '', course_id: props.course_id || '' }
},
filters: [
{ prop: 'classification', label: '类别:', slots: 'filter-type' },
......@@ -90,17 +95,23 @@ const handleCancel = () => {
}
// 保存 添加
const handleAdd = (val: any) => {
const params: any = {
name: val.name,
course_id: props.course_id,
resource_type: props.btnInfo.resource_type,
parent_id: props.chapterID,
resource_id: val.id
}
createCharacter(params).then(() => {
console.log(props.course_id, 'props.course_id')
if (props.course_id === '0') {
emit('update:isShowAddDialog', false)
emit('create')
})
emit('create', val)
} else {
const params: any = {
name: val.name,
course_id: props.course_id,
resource_type: props.btnInfo.resource_type,
parent_id: props.chapterID,
resource_id: val.id
}
createCharacter(params).then(() => {
emit('update:isShowAddDialog', false)
emit('create', val)
})
}
}
if (props.btnInfo.resource_type === '2') {
path.value = '/resource/video/view'
......
......@@ -8,17 +8,24 @@ import VEditor from '@/components/tinymce/Index.vue'
import AddCourseCover from '../components/stepOneComponents/AddCourseCover.vue'
// 添加讲师
import AddLecturer from '../components/stepOneComponents/AddLecturer.vue'
// 添加助教
import AddAssistant from '../components/stepOneComponents/AddAssistant.vue'
// 添加试卷
import AddExam from '../components/stepOneComponents/AddExam.vue'
// 添加直播
import AddLive from '../components/stepOneComponents/AddLive.vue'
// 添加课程资料
import AddCourseData from '../components/stepOneComponents/AddCourseData.vue'
import { ElMessage } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
const store = useMapStore()
const route = useRoute()
const router = useRouter()
const id = route.query.id as string
const id: any = route.query.id as string
const majorList: any = ref([])
const allMajorList: any = ref([])
......@@ -59,13 +66,15 @@ const form = reactive<Record<string, any>>({
source: '2',
cover: 'https://webapp-pub.oss-cn-beijing.aliyuncs.com/center_resource/course-cover.png',
lecturer_id: '',
teacher_id: '',
represent: '',
essay: '',
previous_preparation: '',
target: '',
exam_id: '',
live_id: '',
specialty_id: []
specialty_id: [],
information_id: ''
})
// 表单验证
......@@ -97,19 +106,24 @@ const changeExam = (data: any) => {
})
.toString()
}
// 选择资料
// 考试数据回显
const examList: any = ref([])
const information: any = ref([])
// 获取详情
let loading = $ref<boolean>(false)
function fetchDetail() {
loading = true
getCourseDetails({ id }).then((res: any) => {
console.log(res.data)
Object.assign(form, res.data)
examList.value = res.data.examinations
information.value = res.data.information
form.exam_id = res.data.examinations.map((item: any) => item.id).toString()
form.specialty_id = res.data.specialty.map((item: any) => item.id)
form.teacher_id = res.data.teachers.map((item: any) => item.id)
loading = false
})
}
......@@ -118,6 +132,7 @@ onMounted(() => {
})
watchEffect(() => {
form.teacher_id = setDefaultData(form.teachers)
form.lecturer_id = setDefaultData(form.lecturers)
form.live_id = setDefaultData(form.meetings)
})
......@@ -146,7 +161,6 @@ function handleSubmit() {
// 创建课程
function handleCreate() {
form.specialty_id = form.specialty_id.toString()
createCourse(form).then((res: any) => {
if (res.code === 0) {
// 操作第二部
......@@ -180,6 +194,11 @@ getMajorList({ name: '', 'per-page': '100' }).then((res: any) => {
}
})
})
const handleInformation = (val: any) => {
console.log(val)
form.information_id = val.map((item: any) => item.id).toString()
}
</script>
<template>
......@@ -241,6 +260,10 @@ getMajorList({ name: '', 'per-page': '100' }).then((res: any) => {
label-suffix=":"
style="width: 100%; margin-top: 30px"
>
<el-form-item label="课程助教" prop="teacher_id">
<!-- 添加助教 -->
<AddAssistant v-model="form.teachers" style="width: 100%"></AddAssistant>
</el-form-item>
<el-form-item label="课程讲师" prop="lecturer_id">
<!-- 添加讲师 -->
<AddLecturer v-model="form.lecturers" style="width: 100%"></AddLecturer>
......@@ -265,6 +288,16 @@ getMajorList({ name: '', 'per-page': '100' }).then((res: any) => {
<!-- 添加直播 -->
<AddLive v-model="form.meetings" style="width: 100%"></AddLive>
</el-form-item>
<el-form-item label="课程资料" prop="information_id">
<!-- 添加课程资料 -->
<AddCourseData
v-model="form.information_id"
:data="information"
style="width: 100%"
:id="id"
@information="handleInformation"
></AddCourseData>
</el-form-item>
</el-form>
</div>
<div class="btn-box" style="display: flex; justify-content: center">
......
......@@ -289,19 +289,21 @@ const handleChangeStatus = (node: any, data: any) => {
course_id: id,
resource_type: node.data.resource_type,
name: node.label,
resource_id: node.key,
resource_id: node.data.resource_id,
can_download: node.can_download
}
createCharacter(params).then(() => {
ElMessage.success('设置下载控制成功')
})
} else {
console.log(node, data)
const params: any = {
course_id: id,
id: '',
id: data.id,
name: node.label,
resource_id: node.key,
can_download: node.can_download
resource_id: node.data.resource_id,
can_download: node.data.can_download
}
editCharacter(params).then(() => {
ElMessage.success('设置下载控制成功')
......@@ -361,39 +363,13 @@ const handleChangeStatus = (node: any, data: any) => {
style="margin-left: 35px"
>下载</el-link
>
<span
v-if="
data.depth === '3' &&
node.data.resource_type !== '2' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '9'
"
>学生下载控制:</span
>
<el-switch
class="btn_edit"
v-if="
data.depth === '3' &&
node.data.resource_type !== '2' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '9'
"
v-model="node.data.information_can_download"
size="large"
active-value="1"
inactive-value="0"
inline-prompt
style="--el-switch-on-color: #aa1941"
@change="handleChangeStatus(node, data)"
></el-switch>
<el-link class="btn_edit" v-if="data.depth !== '3'" @click="handleEdit(node)" style="margin-left: 35px"
>编辑</el-link
>
<el-link type="info" @click="handleDel(node)" style="margin-left: 25px">删除</el-link></span
>
<span>
<el-button
class="btn_operate"
......@@ -418,6 +394,34 @@ const handleChangeStatus = (node: any, data: any) => {
{{ item.btn_name }}
</el-button>
</template>
<template
v-if="
data.depth === '3' &&
node.data.resource_type !== '2' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '9'
"
>
<span class="btn_operate">学生下载控制:</span>
<el-switch
class="btn_edit"
v-if="
data.depth === '3' &&
node.data.resource_type !== '2' &&
node.data.resource_type !== '6' &&
node.data.resource_type !== '3' &&
node.data.resource_type !== '9'
"
v-model="node.data.can_download"
size="large"
active-value="1"
inactive-value="0"
inline-prompt
style="--el-switch-on-color: #aa1941"
@change="handleChangeStatus(node, data)"
></el-switch>
</template>
</span>
</span>
</template>
......@@ -529,6 +533,10 @@ const handleChangeStatus = (node: any, data: any) => {
border-radius: 16px;
margin: 3px;
}
.btn_control {
font-weight: 400;
color: #b2833d;
}
.btn_edit {
color: #b2833d;
margin-right: 10px;
......
......@@ -160,6 +160,19 @@ watch(
}
)
const changeDepartment = () => {
departmentList.value.map((i: any) => {
const find = authorizeCheck.value.find((item: any) => item === i.id)
if (!find) {
i.auth_type = ''
i.auth_semester_id = ''
i.auth_start_time = ''
i.auth_end_time = ''
}
return i
})
}
// 复制
const copyCourse = () => {
courseCopy({ id: id }).then((res: any) => {
......@@ -170,7 +183,6 @@ const copyCourse = () => {
})
}
</script>
<template>
<div class="tool-btn-box" v-if="route.query.id" style="margin-bottom: 20px">
<router-link :to="`/course/update-course?id=${route.query.id}`">
......@@ -227,11 +239,11 @@ const copyCourse = () => {
</span>
</template>
</el-dialog>
<el-dialog v-model="dialogVisibleAuthorize" title="项目/学校" width="85vw">
<el-dialog v-model="dialogVisibleAuthorize" title="项目/学校" width="75vw">
<el-checkbox-group v-model="authorizeCheck" style="display: flex; flex-direction: column">
<el-checkbox :label="item.id" v-for="item in departmentList" :key="item.id">
{{ item.name }}
<span v-if="authorizeCheck.filter((it:any)=>it === item.id).length >0">
<div v-for="item in departmentList" :key="item.id">
<el-checkbox :label="item.id" @change="changeDepartment"> {{ item.name }} </el-checkbox>
<span v-if="authorizeCheck.filter((it:any)=>it === item.id).length >0" style="margin-top: 10px">
<el-radio-group v-model="item.auth_type">
<el-radio label="1">长期有效:</el-radio>
<el-radio label="2">学期有效:</el-radio>
......@@ -239,22 +251,17 @@ const copyCourse = () => {
<el-option v-for="(it, id) in item.semesters" :key="id" :label="it.name" :value="it.id"></el-option>
</el-select>
<el-radio label="3">时间范围:</el-radio>
<el-date-picker
v-model="item.auth_start_time"
type="datetime"
style="width: 150px"
value-format="YYYY-MM-DD HH:mm:ss"
/>
~
<el-date-picker v-model="item.auth_start_time" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" />
<span>~</span>
<el-date-picker
v-model="item.auth_end_time"
type="datetime"
style="width: 150px"
value-format="YYYY-MM-DD HH:mm:ss"
style="margin-left: 10px"
/>
</el-radio-group>
</span>
</el-checkbox>
</div>
</el-checkbox-group>
<template #footer>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论