北斗应用技术培训考试管理系统

This commit is contained in:
2026-03-27 17:40:17 +08:00
commit 7eb6b8b530
145 changed files with 31320 additions and 0 deletions

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

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

View 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">&nbsp;&nbsp;</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>

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