北斗应用技术培训考试题库
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
|
/cypress/videos/
|
||||||
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
*.tsbuildinfo
|
||||||
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# open-map-assistant
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 in Vite.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||||
|
|
||||||
|
## Customize configuration
|
||||||
|
|
||||||
|
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||||
|
|
||||||
|
## Project Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Hot-Reload for Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Minify for Production
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
49
index.html
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="w-h-full">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="icon" href="/src/assets/bdjy.png">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="UTF-8">
|
||||||
|
<title>题库</title>
|
||||||
|
<style>
|
||||||
|
/* 当屏幕宽度大于或等于3000px时 */
|
||||||
|
@media (min-width: 3000px) {
|
||||||
|
html {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度在1920px到2999px之间时 */
|
||||||
|
@media (min-width: 1920px) and (max-width: 2999px) {
|
||||||
|
html {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度在750px到1919px之间时 */
|
||||||
|
@media (min-width: 750px) and (max-width: 1919px) {
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度在600px到749px之间时 */
|
||||||
|
@media (min-width: 600px) and (max-width: 749px) {
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度小于600px时 */
|
||||||
|
@media (max-width: 599px) {
|
||||||
|
html {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="w-h-full">
|
||||||
|
<div id="app" class="w-h-full text-white"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
8
jsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
36
package.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "bd-training-exam-topic",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --port=7023",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
|
"axios": "^1.6.8",
|
||||||
|
"bd-training-exam-topic": "file:",
|
||||||
|
"core-js": "^3.37.0",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
|
"element-plus": "^2.7.2",
|
||||||
|
"fingerprintjs2": "^2.1.4",
|
||||||
|
"moment": "^2.30.1",
|
||||||
|
"pinia": "^2.1.7",
|
||||||
|
"pinia-plugin-persist": "^1.0.0",
|
||||||
|
"vue": "^3.4.21",
|
||||||
|
"vue-i18n": "^9.13.1",
|
||||||
|
"vue-router": "^4.3.0",
|
||||||
|
"zipson": "^0.2.12"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
|
"postcss": "^8.4.38",
|
||||||
|
"tailwindcss": "^3.4.3",
|
||||||
|
"unplugin-auto-import": "^0.17.5",
|
||||||
|
"unplugin-vue-components": "^0.27.0",
|
||||||
|
"vite": "^5.2.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 72 KiB |
9
src/App.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<script setup>
|
||||||
|
import { RouterView } from "vue-router";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<RouterView />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
63
src/api/index.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import router from "../router";
|
||||||
|
|
||||||
|
// 添加请求拦截器
|
||||||
|
axios.interceptors.request.use(function (config) {
|
||||||
|
// 在发送请求之前做些什么
|
||||||
|
if (localStorage.data && localStorage.data !== "" && localStorage.data !== null && localStorage.data !== undefined && localStorage.data !== NaN) {
|
||||||
|
if (config.headers) {
|
||||||
|
config.headers.authorization = localStorage.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}, function (error) {
|
||||||
|
// 对请求错误做些什么
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 转到登录页面
|
||||||
|
const toLogin = () => {
|
||||||
|
// localStorage.clear();
|
||||||
|
router.push({ path: '/initialService' });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加响应拦截器
|
||||||
|
let result = true;
|
||||||
|
axios.interceptors.response.use(function (response) {
|
||||||
|
// 2xx 范围内的状态码都会触发该函数。
|
||||||
|
// 对响应数据做点什么
|
||||||
|
if (response.data.code === 200) {
|
||||||
|
if ("data" in response.data) {
|
||||||
|
localStorage.setItem("data", response.data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (response.data.code === 401 && result) {
|
||||||
|
result = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
result = true;
|
||||||
|
}, 1000);
|
||||||
|
toLogin();
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}, function (error) {
|
||||||
|
// 超出 2xx 范围的状态码都会触发该函数。
|
||||||
|
// 对响应错误做点什么
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
get(url, query = {}) {
|
||||||
|
return axios.get(url, {
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
},
|
||||||
|
post(url, body) {
|
||||||
|
return axios.post(url, body);
|
||||||
|
},
|
||||||
|
put(url, body) {
|
||||||
|
return axios.put(url, body);
|
||||||
|
},
|
||||||
|
del(url) {
|
||||||
|
return axios.delete(url);
|
||||||
|
},
|
||||||
|
}
|
||||||
14
src/api/url.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export default {
|
||||||
|
// 题库登录接口
|
||||||
|
login: "/bdTrainingExamTopic/login",
|
||||||
|
// 获取题库登录状态接口
|
||||||
|
loginStatus: "/bdTrainingExamTopic/loginStatus",
|
||||||
|
// 获取单选题接口
|
||||||
|
radio: "/bdTrainingExamTopic/radio",
|
||||||
|
// 获取多选题接口
|
||||||
|
multiple: "/bdTrainingExamTopic/multiple",
|
||||||
|
// 获取判断题接口
|
||||||
|
judgment: "/bdTrainingExamTopic/judgment",
|
||||||
|
// 获取问答题接口
|
||||||
|
interlocution: "/bdTrainingExamTopic/interlocution",
|
||||||
|
}
|
||||||
BIN
src/assets/bdjy.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
src/assets/bdjyLogo.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
src/assets/bdqhLogo.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/assets/bg.jpg
Normal file
|
After Width: | Height: | Size: 760 KiB |
BIN
src/assets/certificate.jpg
Normal file
|
After Width: | Height: | Size: 928 KiB |
BIN
src/assets/default.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/exam.jpg
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
src/assets/favicon.ico
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
src/assets/img/BDThemeLesson.jpg
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
src/assets/img/comprehensivePracticalActivities.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/assets/img/correctExample.png
Normal file
|
After Width: | Height: | Size: 843 B |
BIN
src/assets/img/ephemeris_search.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/img/errorsExample.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
src/assets/img/interferenceSimulation.png
Normal file
|
After Width: | Height: | Size: 4.7 MiB |
BIN
src/assets/img/mapTheCampus.jpg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
src/assets/img/nmea0183-thumbnail.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
src/assets/img/tdt-thumbnail.jpg
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/img/trajectory.jpg
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
1
src/assets/logo.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||||
|
After Width: | Height: | Size: 276 B |
9
src/assets/main.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.w-h-full {
|
||||||
|
@apply w-full h-full m-0 p-0 overflow-hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/assets/qrcode.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
src/assets/training.jpg
Normal file
|
After Width: | Height: | Size: 125 KiB |
83
src/components/database/interlocution.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div style="height: 90%" class="flex justify-center items-center">
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset > 1" direction="left" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
<div class="grow">
|
||||||
|
<Interlocution v-if="topic.length > 0" :topic="topic[0]" />
|
||||||
|
<el-text v-if="topic.length == 0" style="font-weight: bold; color: red">
|
||||||
|
暂无题目
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset < pageCount" direction="right" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 10%">
|
||||||
|
<Jump
|
||||||
|
v-if="topic.length > 0"
|
||||||
|
ref="jumpRef"
|
||||||
|
:id="topic.length > 0 ? topic[0].id : 0"
|
||||||
|
:min="min"
|
||||||
|
:count="pageCount"
|
||||||
|
@jumpToTopic="jumpToTopic"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
import Interlocution from "../topic/interlocution.vue";
|
||||||
|
import Page from "../operate/page.vue";
|
||||||
|
import Jump from "../operate/jump.vue";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
const offset = ref(1);
|
||||||
|
const min = ref(1);
|
||||||
|
const pageCount = ref(0);
|
||||||
|
const topic = ref([]);
|
||||||
|
const jumpRef = ref(null);
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const data = {
|
||||||
|
offset: offset.value,
|
||||||
|
};
|
||||||
|
$http.post($url.interlocution, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
min.value = res.data.min;
|
||||||
|
pageCount.value = res.data.count;
|
||||||
|
topic.value = res.data.rows;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const flip = (direction) => {
|
||||||
|
if (direction === "left" && offset.value > 1) {
|
||||||
|
offset.value--;
|
||||||
|
} else if (direction === "right" && offset.value < pageCount.value) {
|
||||||
|
offset.value++;
|
||||||
|
}
|
||||||
|
jumpRef.value.topicId = offset.value;
|
||||||
|
init();
|
||||||
|
};
|
||||||
|
|
||||||
|
const jumpToTopic = (topicId) => {
|
||||||
|
if (topicId == null) {
|
||||||
|
return;
|
||||||
|
} else if (topicId == 0 || topicId > pageCount.value) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
offset.value = topicId;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
93
src/components/database/judgment.vue
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div style="height: 90%" class="flex justify-center items-center">
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset > 1" direction="left" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
<div class="grow">
|
||||||
|
<Judgment
|
||||||
|
ref="judgmentRef"
|
||||||
|
v-if="topic.length > 0"
|
||||||
|
:topic="topic[0]"
|
||||||
|
:checked="checked"
|
||||||
|
/>
|
||||||
|
<el-text v-if="topic.length == 0" style="font-weight: bold; color: red">
|
||||||
|
暂无题目
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset < pageCount" direction="right" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 10%">
|
||||||
|
<Jump
|
||||||
|
v-if="topic.length > 0"
|
||||||
|
ref="jumpRef"
|
||||||
|
:id="topic.length > 0 ? topic[0].id : 0"
|
||||||
|
:min="min"
|
||||||
|
:count="pageCount"
|
||||||
|
@jumpToTopic="jumpToTopic"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
import Judgment from "../topic/judgment.vue";
|
||||||
|
import Page from "../operate/page.vue";
|
||||||
|
import Jump from "../operate/jump.vue";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
const props = defineProps({ checked: Boolean });
|
||||||
|
|
||||||
|
const offset = ref(1);
|
||||||
|
const min = ref(1);
|
||||||
|
const pageCount = ref(0);
|
||||||
|
const judgmentRef = ref(null);
|
||||||
|
const topic = ref([]);
|
||||||
|
const jumpRef = ref(null);
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const data = {
|
||||||
|
offset: offset.value,
|
||||||
|
};
|
||||||
|
$http.post($url.judgment, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
min.value = res.data.min;
|
||||||
|
pageCount.value = res.data.count;
|
||||||
|
topic.value = res.data.rows;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const flip = (direction) => {
|
||||||
|
if (direction === "left" && offset.value > 1) {
|
||||||
|
offset.value--;
|
||||||
|
} else if (direction === "right" && offset.value < pageCount.value) {
|
||||||
|
offset.value++;
|
||||||
|
}
|
||||||
|
jumpRef.value.topicId = offset.value;
|
||||||
|
init();
|
||||||
|
judgmentRef.value.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
const jumpToTopic = (topicId) => {
|
||||||
|
if (topicId == null) {
|
||||||
|
return;
|
||||||
|
} else if (topicId == 0 || topicId > pageCount.value) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
offset.value = topicId;
|
||||||
|
init();
|
||||||
|
judgmentRef.value.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
93
src/components/database/multiple.vue
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div style="height: 90%" class="flex justify-center items-center">
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset > 1" direction="left" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
<div class="grow">
|
||||||
|
<Multiple
|
||||||
|
ref="multipleRef"
|
||||||
|
v-if="topic.length > 0"
|
||||||
|
:topic="topic[0]"
|
||||||
|
:checked="checked"
|
||||||
|
/>
|
||||||
|
<el-text v-if="topic.length == 0" style="font-weight: bold; color: red">
|
||||||
|
暂无题目
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset < pageCount" direction="right" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 10%">
|
||||||
|
<Jump
|
||||||
|
v-if="topic.length > 0"
|
||||||
|
ref="jumpRef"
|
||||||
|
:id="topic.length > 0 ? topic[0].id : 0"
|
||||||
|
:min="min"
|
||||||
|
:count="pageCount"
|
||||||
|
@jumpToTopic="jumpToTopic"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
import Multiple from "../topic/multiple.vue";
|
||||||
|
import Page from "../operate/page.vue";
|
||||||
|
import Jump from "../operate/jump.vue";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
const props = defineProps({ checked: Boolean });
|
||||||
|
|
||||||
|
const offset = ref(1);
|
||||||
|
const min = ref(1);
|
||||||
|
const pageCount = ref(0);
|
||||||
|
const multipleRef = ref(null);
|
||||||
|
const topic = ref([]);
|
||||||
|
const jumpRef = ref(null);
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const data = {
|
||||||
|
offset: offset.value,
|
||||||
|
};
|
||||||
|
$http.post($url.multiple, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
min.value = res.data.min;
|
||||||
|
pageCount.value = res.data.count;
|
||||||
|
topic.value = res.data.rows;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const flip = (direction) => {
|
||||||
|
if (direction === "left" && offset.value > 1) {
|
||||||
|
offset.value--;
|
||||||
|
} else if (direction === "right" && offset.value < pageCount.value) {
|
||||||
|
offset.value++;
|
||||||
|
}
|
||||||
|
jumpRef.value.topicId = offset.value;
|
||||||
|
init();
|
||||||
|
multipleRef.value.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
const jumpToTopic = (topicId) => {
|
||||||
|
if (topicId == null) {
|
||||||
|
return;
|
||||||
|
} else if (topicId == 0 || topicId > pageCount.value) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
offset.value = topicId;
|
||||||
|
init();
|
||||||
|
multipleRef.value.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
93
src/components/database/radio.vue
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div style="height: 90%" class="flex justify-center items-center">
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset > 1" direction="left" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
<div class="grow">
|
||||||
|
<Radio
|
||||||
|
ref="radioRef"
|
||||||
|
v-if="topic.length > 0"
|
||||||
|
:topic="topic[0]"
|
||||||
|
:checked="checked"
|
||||||
|
/>
|
||||||
|
<el-text v-if="topic.length == 0" style="font-weight: bold; color: red">
|
||||||
|
暂无题目
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
<div style="width: 10%">
|
||||||
|
<Page :showNow="offset < pageCount" direction="right" @flip="flip" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: 10%">
|
||||||
|
<Jump
|
||||||
|
v-if="topic.length > 0"
|
||||||
|
ref="jumpRef"
|
||||||
|
:id="topic.length > 0 ? topic[0].id : 0"
|
||||||
|
:min="min"
|
||||||
|
:count="pageCount"
|
||||||
|
@jumpToTopic="jumpToTopic"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
import Radio from "../topic/radio.vue";
|
||||||
|
import Page from "../operate/page.vue";
|
||||||
|
import Jump from "../operate/jump.vue";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
const props = defineProps({ checked: Boolean });
|
||||||
|
|
||||||
|
const offset = ref(1);
|
||||||
|
const min = ref(1);
|
||||||
|
const pageCount = ref(0);
|
||||||
|
const radioRef = ref(null);
|
||||||
|
const topic = ref([]);
|
||||||
|
const jumpRef = ref(null);
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const data = {
|
||||||
|
offset: offset.value,
|
||||||
|
};
|
||||||
|
$http.post($url.radio, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
min.value = res.data.min;
|
||||||
|
pageCount.value = res.data.count;
|
||||||
|
topic.value = res.data.rows;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const flip = (direction) => {
|
||||||
|
if (direction === "left" && offset.value > 1) {
|
||||||
|
offset.value--;
|
||||||
|
} else if (direction === "right" && offset.value < pageCount.value) {
|
||||||
|
offset.value++;
|
||||||
|
}
|
||||||
|
jumpRef.value.topicId = offset.value;
|
||||||
|
init();
|
||||||
|
radioRef.value.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
const jumpToTopic = (topicId) => {
|
||||||
|
if (topicId == null) {
|
||||||
|
return;
|
||||||
|
} else if (topicId == 0 || topicId > pageCount.value) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
offset.value = topicId;
|
||||||
|
init();
|
||||||
|
radioRef.value.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
38
src/components/operate/jump.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex justify-center items-center">
|
||||||
|
<el-text style="font-weight: bold"> 第 {{ id - min + 1 }} 题 </el-text>
|
||||||
|
|
||||||
|
<el-input
|
||||||
|
v-model="topicId"
|
||||||
|
style="width: 200px; border: 2px solid aqua"
|
||||||
|
placeholder="请输入要跳转到的题目序号"
|
||||||
|
@input="filter"
|
||||||
|
@blur="jumpToTopic"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-text style="font-weight: bold"> 共 {{ count }} 题 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({ id: String, min: String, count: String });
|
||||||
|
|
||||||
|
const emit = defineEmits(["jumpToTopic"]);
|
||||||
|
|
||||||
|
const topicId = ref("");
|
||||||
|
|
||||||
|
const filter = () => {
|
||||||
|
topicId.value = topicId.value.replace(/\D/g, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
const jumpToTopic = () => {
|
||||||
|
emit("jumpToTopic", topicId.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ topicId });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
30
src/components/operate/page.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-icon
|
||||||
|
v-if="showNow && direction == 'left'"
|
||||||
|
style="font-size: 100px; color: #409eff"
|
||||||
|
@click="page('left')"
|
||||||
|
><CaretLeft
|
||||||
|
/></el-icon>
|
||||||
|
<el-icon
|
||||||
|
v-if="showNow && direction == 'right'"
|
||||||
|
style="font-size: 100px; color: #409eff"
|
||||||
|
@click="page('right')"
|
||||||
|
><CaretRight
|
||||||
|
/></el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { CaretLeft, CaretRight } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const props = defineProps({ showNow: Boolean, direction: String });
|
||||||
|
|
||||||
|
const emit = defineEmits(["flip"]);
|
||||||
|
|
||||||
|
const page = (direction) => {
|
||||||
|
emit("flip", direction);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
137
src/components/page/login.vue
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="ruleFormRef"
|
||||||
|
style="max-width: 600px"
|
||||||
|
:model="ruleForm"
|
||||||
|
status-icon
|
||||||
|
:rules="rules"
|
||||||
|
label-width="auto"
|
||||||
|
class="p-6 m-auto flex flex-col justify-center items-center bg-slate-100/70"
|
||||||
|
>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="手机号码" prop="phone">
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请输入手机号码"
|
||||||
|
v-model="ruleForm.phone"
|
||||||
|
@input="filter(ruleForm.phone, 'phone')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="密码" prop="password">
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请输入密码"
|
||||||
|
v-model="ruleForm.password"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
maxlength="16"
|
||||||
|
autocomplete="off"
|
||||||
|
@input="filter(ruleForm.password, 'password')"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false"
|
||||||
|
oncopy="return false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
style="font-weight: bold"
|
||||||
|
type="primary"
|
||||||
|
@click="submitForm(ruleFormRef)"
|
||||||
|
>
|
||||||
|
登录
|
||||||
|
</el-button>
|
||||||
|
<el-button style="font-weight: bold" type="warning" @click="resetForm(ruleFormRef)"
|
||||||
|
>清除</el-button
|
||||||
|
>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, getCurrentInstance } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
const ruleFormRef = ref();
|
||||||
|
|
||||||
|
const phoneRegex = /^(?:13\d|14[579]|15\d|16[67]|17[0135678]|18\d|19[89])\d{8}$/;
|
||||||
|
|
||||||
|
const emit = defineEmits(["changePage"]);
|
||||||
|
|
||||||
|
const validatePhone = (rule, value, callback) => {
|
||||||
|
if (value === "") {
|
||||||
|
callback(new Error("请输入手机号码"));
|
||||||
|
} else if (!phoneRegex.test(value)) {
|
||||||
|
callback(new Error("手机号码格式错误, 请重新输入!"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validatePass = (rule, value, callback) => {
|
||||||
|
if (value === "") {
|
||||||
|
callback(new Error("请输入密码"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ruleForm = reactive({
|
||||||
|
phone: "",
|
||||||
|
password: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
phone: [{ required: true, validator: validatePhone, trigger: "blur" }],
|
||||||
|
password: [{ required: true, validator: validatePass, trigger: "blur" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = (value, label) => {
|
||||||
|
if (label == "phone") {
|
||||||
|
ruleForm.phone = value.replace(/\D/g, "");
|
||||||
|
}
|
||||||
|
if (label == "password") {
|
||||||
|
ruleForm.password = value.replace(/[=\s"'+-]/g, "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
|
const submitForm = (formEl) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
let encryptForm = {
|
||||||
|
phone: proxy.$AES_Encrypt(ruleForm.phone),
|
||||||
|
password: proxy.$AES_Encrypt(ruleForm.password),
|
||||||
|
};
|
||||||
|
$http.post($url.login, encryptForm).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: "登录成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
localStorage.setItem("data", res.data.data);
|
||||||
|
window.location.href = window.location.href.replace("/initialService", "/main");
|
||||||
|
} else {
|
||||||
|
if (res.data.code === 444) {
|
||||||
|
ElMessage.error(res.data.msg);
|
||||||
|
} else {
|
||||||
|
ElMessage.error("登录失败!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage.error("提交失败,请先完善登录信息!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetForm = (formEl) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.resetFields();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
82
src/components/page/main.vue
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<div class="h-full bg-slate-400 flex flex-col" style="min-width: 520px">
|
||||||
|
<div class="flex">
|
||||||
|
<el-menu
|
||||||
|
class="flex font-bold"
|
||||||
|
style="background-color: rgb(148 163 184 / var(--tw-bg-opacity, 1))"
|
||||||
|
:default-active="activeIndex"
|
||||||
|
@select="handleSelect"
|
||||||
|
>
|
||||||
|
<el-menu-item
|
||||||
|
index="1"
|
||||||
|
:style="activeIndex == '1' ? activeStyle : indexStyle"
|
||||||
|
class="border-x-4 border-slate-300"
|
||||||
|
>
|
||||||
|
单选题
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="2"
|
||||||
|
:style="activeIndex == '2' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
多选题
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="3"
|
||||||
|
:style="activeIndex == '3' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
判断题
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="4"
|
||||||
|
:style="activeIndex == '4' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
问答题
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
<div class="px-4 bg-green-100 flex items-center">
|
||||||
|
<el-checkbox v-model="checked" style="color: red" label="直接显示答案" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-grow bg-white text-black">
|
||||||
|
<div v-show="activeIndex === '1'" class="w-h-full">
|
||||||
|
<Radio :checked="checked" />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '2'" class="w-h-full">
|
||||||
|
<Multiple :checked="checked" />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '3'" class="w-h-full">
|
||||||
|
<Judgment :checked="checked" />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '4'" class="w-h-full">
|
||||||
|
<Interlocution />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
import Radio from "../database/radio.vue";
|
||||||
|
import Multiple from "../database/multiple.vue";
|
||||||
|
import Judgment from "../database/judgment.vue";
|
||||||
|
import Interlocution from "../database/interlocution.vue";
|
||||||
|
|
||||||
|
const activeIndex = ref("1");
|
||||||
|
const indexStyle = "background-color: rgb(241 245 249);";
|
||||||
|
const activeStyle = "background-color: rgb(207 250 254);";
|
||||||
|
const checked = ref(false);
|
||||||
|
|
||||||
|
const handleSelect = (key, keyPath) => {
|
||||||
|
activeIndex.value = key;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.flex-grow {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
19
src/components/topic/interlocution.vue
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<el-text style="font-weight: bold">
|
||||||
|
难度:{{
|
||||||
|
topic.difficulty == "0" ? "简单" : topic.difficulty == "1" ? "普通" : "困难"
|
||||||
|
}}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<el-text style="font-weight: bold"> 题目:{{ topic.stem }} </el-text>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<el-text style="font-weight: bold"> 答案:{{ topic.answer }} </el-text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({ topic: Array });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
44
src/components/topic/judgment.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<el-text style="font-weight: bold">
|
||||||
|
难度:{{
|
||||||
|
topic.difficulty == "0" ? "简单" : topic.difficulty == "1" ? "普通" : "困难"
|
||||||
|
}}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<el-text style="font-weight: bold"> 题目:{{ topic.stem }} </el-text>
|
||||||
|
<br />
|
||||||
|
<el-radio-group v-model="radio" class="flex flex-col">
|
||||||
|
<el-radio value="1" style="margin-right: 0px"> 正确 </el-radio>
|
||||||
|
<el-radio value="0" style="margin-right: 0px"> 错误 </el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
<br />
|
||||||
|
<el-text v-show="checked ? true : showAnswer" style="font-weight: bold">
|
||||||
|
答案:{{ topic.answer ? "正确" : "错误" }}
|
||||||
|
</el-text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({ topic: Array, checked: Boolean });
|
||||||
|
|
||||||
|
const radio = ref("");
|
||||||
|
const showAnswer = ref(false);
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
radio.value = "";
|
||||||
|
showAnswer.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ reset });
|
||||||
|
|
||||||
|
watch(radio, (value) => {
|
||||||
|
showAnswer.value = false;
|
||||||
|
if (value != "") {
|
||||||
|
showAnswer.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
96
src/components/topic/multiple.vue
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<el-text style="font-weight: bold">
|
||||||
|
难度:{{
|
||||||
|
topic.difficulty == "0" ? "简单" : topic.difficulty == "1" ? "普通" : "困难"
|
||||||
|
}}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<el-text style="font-weight: bold"> 题目:{{ topic.stem }} </el-text>
|
||||||
|
<div class="my-2">
|
||||||
|
<el-checkbox v-model="checked1" :label="'A:' + topic.options_a" />
|
||||||
|
<br />
|
||||||
|
<el-checkbox v-model="checked2" :label="'B:' + topic.options_b" />
|
||||||
|
<br />
|
||||||
|
<el-checkbox v-model="checked3" :label="'C:' + topic.options_c" />
|
||||||
|
<br />
|
||||||
|
<el-checkbox v-model="checked4" :label="'D:' + topic.options_d" />
|
||||||
|
<br />
|
||||||
|
<el-checkbox
|
||||||
|
v-show="topic.options_e != null"
|
||||||
|
v-model="checked5"
|
||||||
|
:label="'E:' + topic.options_e"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" v-show="showButton" @click="showAnswer = true">
|
||||||
|
查看答案
|
||||||
|
</el-button>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<el-text v-show="checked ? true : showAnswer" style="font-weight: bold">
|
||||||
|
答案:{{ topic.answer }}
|
||||||
|
</el-text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({ topic: Array, checked: Boolean });
|
||||||
|
|
||||||
|
const checked1 = ref(false);
|
||||||
|
const checked2 = ref(false);
|
||||||
|
const checked3 = ref(false);
|
||||||
|
const checked4 = ref(false);
|
||||||
|
const checked5 = ref(false);
|
||||||
|
const showButton = ref(false);
|
||||||
|
const showAnswer = ref(false);
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
checked1.value = false;
|
||||||
|
checked2.value = false;
|
||||||
|
checked3.value = false;
|
||||||
|
checked4.value = false;
|
||||||
|
checked5.value = false;
|
||||||
|
showButton.value = false;
|
||||||
|
showAnswer.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(checked1, (value) => {
|
||||||
|
showButton.value = false;
|
||||||
|
if (value != "") {
|
||||||
|
showButton.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(checked2, (value) => {
|
||||||
|
showButton.value = false;
|
||||||
|
if (value != "") {
|
||||||
|
showButton.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(checked3, (value) => {
|
||||||
|
showButton.value = false;
|
||||||
|
if (value != "") {
|
||||||
|
showButton.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(checked4, (value) => {
|
||||||
|
showButton.value = false;
|
||||||
|
if (value != "") {
|
||||||
|
showButton.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(checked5, (value) => {
|
||||||
|
showButton.value = false;
|
||||||
|
if (value != "") {
|
||||||
|
showButton.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({ reset });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
54
src/components/topic/radio.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<el-text style="font-weight: bold">
|
||||||
|
难度:{{
|
||||||
|
topic.difficulty == "0" ? "简单" : topic.difficulty == "1" ? "普通" : "困难"
|
||||||
|
}}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<el-text style="font-weight: bold"> 题目:{{ topic.stem }} </el-text>
|
||||||
|
<br />
|
||||||
|
<el-radio-group v-model="radio" class="flex flex-col">
|
||||||
|
<div class="w-full">
|
||||||
|
<el-radio value="a" style="margin-right: 0px"> A:{{ topic.options_a }} </el-radio>
|
||||||
|
</div>
|
||||||
|
<div class="w-full">
|
||||||
|
<el-radio value="b" style="margin-right: 0px"> B:{{ topic.options_b }} </el-radio>
|
||||||
|
</div>
|
||||||
|
<div class="w-full">
|
||||||
|
<el-radio value="c" style="margin-right: 0px"> C:{{ topic.options_c }} </el-radio>
|
||||||
|
</div>
|
||||||
|
<div class="w-full">
|
||||||
|
<el-radio value="d" style="margin-right: 0px"> D:{{ topic.options_d }} </el-radio>
|
||||||
|
</div>
|
||||||
|
</el-radio-group>
|
||||||
|
<br />
|
||||||
|
<el-text v-show="checked ? true : showAnswer" style="font-weight: bold">
|
||||||
|
答案:{{ topic.answer }}
|
||||||
|
</el-text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({ topic: Array, checked: Boolean });
|
||||||
|
|
||||||
|
const radio = ref("");
|
||||||
|
const showAnswer = ref(false);
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
radio.value = "";
|
||||||
|
showAnswer.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ reset });
|
||||||
|
|
||||||
|
watch(radio, (value) => {
|
||||||
|
showAnswer.value = false;
|
||||||
|
if (value != "") {
|
||||||
|
showAnswer.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
23
src/main.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import './assets/main.css';
|
||||||
|
|
||||||
|
import { createApp } from 'vue';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
|
import piniaPersist from 'pinia-plugin-persist';
|
||||||
|
import ElementPlus from 'element-plus';
|
||||||
|
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||||
|
import 'element-plus/dist/index.css';
|
||||||
|
import { AES_Encrypt } from '@/utils/aes.js';
|
||||||
|
|
||||||
|
import App from './App.vue';
|
||||||
|
import router from './router';
|
||||||
|
|
||||||
|
const pinia = createPinia();
|
||||||
|
pinia.use(piniaPersist);
|
||||||
|
|
||||||
|
const app = createApp(App);
|
||||||
|
app.config.globalProperties.$AES_Encrypt = AES_Encrypt //全局加密
|
||||||
|
app.use(pinia);
|
||||||
|
app.use(ElementPlus, { locale: zhCn });
|
||||||
|
app.use(router);
|
||||||
|
|
||||||
|
app.mount('#app');
|
||||||
46
src/router/index.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/404page',
|
||||||
|
name: '404page',
|
||||||
|
meta: { label: "404页面" },
|
||||||
|
component: () => import('../views/404page.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/initialService',
|
||||||
|
name: 'initialService',
|
||||||
|
meta: { label: "登录页面" },
|
||||||
|
component: () => import('../views/InitialService.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/main',
|
||||||
|
name: 'main',
|
||||||
|
meta: { label: "主页面" },
|
||||||
|
component: () => import('../views/Main.vue')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (to.matched.length === 0) {
|
||||||
|
if (to.path == "/") {
|
||||||
|
router.push({ path: '/main' });
|
||||||
|
} else if (to.path == "/initialService") {
|
||||||
|
router.push({ path: '/initialService' });
|
||||||
|
} else {
|
||||||
|
router.push({ path: '/404page' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
if(localStorage.length == 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
router.push({ path: '/initialService' });
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router
|
||||||
29
src/utils/aes.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import CryptoJS from 'crypto-js'
|
||||||
|
|
||||||
|
const KEY = CryptoJS.enc.Utf8.parse('BDQH');
|
||||||
|
|
||||||
|
export const AES_Encrypt = (plaintext) => {
|
||||||
|
let ciphertext = CryptoJS.AES.encrypt(plaintext, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString();
|
||||||
|
return ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const encrypt = (plaintext) => {
|
||||||
|
if(plaintext !== null && plaintext !== undefined && plaintext !== "") {
|
||||||
|
return CryptoJS.AES.encrypt(plaintext, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const decrypt = (plaintext) => {
|
||||||
|
if(plaintext !== null && plaintext !== undefined && !plaintext == "") {
|
||||||
|
return CryptoJS.AES.decrypt(plaintext, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString(CryptoJS.enc.Utf8);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/views/404page.vue
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div class="common-layout w-h-full">
|
||||||
|
<el-text class="mx-1"> 404 not found </el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1"> 您搜索的页面不存在 </el-text>
|
||||||
|
<br />
|
||||||
|
<el-button type="primary" @click="backHome">返回首页</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const backHome = () => {
|
||||||
|
router.push({ path: '/main' });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
39
src/views/InitialService.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<el-container class="w-h-full justify-center items-center bg-sky-200">
|
||||||
|
<el-main>
|
||||||
|
<Login />
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
|
||||||
|
import $http from "../api/index";
|
||||||
|
import $url from "../api/url";
|
||||||
|
|
||||||
|
import Login from "../components/page/login.vue";
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (
|
||||||
|
localStorage.data &&
|
||||||
|
localStorage.data !== "" &&
|
||||||
|
localStorage.data !== null &&
|
||||||
|
localStorage.data !== undefined &&
|
||||||
|
localStorage.data !== NaN
|
||||||
|
) {
|
||||||
|
const data = {
|
||||||
|
data: localStorage.data,
|
||||||
|
};
|
||||||
|
$http.post($url.loginStatus, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
window.location.href = window.location.href.replace("/initialService", "/main");
|
||||||
|
} else {
|
||||||
|
localStorage.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
45
src/views/Main.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<div class="common-layout w-h-full">
|
||||||
|
<el-container class="w-h-full">
|
||||||
|
<el-main style="padding: 0">
|
||||||
|
<Main />
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
|
||||||
|
import $http from "../api/index";
|
||||||
|
import $url from "../api/url";
|
||||||
|
|
||||||
|
import Main from "../components/page/main.vue";
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (
|
||||||
|
localStorage.data &&
|
||||||
|
localStorage.data !== "" &&
|
||||||
|
localStorage.data !== null &&
|
||||||
|
localStorage.data !== undefined &&
|
||||||
|
localStorage.data !== NaN
|
||||||
|
) {
|
||||||
|
const data = {
|
||||||
|
data: localStorage.data,
|
||||||
|
};
|
||||||
|
$http.post($url.loginStatus, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
localStorage.clear();
|
||||||
|
window.location.href = window.location.href.replace("/main", "/initialService");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
localStorage.clear();
|
||||||
|
window.location.href = window.location.href.replace("/main", "/initialService");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
13
tailwind.config.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||||
|
darkMode: false, // or 'media' or 'class'
|
||||||
|
content: [],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
44
vite.config.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import AutoImport from 'unplugin-auto-import/vite'
|
||||||
|
import Components from 'unplugin-vue-components/vite'
|
||||||
|
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
base: './',
|
||||||
|
publicPath: './',
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
AutoImport({
|
||||||
|
resolvers: [ElementPlusResolver()],
|
||||||
|
}),
|
||||||
|
Components({
|
||||||
|
resolvers: [ElementPlusResolver()],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
//用来配置跨域
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 7033,
|
||||||
|
proxy: {
|
||||||
|
'/authentication': {
|
||||||
|
target: 'http://127.0.0.1:8011',//鉴权服务器地址
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/authentication/, '')
|
||||||
|
},
|
||||||
|
'/bdTrainingExamTopic': {
|
||||||
|
target: 'http://127.0.0.1:8021',//目标服务器地址
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/bdTrainingExamTopic/, '')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||