北斗应用技术培训考试管理系统
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
|
||||
```
|
||||
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!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">
|
||||
<title>北斗应用技术培训考试管理系统</title>
|
||||
</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"]
|
||||
}
|
||||
8028
package-lock.json
generated
Normal file
38
package.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "bd-training-exam-manager",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --port=7022",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.6.8",
|
||||
"bd-training-exam-manager": "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",
|
||||
"vue3-slide-verify": "^1.1.5",
|
||||
"xlsx": "^0.18.5",
|
||||
"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 @@
|
||||
<template>
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { RouterView } from "vue-router";
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
130
src/api/index.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import axios from "axios";
|
||||
import $url from "./url";
|
||||
import router from "../router";
|
||||
import { encrypt } from "../utils/aes";
|
||||
|
||||
// 添加请求拦截器
|
||||
axios.interceptors.request.use(function (config) {
|
||||
// 在发送请求之前做些什么
|
||||
if (localStorage.access_token && localStorage.access_token !== "" && localStorage.access_token !== null && localStorage.access_token !== undefined && localStorage.access_token !== NaN) {
|
||||
if (config.headers) {
|
||||
config.headers.authorization = localStorage.access_token;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}, function (error) {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
// 转到登录页面
|
||||
const toLogin = () => {
|
||||
// localStorage.clear();
|
||||
router.push({ path: '/alogin' });
|
||||
};
|
||||
|
||||
// 添加响应拦截器
|
||||
let result = true;
|
||||
axios.interceptors.response.use(function (response) {
|
||||
// 2xx 范围内的状态码都会触发该函数。
|
||||
// 对响应数据做点什么
|
||||
if (response.data.code === 200) {
|
||||
if ("access_token" in response.data) {
|
||||
localStorage.setItem("access_token", response.data.access_token);
|
||||
}
|
||||
if ("refresh_token" in response.data) {
|
||||
localStorage.setItem("refresh_token", response.data.refresh_token);
|
||||
}
|
||||
if ("data" in response.data) {
|
||||
localStorage.setItem("data", response.data.data);
|
||||
}
|
||||
}
|
||||
// if (response.data.code === 404) {
|
||||
// localStorage.clear();
|
||||
// //转到404页面
|
||||
// router.push({ path: '/404page' });
|
||||
// }
|
||||
// if (response.data.code === 402) {
|
||||
// toLogin();
|
||||
// }
|
||||
if (response.data.code === 401 && result) {
|
||||
result = false;
|
||||
setTimeout(() => {
|
||||
result = true;
|
||||
}, 1000);
|
||||
let getCode = window.location.href.indexOf('?');
|
||||
if (getCode != '-1') {
|
||||
let code = window.location.href.substring(getCode + 1);
|
||||
const data = {
|
||||
code: code,
|
||||
type: encrypt('code')
|
||||
};
|
||||
axios.post($url.getToken, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
localStorage.setItem("data", res.data.data);
|
||||
localStorage.setItem("access_token", res.data.access_token);
|
||||
localStorage.setItem("refresh_token", res.data.refresh_token);
|
||||
window.location.href = res.data.redirect;
|
||||
} else {
|
||||
toLogin();
|
||||
}
|
||||
});
|
||||
} else if(localStorage.loginCode && localStorage.loginCode !== "" && localStorage.loginCode !== null && localStorage.loginCode !== undefined && localStorage.loginCode !== NaN) {
|
||||
const data = {
|
||||
code: localStorage.loginCode,
|
||||
type: encrypt('code')
|
||||
};
|
||||
axios.post($url.getToken, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
localStorage.setItem("data", res.data.data);
|
||||
localStorage.setItem("access_token", res.data.access_token);
|
||||
localStorage.setItem("refresh_token", res.data.refresh_token);
|
||||
localStorage.removeItem('loginCode');
|
||||
window.location.href = res.data.redirect;
|
||||
} else {
|
||||
toLogin();
|
||||
}
|
||||
});
|
||||
} else if (localStorage.refresh_token && localStorage.refresh_token !== "" && localStorage.refresh_token !== null && localStorage.refresh_token !== undefined && localStorage.refresh_token !== NaN) {
|
||||
const data = {
|
||||
code: localStorage.refresh_token,
|
||||
type: localStorage.data
|
||||
};
|
||||
axios.post($url.getToken, data).then((res) => {
|
||||
console.log(res);
|
||||
if (res.data.code === 200) {
|
||||
localStorage.setItem("data", res.data.data);
|
||||
localStorage.setItem("access_token", res.data.access_token);
|
||||
localStorage.setItem("refresh_token", res.data.refresh_token);
|
||||
window.location.reload();
|
||||
} else {
|
||||
toLogin();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
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);
|
||||
},
|
||||
}
|
||||
192
src/api/url.js
Normal file
@@ -0,0 +1,192 @@
|
||||
export default {
|
||||
// 退出登录
|
||||
unLogin: "/authentication/unLogin",
|
||||
// 登录请求接口
|
||||
alogin: "/authentication/alogin",
|
||||
// 获取登录状态
|
||||
loginStatus: "/authentication/loginStatus",
|
||||
// 用于获取token
|
||||
getToken: "/authentication/getToken",
|
||||
// 用于验证token
|
||||
verify: "/authentication/verify",
|
||||
// 获取用户基本信息
|
||||
getUser: "/authentication/getUser",
|
||||
// 修改用户基本信息
|
||||
editUser: "/authentication/editUser",
|
||||
// 修改密码
|
||||
changePassword: "/authentication/changePassword",
|
||||
// 重置密码
|
||||
resetPassword: "/authentication/resetPassword",
|
||||
|
||||
// 管理系统新增普通管理员账号信息
|
||||
addAdmin: "/bdTrainingExamManager/addAdmin",
|
||||
// 管理系统查看普通管理员账号信息
|
||||
showAdmin: "/bdTrainingExamManager/showAdmin",
|
||||
// 管理系统编辑普通管理员账号信息
|
||||
editAdmin: "/bdTrainingExamManager/editAdmin",
|
||||
// 管理系统删除普通管理员账号信息
|
||||
deleteAdmin: "/bdTrainingExamManager/deleteAdmin",
|
||||
// 管理系统导出管理员账号信息数据
|
||||
downloadAdminData: "/bdTrainingExamManager/downloadAdminData",
|
||||
|
||||
// 管理系统新增考试信息
|
||||
addExam: "/bdTrainingExamManager/addExam",
|
||||
// 管理系统查看考试信息
|
||||
showExam: "/bdTrainingExamManager/showExam",
|
||||
// 管理系统编辑考试信息
|
||||
editExam: "/bdTrainingExamManager/editExam",
|
||||
// 管理系统删除考试信息
|
||||
deleteExam: "/bdTrainingExamManager/deleteExam",
|
||||
// 管理系统导出考试信息数据
|
||||
downloadExamData: "/bdTrainingExamManager/downloadExamData",
|
||||
|
||||
// 管理系统新增用户账号信息
|
||||
addUser: "/bdTrainingExamManager/addUser",
|
||||
// 管理系统查看用户账号信息
|
||||
showUser: "/bdTrainingExamManager/showUser",
|
||||
// 管理系统编辑用户账号信息
|
||||
editUser: "/bdTrainingExamManager/editUser",
|
||||
// 管理系统删除用户账号信息
|
||||
deleteUser: "/bdTrainingExamManager/deleteUser",
|
||||
// 管理系统导出用户账号信息数据
|
||||
downloadUserData: "/bdTrainingExamManager/downloadUserData",
|
||||
|
||||
// 比较身份证号
|
||||
diffIdentityCard: "/bdTrainingExamManager/diffIdentityCard",
|
||||
// 比较邮箱
|
||||
diffEmail: "/bdTrainingExamManager/diffEmail",
|
||||
// 比较电话号码
|
||||
diffPhone: "/bdTrainingExamManager/diffPhone",
|
||||
|
||||
// 管理系统查看用户关键信息变更
|
||||
auditList: "/bdTrainingExamManager/auditList",
|
||||
// 管理系统审核用户关键信息变更
|
||||
userMsgAudit: "/bdTrainingExamManager/userMsgAudit",
|
||||
|
||||
// 管理系统检索考生身份证号码
|
||||
searchIdentityCard: "/bdTrainingExamManager/searchIdentityCard",
|
||||
// 管理系统检索考生姓名
|
||||
searchUserName: "/bdTrainingExamManager/searchUserName",
|
||||
// 管理系统检索考试 uid
|
||||
searchExamUid: "/bdTrainingExamManager/searchExamUid",
|
||||
// 管理系统检索工作单位
|
||||
searchWorkplace: "/bdTrainingExamManager/searchWorkplace",
|
||||
// 管理系统检索报名结果说明
|
||||
searchResult: "/bdTrainingExamManager/searchResult",
|
||||
|
||||
// 管理系统查找指定考生姓名
|
||||
findUserName: "/bdTrainingExamManager/findUserName",
|
||||
// 管理系统查找指定考生身份证号
|
||||
findIdentityCard: "/bdTrainingExamManager/findIdentityCard",
|
||||
// 管理系统查找指定考试 uid
|
||||
findExamUid: "/bdTrainingExamManager/findExamUid",
|
||||
// 管理系统查找指定工作单位
|
||||
findWorkplace: "/bdTrainingExamManager/findWorkplace",
|
||||
|
||||
// 管理系统新增考生报名信息
|
||||
addApplication: "/bdTrainingExamManager/addApplication",
|
||||
// 管理系统查看考生报名信息
|
||||
showApplication: "/bdTrainingExamManager/showApplication",
|
||||
// 管理系统编辑考生报名信息
|
||||
editApplication: "/bdTrainingExamManager/editApplication",
|
||||
// 管理系统删除考生报名信息
|
||||
deleteApplication: "/bdTrainingExamManager/deleteApplication",
|
||||
// 管理系统导出考生报名信息数据
|
||||
downloadApplicationData: "/bdTrainingExamManager/downloadApplicationData",
|
||||
|
||||
// 管理系统新增考生考试结果
|
||||
addGrades: "/bdTrainingExamManager/addGrades",
|
||||
// 管理系统查看考生考试结果
|
||||
showGrades: "/bdTrainingExamManager/showGrades",
|
||||
// 管理系统编辑考生考试结果
|
||||
editGrades: "/bdTrainingExamManager/editGrades",
|
||||
// 管理系统删除考生考试结果
|
||||
deleteGrades: "/bdTrainingExamManager/deleteGrades",
|
||||
// 管理系统导出考生考试结果数据
|
||||
downloadGradesData: "/bdTrainingExamManager/downloadGradesData",
|
||||
|
||||
// 查看导入错误记录
|
||||
showImporterror: "/bdTrainingExamManager/showImporterror",
|
||||
// 删除导入错误记录
|
||||
deleteImporterror: "/bdTrainingExamManager/deleteImporterror",
|
||||
|
||||
// 管理系统新增题库白名单
|
||||
addTopicWhitelist: "/bdTrainingExamManager/addTopicWhitelist",
|
||||
// 管理系统查看题库白名单
|
||||
showTopicWhitelist: "/bdTrainingExamManager/showTopicWhitelist",
|
||||
// 管理系统编辑题库白名单
|
||||
editTopicWhitelist: "/bdTrainingExamManager/editTopicWhitelist",
|
||||
// 管理系统删除题库白名单
|
||||
deleteTopicWhitelist: "/bdTrainingExamManager/deleteTopicWhitelist",
|
||||
// 管理系统导出题库白名单
|
||||
downloadTopicWhitelistData: "/bdTrainingExamManager/downloadTopicWhitelistData",
|
||||
|
||||
// 管理系统新增问答题
|
||||
addInterlocution: "/bdTrainingExamManager/addInterlocution",
|
||||
// 管理系统查看问答题
|
||||
showInterlocution: "/bdTrainingExamManager/showInterlocution",
|
||||
// 管理系统编辑问答题
|
||||
editInterlocution: "/bdTrainingExamManager/editInterlocution",
|
||||
// 管理系统删除问答题
|
||||
deleteInterlocution: "/bdTrainingExamManager/deleteInterlocution",
|
||||
// 管理系统导出问答题
|
||||
downloadInterlocutionData: "/bdTrainingExamManager/downloadInterlocutionData",
|
||||
|
||||
// 管理系统新增选择题
|
||||
addJudgment: "/bdTrainingExamManager/addJudgment",
|
||||
// 管理系统查看选择题
|
||||
showJudgment: "/bdTrainingExamManager/showJudgment",
|
||||
// 管理系统编辑选择题
|
||||
editJudgment: "/bdTrainingExamManager/editJudgment",
|
||||
// 管理系统删除选择题
|
||||
deleteJudgment: "/bdTrainingExamManager/deleteJudgment",
|
||||
// 管理系统导出选择题
|
||||
downloadJudgmentData: "/bdTrainingExamManager/downloadJudgmentData",
|
||||
|
||||
// 管理系统新增多选题
|
||||
addMultiple: "/bdTrainingExamManager/addMultiple",
|
||||
// 管理系统查看多选题
|
||||
showMultiple: "/bdTrainingExamManager/showMultiple",
|
||||
// 管理系统编辑多选题
|
||||
editMultiple: "/bdTrainingExamManager/editMultiple",
|
||||
// 管理系统删除多选题
|
||||
deleteMultiple: "/bdTrainingExamManager/deleteMultiple",
|
||||
// 管理系统导出多选题
|
||||
downloadMultipleData: "/bdTrainingExamManager/downloadMultipleData",
|
||||
|
||||
// 管理系统新增单选题
|
||||
addRadio: "/bdTrainingExamManager/addRadio",
|
||||
// 管理系统查看单选题
|
||||
showRadio: "/bdTrainingExamManager/showRadio",
|
||||
// 管理系统编辑单选题
|
||||
editRadio: "/bdTrainingExamManager/editRadio",
|
||||
// 管理系统删除单选题
|
||||
deleteRadio: "/bdTrainingExamManager/deleteRadio",
|
||||
// 管理系统导出单选题
|
||||
downloadRadioData: "/bdTrainingExamManager/downloadRadioData",
|
||||
|
||||
// 查看监控记录
|
||||
showMonitoring: "/bdTrainingExamManager/showMonitoring",
|
||||
// 删除监控记录
|
||||
deleteMonitoring: "/bdTrainingExamManager/deleteMonitoring",
|
||||
|
||||
// 导出小鹅通导入用户
|
||||
importXiaoeTech: "/bdTrainingExamManager/importXiaoeTech",
|
||||
// 导出小鹅通开课学员
|
||||
commencementXiaoeTech: "/bdTrainingExamManager/commencementXiaoeTech",
|
||||
// 导出批量报名导入 excel 表
|
||||
importApplicationData: "/bdTrainingExamManager/importApplicationData",
|
||||
// 导出考试星学员导入 excel 表
|
||||
importExamStars: "/bdTrainingExamManager/importExamStars",
|
||||
// 导出培训证书发放用户导入 excel 表
|
||||
importIssuance: "/bdTrainingExamManager/importIssuance",
|
||||
// 导出培训证书发放用户照片文件夹
|
||||
importUserPhoto: "/bdTrainingExamManager/importUserPhoto",
|
||||
// 上传用户照片
|
||||
uploadUserPhoto: "/bdTrainingExamManager/uploadUserPhoto",
|
||||
// 导出考试成绩导入 excel 表
|
||||
importGradesData: "/bdTrainingExamManager/importGradesData",
|
||||
|
||||
// 核验用户身份证二要素
|
||||
CNTEV: "/bdTrainingExamManager/CNTEV",
|
||||
}
|
||||
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/default.png
Normal file
|
After Width: | Height: | Size: 12 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 |
163
src/components/addNewData/adminForm/adminForm.vue
Normal file
@@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="adminMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addAdmin="addAdmin"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addAdmin="addAdmin"
|
||||
/>
|
||||
<ExcleAdd ref="excleAddRef" v-if="dialogExcleVisible" @addAdmin="addAdmin" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import adminActiveStore from "../../../stores/adminMsg";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes";
|
||||
|
||||
const adminMsgActive = adminActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
adminMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
adminMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
adminMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
adminMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
adminMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
adminMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
adminMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
adminMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
adminMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addAdmin = (requestMsg) => {
|
||||
requestMsg.forEach((element) => {
|
||||
element.account_name = encrypt(String(element.account_name));
|
||||
element.role = encrypt(String(element.role));
|
||||
});
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addAdmin, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增普通管理员成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增普通管理员失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
92
src/components/addNewData/adminForm/excleAdd.vue
Normal file
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
account_name: {
|
||||
value: "",
|
||||
label: "账号名",
|
||||
},
|
||||
role: {
|
||||
value: "",
|
||||
label: "权限等级",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "账号名",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "权限等级",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addAdmin"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
account_name: item[relatedRules.account_name.value],
|
||||
role: item[relatedRules.role.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addAdmin", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
116
src/components/addNewData/adminForm/multipleAdd.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "管理员1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addAdmin"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.role = singleAddRef.value[0].ruleForm.role;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `管理员${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addAdmin", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
110
src/components/addNewData/adminForm/singleAdd.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="账号名" prop="account_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入账号名"
|
||||
minlength="2"
|
||||
maxlength="5"
|
||||
v-model="ruleForm.account_name"
|
||||
@input="filter(ruleForm.account_name, 'account_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="权限等级" prop="role">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择权限等级"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.role"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.roleOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
account_name: "",
|
||||
role: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const rules = reactive({
|
||||
account_name: [{ required: true, message: "请输入账号名", trigger: "blur" }],
|
||||
role: [{ required: true, message: "请选择权限等级", trigger: "change" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addAdmin"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addAdmin", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
179
src/components/addNewData/applicationForm/applicationForm.vue
Normal file
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="applicationMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addApplication="addApplication"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addApplication="addApplication"
|
||||
/>
|
||||
<ExcleAdd
|
||||
ref="excleAddRef"
|
||||
v-if="dialogExcleVisible"
|
||||
@addApplication="addApplication"
|
||||
/>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import applicationActiveStore from "../../../stores/applicationMsg";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes";
|
||||
|
||||
const applicationMsgActive = applicationActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
applicationMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
applicationMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
applicationMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
applicationMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
applicationMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
applicationMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
applicationMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
applicationMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
applicationMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addApplication = (requestMsg) => {
|
||||
requestMsg.forEach((element) => {
|
||||
element.identity_card = encrypt(String(element.identity_card));
|
||||
element.user_name = encrypt(String(element.user_name));
|
||||
element.exam_uid = encrypt(String(element.exam_uid));
|
||||
element.source = encrypt(String(element.source));
|
||||
element.status = encrypt(String(element.status));
|
||||
element.pay_status = encrypt(String(element.pay_status));
|
||||
element.result = encrypt(String(element.result));
|
||||
});
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addApplication, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增考生报名信息成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else if (res.data.code === 300) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增部分考生报名信息成功,请查看新增失败的数据以查找原因!",
|
||||
type: "warning",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增考生报名信息失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
142
src/components/addNewData/applicationForm/excleAdd.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
identity_card: {
|
||||
value: "",
|
||||
label: "考生身份证号",
|
||||
},
|
||||
user_name: {
|
||||
value: "",
|
||||
label: "考生姓名",
|
||||
},
|
||||
exam_uid: {
|
||||
value: "",
|
||||
label: "考试uid",
|
||||
},
|
||||
source: {
|
||||
value: "",
|
||||
label: "报名来源",
|
||||
},
|
||||
status: {
|
||||
value: "",
|
||||
label: "报名状态",
|
||||
},
|
||||
pay_status: {
|
||||
value: "",
|
||||
label: "缴费状态",
|
||||
},
|
||||
result: {
|
||||
value: "",
|
||||
label: "报名结果说明",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "考生身份证号",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "考生姓名",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "考试uid",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "报名来源",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "报名状态",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "缴费状态",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "6",
|
||||
label: "报名结果说明",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addApplication"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
identity_card: item[relatedRules.identity_card.value],
|
||||
user_name: item[relatedRules.user_name.value],
|
||||
exam_uid: item[relatedRules.exam_uid.value],
|
||||
source: item[relatedRules.source.value],
|
||||
status: item[relatedRules.status.value],
|
||||
pay_status: item[relatedRules.pay_status.value],
|
||||
result: item[relatedRules.result.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addApplication", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
119
src/components/addNewData/applicationForm/multipleAdd.vue
Normal file
@@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "报名数据1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addApplication"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.source = singleAddRef.value[0].ruleForm.source;
|
||||
item.ruleForm.status = singleAddRef.value[0].ruleForm.status;
|
||||
item.ruleForm.pay_status = singleAddRef.value[0].ruleForm.pay_status;
|
||||
item.ruleForm.result = singleAddRef.value[0].ruleForm.result;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `报名数据${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addApplication", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
282
src/components/addNewData/applicationForm/singleAdd.vue
Normal file
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="考生姓名" prop="user_name">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchUserName"
|
||||
clearable
|
||||
placeholder="请输入考生姓名"
|
||||
minlength="1"
|
||||
maxlength="6"
|
||||
v-model="ruleForm.user_name"
|
||||
@input="filter(ruleForm.user_name, 'user_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="身份证号" prop="identity_card">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchIdentityCard"
|
||||
clearable
|
||||
placeholder="请输入身份证号"
|
||||
minlength="18"
|
||||
maxlength="18"
|
||||
v-model="ruleForm.identity_card"
|
||||
@input="filter(ruleForm.identity_card, 'identity_card')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试uid" prop="exam_uid">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchExamUid"
|
||||
clearable
|
||||
placeholder="请输入考试uid"
|
||||
minlength="10"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.exam_uid"
|
||||
@input="filter(ruleForm.exam_uid, 'exam_uid')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名来源" prop="source">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入报名来源"
|
||||
maxlength="24"
|
||||
v-model="ruleForm.source"
|
||||
@input="filter(ruleForm.source, 'source')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择报名状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="缴费状态" prop="pay_status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择缴费状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.pay_status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.payStatusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名结果说明" prop="result">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入报名结果说明"
|
||||
maxlength="24"
|
||||
v-model="ruleForm.result"
|
||||
@input="filter(ruleForm.result, 'result')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
user_name: "",
|
||||
identity_card: "",
|
||||
exam_uid: "",
|
||||
source: "",
|
||||
status: "",
|
||||
pay_status: "",
|
||||
result: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const identityCardRegex = /^[1-9](?:\d{5})(?:19|20)?\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}(?:\d|X|x)$/;
|
||||
|
||||
const searchUserName = (value, cb) => {
|
||||
const data = {
|
||||
user_name: value,
|
||||
};
|
||||
$http.post($url.searchUserName, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateUserName = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入考生姓名"));
|
||||
} else {
|
||||
const data = {
|
||||
user_name: value,
|
||||
};
|
||||
$http.post($url.findUserName, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该考生不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const searchIdentityCard = (value, cb) => {
|
||||
const data = {
|
||||
identity_card: value,
|
||||
};
|
||||
$http.post($url.searchIdentityCard, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateIdentityCard = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入身份证号"));
|
||||
} else if (!identityCardRegex.test(value)) {
|
||||
callback(new Error("身份证格式不正确,请重新输入!"));
|
||||
} else if (ruleForm.user_name == "") {
|
||||
callback(new Error("请输入考生姓名"));
|
||||
} else {
|
||||
const data = {
|
||||
identity_card: value,
|
||||
user_name: ruleForm.user_name,
|
||||
};
|
||||
$http.post($url.findIdentityCard, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else if (res.data.code === 303) {
|
||||
callback(new Error("考生身份证号码与考生姓名不匹配!"));
|
||||
} else {
|
||||
callback(new Error("该考生身份证号未注册!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const searchExamUid = (value, cb) => {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.searchExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateExamUid = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入考试uid"));
|
||||
} else {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.findExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该考试不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
identity_card: [{ required: true, validator: validateIdentityCard, trigger: "blur" }],
|
||||
user_name: [{ required: true, validator: validateUserName, trigger: "blur" }],
|
||||
exam_uid: [{ required: true, validator: validateExamUid, trigger: "blur" }],
|
||||
source: [{ required: true, message: "请输入报名来源", trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择报名状态", trigger: "change" }],
|
||||
pay_status: [{ required: true, message: "请选择缴费状态", trigger: "change" }],
|
||||
result: [{ required: true, message: "请输入报名结果说明", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addApplication"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addApplication", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
168
src/components/addNewData/examForm/examForm.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="examMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addExam="addExam"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addExam="addExam"
|
||||
/>
|
||||
<ExcleAdd ref="excleAddRef" v-if="dialogExcleVisible" @addExam="addExam" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import examActiveStore from "../../../stores/examMsg";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes";
|
||||
|
||||
const examMsgActive = examActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
examMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
examMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
examMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
examMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
examMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
examMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
examMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
examMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
examMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addExam = (requestMsg) => {
|
||||
requestMsg.forEach((element) => {
|
||||
element.uid = encrypt(String(element.uid));
|
||||
element.exam_name = encrypt(String(element.exam_name));
|
||||
element.status = encrypt(String(element.status));
|
||||
element.application_start = new Date(element.application_start);
|
||||
element.application_end = new Date(element.application_end);
|
||||
element.exam_start = new Date(element.exam_start);
|
||||
element.exam_end = new Date(element.exam_end);
|
||||
});
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addExam, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增考试信息成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增考试信息失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
142
src/components/addNewData/examForm/excleAdd.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
uid: {
|
||||
value: "",
|
||||
label: "考试uid",
|
||||
},
|
||||
exam_name: {
|
||||
value: "",
|
||||
label: "考试名称",
|
||||
},
|
||||
status: {
|
||||
value: "",
|
||||
label: "考试状态",
|
||||
},
|
||||
application_start: {
|
||||
value: "",
|
||||
label: "报名开始时间",
|
||||
},
|
||||
application_end: {
|
||||
value: "",
|
||||
label: "报名结束时间",
|
||||
},
|
||||
exam_start: {
|
||||
value: "",
|
||||
label: "考试开始时间",
|
||||
},
|
||||
exam_end: {
|
||||
value: "",
|
||||
label: "考试结束时间",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "考试uid",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "考试名称",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "考试状态",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "报名开始时间",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "报名结束时间",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "考试开始时间",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "6",
|
||||
label: "考试结束时间",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addExam"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
uid: item[relatedRules.uid.value],
|
||||
exam_name: item[relatedRules.exam_name.value],
|
||||
status: item[relatedRules.status.value],
|
||||
application_start: item[relatedRules.application_start.value],
|
||||
application_end: item[relatedRules.application_end.value],
|
||||
exam_start: item[relatedRules.exam_start.value],
|
||||
exam_end: item[relatedRules.exam_end.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addExam", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
116
src/components/addNewData/examForm/multipleAdd.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "考试1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addExam"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.status = singleAddRef.value[0].ruleForm.status;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `考试${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addExam", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
187
src/components/addNewData/examForm/singleAdd.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="考试uid" prop="uid">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入考试uid"
|
||||
minlength="10"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.uid"
|
||||
@input="filter(ruleForm.uid, 'uid')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试名称" prop="exam_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入考试名称"
|
||||
maxlength="60"
|
||||
v-model="ruleForm.exam_name"
|
||||
@input="filter(ruleForm.exam_name, 'exam_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择考试状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="报名起止时间">
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="application_start">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.application_start"
|
||||
type="datetime"
|
||||
placeholder="请选择报名开始时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" class="text-center">
|
||||
<span class="text-gray-500">-</span>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="application_end">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.application_end"
|
||||
type="datetime"
|
||||
placeholder="请选择报名结束时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="考试起止时间">
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="exam_start">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.exam_start"
|
||||
type="datetime"
|
||||
placeholder="请选择考试开始时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" class="text-center">
|
||||
<span class="text-gray-500">-</span>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="exam_end">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.exam_end"
|
||||
type="datetime"
|
||||
placeholder="请选择考试结束时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
uid: "",
|
||||
exam_name: "",
|
||||
status: "",
|
||||
application_start: "",
|
||||
application_end: "",
|
||||
exam_start: "",
|
||||
exam_end: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const rules = reactive({
|
||||
uid: [{ required: true, message: "请输入考试uid", trigger: "blur" }],
|
||||
exam_name: [{ required: true, message: "请输入考试名称", trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择考试状态", trigger: "change" }],
|
||||
application_start: [
|
||||
{ type: "date", required: true, message: "请选择报名开始时间", trigger: "change" },
|
||||
],
|
||||
application_end: [
|
||||
{ type: "date", required: true, message: "请选择报名结束时间", trigger: "change" },
|
||||
],
|
||||
exam_start: [
|
||||
{ type: "date", required: true, message: "请选择考试开始时间", trigger: "change" },
|
||||
],
|
||||
exam_end: [
|
||||
{ type: "date", required: true, message: "请选择考试结束时间", trigger: "change" },
|
||||
],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addExam"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addExam", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
132
src/components/addNewData/gradesForm/excleAdd.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
user_name: {
|
||||
value: "",
|
||||
label: "考生姓名",
|
||||
},
|
||||
identity_card: {
|
||||
value: "",
|
||||
label: "身份证号",
|
||||
},
|
||||
exam_uid: {
|
||||
value: "",
|
||||
label: "考试uid",
|
||||
},
|
||||
status: {
|
||||
value: "",
|
||||
label: "参与状态",
|
||||
},
|
||||
grades: {
|
||||
value: "",
|
||||
label: "考试成绩",
|
||||
},
|
||||
pass_type: {
|
||||
value: "",
|
||||
label: "考试结果",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "考生姓名",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "身份证号",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "考试uid",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "参与状态",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "考试成绩",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "考试结果",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addGrades"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
identity_card: item[relatedRules.identity_card.value],
|
||||
user_name: item[relatedRules.user_name.value],
|
||||
exam_uid: item[relatedRules.exam_uid.value],
|
||||
status: item[relatedRules.status.value],
|
||||
grades: item[relatedRules.grades.value],
|
||||
pass_type: item[relatedRules.pass_type.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addGrades", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
174
src/components/addNewData/gradesForm/gradesForm.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="gradesMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addGrades="addGrades"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addGrades="addGrades"
|
||||
/>
|
||||
<ExcleAdd ref="excleAddRef" v-if="dialogExcleVisible" @addGrades="addGrades" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import gradesActiveStore from "../../../stores/gradesMsg";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes";
|
||||
|
||||
const gradesMsgActive = gradesActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
gradesMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
gradesMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
gradesMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
gradesMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
gradesMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
gradesMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
gradesMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
gradesMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
gradesMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addGrades = (requestMsg) => {
|
||||
requestMsg.forEach((element) => {
|
||||
element.identity_card = encrypt(String(element.identity_card));
|
||||
element.user_name = encrypt(String(element.user_name));
|
||||
element.exam_uid = encrypt(String(element.exam_uid));
|
||||
element.status = encrypt(String(element.status));
|
||||
element.grades = encrypt(String(element.grades));
|
||||
element.pass_type = encrypt(String(element.pass_type));
|
||||
});
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addGrades, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增考生成绩成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else if (res.data.code === 300) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增部分考生成绩成功,请查看新增失败的数据以查找原因!",
|
||||
type: "warning",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增考生成绩失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
117
src/components/addNewData/gradesForm/multipleAdd.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "成绩1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addGrades"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.status = singleAddRef.value[0].ruleForm.status;
|
||||
item.ruleForm.pass_type = singleAddRef.value[0].ruleForm.pass_type;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `成绩${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addGrades", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
272
src/components/addNewData/gradesForm/singleAdd.vue
Normal file
@@ -0,0 +1,272 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="考生姓名" prop="user_name">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchUserName"
|
||||
clearable
|
||||
placeholder="请输入考生姓名"
|
||||
minlength="1"
|
||||
maxlength="6"
|
||||
v-model="ruleForm.user_name"
|
||||
@input="filter(ruleForm.user_name, 'user_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="身份证号" prop="identity_card">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchIdentityCard"
|
||||
clearable
|
||||
placeholder="请输入身份证号"
|
||||
minlength="18"
|
||||
maxlength="18"
|
||||
v-model="ruleForm.identity_card"
|
||||
@input="filter(ruleForm.identity_card, 'identity_card')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试uid" prop="exam_uid">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchExamUid"
|
||||
clearable
|
||||
placeholder="请输入考试uid"
|
||||
minlength="10"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.exam_uid"
|
||||
@input="filter(ruleForm.exam_uid, 'exam_uid')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="参与状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择参与状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考生成绩" prop="grades">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入考生成绩"
|
||||
minlength="1"
|
||||
maxlength="5"
|
||||
v-model="ruleForm.grades"
|
||||
@input="filter(ruleForm.grades, 'grades')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试结果" prop="pass_type">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择考试结果"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.pass_type"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.passTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
identity_card: "",
|
||||
user_name: "",
|
||||
exam_uid: "",
|
||||
status: "",
|
||||
grades: "",
|
||||
pass_type: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const identityCardRegex = /^[1-9](?:\d{5})(?:19|20)?\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}(?:\d|X|x)$/;
|
||||
|
||||
const searchUserName = (value, cb) => {
|
||||
const data = {
|
||||
user_name: value,
|
||||
};
|
||||
$http.post($url.searchUserName, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateUserName = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入考生姓名"));
|
||||
} else {
|
||||
const data = {
|
||||
user_name: value,
|
||||
};
|
||||
$http.post($url.findUserName, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该考生不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const searchIdentityCard = (value, cb) => {
|
||||
const data = {
|
||||
identity_card: value,
|
||||
};
|
||||
$http.post($url.searchIdentityCard, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateIdentityCard = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入身份证号"));
|
||||
} else if (!identityCardRegex.test(value)) {
|
||||
callback(new Error("身份证格式不正确,请重新输入!"));
|
||||
} else if (ruleForm.user_name == "") {
|
||||
callback(new Error("请输入考生姓名"));
|
||||
} else {
|
||||
const data = {
|
||||
identity_card: value,
|
||||
user_name: ruleForm.user_name,
|
||||
};
|
||||
$http.post($url.findIdentityCard, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else if (res.data.code === 303) {
|
||||
callback(new Error("考生身份证号码与考生姓名不匹配!"));
|
||||
} else {
|
||||
callback(new Error("该考生身份证号未注册!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const searchExamUid = (value, cb) => {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.searchExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateExamUid = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入考试uid"));
|
||||
} else {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.findExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该考试不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
identity_card: [{ required: true, validator: validateIdentityCard, trigger: "blur" }],
|
||||
user_name: [{ required: true, validator: validateUserName, trigger: "blur" }],
|
||||
exam_uid: [{ required: true, validator: validateExamUid, trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择参与状态", trigger: "change" }],
|
||||
grades: [{ required: true, message: "请输入考生成绩", trigger: "blur" }],
|
||||
pass_type: [{ required: true, message: "请选择考试结果", trigger: "change" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addGrades"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addGrades", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
101
src/components/addNewData/topicWhitelistForm/excleAdd.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
phone: {
|
||||
value: "",
|
||||
label: "电话号码",
|
||||
},
|
||||
type: {
|
||||
value: "",
|
||||
label: "白名单类型",
|
||||
},
|
||||
expired_at: {
|
||||
value: "",
|
||||
label: "白名单过期时间",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "电话号码",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "白名单类型",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "白名单过期时间",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addTopicWhitelist"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
phone: item[relatedRules.phone.value],
|
||||
type: item[relatedRules.type.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addTopicWhitelist", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
116
src/components/addNewData/topicWhitelistForm/multipleAdd.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "白名单1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addTopicWhitelist"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.type = singleAddRef.value[0].ruleForm.typw;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `白名单${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addTopicWhitelist", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
123
src/components/addNewData/topicWhitelistForm/singleAdd.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="电话号码" prop="phone">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入电话号码"
|
||||
minlength="11"
|
||||
maxlength="11"
|
||||
v-model="ruleForm.phone"
|
||||
@input="filter(ruleForm.phone, 'phone')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="白名单类型" prop="type">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择白名单类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.type"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="白名单过期时间">
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="expired_at">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.expired_at"
|
||||
type="datetime"
|
||||
placeholder="请选择白名单过期时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
phone: "",
|
||||
type: "",
|
||||
expired_at: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const rules = reactive({
|
||||
phone: [{ required: true, message: "请输入手机号码", trigger: "blur" }],
|
||||
type: [{ required: true, message: "请选择白名单类型", trigger: "change" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addTopicWhitelist"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addTopicWhitelist", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="topicWhitelistActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addTopicWhitelist="addTopicWhitelist"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addTopicWhitelist="addTopicWhitelist"
|
||||
/>
|
||||
<ExcleAdd
|
||||
ref="excleAddRef"
|
||||
v-if="dialogExcleVisible"
|
||||
@addTopicWhitelist="addTopicWhitelist"
|
||||
/>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import topicWhitelistActiveStore from "../../../stores/topicWhitelist";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes";
|
||||
|
||||
const topicWhitelistActive = topicWhitelistActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
topicWhitelistActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
topicWhitelistActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
topicWhitelistActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
topicWhitelistActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
topicWhitelistActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
topicWhitelistActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
topicWhitelistActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
topicWhitelistActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
topicWhitelistActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addTopicWhitelist = (requestMsg) => {
|
||||
requestMsg.forEach((element) => {
|
||||
element.phone = encrypt(String(element.phone));
|
||||
element.type = encrypt(String(element.type));
|
||||
element.expired_at = encrypt(String(element.expired_at));
|
||||
});
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addTopicWhitelist, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增题库白名单成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增题库白名单失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
stem: {
|
||||
value: "",
|
||||
label: "题干",
|
||||
},
|
||||
answer: {
|
||||
value: "",
|
||||
label: "答案",
|
||||
},
|
||||
difficulty: {
|
||||
value: "",
|
||||
label: "难度",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "题干",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "答案",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "难度",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addInterlocution"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
stem: item[relatedRules.stem.value],
|
||||
answer: item[relatedRules.answer.value],
|
||||
difficulty: item[relatedRules.difficulty.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addInterlocution", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="interlocutionMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addInterlocution="addInterlocution"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addInterlocution="addInterlocution"
|
||||
/>
|
||||
<ExcleAdd
|
||||
ref="excleAddRef"
|
||||
v-if="dialogExcleVisible"
|
||||
@addInterlocution="addInterlocution"
|
||||
/>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import interlocutionActiveStore from "../../../../stores/trainindTopic/interlocution.js";
|
||||
|
||||
import $http from "../../../../api/index";
|
||||
import $url from "../../../../api/url";
|
||||
|
||||
const interlocutionMsgActive = interlocutionActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
interlocutionMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
interlocutionMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
interlocutionMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
interlocutionMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
interlocutionMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
interlocutionMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
interlocutionMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
interlocutionMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
interlocutionMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addInterlocution = (requestMsg) => {
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addInterlocution, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增问答题成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增问答题失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "问答题1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addInterlocution"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.role = singleAddRef.value[0].ruleForm.role;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `问答题${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addInterlocution", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="题干" prop="stem">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="答案" prop="answer">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入答案"
|
||||
v-model="ruleForm.answer"
|
||||
@input="filter(ruleForm.answer, 'answer')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请输入答案", trigger: "blur" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addInterlocution"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addInterlocution", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
102
src/components/addNewData/trainindTopic/judgment/excleAdd.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
stem: {
|
||||
value: "",
|
||||
label: "题干",
|
||||
},
|
||||
answer: {
|
||||
value: "",
|
||||
label: "答案",
|
||||
},
|
||||
difficulty: {
|
||||
value: "",
|
||||
label: "难度",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "题干",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "答案",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "难度",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addJudgment"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
stem: item[relatedRules.stem.value],
|
||||
answer: item[relatedRules.answer.value],
|
||||
difficulty: item[relatedRules.difficulty.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addJudgment", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="judgmentMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addJudgment="addJudgment"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addJudgment="addJudgment"
|
||||
/>
|
||||
<ExcleAdd ref="excleAddRef" v-if="dialogExcleVisible" @addJudgment="addJudgment" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import judgmentActiveStore from "../../../../stores/trainindTopic/judgment.js";
|
||||
|
||||
import $http from "../../../../api/index";
|
||||
import $url from "../../../../api/url";
|
||||
|
||||
const judgmentMsgActive = judgmentActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
judgmentMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
judgmentMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
judgmentMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
judgmentMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
judgmentMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
judgmentMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
judgmentMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
judgmentMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
judgmentMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addJudgment = (requestMsg) => {
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addJudgment, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增判断题成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增判断题失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
116
src/components/addNewData/trainindTopic/judgment/multipleAdd.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "判断题1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addJudgment"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.role = singleAddRef.value[0].ruleForm.role;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `判断题${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addJudgment", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
129
src/components/addNewData/trainindTopic/judgment/singleAdd.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="题干" prop="stem">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="答案" prop="answer">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择答案"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.answer"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.answerOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请选择答案", trigger: "change" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addJudgment"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addJudgment", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
152
src/components/addNewData/trainindTopic/multiple/excleAdd.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
stem: {
|
||||
value: "",
|
||||
label: "题干",
|
||||
},
|
||||
options_a: {
|
||||
value: "",
|
||||
label: "选项A",
|
||||
},
|
||||
options_b: {
|
||||
value: "",
|
||||
label: "选项B",
|
||||
},
|
||||
options_c: {
|
||||
value: "",
|
||||
label: "选项C",
|
||||
},
|
||||
options_d: {
|
||||
value: "",
|
||||
label: "选项D",
|
||||
},
|
||||
options_e: {
|
||||
value: "",
|
||||
label: "选项E",
|
||||
},
|
||||
answer: {
|
||||
value: "",
|
||||
label: "答案",
|
||||
},
|
||||
difficulty: {
|
||||
value: "",
|
||||
label: "难度",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "题干",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "选项A",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "选项B",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "选项C",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "选项D",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "选项E",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "6",
|
||||
label: "答案",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "7",
|
||||
label: "难度",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addMultiple"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
stem: item[relatedRules.stem.value],
|
||||
options_a: item[relatedRules.options_a.value],
|
||||
options_b: item[relatedRules.options_b.value],
|
||||
options_c: item[relatedRules.options_c.value],
|
||||
options_d: item[relatedRules.options_d.value],
|
||||
options_e: item[relatedRules.options_e.value],
|
||||
answer: item[relatedRules.answer.value],
|
||||
difficulty: item[relatedRules.difficulty.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addMultiple", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
116
src/components/addNewData/trainindTopic/multiple/multipleAdd.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "多选题1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addMultiple"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.role = singleAddRef.value[0].ruleForm.role;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `多选题${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addMultiple", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="multipleMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addMultiple="addMultiple"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addMultiple="addMultiple"
|
||||
/>
|
||||
<ExcleAdd ref="excleAddRef" v-if="dialogExcleVisible" @addMultiple="addMultiple" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import multipleActiveStore from "../../../../stores/trainindTopic/multiple.js";
|
||||
|
||||
import $http from "../../../../api/index";
|
||||
import $url from "../../../../api/url";
|
||||
|
||||
const multipleMsgActive = multipleActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
multipleMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
multipleMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
multipleMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
multipleMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
multipleMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
multipleMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
multipleMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
multipleMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
multipleMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addMultiple = (requestMsg) => {
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addMultiple, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增多选题成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增多选题失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
168
src/components/addNewData/trainindTopic/multiple/singleAdd.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="题干" prop="stem">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项A" prop="options_a">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项A"
|
||||
v-model="ruleForm.options_a"
|
||||
@input="filter(ruleForm.options_a, 'options_a')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项B" prop="options_b">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项B"
|
||||
v-model="ruleForm.options_b"
|
||||
@input="filter(ruleForm.options_b, 'options_b')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项C" prop="options_c">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项C"
|
||||
v-model="ruleForm.options_c"
|
||||
@input="filter(ruleForm.options_c, 'options_c')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项D" prop="options_d">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项D"
|
||||
v-model="ruleForm.options_d"
|
||||
@input="filter(ruleForm.options_d, 'options_d')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项E" prop="options_e">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项E"
|
||||
v-model="ruleForm.options_e"
|
||||
@input="filter(ruleForm.options_e, 'options_e')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="答案" prop="answer">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入答案"
|
||||
v-model="ruleForm.answer"
|
||||
@input="filter(ruleForm.answer, 'answer')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
options_a: "",
|
||||
options_b: "",
|
||||
options_c: "",
|
||||
options_d: "",
|
||||
options_e: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
options_a: [{ required: true, message: "请输入选项A", trigger: "blur" }],
|
||||
options_b: [{ required: true, message: "请输入选项B", trigger: "blur" }],
|
||||
options_c: [{ required: true, message: "请输入选项C", trigger: "blur" }],
|
||||
options_d: [{ required: true, message: "请输入选项D", trigger: "blur" }],
|
||||
options_e: [{ required: true, message: "请输入选项E", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请输入答案", trigger: "blur" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addMultiple"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addMultiple", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
142
src/components/addNewData/trainindTopic/radio/excleAdd.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
stem: {
|
||||
value: "",
|
||||
label: "题干",
|
||||
},
|
||||
options_a: {
|
||||
value: "",
|
||||
label: "选项A",
|
||||
},
|
||||
options_b: {
|
||||
value: "",
|
||||
label: "选项B",
|
||||
},
|
||||
options_c: {
|
||||
value: "",
|
||||
label: "选项C",
|
||||
},
|
||||
options_d: {
|
||||
value: "",
|
||||
label: "选项D",
|
||||
},
|
||||
answer: {
|
||||
value: "",
|
||||
label: "答案",
|
||||
},
|
||||
difficulty: {
|
||||
value: "",
|
||||
label: "难度",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "题干",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "选项A",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "选项B",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "选项C",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "选项D",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "答案",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "6",
|
||||
label: "难度",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addRadio"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
stem: item[relatedRules.stem.value],
|
||||
options_a: item[relatedRules.options_a.value],
|
||||
options_b: item[relatedRules.options_b.value],
|
||||
options_c: item[relatedRules.options_c.value],
|
||||
options_d: item[relatedRules.options_d.value],
|
||||
answer: item[relatedRules.answer.value],
|
||||
difficulty: item[relatedRules.difficulty.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addRadio", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
116
src/components/addNewData/trainindTopic/radio/multipleAdd.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "单选题1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addRadio"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.ruleForm.role = singleAddRef.value[0].ruleForm.role;
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `单选题${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addRadio", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
157
src/components/addNewData/trainindTopic/radio/radioForm.vue
Normal file
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="radioMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addRadio="addRadio"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="true"
|
||||
:addData="addData"
|
||||
@addRadio="addRadio"
|
||||
/>
|
||||
<ExcleAdd ref="excleAddRef" v-if="dialogExcleVisible" @addRadio="addRadio" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import radioActiveStore from "../../../../stores/trainindTopic/radio.js";
|
||||
|
||||
import $http from "../../../../api/index";
|
||||
import $url from "../../../../api/url";
|
||||
|
||||
const radioMsgActive = radioActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
radioMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
radioMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
radioMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
radioMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
radioMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
radioMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
radioMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
radioMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
radioMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addRadio = (requestMsg) => {
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addRadio, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增单选题成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增单选题失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
158
src/components/addNewData/trainindTopic/radio/singleAdd.vue
Normal file
@@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="题干" prop="stem">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项A" prop="options_a">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项A"
|
||||
v-model="ruleForm.options_a"
|
||||
@input="filter(ruleForm.options_a, 'options_a')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项B" prop="options_b">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项B"
|
||||
v-model="ruleForm.options_b"
|
||||
@input="filter(ruleForm.options_b, 'options_b')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项C" prop="options_c">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项C"
|
||||
v-model="ruleForm.options_c"
|
||||
@input="filter(ruleForm.options_c, 'options_c')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="选项D" prop="options_d">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项D"
|
||||
v-model="ruleForm.options_d"
|
||||
@input="filter(ruleForm.options_d, 'options_d')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="答案" prop="answer">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入答案"
|
||||
v-model="ruleForm.answer"
|
||||
@input="filter(ruleForm.answer, 'answer')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in addData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
options_a: "",
|
||||
options_b: "",
|
||||
options_c: "",
|
||||
options_d: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
options_a: [{ required: true, message: "请输入选项A", trigger: "blur" }],
|
||||
options_b: [{ required: true, message: "请输入选项B", trigger: "blur" }],
|
||||
options_c: [{ required: true, message: "请输入选项C", trigger: "blur" }],
|
||||
options_d: [{ required: true, message: "请输入选项D", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请输入答案", trigger: "blur" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addRadio"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addRadio", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
132
src/components/addNewData/userForm/excleAdd.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import UploadFile from "../../operate/uploadFile.vue";
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
phone: {
|
||||
value: "",
|
||||
label: "手机号码",
|
||||
},
|
||||
user_name: {
|
||||
value: "",
|
||||
label: "真实姓名",
|
||||
},
|
||||
identity_card: {
|
||||
value: "",
|
||||
label: "身份证号",
|
||||
},
|
||||
workplace: {
|
||||
value: "",
|
||||
label: "工作单位",
|
||||
},
|
||||
email: {
|
||||
value: "",
|
||||
label: "电子邮箱",
|
||||
},
|
||||
address: {
|
||||
value: "",
|
||||
label: "通讯地址",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "手机号码",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "真实姓名",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "身份证号",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "工作单位",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "电子邮箱",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "通讯地址",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["addUser"]);
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!uploadFileRef) return;
|
||||
uploadFileRef.value.handleExceed();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
user_name: item[relatedRules.user_name.value],
|
||||
identity_card: item[relatedRules.identity_card.value],
|
||||
workplace: item[relatedRules.workplace.value],
|
||||
address: item[relatedRules.address.value],
|
||||
phone: item[relatedRules.phone.value],
|
||||
email: item[relatedRules.email.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
emit("addUser", formClone.value);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
114
src/components/addNewData/userForm/multipleAdd.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="flex flex-warp justify-center items-center font-bold"
|
||||
>
|
||||
<div style="font-size: 1rem">请输入要导入的数据数量:</div>
|
||||
<el-input-number v-model="singleFormNum" :min="1" :max="10" @change="createForm" />
|
||||
<div v-if="checkNeed"> </div>
|
||||
<el-checkbox
|
||||
v-if="checkNeed"
|
||||
v-model="checked"
|
||||
label="为所有表单进行相同操作"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<el-scrollbar max-height="40rem">
|
||||
<div class="mt-2 border-2 border-gray-300" v-for="item in input">
|
||||
<div style="font-size: 1.2rem" class="w-full text-center font-bold">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<SingleAdd ref="singleAddRef" :addData="addData" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
|
||||
const singleFormNum = ref(1);
|
||||
const checked = ref(true);
|
||||
const input = ref([{ label: "用户1" }]);
|
||||
const singleAddRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
checkNeed: Boolean,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addUser"]);
|
||||
|
||||
const initData = () => {
|
||||
setTimeout(() => {
|
||||
singleAddRef.value.forEach((item) => {});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const createForm = () => {
|
||||
let difference = Math.abs(singleFormNum.value - input.value.length);
|
||||
for (let i = 0; i < difference; i++) {
|
||||
if (singleFormNum.value > input.value.length) {
|
||||
input.value.push({ label: `用户${input.value.length + 1}` });
|
||||
} else if (singleFormNum.value < input.value.length) {
|
||||
input.value.pop();
|
||||
}
|
||||
}
|
||||
if (checked.value) {
|
||||
initData();
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!singleAddRef) return;
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.resetCheckForm();
|
||||
});
|
||||
singleFormNum.value = 1;
|
||||
createForm();
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (!singleAddRef) return;
|
||||
let valid = true;
|
||||
formClone.value = [];
|
||||
singleAddRef.value.forEach((element) => {
|
||||
element.validate().then((result) => {
|
||||
if (result) {
|
||||
formClone.value.push({ ...element.ruleForm });
|
||||
} else {
|
||||
valid = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (valid) {
|
||||
emit("addUser", formClone.value);
|
||||
singleAddRef.value.forEach((item) => {
|
||||
item.resetCheckForm();
|
||||
});
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, formClone });
|
||||
|
||||
watch(checked, (value) => {
|
||||
if (value) {
|
||||
initData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
224
src/components/addNewData/userForm/singleAdd.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="姓名" prop="user_name">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入姓名"
|
||||
minlength="2"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.user_name"
|
||||
@input="filter(ruleForm.user_name, 'user_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="身份证号" prop="identity_card">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入身份证号"
|
||||
minlength="18"
|
||||
maxlength="18"
|
||||
v-model="ruleForm.identity_card"
|
||||
@input="filter(ruleForm.identity_card, 'identity_card')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="工作单位" prop="workplace">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入工作单位"
|
||||
maxlength="60"
|
||||
v-model="ruleForm.workplace"
|
||||
@input="filter(ruleForm.workplace, 'workplace')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="通讯地址" prop="address">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入通讯地址"
|
||||
maxlength="120"
|
||||
v-model="ruleForm.address"
|
||||
@input="filter(ruleForm.address, 'address')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="手机号码" prop="phone">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入手机号码"
|
||||
minlength="11"
|
||||
maxlength="11"
|
||||
v-model="ruleForm.phone"
|
||||
@input="filter(ruleForm.phone, 'phone')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="电子邮箱号码" prop="email">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入电子邮箱号码"
|
||||
minlength="8"
|
||||
maxlength="60"
|
||||
v-model="ruleForm.email"
|
||||
@input="filter(ruleForm.email, 'email')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
const ruleFormRef = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
user_name: "",
|
||||
identity_card: "",
|
||||
workplace: "",
|
||||
address: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
});
|
||||
|
||||
const formClone = ref({});
|
||||
|
||||
const identityCardRegex = /^[1-9](?:\d{5})(?:19|20)?\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}(?:\d|X|x)$/;
|
||||
const phoneRegex = /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[0123456789]))\d{8}$/;
|
||||
const emailRegex = /^([a-zA-Z0-9]+[|-|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[|-|.]?)*[a-zA-Z0-9]+(.[a-zA-Z]{2,3})+$/;
|
||||
|
||||
const validateIdentityCard = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入身份证号"));
|
||||
} else if (!identityCardRegex.test(value)) {
|
||||
callback(new Error("身份证格式不正确,请重新输入!"));
|
||||
} else {
|
||||
const data = {
|
||||
identity_card: value,
|
||||
type: "register",
|
||||
data: "null",
|
||||
};
|
||||
$http.post($url.diffIdentityCard, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该身份证号已被注册"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validatePhone = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入手机号码"));
|
||||
} else if (!phoneRegex.test(value)) {
|
||||
callback(new Error("手机号码格式错误, 请重新输入!"));
|
||||
} else {
|
||||
const data = {
|
||||
phone: value,
|
||||
type: "register",
|
||||
data: "null",
|
||||
};
|
||||
$http.post($url.diffPhone, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该手机号码已被注册"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validateEmail = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入电子邮箱号码"));
|
||||
} else if (!emailRegex.test(value)) {
|
||||
callback(new Error("电子邮箱号码格式不正确,请重新输入!"));
|
||||
} else {
|
||||
const data = {
|
||||
email: value,
|
||||
type: "register",
|
||||
data: "null",
|
||||
};
|
||||
$http.post($url.diffEmail, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该电子邮箱号码已被注册"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
user_name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
||||
identity_card: [{ required: true, validator: validateIdentityCard, trigger: "blur" }],
|
||||
workplace: {
|
||||
required: true,
|
||||
message: "请输入工作单位(若没有则填“无”)",
|
||||
trigger: "blur",
|
||||
},
|
||||
address: { required: true, message: "请输入通讯地址(若没有则填“无”)", trigger: "blur" },
|
||||
phone: [{ required: true, validator: validatePhone, trigger: "blur" }],
|
||||
email: [
|
||||
{ required: true, validator: validateEmail, trigger: "blur" },
|
||||
{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] },
|
||||
],
|
||||
});
|
||||
|
||||
const emit = defineEmits(["addUser"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (label == "phone") {
|
||||
ruleForm.phone = value.replace(/\D/g, "");
|
||||
} else {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (!ruleFormRef) return;
|
||||
ruleFormRef.value.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async () => {
|
||||
if (!ruleFormRef) return;
|
||||
await ruleFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
formClone.value = { ...ruleForm };
|
||||
emit("addUser", [formClone.value]);
|
||||
ruleFormRef.value.resetFields();
|
||||
ElMessage({
|
||||
message: `提交成功!`,
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
if (!ruleFormRef) return Promise.resolve(false);
|
||||
return new Promise((resolve) => {
|
||||
ruleFormRef.value.validate((valid) => {
|
||||
resolve(valid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ resetCheckForm, confirm, validate, ruleForm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
170
src/components/addNewData/userForm/userForm.vue
Normal file
@@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="resetCheckForm"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<FormTools @showTools="showTools" :dialogObj="userMsgActive" />
|
||||
<SingleAdd
|
||||
ref="singleAddRef"
|
||||
v-if="dialogSingleVisible"
|
||||
:addData="addData"
|
||||
@addUser="addUser"
|
||||
/>
|
||||
<MultipleAdd
|
||||
ref="multipleAddRef"
|
||||
v-if="dialogMultipleVisible"
|
||||
:checkNeed="false"
|
||||
:addData="addData"
|
||||
@addUser="addUser"
|
||||
/>
|
||||
<ExcleAdd ref="excleAddRef" v-if="dialogExcleVisible" @addUser="addUser" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm"> 取消 </el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import FormTools from "../../operate/formTools.vue";
|
||||
import SingleAdd from "./singleAdd.vue";
|
||||
import MultipleAdd from "./multipleAdd.vue";
|
||||
import ExcleAdd from "./excleAdd.vue";
|
||||
|
||||
import userActiveStore from "../../../stores/userMsg";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes";
|
||||
|
||||
const userMsgActive = userActiveStore();
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const singleAddRef = ref(null);
|
||||
const multipleAddRef = ref(null);
|
||||
const excleAddRef = ref(null);
|
||||
const dialogSingleVisible = ref(true);
|
||||
const dialogMultipleVisible = ref(false);
|
||||
const dialogExcleVisible = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
addData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["reloadData"]);
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "single":
|
||||
dialogSingleVisible.value = true;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = false;
|
||||
userMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
userMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
userMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "multiple":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = true;
|
||||
dialogExcleVisible.value = false;
|
||||
userMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
userMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
userMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
case "excle":
|
||||
dialogSingleVisible.value = false;
|
||||
dialogMultipleVisible.value = false;
|
||||
dialogExcleVisible.value = true;
|
||||
userMsgActive.dialogSingleVisible = dialogSingleVisible.value;
|
||||
userMsgActive.dialogMultipleVisible = dialogMultipleVisible.value;
|
||||
userMsgActive.dialogExcleVisible = dialogExcleVisible.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.resetCheckForm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.resetCheckForm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.resetCheckForm();
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
if (dialogSingleVisible.value) {
|
||||
singleAddRef.value.confirm();
|
||||
} else if (dialogMultipleVisible.value) {
|
||||
multipleAddRef.value.confirm();
|
||||
} else if (dialogExcleVisible.value) {
|
||||
excleAddRef.value.confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const addUser = (requestMsg) => {
|
||||
requestMsg.forEach((element) => {
|
||||
element.account_name = encrypt(String(element.account_name));
|
||||
element.identity_card = encrypt(String(element.identity_card));
|
||||
element.user_name = encrypt(String(element.user_name));
|
||||
element.gender = encrypt(String(element.gender));
|
||||
element.age = encrypt(String(element.age));
|
||||
element.email = encrypt(String(element.email));
|
||||
element.phone = encrypt(String(element.phone));
|
||||
element.address = encrypt(String(element.address));
|
||||
element.workplace = encrypt(String(element.workplace));
|
||||
});
|
||||
const data = { requestMsg };
|
||||
$http.post($url.addUser, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
resetCheckForm();
|
||||
ElMessage({
|
||||
message: "新增用户信息成功!",
|
||||
type: "success",
|
||||
});
|
||||
emit("reloadData");
|
||||
} else {
|
||||
ElMessage.error("新增用户信息失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ dialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
204
src/components/editData/adminForm.vue
Normal file
@@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="账号名"
|
||||
prop="account_name"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入账号名"
|
||||
minlength="2"
|
||||
maxlength="5"
|
||||
v-model="ruleForm.account_name"
|
||||
@input="filter(ruleForm.account_name, 'account_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="权限等级" prop="role">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择权限等级"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.role"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.roleOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="账号状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择账号状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
account_name: "",
|
||||
role: "",
|
||||
status: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
account_name: [{ required: true, message: "请输入账号名", trigger: "blur" }],
|
||||
role: [{ required: true, message: "请选择权限等级", trigger: "change" }],
|
||||
status: [{ required: true, message: "请选择账号状态", trigger: "change" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
238
src/components/editData/applicationForm.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="考试uid" prop="exam_uid">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchExamUid"
|
||||
clearable
|
||||
placeholder="请输入考试uid"
|
||||
minlength="10"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.exam_uid"
|
||||
@input="filter(ruleForm.exam_uid, 'exam_uid')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名来源" prop="source">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入报名来源"
|
||||
maxlength="24"
|
||||
v-model="ruleForm.source"
|
||||
@input="filter(ruleForm.source, 'source')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择报名状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="缴费状态" prop="pay_status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择缴费状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.pay_status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.payStatusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名结果说明" prop="result">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入报名结果说明"
|
||||
maxlength="24"
|
||||
v-model="ruleForm.result"
|
||||
@input="filter(ruleForm.result, 'result')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
const password = ref("");
|
||||
|
||||
const ruleForm = reactive({
|
||||
exam_uid: "",
|
||||
source: "",
|
||||
status: "",
|
||||
pay_status: "",
|
||||
result: "",
|
||||
});
|
||||
|
||||
const searchExamUid = (value, cb) => {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.searchExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
exam_uid: [{ required: true, message: "请输入考试uid", trigger: "blur" }],
|
||||
source: [{ required: true, message: "请输入报名来源", trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择报名状态", trigger: "change" }],
|
||||
pay_status: [{ required: true, message: "请选择缴费状态", trigger: "change" }],
|
||||
result: [{ required: true, message: "请输入报名结果说明", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
createdAt: String,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
248
src/components/editData/examForm.vue
Normal file
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="考试名称"
|
||||
prop="exam_name"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入考试名称"
|
||||
maxlength="60"
|
||||
v-model="ruleForm.exam_name"
|
||||
@input="filter(ruleForm.exam_name, 'exam_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择考试状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="报名起止时间">
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="application_start">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.application_start"
|
||||
type="datetime"
|
||||
placeholder="请选择报名开始时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" class="text-center">
|
||||
<span class="text-gray-500">-</span>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="application_end">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.application_end"
|
||||
type="datetime"
|
||||
placeholder="请选择报名结束时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item label="考试起止时间">
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="exam_start">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.exam_start"
|
||||
type="datetime"
|
||||
placeholder="请选择考试开始时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" class="text-center">
|
||||
<span class="text-gray-500">-</span>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="exam_end">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.exam_end"
|
||||
type="datetime"
|
||||
placeholder="请选择考试结束时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
exam_name: "",
|
||||
status: "",
|
||||
application_start: "",
|
||||
application_end: "",
|
||||
exam_start: "",
|
||||
exam_end: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
exam_name: [{ required: true, message: "请输入考试名称", trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择考试状态", trigger: "change" }],
|
||||
application_start: [
|
||||
{ type: "date", required: true, message: "请选择报名开始时间", trigger: "change" },
|
||||
],
|
||||
application_end: [
|
||||
{ type: "date", required: true, message: "请选择报名结束时间", trigger: "change" },
|
||||
],
|
||||
exam_start: [
|
||||
{ type: "date", required: true, message: "请选择考试开始时间", trigger: "change" },
|
||||
],
|
||||
exam_end: [
|
||||
{ type: "date", required: true, message: "请选择考试结束时间", trigger: "change" },
|
||||
],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
199
src/components/editData/gradesForm.vue
Normal file
@@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="参与状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择参与状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考生成绩" prop="grades">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入考生成绩(没有则填“无”)"
|
||||
minlength="1"
|
||||
maxlength="5"
|
||||
v-model="ruleForm.grades"
|
||||
@input="filter(ruleForm.grades, 'grades')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试结果" prop="pass_type">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择考试结果"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.pass_type"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.passTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
status: "",
|
||||
grades: "",
|
||||
pass_type: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
status: [{ required: true, message: "请选择参与状态", trigger: "change" }],
|
||||
grades: [{ required: true, message: "请输入考生成绩", trigger: "blur" }],
|
||||
pass_type: [{ required: true, message: "请选择考试结果", trigger: "change" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
171
src/components/editData/topicWhitelistForm.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="权限等级" prop="type">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择权限等级"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.type"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="白名单过期时间">
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="expired_at">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.expired_at"
|
||||
type="datetime"
|
||||
placeholder="请选择白名单过期时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
type: "",
|
||||
expired_at: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
type: [{ required: true, message: "请选择白名单类型", trigger: "change" }],
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
196
src/components/editData/trainindTopic/interlocution.vue
Normal file
@@ -0,0 +1,196 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="题干"
|
||||
prop="stem"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="答案"
|
||||
prop="answer"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入答案"
|
||||
v-model="ruleForm.answer"
|
||||
@input="filter(ruleForm.answer, 'answer')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请输入答案", trigger: "blur" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
202
src/components/editData/trainindTopic/judgment.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="题干"
|
||||
prop="stem"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="答案" prop="answer">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择答案"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.answer"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.answerOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请选择答案", trigger: "change" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
271
src/components/editData/trainindTopic/multiple.vue
Normal file
@@ -0,0 +1,271 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="题干"
|
||||
prop="stem"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项A"
|
||||
prop="options_a"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项A"
|
||||
v-model="ruleForm.options_a"
|
||||
@input="filter(ruleForm.options_a, 'options_a')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项B"
|
||||
prop="options_c"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项B"
|
||||
v-model="ruleForm.options_c"
|
||||
@input="filter(ruleForm.options_c, 'options_c')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项C"
|
||||
prop="options_c"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项C"
|
||||
v-model="ruleForm.options_c"
|
||||
@input="filter(ruleForm.options_c, 'options_c')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项D"
|
||||
prop="options_d"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项D"
|
||||
v-model="ruleForm.options_d"
|
||||
@input="filter(ruleForm.options_d, 'options_d')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项E"
|
||||
prop="options_e"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项E"
|
||||
v-model="ruleForm.options_e"
|
||||
@input="filter(ruleForm.options_e, 'options_e')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="答案"
|
||||
prop="answer"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入答案"
|
||||
v-model="ruleForm.answer"
|
||||
@input="filter(ruleForm.answer, 'answer')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
options_a: "",
|
||||
options_b: "",
|
||||
options_c: "",
|
||||
options_d: "",
|
||||
options_e: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
options_a: [{ required: true, message: "请输入选项A", trigger: "blur" }],
|
||||
options_b: [{ required: true, message: "请输入选项B", trigger: "blur" }],
|
||||
options_c: [{ required: true, message: "请输入选项C", trigger: "blur" }],
|
||||
options_d: [{ required: true, message: "请输入选项D", trigger: "blur" }],
|
||||
options_e: [{ required: true, message: "请输入选项E", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请输入答案", trigger: "blur" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
256
src/components/editData/trainindTopic/radio.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="题干"
|
||||
prop="stem"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入题干"
|
||||
v-model="ruleForm.stem"
|
||||
@input="filter(ruleForm.stem, 'stem')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项A"
|
||||
prop="options_a"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项A"
|
||||
v-model="ruleForm.options_a"
|
||||
@input="filter(ruleForm.options_a, 'options_a')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项B"
|
||||
prop="options_b"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项B"
|
||||
v-model="ruleForm.options_b"
|
||||
@input="filter(ruleForm.options_b, 'options_b')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项C"
|
||||
prop="options_c"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项C"
|
||||
v-model="ruleForm.options_c"
|
||||
@input="filter(ruleForm.options_c, 'options_c')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="选项D"
|
||||
prop="options_d"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入选项D"
|
||||
v-model="ruleForm.options_d"
|
||||
@input="filter(ruleForm.options_d, 'options_d')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="答案"
|
||||
prop="answer"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入答案"
|
||||
v-model="ruleForm.answer"
|
||||
@input="filter(ruleForm.answer, 'answer')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="难度" prop="difficulty">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择难度"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.difficulty"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.difficultyOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
stem: "",
|
||||
options_a: "",
|
||||
options_b: "",
|
||||
options_c: "",
|
||||
options_d: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const rules = reactive({
|
||||
stem: [{ required: true, message: "请输入题干", trigger: "blur" }],
|
||||
options_a: [{ required: true, message: "请输入选项A", trigger: "blur" }],
|
||||
options_b: [{ required: true, message: "请输入选项B", trigger: "blur" }],
|
||||
options_c: [{ required: true, message: "请输入选项C", trigger: "blur" }],
|
||||
options_d: [{ required: true, message: "请输入选项D", trigger: "blur" }],
|
||||
answer: [{ required: true, message: "请输入答案", trigger: "blur" }],
|
||||
difficulty: [{ required: true, message: "请选择难度", trigger: "change" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
373
src/components/editData/userForm.vue
Normal file
@@ -0,0 +1,373 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="operateDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="姓名"
|
||||
prop="user_name"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入姓名"
|
||||
minlength="2"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.user_name"
|
||||
@input="filter(ruleForm.user_name, 'user_name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="身份证号"
|
||||
prop="identity_card"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入身份证号"
|
||||
minlength="18"
|
||||
maxlength="18"
|
||||
v-model="ruleForm.identity_card"
|
||||
@input="filter(ruleForm.identity_card, 'identity_card')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="mx-1 font-bold"
|
||||
label="身份证二要素核验状态"
|
||||
prop="real_check"
|
||||
>
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择身份证二要素核验状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.real_check"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.realCheckOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="工作单位"
|
||||
prop="workplace"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入工作单位"
|
||||
maxlength="60"
|
||||
v-model="ruleForm.workplace"
|
||||
@input="filter(ruleForm.workplace, 'workplace')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="通讯地址"
|
||||
prop="address"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入通讯地址"
|
||||
maxlength="120"
|
||||
v-model="ruleForm.address"
|
||||
@input="filter(ruleForm.address, 'address')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="手机号码"
|
||||
prop="phone"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入手机号码"
|
||||
minlength="11"
|
||||
maxlength="11"
|
||||
v-model="ruleForm.phone"
|
||||
@input="filter(ruleForm.phone, 'phone')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="model == 'single' ? true : false"
|
||||
class="mx-1 font-bold"
|
||||
label="电子邮箱号码"
|
||||
prop="email"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入电子邮箱号码"
|
||||
minlength="8"
|
||||
maxlength="60"
|
||||
v-model="ruleForm.email"
|
||||
@input="filter(ruleForm.email, 'email')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="账号状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择账号状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in editData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
@click="confirm(ruleFormRef)"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<PasswordOauth
|
||||
ref="editPasswordOauthRef"
|
||||
:operateLabel="operateLabel"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
|
||||
const operateDialogVisible = ref(false);
|
||||
const model = ref("single");
|
||||
const ruleFormRef = ref(null);
|
||||
const editPasswordOauthRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
uid: "",
|
||||
user_name: "",
|
||||
identity_card: "",
|
||||
real_check: "",
|
||||
workplace: "",
|
||||
address: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
status: "",
|
||||
});
|
||||
|
||||
const password = ref("");
|
||||
|
||||
const identityCardRegex = /^[1-9](?:\d{5})(?:19|20)?\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}(?:\d|X|x)$/;
|
||||
const phoneRegex = /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[0123456789]))\d{8}$/;
|
||||
const emailRegex = /^([a-zA-Z0-9]+[|-|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[|-|.]?)*[a-zA-Z0-9]+(.[a-zA-Z]{2,3})+$/;
|
||||
|
||||
const validateIdentityCard = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入身份证号"));
|
||||
} else if (!identityCardRegex.test(value)) {
|
||||
callback(new Error("身份证格式不正确,请重新输入!"));
|
||||
} else {
|
||||
const data = {
|
||||
identity_card: value,
|
||||
type: "edit",
|
||||
data: ruleForm.uid,
|
||||
};
|
||||
$http.post($url.diffIdentityCard, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该身份证号已被注册"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validateEmail = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入电子邮箱号码"));
|
||||
} else if (!emailRegex.test(value)) {
|
||||
callback(new Error("电子邮箱号码格式不正确,请重新输入!"));
|
||||
} else {
|
||||
const data = {
|
||||
email: value,
|
||||
type: "edit",
|
||||
data: ruleForm.uid,
|
||||
};
|
||||
$http.post($url.diffEmail, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该电子邮箱号码已被注册"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validatePhone = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入手机号码"));
|
||||
} else if (!phoneRegex.test(value)) {
|
||||
callback(new Error("手机号码格式错误, 请重新输入!"));
|
||||
} else {
|
||||
const data = {
|
||||
phone: value,
|
||||
type: "edit",
|
||||
data: ruleForm.uid,
|
||||
};
|
||||
$http.post($url.diffPhone, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该手机号码已被注册"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
user_name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
||||
identity_card: [{ required: true, validator: validateIdentityCard, trigger: "blur" }],
|
||||
real_check: [
|
||||
{ required: true, message: "请选择身份证二要素核验状态", trigger: "change" },
|
||||
],
|
||||
workplace: {
|
||||
required: true,
|
||||
message: "请输入工作单位(若没有则填“无”)",
|
||||
trigger: "blur",
|
||||
},
|
||||
address: { required: true, message: "请输入通讯地址(若没有则填“无”)", trigger: "blur" },
|
||||
phone: [{ required: true, validator: validatePhone, trigger: "blur" }],
|
||||
email: [
|
||||
{ required: true, validator: validateEmail, trigger: "blur" },
|
||||
{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] },
|
||||
],
|
||||
status: [{ required: true, message: "请选择账号状态", trigger: "change" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (label == "phone") {
|
||||
ruleForm.phone = value.replace(/\D/g, "");
|
||||
} else if (label == "age") {
|
||||
ruleForm.age = value.replace(/\D/g, "");
|
||||
} else {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
editData: Object,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const resetForm = () => {
|
||||
for (let key in ruleForm) {
|
||||
if (ruleForm.hasOwnProperty(key)) {
|
||||
ruleForm[key] = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
operateDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
password.value = editPasswordOauthRef.value.ruleForm.password;
|
||||
emit("requestOperate");
|
||||
operateDialogVisible.value = false;
|
||||
formElClone.value.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
editPasswordOauthRef.value.operateDialogVisible = true;
|
||||
formElClone.value = formEl;
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ operateDialogVisible, model, ruleForm, password });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
777
src/components/features/adminList.vue
Normal file
@@ -0,0 +1,777 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="adminMsgActive" />
|
||||
<AddNewData newDataLabel="新增普通管理员" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="40rem"
|
||||
max-height="40rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="uid">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUidKeyRef"
|
||||
holderText="输入普通管理员uid以搜索相关数据"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 普通管理员uid </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.uid }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="160" column-key="account_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchAccountNameKeyRef"
|
||||
holderText="输入账号名称以搜索相关数据"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 账号名称 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.account_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="120" column-key="role">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectRoleSearchRef"
|
||||
holderText="选择权限等级以搜索相关数据"
|
||||
:options="roleOptions"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 权限等级 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(roleOptions, scope.row.role)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(roleOptions, scope.row.role) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="status">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectStatusSearchRef"
|
||||
holderText="选择账号状态以搜索相关数据"
|
||||
:options="statusOptions"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 账号状态 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(statusOptions, scope.row.status)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(statusOptions, scope.row.status) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="created_at">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="createdDateTimePickerRef"
|
||||
DateTimePicker="createdDateTimePicker"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 注册时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="createdSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.created_at }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="updated_at">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="updatedDateTimePickerRef"
|
||||
DateTimePicker="updatedMsgDateTimePicker"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 绑定状态变更时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="updatedSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.updated_at }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="80" column-key="login_status">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectLoginStatusSearchRef"
|
||||
holderText="选择登录状态以搜索相关数据"
|
||||
:options="loginStatusOptions"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 登录状态 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(loginStatusOptions, scope.row.login_status)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(loginStatusOptions, scope.row.login_status) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="adminMsgActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="adminMsg"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddAdminForm
|
||||
ref="addAdminFormRef"
|
||||
title="新增普通管理员"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="adminMsg"
|
||||
/>
|
||||
<EditAdminForm
|
||||
ref="editAdminFormRef"
|
||||
operateLabel="编辑普通管理员"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除普通管理员"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出管理员数据"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../operate/tabelTools.vue";
|
||||
import AddNewData from "../operate/addNewData.vue";
|
||||
import TabelSelect from "../operate/tabelSelect.vue";
|
||||
import SearchKey from "../search/searchKey.vue";
|
||||
import SortSearch from "../search/sortSearch.vue";
|
||||
import SelectSearch from "../search/selectSearch.vue";
|
||||
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||
import Pagination from "../search/pagination.vue";
|
||||
import AddAdminForm from "../addNewData/adminForm/adminForm.vue";
|
||||
import EditAdminForm from "../editData/adminForm.vue";
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
import DownloadData from "../operate/downloadData.vue";
|
||||
|
||||
import adminMsgActiveStore from "../../stores/adminMsg";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
import { encrypt } from "../../utils/aes.js";
|
||||
import { downloadData } from "../../utils/downloadData.js";
|
||||
import { judgment } from "../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const adminMsgActive = adminMsgActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑普通管理员",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除普通管理员",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchUidKeyRef = ref(null);
|
||||
const SearchAccountNameKeyRef = ref(null);
|
||||
const SelectRoleSearchRef = ref(null);
|
||||
const SelectStatusSearchRef = ref(null);
|
||||
const SelectLoginStatusSearchRef = ref(null);
|
||||
const createdDateTimePickerRef = ref(null);
|
||||
const updatedDateTimePickerRef = ref(null);
|
||||
const createdSortDateTimeRef = ref(null);
|
||||
const updatedSortDateTimeRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addAdminFormRef = ref(null);
|
||||
const editAdminFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
uid: "",
|
||||
account_name: "",
|
||||
role: "",
|
||||
status: "",
|
||||
created_at: "",
|
||||
updated_at: "",
|
||||
login_status: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({
|
||||
created_at: false,
|
||||
updated_at: false,
|
||||
});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const roleOptions = [
|
||||
{
|
||||
value: "9",
|
||||
label: "系统管理员",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "0",
|
||||
label: "临时管理员",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "普通管理员",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "高级管理员",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const statusOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "默认状态",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "正常使用",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "已被弃用",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const loginStatusOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "未登录",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "已登录",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
roleOptions,
|
||||
statusOptions,
|
||||
loginStatusOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
roleOptions,
|
||||
statusOptions,
|
||||
loginStatusOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addAdminFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
adminMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
adminMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
adminMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const adminMsg = () => {
|
||||
judgment(searchOptions, "uid", SearchUidKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "account_name", SearchAccountNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "role", SelectRoleSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "status", SelectStatusSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "created_at", createdDateTimePickerRef.value, "searchMsg");
|
||||
judgment(searchOptions, "updated_at", updatedDateTimePickerRef.value, "searchMsg");
|
||||
judgment(searchOptions, "login_status", SelectLoginStatusSearchRef.value, "searchMsg");
|
||||
judgment(sortOptions, "created_at", createdSortDateTimeRef.value, "searchMsg");
|
||||
judgment(sortOptions, "updated_at", updatedSortDateTimeRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showAdmin, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.adminMsg;
|
||||
tableData.value.forEach((item) => {
|
||||
item.origin_createdAt = item.created_at;
|
||||
item.created_at = moment
|
||||
.utc(item.created_at)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
item.origin_updatedAt = item.updated_at;
|
||||
item.updated_at = moment
|
||||
.utc(item.updated_at)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
});
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
adminMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
adminMsgActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.created_at == element.created_at) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.created_at == element.created_at) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((item) => {
|
||||
if (item.origin_createdAt) {
|
||||
item.created_at = item.origin_createdAt;
|
||||
}
|
||||
if (item.origin_updatedAt) {
|
||||
item.created_at = item.origin_updatedAt;
|
||||
}
|
||||
delete item.origin_createdAt;
|
||||
delete item.origin_updatedAt;
|
||||
delete item.location;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
singleData.created_at = singleData.origin_createdAt;
|
||||
singleData.updated_at = singleData.origin_updatedAt;
|
||||
delete singleData.origin_createdAt;
|
||||
delete singleData.origin_updatedAt;
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editAdminFormRef.value.model = EditSelectRef.value.model;
|
||||
editAdminFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
editAdminFormRef.value.ruleForm.account_name = singleData.account_name;
|
||||
roleOptions.forEach((item) => {
|
||||
if (item.value == singleData.role) {
|
||||
editAdminFormRef.value.ruleForm.role = item.label;
|
||||
}
|
||||
});
|
||||
statusOptions.forEach((item) => {
|
||||
if (item.value == singleData.status) {
|
||||
editAdminFormRef.value.ruleForm.status = item.label;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editAdmin;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editAdminFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteAdmin;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
data.updateMsg = { ...editAdminFormRef.value.ruleForm };
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
}
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
adminMsg();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
roleOptions.forEach((element) => {
|
||||
if (element.value == item["role"]) {
|
||||
item["role"] = element.label;
|
||||
}
|
||||
});
|
||||
statusOptions.forEach((element) => {
|
||||
if (element.value == item["status"]) {
|
||||
item["status"] = element.label;
|
||||
}
|
||||
});
|
||||
delete item.login_status;
|
||||
delete item.origin_createdAt;
|
||||
delete item.origin_updatedAt;
|
||||
});
|
||||
const dataHeaders = [
|
||||
"账号uid",
|
||||
"账号名称",
|
||||
"权限等级",
|
||||
"账号状态",
|
||||
"注册时间",
|
||||
"更新时间",
|
||||
];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadAdminData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ adminMsg });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
adminMsgActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
adminMsgActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = adminMsgActive.pageCount;
|
||||
dialogSearchVisible.value = adminMsgActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = adminMsgActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = adminMsgActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
adminMsgActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.uid = adminMsgActive.searchOptions.uid;
|
||||
searchOptions.account_name = adminMsgActive.searchOptions.account_name;
|
||||
searchOptions.role = adminMsgActive.searchOptions.role;
|
||||
searchOptions.status = adminMsgActive.searchOptions.status;
|
||||
searchOptions.created_at = adminMsgActive.searchOptions.created_at;
|
||||
searchOptions.updated_at = adminMsgActive.searchOptions.updated_at;
|
||||
searchOptions.login_status = adminMsgActive.searchOptions.login_status;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
sortOptions.created_at = adminMsgActive.sortOptions.created_at;
|
||||
sortOptions.updated_at = adminMsgActive.sortOptions.updated_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
adminMsg();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchUidKeyRef.value.searchMsg = adminMsgActive.searchOptions.uid;
|
||||
SearchAccountNameKeyRef.value.searchMsg = adminMsgActive.searchOptions.account_name;
|
||||
SelectRoleSearchRef.value.searchMsg = adminMsgActive.searchOptions.role;
|
||||
SelectStatusSearchRef.value.searchMsg = adminMsgActive.searchOptions.status;
|
||||
createdDateTimePickerRef.value.created_at = adminMsgActive.searchOptions.created_at;
|
||||
updatedDateTimePickerRef.value.updated_at = adminMsgActive.searchOptions.updated_at;
|
||||
SelectLoginStatusSearchRef.value.searchMsg =
|
||||
adminMsgActive.searchOptions.login_status;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
createdSortDateTimeRef.value.searchMsg = adminMsgActive.sortOptions.created_at;
|
||||
updatedSortDateTimeRef.value.searchMsg = adminMsgActive.sortOptions.updated_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
1277
src/components/features/applicationList.vue
Normal file
797
src/components/features/examList.vue
Normal file
@@ -0,0 +1,797 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="examMsgActive" />
|
||||
<AddNewData newDataLabel="新增考试信息" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="40rem"
|
||||
max-height="40rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="120" column-key="uid">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUidKeyRef"
|
||||
holderText="输入考试uid以搜索相关数据"
|
||||
@search="examMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试uid </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.uid }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchExamNameKeyRef"
|
||||
holderText="输入考试名称以搜索相关数据"
|
||||
@search="examMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试名称 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.exam_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="status">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectStatusSearchRef"
|
||||
holderText="选择考试状态以搜索相关数据"
|
||||
:options="statusOptions"
|
||||
@search="examMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试状态 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(statusOptions, scope.row.status)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(statusOptions, scope.row.status) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="application_start">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="applicationStartDateTimePickerRef"
|
||||
DateTimePicker="applicationStartDateTimePicker"
|
||||
@search="examMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 报名开始时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="applicationStartSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="examMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.application_start }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="application_end">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="applicationEndDateTimePickerRef"
|
||||
DateTimePicker="applicationEndDateTimePicker"
|
||||
@search="examMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 报名结束时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="applicationEndSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="examMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.application_end }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_start">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="examStartDateTimePickerRef"
|
||||
DateTimePicker="examStartDateTimePicker"
|
||||
@search="examMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试开始时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="examStartSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="examMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.exam_start }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_end">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="examEndDateTimePickerRef"
|
||||
DateTimePicker="examEndMsgDateTimePicker"
|
||||
@search="examMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试结束时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="examEndSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="examMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.exam_end }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="examMsgActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="examMsg"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddExamForm
|
||||
ref="addExamFormRef"
|
||||
title="新增考试信息"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="examMsg"
|
||||
/>
|
||||
<EditExamForm
|
||||
ref="editExamFormRef"
|
||||
operateLabel="编辑考试信息"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除考试信息"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出考试数据"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../operate/tabelTools.vue";
|
||||
import AddNewData from "../operate/addNewData.vue";
|
||||
import TabelSelect from "../operate/tabelSelect.vue";
|
||||
import SearchKey from "../search/searchKey.vue";
|
||||
import SortSearch from "../search/sortSearch.vue";
|
||||
import SelectSearch from "../search/selectSearch.vue";
|
||||
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||
import Pagination from "../search/pagination.vue";
|
||||
import AddExamForm from "../addNewData/examForm/examForm.vue";
|
||||
import EditExamForm from "../editData/examForm.vue";
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
import DownloadData from "../operate/downloadData.vue";
|
||||
|
||||
import examMsgActiveStore from "../../stores/examMsg";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
import { encrypt } from "../../utils/aes.js";
|
||||
import { downloadData } from "../../utils/downloadData.js";
|
||||
import { judgment } from "../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const examMsgActive = examMsgActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑考试信息",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除考试信息",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchUidKeyRef = ref(null);
|
||||
const SearchExamNameKeyRef = ref(null);
|
||||
const SelectStatusSearchRef = ref(null);
|
||||
const applicationStartDateTimePickerRef = ref(null);
|
||||
const applicationEndDateTimePickerRef = ref(null);
|
||||
const examStartDateTimePickerRef = ref(null);
|
||||
const examEndDateTimePickerRef = ref(null);
|
||||
const applicationStartSortDateTimeRef = ref(null);
|
||||
const applicationEndSortDateTimeRef = ref(null);
|
||||
const examStartSortDateTimeRef = ref(null);
|
||||
const examEndSortDateTimeRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addExamFormRef = ref(null);
|
||||
const editExamFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
uid: "",
|
||||
exam_name: "",
|
||||
status: "",
|
||||
application_start: "",
|
||||
application_end: "",
|
||||
exam_start: "",
|
||||
exam_end: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({
|
||||
application_start: false,
|
||||
application_end: false,
|
||||
exam_start: false,
|
||||
exam_end: false,
|
||||
});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const statusOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "即将进行",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "正在进行",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "已经结束",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
statusOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
statusOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addExamFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
examMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
examMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
examMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const examMsg = () => {
|
||||
judgment(searchOptions, "uid", SearchUidKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_name", SearchExamNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "status", SelectStatusSearchRef.value, "searchMsg");
|
||||
judgment(
|
||||
searchOptions,
|
||||
"application_start",
|
||||
applicationStartDateTimePickerRef.value,
|
||||
"searchMsg"
|
||||
);
|
||||
judgment(
|
||||
searchOptions,
|
||||
"application_end",
|
||||
applicationEndDateTimePickerRef.value,
|
||||
"searchMsg"
|
||||
);
|
||||
judgment(searchOptions, "exam_start", examStartDateTimePickerRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_end", examEndDateTimePickerRef.value, "searchMsg");
|
||||
judgment(
|
||||
sortOptions,
|
||||
"application_start",
|
||||
applicationStartSortDateTimeRef.value,
|
||||
"searchMsg"
|
||||
);
|
||||
judgment(
|
||||
sortOptions,
|
||||
"application_end",
|
||||
applicationEndSortDateTimeRef.value,
|
||||
"searchMsg"
|
||||
);
|
||||
judgment(sortOptions, "exam_start", examStartSortDateTimeRef.value, "searchMsg");
|
||||
judgment(sortOptions, "exam_end", examEndSortDateTimeRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showExam, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.examMsg;
|
||||
tableData.value.forEach((item) => {
|
||||
item.origin_applicationStart = item.application_start;
|
||||
item.application_start = moment
|
||||
.utc(item.application_start)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
item.origin_applicationEnd = item.application_end;
|
||||
item.application_end = moment
|
||||
.utc(item.application_end)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
item.origin_examStart = item.exam_start;
|
||||
item.exam_start = moment
|
||||
.utc(item.exam_start)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
item.origin_examEnd = item.exam_end;
|
||||
item.exam_end = moment
|
||||
.utc(item.exam_end)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
});
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
examMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
examMsgActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.uid == element.uid) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.uid == element.uid) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((item) => {
|
||||
if (item.origin_applicationStart) {
|
||||
item.application_start = item.origin_applicationStart;
|
||||
}
|
||||
if (item.origin_applicationEnd) {
|
||||
item.application_end = item.origin_applicationEnd;
|
||||
}
|
||||
if (item.origin_examStart) {
|
||||
item.exam_start = item.origin_examStart;
|
||||
}
|
||||
if (item.origin_examEnd) {
|
||||
item.exam_end = item.origin_examEnd;
|
||||
}
|
||||
delete item.origin_applicationStart;
|
||||
delete item.origin_applicationEnd;
|
||||
delete item.origin_examStart;
|
||||
delete item.origin_examEnd;
|
||||
delete item.location;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
singleData.application_start = singleData.origin_applicationStart;
|
||||
singleData.application_end = singleData.origin_applicationEnd;
|
||||
singleData.exam_start = singleData.origin_examStart;
|
||||
singleData.exam_end = singleData.origin_examEnd;
|
||||
delete singleData.origin_applicationStart;
|
||||
delete singleData.origin_applicationEnd;
|
||||
delete singleData.origin_examStart;
|
||||
delete singleData.origin_examEnd;
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editExamFormRef.value.model = EditSelectRef.value.model;
|
||||
editExamFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
editExamFormRef.value.ruleForm.exam_name = singleData.exam_name;
|
||||
statusOptions.forEach((item) => {
|
||||
if (item.value == singleData.status) {
|
||||
editExamFormRef.value.ruleForm.status = item.label;
|
||||
}
|
||||
});
|
||||
editExamFormRef.value.ruleForm.application_start = singleData.application_start;
|
||||
editExamFormRef.value.ruleForm.application_end = singleData.application_end;
|
||||
editExamFormRef.value.ruleForm.exam_start = singleData.exam_start;
|
||||
editExamFormRef.value.ruleForm.exam_end = singleData.exam_end;
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editExam;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editExamFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteExam;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
statusOptions.forEach((item) => {
|
||||
if (editExamFormRef.value.ruleForm.status == item.label) {
|
||||
editExamFormRef.value.ruleForm.status = item.value;
|
||||
}
|
||||
});
|
||||
data.updateMsg = { ...editExamFormRef.value.ruleForm };
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
}
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
examMsg();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
statusOptions.forEach((element) => {
|
||||
if (element.value == item["status"]) {
|
||||
item["status"] = element.label;
|
||||
}
|
||||
});
|
||||
delete item.origin_applicationStart;
|
||||
delete item.origin_applicationEnd;
|
||||
delete item.origin_examStart;
|
||||
delete item.origin_examEnd;
|
||||
});
|
||||
const dataHeaders = [
|
||||
"考试uid",
|
||||
"考试名称",
|
||||
"考试状态",
|
||||
"报名开始时间",
|
||||
"报名结束时间",
|
||||
"考试开始时间",
|
||||
"考试结束时间",
|
||||
];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadExamData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ examMsg });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
examMsgActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
examMsgActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = examMsgActive.pageCount;
|
||||
dialogSearchVisible.value = examMsgActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = examMsgActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = examMsgActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
examMsgActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.uid = examMsgActive.searchOptions.uid;
|
||||
searchOptions.exam_name = examMsgActive.searchOptions.exam_name;
|
||||
searchOptions.status = examMsgActive.searchOptions.status;
|
||||
searchOptions.application_start = examMsgActive.searchOptions.application_start;
|
||||
searchOptions.application_end = examMsgActive.searchOptions.application_end;
|
||||
searchOptions.exam_start = examMsgActive.searchOptions.exam_start;
|
||||
searchOptions.exam_end = examMsgActive.searchOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
sortOptions.application_start = examMsgActive.sortOptions.application_start;
|
||||
sortOptions.application_end = examMsgActive.sortOptions.application_end;
|
||||
sortOptions.exam_start = examMsgActive.sortOptions.exam_start;
|
||||
sortOptions.exam_end = examMsgActive.sortOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
examMsg();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchUidKeyRef.value.searchMsg = examMsgActive.searchOptions.uid;
|
||||
SearchExamNameKeyRef.value.searchMsg = examMsgActive.searchOptions.exam_name;
|
||||
SelectStatusSearchRef.value.searchMsg = examMsgActive.searchOptions.status;
|
||||
applicationStartDateTimePickerRef.value.application_start =
|
||||
examMsgActive.searchOptions.application_start;
|
||||
applicationEndDateTimePickerRef.value.application_end =
|
||||
examMsgActive.searchOptions.application_end;
|
||||
examStartDateTimePickerRef.value.exam_start =
|
||||
examMsgActive.searchOptions.exam_start;
|
||||
examEndDateTimePickerRef.value.exam_end = examMsgActive.searchOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
applicationStartSortDateTimeRef.value.searchMsg =
|
||||
examMsgActive.sortOptions.application_start;
|
||||
applicationEndSortDateTimeRef.value.searchMsg =
|
||||
examMsgActive.sortOptions.application_end;
|
||||
examStartSortDateTimeRef.value.searchMsg = examMsgActive.sortOptions.exam_start;
|
||||
examEndSortDateTimeRef.value.searchMsg = examMsgActive.sortOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
957
src/components/features/gradesList.vue
Normal file
@@ -0,0 +1,957 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap relative top-0 right-0">
|
||||
<div class="w-full mb-2 flex items-center absolute top-0 left-28 z-10">
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
size="small"
|
||||
plain
|
||||
@click="showExport('grades')"
|
||||
>
|
||||
生成考试成绩导入表
|
||||
</el-button>
|
||||
</div>
|
||||
<TabelTools @showTools="showTools" :dialogObj="gradesMsgActive" />
|
||||
<AddNewData newDataLabel="新增考生成绩" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="40rem"
|
||||
max-height="40rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="userPhotoUrl">
|
||||
<template #header>
|
||||
<div>
|
||||
<div>
|
||||
<el-text class="mx-1"> 用户照片 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
<img
|
||||
:key="scope.row.user_uid"
|
||||
:src="
|
||||
scope.row.userPhotoUrl == '#' ? defaultPhoto : scope.row.userPhotoUrl
|
||||
"
|
||||
style="width: 115px; height: 165px"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="user_uid">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUserUidKeyRef"
|
||||
holderText="输入考生uid以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考生uid </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.user_uid }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="120" column-key="user_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUserNameKeyRef"
|
||||
holderText="输入考生姓名以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考生姓名 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examinee.user_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="identity_card">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchIdentityCardKeyRef"
|
||||
holderText="输入身份证号以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 身份证号 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examinee.identity_card }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="workplace">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchWorkplaceKeyRef"
|
||||
holderText="输入工作单位以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 工作单位 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examinee.workplace }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="phone">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchPhoneKeyRef"
|
||||
holderText="输入手机号码以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 手机号码 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examinee.phone }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="120" column-key="exam_uid">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchExamUidKeyRef"
|
||||
holderText="输入考试uid以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试uid </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.exam_uid }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchExamNameKeyRef"
|
||||
holderText="输入考试名称以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试名称 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examination.exam_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="status">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectStatusSearchRef"
|
||||
holderText="选择参与状态以搜索相关数据"
|
||||
:options="statusOptions"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 参与状态 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(statusOptions, scope.row.status)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(statusOptions, scope.row.status) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="80" column-key="grades">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchGradesKeyRef"
|
||||
holderText="输入考试成绩以搜索相关数据"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试成绩 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="SortGradesRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(passTypeOptions, scope.row.pass_type)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ scope.row.grades == null ? "无成绩" : scope.row.grades }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="110" column-key="pass_type">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectPassTypeSearchRef"
|
||||
holderText="选择考试结果以搜索相关数据"
|
||||
:options="passTypeOptions"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试结果 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(passTypeOptions, scope.row.pass_type)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(passTypeOptions, scope.row.pass_type) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_start">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="examStartDateTimePickerRef"
|
||||
DateTimePicker="examStartDateTimePicker"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试开始时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="examStartSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.exam_start }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_end">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="examEndDateTimePickerRef"
|
||||
DateTimePicker="examEndMsgDateTimePicker"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试结束时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="examEndSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.exam_end }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="gradesMsgActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="gradesMsg"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddGradesForm
|
||||
ref="addGradesFormRef"
|
||||
title="新增考生成绩"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="gradesMsg"
|
||||
/>
|
||||
<EditGradesForm
|
||||
ref="editGradesFormRef"
|
||||
operateLabel="编辑考生成绩"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除考生成绩"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出考生成绩数据"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
<ExportGrades ref="gradesRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../operate/tabelTools.vue";
|
||||
import AddNewData from "../operate/addNewData.vue";
|
||||
import TabelSelect from "../operate/tabelSelect.vue";
|
||||
import SearchKey from "../search/searchKey.vue";
|
||||
import SortSearch from "../search/sortSearch.vue";
|
||||
import SelectSearch from "../search/selectSearch.vue";
|
||||
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||
import Pagination from "../search/pagination.vue";
|
||||
import AddGradesForm from "../addNewData/gradesForm/gradesForm.vue";
|
||||
import EditGradesForm from "../editData/gradesForm.vue";
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
import DownloadData from "../operate/downloadData.vue";
|
||||
import ExportGrades from "../operate/export/exportGrades.vue";
|
||||
|
||||
import gradesMsgActiveStore from "../../stores/gradesMsg";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
import { encrypt } from "../../utils/aes.js";
|
||||
import { downloadData } from "../../utils/downloadData.js";
|
||||
import { judgment } from "../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
import defaultPhoto from "../../assets/default.png";
|
||||
|
||||
const gradesMsgActive = gradesMsgActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑考生成绩",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除考生成绩",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchUserUidKeyRef = ref(null);
|
||||
const SearchIdentityCardKeyRef = ref(null);
|
||||
const SearchWorkplaceKeyRef = ref(null);
|
||||
const SearchPhoneKeyRef = ref(null);
|
||||
const SearchUserNameKeyRef = ref(null);
|
||||
const SearchExamUidKeyRef = ref(null);
|
||||
const SearchExamNameKeyRef = ref(null);
|
||||
const SelectStatusSearchRef = ref(null);
|
||||
const SearchGradesKeyRef = ref(null);
|
||||
const SelectPassTypeSearchRef = ref(null);
|
||||
const examStartDateTimePickerRef = ref(null);
|
||||
const examEndDateTimePickerRef = ref(null);
|
||||
const SortGradesRef = ref(null);
|
||||
const examStartSortDateTimeRef = ref(null);
|
||||
const examEndSortDateTimeRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addGradesFormRef = ref(null);
|
||||
const editGradesFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const gradesRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
user_uid: "",
|
||||
user_name: "",
|
||||
identity_card: "",
|
||||
workplace: "",
|
||||
phone: "",
|
||||
exam_uid: "",
|
||||
exam_name: "",
|
||||
status: "",
|
||||
grades: "",
|
||||
pass_type: "",
|
||||
exam_start: "",
|
||||
exam_end: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({
|
||||
grades: false,
|
||||
exam_start: false,
|
||||
exam_end: false,
|
||||
});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const statusOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "旷考",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "正常参加",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "考试作弊",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const passTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "成绩不及格",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "成绩及格",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "无成绩",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
statusOptions,
|
||||
passTypeOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
statusOptions,
|
||||
passTypeOptions,
|
||||
});
|
||||
|
||||
const exportData = reactive({
|
||||
statusOptions,
|
||||
passTypeOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addGradesFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showExport = (type) => {
|
||||
if (type == "grades") {
|
||||
gradesRef.value.gradesDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
gradesMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
gradesMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
gradesMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const gradesMsg = () => {
|
||||
judgment(searchOptions, "user_uid", SearchUserUidKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "user_name", SearchUserNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "identity_card", SearchIdentityCardKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "workplace", SearchWorkplaceKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "phone", SearchPhoneKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_uid", SearchExamUidKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_name", SearchExamNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "status", SelectStatusSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "grades", SearchGradesKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "pass_type", SelectPassTypeSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_start", examStartDateTimePickerRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_end", examEndDateTimePickerRef.value, "searchMsg");
|
||||
judgment(sortOptions, "grades", SortGradesRef.value, "searchMsg");
|
||||
judgment(sortOptions, "exam_start", examStartSortDateTimeRef.value, "searchMsg");
|
||||
judgment(sortOptions, "exam_end", examEndSortDateTimeRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showGrades, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.gradesMsg;
|
||||
tableData.value.forEach((item) => {
|
||||
item.origin_examStart = item.exam_start;
|
||||
item.exam_start = moment
|
||||
.utc(item.exam_start)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
item.origin_examEnd = item.exam_end;
|
||||
item.exam_end = moment
|
||||
.utc(item.exam_end)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
});
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
gradesMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
gradesMsgActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.user_uid == element.user_uid && item.exam_uid == element.exam_uid) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.user_uid == element.user_uid && item.exam_uid == element.exam_uid) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((item) => {
|
||||
if (item.origin_examStart) {
|
||||
item.exam_start = item.origin_examStart;
|
||||
}
|
||||
if (item.origin_examEnd) {
|
||||
item.exam_end = item.origin_examEnd;
|
||||
}
|
||||
delete item.origin_examStart;
|
||||
delete item.origin_examEnd;
|
||||
delete item.location;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
singleData.exam_start = singleData.origin_examStart;
|
||||
singleData.exam_end = singleData.origin_examEnd;
|
||||
delete singleData.origin_examStart;
|
||||
delete singleData.origin_examEnd;
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editGradesFormRef.value.model = EditSelectRef.value.model;
|
||||
editGradesFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
statusOptions.forEach((item) => {
|
||||
if (item.value == singleData.status) {
|
||||
editGradesFormRef.value.ruleForm.status = item.label;
|
||||
}
|
||||
});
|
||||
editGradesFormRef.value.ruleForm.grades = singleData.grades;
|
||||
passTypeOptions.forEach((item) => {
|
||||
if (item.value == singleData.pass_type) {
|
||||
editGradesFormRef.value.ruleForm.pass_type = item.label;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editGrades;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editGradesFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteGrades;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
statusOptions.forEach((item) => {
|
||||
if (editGradesFormRef.value.ruleForm.status == item.label) {
|
||||
editGradesFormRef.value.ruleForm.status = item.value;
|
||||
}
|
||||
});
|
||||
passTypeOptions.forEach((item) => {
|
||||
if (editGradesFormRef.value.ruleForm.pass_type == item.label) {
|
||||
editGradesFormRef.value.ruleForm.pass_type = item.value;
|
||||
}
|
||||
});
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
data.updateMsg = { ...editGradesFormRef.value.ruleForm };
|
||||
if (data.updateMsg.grades == "无") {
|
||||
data.updateMsg.grades = null;
|
||||
}
|
||||
}
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
gradesMsg();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
statusOptions.forEach((element) => {
|
||||
if (element.value == item["status"]) {
|
||||
item["status"] = element.label;
|
||||
}
|
||||
});
|
||||
passTypeOptions.forEach((element) => {
|
||||
if (element.value == item["pass_type"]) {
|
||||
item["pass_type"] = element.label;
|
||||
}
|
||||
});
|
||||
delete item.origin_examStart;
|
||||
delete item.origin_examEnd;
|
||||
});
|
||||
const dataHeaders = [
|
||||
"考生uid",
|
||||
"考生姓名",
|
||||
"身份证号",
|
||||
"工作单位",
|
||||
"手机号码",
|
||||
"考试uid",
|
||||
"考试名称",
|
||||
"参与状态",
|
||||
"考生成绩",
|
||||
"考试开始时间",
|
||||
"考试结束时间",
|
||||
];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadGradesData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ gradesMsg });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
gradesMsgActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
gradesMsgActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = gradesMsgActive.pageCount;
|
||||
dialogSearchVisible.value = gradesMsgActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = gradesMsgActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = gradesMsgActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
gradesMsgActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.user_uid = gradesMsgActive.searchOptions.user_uid;
|
||||
searchOptions.user_name = gradesMsgActive.searchOptions.user_name;
|
||||
searchOptions.identity_card = gradesMsgActive.searchOptions.identity_card;
|
||||
searchOptions.workplace = gradesMsgActive.searchOptions.workplace;
|
||||
searchOptions.phone = gradesMsgActive.searchOptions.phone;
|
||||
searchOptions.exam_uid = gradesMsgActive.searchOptions.exam_uid;
|
||||
searchOptions.exam_name = gradesMsgActive.searchOptions.exam_name;
|
||||
searchOptions.status = gradesMsgActive.searchOptions.status;
|
||||
searchOptions.grades = gradesMsgActive.searchOptions.grades;
|
||||
searchOptions.pass_type = gradesMsgActive.searchOptions.pass_type;
|
||||
searchOptions.exam_start = gradesMsgActive.searchOptions.exam_start;
|
||||
searchOptions.exam_end = gradesMsgActive.searchOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
sortOptions.grades = gradesMsgActive.sortOptions.grades;
|
||||
sortOptions.exam_start = gradesMsgActive.sortOptions.exam_start;
|
||||
sortOptions.exam_end = gradesMsgActive.sortOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
gradesMsg();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchUserUidKeyRef.value.searchMsg = gradesMsgActive.searchOptions.user_uid;
|
||||
SearchUserNameKeyRef.value.searchMsg = gradesMsgActive.searchOptions.user_name;
|
||||
SearchIdentityCardKeyRef.value.searchMsg =
|
||||
gradesMsgActive.searchOptions.identity_card;
|
||||
SearchWorkplaceKeyRef.value.searchMsg = gradesMsgActive.searchOptions.workplace;
|
||||
SearchPhoneKeyRef.value.searchMsg = gradesMsgActive.searchOptions.phone;
|
||||
SearchExamUidKeyRef.value.searchMsg = gradesMsgActive.searchOptions.exam_uid;
|
||||
SearchExamNameKeyRef.value.searchMsg = gradesMsgActive.searchOptions.exam_name;
|
||||
SelectStatusSearchRef.value.searchMsg = gradesMsgActive.searchOptions.status;
|
||||
SearchGradesKeyRef.value.searchMsg = gradesMsgActive.searchOptions.grades;
|
||||
SelectPassTypeSearchRef.value.searchMsg = gradesMsgActive.searchOptions.pass_type;
|
||||
examStartDateTimePickerRef.value.exam_start =
|
||||
gradesMsgActive.searchOptions.exam_start;
|
||||
examEndDateTimePickerRef.value.exam_end = gradesMsgActive.searchOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
SortGradesRef.value.searchMsg = gradesMsgActive.sortOptions.grades;
|
||||
examStartSortDateTimeRef.value.searchMsg = gradesMsgActive.sortOptions.exam_start;
|
||||
examEndSortDateTimeRef.value.searchMsg = gradesMsgActive.sortOptions.exam_end;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
633
src/components/features/importerrorList.vue
Normal file
@@ -0,0 +1,633 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="importerrorActive" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="40rem"
|
||||
max-height="40rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="user_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUserNameKeyRef"
|
||||
holderText="输入用户姓名以搜索相关数据"
|
||||
@search="importerror"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 用户姓名 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.user_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="identity_card">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchIdentityCardKeyRef"
|
||||
holderText="输入身份证号以搜索相关数据"
|
||||
@search="importerror"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 身份证号 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.identity_card }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_uid">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchExamUidKeyRef"
|
||||
holderText="输入考试uid以搜索相关数据"
|
||||
@search="importerror"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试uid </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.exam_uid }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="exam_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchExamNameKeyRef"
|
||||
holderText="输入考试名称以搜索相关数据"
|
||||
@search="importerror"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 考试名称 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examination.exam_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="120" column-key="type">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectTypeSearchRef"
|
||||
holderText="选择错误类型以搜索相关数据"
|
||||
:options="typeOptions"
|
||||
@search="importerror"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 错误类型 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(typeOptions, scope.row.type)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(typeOptions, scope.row.type) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="status">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectStatusSearchRef"
|
||||
holderText="选择处理状态以搜索相关数据"
|
||||
:options="statusOptions"
|
||||
@search="importerror"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 处理状态 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(statusOptions, scope.row.status)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(statusOptions, scope.row.status) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="created_at">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="createdDateTimePickerRef"
|
||||
DateTimePicker="createdDateTimePicker"
|
||||
@search="importerror"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 报错时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="createdSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="importerror"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.created_at }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="importerrorActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="importerror"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除错误日志"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出错误日志"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../operate/tabelTools.vue";
|
||||
import TabelSelect from "../operate/tabelSelect.vue";
|
||||
import SearchKey from "../search/searchKey.vue";
|
||||
import SortSearch from "../search/sortSearch.vue";
|
||||
import SelectSearch from "../search/selectSearch.vue";
|
||||
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||
import Pagination from "../search/pagination.vue";
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
import DownloadData from "../operate/downloadData.vue";
|
||||
|
||||
import importerrorActiveStore from "../../stores/importerror";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
import { encrypt } from "../../utils/aes.js";
|
||||
import { downloadData } from "../../utils/downloadData.js";
|
||||
import { judgment } from "../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const importerrorActive = importerrorActiveStore();
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除错误日志",
|
||||
};
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchUserNameKeyRef = ref(null);
|
||||
const SearchIdentityCardKeyRef = ref(null);
|
||||
const SearchExamUidKeyRef = ref(null);
|
||||
const SearchExamNameKeyRef = ref(null);
|
||||
const SelectTypeSearchRef = ref(null);
|
||||
const SelectStatusSearchRef = ref(null);
|
||||
const createdDateTimePickerRef = ref(null);
|
||||
const createdSortDateTimeRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
user_name: "",
|
||||
identity_card: "",
|
||||
exam_uid: "",
|
||||
exam_name: "",
|
||||
type: "",
|
||||
status: "",
|
||||
created_at: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({
|
||||
created_at: false,
|
||||
});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const typeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "报名信息导入错误",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "成绩导入错误",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const statusOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "待解决",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "已解决",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
importerrorActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
importerrorActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
importerrorActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const importerror = () => {
|
||||
judgment(searchOptions, "user_name", SearchUserNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "identity_card", SearchIdentityCardKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_uid", SearchExamUidKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "exam_name", SearchExamNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "type", SelectTypeSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "status", SelectStatusSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "created_at", createdDateTimePickerRef.value, "searchMsg");
|
||||
judgment(sortOptions, "created_at", createdSortDateTimeRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showImporterror, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.importerrorMsg;
|
||||
tableData.value.forEach((item) => {
|
||||
item.origin_createdAt = item.created_at;
|
||||
item.created_at = moment
|
||||
.utc(item.created_at)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
});
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
importerrorActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
importerrorActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.created_at == element.created_at) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.created_at == element.created_at) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((item) => {
|
||||
if (item.origin_createdAt) {
|
||||
item.created_at = item.origin_createdAt;
|
||||
}
|
||||
delete item.origin_createdAt;
|
||||
delete item.location;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
singleData.created_at = singleData.origin_createdAt;
|
||||
delete singleData.origin_createdAt;
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteImporterror;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
importerror();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
typeOptions.forEach((element) => {
|
||||
if (element.value == item["type"]) {
|
||||
item["type"] = element.label;
|
||||
}
|
||||
});
|
||||
statusOptions.forEach((element) => {
|
||||
if (element.value == item["status"]) {
|
||||
item["status"] = element.label;
|
||||
}
|
||||
});
|
||||
delete item.origin_createdAt;
|
||||
});
|
||||
const dataHeaders = [
|
||||
"用户姓名",
|
||||
"身份证号",
|
||||
"考试uid",
|
||||
"考试名称",
|
||||
"错误类型",
|
||||
"处理状态",
|
||||
"报错时间",
|
||||
];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadImporterrorData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ importerror });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
importerrorActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
importerrorActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = importerrorActive.pageCount;
|
||||
dialogSearchVisible.value = importerrorActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = importerrorActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = importerrorActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
importerrorActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.user_name = importerrorActive.searchOptions.user_name;
|
||||
searchOptions.identity_card = importerrorActive.searchOptions.identity_card;
|
||||
searchOptions.exam_uid = importerrorActive.searchOptions.exam_uid;
|
||||
searchOptions.exam_name = importerrorActive.searchOptions.exam_name;
|
||||
searchOptions.type = importerrorActive.searchOptions.type;
|
||||
searchOptions.status = importerrorActive.searchOptions.status;
|
||||
searchOptions.created_at = importerrorActive.searchOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
sortOptions.created_at = importerrorActive.sortOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
importerror();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchUserNameKeyRef.value.searchMsg = importerrorActive.searchOptions.user_name;
|
||||
SearchIdentityCardKeyRef.value.searchMsg =
|
||||
importerrorActive.searchOptions.identity_card;
|
||||
SearchExamUidKeyRef.value.searchMsg = importerrorActive.searchOptions.exam_uid;
|
||||
SearchExamNameKeyRef.value.searchMsg = importerrorActive.searchOptions.exam_name;
|
||||
SelectTypeSearchRef.value.searchMsg = importerrorActive.searchOptions.type;
|
||||
SelectStatusSearchRef.value.searchMsg = importerrorActive.searchOptions.status;
|
||||
createdDateTimePickerRef.value.created_at =
|
||||
importerrorActive.searchOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
createdSortDateTimeRef.value.searchMsg = importerrorActive.sortOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
759
src/components/features/monitoringList.vue
Normal file
@@ -0,0 +1,759 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="monitoringActive" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="40rem"
|
||||
max-height="40rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="120" column-key="operate">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectOperateSearchRef"
|
||||
holderText="选择操作名称以搜索相关数据"
|
||||
:options="operateOptions"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 操作名称 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(operateOptions, scope.row.operate)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(operateOptions, scope.row.operate) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="operate_msg">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOperateMsgKeyRef"
|
||||
holderText="输入操作描述以搜索相关数据"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 操作描述 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.operate_msg }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="120" column-key="type">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectTypeSearchRef"
|
||||
holderText="选择危险等级以搜索相关数据"
|
||||
:options="typeOptions"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 危险等级 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(typeOptions, scope.row.type)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(typeOptions, scope.row.type) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="status">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectStatusSearchRef"
|
||||
holderText="选择执行状态以搜索相关数据"
|
||||
:options="statusOptions"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 执行状态 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(statusOptions, scope.row.status)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(statusOptions, scope.row.status) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="affect_entries">
|
||||
<template #header>
|
||||
<div>
|
||||
<div>
|
||||
<el-text class="mx-1"> 影响到的数据数目 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.affect_entries }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="user">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUserKeyRef"
|
||||
holderText="输入操作者uid以搜索相关数据"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 操作者uid </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.user }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="account_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchAccountNameKeyRef"
|
||||
holderText="输入操作者姓名以搜索相关数据"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 操作者姓名 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.account_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="120" column-key="role">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectRoleSearchRef"
|
||||
holderText="选择操作者权限以搜索相关数据"
|
||||
:options="roleOptions"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 操作者权限 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(roleOptions, scope.row.role)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(roleOptions, scope.row.role) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="created_at">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="createdDateTimePickerRef"
|
||||
DateTimePicker="createdDateTimePicker"
|
||||
@search="monitoring"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 操作发生时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="createdSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="monitoring"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.created_at }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="monitoringActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="monitoring"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除系统记录"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出系统记录"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../operate/tabelTools.vue";
|
||||
import TabelSelect from "../operate/tabelSelect.vue";
|
||||
import SearchKey from "../search/searchKey.vue";
|
||||
import SortSearch from "../search/sortSearch.vue";
|
||||
import SelectSearch from "../search/selectSearch.vue";
|
||||
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||
import Pagination from "../search/pagination.vue";
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
import DownloadData from "../operate/downloadData.vue";
|
||||
|
||||
import monitoringActiveStore from "../../stores/monitoring";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
import { encrypt } from "../../utils/aes.js";
|
||||
import { downloadData } from "../../utils/downloadData.js";
|
||||
import { judgment } from "../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const monitoringActive = monitoringActiveStore();
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除系统记录",
|
||||
};
|
||||
const DelSelectRef = ref(null);
|
||||
const SelectOperateSearchRef = ref(null);
|
||||
const SearchOperateMsgKeyRef = ref(null);
|
||||
const SelectTypeSearchRef = ref(null);
|
||||
const SelectStatusSearchRef = ref(null);
|
||||
const SearchUserKeyRef = ref(null);
|
||||
const SearchAccountNameKeyRef = ref(null);
|
||||
const SelectRoleSearchRef = ref(null);
|
||||
const createdDateTimePickerRef = ref(null);
|
||||
const createdSortDateTimeRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
operate: "",
|
||||
operate_msg: "",
|
||||
type: "",
|
||||
status: "",
|
||||
user: "",
|
||||
account_name: "",
|
||||
role: "",
|
||||
created_at: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({
|
||||
created_at: false,
|
||||
});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const operateOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "新增数据",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "编辑数据",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "删除数据",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const typeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "普通",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "重要",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "危险",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const statusOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "操作执行失败,原因:无用户身份",
|
||||
style:
|
||||
"color: rgb(120, 140, 180);background-color: rgba(120, 140, 180, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "操作执行失败,原因:密码错误",
|
||||
style:
|
||||
"color: rgb(255, 100, 180);background-color: rgba(255, 100, 180, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "操作执行失败,原因:权限不足",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "3",
|
||||
label: "操作执行失败,原因:查询条件错误",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "4",
|
||||
label: "操作执行成功",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "5",
|
||||
label: "操作执行失败,原因:程序错误",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const roleOptions = [
|
||||
{
|
||||
value: "9",
|
||||
label: "系统管理员",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "0",
|
||||
label: "临时管理员",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "普通管理员",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "高级管理员",
|
||||
style: "color: rgb(255, 200, 0);background-color: rgba(255, 200, 0, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
monitoringActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
monitoringActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
monitoringActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const monitoring = () => {
|
||||
judgment(searchOptions, "operate", SelectOperateSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "operate_msg", SearchOperateMsgKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "type", SelectTypeSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "status", SelectStatusSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "user", SearchUserKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "account_name", SearchAccountNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "role", SelectRoleSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "created_at", createdDateTimePickerRef.value, "searchMsg");
|
||||
judgment(sortOptions, "created_at", createdSortDateTimeRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showMonitoring, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.monitoringMsg;
|
||||
tableData.value.forEach((item) => {
|
||||
item.origin_createdAt = item.created_at;
|
||||
item.created_at = moment
|
||||
.utc(item.created_at)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
});
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
monitoringActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
monitoringActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.created_at == element.created_at) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.created_at == element.created_at) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((item) => {
|
||||
if (item.origin_createdAt) {
|
||||
item.created_at = item.origin_createdAt;
|
||||
}
|
||||
delete item.origin_createdAt;
|
||||
delete item.location;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
singleData.created_at = singleData.origin_createdAt;
|
||||
delete singleData.origin_createdAt;
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteMonitoring;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
monitoring();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
operateOptions.forEach((element) => {
|
||||
if (element.value == item["operate"]) {
|
||||
item["operate"] = element.label;
|
||||
}
|
||||
});
|
||||
typeOptions.forEach((element) => {
|
||||
if (element.value == item["type"]) {
|
||||
item["type"] = element.label;
|
||||
}
|
||||
});
|
||||
statusOptions.forEach((element) => {
|
||||
if (element.value == item["status"]) {
|
||||
item["status"] = element.label;
|
||||
}
|
||||
});
|
||||
roleOptions.forEach((element) => {
|
||||
if (element.value == item["role"]) {
|
||||
item["role"] = element.label;
|
||||
}
|
||||
});
|
||||
delete item.origin_createdAt;
|
||||
});
|
||||
const dataHeaders = [
|
||||
"操作名称",
|
||||
"操作描述",
|
||||
"危险等级",
|
||||
"执行状态",
|
||||
"操作者uid",
|
||||
"操作者姓名",
|
||||
"操作者权限",
|
||||
"操作发生时间",
|
||||
];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadMonitoringData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ monitoring });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
monitoringActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
monitoringActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = monitoringActive.pageCount;
|
||||
dialogSearchVisible.value = monitoringActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = monitoringActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = monitoringActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
monitoringActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.operate = monitoringActive.searchOptions.operate;
|
||||
searchOptions.operate_msg = monitoringActive.searchOptions.operate_msg;
|
||||
searchOptions.type = monitoringActive.searchOptions.type;
|
||||
searchOptions.status = monitoringActive.searchOptions.status;
|
||||
searchOptions.user = monitoringActive.searchOptions.user;
|
||||
searchOptions.account_name = monitoringActive.searchOptions.account_name;
|
||||
searchOptions.role = monitoringActive.searchOptions.role;
|
||||
searchOptions.created_at = monitoringActive.searchOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
sortOptions.created_at = monitoringActive.sortOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
monitoring();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SelectOperateSearchRef.value.searchMsg = monitoringActive.searchOptions.operate;
|
||||
SearchOperateMsgKeyRef.value.searchMsg = monitoringActive.searchOptions.operate_msg;
|
||||
SelectTypeSearchRef.value.searchMsg = monitoringActive.searchOptions.type;
|
||||
SelectStatusSearchRef.value.searchMsg = monitoringActive.searchOptions.status;
|
||||
SearchUserKeyRef.value.searchMsg = monitoringActive.searchOptions.user;
|
||||
SearchAccountNameKeyRef.value.searchMsg =
|
||||
monitoringActive.searchOptions.account_name;
|
||||
SelectRoleSearchRef.value.searchMsg = monitoringActive.searchOptions.role;
|
||||
createdDateTimePickerRef.value.created_at =
|
||||
monitoringActive.searchOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
createdSortDateTimeRef.value.searchMsg = monitoringActive.sortOptions.created_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
668
src/components/features/topicWhitelist.vue
Normal file
@@ -0,0 +1,668 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="topicWhitelistActive" />
|
||||
<AddNewData newDataLabel="新增题库白名单" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="40rem"
|
||||
max-height="40rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="userPhotoUrl">
|
||||
<template #header>
|
||||
<div>
|
||||
<div>
|
||||
<el-text class="mx-1"> 用户照片 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
<img
|
||||
:key="scope.row.user_uid"
|
||||
:src="
|
||||
scope.row.userPhotoUrl == '#' ? defaultPhoto : scope.row.userPhotoUrl
|
||||
"
|
||||
style="width: 115px; height: 165px"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="user_uid">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUserUidKeyRef"
|
||||
holderText="输入用户uid以搜索相关数据"
|
||||
@search="topicWhitelist"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 用户uid </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.user_uid }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="160" column-key="user_name">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchUserNameKeyRef"
|
||||
holderText="输入用户姓名以搜索相关数据"
|
||||
@search="topicWhitelist"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 用户姓名 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examinee.user_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="identity_card">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchIdentityCardKeyRef"
|
||||
holderText="输入身份证号以搜索相关数据"
|
||||
@search="topicWhitelist"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 身份证号 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.examinee.identity_card }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="120" column-key="type">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectTypeSearchRef"
|
||||
holderText="选择白名单类型以搜索相关数据"
|
||||
:options="typeOptions"
|
||||
@search="topicWhitelist"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 白名单类型 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(typeOptions, scope.row.type)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(typeOptions, scope.row.type) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="expired_at">
|
||||
<template #header>
|
||||
<DateTimePicker
|
||||
v-if="dialogSearchVisible"
|
||||
ref="expiredDateTimePickerRef"
|
||||
DateTimePicker="expiredMsgDateTimePicker"
|
||||
@search="topicWhitelist"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 白名单过期时间 </el-text>
|
||||
<SortSearch
|
||||
v-if="dialogSortVisible"
|
||||
ref="expiredSortDateTimeRef"
|
||||
activeText="顺序"
|
||||
inactiveText="倒序"
|
||||
@search="topicWhitelist"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.expired_at }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="topicWhitelistActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="topicWhitelist"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddTopicWhitelistForm
|
||||
ref="addTopicWhitelistFormRef"
|
||||
title="新增题库白名单"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="topicWhitelist"
|
||||
/>
|
||||
<EditTopicWhitelistForm
|
||||
ref="editTopicWhitelistFormRef"
|
||||
operateLabel="编辑题库白名单"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除题库白名单"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出题库白名单"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../operate/tabelTools.vue";
|
||||
import AddNewData from "../operate/addNewData.vue";
|
||||
import TabelSelect from "../operate/tabelSelect.vue";
|
||||
import SearchKey from "../search/searchKey.vue";
|
||||
import SortSearch from "../search/sortSearch.vue";
|
||||
import SelectSearch from "../search/selectSearch.vue";
|
||||
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||
import Pagination from "../search/pagination.vue";
|
||||
import AddTopicWhitelistForm from "../addNewData/topicWhitelistForm/topicWhitelistForm.vue";
|
||||
import EditTopicWhitelistForm from "../editData/topicWhitelistForm.vue";
|
||||
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||
import DownloadData from "../operate/downloadData.vue";
|
||||
|
||||
import topicWhitelistActiveStore from "../../stores/topicWhitelist";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import $http from "../../api/index";
|
||||
import $url from "../../api/url";
|
||||
|
||||
import { encrypt } from "../../utils/aes.js";
|
||||
import { downloadData } from "../../utils/downloadData.js";
|
||||
import { judgment } from "../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
import defaultPhoto from "../../assets/default.png";
|
||||
|
||||
const topicWhitelistActive = topicWhitelistActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑题库白名单",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除题库白名单",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchUserUidKeyRef = ref(null);
|
||||
const SearchUserNameKeyRef = ref(null);
|
||||
const SearchIdentityCardKeyRef = ref(null);
|
||||
const SelectTypeSearchRef = ref(null);
|
||||
const expiredDateTimePickerRef = ref(null);
|
||||
const expiredSortDateTimeRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addTopicWhitelistFormRef = ref(null);
|
||||
const editTopicWhitelistFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
user_uid: "",
|
||||
user_name: "",
|
||||
identity_card: "",
|
||||
type: "",
|
||||
expired_at: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({
|
||||
expired_at: false,
|
||||
});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const typeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "永久白名单",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "临时白名单",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
typeOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
typeOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addTopicWhitelistFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
topicWhitelistActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
topicWhitelistActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
topicWhitelistActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const topicWhitelist = () => {
|
||||
judgment(searchOptions, "user_uid", SearchUserUidKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "user_name", SearchUserNameKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "identity_card", SearchIdentityCardKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "type", SelectTypeSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "expired_at", expiredDateTimePickerRef.value, "searchMsg");
|
||||
judgment(sortOptions, "expired_at", expiredSortDateTimeRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showTopicWhitelist, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.topicWhitelistMsg;
|
||||
tableData.value.forEach((item) => {
|
||||
item.origin_expiredAt = item.expired_at;
|
||||
if (item.expired_at != null) {
|
||||
item.expired_at = moment
|
||||
.utc(item.expired_at)
|
||||
.add(8, "hours")
|
||||
.format("YYYY年MM月DD日HH时mm分ss秒");
|
||||
} else {
|
||||
item.expired_at = "永久有效";
|
||||
}
|
||||
});
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
topicWhitelistActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
topicWhitelistActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.expired_at == element.expired_at) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.expired_at == element.expired_at) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((item) => {
|
||||
if (item.origin_expiredAt) {
|
||||
item.expired_at = item.origin_expiredAt;
|
||||
}
|
||||
delete item.origin_expiredAt;
|
||||
delete item.location;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
singleData.expired_at = singleData.origin_expiredAt;
|
||||
delete singleData.origin_expiredAt;
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editTopicWhitelistFormRef.value.model = EditSelectRef.value.model;
|
||||
editTopicWhitelistFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
typeOptions.forEach((item) => {
|
||||
if (item.value == singleData.type) {
|
||||
editTopicWhitelistFormRef.value.ruleForm.type = item.label;
|
||||
}
|
||||
});
|
||||
editTopicWhitelistFormRef.value.ruleForm.expired_at = singleData.expired_at;
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editTopicWhitelist;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editTopicWhitelistFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteTopicWhitelist;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
typeOptions.forEach((item) => {
|
||||
if (editTopicWhitelistFormRef.value.ruleForm.type == item.label) {
|
||||
editTopicWhitelistFormRef.value.ruleForm.type = item.value;
|
||||
}
|
||||
});
|
||||
data.updateMsg = { ...editTopicWhitelistFormRef.value.ruleForm };
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(data);
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
topicWhitelist();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
typeOptions.forEach((element) => {
|
||||
if (element.value == item["type"]) {
|
||||
item["type"] = element.label;
|
||||
}
|
||||
});
|
||||
});
|
||||
const dataHeaders = ["用户uid", "用户姓名", "身份证号", "白名单类型", "白名单过期时间"];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadTopicWhitelistData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ topicWhitelist });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
topicWhitelistActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
topicWhitelistActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = topicWhitelistActive.pageCount;
|
||||
dialogSearchVisible.value = topicWhitelistActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = topicWhitelistActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = topicWhitelistActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
topicWhitelistActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.user_uid = topicWhitelistActive.searchOptions.user_uid;
|
||||
searchOptions.user_name = topicWhitelistActive.searchOptions.user_name;
|
||||
searchOptions.identity_card = topicWhitelistActive.searchOptions.identity_card;
|
||||
searchOptions.type = topicWhitelistActive.searchOptions.type;
|
||||
searchOptions.expired_at = topicWhitelistActive.searchOptions.expired_at;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
sortOptions.expired_at = topicWhitelistActive.sortOptions.expired_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
topicWhitelist();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchUserUidKeyRef.value.searchMsg = topicWhitelistActive.searchOptions.user_uid;
|
||||
SearchUserNameKeyRef.value.searchMsg = topicWhitelistActive.searchOptions.user_name;
|
||||
SearchIdentityCardKeyRef.value.searchMsg =
|
||||
topicWhitelistActive.searchOptions.identity_card;
|
||||
SelectTypeSearchRef.value.searchMsg = topicWhitelistActive.searchOptions.type;
|
||||
expiredDateTimePickerRef.value.expired_at =
|
||||
topicWhitelistActive.searchOptions.expired_at;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
expiredSortDateTimeRef.value.searchMsg =
|
||||
topicWhitelistActive.sortOptions.expired_at;
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
72
src/components/features/trainindTopic.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-menu
|
||||
class="flex flex-wrap 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>
|
||||
<el-card>
|
||||
<div v-show="activeIndex === '1'">
|
||||
<Radio />
|
||||
</div>
|
||||
<div v-show="activeIndex === '2'">
|
||||
<Multiple />
|
||||
</div>
|
||||
<div v-show="activeIndex === '3'">
|
||||
<Judgment />
|
||||
</div>
|
||||
<div v-show="activeIndex === '4'">
|
||||
<Interlocution />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
import Interlocution from "../features/trainindTopic/interlocution.vue";
|
||||
import Judgment from "../features/trainindTopic/judgment.vue";
|
||||
import Multiple from "../features/trainindTopic/multiple.vue";
|
||||
import Radio from "../features/trainindTopic/radio.vue";
|
||||
|
||||
const activeIndex = ref("1");
|
||||
const indexStyle = "background-color: rgb(241 245 249);";
|
||||
const activeStyle = "background-color: rgb(207 250 254);";
|
||||
|
||||
const handleSelect = (key, keyPath) => {
|
||||
activeIndex.value = key;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
556
src/components/features/trainindTopic/interlocution.vue
Normal file
@@ -0,0 +1,556 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="interlocutionMsgActive" />
|
||||
<AddNewData newDataLabel="新增问答题" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="30rem"
|
||||
max-height="30rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="stem">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchStemKeyRef"
|
||||
holderText="输入题干以搜索相关数据"
|
||||
@search="interlocutionMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 题干 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.stem }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="160" column-key="answer">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchAnswerKeyRef"
|
||||
holderText="输入答案以搜索相关数据"
|
||||
@search="interlocutionMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 答案 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.answer }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="difficulty">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectDifficultySearchRef"
|
||||
holderText="选择难度以搜索相关数据"
|
||||
:options="difficultyOptions"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 难度 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(difficultyOptions, scope.row.difficulty)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(difficultyOptions, scope.row.difficulty) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="interlocutionMsgActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="interlocutionMsg"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddInterlocutionForm
|
||||
ref="addInterlocutionFormRef"
|
||||
title="新增问答题"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="interlocutionMsg"
|
||||
/>
|
||||
<EditInterlocutionForm
|
||||
ref="editInterlocutionFormRef"
|
||||
operateLabel="编辑问答题"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除问答题"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出问答题"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../../operate/tabelTools.vue";
|
||||
import AddNewData from "../../operate/addNewData.vue";
|
||||
import TabelSelect from "../../operate/tabelSelect.vue";
|
||||
import SearchKey from "../../search/searchKey.vue";
|
||||
import Pagination from "../../search/pagination.vue";
|
||||
import AddInterlocutionForm from "../../addNewData/trainindTopic/interlocution/interlocutionForm.vue";
|
||||
import EditInterlocutionForm from "../../editData/trainindTopic/interlocution.vue";
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
import DownloadData from "../../operate/downloadData.vue";
|
||||
|
||||
import interlocutionMsgActiveStore from "../../../stores/trainindTopic/interlocution.js";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes.js";
|
||||
import { downloadData } from "../../../utils/downloadData.js";
|
||||
import { judgment } from "../../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const interlocutionMsgActive = interlocutionMsgActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑问答题",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除问答题",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchStemKeyRef = ref(null);
|
||||
const SearchAnswerKeyRef = ref(null);
|
||||
const SelectDifficultySearchRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addInterlocutionFormRef = ref(null);
|
||||
const editInterlocutionFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
stem: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const difficultyOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "简单",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "普通",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "困难",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addInterlocutionFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
interlocutionMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
interlocutionMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
interlocutionMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const interlocutionMsg = () => {
|
||||
judgment(searchOptions, "stem", SearchStemKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "answer", SearchAnswerKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "difficulty", SelectDifficultySearchRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showInterlocution, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.interlocutionMsg;
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
interlocutionMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
interlocutionMsgActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.stem == element.stem) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.stem == element.stem) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editInterlocutionFormRef.value.model = EditSelectRef.value.model;
|
||||
editInterlocutionFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
editInterlocutionFormRef.value.ruleForm.stem = singleData.stem;
|
||||
editInterlocutionFormRef.value.ruleForm.answer = singleData.answer;
|
||||
difficultyOptions.forEach((item) => {
|
||||
if (item.value == singleData.difficulty) {
|
||||
editInterlocutionFormRef.value.ruleForm.difficulty = item.label;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editInterlocution;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editInterlocutionFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteInterlocution;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
data.updateMsg = { ...editInterlocutionFormRef.value.ruleForm };
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
}
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
interlocutionMsg();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
difficultyOptions.forEach((element) => {
|
||||
if (element.value == item["difficulty"]) {
|
||||
item["difficulty"] = element.label;
|
||||
}
|
||||
});
|
||||
});
|
||||
const dataHeaders = ["题干", "答案", "难度"];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadInterlocutionData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ interlocutionMsg });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
interlocutionMsgActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
interlocutionMsgActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = interlocutionMsgActive.pageCount;
|
||||
dialogSearchVisible.value = interlocutionMsgActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = interlocutionMsgActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = interlocutionMsgActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
interlocutionMsgActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.stem = interlocutionMsgActive.searchOptions.stem;
|
||||
searchOptions.answer = interlocutionMsgActive.searchOptions.answer;
|
||||
searchOptions.difficulty = interlocutionMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
interlocutionMsg();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchStemKeyRef.value.searchMsg = interlocutionMsgActive.searchOptions.stem;
|
||||
SearchAnswerKeyRef.value.searchMsg = interlocutionMsgActive.searchOptions.answer;
|
||||
SelectDifficultySearchRef.value.searchMsg =
|
||||
interlocutionMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
584
src/components/features/trainindTopic/judgment.vue
Normal file
@@ -0,0 +1,584 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="judgmentMsgActive" />
|
||||
<AddNewData newDataLabel="新增判断题" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="30rem"
|
||||
max-height="30rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="stem">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchStemKeyRef"
|
||||
holderText="输入题干以搜索相关数据"
|
||||
@search="judgmentMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 题干 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.stem }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="answer">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectAnswerSearchRef"
|
||||
holderText="选择答案以搜索相关数据"
|
||||
:options="answerOptions"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 答案 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(answerOptions, scope.row.answer)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(answerOptions, scope.row.answer) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="difficulty">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectDifficultySearchRef"
|
||||
holderText="选择难度以搜索相关数据"
|
||||
:options="difficultyOptions"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 难度 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(difficultyOptions, scope.row.difficulty)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(difficultyOptions, scope.row.difficulty) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="judgmentMsgActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="judgmentMsg"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddJudgmentForm
|
||||
ref="addJudgmentFormRef"
|
||||
title="新增判断题"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="judgmentMsg"
|
||||
/>
|
||||
<EditJudgmentForm
|
||||
ref="editJudgmentFormRef"
|
||||
operateLabel="编辑判断题"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除判断题"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出判断题"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../../operate/tabelTools.vue";
|
||||
import AddNewData from "../../operate/addNewData.vue";
|
||||
import TabelSelect from "../../operate/tabelSelect.vue";
|
||||
import SearchKey from "../../search/searchKey.vue";
|
||||
import SelectSearch from "../../search/selectSearch.vue";
|
||||
import Pagination from "../../search/pagination.vue";
|
||||
import AddJudgmentForm from "../../addNewData/trainindTopic/judgment/judgmentForm.vue";
|
||||
import EditJudgmentForm from "../../editData/trainindTopic/judgment.vue";
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
import DownloadData from "../../operate/downloadData.vue";
|
||||
|
||||
import judgmentMsgActiveStore from "../../../stores/trainindTopic/judgment.js";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes.js";
|
||||
import { downloadData } from "../../../utils/downloadData.js";
|
||||
import { judgment } from "../../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const judgmentMsgActive = judgmentMsgActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑判断题",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除判断题",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchStemKeyRef = ref(null);
|
||||
const SelectAnswerSearchRef = ref(null);
|
||||
const SelectDifficultySearchRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addJudgmentFormRef = ref(null);
|
||||
const editJudgmentFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
stem: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const answerOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "错误",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "正确",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
const difficultyOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "简单",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "普通",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "困难",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
answerOptions,
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
answerOptions,
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addJudgmentFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
judgmentMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
judgmentMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
judgmentMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const judgmentMsg = () => {
|
||||
judgment(searchOptions, "stem", SearchStemKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "answer", SelectAnswerSearchRef.value, "searchMsg");
|
||||
judgment(searchOptions, "difficulty", SelectDifficultySearchRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showJudgment, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.judgmentMsg;
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
judgmentMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
judgmentMsgActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.stem == element.stem) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.stem == element.stem) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editJudgmentFormRef.value.model = EditSelectRef.value.model;
|
||||
editJudgmentFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
editJudgmentFormRef.value.ruleForm.stem = singleData.stem;
|
||||
answerOptions.forEach((item) => {
|
||||
if (item.value == singleData.answer) {
|
||||
editJudgmentFormRef.value.ruleForm.answer = item.label;
|
||||
}
|
||||
});
|
||||
difficultyOptions.forEach((item) => {
|
||||
if (item.value == singleData.difficulty) {
|
||||
editJudgmentFormRef.value.ruleForm.difficulty = item.label;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editJudgment;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editJudgmentFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteJudgment;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
data.updateMsg = { ...editJudgmentFormRef.value.ruleForm };
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
}
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
judgmentMsg();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
answerOptions.forEach((element) => {
|
||||
if (element.value == item["answer"]) {
|
||||
item["answer"] = element.label;
|
||||
}
|
||||
});
|
||||
difficultyOptions.forEach((element) => {
|
||||
if (element.value == item["difficulty"]) {
|
||||
item["difficulty"] = element.label;
|
||||
}
|
||||
});
|
||||
});
|
||||
const dataHeaders = ["题干", "答案", "难度"];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadJudgmentData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ judgmentMsg });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
judgmentMsgActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
judgmentMsgActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = judgmentMsgActive.pageCount;
|
||||
dialogSearchVisible.value = judgmentMsgActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = judgmentMsgActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = judgmentMsgActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
judgmentMsgActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.stem = judgmentMsgActive.searchOptions.stem;
|
||||
searchOptions.answer = judgmentMsgActive.searchOptions.answer;
|
||||
searchOptions.difficulty = judgmentMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
judgmentMsg();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchStemKeyRef.value.searchMsg = judgmentMsgActive.searchOptions.stem;
|
||||
SelectAnswerSearchRef.value.searchMsg = judgmentMsgActive.searchOptions.answer;
|
||||
SelectDifficultySearchRef.value.searchMsg =
|
||||
judgmentMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
695
src/components/features/trainindTopic/multiple.vue
Normal file
@@ -0,0 +1,695 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="multipleMsgActive" />
|
||||
<AddNewData newDataLabel="新增多选题" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="30rem"
|
||||
max-height="30rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="stem">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchStemKeyRef"
|
||||
holderText="输入题干以搜索相关数据"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 题干 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.stem }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_a">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsAKeyRef"
|
||||
holderText="输入选项A以搜索相关数据"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项A </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_a }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_b">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsBKeyRef"
|
||||
holderText="输入选项B以搜索相关数据"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项B </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_b }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_c">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsCKeyRef"
|
||||
holderText="输入选项C以搜索相关数据"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项C </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_c }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_d">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsDKeyRef"
|
||||
holderText="输入选项D以搜索相关数据"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项D </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_d }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_e">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsEKeyRef"
|
||||
holderText="输入选项E以搜索相关数据"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项E </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_e }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="160" column-key="answer">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchAnswerKeyRef"
|
||||
holderText="输入答案以搜索相关数据"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 答案 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.answer }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="difficulty">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectDifficultySearchRef"
|
||||
holderText="选择难度以搜索相关数据"
|
||||
:options="difficultyOptions"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 难度 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(difficultyOptions, scope.row.difficulty)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(difficultyOptions, scope.row.difficulty) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="multipleMsgActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddMultipleForm
|
||||
ref="addMultipleFormRef"
|
||||
title="新增多选题"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="multipleMsg"
|
||||
/>
|
||||
<EditMultipleForm
|
||||
ref="editMultipleFormRef"
|
||||
operateLabel="编辑多选题"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除多选题"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出多选题"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../../operate/tabelTools.vue";
|
||||
import AddNewData from "../../operate/addNewData.vue";
|
||||
import TabelSelect from "../../operate/tabelSelect.vue";
|
||||
import SearchKey from "../../search/searchKey.vue";
|
||||
import Pagination from "../../search/pagination.vue";
|
||||
import AddMultipleForm from "../../addNewData/trainindTopic/multiple/multipleForm.vue";
|
||||
import EditMultipleForm from "../../editData/trainindTopic/multiple.vue";
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
import DownloadData from "../../operate/downloadData.vue";
|
||||
|
||||
import multipleMsgActiveStore from "../../../stores/trainindTopic/multiple.js";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes.js";
|
||||
import { downloadData } from "../../../utils/downloadData.js";
|
||||
import { judgment } from "../../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const multipleMsgActive = multipleMsgActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑多选题",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除多选题",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchStemKeyRef = ref(null);
|
||||
const SearchOptionsAKeyRef = ref(null);
|
||||
const SearchOptionsBKeyRef = ref(null);
|
||||
const SearchOptionsCKeyRef = ref(null);
|
||||
const SearchOptionsDKeyRef = ref(null);
|
||||
const SearchOptionsEKeyRef = ref(null);
|
||||
const SearchAnswerKeyRef = ref(null);
|
||||
const SelectDifficultySearchRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addMultipleFormRef = ref(null);
|
||||
const editMultipleFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
stem: "",
|
||||
options_a: "",
|
||||
options_b: "",
|
||||
options_c: "",
|
||||
options_d: "",
|
||||
options_e: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const difficultyOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "简单",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "普通",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "困难",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addMultipleFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
multipleMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
multipleMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
multipleMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const multipleMsg = () => {
|
||||
judgment(searchOptions, "stem", SearchStemKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_a", SearchOptionsAKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_b", SearchOptionsBKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_c", SearchOptionsCKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_d", SearchOptionsDKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_e", SearchOptionsEKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "answer", SearchAnswerKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "difficulty", SelectDifficultySearchRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showMultiple, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.multipleMsg;
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
multipleMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
multipleMsgActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.stem == element.stem) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.stem == element.stem) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editMultipleFormRef.value.model = EditSelectRef.value.model;
|
||||
editMultipleFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
editMultipleFormRef.value.ruleForm.stem = singleData.stem;
|
||||
editMultipleFormRef.value.ruleForm.options_a = singleData.options_a;
|
||||
editMultipleFormRef.value.ruleForm.options_b = singleData.options_b;
|
||||
editMultipleFormRef.value.ruleForm.options_c = singleData.options_c;
|
||||
editMultipleFormRef.value.ruleForm.options_d = singleData.options_d;
|
||||
editMultipleFormRef.value.ruleForm.options_e = singleData.options_e;
|
||||
editMultipleFormRef.value.ruleForm.answer = singleData.answer;
|
||||
difficultyOptions.forEach((item) => {
|
||||
if (item.value == singleData.difficulty) {
|
||||
editMultipleFormRef.value.ruleForm.difficulty = item.label;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editMultiple;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editMultipleFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteMultiple;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
data.updateMsg = { ...editMultipleFormRef.value.ruleForm };
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
}
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
multipleMsg();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
difficultyOptions.forEach((element) => {
|
||||
if (element.value == item["difficulty"]) {
|
||||
item["difficulty"] = element.label;
|
||||
}
|
||||
});
|
||||
});
|
||||
const dataHeaders = [
|
||||
"题干",
|
||||
"选项A",
|
||||
"选项B",
|
||||
"选项C",
|
||||
"选项D",
|
||||
"选项E",
|
||||
"答案",
|
||||
"难度",
|
||||
];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadMultipleData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ multipleMsg });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
multipleMsgActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
multipleMsgActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = multipleMsgActive.pageCount;
|
||||
dialogSearchVisible.value = multipleMsgActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = multipleMsgActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = multipleMsgActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
multipleMsgActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.stem = multipleMsgActive.searchOptions.stem;
|
||||
searchOptions.options_a = multipleMsgActive.searchOptions.options_a;
|
||||
searchOptions.options_b = multipleMsgActive.searchOptions.options_b;
|
||||
searchOptions.options_c = multipleMsgActive.searchOptions.options_c;
|
||||
searchOptions.options_d = multipleMsgActive.searchOptions.options_d;
|
||||
searchOptions.options_e = multipleMsgActive.searchOptions.options_e;
|
||||
searchOptions.answer = multipleMsgActive.searchOptions.answer;
|
||||
searchOptions.difficulty = multipleMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
multipleMsg();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchStemKeyRef.value.searchMsg = multipleMsgActive.searchOptions.stem;
|
||||
SearchOptionsAKeyRef.value.searchMsg = multipleMsgActive.searchOptions.options_a;
|
||||
SearchOptionsBKeyRef.value.searchMsg = multipleMsgActive.searchOptions.options_b;
|
||||
SearchOptionsCKeyRef.value.searchMsg = multipleMsgActive.searchOptions.options_c;
|
||||
SearchOptionsDKeyRef.value.searchMsg = multipleMsgActive.searchOptions.options_d;
|
||||
SearchOptionsEKeyRef.value.searchMsg = multipleMsgActive.searchOptions.options_e;
|
||||
SearchAnswerKeyRef.value.searchMsg = multipleMsgActive.searchOptions.answer;
|
||||
SelectDifficultySearchRef.value.searchMsg =
|
||||
multipleMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
659
src/components/features/trainindTopic/radio.vue
Normal file
@@ -0,0 +1,659 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格 -->
|
||||
<el-card>
|
||||
<div class="flex justify-center flex-wrap">
|
||||
<TabelTools @showTools="showTools" :dialogObj="radioMsgActive" />
|
||||
<AddNewData newDataLabel="新增单选题" @showAddForm="showAddForm" />
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
height="30rem"
|
||||
max-height="30rem"
|
||||
table-layout="auto"
|
||||
scrollbar-always-on
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="dialogOperationVisible"
|
||||
fixed="left"
|
||||
type="selection"
|
||||
min-width="40"
|
||||
column-key="selection"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="EditSelectRef"
|
||||
:holderText="editSelectHold"
|
||||
singleColor="primary"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="edit"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<TabelSelect
|
||||
v-if="dialogOperationVisible"
|
||||
ref="DelSelectRef"
|
||||
:holderText="delSelectHold"
|
||||
singleColor="danger"
|
||||
multipleColor="warning"
|
||||
allColor="danger"
|
||||
singleSize="small"
|
||||
multipleSize="small"
|
||||
allSize="small"
|
||||
:singlePlain="true"
|
||||
:multiplePlain="false"
|
||||
:allPlain="false"
|
||||
operateType="del"
|
||||
@showComfirmDialog="showComfirmDialog"
|
||||
/>
|
||||
<el-table-column min-width="200" column-key="stem">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchStemKeyRef"
|
||||
holderText="输入题干以搜索相关数据"
|
||||
@search="radioMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 题干 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.stem }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_a">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsAKeyRef"
|
||||
holderText="输入选项A以搜索相关数据"
|
||||
@search="radioMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项A </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_a }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_b">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsBKeyRef"
|
||||
holderText="输入选项B以搜索相关数据"
|
||||
@search="radioMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项B </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_b }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_c">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsCKeyRef"
|
||||
holderText="输入选项C以搜索相关数据"
|
||||
@search="radioMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项C </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_c }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" column-key="options_d">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchOptionsDKeyRef"
|
||||
holderText="输入选项D以搜索相关数据"
|
||||
@search="radioMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 选项D </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.options_d }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="160" column-key="answer">
|
||||
<template #header>
|
||||
<div>
|
||||
<SearchKey
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SearchAnswerKeyRef"
|
||||
holderText="输入答案以搜索相关数据"
|
||||
@search="radioMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 答案 </el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="flex justify-start items-center text-base">
|
||||
{{ scope.row.answer }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" column-key="difficulty">
|
||||
<template #header>
|
||||
<SelectSearch
|
||||
v-if="dialogSearchVisible"
|
||||
ref="SelectDifficultySearchRef"
|
||||
holderText="选择难度以搜索相关数据"
|
||||
:options="difficultyOptions"
|
||||
@search="multipleMsg"
|
||||
/>
|
||||
<div>
|
||||
<el-text class="mx-1"> 难度 </el-text>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div
|
||||
:style="styleShunt(difficultyOptions, scope.row.difficulty)"
|
||||
class="flex justify-center items-center text-base"
|
||||
>
|
||||
{{ labelShunt(difficultyOptions, scope.row.difficulty) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 表格 -->
|
||||
<Pagination
|
||||
ref="PaginationRef"
|
||||
:active="radioMsgActive"
|
||||
@sizeChangeBack="changePage"
|
||||
@search="radioMsg"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<AddRadioForm
|
||||
ref="addRadioFormRef"
|
||||
title="新增单选题"
|
||||
:addData="addData"
|
||||
:createdAt="null"
|
||||
@reloadData="radioMsg"
|
||||
/>
|
||||
<EditRadioForm
|
||||
ref="editRadioFormRef"
|
||||
operateLabel="编辑单选题"
|
||||
:editData="editData"
|
||||
:createdAt="null"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<PasswordOauth
|
||||
ref="delPasswordOauthRef"
|
||||
operateLabel="删除单选题"
|
||||
@requestOperate="requestOperate"
|
||||
/>
|
||||
<DownloadData
|
||||
ref="downloadDataRef"
|
||||
operateLabel="导出单选题"
|
||||
@downloadData="executeDownloadData"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import TabelTools from "../../operate/tabelTools.vue";
|
||||
import AddNewData from "../../operate/addNewData.vue";
|
||||
import TabelSelect from "../../operate/tabelSelect.vue";
|
||||
import SearchKey from "../../search/searchKey.vue";
|
||||
import Pagination from "../../search/pagination.vue";
|
||||
import AddRadioForm from "../../addNewData/trainindTopic/radio/radioForm.vue";
|
||||
import EditRadioForm from "../../editData/trainindTopic/radio.vue";
|
||||
import PasswordOauth from "../../operate/passwordOauth.vue";
|
||||
import DownloadData from "../../operate/downloadData.vue";
|
||||
|
||||
import radioMsgActiveStore from "../../../stores/trainindTopic/radio.js";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import { encrypt } from "../../../utils/aes.js";
|
||||
import { downloadData } from "../../../utils/downloadData.js";
|
||||
import { judgment } from "../../../utils/judgment.js";
|
||||
import { hasNullOrEmptyPropertyWithTypeof } from "../../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||
|
||||
const radioMsgActive = radioMsgActiveStore();
|
||||
|
||||
const editSelectHold = {
|
||||
single: "编辑",
|
||||
multiple: "编辑选中",
|
||||
all: "编辑所有",
|
||||
label: "编辑单选题",
|
||||
};
|
||||
|
||||
const delSelectHold = {
|
||||
single: "删除",
|
||||
multiple: "删除选中",
|
||||
all: "删除所有",
|
||||
label: "删除单选题",
|
||||
};
|
||||
const EditSelectRef = ref(null);
|
||||
const DelSelectRef = ref(null);
|
||||
const SearchStemKeyRef = ref(null);
|
||||
const SearchOptionsAKeyRef = ref(null);
|
||||
const SearchOptionsBKeyRef = ref(null);
|
||||
const SearchOptionsCKeyRef = ref(null);
|
||||
const SearchOptionsDKeyRef = ref(null);
|
||||
const SearchAnswerKeyRef = ref(null);
|
||||
const SelectDifficultySearchRef = ref(null);
|
||||
const PaginationRef = ref(null);
|
||||
const addRadioFormRef = ref(null);
|
||||
const editRadioFormRef = ref(null);
|
||||
const delPasswordOauthRef = ref(null);
|
||||
const downloadDataRef = ref(null);
|
||||
const dialogSearchVisible = ref(false);
|
||||
const dialogSortVisible = ref(false);
|
||||
const dialogOperationVisible = ref(false);
|
||||
const tableRef = ref();
|
||||
const offsetOff = ref(true);
|
||||
const pageCount = ref(0);
|
||||
const operate = ref("edit");
|
||||
|
||||
const searchOptions = reactive({
|
||||
stem: "",
|
||||
options_a: "",
|
||||
options_b: "",
|
||||
options_c: "",
|
||||
options_d: "",
|
||||
answer: "",
|
||||
difficulty: "",
|
||||
});
|
||||
|
||||
const sortOptions = reactive({});
|
||||
|
||||
const tableData = ref([]);
|
||||
|
||||
const difficultyOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "简单",
|
||||
style:
|
||||
"color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "普通",
|
||||
style:
|
||||
"color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "困难",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);padding: 0;",
|
||||
},
|
||||
];
|
||||
|
||||
let singleData = reactive({});
|
||||
let operateData = reactive({});
|
||||
let operateDataClone = reactive({});
|
||||
|
||||
const addData = reactive({
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const editData = reactive({
|
||||
difficultyOptions,
|
||||
});
|
||||
|
||||
const showAddForm = () => {
|
||||
addRadioFormRef.value.dialogVisible = true;
|
||||
};
|
||||
|
||||
const styleShunt = (options, data) => {
|
||||
let nowStyle;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowStyle = item.style;
|
||||
}
|
||||
});
|
||||
return nowStyle;
|
||||
};
|
||||
|
||||
const labelShunt = (options, data) => {
|
||||
let nowLabel;
|
||||
options.forEach((item) => {
|
||||
if (data == item.value) {
|
||||
nowLabel = item.label;
|
||||
}
|
||||
});
|
||||
return nowLabel;
|
||||
};
|
||||
|
||||
const showTools = (operateType) => {
|
||||
switch (operateType) {
|
||||
case "search":
|
||||
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||
radioMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||
break;
|
||||
case "sort":
|
||||
dialogSortVisible.value = !dialogSortVisible.value;
|
||||
radioMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||
break;
|
||||
case "operation":
|
||||
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||
radioMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||
break;
|
||||
case "downloadData":
|
||||
downloadDataRef.value.downloadDataDialogVisible = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const resetOffset = () => {
|
||||
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||
PaginationRef.value.handleCurrentChange(1);
|
||||
offsetOff.value = false;
|
||||
}
|
||||
} else {
|
||||
offsetOff.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const radioMsg = () => {
|
||||
judgment(searchOptions, "stem", SearchStemKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_a", SearchOptionsAKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_b", SearchOptionsBKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_c", SearchOptionsCKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "options_d", SearchOptionsDKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "answer", SearchAnswerKeyRef.value, "searchMsg");
|
||||
judgment(searchOptions, "difficulty", SelectDifficultySearchRef.value, "searchMsg");
|
||||
resetOffset();
|
||||
const data = {
|
||||
offset: PaginationRef.value == null ? 1 : PaginationRef.value.offset,
|
||||
limit: PaginationRef.value == null ? 10 : PaginationRef.value.limit,
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
};
|
||||
$http.post($url.showRadio, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableData.value = res.data.radioMsg;
|
||||
PaginationRef.value.dataCount = res.data.count;
|
||||
radioMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||
pageCount.value = Math.ceil(
|
||||
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||
);
|
||||
radioMsgActive.pageCount = pageCount.value;
|
||||
if (!operateData[PaginationRef.value.offset]) return;
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
tableData.value.forEach((item) => {
|
||||
if (item.stem == element.stem) {
|
||||
nextTick(() => {
|
||||
tableRef.value.toggleRowSelection(item, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tableData.value = [];
|
||||
// ElMessage.error("未查找到相关数据!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const changePage = (val) => {
|
||||
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||
operateData = {};
|
||||
for (let i = 0; i < pageCount.value; i++) {
|
||||
operateData[i + 1] = [];
|
||||
for (const key in operateDataClone) {
|
||||
operateDataClone[key].forEach((element) => {
|
||||
// 判断数据在第几页
|
||||
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||
operateData[i + 1].push(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
operateData[PaginationRef.value.offset] = val;
|
||||
tableData.value.forEach((item, index) => {
|
||||
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||
if (item.stem == element.stem) {
|
||||
// 数据在表格中的位置
|
||||
element.location =
|
||||
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||
};
|
||||
|
||||
const showComfirmDialog = (singleMsg) => {
|
||||
singleData = { ...singleMsg.data };
|
||||
operate.value = singleMsg.operateType;
|
||||
if (singleMsg.operateType == "edit") {
|
||||
editRadioFormRef.value.model = EditSelectRef.value.model;
|
||||
editRadioFormRef.value.operateDialogVisible = true;
|
||||
if (EditSelectRef.value.model == "single") {
|
||||
editRadioFormRef.value.ruleForm.stem = singleData.stem;
|
||||
editRadioFormRef.value.ruleForm.options_a = singleData.options_a;
|
||||
editRadioFormRef.value.ruleForm.options_b = singleData.options_b;
|
||||
editRadioFormRef.value.ruleForm.options_c = singleData.options_c;
|
||||
editRadioFormRef.value.ruleForm.options_d = singleData.options_d;
|
||||
editRadioFormRef.value.ruleForm.answer = singleData.answer;
|
||||
difficultyOptions.forEach((item) => {
|
||||
if (item.value == singleData.difficulty) {
|
||||
editRadioFormRef.value.ruleForm.difficulty = item.label;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (singleMsg.operateType == "del") {
|
||||
delPasswordOauthRef.value.operateDialogVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const requestOperate = () => {
|
||||
let operateType, url, model, password;
|
||||
if (operate.value == "edit") {
|
||||
operateType = "编辑";
|
||||
url = $url.editRadio;
|
||||
model = EditSelectRef.value.model;
|
||||
password = editRadioFormRef.value.password;
|
||||
} else if (operate.value == "del") {
|
||||
operateType = "删除";
|
||||
url = $url.deleteRadio;
|
||||
model = DelSelectRef.value.model;
|
||||
password = delPasswordOauthRef.value.ruleForm.password;
|
||||
}
|
||||
const data = {
|
||||
model: encrypt(model),
|
||||
password: encrypt(password),
|
||||
requestMsg:
|
||||
model == "single" ? singleData : model == "multiple" ? operateDataClone : "",
|
||||
};
|
||||
if (operate.value == "edit") {
|
||||
data.updateMsg = { ...editRadioFormRef.value.ruleForm };
|
||||
for (const element in data.updateMsg) {
|
||||
if (data.updateMsg[element] == "") {
|
||||
delete data.updateMsg[element];
|
||||
}
|
||||
}
|
||||
}
|
||||
$http.post(url, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
tableRef.value.clearSelection();
|
||||
operateData = {};
|
||||
operateDataClone = {};
|
||||
ElMessage({
|
||||
message: `${operateType}成功!`,
|
||||
type: "success",
|
||||
});
|
||||
radioMsg();
|
||||
} else {
|
||||
ElMessage.error(`${operateType}失败!`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const executeDownloadData = (form) => {
|
||||
// 根据数据量大小来决定在前端还是后端导出数据
|
||||
if (
|
||||
tableData.value == [] ||
|
||||
tableData.value == undefined ||
|
||||
PaginationRef.value.dataCount == 0 ||
|
||||
PaginationRef.value.dataCount == null
|
||||
) {
|
||||
ElMessage.error("暂无数据!");
|
||||
return;
|
||||
}
|
||||
let dataClone = JSON.parse(JSON.stringify(tableData.value));
|
||||
dataClone.forEach((item) => {
|
||||
difficultyOptions.forEach((element) => {
|
||||
if (element.value == item["difficulty"]) {
|
||||
item["difficulty"] = element.label;
|
||||
}
|
||||
});
|
||||
});
|
||||
const dataHeaders = ["题干", "选项A", "选项B", "选项C", "选项D", "答案", "难度"];
|
||||
if (PaginationRef.value.dataCount <= PaginationRef.value.limit) {
|
||||
downloadData(form, dataClone, dataHeaders);
|
||||
} else {
|
||||
const data = {
|
||||
form,
|
||||
searchMsg: {
|
||||
searchOptions: searchOptions,
|
||||
sortOptions: sortOptions,
|
||||
},
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.downloadRadioData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ radioMsg });
|
||||
|
||||
watch(searchOptions, (value) => {
|
||||
radioMsgActive.searchOptions = value;
|
||||
});
|
||||
|
||||
watch(sortOptions, (value) => {
|
||||
radioMsgActive.sortOptions = value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
pageCount.value = radioMsgActive.pageCount;
|
||||
dialogSearchVisible.value = radioMsgActive.dialogSearchVisible;
|
||||
dialogSortVisible.value = radioMsgActive.dialogSortVisible;
|
||||
dialogOperationVisible.value = radioMsgActive.dialogOperationVisible;
|
||||
downloadDataRef.value.downloadDataDialogVisible =
|
||||
radioMsgActive.downloadDataDialogVisible;
|
||||
|
||||
if (dialogSearchVisible.value) {
|
||||
searchOptions.stem = radioMsgActive.searchOptions.stem;
|
||||
searchOptions.options_a = radioMsgActive.searchOptions.options_a;
|
||||
searchOptions.options_b = radioMsgActive.searchOptions.options_b;
|
||||
searchOptions.options_c = radioMsgActive.searchOptions.options_c;
|
||||
searchOptions.options_d = radioMsgActive.searchOptions.options_d;
|
||||
searchOptions.answer = radioMsgActive.searchOptions.answer;
|
||||
searchOptions.difficulty = radioMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
radioMsg();
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
if (dialogSearchVisible.value) {
|
||||
SearchStemKeyRef.value.searchMsg = radioMsgActive.searchOptions.stem;
|
||||
SearchOptionsAKeyRef.value.searchMsg = radioMsgActive.searchOptions.options_a;
|
||||
SearchOptionsBKeyRef.value.searchMsg = radioMsgActive.searchOptions.options_b;
|
||||
SearchOptionsCKeyRef.value.searchMsg = radioMsgActive.searchOptions.options_c;
|
||||
SearchOptionsDKeyRef.value.searchMsg = radioMsgActive.searchOptions.options_d;
|
||||
SearchAnswerKeyRef.value.searchMsg = radioMsgActive.searchOptions.answer;
|
||||
SelectDifficultySearchRef.value.searchMsg = radioMsgActive.searchOptions.difficulty;
|
||||
}
|
||||
|
||||
if (dialogSortVisible.value) {
|
||||
}
|
||||
|
||||
if (dialogOperationVisible.value) {
|
||||
}
|
||||
|
||||
if (downloadDataRef.value.downloadDataDialogVisible) {
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
1106
src/components/features/userList.vue
Normal file
29
src/components/operate/addNewData.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div class="relative top-0 right-0 z-10">
|
||||
<div class="absolute top-0 right-0" style="font-size: 1rem">
|
||||
<el-button
|
||||
style="font-weight: bold"
|
||||
type="primary"
|
||||
size="small"
|
||||
plain
|
||||
@click="showAddForm"
|
||||
>
|
||||
{{ newDataLabel }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
newDataLabel: String,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["showAddForm"]);
|
||||
|
||||
const showAddForm = () => {
|
||||
emit("showAddForm");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
167
src/components/operate/downloadData.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="downloadDataDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
{{ operateLabel }}
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto text-center"
|
||||
>
|
||||
<el-text class="mx-1" size="small" type="danger">
|
||||
如果需要导出符合一定条件的数据,请先使用表格工具来对表格进行操作,然后再进行数据导出。
|
||||
</el-text>
|
||||
<el-form-item class="mx-1 font-bold" label="工作表名称" prop="sheetName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入工作表名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.sheetName"
|
||||
@input="filter(ruleForm.sheetName, 'sheetName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入文件名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.fileName"
|
||||
@input="filter(ruleForm.fileName, 'fileName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件类型" prop="extensionType">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择文件类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.extensionType"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in extensionTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm(ruleFormRef)">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const downloadDataDialogVisible = ref(false);
|
||||
const ruleFormRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
sheetName: "",
|
||||
fileName: "",
|
||||
extensionType: "",
|
||||
});
|
||||
|
||||
const extensionTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "xlsx文件(推荐)",
|
||||
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "xls文件",
|
||||
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "csv文件(数据库导入专用)",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);",
|
||||
},
|
||||
];
|
||||
|
||||
const rules = reactive({
|
||||
sheetName: [{ required: true, message: "请输入工作表名称", trigger: "blur" }],
|
||||
fileName: [{ required: true, message: "请输入文件名称", trigger: "blur" }],
|
||||
extensionType: [{ required: true, message: "请选择文件类型", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
operateLabel: String,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["downloadData"]);
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
downloadDataDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
formElClone.value = JSON.parse(JSON.stringify(ruleForm));
|
||||
emit("downloadData", formElClone.value);
|
||||
downloadDataDialogVisible.value = false;
|
||||
formEl.resetFields();
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ downloadDataDialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
407
src/components/operate/export/exportApplication.vue
Normal file
@@ -0,0 +1,407 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="applicationDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
<!-- {{ applicationLabel }} -->
|
||||
导出报名用户
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="工作单位" prop="workplace">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchWorkplace"
|
||||
clearable
|
||||
placeholder="请输入工作单位"
|
||||
v-model="ruleForm.workplace"
|
||||
@input="filter(ruleForm.workplace, 'workplace')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="注册时间段" prop="created_at">
|
||||
<el-date-picker
|
||||
v-model="ruleForm.created_at"
|
||||
type="datetimerange"
|
||||
size="small"
|
||||
range-separator="到"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
popper-class="DateTimePicker"
|
||||
@visible-change="handleVisibleChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="考试uid" prop="exam_uid">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchExamUid"
|
||||
clearable
|
||||
placeholder="请输入考试uid"
|
||||
v-model="ruleForm.exam_uid"
|
||||
@input="filter(ruleForm.exam_uid, 'exam_uid')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名来源" prop="source">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入报名来源"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.source"
|
||||
@input="filter(ruleForm.source, 'source')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名结果说明" prop="result">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入报名结果说明"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.result"
|
||||
@input="filter(ruleForm.result, 'result')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="工作表名称" prop="sheetName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入工作表名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.sheetName"
|
||||
@input="filter(ruleForm.sheetName, 'sheetName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入文件名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.fileName"
|
||||
@input="filter(ruleForm.fileName, 'fileName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件类型" prop="extensionType">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择文件类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.extensionType"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in extensionTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm(ruleFormRef)">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
// const props = defineProps({
|
||||
// applicationLabel: String,
|
||||
// });
|
||||
|
||||
// const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const applicationDialogVisible = ref(false);
|
||||
const ruleFormRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
workplace: "",
|
||||
created_at: "",
|
||||
exam_uid: "",
|
||||
source: "",
|
||||
result: "",
|
||||
sheetName: "",
|
||||
fileName: "",
|
||||
extensionType: "",
|
||||
});
|
||||
|
||||
const extensionTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "xlsx文件(推荐)",
|
||||
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "xls文件",
|
||||
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "csv文件(数据库导入专用)",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);",
|
||||
},
|
||||
];
|
||||
|
||||
const searchWorkplace = (value, cb) => {
|
||||
const data = {
|
||||
workplace: value,
|
||||
};
|
||||
$http.post($url.searchWorkplace, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const searchExamUid = (value, cb) => {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.searchExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateWorkplace = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入工作单位"));
|
||||
} else {
|
||||
const data = {
|
||||
workplace: value,
|
||||
};
|
||||
$http.post($url.findWorkplace, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该工作单位不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const validateExamUid = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入考试uid"));
|
||||
} else {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.findExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该考试uid不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
workplace: [{ required: true, validator: validateWorkplace, trigger: "blur" }],
|
||||
created_at: [{ required: true, message: "请选择注册时间段", trigger: "change" }],
|
||||
exam_uid: [{ required: true, validator: validateExamUid, trigger: "blur" }],
|
||||
source: [{ required: true, message: "请输入报名来源", trigger: "blur" }],
|
||||
result: [{ required: true, message: "请输入报名结果说明", trigger: "blur" }],
|
||||
sheetName: [{ required: true, message: "请输入工作表名称", trigger: "blur" }],
|
||||
fileName: [{ required: true, message: "请输入文件名称", trigger: "blur" }],
|
||||
extensionType: [{ required: true, message: "请选择文件类型", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
applicationDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
applicationDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
const applicationOperate = (form, searchMsg, importForm) => {
|
||||
const dataHeaders = [
|
||||
"考生身份证号",
|
||||
"考生姓名",
|
||||
"考试uid",
|
||||
"报名来源",
|
||||
"报名状态",
|
||||
"缴费状态",
|
||||
"报名结果说明",
|
||||
];
|
||||
const data = {
|
||||
form,
|
||||
searchMsg,
|
||||
importForm,
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.importApplicationData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
let form = {};
|
||||
form.sheetName = ruleForm.sheetName;
|
||||
form.fileName = ruleForm.fileName;
|
||||
form.extensionType = ruleForm.extensionType;
|
||||
let searchMsg = {
|
||||
searchOptions: {},
|
||||
sortOptions: {},
|
||||
};
|
||||
searchMsg.searchOptions.workplace = ruleForm.workplace;
|
||||
searchMsg.searchOptions.created_at = ruleForm.created_at;
|
||||
let importForm = {};
|
||||
importForm.exam_uid = ruleForm.exam_uid;
|
||||
importForm.source = ruleForm.source;
|
||||
importForm.result = ruleForm.result;
|
||||
// emit("requestOperate", form, searchMsg, importForm);
|
||||
applicationOperate(form, searchMsg, importForm);
|
||||
applicationDialogVisible.value = false;
|
||||
formEl.resetFields();
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleVisibleChange = () => {
|
||||
setTimeout(() => {
|
||||
let changeNode = window.document.getElementsByClassName("DateTimePicker")[0];
|
||||
let Triangles = changeNode.children[1];
|
||||
Triangles.style.display = "none";
|
||||
let elppNode = changeNode.children[0];
|
||||
elppNode.style.width = "30rem";
|
||||
elppNode.style.backgroundColor = "#aaffff";
|
||||
let elppbwNode = elppNode.children[0];
|
||||
elppbwNode.style.width = "30rem";
|
||||
let elppfNode = elppNode.children[1];
|
||||
elppfNode.style.width = "30rem";
|
||||
elppfNode.style.backgroundColor = "#aaffff";
|
||||
let elppbNode = elppbwNode.children[0];
|
||||
elppbNode.style.width = "30rem";
|
||||
let elppbCNode = elppbNode.children;
|
||||
elppbCNode[0].style.width = "30rem";
|
||||
let leftDateSelectNode = elppbCNode[0].children[0].children[1];
|
||||
let leftTimeSelectNode = leftDateSelectNode.children[0];
|
||||
leftTimeSelectNode.addEventListener("click", function () {
|
||||
let leftTimeTableNode = leftDateSelectNode.children[1];
|
||||
leftTimeTableNode.style.width = "10rem";
|
||||
leftTimeTableNode.style.fontSize = "1rem";
|
||||
leftTimeTableNode.style.transform = "translate(-20%, 0)";
|
||||
});
|
||||
let rightDateSelectNode = elppbCNode[0].children[2].children[1];
|
||||
let rightTimeSelectNode = rightDateSelectNode.children[0];
|
||||
rightTimeSelectNode.addEventListener("click", function () {
|
||||
let rightTimeTableNode = rightDateSelectNode.children[1];
|
||||
rightTimeTableNode.style.width = "10rem";
|
||||
rightTimeTableNode.style.fontSize = "1rem";
|
||||
rightTimeTableNode.style.transform = "translate(-20%, 0)";
|
||||
});
|
||||
elppbCNode[1].style.width = "15rem";
|
||||
let elppbCFCNode = elppbCNode[1].children;
|
||||
elppbCFCNode[0].style.fontSize = "1rem";
|
||||
let elppbCFCCNode = elppbCFCNode[0].children;
|
||||
elppbCFCCNode[0].style.margin = "0";
|
||||
elppbCFCCNode[1].style.margin = "0";
|
||||
elppbCFCCNode[2].style.fontSize = "1rem";
|
||||
elppbCFCCNode[2].style.margin = "0";
|
||||
elppbCFCNode[1].style.fontSize = "1rem";
|
||||
elppbCNode[2].style.width = "15rem";
|
||||
let elppbCSCNode = elppbCNode[2].children;
|
||||
elppbCSCNode[0].style.fontSize = "1rem";
|
||||
let elppbCSCCNode = elppbCSCNode[0].children;
|
||||
elppbCSCCNode[0].style.margin = "0";
|
||||
elppbCSCCNode[1].style.margin = "0";
|
||||
elppbCSCCNode[2].style.fontSize = "1rem";
|
||||
elppbCSCCNode[2].style.margin = "0";
|
||||
elppbCSCNode[1].style.fontSize = "1rem";
|
||||
}, 0);
|
||||
};
|
||||
|
||||
defineExpose({ applicationDialogVisible });
|
||||
|
||||
onMounted(() => {
|
||||
handleVisibleChange();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
284
src/components/operate/export/exportExamStars.vue
Normal file
@@ -0,0 +1,284 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="examStarsDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
<!-- {{ examStarsLabel }} -->
|
||||
导出考试星学员
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="考试uid" prop="exam_uid">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchExamUid"
|
||||
clearable
|
||||
placeholder="请输入考试uid"
|
||||
minlength="10"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.exam_uid"
|
||||
@input="filter(ruleForm.exam_uid, 'exam_uid')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择报名状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in exportData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="工作表名称" prop="sheetName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入工作表名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.sheetName"
|
||||
@input="filter(ruleForm.sheetName, 'sheetName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入文件名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.fileName"
|
||||
@input="filter(ruleForm.fileName, 'fileName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件类型" prop="extensionType">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择文件类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.extensionType"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in extensionTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm(ruleFormRef)">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
const props = defineProps({
|
||||
exportData: Object,
|
||||
// examStarsLabel: String,
|
||||
});
|
||||
|
||||
// const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const examStarsDialogVisible = ref(false);
|
||||
const ruleFormRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
exam_uid: "",
|
||||
status: "",
|
||||
sheetName: "",
|
||||
fileName: "",
|
||||
extensionType: "",
|
||||
});
|
||||
|
||||
const extensionTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "xlsx文件(推荐)",
|
||||
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "xls文件",
|
||||
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "csv文件(数据库导入专用)",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);",
|
||||
},
|
||||
];
|
||||
|
||||
const searchExamUid = (value, cb) => {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.searchExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateExamUid = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入考试uid"));
|
||||
} else {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.findExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该考试不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
exam_uid: [{ required: true, validator: validateExamUid, trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择报名状态", trigger: "change" }],
|
||||
sheetName: [{ required: true, message: "请输入工作表名称", trigger: "blur" }],
|
||||
fileName: [{ required: true, message: "请输入文件名称", trigger: "blur" }],
|
||||
extensionType: [{ required: true, message: "请选择文件类型", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
examStarsDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
examStarsDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
const examStarsOperate = (form, searchMsg, importForm) => {
|
||||
const dataHeaders = ["*账号", "*密码", "*姓名", "*部门"];
|
||||
const data = {
|
||||
form,
|
||||
searchMsg,
|
||||
importForm,
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.importExamStars, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
let form = {};
|
||||
form.sheetName = ruleForm.sheetName;
|
||||
form.fileName = ruleForm.fileName;
|
||||
form.extensionType = ruleForm.extensionType;
|
||||
let searchMsg = {
|
||||
searchOptions: {},
|
||||
sortOptions: {},
|
||||
};
|
||||
searchMsg.searchOptions.exam_uid = ruleForm.exam_uid;
|
||||
searchMsg.searchOptions.status = ruleForm.status;
|
||||
let importForm = {};
|
||||
// emit("requestOperate", form, searchMsg, importForm);
|
||||
examStarsOperate(form, searchMsg, importForm);
|
||||
examStarsDialogVisible.value = false;
|
||||
formEl.resetFields();
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ examStarsDialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
390
src/components/operate/export/exportGrades.vue
Normal file
@@ -0,0 +1,390 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="gradesDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
<!-- {{ gradesLabel }} -->
|
||||
生成考试成绩导入表
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="工作表名称" prop="sheetName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入工作表名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.sheetName"
|
||||
@input="filter(ruleForm.sheetName, 'sheetName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入文件名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.fileName"
|
||||
@input="filter(ruleForm.fileName, 'fileName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件类型" prop="extensionType">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择文件类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.extensionType"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in extensionTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="数据类型" prop="dataType">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择文件类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.dataType"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in dataTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="ruleForm.dataType == '1'"
|
||||
class="mx-1 font-bold"
|
||||
label="及格分数"
|
||||
prop="passingScore"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入及格分数"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.passingScore"
|
||||
@input="filter(ruleForm.passingScore, 'passingScore')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="成绩录入类型" prop="gradesType">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择成绩录入类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.gradesType"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in gradesTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<UploadFile
|
||||
ref="uploadFileRef"
|
||||
:options="options"
|
||||
:relatedRules="relatedRules"
|
||||
:relatedOptions="relatedOptions"
|
||||
/>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm(ruleFormRef)">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
import UploadFile from "../uploadFile.vue";
|
||||
|
||||
const gradesDialogVisible = ref(false);
|
||||
const ruleFormRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
sheetName: "",
|
||||
fileName: "",
|
||||
extensionType: "",
|
||||
dataType: "",
|
||||
passingScore: "",
|
||||
gradesType: "",
|
||||
});
|
||||
|
||||
const extensionTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "xlsx文件(推荐)",
|
||||
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "xls文件",
|
||||
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "csv文件(数据库导入专用)",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);",
|
||||
},
|
||||
];
|
||||
|
||||
const dataTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "仅及格数据",
|
||||
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "全部数据",
|
||||
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);",
|
||||
},
|
||||
];
|
||||
|
||||
const gradesTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "普通成绩录入",
|
||||
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "补考成绩录入",
|
||||
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);",
|
||||
},
|
||||
];
|
||||
|
||||
const uploadFileRef = ref(null);
|
||||
const formClone = ref([]);
|
||||
|
||||
const options = {
|
||||
limit: 1,
|
||||
accept: ".xlsx",
|
||||
action: "",
|
||||
multiple: false,
|
||||
listType: "text",
|
||||
autoUpload: false,
|
||||
};
|
||||
|
||||
const relatedRules = {
|
||||
user_name: {
|
||||
value: "",
|
||||
label: "考生姓名",
|
||||
},
|
||||
identity_card: {
|
||||
value: "",
|
||||
label: "身份证号",
|
||||
},
|
||||
grades: {
|
||||
value: "",
|
||||
label: "考试成绩",
|
||||
},
|
||||
};
|
||||
|
||||
const relatedOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "考生姓名",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "身份证号",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "考试成绩",
|
||||
disabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
// const emit = defineEmits(["addGrades"]);
|
||||
|
||||
const rules = reactive({
|
||||
sheetName: [{ required: true, message: "请输入工作表名称", trigger: "blur" }],
|
||||
fileName: [{ required: true, message: "请输入文件名称", trigger: "blur" }],
|
||||
extensionType: [{ required: true, message: "请选择文件类型", trigger: "blur" }],
|
||||
dataType: [{ required: true, message: "请选择数据类型", trigger: "blur" }],
|
||||
passingScore: [{ required: true, message: "请输入及格分数", trigger: "blur" }],
|
||||
gradesType: [{ required: true, message: "请选择成绩录入类型", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
gradesDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
gradesDialogVisible.value = false;
|
||||
if (formEl) {
|
||||
formEl.resetFields();
|
||||
}
|
||||
if (uploadFileRef) {
|
||||
uploadFileRef.value.handleExceed();
|
||||
}
|
||||
};
|
||||
|
||||
const gradesOperate = (form, formClone, dataType, passingScore, gradesType) => {
|
||||
const dataHeaders = [
|
||||
"考生姓名",
|
||||
"身份证号",
|
||||
"考试uid",
|
||||
"参与状态",
|
||||
"考试成绩",
|
||||
"考试结果",
|
||||
];
|
||||
const data = {
|
||||
form,
|
||||
formClone,
|
||||
dataType,
|
||||
passingScore,
|
||||
gradesType,
|
||||
dataHeaders,
|
||||
};
|
||||
$http.post($url.importGradesData, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl || !uploadFileRef) return;
|
||||
formClone.value = [];
|
||||
const length = uploadFileRef.value.loadData.length;
|
||||
if (length == 0) return ElMessage.error("请先上传文件!");
|
||||
const flag = await uploadFileRef.value.confirm();
|
||||
if (!flag) return ElMessage.error("请先选择表格关联项!");
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
let form = {};
|
||||
form.sheetName = ruleForm.sheetName;
|
||||
form.fileName = ruleForm.fileName;
|
||||
form.extensionType = ruleForm.extensionType;
|
||||
ElMessage({
|
||||
message: `正在上传数据中,请稍等...`,
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uploadFileRef.value.loadData.forEach((ExcleForm) => {
|
||||
ExcleForm.forEach((worksheet) => {
|
||||
let context = [...worksheet];
|
||||
context.shift();
|
||||
context.forEach((item) => {
|
||||
if (item.length != 0) {
|
||||
formClone.value.push({
|
||||
identity_card: item[relatedRules.identity_card.value],
|
||||
user_name: item[relatedRules.user_name.value],
|
||||
grades: item[relatedRules.grades.value],
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
gradesOperate(
|
||||
form,
|
||||
formClone.value,
|
||||
ruleForm.dataType,
|
||||
ruleForm.passingScore,
|
||||
ruleForm.gradesType
|
||||
);
|
||||
gradesDialogVisible.value = false;
|
||||
formEl.resetFields();
|
||||
uploadFileRef.value.handleExceed();
|
||||
}, 3000);
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ gradesDialogVisible, resetCheckForm, confirm, formClone });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
331
src/components/operate/export/exportIssuance.vue
Normal file
@@ -0,0 +1,331 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="issuanceDialogVisible"
|
||||
:show-close="false"
|
||||
style="width: 80%"
|
||||
center
|
||||
align-center
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div
|
||||
style="font-size: 2rem"
|
||||
class="w-full font-bold"
|
||||
:id="titleId"
|
||||
:class="titleClass"
|
||||
>
|
||||
<!-- {{ issuanceLabel }} -->
|
||||
导出培训证书发放用户
|
||||
</div>
|
||||
<div
|
||||
@click="resetCheckForm(ruleFormRef)"
|
||||
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<el-icon>
|
||||
<CloseBold />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
style="max-width: 600px"
|
||||
:model="ruleForm"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="default"
|
||||
status-icon
|
||||
class="mx-auto"
|
||||
>
|
||||
<el-form-item class="mx-1 font-bold" label="考试uid" prop="exam_uid">
|
||||
<el-autocomplete
|
||||
:fetch-suggestions="searchExamUid"
|
||||
clearable
|
||||
placeholder="请输入考试uid"
|
||||
minlength="10"
|
||||
maxlength="10"
|
||||
v-model="ruleForm.exam_uid"
|
||||
@input="filter(ruleForm.exam_uid, 'exam_uid')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="报名状态" prop="status">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择报名状态"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.status"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in exportData.statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="工作表名称" prop="sheetName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入工作表名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.sheetName"
|
||||
@input="filter(ruleForm.sheetName, 'sheetName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入文件名称"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.fileName"
|
||||
@input="filter(ruleForm.fileName, 'fileName')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="mx-1 font-bold" label="文件类型" prop="extensionType">
|
||||
<el-select
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择文件类型"
|
||||
autocomplete="off"
|
||||
v-model="ruleForm.extensionType"
|
||||
style="width: 100%; font-size: 1rem"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in extensionTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
class="text-center"
|
||||
:style="item.style"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button style="font-weight: bold" type="primary" @click="confirm(ruleFormRef)">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { CloseBold } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import $http from "../../../api/index";
|
||||
import $url from "../../../api/url";
|
||||
|
||||
const props = defineProps({
|
||||
exportData: Object,
|
||||
// issuanceLabel: String,
|
||||
});
|
||||
|
||||
// const emit = defineEmits(["requestOperate"]);
|
||||
|
||||
const issuanceDialogVisible = ref(false);
|
||||
const ruleFormRef = ref(null);
|
||||
const formElClone = ref(null);
|
||||
|
||||
const ruleForm = reactive({
|
||||
exam_uid: "",
|
||||
status: "",
|
||||
sheetName: "",
|
||||
fileName: "",
|
||||
extensionType: "",
|
||||
});
|
||||
|
||||
const extensionTypeOptions = [
|
||||
{
|
||||
value: "0",
|
||||
label: "xlsx文件(推荐)",
|
||||
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "1",
|
||||
label: "xls文件",
|
||||
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);",
|
||||
},
|
||||
{
|
||||
value: "2",
|
||||
label: "csv文件(数据库导入专用)",
|
||||
style: "color: rgb(240, 70, 70);background-color: rgba(240, 70, 70, 0.1);",
|
||||
},
|
||||
];
|
||||
|
||||
const searchExamUid = (value, cb) => {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.searchExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
cb(res.data.data);
|
||||
} else {
|
||||
cb([]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const validateExamUid = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入考试uid"));
|
||||
} else {
|
||||
const data = {
|
||||
exam_uid: value,
|
||||
};
|
||||
$http.post($url.findExamUid, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("该考试不存在!"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const rules = reactive({
|
||||
exam_uid: [{ required: true, validator: validateExamUid, trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择报名状态", trigger: "change" }],
|
||||
sheetName: [{ required: true, message: "请输入工作表名称", trigger: "blur" }],
|
||||
fileName: [{ required: true, message: "请输入文件名称", trigger: "blur" }],
|
||||
extensionType: [{ required: true, message: "请选择文件类型", trigger: "blur" }],
|
||||
});
|
||||
|
||||
const filter = (value, label) => {
|
||||
if (/[=\s"'+-]/.test(value)) {
|
||||
if (ruleForm[label]) {
|
||||
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
issuanceDialogVisible.value = false;
|
||||
if (!ruleFormRef) return;
|
||||
formElClone.value = ruleFormRef.value;
|
||||
formElClone.value.resetFields();
|
||||
};
|
||||
|
||||
const resetCheckForm = (formEl) => {
|
||||
issuanceDialogVisible.value = false;
|
||||
if (!formEl) return;
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
const issuanceOperate = (form, searchMsg, importForm) => {
|
||||
const dataHeaders = [
|
||||
"序号",
|
||||
"姓名",
|
||||
"身份证号",
|
||||
"工作单位",
|
||||
"通讯地址",
|
||||
"联系电话",
|
||||
"培训开始时间",
|
||||
"培训结束时间",
|
||||
"培训地点",
|
||||
"考试方式",
|
||||
"考试成绩",
|
||||
"证书名称",
|
||||
"级别",
|
||||
];
|
||||
const data = {
|
||||
form,
|
||||
searchMsg,
|
||||
importForm,
|
||||
dataHeaders,
|
||||
};
|
||||
// 导出培训证书发放用户 excel 表
|
||||
$http.post($url.importIssuance, data).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "数据导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
setTimeout(() => {
|
||||
// 导出培训证书发放用户照片文件夹
|
||||
const dataPhoto = { searchMsg };
|
||||
$http.post($url.importUserPhoto, dataPhoto).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
ElMessage({
|
||||
message: "正在下载压缩包!",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
// 创建一个隐藏的<a>标签
|
||||
const link = document.createElement("a");
|
||||
link.style.display = "none";
|
||||
link.href = res.data.fileUrl;
|
||||
// 设置下载的文件名
|
||||
link.download = res.data.fileName;
|
||||
// 触发点击事件来下载文件
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
ElMessage({
|
||||
message: "用户照片文件夹导出成功!",
|
||||
type: "success",
|
||||
});
|
||||
}, 1000);
|
||||
} else {
|
||||
ElMessage.error("用户照片文件夹导出失败!");
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
} else {
|
||||
ElMessage.error("数据导出失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const confirm = async (formEl) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
let form = {};
|
||||
form.sheetName = ruleForm.sheetName;
|
||||
form.fileName = ruleForm.fileName;
|
||||
form.extensionType = ruleForm.extensionType;
|
||||
let searchMsg = {
|
||||
searchOptions: {},
|
||||
sortOptions: {},
|
||||
};
|
||||
searchMsg.searchOptions.exam_uid = ruleForm.exam_uid;
|
||||
searchMsg.searchOptions.status = ruleForm.status;
|
||||
let importForm = {};
|
||||
// emit("requestOperate", form, searchMsg, importForm);
|
||||
issuanceOperate(form, searchMsg, importForm);
|
||||
issuanceDialogVisible.value = false;
|
||||
formEl.resetFields();
|
||||
} else {
|
||||
ElMessage.error("提交失败!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ issuanceDialogVisible });
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||