12 changed files with 21 additions and 1895 deletions
-
17work/src/api/AddWorkApi.js
-
20work/src/api/ClassListApi.js
-
12work/src/api/LoginApi.js
-
20work/src/api/UpdateWorkApi.js
-
83work/src/api/index.js
-
30work/src/router/index.js
-
402work/src/views/AddWork.vue
-
251work/src/views/HomeWork.vue
-
149work/src/views/Login.vue
-
532work/src/views/UpdateWork.vue
-
388work/src/views/WorkDetail.vue
-
6work/src/views/WorksShowView.vue
@ -1,17 +0,0 @@ |
|||
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; |
@ -1,20 +0,0 @@ |
|||
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; |
@ -1,12 +0,0 @@ |
|||
import service from "."; |
|||
const LoginApi={ |
|||
//登录
|
|||
login(username,password){ |
|||
return service.post("/api/login",username,password) |
|||
}, |
|||
//退出登录
|
|||
logout(token){ |
|||
return service.post("/api/logout",token) |
|||
} |
|||
} |
|||
export default LoginApi; |
@ -1,20 +0,0 @@ |
|||
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,83 +1,30 @@ |
|||
// 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({ |
|||
// baseURL: 'http://192.168.8.191:8080',
|
|||
// baseURL: 'http://localhost:8080',
|
|||
baseURL: '/api', |
|||
}); |
|||
|
|||
// Axios的请求拦截器,在这里添加token到请求头
|
|||
|
|||
axios.interceptors.request.use(config => { |
|||
const token = useTokenStore(); |
|||
// 添加请求拦截器
|
|||
service.interceptors.request.use( |
|||
config => { |
|||
// 假设你的token存储在Vuex、Pinia或者本地存储中,这里直接用一个变量代替
|
|||
// 请确保在实际应用中从安全的地方获取token
|
|||
const token = "9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs"; |
|||
if (token) { |
|||
config.headers.token = `${token}`; |
|||
config.headers['token'] = ` ${token}`; |
|||
} |
|||
return config; |
|||
}, error => { |
|||
}, |
|||
error => { |
|||
return Promise.reject(error); |
|||
}); |
|||
|
|||
service.interceptors.request.use(config => { |
|||
const token = useTokenStore(); |
|||
if (token) { |
|||
// 一般后端会约定一个请求头的字段名来接收token,常见的如 'Authorization',并要求按照一定格式传递,比如 'Bearer <token>',这里按照此格式添加,你需要根据后端实际要求调整
|
|||
config.headers.token = `${token}`; |
|||
} |
|||
return config; |
|||
); |
|||
|
|||
// 添加响应拦截器
|
|||
service.interceptors.response.use(resp => { |
|||
return resp.data; |
|||
}, 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.status == 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; |
@ -1,402 +0,0 @@ |
|||
<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+'--------------') |
|||
} |
|||
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,251 +0,0 @@ |
|||
<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>财富的游戏</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 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('/') |
|||
// } |
|||
|
|||
//退出 |
|||
function logout(){ |
|||
//清除登录信息 |
|||
const tokenStore = useTokenStore(); |
|||
const userStore = useUserStore(); |
|||
tokenStore.clear(); |
|||
userStore.clear(); |
|||
LoginApi.logout().then(res => { |
|||
console.log(res) |
|||
}) |
|||
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> |
@ -1,149 +0,0 @@ |
|||
<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'; |
|||
// 使用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; |
|||
// 将token存储到localStorage中,键名为'token',你可以根据实际情况调整键名 |
|||
localStorage.setItem('token', token.value); |
|||
// 设置axios的请求拦截器,将token添加到后续请求的请求头中 |
|||
axios.interceptors.request.use(config => { |
|||
//config.headers.token = `${token.value}`; |
|||
config.headers['token'] = token.value; |
|||
return config; |
|||
}); |
|||
console.log(token.value); |
|||
// 登录成功提示 |
|||
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> |
@ -1,532 +0,0 @@ |
|||
<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 = ''; |
|||
} 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; |
|||
} |
|||
ClassListApi.editWork(form.value) |
|||
.then((response) => { |
|||
console.log(response); |
|||
ElMessage.success('编辑成功'); |
|||
router.push('/list') |
|||
}) |
|||
.catch((error) => { |
|||
console.error('编辑失败', error); |
|||
ElMessage.error('编辑失败'); |
|||
}); |
|||
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 (form.value.ArticleId) { |
|||
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> |
@ -1,388 +0,0 @@ |
|||
<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" /> |
|||
<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 () => { |
|||
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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue