15 changed files with 1915 additions and 958 deletions
-
2work/package.json
-
17work/src/api/AddWorkApi.js
-
20work/src/api/ClassListApi.js
-
12work/src/api/LoginApi.js
-
20work/src/api/UpdateWorkApi.js
-
89work/src/api/index.js
-
48work/src/router/index.js
-
403work/src/views/AddWork.vue
-
366work/src/views/DoHomeworkView.vue
-
258work/src/views/HomeWork.vue
-
145work/src/views/Login.vue
-
535work/src/views/UpdateWork.vue
-
391work/src/views/WorkDetail.vue
-
563work/src/views/WorksShowView.vue
-
2work/vite.config.js
@ -0,0 +1,17 @@ |
|||||
|
import service from "."; |
||||
|
const AddWorkApi={ |
||||
|
|
||||
|
//获取关联文章列表(关键字)
|
||||
|
getArticleList(Name){ |
||||
|
return service.post("/api/homework_manage/get-article-list",{Name}); |
||||
|
}, |
||||
|
//获取关联直播列表
|
||||
|
getLiveList(){ |
||||
|
return service.post("/api/homework_manage/get-live-list"); |
||||
|
}, |
||||
|
//添加作业
|
||||
|
addWork(data){ |
||||
|
return service.post("/api/homework_manage/add-homework",data); |
||||
|
}, |
||||
|
} |
||||
|
export default AddWorkApi; |
@ -0,0 +1,20 @@ |
|||||
|
import service from "."; |
||||
|
const ClassListApi={ |
||||
|
//获取作业列表
|
||||
|
getClassList(PageNo,PageSize){ |
||||
|
return service.post("/api/homework_manage/get-homework-list",{PageNo,PageSize}) |
||||
|
}, |
||||
|
//为了编辑,首先获取单个作业内容
|
||||
|
getClassListOne(Id){ |
||||
|
return service.post("/api/homework_manage/get-homework",{Id}) |
||||
|
}, |
||||
|
//获取作业详情
|
||||
|
getWorkDetail(id,pageNo,pageSize){ |
||||
|
return service.post("/api/homework_manage/getrecordlist",{id,pageNo,pageSize}) |
||||
|
}, |
||||
|
//编辑作业
|
||||
|
editWork(data){ |
||||
|
return service.post("/api/homework_manage/edit-homework",data) |
||||
|
}, |
||||
|
} |
||||
|
export default ClassListApi; |
@ -0,0 +1,12 @@ |
|||||
|
import service from "."; |
||||
|
const LoginApi={ |
||||
|
//登录
|
||||
|
login(username,password){ |
||||
|
return service.post("/api/login",username,password) |
||||
|
}, |
||||
|
//退出登录
|
||||
|
logout(){ |
||||
|
return service.post("/api/logout") |
||||
|
} |
||||
|
} |
||||
|
export default LoginApi; |
@ -0,0 +1,20 @@ |
|||||
|
import service from "."; |
||||
|
const UpdateWorkApi={ |
||||
|
//查询分部
|
||||
|
getdeptinfo(){ |
||||
|
return service.post("/api/homework_manage/getdeptinfo") |
||||
|
}, |
||||
|
//查询分部门店
|
||||
|
getshopinfo(deptId){ |
||||
|
return service.post("/api/homework_manage/getshopinfo",{deptId}) |
||||
|
}, |
||||
|
//查询功能
|
||||
|
getrecordbycondition(data){ |
||||
|
return service.post("/api/homework_manage/getrecordbycondition",data) |
||||
|
}, |
||||
|
//数据导出
|
||||
|
excelexport(data){ |
||||
|
return service.post("/api/homework_manage/export-record",data) |
||||
|
} |
||||
|
} |
||||
|
export default UpdateWorkApi; |
@ -1,30 +1,83 @@ |
|||||
import axios from "axios"; |
|
||||
|
// import axios from "axios";
|
||||
|
|
||||
|
// const service = axios.create({
|
||||
|
// // baseURL: 'http://192.168.8.191:8080',
|
||||
|
// // baseURL: 'http://localhost:8080',
|
||||
|
// baseURL: '/api',
|
||||
|
// });
|
||||
|
// // http://192.168.8.191:8080
|
||||
|
|
||||
|
// //Axios的响应拦截器..
|
||||
|
// service.interceptors.response.use(resp => {
|
||||
|
// return resp.data;
|
||||
|
// }, error => {
|
||||
|
// return Promise.reject(error);
|
||||
|
// });
|
||||
|
// export default service;
|
||||
|
|
||||
|
|
||||
|
import axios from "axios"; |
||||
|
import { useTokenStore } from "../stores/token"; |
||||
const service = axios.create({ |
const service = axios.create({ |
||||
|
// baseURL: 'http://192.168.8.191:8080',
|
||||
|
// baseURL: 'http://localhost:8080',
|
||||
baseURL: '/api', |
baseURL: '/api', |
||||
}); |
}); |
||||
|
|
||||
// 添加请求拦截器
|
|
||||
service.interceptors.request.use( |
|
||||
config => { |
|
||||
// 假设你的token存储在Vuex、Pinia或者本地存储中,这里直接用一个变量代替
|
|
||||
// 请确保在实际应用中从安全的地方获取token
|
|
||||
const token = "9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs"; |
|
||||
if (token) { |
|
||||
config.headers['token'] = ` ${token}`; |
|
||||
} |
|
||||
return config; |
|
||||
}, |
|
||||
error => { |
|
||||
return Promise.reject(error); |
|
||||
|
// Axios的请求拦截器,在这里添加token到请求头
|
||||
|
|
||||
|
axios.interceptors.request.use(config => { |
||||
|
const tokenStore = useTokenStore(); |
||||
|
if (tokenStore.token) { |
||||
|
config.headers.token = tokenStore.token; |
||||
} |
} |
||||
); |
|
||||
|
return config; |
||||
|
}, error => { |
||||
|
return Promise.reject(error); |
||||
|
}); |
||||
|
|
||||
// 添加响应拦截器
|
|
||||
service.interceptors.response.use(resp => { |
|
||||
return resp.data; |
|
||||
|
service.interceptors.request.use(config => { |
||||
|
const tokenStore = useTokenStore(); |
||||
|
if (tokenStore.token) { |
||||
|
// 一般后端会约定一个请求头的字段名来接收token,常见的如 'Authorization',并要求按照一定格式传递,比如 'Bearer <token>',这里按照此格式添加,你需要根据后端实际要求调整
|
||||
|
config.headers.token =tokenStore.token; |
||||
|
} |
||||
|
return config; |
||||
}, error => { |
}, error => { |
||||
return Promise.reject(error); |
return Promise.reject(error); |
||||
}); |
}); |
||||
|
|
||||
|
// // Axios的响应拦截器
|
||||
|
// service.interceptors.response.use(resp => {
|
||||
|
// return resp.data;
|
||||
|
// }, error => {
|
||||
|
// return Promise.reject(error);
|
||||
|
// });
|
||||
|
|
||||
|
//响应拦截器
|
||||
|
service.interceptors.response.use(response => { |
||||
|
return response.data; |
||||
|
}, error =>{ |
||||
|
if(error.code === "500"){ |
||||
|
ElMessage.error("服务器错误!"); |
||||
|
} |
||||
|
const response = error.response; |
||||
|
if(error.response && error.response.status === 403){ |
||||
|
//提示一下权限不足
|
||||
|
ElMessage.warning(response.data.message); |
||||
|
} else if(response && response.code === 401){ |
||||
|
//提示一下未登录
|
||||
|
ElMessage.warning(response.data.message); |
||||
|
//跳转登录页面
|
||||
|
const curURL = router.currentRoute.value.path; |
||||
|
if(curURL.startsWith('/')){ |
||||
|
router.push('/login') |
||||
|
} else{ |
||||
|
router.push('/login'); |
||||
|
} |
||||
|
console.log(); |
||||
|
} |
||||
|
return Promise.reject(error); |
||||
|
}) |
||||
|
|
||||
export default service; |
export default service; |
@ -1,21 +1,53 @@ |
|||||
import { createRouter, createWebHistory } from 'vue-router'; |
import { createRouter, createWebHistory } from 'vue-router'; |
||||
import WorksShowView from '../views/WorksShowView.vue'; |
|
||||
import DoHomeworkView from "@/views/DoHomeworkView.vue"; |
|
||||
|
import HomeWork from '../views/HomeWork.vue'; |
||||
|
import Login from '../views/Login.vue'; |
||||
|
import AddWork from '../views/AddWork.vue'; |
||||
|
import WorkDetail from '../views/WorkDetail.vue'; |
||||
|
import UpdateWork from '../views/UpdateWork.vue'; |
||||
|
import { useTokenStore } from '../stores/token'; |
||||
|
|
||||
const router = createRouter({ |
const router = createRouter({ |
||||
history: createWebHistory(), |
history: createWebHistory(), |
||||
routes: [ |
routes: [ |
||||
{ |
{ |
||||
path: '/show', |
|
||||
name: 'workshow', |
|
||||
component: WorksShowView |
|
||||
|
path: '/', |
||||
|
name: 'login', |
||||
|
component: Login, |
||||
}, |
}, |
||||
{ |
{ |
||||
path:'/doWork/:id?/:sub?', |
|
||||
name:'doWork', |
|
||||
component: DoHomeworkView |
|
||||
|
path: '/list', |
||||
|
name: 'homeWorklist', |
||||
|
component: HomeWork, |
||||
|
}, |
||||
|
{ |
||||
|
path:'/addwork', |
||||
|
name:'addwork', |
||||
|
component: AddWork |
||||
|
}, |
||||
|
{ |
||||
|
path:'/workdetail/:id', |
||||
|
name:'workdetail', |
||||
|
component: WorkDetail |
||||
|
}, |
||||
|
{ |
||||
|
path:'/updatework/:id', |
||||
|
name:'updatework', |
||||
|
component: UpdateWork |
||||
} |
} |
||||
] |
] |
||||
}) |
}) |
||||
|
|
||||
|
// 添加全局前置守卫
|
||||
|
router.beforeEach((to, from, next) => { |
||||
|
const tokenStore = useTokenStore(); |
||||
|
const token = tokenStore.token; |
||||
|
if (!token && to.name !== 'login') { |
||||
|
// 如果没有token且要访问的不是登录页面,就跳转到登录页面
|
||||
|
next({ name: 'login' }); |
||||
|
} else { |
||||
|
// 有token或者要访问的是登录页面,正常放行
|
||||
|
next(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
export default router |
export default router |
@ -0,0 +1,403 @@ |
|||||
|
<template> |
||||
|
<div class="common-layout"> |
||||
|
<el-container> |
||||
|
<el-header class="header"> |
||||
|
<el-text class="header-text">抢点班作业后台管理</el-text> |
||||
|
<el-button class="header-button" type="primary" text style="float: right;" @click="logout">退出登录</el-button> |
||||
|
</el-header> |
||||
|
<el-main class="main"> |
||||
|
<div class="main-title"> |
||||
|
<div class="main-title-text" style="float: left;"> |
||||
|
新建作业 |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button class="main-button" @click="back">返回上一页</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="main-back"> |
||||
|
<el-form :model="form" label-width="auto" style="max-width: 700px" size="large"> |
||||
|
<el-form-item label="作业名称"> |
||||
|
<el-input v-model="form.Name" placeholder="请输入"></el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="提交时间" style="width: 70%"> |
||||
|
<el-date-picker v-model="form.picker" type="daterange" range-separator="至" start-placeholder="开始日期" |
||||
|
end-placeholder="结束日期" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="作业归属"> |
||||
|
<el-select v-model="form.ClubType" placeholder="请选择" style="width: 100%"> |
||||
|
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="关联文章"> |
||||
|
<el-autocomplete v-model="articleTitle" :fetch-suggestions="queryArticleList" placeholder="请输入" |
||||
|
@select="handleSelectArticle" clearable @change="handleArticleChange"/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="关联直播"> |
||||
|
<el-select v-model="form.LiveId" placeholder="请选择" style="width: 100%" clearable @change="handleLiveChange"> |
||||
|
<el-option v-for="item in live" :key="item.id" :label="item.name" :value="item.id" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="选择类型"> |
||||
|
<div> |
||||
|
<el-button type="primary" @click="addSingleChoice">添加单选</el-button> |
||||
|
<el-button type="primary" @click="addMultipleChoice">添加多选</el-button> |
||||
|
<el-button type="primary" @click="addBlank">添加单选填空</el-button> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
<div class="question-container" v-for="(question, index) in questions" :key="index" |
||||
|
:class="{ 'bg-change': isHovered[index] }" @mouseenter="handleMouseEnter(index)" |
||||
|
@mouseleave="handleMouseLeave(index)"> |
||||
|
<div class="question-title"> |
||||
|
{{ questionPrefix(index) }} {{ getQuestionTypeText(question.type) }} |
||||
|
</div> |
||||
|
<div style="width: 600px;"> |
||||
|
<el-input v-model="question.description" /> |
||||
|
</div> |
||||
|
<div class="add" v-if="question.type !== 'blank'"> |
||||
|
<div class="question-option"> |
||||
|
<span>设置选项:</span> |
||||
|
<el-button type="primary" text @click="addOption(index)">添加</el-button> |
||||
|
</div> |
||||
|
<div v-for="(option, optionIndex) in question.content" :key="optionIndex"> |
||||
|
<div class="select" style="display: flex;"> |
||||
|
<div class="selection-item" style="display: flex;"> |
||||
|
<div style="width: 550px;"> |
||||
|
<el-input v-model="question.content[optionIndex].text" /> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button type="primary" text @click="removeOption(index, optionIndex)">删除</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="delete" style="margin-left: 50px;"> |
||||
|
<el-button type="info" plain @click="removeQuestion(index)">删除</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="submit"> |
||||
|
<el-button type="primary" :disabled="!form.Name||!form.picker" @click="onSubmit">确认</el-button> |
||||
|
</div> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
</el-main> |
||||
|
</el-container> |
||||
|
</div> |
||||
|
|
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts" setup> |
||||
|
import { ref, onMounted, computed } from 'vue' |
||||
|
import AddWorkApi from '../api/AddWorkApi'; |
||||
|
import _ from 'lodash'; |
||||
|
import dayjs from 'dayjs'; |
||||
|
import { ElMessage } from 'element-plus' |
||||
|
import LoginApi from '../api/LoginApi'; |
||||
|
import axios from 'axios'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import { useTokenStore } from '../stores/token'; |
||||
|
import { useUserStore } from '../stores/user'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const options = ref([ |
||||
|
{ id: 1, name: '牧民俱乐部' }, |
||||
|
{ id: 2, name: '博古论坛' }, |
||||
|
{ id: 3, name: '神枪手俱乐部' }, |
||||
|
{ id: 4, name: '环球俱乐部' }, |
||||
|
{ id: 5, name: '价值投资' }, |
||||
|
{ id: 6, name: '波段行情' }, |
||||
|
{ id: 7, name: '抄底卖顶' }, |
||||
|
{ id: 8, name: '资金及仓位管理' }, |
||||
|
{ id: 9, name: '财富的游戏' }, |
||||
|
|
||||
|
]); |
||||
|
|
||||
|
// do not use same name with ref |
||||
|
const form = ref({ |
||||
|
Name: '', |
||||
|
ClubType: '', |
||||
|
ArticleId: '', |
||||
|
LiveId: '', |
||||
|
picker: [], |
||||
|
StartDate: '', |
||||
|
EndDate: '', |
||||
|
Questions: [] |
||||
|
}); |
||||
|
const articleTitle = ref(''); |
||||
|
// 问题列表数据 |
||||
|
const questions = ref([]); |
||||
|
const onSubmit = () => { |
||||
|
// 从picker中获取日期数据并进行格式转换 |
||||
|
if (form.value.picker && form.value.picker.length === 2) { |
||||
|
const startDate = dayjs(form.value.picker[0]).format('YYYY-MM-DD HH:mm:00'); |
||||
|
const endDate = dayjs(form.value.picker[1]).format('YYYY-MM-DD HH:mm:00'); |
||||
|
form.value.StartDate = startDate; |
||||
|
form.value.EndDate = endDate; |
||||
|
} |
||||
|
form.value.Questions = questions.value; |
||||
|
AddWorkApi.addWork(form.value) |
||||
|
console.log(questions.value+'--------------') |
||||
|
ElMessage.success('添加成功'); |
||||
|
router.push('/list') |
||||
|
} |
||||
|
const back = () => { |
||||
|
window.history.back() |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// 存储根据文章输入内容查询到的关联文章结果列表 |
||||
|
const articleSearchResults = ref([]); |
||||
|
// 根据文章输入内容查询关联文章的函数 |
||||
|
const queryArticleList = async (queryString: string) => { |
||||
|
if (form.value.LiveId) { |
||||
|
ElMessage.warning('您已关联直播,暂无法关联文章'); |
||||
|
articleTitle.value = ''; // 清空文章标题输入框 |
||||
|
form.value.LiveId = ''; |
||||
|
return []; |
||||
|
} |
||||
|
try { |
||||
|
const response = await AddWorkApi.getArticleList(queryString); |
||||
|
const formattedResults = response.data.map(article => ({ |
||||
|
value: article.title, |
||||
|
label: article.id |
||||
|
})); |
||||
|
articleSearchResults.value = formattedResults; |
||||
|
return formattedResults; |
||||
|
} catch (error) { |
||||
|
console.error('查询关联文章失败', error); |
||||
|
return []; |
||||
|
} |
||||
|
}; |
||||
|
// 处理选择文章的函数 |
||||
|
const handleSelectArticle = (article: { label: string }) => { |
||||
|
// 这里可以根据业务需求,比如将选中的文章id(article.label)传递给其他地方使用等 |
||||
|
console.log('选中的文章id', article.label); |
||||
|
form.value.ArticleId = article.label; // 将选中文章的id赋值给对应表单字段,用于传递给后端 |
||||
|
const selectedArticle = articleSearchResults.value.find(a => a.label === article.label); |
||||
|
if (selectedArticle) { |
||||
|
articleTitle.value = selectedArticle.value; // 更新显示的文章题目 |
||||
|
} |
||||
|
}; |
||||
|
const handleLiveChange = () => { |
||||
|
if (form.value.ArticleId) { |
||||
|
ElMessage.warning('您已关联文章,暂无法关联直播'); |
||||
|
form.value.LiveId = ''; // 清空关联直播选择框的值 |
||||
|
form.value.ArticleId = ''; |
||||
|
articleTitle.value = ''; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
//获取直播列表 |
||||
|
const live = ref([]); |
||||
|
function getLive() { |
||||
|
AddWorkApi.getLiveList() |
||||
|
.then(res => { |
||||
|
live.value = res.data; |
||||
|
console.log(live.value); |
||||
|
}) |
||||
|
.catch(error => { |
||||
|
console.error('获取直播列表失败', error) |
||||
|
}) |
||||
|
} |
||||
|
getLive(); |
||||
|
|
||||
|
// 根据类型获取对应的题目类型文本显示 |
||||
|
const getQuestionTypeText = (type) => { |
||||
|
switch (type) { |
||||
|
case 1: |
||||
|
return '作业题目(单选)'; |
||||
|
case 2: |
||||
|
return '作业题目(多选)'; |
||||
|
case 3: |
||||
|
return '作业题目(简答题)'; |
||||
|
default: |
||||
|
return '未知类型题目'; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const addSingleChoice = () => { |
||||
|
questions.value.push({ |
||||
|
type: 1, // 假设1代表单选,和后端格式对应起来 |
||||
|
description: '', |
||||
|
content: [{ "id": "", "text": "" },{ "id": "", "text": "" }] |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const addMultipleChoice = () => { |
||||
|
questions.value.push({ |
||||
|
type: 2, // 假设2代表多选,和后端格式对应起来 |
||||
|
description: '', |
||||
|
content: [{ "id": "", "text": "" },{ "id": "", "text": "" }] |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const addBlank = () => { |
||||
|
questions.value.push({ |
||||
|
type: 3, // 假设3代表简答题,和后端格式对应起来 |
||||
|
description: '', |
||||
|
content: [{ "id": "", "text": "" }] |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// const addOption = (questionIndex) => { |
||||
|
// const currentQuestion = questions.value[questionIndex]; |
||||
|
// const currentContent = JSON.parse(currentQuestion.content); |
||||
|
// currentContent.push({ "id": "", "text": "" }); |
||||
|
// currentQuestion.content = JSON.stringify(currentContent); |
||||
|
// }; |
||||
|
|
||||
|
// const removeOption = (questionIndex, optionIndex) => { |
||||
|
// const currentQuestion = questions.value[questionIndex]; |
||||
|
// const currentContent = JSON.parse(currentQuestion.content); |
||||
|
// currentContent.splice(optionIndex, 1); |
||||
|
// currentQuestion.content = JSON.stringify(currentContent); |
||||
|
// }; |
||||
|
const addOption = (questionIndex) => { |
||||
|
const currentQuestion = questions.value[questionIndex]; |
||||
|
// 如果当前题目没有content属性,则初始化一个空数组 |
||||
|
if (!currentQuestion.content) { |
||||
|
currentQuestion.content = []; |
||||
|
} |
||||
|
currentQuestion.content.push({ id: "", text: "" }); |
||||
|
}; |
||||
|
const removeOption = (questionIndex, optionIndex) => { |
||||
|
const currentQuestion = questions.value[questionIndex]; |
||||
|
currentQuestion.content.splice(optionIndex, 1); |
||||
|
}; |
||||
|
const removeQuestion = (questionIndex) => { |
||||
|
questions.value.splice(questionIndex, 1); |
||||
|
}; |
||||
|
|
||||
|
// 计算属性,用于生成序号前缀 |
||||
|
const questionPrefix = computed(() => { |
||||
|
return (index) => { |
||||
|
return `${index + 1}、`; |
||||
|
}; |
||||
|
}) |
||||
|
|
||||
|
// 用于存储每个问题标题是否被鼠标悬停的状态,初始化为false |
||||
|
const isHovered = ref(Array(questions.value.length).fill(false)); |
||||
|
const handleMouseEnter = (index) => { |
||||
|
isHovered.value[index] = true; |
||||
|
}; |
||||
|
|
||||
|
const handleMouseLeave = (index) => { |
||||
|
isHovered.value[index] = false; |
||||
|
}; |
||||
|
|
||||
|
// 在组件挂载后初始化 `isHovered` 数组长度与 `questions` 数组长度一致 |
||||
|
onMounted(() => { |
||||
|
isHovered.value = Array(questions.value.length).fill(false); |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
//退出 |
||||
|
function logout(){ |
||||
|
//清除登录信息 |
||||
|
const tokenStore = useTokenStore(); |
||||
|
const userStore = useUserStore(); |
||||
|
tokenStore.clear(); |
||||
|
userStore.clear(); |
||||
|
LoginApi.logout().then(res => { |
||||
|
console.log(res) |
||||
|
}) |
||||
|
router.push('/') |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.submit { |
||||
|
margin: 100px 212px; |
||||
|
} |
||||
|
|
||||
|
.submit .el-button { |
||||
|
padding: 25px 150px; |
||||
|
} |
||||
|
|
||||
|
.question-title { |
||||
|
transition: background-color 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.bg-change { |
||||
|
background-color: rgba(200, 200, 200, 0.3); |
||||
|
} |
||||
|
|
||||
|
.question-title { |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.select { |
||||
|
margin: 10px 0px 0px; |
||||
|
} |
||||
|
|
||||
|
.delete { |
||||
|
position: absolute; |
||||
|
right: 10px; |
||||
|
bottom: 0px; |
||||
|
} |
||||
|
|
||||
|
.add { |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.question-container { |
||||
|
margin: 20px 0; |
||||
|
padding: 10px 20px; |
||||
|
width: 750px; |
||||
|
border-bottom: 1px solid #e5e5e5; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
height: 100px; |
||||
|
line-height: 100px; |
||||
|
padding: 0 80px; |
||||
|
} |
||||
|
|
||||
|
.header-text { |
||||
|
font-size: 22px; |
||||
|
font-weight: 500; |
||||
|
color: black; |
||||
|
float: left; |
||||
|
} |
||||
|
|
||||
|
.header-button { |
||||
|
margin-top: 30px; |
||||
|
} |
||||
|
|
||||
|
.main { |
||||
|
padding: 30px 212px; |
||||
|
background-color: #F8F8F8; |
||||
|
} |
||||
|
|
||||
|
.main-title { |
||||
|
font-size: 16px; |
||||
|
background-color: white; |
||||
|
font-weight: bold; |
||||
|
height: 60px; |
||||
|
border-bottom: 2px solid #ececec; |
||||
|
padding: 0 15px; |
||||
|
line-height: 52px; |
||||
|
} |
||||
|
|
||||
|
.main-button { |
||||
|
margin: 10px 15px 0 0; |
||||
|
padding: 12px 20px; |
||||
|
height: 40px; |
||||
|
float: right; |
||||
|
} |
||||
|
|
||||
|
.el-form { |
||||
|
padding: 30px 78.5px; |
||||
|
margin: auto; |
||||
|
} |
||||
|
|
||||
|
.el-form-item { |
||||
|
--font-size: 16px; |
||||
|
margin: 0 0 25px; |
||||
|
} |
||||
|
|
||||
|
.main-back { |
||||
|
background-color: white; |
||||
|
} |
||||
|
</style> |
@ -1,366 +0,0 @@ |
|||||
<template> |
|
||||
<div class="container"> |
|
||||
<div class="main"> |
|
||||
<div class="content"> |
|
||||
<div class="title"> |
|
||||
{{ questionList[0].name }} |
|
||||
</div> |
|
||||
<template v-for="(question, questionIndex) in questionList" :key="questionIndex"> |
|
||||
<!-- 单选 --> |
|
||||
<template v-if="question.type == 1"> |
|
||||
<div class="question"> |
|
||||
{{ questionIndex + 1 }}. {{ question.description }}(单选) |
|
||||
</div> |
|
||||
<div v-for="(answer, index) in question.content" :key="index" class="answer"> |
|
||||
<div class="selected"> |
|
||||
<input :id="`select-${questionIndex}-${index}`" :name="`radio-group-${questionIndex}`" type="radio" |
|
||||
v-model="selectedAnswers[questionIndex]" |
|
||||
:value="answer.text" |
|
||||
> |
|
||||
<label :for="`select-${questionIndex}-${index}`">{{ answer.text }}</label> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 多选 --> |
|
||||
<template v-if="question.type == 2"> |
|
||||
<div class="question"> |
|
||||
{{ questionIndex + 1 }}. {{ question.description }}(多选) |
|
||||
</div> |
|
||||
<div v-for="(answer, index) in question.content" :key="index" class="answer"> |
|
||||
<div class="selected"> |
|
||||
<input :id="`checkbox-${questionIndex}-${index}`" name="checkbox" type="checkbox" |
|
||||
v-model="selectedAnswers[questionIndex]" |
|
||||
:value="answer.text" |
|
||||
> |
|
||||
<label :for="`checkbox-${questionIndex}-${index}`">{{ answer.text }}</label> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 简答题 --> |
|
||||
<template v-if="question.type == 3"> |
|
||||
<div class="Short-answers"> |
|
||||
<div class="question"> |
|
||||
{{ questionIndex + 1 }}. {{ question.description }} |
|
||||
</div> |
|
||||
<el-input |
|
||||
v-model="editorTitles[questionIndex]" |
|
||||
style="width: 100%; padding: 3.5%" |
|
||||
size="large" |
|
||||
placeholder="请输入标题(5-100字符)" |
|
||||
maxlength="100" |
|
||||
minlength="5" |
|
||||
show-word-limit |
|
||||
/> |
|
||||
<div class="editor"> |
|
||||
<div style="border: 1px solid #ccc"> |
|
||||
<Toolbar |
|
||||
style="border-bottom: 1px solid #ccc" |
|
||||
:editor="editorRefs[questionIndex]" |
|
||||
:defaultConfig="toolbarConfig" |
|
||||
:mode="mode" |
|
||||
/> |
|
||||
<Editor |
|
||||
style="height: 500px; overflow-y: hidden;" |
|
||||
v-model="editorContents[questionIndex]" |
|
||||
:defaultConfig="editorConfig" |
|
||||
:mode="mode" |
|
||||
@onCreated="editor => handleCreated(editor, questionIndex)" |
|
||||
|
|
||||
/> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 提交按钮 --> |
|
||||
<div class="submit"> |
|
||||
<img src="https://d31zlh4on95l9h.cloudfront.net/images/5iujb101000d2foxm6thylaa50qz6lgl.png" @click="submit"> |
|
||||
</div> |
|
||||
<!-- 提交次数 --> |
|
||||
<div class="submit-times"> |
|
||||
<span>您已提交{{sub}}次,每个作业可以提交3次</span> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
|
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { onMounted, ref, shallowRef } from 'vue'; |
|
||||
import homeworkApi from "@/api/HomeworkApi.js"; |
|
||||
import { ElMessage } from "element-plus"; |
|
||||
import '@wangeditor/editor/dist/css/style.css' // 引入 css |
|
||||
import { onBeforeUnmount } from 'vue' |
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue' |
|
||||
import {useRoute, useRouter} from "vue-router"; |
|
||||
|
|
||||
const router = useRouter(); |
|
||||
const route = useRoute(); |
|
||||
let groupId = route.params.id; |
|
||||
let sub = route.params.sub; |
|
||||
// 编辑器实例,必须用 shallowRef |
|
||||
const editorRefs = ref([]); |
|
||||
|
|
||||
// 内容 HTML |
|
||||
const editorContents = ref([]); |
|
||||
const editorTitles = ref([]); |
|
||||
|
|
||||
// 模拟 ajax 异步获取内容 |
|
||||
onMounted(() => { |
|
||||
setTimeout(() => { |
|
||||
editorContents.value = editorContents.value.map(() => ''); |
|
||||
}, 1500) |
|
||||
}) |
|
||||
|
|
||||
const toolbarConfig = { |
|
||||
excludeKeys: [ |
|
||||
'justify', |
|
||||
'table', |
|
||||
'codeBlock', |
|
||||
'divider', |
|
||||
'undo', |
|
||||
'redo', |
|
||||
'insertImage', // 去掉插入图片 |
|
||||
'insertLink', // 去掉插入链接 |
|
||||
'insertTable', // 去掉插入表格 |
|
||||
'video', |
|
||||
'group-more-style', |
|
||||
'group-image', |
|
||||
'group-video', |
|
||||
'fullScreen', |
|
||||
'todo' |
|
||||
], |
|
||||
insertKeys: { |
|
||||
index: 0, |
|
||||
keys: ['bold', 'italic'] |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
const editorConfig = { |
|
||||
placeholder: '请输入内容...', |
|
||||
toolbarKeys: toolbarConfig.toolbarKeys |
|
||||
} |
|
||||
|
|
||||
// 组件销毁时,也及时销毁编辑器 |
|
||||
onBeforeUnmount(() => { |
|
||||
editorRefs.value.forEach(editor => { |
|
||||
if (editor == null) return; |
|
||||
editor.destroy(); |
|
||||
}); |
|
||||
}) |
|
||||
|
|
||||
const handleCreated = (editor, questionIndex) => { |
|
||||
editorRefs.value[questionIndex] = editor; // 记录 editor 实例 |
|
||||
editor.config.toolbarConfig = toolbarConfig; // 确保配置正确应用 |
|
||||
} |
|
||||
|
|
||||
const questionList = ref([]); |
|
||||
|
|
||||
function getQuestionList() { |
|
||||
console.log("ljghasjkhdjksahjkhsajkhjkasd",groupId); |
|
||||
homeworkApi.getHomeworkQuestion(groupId).then(resp => { |
|
||||
if (resp.code == 200) { |
|
||||
questionList.value = resp.data; |
|
||||
for (let i = 0; i < questionList.value.length; i++) { |
|
||||
questionList.value[i].content = JSON.parse(questionList.value[i].content); |
|
||||
// 初始化 editorTitles 和 editorContents |
|
||||
editorTitles.value.push(''); |
|
||||
editorContents.value.push(''); |
|
||||
// 初始化 selectedAnswers 为数组 |
|
||||
selectedAnswers.value.push([]); |
|
||||
} |
|
||||
} else { |
|
||||
ElMessage.error("未知错误,请联系管理员"); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
getQuestionList(); |
|
||||
|
|
||||
// 提交作业 |
|
||||
const homework = ref([]); |
|
||||
|
|
||||
const selectedAnswers = ref([]); |
|
||||
questionList.value.forEach(() => { |
|
||||
selectedAnswers.value.push([]); |
|
||||
}); |
|
||||
|
|
||||
// 上一个页面传递的参数 groupId |
|
||||
function submit() { |
|
||||
homework.value = []; |
|
||||
for (let i = 0; i < questionList.value.length; i++) { |
|
||||
if (questionList.value[i].type == 1 || questionList.value[i].type == 2) { |
|
||||
homework.value.push({ |
|
||||
"id": questionList.value[i].id, |
|
||||
"answer": selectedAnswers.value[i], |
|
||||
"type": questionList.value[i].type |
|
||||
}); |
|
||||
} else if (questionList.value[i].type == 3) { |
|
||||
const editor = editorRefs.value[i]; |
|
||||
const plainText = editor ? editor.getText() : ''; |
|
||||
homework.value.push({ |
|
||||
"id": questionList.value[i].id, |
|
||||
"answer": [editorTitles.value[i], plainText], |
|
||||
"type": questionList.value[i].type |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
let groupId = route.params.id; |
|
||||
let sub = route.params.sub; |
|
||||
if (sub <=2){ |
|
||||
homeworkApi.submitHomework(homework.value, groupId).then(resp => { |
|
||||
if (resp.code == 200) { |
|
||||
ElMessage.success("提交成功"); |
|
||||
homework.value = []; |
|
||||
router.push("/show"); |
|
||||
} else { |
|
||||
ElMessage.error("未知错误,请联系管理员"); |
|
||||
} |
|
||||
}); |
|
||||
}else { |
|
||||
ElMessage.error("提交失败您,已提交3次,每个作业可以提交3次"); |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.container { |
|
||||
text-align: center; |
|
||||
margin-left: auto; |
|
||||
margin-right: auto; |
|
||||
width: 34.375rem; |
|
||||
height: 114.399375rem; |
|
||||
} |
|
||||
|
|
||||
.main { |
|
||||
background-image: url("https://lfjf.rzfwq.com/jtzy/Product/pcjingwang/images/20230823/qiangdianbanHomeWorkBg.png"); |
|
||||
background-size: contain; |
|
||||
background-position: center 0; |
|
||||
background-repeat: no-repeat; |
|
||||
margin: 0; |
|
||||
width: 100%; |
|
||||
height: 1830px; |
|
||||
text-align: center; |
|
||||
position: relative; |
|
||||
} |
|
||||
|
|
||||
.content { |
|
||||
position: absolute; |
|
||||
width: 93%; |
|
||||
height: 80%; |
|
||||
overflow-y: scroll; |
|
||||
/* 居中显示 */ |
|
||||
left: 50%; |
|
||||
transform: translate(-50%, 0); |
|
||||
top: 12.5%; |
|
||||
text-align: left; |
|
||||
} |
|
||||
|
|
||||
/* 滚动条样式 */ |
|
||||
.content::-webkit-scrollbar { |
|
||||
width: 3px; |
|
||||
} |
|
||||
|
|
||||
.content::-webkit-scrollbar-track { |
|
||||
background: #f1f1f1; /* 滚动条轨道的背景色 */ |
|
||||
} |
|
||||
|
|
||||
.content::-webkit-scrollbar-thumb { |
|
||||
background: #d9d9d9; /* 滚动条滑块的颜色 */ |
|
||||
border-radius: 6px; /* 滑块的圆角 */ |
|
||||
} |
|
||||
|
|
||||
.title { |
|
||||
font-size: 1.65rem; |
|
||||
font-weight: 600; |
|
||||
/* 居中显示 */ |
|
||||
text-align: center; |
|
||||
/*字体颜色*/ |
|
||||
color: #3f27b1; |
|
||||
} |
|
||||
|
|
||||
.question { |
|
||||
padding-top: 10%; |
|
||||
padding-left: 4%; |
|
||||
font-size: 1.35rem; |
|
||||
font-weight: 500; |
|
||||
} |
|
||||
|
|
||||
.answer { |
|
||||
padding-top: 2.5%; |
|
||||
padding-left: 7%; |
|
||||
font-size: 1.35rem; |
|
||||
} |
|
||||
|
|
||||
.selected { |
|
||||
display: block; |
|
||||
padding: 1% 0 1.2% 0; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
.selected input[name="checkbox"] { |
|
||||
margin-right: 1%; |
|
||||
width: 1.2rem; |
|
||||
height: 1rem; |
|
||||
/* 透明度 */ |
|
||||
opacity: 0.8; |
|
||||
cursor: pointer; /* 鼠标悬停时变成手的形状 */ |
|
||||
} |
|
||||
.selected input[type="radio"]{ |
|
||||
margin-right: 1%; |
|
||||
width: 1.2rem; |
|
||||
height: 1rem; |
|
||||
/* 透明度 */ |
|
||||
opacity: 0.8; |
|
||||
cursor: pointer; /* 鼠标悬停时变成手的形状 */ |
|
||||
} |
|
||||
|
|
||||
/* 单选按钮选中时的样式 */ |
|
||||
.selected input[type="radio"]:checked { |
|
||||
accent-color: blue; /* 设置选中时的颜色为蓝色 */ |
|
||||
} |
|
||||
|
|
||||
/* 多选按钮选中时的样式 */ |
|
||||
.selected input[type="checkbox"]:checked { |
|
||||
accent-color: blue; /* 设置选中时的颜色为蓝色 */ |
|
||||
} |
|
||||
|
|
||||
.selected label { |
|
||||
cursor: pointer; |
|
||||
} |
|
||||
|
|
||||
.editor { |
|
||||
padding-top: 2.5%; |
|
||||
padding-left: 3.5%; |
|
||||
padding-right: 3.5%; |
|
||||
height: 30rem; |
|
||||
} |
|
||||
|
|
||||
.Short-answers { |
|
||||
height: 48rem; |
|
||||
} |
|
||||
|
|
||||
.submit { |
|
||||
display: block; |
|
||||
text-align: center; |
|
||||
} |
|
||||
|
|
||||
.submit img { |
|
||||
padding-top: 2.5%; |
|
||||
padding-left: 3.5%; |
|
||||
padding-right: 3.5%; |
|
||||
cursor: pointer; |
|
||||
width: 67%; |
|
||||
} |
|
||||
|
|
||||
.submit-times { |
|
||||
font-size: 0.8rem; |
|
||||
color: #858585; |
|
||||
text-align: center; |
|
||||
} |
|
||||
</style> |
|
@ -0,0 +1,258 @@ |
|||||
|
<template> |
||||
|
<div class="common-layout"> |
||||
|
<el-container> |
||||
|
<el-header class="header"> |
||||
|
<el-text class="header-text">抢点班作业后台管理</el-text> |
||||
|
<el-button class="header-button" type="primary" text style="float: right;" @click="logout">退出登录</el-button> |
||||
|
</el-header> |
||||
|
<el-main class="main"> |
||||
|
<div class="main-title"> |
||||
|
抢点班作业列表 |
||||
|
</div> |
||||
|
<div class="list"> |
||||
|
<el-button class="main-button" type="primary" style="float: left;" @click="newAssignment">新建作业</el-button> |
||||
|
<el-table :data="assignments" style="width: 100%" :header-cell-style="{ 'text-align': 'center' }" |
||||
|
:cell-style="{ 'text-align': 'center' }"> |
||||
|
<el-table-column label="序号"> |
||||
|
<template #default="scope"> |
||||
|
{{ scope.$index + (PageNo - 1) * PageSize + 1 }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="name" label="作业名称"></el-table-column> |
||||
|
<el-table-column label="内容归属"> |
||||
|
<template v-slot="scope"> |
||||
|
<span v-if="scope.row.clubType == '1'">牧民俱乐部</span> |
||||
|
<span v-else-if="scope.row.clubType == '2'">博古论坛</span> |
||||
|
<span v-else-if="scope.row.clubType == '3'">神枪手俱乐部</span> |
||||
|
<span v-else-if="scope.row.clubType == '4'">环球俱乐部</span> |
||||
|
<span v-else-if="scope.row.clubType == '5'">价值投资</span> |
||||
|
<span v-else-if="scope.row.clubType == '6'">波段行情</span> |
||||
|
<span v-else-if="scope.row.clubType == '7'">抄底卖顶</span> |
||||
|
<span v-else-if="scope.row.clubType == '8'">资金及仓位管理</span> |
||||
|
<span v-else-if="scope.row.clubType == '9'">财富的游戏</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="article" label="关联文章"> |
||||
|
<template #default="{ row }"> |
||||
|
<el-tooltip class="tooltip" v-if="row.article" :content="row.article.title" placement="bottom" |
||||
|
:disabled="row.article.title.length <= 10" effect="light"> |
||||
|
{{ row.article.title.slice(0, 10) || '—' }} |
||||
|
</el-tooltip> |
||||
|
<span v-else>—</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="live" label="关联直播"> |
||||
|
<template #default="{ row }"> |
||||
|
<el-tooltip class="tooltip" v-if="row.live" :content="row.live.name" placement="bottom" |
||||
|
:disabled="row.live.name.length <= 10" effect="light"> |
||||
|
{{ row.live.name.slice(0, 10) || '—' }} |
||||
|
</el-tooltip> |
||||
|
<span v-else>—</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="count" label="填写份数"></el-table-column> |
||||
|
<el-table-column label="提交时间"> |
||||
|
<template v-slot="scope"> |
||||
|
{{ scope.row.startDate.split(' ')[0] }} 至 {{ scope.row.endDate.split(' ')[0] }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="status" label="状态"> |
||||
|
<template #default="{ row }"> |
||||
|
<span v-if="row.status === 0">未上架</span> |
||||
|
<span v-else-if="row.status === 1">发布中</span> |
||||
|
<span v-else-if="row.status === 2">已下架</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="createdAt" label="发布时间"></el-table-column> |
||||
|
<el-table-column label="操作"> |
||||
|
<template #default="scope"> |
||||
|
<el-button type="primary" link @click="viewDetails(scope.row)">查看明细</el-button> |
||||
|
<el-button type="primary" link v-if="scope.row.status != '2'" @click="editAssignment(scope.row)">编辑</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
</div> |
||||
|
<div class="page"> |
||||
|
<el-pagination v-model:current-page="PageNo" v-model:page-size="PageSize" :page-sizes="[20, 50, 100, 200]" |
||||
|
:size="size" :disabled="disabled" :background="background" layout="total,prev,next,sizes,jumper" |
||||
|
:total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> |
||||
|
</div> |
||||
|
</el-main> |
||||
|
</el-container> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, onMounted } from 'vue'; |
||||
|
import { ElMessage } from 'element-plus'; |
||||
|
import ClassListApi from '../api/ClassListApi'; |
||||
|
import axios from 'axios'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import LoginApi from '../api/LoginApi'; |
||||
|
import { useTokenStore } from '../stores/token'; |
||||
|
import { useUserStore } from '../stores/user'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const assignments = ref([]); |
||||
|
|
||||
|
// 初始化页码,这里假设初始页码为1,你可以根据实际需求修改 |
||||
|
const PageNo = ref(1); |
||||
|
// 初始化页面大小,这里假设初始页面大小为10,同样可按需修改 |
||||
|
const PageSize = ref(20); |
||||
|
const size = ref('default'); |
||||
|
const disabled = ref(false); |
||||
|
const background = ref(true); |
||||
|
const total = ref(0); |
||||
|
// 处理页面大小改变的事件函数,将新的页面大小赋值给PageSize变量 |
||||
|
const handleSizeChange = (newPageSize) => { |
||||
|
PageSize.value = newPageSize; |
||||
|
getAssignments(PageNo.value, PageSize.value); |
||||
|
}; |
||||
|
|
||||
|
// 处理当前页码改变的事件函数,将新的页码赋值给PageNo变量 |
||||
|
const handleCurrentChange = (newPageNo) => { |
||||
|
PageNo.value = newPageNo; |
||||
|
getAssignments(PageNo.value, PageSize.value); |
||||
|
}; |
||||
|
const getAssignments = (PageNo, PageSize) => { |
||||
|
ClassListApi.getClassList(PageNo, PageSize) |
||||
|
.then((response) => { |
||||
|
assignments.value = response.data.list; |
||||
|
total.value = response.data.total; |
||||
|
console.log(assignments.value); |
||||
|
}) |
||||
|
.catch((error) => { |
||||
|
console.error('获取作业列表失败', error); |
||||
|
}); |
||||
|
}; |
||||
|
//在组件初始化时(类似mounted生命周期的效果)获取一次初始数据 |
||||
|
onMounted(() => { |
||||
|
getAssignments(PageNo.value, PageSize.value); |
||||
|
const token = useTokenStore(); |
||||
|
console.log(token); |
||||
|
console.log(token.value); |
||||
|
console.log(token.token) |
||||
|
console.log("============="); |
||||
|
}); |
||||
|
|
||||
|
const newAssignment = () => { |
||||
|
router.push('/addwork') |
||||
|
} |
||||
|
|
||||
|
// 查看明细按钮的点击事件处理函数 |
||||
|
const viewDetails = async(row) => { |
||||
|
try { |
||||
|
router.push({ |
||||
|
name: 'workdetail', |
||||
|
params: { id: row.id }, |
||||
|
}); |
||||
|
console.log(row.id) |
||||
|
} catch (error) { |
||||
|
console.log('获取数据出错:', error) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// 编辑按钮的点击事件处理函数 |
||||
|
const editAssignment = async (row) => { |
||||
|
try { |
||||
|
router.push({ |
||||
|
name: 'updatework', |
||||
|
params: { id: row.id }, |
||||
|
}); |
||||
|
console.log(row.id) |
||||
|
} catch (error) { |
||||
|
console.log('获取数据出错:', error) |
||||
|
} |
||||
|
}; |
||||
|
// // 退出登录 |
||||
|
// const logout = () => { |
||||
|
// LoginApi.logout().then(res => { |
||||
|
// console.log(res); |
||||
|
// // 移除axios请求拦截器中设置token的逻辑,恢复到初始状态 |
||||
|
// // axios.interceptors.request.eject(axios.interceptors.request.handlers.find( |
||||
|
// // handler => handler.fulfilled && handler.fulfilled.toString().includes('token') |
||||
|
// // )); |
||||
|
// config.headers['token'] = ` `; |
||||
|
// }).catch(err => { |
||||
|
// // 处理退出登录接口调用失败的情况,比如提示错误信息等 |
||||
|
// ElMessage.error('退出登录失败,请稍后重试'); |
||||
|
// }).finally(() => { |
||||
|
// // 无论接口调用成功与否,都进行页面跳转 |
||||
|
// router.push('/'); |
||||
|
// }); |
||||
|
// } |
||||
|
// //退出登录 |
||||
|
// const logout = () => { |
||||
|
// LoginApi.logout().then(res => { |
||||
|
// console.log(res) |
||||
|
// }) |
||||
|
// router.push('/') |
||||
|
// } |
||||
|
|
||||
|
//退出 |
||||
|
const logout=async()=>{ |
||||
|
try { |
||||
|
await LoginApi.logout() |
||||
|
} catch (error) { |
||||
|
console.log(error) |
||||
|
} |
||||
|
//清除登录信息 |
||||
|
const tokenStore = useTokenStore(); |
||||
|
const userStore = useUserStore(); |
||||
|
tokenStore.clear(); |
||||
|
userStore.clear(); |
||||
|
router.push('/') |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.page { |
||||
|
margin-left: 70%; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
height: 100px; |
||||
|
line-height: 100px; |
||||
|
padding: 0 80px; |
||||
|
} |
||||
|
|
||||
|
.header-text { |
||||
|
font-size: 22px; |
||||
|
font-weight: 500; |
||||
|
color: black; |
||||
|
float: left; |
||||
|
} |
||||
|
|
||||
|
.header-button { |
||||
|
margin-top: 30px; |
||||
|
} |
||||
|
|
||||
|
.main { |
||||
|
padding: 20px 203px; |
||||
|
background-color: #F8F8F8; |
||||
|
} |
||||
|
|
||||
|
.list { |
||||
|
padding: 0 60px; |
||||
|
background-color: white; |
||||
|
} |
||||
|
|
||||
|
.main-title { |
||||
|
font-size: 16px; |
||||
|
background-color: white; |
||||
|
font-weight: bold; |
||||
|
height: 52px; |
||||
|
border-bottom: 2px solid #ececec; |
||||
|
padding: 0 60px; |
||||
|
line-height: 52px; |
||||
|
} |
||||
|
|
||||
|
.main-button { |
||||
|
margin: 15px 0; |
||||
|
padding: 12px 20px; |
||||
|
height: 40px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,145 @@ |
|||||
|
<template> |
||||
|
<div class="login-container"> |
||||
|
<div class="title1">管理后台</div> |
||||
|
<div class="login-box"> |
||||
|
<div class="title2">欢迎登录</div> |
||||
|
<div class="username"> |
||||
|
<el-input type="text" v-model="username" placeholder="请输入账号"> |
||||
|
<template #prefix> |
||||
|
<img class="img" src="../assets/login/denglu.png" /> |
||||
|
</template> |
||||
|
</el-input> |
||||
|
</div> |
||||
|
<div class="password"> |
||||
|
<el-input type="password" v-model="password" placeholder="请输入密码"> |
||||
|
<template #prefix> |
||||
|
<img class="img" src="../assets/login/mima.png" /> |
||||
|
</template> |
||||
|
</el-input> |
||||
|
</div> |
||||
|
<button @click="login">登录</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref } from 'vue'; |
||||
|
import LoginApi from '../api/LoginApi'; |
||||
|
import { ElMessage } from 'element-plus'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
import axios from 'axios'; |
||||
|
import { useTokenStore } from '../stores/token'; |
||||
|
// 使用ref创建响应式数据 |
||||
|
const username = ref(''); |
||||
|
const password = ref(''); |
||||
|
// 用于存储token的响应式变量 |
||||
|
const token = ref(''); |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
// 定义登录函数 |
||||
|
const login = async () => { |
||||
|
if (!username.value ||!password.value) { |
||||
|
ElMessage.error('账号和密码不能为空,请输入完整信息'); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
// 调用登录接口,假设LoginApi.login接收一个包含用户名和密码的对象作为参数,你需要根据实际接口情况调整 |
||||
|
const response = await LoginApi.login({ |
||||
|
username: username.value, |
||||
|
password: password.value |
||||
|
}); |
||||
|
if (response.code === 200) { |
||||
|
// 获取登录成功返回的token并存储 |
||||
|
token.value = response.data.token; |
||||
|
const tokenStore=useTokenStore(); |
||||
|
tokenStore.changeToken(token.value); |
||||
|
// const userStore=useUserStore(); |
||||
|
// userStore.changeUser(response.data.user); |
||||
|
console.log(token.value); |
||||
|
console.log("=--------"); |
||||
|
// 登录成功提示 |
||||
|
ElMessage.success('登录成功'); |
||||
|
// 这里可以根据实际业务逻辑,比如跳转到管理后台的首页等操作 |
||||
|
router.push('/list'); |
||||
|
} else { |
||||
|
// 登录失败提示,展示接口返回的错误信息,如果有的话 |
||||
|
ElMessage.error(response.message || '登录失败,请稍后重试'); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
// 捕获接口请求过程中的其他错误,比如网络问题等 |
||||
|
ElMessage.error('网络异常,请检查网络连接后重试'); |
||||
|
console.error(error); |
||||
|
} |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.title1 { |
||||
|
font-size: 40px; |
||||
|
color: #21d3ca; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.title2 { |
||||
|
font-size: 20px; |
||||
|
color: #21d3ca; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.username, |
||||
|
.password { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-bottom: 20px; |
||||
|
background-color: #e6e6e6; |
||||
|
} |
||||
|
|
||||
|
:deep(.el-input__wrapper) { |
||||
|
background-color: rgba(0, 0, 0, 0); |
||||
|
} |
||||
|
|
||||
|
.img { |
||||
|
width: 25px; |
||||
|
height: 25px; |
||||
|
} |
||||
|
|
||||
|
.login-container { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
height: 100vh; |
||||
|
} |
||||
|
|
||||
|
.login-box { |
||||
|
background-color: white; |
||||
|
border-radius: 5px; |
||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
||||
|
padding: 50px; |
||||
|
text-align: center; |
||||
|
height: 200px; |
||||
|
width: 250px; |
||||
|
} |
||||
|
|
||||
|
h1 { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
input { |
||||
|
width: 100%; |
||||
|
padding: 10px; |
||||
|
margin-bottom: 10px; |
||||
|
border: 1px solid #ccc; |
||||
|
border-radius: 3px; |
||||
|
} |
||||
|
|
||||
|
button { |
||||
|
width: 100%; |
||||
|
padding: 10px; |
||||
|
background-color: #21d3ca; |
||||
|
color: white; |
||||
|
border: none; |
||||
|
border-radius: 3px; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,535 @@ |
|||||
|
<template> |
||||
|
<div class="common-layout"> |
||||
|
<el-container> |
||||
|
<el-header class="header"> |
||||
|
<el-text class="header-text">抢点班作业后台管理</el-text> |
||||
|
<el-button class="header-button" type="primary" text style="float: right;" @click="logout">退出登录</el-button> |
||||
|
</el-header> |
||||
|
<el-main class="main"> |
||||
|
<div class="main-title"> |
||||
|
<div class="main-title-text" style="float: left;"> |
||||
|
编辑作业 |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button class="main-button" @click="back">返回上一页</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="main-back"> |
||||
|
<el-form :model="form" label-width="auto" style="max-width: 700px" size="large"> |
||||
|
<el-form-item label="作业名称"> |
||||
|
<el-input v-model="form.Name" placeholder="请输入"></el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="提交时间" style="width: 70%"> |
||||
|
<el-date-picker v-model="form.picker" type="daterange" range-separator="至" start-placeholder="开始日期" |
||||
|
end-placeholder="结束日期" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="作业归属"> |
||||
|
<el-select v-model="form.ClubType" placeholder="请选择" style="width: 100%"> |
||||
|
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="关联文章"> |
||||
|
<el-autocomplete v-model="articleTitle" :fetch-suggestions="queryArticleList" placeholder="请输入" |
||||
|
@select="handleSelectArticle" clearable /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="关联直播"> |
||||
|
<el-select v-model="form.LiveId" placeholder="请选择" style="width: 100%" clearable |
||||
|
@change="handleLiveChange"> |
||||
|
<el-option v-for="item in live" :key="item.id" :label="item.name" :value="item.id" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="选择类型"> |
||||
|
<div> |
||||
|
<el-button type="primary" @click="addSingleChoice">添加单选</el-button> |
||||
|
<el-button type="primary" @click="addMultipleChoice">添加多选</el-button> |
||||
|
<el-button type="primary" @click="addBlank">添加单选填空</el-button> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
<div class="question-container" v-for="(question, index) in questions" :key="index" |
||||
|
:class="{ 'bg-change': isHovered[index] }" @mouseenter="handleMouseEnter(index)" |
||||
|
@mouseleave="handleMouseLeave(index)"> |
||||
|
<div class="question-title"> |
||||
|
{{ questionPrefix(index) }} {{ getQuestionTypeText(question.type) }} |
||||
|
</div> |
||||
|
<div style="width: 600px;"> |
||||
|
<el-input v-model="question.description" /> |
||||
|
</div> |
||||
|
<div class="add" v-if="question.type !== 'blank'"> |
||||
|
<div class="question-option"> |
||||
|
<span>设置选项:</span> |
||||
|
<el-button type="primary" text @click="addOption(index)">添加</el-button> |
||||
|
</div> |
||||
|
<div v-for="(option, optionIndex) in question.content" :key="optionIndex"> |
||||
|
<div class="select" style="display: flex;"> |
||||
|
<div class="selection-item" style="display: flex;"> |
||||
|
<div style="width: 550px;"> |
||||
|
<el-input v-model="question.content[optionIndex].text" /> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button type="primary" text @click="removeOption(index, optionIndex)">删除</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="delete" style="margin-left: 50px;"> |
||||
|
<el-button type="info" plain @click="removeQuestion(index)">删除</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="submit"> |
||||
|
<el-button type="primary" :disabled="!form.Name || !form.picker" @click="onSubmit">确认</el-button> |
||||
|
</div> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
</el-main> |
||||
|
</el-container> |
||||
|
</div> |
||||
|
|
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts" setup> |
||||
|
import { ref, onMounted, computed } from 'vue' |
||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||
|
import AddWorkApi from '../api/AddWorkApi'; |
||||
|
import _ from 'lodash'; |
||||
|
import dayjs from 'dayjs'; |
||||
|
import ClassListApi from '../api/ClassListApi'; |
||||
|
import { ElMessage } from 'element-plus'; |
||||
|
import LoginApi from '../api/LoginApi'; |
||||
|
|
||||
|
import { useTokenStore } from '../stores/token'; |
||||
|
import { useUserStore } from '../stores/user'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
const options = ref([ |
||||
|
{ id: 1, name: '牧民俱乐部' }, |
||||
|
{ id: 2, name: '博古论坛' }, |
||||
|
{ id: 3, name: '神枪手俱乐部' }, |
||||
|
{ id: 4, name: '环球俱乐部' }, |
||||
|
{ id: 5, name: '价值投资' }, |
||||
|
{ id: 6, name: '波段行情' }, |
||||
|
{ id: 7, name: '抄底卖顶' }, |
||||
|
{ id: 8, name: '资金及仓位管理' }, |
||||
|
{ id: 9, name: '财富的游戏' }, |
||||
|
]); |
||||
|
|
||||
|
const route = useRoute(); |
||||
|
const id = ref(route.params.id) |
||||
|
console.log(id.value + '============') |
||||
|
|
||||
|
// 用于存储获取到的作业数据 |
||||
|
const homeworkData = ref<{ |
||||
|
name: string; |
||||
|
startDate: string; |
||||
|
endDate: string; |
||||
|
clubType: string; |
||||
|
article: { |
||||
|
id: string; |
||||
|
title: string; |
||||
|
}; |
||||
|
live: { |
||||
|
id: string; |
||||
|
name: string; |
||||
|
}; |
||||
|
status: number; |
||||
|
form: FormItemType[]; |
||||
|
|
||||
|
}>({ |
||||
|
name: '', |
||||
|
startDate: '', |
||||
|
endDate: '', |
||||
|
clubType: '', |
||||
|
article: { |
||||
|
id: '', |
||||
|
title: '', |
||||
|
}, |
||||
|
live: { |
||||
|
id: '', |
||||
|
name: '' |
||||
|
}, |
||||
|
status: 0, |
||||
|
form: [] |
||||
|
}); |
||||
|
|
||||
|
// 定义form数组中每个元素的类型接口 |
||||
|
interface FormItemType { |
||||
|
id: number; |
||||
|
type: number; |
||||
|
description: string; |
||||
|
content: string; // 这里先定义为string,因为从数据看是JSON字符串格式,后续需要解析 |
||||
|
groupId: number; |
||||
|
name: string; |
||||
|
sort: number; |
||||
|
status: number; |
||||
|
createdAt: string; |
||||
|
updatedAt: string; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
const form = ref({ |
||||
|
id: '', |
||||
|
Name: '', |
||||
|
ClubType: '', |
||||
|
ArticleId: '', |
||||
|
LiveId: '', |
||||
|
picker: [], |
||||
|
StartDate: '', |
||||
|
EndDate: '', |
||||
|
Questions: [] |
||||
|
}); |
||||
|
|
||||
|
// 新增一个变量用于标识是否发布,这里先设为false表示未发布 |
||||
|
const isPublished = ref(0); |
||||
|
onMounted(async () => { |
||||
|
try { |
||||
|
const response = await ClassListApi.getClassListOne(id.value); |
||||
|
homeworkData.value = response.data; |
||||
|
console.log(homeworkData.value) |
||||
|
form.value.Name = homeworkData.value.name; |
||||
|
// 根据后端返回数据设置发布状态变量的值 |
||||
|
isPublished.value = homeworkData.value.status; |
||||
|
|
||||
|
const start = dayjs(homeworkData.value.startDate).format('YYYY-MM-DD'); |
||||
|
const end = dayjs(homeworkData.value.endDate).format('YYYY-MM-DD'); |
||||
|
form.value.picker = [start, end]; |
||||
|
|
||||
|
if (homeworkData.value.article && homeworkData.value.article.title) { |
||||
|
articleTitle.value = homeworkData.value.article.title; |
||||
|
} else if (homeworkData.value.live && homeworkData.value.live.name) { |
||||
|
form.value.LiveId = homeworkData.value.live.name; |
||||
|
} |
||||
|
form.value.ClubType = homeworkData.value.clubType; |
||||
|
const processFormData = () => { |
||||
|
const newQuestions = []; |
||||
|
homeworkData.value.form.forEach((formItem: FormItemType) => { |
||||
|
// 解析content字段中的JSON字符串为实际的数组对象 |
||||
|
const contentArray = JSON.parse(formItem.content) as { id: string, text: string }[]; |
||||
|
// 创建一个新的符合questions结构的对象 |
||||
|
const question = { |
||||
|
id: formItem.id, |
||||
|
type: formItem.type, |
||||
|
description: formItem.description, |
||||
|
content: contentArray, |
||||
|
groupId: formItem.groupId, |
||||
|
name: formItem.name, |
||||
|
sort: formItem.sort, |
||||
|
status: formItem.status, |
||||
|
createdAt: formItem.createdAt, |
||||
|
updatedAt: formItem.updatedAt, |
||||
|
}; |
||||
|
newQuestions.push(question); |
||||
|
}); |
||||
|
return newQuestions; |
||||
|
}; |
||||
|
questions.value = processFormData(); |
||||
|
} catch (error) { |
||||
|
console.error('接口请求出现错误:', error); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
const articleTitle = ref(''); |
||||
|
// 问题列表数据 |
||||
|
const questions = ref([]); |
||||
|
const onSubmit = () => { |
||||
|
// 从picker中获取日期数据并进行格式转换 |
||||
|
if (form.value.picker && form.value.picker.length === 2) { |
||||
|
const startDate = dayjs(form.value.picker[0]).format('YYYY-MM-DD HH:mm:00'); |
||||
|
const endDate = dayjs(form.value.picker[1]).format('YYYY-MM-DD HH:mm:00'); |
||||
|
form.value.StartDate = startDate; |
||||
|
form.value.EndDate = endDate; |
||||
|
} |
||||
|
form.value.Questions = questions.value; |
||||
|
if (form.value.LiveId) { |
||||
|
// 如果form.value.liveid有值,优先使用liveid,清空ArticleId(假设后端不接受同时传这两个值且以liveid为准,可根据实际情况调整) |
||||
|
form.value.ArticleId = ''; |
||||
|
articleTitle.value = ''; |
||||
|
} else if (form.value.ArticleId) { |
||||
|
|
||||
|
// 如果手动选择了关联文章,使用手动选择后更新的文章id(form.value.ArticleId) |
||||
|
} else if (homeworkData.value.article && homeworkData.value.article.id) { |
||||
|
// 如果没有手动选择,使用后端传回的数据中的关联文章id(homeworkData.value.article.id) |
||||
|
form.value.ArticleId = homeworkData.value.article.id; |
||||
|
} |
||||
|
if (typeof id.value === 'string') { |
||||
|
form.value.id = id.value; |
||||
|
} |
||||
|
if(!form.value.ArticleId&&!form.value.LiveId){ |
||||
|
ElMessage.error('编辑失败'); |
||||
|
}else{ |
||||
|
ClassListApi.editWork(form.value) |
||||
|
.then((response) => { |
||||
|
console.log(response); |
||||
|
ElMessage.success('编辑成功'); |
||||
|
router.push('/list') |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
console.log(id.value + '--------------') |
||||
|
console.log(form.value) |
||||
|
} |
||||
|
const back = () => { |
||||
|
window.history.back() |
||||
|
} |
||||
|
|
||||
|
// 存储根据文章输入内容查询到的关联文章结果列表 |
||||
|
const articleSearchResults = ref([]); |
||||
|
// 根据文章输入内容查询关联文章的函数 |
||||
|
const queryArticleList = async (queryString: string) => { |
||||
|
if (form.value.LiveId) { |
||||
|
ElMessage.warning('您已关联直播,暂无法关联文章'); |
||||
|
articleTitle.value = ''; // 清空文章标题输入框 |
||||
|
form.value.LiveId = ''; |
||||
|
return []; |
||||
|
} |
||||
|
try { |
||||
|
const response = await AddWorkApi.getArticleList(queryString); |
||||
|
const formattedResults = response.data.map(article => ({ |
||||
|
value: article.title, |
||||
|
label: article.id |
||||
|
})); |
||||
|
articleSearchResults.value = formattedResults; |
||||
|
return formattedResults; |
||||
|
} catch (error) { |
||||
|
console.error('查询关联文章失败', error); |
||||
|
return []; |
||||
|
} |
||||
|
}; |
||||
|
const handleLiveChange = () => { |
||||
|
if (articleTitle.value) { |
||||
|
ElMessage.warning('您已关联文章,暂无法关联直播'); |
||||
|
form.value.LiveId = ''; // 清空关联直播选择框的值 |
||||
|
form.value.ArticleId = ''; |
||||
|
articleTitle.value = ''; |
||||
|
} |
||||
|
}; |
||||
|
// 处理选择文章的函数 |
||||
|
const handleSelectArticle = (article: { label: string }) => { |
||||
|
// 这里可以根据业务需求,比如将选中的文章id(article.label)传递给其他地方使用等 |
||||
|
console.log('选中的文章id', article.label); |
||||
|
form.value.ArticleId = article.label; // 将选中文章的id赋值给对应表单字段,用于传递给后端 |
||||
|
const selectedArticle = articleSearchResults.value.find(a => a.label === article.label); |
||||
|
if (selectedArticle) { |
||||
|
articleTitle.value = selectedArticle.value; // 更新显示的文章题目 |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
//获取直播列表 |
||||
|
const live = ref([]); |
||||
|
function getLive() { |
||||
|
AddWorkApi.getLiveList() |
||||
|
.then(res => { |
||||
|
live.value = res.data; |
||||
|
console.log(live.value); |
||||
|
}) |
||||
|
.catch(error => { |
||||
|
console.error('获取直播列表失败', error) |
||||
|
}) |
||||
|
} |
||||
|
getLive(); |
||||
|
|
||||
|
// 根据类型获取对应的题目类型文本显示 |
||||
|
const getQuestionTypeText = (type) => { |
||||
|
switch (type) { |
||||
|
case 1: |
||||
|
return '作业题目(单选)'; |
||||
|
case 2: |
||||
|
return '作业题目(多选)'; |
||||
|
case 3: |
||||
|
return '作业题目(简答题)'; |
||||
|
default: |
||||
|
return '未知类型题目'; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const addSingleChoice = () => { |
||||
|
if (isPublished.value === 1) { |
||||
|
ElMessage.warning('处于发布中,不能添加新题目'); |
||||
|
} else { |
||||
|
questions.value.push({ |
||||
|
type: 1, // 假设1代表单选,和后端格式对应起来 |
||||
|
description: '', |
||||
|
content: [{ "id": "", "text": "" }, { "id": "", "text": "" }] |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
const addMultipleChoice = () => { |
||||
|
if (isPublished.value === 1) { |
||||
|
ElMessage.warning('处于发布中,不能添加新题目'); |
||||
|
} else { |
||||
|
questions.value.push({ |
||||
|
type: 2, // 假设2代表多选,和后端格式对应起来 |
||||
|
description: '', |
||||
|
content: [{ "id": "", "text": "" }, { "id": "", "text": "" }] |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
const addBlank = () => { |
||||
|
if (isPublished.value === 1) { |
||||
|
ElMessage.warning('处于发布中,不能添加新题目'); |
||||
|
} else { |
||||
|
questions.value.push({ |
||||
|
type: 3, // 假设3代表简答题,和后端格式对应起来 |
||||
|
description: '', |
||||
|
content: [{ "id": "", "text": "" }] |
||||
|
}); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const addOption = (questionIndex) => { |
||||
|
const currentQuestion = questions.value[questionIndex]; |
||||
|
// 如果当前题目没有content属性,则初始化一个空数组 |
||||
|
if (!currentQuestion.content) { |
||||
|
currentQuestion.content = []; |
||||
|
} |
||||
|
currentQuestion.content.push({ id: "", text: "" }); |
||||
|
}; |
||||
|
const removeOption = (questionIndex, optionIndex) => { |
||||
|
const currentQuestion = questions.value[questionIndex]; |
||||
|
currentQuestion.content.splice(optionIndex, 1); |
||||
|
}; |
||||
|
|
||||
|
const removeQuestion = (questionIndex) => { |
||||
|
if(isPublished.value === 1){ |
||||
|
ElMessage.warning('处于发布中,不能删除题目'); |
||||
|
}else{ |
||||
|
questions.value.splice(questionIndex, 1); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 计算属性,用于生成序号前缀 |
||||
|
const questionPrefix = computed(() => { |
||||
|
return (index) => { |
||||
|
return `${index + 1}、`; |
||||
|
}; |
||||
|
}) |
||||
|
|
||||
|
// 用于存储每个问题标题是否被鼠标悬停的状态,初始化为false |
||||
|
const isHovered = ref(Array(questions.value.length).fill(false)); |
||||
|
const handleMouseEnter = (index) => { |
||||
|
isHovered.value[index] = true; |
||||
|
}; |
||||
|
|
||||
|
const handleMouseLeave = (index) => { |
||||
|
isHovered.value[index] = false; |
||||
|
}; |
||||
|
|
||||
|
// 在组件挂载后初始化 `isHovered` 数组长度与 `questions` 数组长度一致 |
||||
|
onMounted(() => { |
||||
|
isHovered.value = Array(questions.value.length).fill(false); |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
//退出 |
||||
|
function logout() { |
||||
|
//清除登录信息 |
||||
|
const tokenStore = useTokenStore(); |
||||
|
const userStore = useUserStore(); |
||||
|
tokenStore.clear(); |
||||
|
userStore.clear(); |
||||
|
LoginApi.logout().then(res => { |
||||
|
console.log(res) |
||||
|
}) |
||||
|
router.push('/') |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.submit { |
||||
|
margin: 100px 212px; |
||||
|
} |
||||
|
|
||||
|
.submit .el-button { |
||||
|
padding: 25px 150px; |
||||
|
} |
||||
|
|
||||
|
.question-title { |
||||
|
transition: background-color 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.bg-change { |
||||
|
background-color: rgba(200, 200, 200, 0.3); |
||||
|
} |
||||
|
|
||||
|
.question-title { |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.select { |
||||
|
margin: 10px 0px 0px; |
||||
|
} |
||||
|
|
||||
|
.delete { |
||||
|
position: absolute; |
||||
|
right: 10px; |
||||
|
bottom: 0px; |
||||
|
} |
||||
|
|
||||
|
.add { |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.question-container { |
||||
|
margin: 20px 0; |
||||
|
padding: 10px 20px; |
||||
|
width: 750px; |
||||
|
border-bottom: 1px solid #e5e5e5; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
height: 100px; |
||||
|
line-height: 100px; |
||||
|
padding: 0 80px; |
||||
|
} |
||||
|
|
||||
|
.header-text { |
||||
|
font-size: 22px; |
||||
|
font-weight: 500; |
||||
|
color: black; |
||||
|
float: left; |
||||
|
} |
||||
|
|
||||
|
.header-button { |
||||
|
margin-top: 30px; |
||||
|
} |
||||
|
|
||||
|
.main { |
||||
|
padding: 30px 212px; |
||||
|
background-color: #F8F8F8; |
||||
|
} |
||||
|
|
||||
|
.main-title { |
||||
|
font-size: 16px; |
||||
|
background-color: white; |
||||
|
font-weight: bold; |
||||
|
height: 60px; |
||||
|
border-bottom: 2px solid #ececec; |
||||
|
padding: 0 15px; |
||||
|
line-height: 52px; |
||||
|
} |
||||
|
|
||||
|
.main-button { |
||||
|
margin: 10px 15px 0 0; |
||||
|
padding: 12px 20px; |
||||
|
height: 40px; |
||||
|
float: right; |
||||
|
} |
||||
|
|
||||
|
.el-form { |
||||
|
padding: 30px 78.5px; |
||||
|
margin: auto; |
||||
|
} |
||||
|
|
||||
|
.el-form-item { |
||||
|
--font-size: 16px; |
||||
|
margin: 0 0 25px; |
||||
|
} |
||||
|
|
||||
|
.main-back { |
||||
|
background-color: white; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,391 @@ |
|||||
|
<template> |
||||
|
<div class="common-layout"> |
||||
|
<el-container> |
||||
|
<el-header class="header"> |
||||
|
<el-text class="header-text">抢点班作业后台管理</el-text> |
||||
|
<el-button class="header-button" type="primary" text style="float: right;" |
||||
|
@click="logout">退出登录</el-button> |
||||
|
</el-header> |
||||
|
<el-main class="main"> |
||||
|
<div class="main-title"> |
||||
|
<div class="main-title-text" style="float: left;"> |
||||
|
作业详情 |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button class="main-button" @click="back">返回上一页</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="table-container"> |
||||
|
<div class="search-bar" :v-model="form"> |
||||
|
<el-input v-model="form.jwcode" type="text" placeholder="请输入精网号" style="width: 180px;" |
||||
|
size="large" clearable /> |
||||
|
<el-select v-model="form.deptId" placeholder="选择分店门部" size="large" |
||||
|
style="width: 180px; margin-left: 15px;" clearable @change="handleDeptSelect"> |
||||
|
<el-option v-for="item in dept" :key="item.id" :label="item.deptName" |
||||
|
:value="item.deptId" /> |
||||
|
</el-select> |
||||
|
|
||||
|
<el-select v-model="form.shopId" placeholder="--请选择所属门店--" size="large" |
||||
|
style="width: 180px; margin-left: 15px" clearable> |
||||
|
<el-option v-for="item in shop" :key="item.id" :label="item.shopName" |
||||
|
:value="item.shopId" /> |
||||
|
</el-select> |
||||
|
<el-button class="search-btn" type="primary" size="large" @click="searchData">搜索</el-button> |
||||
|
<div class="export"> |
||||
|
<el-button class="export-btn" type="primary" size="large" |
||||
|
@click="exportData">导出数据</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-table :data="workdetailData" style="width: 100%"> |
||||
|
<el-table-column label="序号"> |
||||
|
<template #default="scope"> |
||||
|
{{ scope.$index + (PageNo - 1) * PageSize + 1 }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="name" label="姓名"></el-table-column> |
||||
|
<el-table-column prop="jwcode" label="精网号"></el-table-column> |
||||
|
<el-table-column label="分布-门店"> |
||||
|
<template v-slot="scope"> |
||||
|
{{ scope.row.deptName }} - {{ scope.row.shopName }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="作业详情"> |
||||
|
<template v-slot="{ $index }"> |
||||
|
<el-popover placement="bottom" title="详情" :width="500" trigger="click"> |
||||
|
<template #reference> |
||||
|
<el-button link type="primary">查看</el-button> |
||||
|
</template> |
||||
|
<div v-for="(r, subIndex) in getContent($index).replies" :key="subIndex"> |
||||
|
<div>{{ r.formTitle }}</div> |
||||
|
<div>{{ r.contentTitle }}</div> |
||||
|
<div>{{ r.content }}</div> |
||||
|
<div style="margin-bottom: 10px;"></div> |
||||
|
</div> |
||||
|
</el-popover> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="submitTime" label="提交时间"> |
||||
|
<template v-slot="scope"> |
||||
|
{{ scope.row.Reply[0].submitTime }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
<div class="page"> |
||||
|
<el-pagination v-model:current-page="PageNo" v-model:page-size="PageSize" |
||||
|
:page-sizes="[20, 50, 100, 200]" :size="size" :disabled="disabled" :background="background" |
||||
|
layout="sizes,prev,next,jumper" :total="10" @size-change="handleSizeChange" |
||||
|
@current-change="handleCurrentChange" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-main> |
||||
|
</el-container> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts" setup> |
||||
|
import { ref, onMounted, watch } from 'vue' |
||||
|
import { useRoute, useRouter } from 'vue-router'; |
||||
|
import ClassListApi from '../api/ClassListApi'; |
||||
|
import { ElMessage } from 'element-plus'; |
||||
|
import UpdateWorkApi from '../api/UpdateWorkApi'; |
||||
|
import * as XLSX from 'xlsx'; |
||||
|
import axios from 'axios'; |
||||
|
import LoginApi from '../api/LoginApi'; |
||||
|
import { useTokenStore } from '../stores/token'; |
||||
|
import { useUserStore } from '../stores/user'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const back = () => { |
||||
|
window.history.back() |
||||
|
} |
||||
|
//获取门店列表 |
||||
|
const shop = ref([]); |
||||
|
// 处理部门选择变化的事件函数 |
||||
|
const handleDeptSelect = async (val) => { |
||||
|
console.log(val); |
||||
|
const res = await UpdateWorkApi.getshopinfo(val); |
||||
|
shop.value = res.data; |
||||
|
console.log(shop.value); |
||||
|
form.value.shopId = ""; |
||||
|
}; |
||||
|
|
||||
|
// 初始化页码,这里假设初始页码为1 |
||||
|
const PageNo = ref(1); |
||||
|
// 初始化页面大小,这里假设初始页面大小为10 |
||||
|
const PageSize = ref(20); |
||||
|
|
||||
|
// 处理页面大小改变的事件函数,将新的页面大小赋值给PageSize变量 |
||||
|
const handleSizeChange = (newPageSize) => { |
||||
|
PageSize.value = newPageSize; |
||||
|
ClassListApi.getWorkDetail(id.value, PageNo.value, PageSize.value); |
||||
|
}; |
||||
|
|
||||
|
// 处理当前页码改变的事件函数,将新的页码赋值给PageNo变量 |
||||
|
const handleCurrentChange = (newPageNo) => { |
||||
|
PageNo.value = newPageNo; |
||||
|
ClassListApi.getWorkDetail(id.value, PageNo.value, PageSize.value); |
||||
|
}; |
||||
|
|
||||
|
const form = ref({ |
||||
|
jwcode: "", |
||||
|
deptId: "", |
||||
|
shopId: "", |
||||
|
}); |
||||
|
|
||||
|
// 搜索方法 |
||||
|
const searchData = async () => { |
||||
|
try { |
||||
|
const params = { |
||||
|
id: id.value, |
||||
|
...form.value |
||||
|
}; |
||||
|
const res = await UpdateWorkApi.getrecordbycondition(params); |
||||
|
console.log('搜索结果:', res); |
||||
|
workdetailData.value = res.data; |
||||
|
} catch (error) { |
||||
|
console.error('搜索失败', error); |
||||
|
} |
||||
|
// form.value.jwcode = ""; |
||||
|
// form.value.deptId = ""; |
||||
|
// form.value.shopId = ""; |
||||
|
} |
||||
|
//获取门部列表 |
||||
|
const dept = ref([]); |
||||
|
const getDept = async () => { |
||||
|
try { |
||||
|
const res = await UpdateWorkApi.getdeptinfo(); |
||||
|
dept.value = res.data; |
||||
|
console.log(dept.value); |
||||
|
} catch (error) { |
||||
|
console.error('获取分部失败', error); |
||||
|
} |
||||
|
}; |
||||
|
getDept(); |
||||
|
|
||||
|
|
||||
|
const route = useRoute(); |
||||
|
const id = ref(route.params.id) |
||||
|
console.log(id.value + '============') |
||||
|
|
||||
|
const workdetailData = ref([]); |
||||
|
// onMounted(async () => { |
||||
|
// try { |
||||
|
// const response = await ClassListApi.getWorkDetail(id.value, PageNo.value, PageSize.value); |
||||
|
// workdetailData.value = response.data; |
||||
|
// console.log(workdetailData.value); |
||||
|
// } catch (error) { |
||||
|
// console.error('接口请求出现错误:', error); |
||||
|
// } |
||||
|
// }); |
||||
|
onMounted(async () => { |
||||
|
const refdata = { |
||||
|
id: id.value, |
||||
|
pageNo: PageNo.value, |
||||
|
pageSize: PageSize.value |
||||
|
} |
||||
|
try { |
||||
|
const response = await UpdateWorkApi.getrecordbycondition(refdata); |
||||
|
workdetailData.value = response.data; |
||||
|
console.log(workdetailData.value); |
||||
|
} catch (error) { |
||||
|
console.error('接口请求出现错误:', error); |
||||
|
} |
||||
|
}) |
||||
|
const getContent = (index) => { |
||||
|
if (workdetailData.value && workdetailData.value[index] && workdetailData.value[index].Reply) { |
||||
|
const replies = workdetailData.value[index].Reply; |
||||
|
return { |
||||
|
// 这里直接返回包含所有reply数据的数组 |
||||
|
replies: replies.map((reply) => ({ |
||||
|
formTitle: reply.formTitle, |
||||
|
contentTitle: reply.contentTitle, |
||||
|
content: reply.content |
||||
|
})) |
||||
|
}; |
||||
|
} |
||||
|
return { |
||||
|
replies: [] |
||||
|
}; |
||||
|
}; |
||||
|
const exportData = async () => { |
||||
|
if(!workdetailData.value){ |
||||
|
ElMessage.warning('暂无数据可导出'); |
||||
|
} |
||||
|
try { |
||||
|
const params = { |
||||
|
// 这里假设form.value和id.value是你已有的正确数据获取方式,按需替换成实际的准确值 |
||||
|
...form.value, |
||||
|
id: id.value, |
||||
|
}; |
||||
|
const response = await axios.post('/api/api/homework_manage/export-record', params, { |
||||
|
responseType: 'arraybuffer' |
||||
|
}); |
||||
|
console.log('导出数据:', response); |
||||
|
console.log('导出数据:', response.data); |
||||
|
// 将返回的二进制数据转换为Blob对象,用于创建下载链接 |
||||
|
const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); |
||||
|
const url = URL.createObjectURL(blob); |
||||
|
const a = document.createElement('a'); |
||||
|
a.href = url; |
||||
|
// 尝试从响应头中获取Content-Disposition字段来解析文件名 |
||||
|
const contentDisposition = response.headers['content-disposition']; |
||||
|
console.log('文件名:', contentDisposition); |
||||
|
if (contentDisposition) { |
||||
|
// 使用正则表达式匹配filename |
||||
|
const fileNameMatch = contentDisposition.match(/filename=([^"]+)/); |
||||
|
if (fileNameMatch && fileNameMatch.length > 1) { |
||||
|
const fileName = fileNameMatch[1]; |
||||
|
a.download = fileName; |
||||
|
} else { |
||||
|
console.error('无法从Content-Disposition中解析出文件名'); |
||||
|
return; |
||||
|
} |
||||
|
} else { |
||||
|
console.error('响应头中不存在Content-Disposition字段'); |
||||
|
return; |
||||
|
} |
||||
|
document.body.appendChild(a); |
||||
|
a.click(); |
||||
|
document.body.removeChild(a); |
||||
|
URL.revokeObjectURL(url); |
||||
|
} catch (error) { |
||||
|
console.error('详细的请求错误信息:', error); |
||||
|
ElMessage.error('导出失败'); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const tokenStore = useTokenStore(); |
||||
|
// // 退出登录 |
||||
|
// const logout = () => { |
||||
|
// LoginApi.logout().then(res => { |
||||
|
// console.log(tokenStore); |
||||
|
// tokenStore.clear(); |
||||
|
// localStorage.removeItem('token'); |
||||
|
// console.log(tokenStore); |
||||
|
// router.push('/'); |
||||
|
// }).catch(err => { |
||||
|
// // 处理退出登录接口调用失败的情况,比如提示错误信息等 |
||||
|
// ElMessage.error('退出登录失败,请稍后重试'); |
||||
|
// }) |
||||
|
// } |
||||
|
|
||||
|
|
||||
|
//退出 |
||||
|
function logout(){ |
||||
|
//清除登录信息 |
||||
|
const tokenStore = useTokenStore(); |
||||
|
const userStore = useUserStore(); |
||||
|
tokenStore.clear(); |
||||
|
userStore.clear(); |
||||
|
LoginApi.logout().then(res => { |
||||
|
console.log(res) |
||||
|
}) |
||||
|
router.push('/') |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.look { |
||||
|
color: rgb(69, 131, 254); |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.table-container { |
||||
|
margin: 6px 0 0; |
||||
|
padding: 15px 60px; |
||||
|
} |
||||
|
|
||||
|
.search-bar { |
||||
|
margin-bottom: 10px; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.search-btn { |
||||
|
padding: 10px 20px; |
||||
|
margin: 0 0 0 15px; |
||||
|
} |
||||
|
|
||||
|
.export { |
||||
|
position: absolute; |
||||
|
right: 20px; |
||||
|
top: 0px; |
||||
|
} |
||||
|
|
||||
|
.export-btn { |
||||
|
padding: 12px 20px; |
||||
|
text-align: right; |
||||
|
} |
||||
|
|
||||
|
table { |
||||
|
width: 100%; |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
|
||||
|
th, |
||||
|
td { |
||||
|
border: 1px solid #ccc; |
||||
|
padding: 5px; |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
.pagination { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
|
||||
|
.pagination select { |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
|
||||
|
.pagination button { |
||||
|
margin-right: 5px; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
.header { |
||||
|
height: 100px; |
||||
|
line-height: 100px; |
||||
|
padding: 0 80px; |
||||
|
} |
||||
|
|
||||
|
.header-text { |
||||
|
font-size: 22px; |
||||
|
font-weight: 500; |
||||
|
color: black; |
||||
|
float: left; |
||||
|
} |
||||
|
|
||||
|
.header-button { |
||||
|
margin-top: 30px; |
||||
|
} |
||||
|
|
||||
|
.main { |
||||
|
padding: 30px 212px; |
||||
|
background-color: #F8F8F8; |
||||
|
} |
||||
|
|
||||
|
.main-title { |
||||
|
font-size: 16px; |
||||
|
background-color: white; |
||||
|
font-weight: bold; |
||||
|
height: 60px; |
||||
|
border-bottom: 2px solid #ececec; |
||||
|
padding: 0 60px; |
||||
|
line-height: 52px; |
||||
|
} |
||||
|
|
||||
|
.main-button { |
||||
|
margin: 10px 15px 0 0; |
||||
|
padding: 12px 20px; |
||||
|
height: 40px; |
||||
|
float: right; |
||||
|
} |
||||
|
|
||||
|
.main-back { |
||||
|
background-color: white; |
||||
|
} |
||||
|
</style> |
@ -1,563 +0,0 @@ |
|||||
<script setup> |
|
||||
import { ref } from 'vue'; |
|
||||
import ShowApi from '../api/ShowApi'; |
|
||||
import { format } from 'date-fns'; |
|
||||
import {useRouter} from "vue-router"; |
|
||||
import {ElMessage} from "element-plus"; |
|
||||
|
|
||||
const router = useRouter() |
|
||||
|
|
||||
//作业展示列表 |
|
||||
const works = ref([]); |
|
||||
function loadWorks() { |
|
||||
ShowApi.getWorks().then(result => { |
|
||||
works.value = result.data; |
|
||||
console.log(works.value); |
|
||||
console.log(result.data); |
|
||||
works.value.forEach(work => { |
|
||||
let date = work.endData; |
|
||||
work.endData = format(new Date(date), 'yyyy-MM-dd'); |
|
||||
}); |
|
||||
}) |
|
||||
} |
|
||||
loadWorks(); |
|
||||
//跳转写作业页面 |
|
||||
function writeWorks(id,sub){ |
|
||||
if(sub >= 3){ |
|
||||
ElMessage.error('每个作业可提交3次,您已提交3次。') |
|
||||
}else{ |
|
||||
router.push({ |
|
||||
path:`/doWork/${id}/${sub}` |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<template> |
|
||||
<div class="container"> |
|
||||
<div class="works"> |
|
||||
<div class="work-header"> |
|
||||
<img class="ketangzuoye" src="http://39.101.133.168:8857/LiveActivity/img/ketangzuoye.cc888815.png"> |
|
||||
<img class="book" |
|
||||
src="https://img.js.design/assets/img/65f9235904fb00a3ea731672.png#dcda48ae8da37daeccd6583d45c7790b"> |
|
||||
</div> |
|
||||
<div class="work-list"> |
|
||||
<div class="list" v-for="work in works"> |
|
||||
<div class="work-item"> |
|
||||
<div class="work-name"> |
|
||||
{{ work.name }} |
|
||||
</div> |
|
||||
<div class="work-content"> |
|
||||
<div class="work-time"> |
|
||||
<span class="deadline">截止时间:{{ work.endData }}</span> |
|
||||
<!-- 作业提价状态 --> |
|
||||
<div v-if="work.submit == 0" class="work-status">未提交</div> |
|
||||
<div v-else class="work-status2">已提交</div> |
|
||||
</div> |
|
||||
<div class="work-bottem" @click="writeWorks(work.groupId,work.submit)"> |
|
||||
<span class="write">写作业</span> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<style scoped> |
|
||||
.container { |
|
||||
width: 27%; /* 假设桌面布局的容器宽度为 80% */ |
|
||||
margin: 0 auto; /* 居中对齐 */ |
|
||||
} |
|
||||
body{ |
|
||||
margin: 0; |
|
||||
} |
|
||||
.work-name { |
|
||||
opacity: 1; |
|
||||
/** 文本1 */ |
|
||||
font-size: 1.5vw; |
|
||||
font-weight: 700; |
|
||||
letter-spacing: 0px; |
|
||||
color: rgba(53, 56, 112, 1); |
|
||||
text-align: left; |
|
||||
/*左对齐*/ |
|
||||
vertical-align: top; |
|
||||
/* 这个属性在 Flex 容器中不起作用,将被移除 */ |
|
||||
display: flex; |
|
||||
/* 启用 Flexbox 布局 */ |
|
||||
align-items: center; |
|
||||
/* 垂直居中 */ |
|
||||
height: 30%; |
|
||||
/* 设置高度,根据需要调整 */ |
|
||||
width: 50%; |
|
||||
/* 如果需要,也可以设置宽度 */ |
|
||||
} |
|
||||
|
|
||||
|
|
||||
.ketangzuoye { |
|
||||
margin-top: 2vh; |
|
||||
margin-left: 2vw; |
|
||||
width: 43%; |
|
||||
} |
|
||||
|
|
||||
.book { |
|
||||
float: right; |
|
||||
margin-right: 1vw; |
|
||||
width: 30%; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/* 手机 */ |
|
||||
@media (max-width: 768px) { |
|
||||
.container { |
|
||||
width: 100%; |
|
||||
margin: auto; |
|
||||
} |
|
||||
.works { |
|
||||
/* ../api/ShowApi |
|
||||
work\src\assets\bg@3x.png */ |
|
||||
background-image: url('../assets/bg.png'); |
|
||||
background-size: 100% 100%; |
|
||||
background-color: #8f98f6; |
|
||||
width: 100%; |
|
||||
min-height: 100vh; |
|
||||
position: relative; |
|
||||
margin: auto; |
|
||||
} |
|
||||
|
|
||||
.work-list { |
|
||||
width: 95%; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
flex-direction: column; |
|
||||
margin: auto; |
|
||||
} |
|
||||
|
|
||||
.list { |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
width: 97%; |
|
||||
height: 16vh; |
|
||||
opacity: 1; |
|
||||
border-radius: 10px; |
|
||||
background-color: rgba(255, 225, 174, 1); |
|
||||
margin-bottom: 3%; |
|
||||
} |
|
||||
|
|
||||
.work-item { |
|
||||
|
|
||||
width: 87%; |
|
||||
height: 63%; |
|
||||
padding: 10px; |
|
||||
position: relative; |
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 1) 0%, rgba(250, 245, 235, 1) 100%); |
|
||||
border-radius: 10px; |
|
||||
border-radius: 10px; |
|
||||
} |
|
||||
.work-name { |
|
||||
opacity: 1; |
|
||||
/** 文本1 */ |
|
||||
font-size: 4vw; |
|
||||
font-weight: 700; |
|
||||
letter-spacing: 0px; |
|
||||
color: rgba(53, 56, 112, 1); |
|
||||
text-align: left; |
|
||||
/*左对齐*/ |
|
||||
vertical-align: top; |
|
||||
/* 这个属性在 Flex 容器中不起作用,将被移除 */ |
|
||||
display: flex; |
|
||||
/* 启用 Flexbox 布局 */ |
|
||||
align-items: center; |
|
||||
/* 垂直居中 */ |
|
||||
height: 30%; |
|
||||
/* 设置高度,根据需要调整 */ |
|
||||
width: 50%; |
|
||||
/* 如果需要,也可以设置宽度 */ |
|
||||
} |
|
||||
|
|
||||
.work-content { |
|
||||
width: 95%; |
|
||||
height: 35%; |
|
||||
position: absolute; |
|
||||
bottom: 10%; |
|
||||
display: flex; |
|
||||
} |
|
||||
|
|
||||
.work-time { |
|
||||
position: absolute; |
|
||||
display: flex; |
|
||||
width: 70%; |
|
||||
bottom: 12%; |
|
||||
} |
|
||||
|
|
||||
.deadline { |
|
||||
color: rgba(142, 142, 142, 1); |
|
||||
font-size: 3.6vw; |
|
||||
opacity: 1; |
|
||||
align-items: center; |
|
||||
padding-top: 0.5vw; |
|
||||
/* 水平居中 */ |
|
||||
/* justify-content: center; */ |
|
||||
} |
|
||||
|
|
||||
.work-status { |
|
||||
font-size: 3.8vw; |
|
||||
display: inline-block; |
|
||||
background: rgba(53, 56, 112, 0.1); |
|
||||
padding: 1% 3.5%; |
|
||||
text-align: center; |
|
||||
color: #353870; |
|
||||
border-radius: 5px; |
|
||||
opacity: 2; |
|
||||
margin-left: 5px; |
|
||||
} |
|
||||
.work-status2 { |
|
||||
font-size: 3.8vw; |
|
||||
display: inline-block; |
|
||||
background: #ffe1ae; |
|
||||
padding: 1% 3.5%; |
|
||||
text-align: center; |
|
||||
color: #353870; |
|
||||
border-radius: 5px; |
|
||||
opacity: 2; |
|
||||
margin-left: 5px; |
|
||||
} |
|
||||
|
|
||||
.work-bottem { |
|
||||
cursor: pointer; |
|
||||
display: flex; |
|
||||
position: absolute; |
|
||||
width: 28%; |
|
||||
height: 70%; |
|
||||
right: 0; |
|
||||
bottom: 2%; |
|
||||
opacity: 1; |
|
||||
border-radius: 50px; |
|
||||
background: linear-gradient(270deg, rgba(4, 15, 179, 1) 0%, rgba(120, 89, 255, 1) 100%); |
|
||||
border: 1px solid #a5e0f3; |
|
||||
justify-content: center; |
|
||||
/* 水平居中 */ |
|
||||
align-items: center; |
|
||||
/* 垂直居中 */ |
|
||||
text-align: center; |
|
||||
/* 确保文本在其容器内居中 */ |
|
||||
} |
|
||||
|
|
||||
.write { |
|
||||
opacity: 1; |
|
||||
/** 文本1 */ |
|
||||
padding: auto; |
|
||||
font-size: 18px; |
|
||||
font-weight: 700; |
|
||||
letter-spacing: 0px; |
|
||||
line-height: 26.06px; |
|
||||
color: rgba(255, 255, 255, 1); |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/* 平板 */ |
|
||||
@media (min-width: 768px) and (max-width:1280px) { |
|
||||
.container { |
|
||||
width: 100%; |
|
||||
margin: auto; |
|
||||
} |
|
||||
.works { |
|
||||
/* ../api/ShowApi |
|
||||
work\src\assets\bg@3x.png */ |
|
||||
background-image: url('../assets/bg@2x.png'); |
|
||||
background-color: #8f98f6; |
|
||||
width: 100%; |
|
||||
min-height: 100vh; |
|
||||
position: relative; |
|
||||
margin: auto; |
|
||||
background-size: 100% 100%; |
|
||||
} |
|
||||
|
|
||||
.work-list { |
|
||||
width: 95%; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
flex-direction: column; |
|
||||
margin: auto; |
|
||||
} |
|
||||
|
|
||||
.list { |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
width: 97%; |
|
||||
height: 17vh; |
|
||||
opacity: 1; |
|
||||
border-radius: 10px; |
|
||||
background-color: rgba(255, 225, 174, 1); |
|
||||
margin-bottom: 3%; |
|
||||
} |
|
||||
|
|
||||
.work-item { |
|
||||
|
|
||||
width: 90%; |
|
||||
height: 70%; |
|
||||
padding: 10px; |
|
||||
position: relative; |
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 1) 0%, rgba(250, 245, 235, 1) 100%); |
|
||||
border-radius: 10px; |
|
||||
border-radius: 10px; |
|
||||
} |
|
||||
.work-name { |
|
||||
opacity: 1; |
|
||||
/** 文本1 */ |
|
||||
font-size: 1.6rem; |
|
||||
font-weight: 700; |
|
||||
letter-spacing: 0px; |
|
||||
color: rgba(53, 56, 112, 1); |
|
||||
text-align: left; |
|
||||
/*左对齐*/ |
|
||||
vertical-align: top; |
|
||||
/* 这个属性在 Flex 容器中不起作用,将被移除 */ |
|
||||
display: flex; |
|
||||
/* 启用 Flexbox 布局 */ |
|
||||
align-items: center; |
|
||||
/* 垂直居中 */ |
|
||||
height: 30%; |
|
||||
/* 设置高度,根据需要调整 */ |
|
||||
width: 50%; |
|
||||
/* 如果需要,也可以设置宽度 */ |
|
||||
} |
|
||||
.work-content { |
|
||||
width: 90%; |
|
||||
height: 35%; |
|
||||
position: absolute; |
|
||||
bottom: 10%; |
|
||||
display: flex; |
|
||||
} |
|
||||
|
|
||||
.work-time { |
|
||||
position: absolute; |
|
||||
display: flex; |
|
||||
width: 70%; |
|
||||
bottom: 20%; |
|
||||
} |
|
||||
|
|
||||
.deadline { |
|
||||
color: rgba(142, 142, 142, 1); |
|
||||
font-size: 14px; |
|
||||
opacity: 1; |
|
||||
} |
|
||||
|
|
||||
.work-status { |
|
||||
display: inline-block; |
|
||||
background: rgba(53, 56, 112, 0.1); |
|
||||
padding: 0.5% 2%; |
|
||||
text-align: center; |
|
||||
color: #353870; |
|
||||
font-size: 1rem; |
|
||||
border-radius: 5px; |
|
||||
opacity: 2; |
|
||||
margin-left: 5px; |
|
||||
} |
|
||||
.work-status2 { |
|
||||
display: inline-block; |
|
||||
background: #ffe1ae; |
|
||||
padding: 0.5% 2%; |
|
||||
text-align: center; |
|
||||
color: #353870; |
|
||||
font-size: 1rem; |
|
||||
border-radius: 5px; |
|
||||
opacity: 2; |
|
||||
margin-left: 5px; |
|
||||
} |
|
||||
|
|
||||
.work-bottem { |
|
||||
cursor: pointer; |
|
||||
display: flex; |
|
||||
position: absolute; |
|
||||
width: 25%; |
|
||||
height: 70%; |
|
||||
right: 0%; |
|
||||
bottom: 2%; |
|
||||
opacity: 1; |
|
||||
border-radius: 50px; |
|
||||
background: linear-gradient(270deg, rgba(4, 15, 179, 1) 0%, rgba(120, 89, 255, 1) 100%); |
|
||||
border: 1px solid #a5e0f3; |
|
||||
justify-content: center; |
|
||||
/* 水平居中 */ |
|
||||
align-items: center; |
|
||||
/* 垂直居中 */ |
|
||||
text-align: center; |
|
||||
/* 确保文本在其容器内居中 */ |
|
||||
} |
|
||||
|
|
||||
.write { |
|
||||
opacity: 1; |
|
||||
/** 文本1 */ |
|
||||
padding: auto; |
|
||||
font-size: 1.125rem; |
|
||||
font-weight: 700; |
|
||||
letter-spacing: 0px; |
|
||||
line-height: 26.06px; |
|
||||
color: rgba(255, 255, 255, 1); |
|
||||
} |
|
||||
} |
|
||||
/* 电脑 */ |
|
||||
@media (min-width: 1280px) { |
|
||||
.container { |
|
||||
width: 27%; |
|
||||
margin: auto; |
|
||||
} |
|
||||
.works { |
|
||||
/* ../api/ShowApi |
|
||||
work\src\assets\bg@3x.png */ |
|
||||
background-image: url('../assets/bg@3x.png'); |
|
||||
background-color: #8f98f6; |
|
||||
width: 100%; |
|
||||
min-height: 100vh; |
|
||||
position: relative; |
|
||||
margin: auto; |
|
||||
background-size: 100% 100%; |
|
||||
} |
|
||||
.work-name { |
|
||||
opacity: 1; |
|
||||
/** 文本1 */ |
|
||||
font-size: 1.4vw; |
|
||||
font-weight: 700; |
|
||||
letter-spacing: 0px; |
|
||||
color: rgba(53, 56, 112, 1); |
|
||||
text-align: left; |
|
||||
/*左对齐*/ |
|
||||
vertical-align: top; |
|
||||
/* 这个属性在 Flex 容器中不起作用,将被移除 */ |
|
||||
display: flex; |
|
||||
/* 启用 Flexbox 布局 */ |
|
||||
align-items: center; |
|
||||
/* 垂直居中 */ |
|
||||
height: 30%; |
|
||||
/* 设置高度,根据需要调整 */ |
|
||||
width: 70%; |
|
||||
} |
|
||||
|
|
||||
.work-list { |
|
||||
width: 95%; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
flex-direction: column; |
|
||||
margin: auto; |
|
||||
} |
|
||||
|
|
||||
.list { |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
width: 97%; |
|
||||
height: 17vh; |
|
||||
opacity: 1; |
|
||||
border-radius: 10px; |
|
||||
background-color: rgba(255, 225, 174, 1); |
|
||||
margin-bottom: 3%; |
|
||||
} |
|
||||
|
|
||||
.work-item { |
|
||||
|
|
||||
width: 90%; |
|
||||
height: 70%; |
|
||||
padding: 10px; |
|
||||
position: relative; |
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 1) 0%, rgba(250, 245, 235, 1) 100%); |
|
||||
border-radius: 10px; |
|
||||
border-radius: 10px; |
|
||||
} |
|
||||
.work-content { |
|
||||
width: 90%; |
|
||||
height: 35%; |
|
||||
position: absolute; |
|
||||
bottom: 10%; |
|
||||
display: flex; |
|
||||
} |
|
||||
|
|
||||
.work-time { |
|
||||
position: absolute; |
|
||||
display: flex; |
|
||||
width: 70%; |
|
||||
bottom: 15%; |
|
||||
} |
|
||||
|
|
||||
.deadline { |
|
||||
color: rgba(142, 142, 142, 1); |
|
||||
font-size: 14px; |
|
||||
opacity: 1; |
|
||||
align-items: center; |
|
||||
padding-top: 0.2vw; |
|
||||
} |
|
||||
|
|
||||
.work-status { |
|
||||
display: inline-block; |
|
||||
background: rgba(53, 56, 112, 0.1); |
|
||||
padding: 0.5% 2%; |
|
||||
text-align: center; |
|
||||
color: #353870; |
|
||||
font-size: 1rem; |
|
||||
border-radius: 5px; |
|
||||
opacity: 2; |
|
||||
margin-left: 5px; |
|
||||
} |
|
||||
.work-status2 { |
|
||||
display: inline-block; |
|
||||
background: #ffe1ae; |
|
||||
padding: 0.5% 2%; |
|
||||
text-align: center; |
|
||||
color: #353870; |
|
||||
font-size: 1rem; |
|
||||
border-radius: 5px; |
|
||||
opacity: 2; |
|
||||
margin-left: 5px; |
|
||||
} |
|
||||
.work-bottem { |
|
||||
cursor: pointer; |
|
||||
display: flex; |
|
||||
position: absolute; |
|
||||
width: 25%; |
|
||||
height: 70%; |
|
||||
right: 0%; |
|
||||
bottom: 2%; |
|
||||
opacity: 1; |
|
||||
border-radius: 50px; |
|
||||
background: linear-gradient(270deg, rgba(4, 15, 179, 1) 0%, rgba(120, 89, 255, 1) 100%); |
|
||||
border: 1px solid #a5e0f3; |
|
||||
justify-content: center; |
|
||||
/* 水平居中 */ |
|
||||
align-items: center; |
|
||||
/* 垂直居中 */ |
|
||||
text-align: center; |
|
||||
/* 确保文本在其容器内居中 */ |
|
||||
} |
|
||||
|
|
||||
.write { |
|
||||
opacity: 1; |
|
||||
/** 文本1 */ |
|
||||
padding: auto; |
|
||||
font-size: 1.125rem; |
|
||||
font-weight: 700; |
|
||||
letter-spacing: 0px; |
|
||||
line-height: 26.06px; |
|
||||
color: rgba(255, 255, 255, 1); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
.work-list{ |
|
||||
margin-top: 12%; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
</style> |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue