You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
12 KiB

5 months ago
  1. <template>
  2. <div class="common-layout">
  3. <el-container>
  4. <el-header class="header">
  5. <el-text class="header-text">抢点班作业后台管理</el-text>
  6. <el-button class="header-button" type="primary" text style="float: right;" @click="logout">退出登录</el-button>
  7. </el-header>
  8. <el-main class="main">
  9. <div class="main-title">
  10. <div class="main-title-text" style="float: left;">
  11. 新建作业
  12. </div>
  13. <div>
  14. <el-button class="main-button" @click="back">返回上一页</el-button>
  15. </div>
  16. </div>
  17. <div class="main-back">
  18. <el-form :model="form" label-width="auto" style="max-width: 700px" size="large">
  19. <el-form-item label="作业名称">
  20. <el-input v-model="form.Name" placeholder="请输入"></el-input>
  21. </el-form-item>
  22. <el-form-item label="提交时间" style="width: 70%">
  23. <el-date-picker v-model="form.picker" type="daterange" range-separator="" start-placeholder="开始日期"
  24. end-placeholder="结束日期" />
  25. </el-form-item>
  26. <el-form-item label="作业归属">
  27. <el-select v-model="form.ClubType" placeholder="请选择" style="width: 100%">
  28. <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
  29. </el-select>
  30. </el-form-item>
  31. <el-form-item label="关联文章">
  32. <el-autocomplete v-model="articleTitle" :fetch-suggestions="queryArticleList" placeholder="请输入"
  33. @select="handleSelectArticle" clearable @change="handleArticleChange"/>
  34. </el-form-item>
  35. <el-form-item label="关联直播">
  36. <el-select v-model="form.LiveId" placeholder="请选择" style="width: 100%" clearable @change="handleLiveChange">
  37. <el-option v-for="item in live" :key="item.id" :label="item.name" :value="item.id" />
  38. </el-select>
  39. </el-form-item>
  40. <el-form-item label="选择类型">
  41. <div>
  42. <el-button type="primary" @click="addSingleChoice">添加单选</el-button>
  43. <el-button type="primary" @click="addMultipleChoice">添加多选</el-button>
  44. <el-button type="primary" @click="addBlank">添加单选填空</el-button>
  45. </div>
  46. </el-form-item>
  47. <div class="question-container" v-for="(question, index) in questions" :key="index"
  48. :class="{ 'bg-change': isHovered[index] }" @mouseenter="handleMouseEnter(index)"
  49. @mouseleave="handleMouseLeave(index)">
  50. <div class="question-title">
  51. {{ questionPrefix(index) }} {{ getQuestionTypeText(question.type) }}
  52. </div>
  53. <div style="width: 600px;">
  54. <el-input v-model="question.description" />
  55. </div>
  56. <div class="add" v-if="question.type !== 'blank'">
  57. <div class="question-option">
  58. <span>设置选项:</span>
  59. <el-button type="primary" text @click="addOption(index)">添加</el-button>
  60. </div>
  61. <div v-for="(option, optionIndex) in question.content" :key="optionIndex">
  62. <div class="select" style="display: flex;">
  63. <div class="selection-item" style="display: flex;">
  64. <div style="width: 550px;">
  65. <el-input v-model="question.content[optionIndex].text" />
  66. </div>
  67. <div>
  68. <el-button type="primary" text @click="removeOption(index, optionIndex)">删除</el-button>
  69. </div>
  70. </div>
  71. </div>
  72. </div>
  73. <div class="delete" style="margin-left: 50px;">
  74. <el-button type="info" plain @click="removeQuestion(index)">删除</el-button>
  75. </div>
  76. </div>
  77. </div>
  78. <div class="submit">
  79. <el-button type="primary" :disabled="!form.Name||!form.picker" @click="onSubmit">确认</el-button>
  80. </div>
  81. </el-form>
  82. </div>
  83. </el-main>
  84. </el-container>
  85. </div>
  86. </template>
  87. <script lang="ts" setup>
  88. import { ref, onMounted, computed } from 'vue'
  89. import AddWorkApi from '../api/AddWorkApi';
  90. import _ from 'lodash';
  91. import dayjs from 'dayjs';
  92. import { ElMessage } from 'element-plus'
  93. import LoginApi from '../api/LoginApi';
  94. import axios from 'axios';
  95. import { useRouter } from 'vue-router';
  96. import { useTokenStore } from '../stores/token';
  97. import { useUserStore } from '../stores/user';
  98. const router = useRouter();
  99. const options = ref([
  100. { id: 1, name: '牧民俱乐部' },
  101. { id: 2, name: '博古论坛' },
  102. { id: 3, name: '神枪手俱乐部' },
  103. { id: 4, name: '环球俱乐部' },
  104. { id: 5, name: '价值投资' },
  105. { id: 6, name: '波段行情' },
  106. { id: 7, name: '抄底卖顶' },
  107. { id: 8, name: '资金及仓位管理' },
  108. { id: 9, name: '财富的游戏' },
  109. ]);
  110. // do not use same name with ref
  111. const form = ref({
  112. Name: '',
  113. ClubType: '',
  114. ArticleId: '',
  115. LiveId: '',
  116. picker: [],
  117. StartDate: '',
  118. EndDate: '',
  119. Questions: []
  120. });
  121. const articleTitle = ref('');
  122. // 问题列表数据
  123. const questions = ref([]);
  124. const onSubmit = () => {
  125. // 从picker中获取日期数据并进行格式转换
  126. if (form.value.picker && form.value.picker.length === 2) {
  127. const startDate = dayjs(form.value.picker[0]).format('YYYY-MM-DD HH:mm:00');
  128. const endDate = dayjs(form.value.picker[1]).format('YYYY-MM-DD HH:mm:00');
  129. form.value.StartDate = startDate;
  130. form.value.EndDate = endDate;
  131. }
  132. form.value.Questions = questions.value;
  133. AddWorkApi.addWork(form.value)
  134. console.log(questions.value+'--------------')
  135. ElMessage.success('添加成功');
  136. router.push('/list')
  137. }
  138. const back = () => {
  139. window.history.back()
  140. }
  141. // 存储根据文章输入内容查询到的关联文章结果列表
  142. const articleSearchResults = ref([]);
  143. // 根据文章输入内容查询关联文章的函数
  144. const queryArticleList = async (queryString: string) => {
  145. if (form.value.LiveId) {
  146. ElMessage.warning('您已关联直播,暂无法关联文章');
  147. articleTitle.value = ''; // 清空文章标题输入框
  148. form.value.LiveId = '';
  149. return [];
  150. }
  151. try {
  152. const response = await AddWorkApi.getArticleList(queryString);
  153. const formattedResults = response.data.map(article => ({
  154. value: article.title,
  155. label: article.id
  156. }));
  157. articleSearchResults.value = formattedResults;
  158. return formattedResults;
  159. } catch (error) {
  160. console.error('查询关联文章失败', error);
  161. return [];
  162. }
  163. };
  164. // 处理选择文章的函数
  165. const handleSelectArticle = (article: { label: string }) => {
  166. // 这里可以根据业务需求,比如将选中的文章id(article.label)传递给其他地方使用等
  167. console.log('选中的文章id', article.label);
  168. form.value.ArticleId = article.label; // 将选中文章的id赋值给对应表单字段,用于传递给后端
  169. const selectedArticle = articleSearchResults.value.find(a => a.label === article.label);
  170. if (selectedArticle) {
  171. articleTitle.value = selectedArticle.value; // 更新显示的文章题目
  172. }
  173. };
  174. const handleLiveChange = () => {
  175. if (form.value.ArticleId) {
  176. ElMessage.warning('您已关联文章,暂无法关联直播');
  177. form.value.LiveId = ''; // 清空关联直播选择框的值
  178. form.value.ArticleId = '';
  179. articleTitle.value = '';
  180. }
  181. };
  182. //获取直播列表
  183. const live = ref([]);
  184. function getLive() {
  185. AddWorkApi.getLiveList()
  186. .then(res => {
  187. live.value = res.data;
  188. console.log(live.value);
  189. })
  190. .catch(error => {
  191. console.error('获取直播列表失败', error)
  192. })
  193. }
  194. getLive();
  195. // 根据类型获取对应的题目类型文本显示
  196. const getQuestionTypeText = (type) => {
  197. switch (type) {
  198. case 1:
  199. return '作业题目(单选)';
  200. case 2:
  201. return '作业题目(多选)';
  202. case 3:
  203. return '作业题目(简答题)';
  204. default:
  205. return '未知类型题目';
  206. }
  207. };
  208. const addSingleChoice = () => {
  209. questions.value.push({
  210. type: 1, // 假设1代表单选,和后端格式对应起来
  211. description: '',
  212. content: [{ "id": "", "text": "" },{ "id": "", "text": "" }]
  213. });
  214. };
  215. const addMultipleChoice = () => {
  216. questions.value.push({
  217. type: 2, // 假设2代表多选,和后端格式对应起来
  218. description: '',
  219. content: [{ "id": "", "text": "" },{ "id": "", "text": "" }]
  220. });
  221. };
  222. const addBlank = () => {
  223. questions.value.push({
  224. type: 3, // 假设3代表简答题,和后端格式对应起来
  225. description: '',
  226. content: [{ "id": "", "text": "" }]
  227. });
  228. };
  229. // const addOption = (questionIndex) => {
  230. // const currentQuestion = questions.value[questionIndex];
  231. // const currentContent = JSON.parse(currentQuestion.content);
  232. // currentContent.push({ "id": "", "text": "" });
  233. // currentQuestion.content = JSON.stringify(currentContent);
  234. // };
  235. // const removeOption = (questionIndex, optionIndex) => {
  236. // const currentQuestion = questions.value[questionIndex];
  237. // const currentContent = JSON.parse(currentQuestion.content);
  238. // currentContent.splice(optionIndex, 1);
  239. // currentQuestion.content = JSON.stringify(currentContent);
  240. // };
  241. const addOption = (questionIndex) => {
  242. const currentQuestion = questions.value[questionIndex];
  243. // 如果当前题目没有content属性,则初始化一个空数组
  244. if (!currentQuestion.content) {
  245. currentQuestion.content = [];
  246. }
  247. currentQuestion.content.push({ id: "", text: "" });
  248. };
  249. const removeOption = (questionIndex, optionIndex) => {
  250. const currentQuestion = questions.value[questionIndex];
  251. currentQuestion.content.splice(optionIndex, 1);
  252. };
  253. const removeQuestion = (questionIndex) => {
  254. questions.value.splice(questionIndex, 1);
  255. };
  256. // 计算属性,用于生成序号前缀
  257. const questionPrefix = computed(() => {
  258. return (index) => {
  259. return `${index + 1}`;
  260. };
  261. })
  262. // 用于存储每个问题标题是否被鼠标悬停的状态,初始化为false
  263. const isHovered = ref(Array(questions.value.length).fill(false));
  264. const handleMouseEnter = (index) => {
  265. isHovered.value[index] = true;
  266. };
  267. const handleMouseLeave = (index) => {
  268. isHovered.value[index] = false;
  269. };
  270. // 在组件挂载后初始化 `isHovered` 数组长度与 `questions` 数组长度一致
  271. onMounted(() => {
  272. isHovered.value = Array(questions.value.length).fill(false);
  273. });
  274. //退出
  275. function logout(){
  276. //清除登录信息
  277. const tokenStore = useTokenStore();
  278. const userStore = useUserStore();
  279. tokenStore.clear();
  280. userStore.clear();
  281. LoginApi.logout().then(res => {
  282. console.log(res)
  283. })
  284. router.push('/')
  285. }
  286. </script>
  287. <style scoped>
  288. .submit {
  289. margin: 100px 212px;
  290. }
  291. .submit .el-button {
  292. padding: 25px 150px;
  293. }
  294. .question-title {
  295. transition: background-color 0.3s ease;
  296. }
  297. .bg-change {
  298. background-color: rgba(200, 200, 200, 0.3);
  299. }
  300. .question-title {
  301. margin-bottom: 10px;
  302. }
  303. .select {
  304. margin: 10px 0px 0px;
  305. }
  306. .delete {
  307. position: absolute;
  308. right: 10px;
  309. bottom: 0px;
  310. }
  311. .add {
  312. position: relative;
  313. }
  314. .question-container {
  315. margin: 20px 0;
  316. padding: 10px 20px;
  317. width: 750px;
  318. border-bottom: 1px solid #e5e5e5;
  319. }
  320. .header {
  321. height: 100px;
  322. line-height: 100px;
  323. padding: 0 80px;
  324. }
  325. .header-text {
  326. font-size: 22px;
  327. font-weight: 500;
  328. color: black;
  329. float: left;
  330. }
  331. .header-button {
  332. margin-top: 30px;
  333. }
  334. .main {
  335. padding: 30px 212px;
  336. background-color: #F8F8F8;
  337. }
  338. .main-title {
  339. font-size: 16px;
  340. background-color: white;
  341. font-weight: bold;
  342. height: 60px;
  343. border-bottom: 2px solid #ececec;
  344. padding: 0 15px;
  345. line-height: 52px;
  346. }
  347. .main-button {
  348. margin: 10px 15px 0 0;
  349. padding: 12px 20px;
  350. height: 40px;
  351. float: right;
  352. }
  353. .el-form {
  354. padding: 30px 78.5px;
  355. margin: auto;
  356. }
  357. .el-form-item {
  358. --font-size: 16px;
  359. margin: 0 0 25px;
  360. }
  361. .main-back {
  362. background-color: white;
  363. }
  364. </style>