Browse Source

修正代码

admin_zwk
zhaowenkang 5 months ago
parent
commit
4e3e67047d
  1. 2
      work/package.json
  2. 17
      work/src/api/AddWorkApi.js
  3. 20
      work/src/api/ClassListApi.js
  4. 12
      work/src/api/LoginApi.js
  5. 20
      work/src/api/UpdateWorkApi.js
  6. 89
      work/src/api/index.js
  7. 48
      work/src/router/index.js
  8. 403
      work/src/views/AddWork.vue
  9. 366
      work/src/views/DoHomeworkView.vue
  10. 258
      work/src/views/HomeWork.vue
  11. 145
      work/src/views/Login.vue
  12. 535
      work/src/views/UpdateWork.vue
  13. 391
      work/src/views/WorkDetail.vue
  14. 563
      work/src/views/WorksShowView.vue
  15. 2
      work/vite.config.js

2
work/package.json

@ -4,7 +4,7 @@
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite",
"dev": "vite --host 0.0.0.0",
"build": "vite build", "build": "vite build",
"preview": "vite preview" "preview": "vite preview"
}, },

17
work/src/api/AddWorkApi.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;

20
work/src/api/ClassListApi.js

@ -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;

12
work/src/api/LoginApi.js

@ -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;

20
work/src/api/UpdateWorkApi.js

@ -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;

89
work/src/api/index.js

@ -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;

48
work/src/router/index.js

@ -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

403
work/src/views/AddWork.vue

@ -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 }) => {
// idarticle.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>

366
work/src/views/DoHomeworkView.vue

@ -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>

258
work/src/views/HomeWork.vue

@ -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);
// // axiostoken
// // 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>

145
work/src/views/Login.vue

@ -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>

535
work/src/views/UpdateWork.vue

@ -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; // stringJSON
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) => {
// contentJSON
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使liveidArticleIdliveid
form.value.ArticleId = '';
articleTitle.value = '';
} else if (form.value.ArticleId) {
// 使idform.value.ArticleId
} else if (homeworkData.value.article && homeworkData.value.article.id) {
// 使idhomeworkData.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 }) => {
// idarticle.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>

391
work/src/views/WorkDetail.vue

@ -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.valueid.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>

563
work/src/views/WorksShowView.vue

@ -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>

2
work/vite.config.js

@ -16,7 +16,7 @@ export default defineConfig({
server: { server: {
proxy: { proxy: {
'/api': { '/api': {
target: 'http://192.168.8.191:8080',
target: 'http://192.168.9.19:8080',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '') rewrite: (path) => path.replace(/^\/api/, '')
}, },

Loading…
Cancel
Save