528 lines
14 KiB
Vue
528 lines
14 KiB
Vue
<!-- 新建赴校信息 -->
|
|
<template>
|
|
<el-dialog
|
|
v-model="dialogVisible"
|
|
title="新建"
|
|
width="800px"
|
|
@close="onCancel"
|
|
align-center
|
|
>
|
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
|
|
<el-divider>基础信息</el-divider>
|
|
<el-row :gutter="12">
|
|
<el-col :span="12">
|
|
<el-form-item label="学校" prop="baseInfo.school">
|
|
<el-select
|
|
v-model="form.baseInfo.school"
|
|
placeholder="请选择学校"
|
|
clearable
|
|
filterable
|
|
>
|
|
<el-option
|
|
v-for="s in schoolOptions"
|
|
:key="s.value"
|
|
:label="s.label"
|
|
:value="s.value"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="年级" prop="baseInfo.gradeLevel">
|
|
<el-select
|
|
v-model="form.baseInfo.gradeLevel"
|
|
placeholder="请年级"
|
|
clearable
|
|
style="width: 120px"
|
|
>
|
|
<el-option
|
|
v-for="g in gradeOptions"
|
|
:key="g.value"
|
|
:label="g.label"
|
|
:value="g.value"
|
|
/>
|
|
</el-select>
|
|
<el-input-number
|
|
style="width: 120px"
|
|
v-model="form.baseInfo.gradeYear"
|
|
:min="2020"
|
|
:max="2100"
|
|
/>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="赴校时间" prop="baseInfo.date">
|
|
<el-date-picker
|
|
v-model="form.baseInfo.date"
|
|
type="date"
|
|
value-format="YYYY-MM-DD"
|
|
placeholder="请选择日期"
|
|
style="width: 100%"
|
|
/>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="赴校人员" prop="baseInfo.people">
|
|
<el-select
|
|
v-model="form.baseInfo.people"
|
|
placeholder="请选择赴校人员"
|
|
clearable
|
|
multiple
|
|
filterable
|
|
style="width: 100%"
|
|
>
|
|
<el-option
|
|
v-for="p in peopleOptions"
|
|
:key="p.value"
|
|
:label="p.text"
|
|
:value="p.value"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="预计解决时间" prop="baseInfo.endTime">
|
|
<el-date-picker
|
|
v-model="form.baseInfo.endTime"
|
|
type="date"
|
|
value-format="YYYY-MM-DD"
|
|
placeholder="请选预计解决时间"
|
|
style="width: 100%"
|
|
/>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<div>
|
|
提示:离赴校时间超过<span class="text-yellow-500">{ {{ warningDay }}天}</span
|
|
>黄色警告, 超过预计完成时间<span class="text-red-500"
|
|
>{ {{ errorDay }}天}</span
|
|
>红色警告
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-divider>基础工作</el-divider>
|
|
<el-row :gutter="12">
|
|
<el-col :span="12">
|
|
<el-form-item label="开展座谈" prop="work.talk">
|
|
<el-radio-group v-model="form.work.talk">
|
|
<el-radio :label="true">是</el-radio>
|
|
<el-radio :label="false">否</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="座谈情况">
|
|
<el-input
|
|
:maxlength="500"
|
|
v-model="form.work.talkDetail"
|
|
:disabled="!form.work.talk"
|
|
placeholder="请输入座谈情况"
|
|
/>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="开展班会" prop="work.classMeeting">
|
|
<el-radio-group v-model="form.work.classMeeting">
|
|
<el-radio :label="true">是</el-radio>
|
|
<el-radio :label="false">否</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="班会情况">
|
|
<el-input
|
|
:maxlength="500"
|
|
v-model="form.work.classMeetingDetail"
|
|
:disabled="!form.work.classMeeting"
|
|
placeholder="请输入班会情况"
|
|
/>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-divider>反馈问题</el-divider>
|
|
<div style="height: 370px; overflow-y: auto">
|
|
<div v-for="group in feedbackGroups" :key="group.key" class="feedback-group">
|
|
<div class="feedback-header">
|
|
<span class="group-title">{{ group.name }}</span>
|
|
<el-button type="primary" link @click="addProblem(group.key)"
|
|
>添加问题</el-button
|
|
>
|
|
</div>
|
|
<div v-if="form.feedback[group.key].length === 0" class="feedback-empty">
|
|
暂无问题
|
|
</div>
|
|
<div
|
|
v-for="(item, idx) in form.feedback[group.key]"
|
|
:key="item.id"
|
|
class="feedback-item"
|
|
>
|
|
<el-input v-model="item.text" :placeholder="`请输入${group.name}问题描述`" />
|
|
<el-button type="danger" text @click="removeProblem(group.key, idx)"
|
|
>删除</el-button
|
|
>
|
|
</div>
|
|
<el-divider />
|
|
</div>
|
|
</div>
|
|
</el-form>
|
|
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="onCancel">取 消</el-button>
|
|
<el-button type="primary" :loading="submitting" @click="onSubmit"
|
|
>确 定</el-button
|
|
>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script setup lang="ts" name="AddModal">
|
|
import { ref, reactive, computed, defineProps, defineEmits, watch } from "vue";
|
|
import type { FormInstance, FormRules } from "element-plus";
|
|
import { ElMessage } from "element-plus";
|
|
import { getSchoolData } from "@/api/userCenter";
|
|
import { errorDay, warningDay } from "./config";
|
|
import { getSchoolBusinessPeopleListApi, addOrEditApi } from "@/api/toschoolinfomanage";
|
|
const props = defineProps<{ visible: boolean }>();
|
|
// const emit = defineEmits<{ (e: "update:visible", value: boolean): void }>();
|
|
const emit = defineEmits<{
|
|
(e: "update:visible", value: boolean): void;
|
|
(e: "handleReset"): void;
|
|
}>();
|
|
const dialogVisible = computed({
|
|
get: () => props.visible,
|
|
set: (v) => emit("update:visible", v),
|
|
});
|
|
|
|
const formRef = ref<FormInstance>();
|
|
function uid() {
|
|
return Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
}
|
|
|
|
const schoolOptions = ref([]);
|
|
const peopleOptions = ref([]);
|
|
const getSchoolDataFn = () => {
|
|
getSchoolData().then((res) => {
|
|
if (res.code == 200) {
|
|
schoolOptions.value = res.data.map((i: any) => ({
|
|
label: i.text,
|
|
value: i.value,
|
|
}));
|
|
}
|
|
});
|
|
};
|
|
/**
|
|
* 获取赴校人员下拉数据
|
|
*/
|
|
const getSchoolBusinessPeopleList = () => {
|
|
getSchoolBusinessPeopleListApi({}).then((res: any) => {
|
|
if (res.code == 200) {
|
|
peopleOptions.value = (res.data || []).map((i) => ({
|
|
label: i.text,
|
|
value: i.text,
|
|
}));
|
|
}
|
|
});
|
|
};
|
|
getSchoolDataFn();
|
|
getSchoolBusinessPeopleList();
|
|
|
|
const gradeOptions = [
|
|
{ label: "高", value: "高" },
|
|
{ label: "初", value: "初" },
|
|
{ label: "小", value: "小" },
|
|
];
|
|
|
|
type FeedbackKey = "leaders" | "classroom" | "equipment" | "students" | "others";
|
|
interface FeedbackItem {
|
|
id: string;
|
|
text: string;
|
|
}
|
|
interface FormModel {
|
|
baseInfo: {
|
|
school?: string;
|
|
gradeYear?: number;
|
|
gradeLevel?: string;
|
|
date?: string;
|
|
endTime?: string;
|
|
people: string[];
|
|
};
|
|
work: {
|
|
talk: boolean;
|
|
talkDetail: string;
|
|
classMeeting: boolean;
|
|
classMeetingDetail: string;
|
|
};
|
|
feedback: Record<FeedbackKey, FeedbackItem[]>;
|
|
}
|
|
|
|
const form = reactive<FormModel>({
|
|
baseInfo: {
|
|
school: undefined,
|
|
gradeLevel: "高",
|
|
gradeYear: 2025,
|
|
date: undefined,
|
|
people: [],
|
|
},
|
|
work: {
|
|
talk: false,
|
|
talkDetail: "",
|
|
classMeeting: false,
|
|
classMeetingDetail: "",
|
|
},
|
|
feedback: {
|
|
leaders: [],
|
|
classroom: [],
|
|
equipment: [],
|
|
students: [],
|
|
others: [],
|
|
},
|
|
});
|
|
watch(
|
|
() => form.work.talk,
|
|
(val) => {
|
|
!val ? (form.work.talkDetail = "") : "";
|
|
}
|
|
);
|
|
watch(
|
|
() => form.work.classMeeting,
|
|
(val) => {
|
|
!val ? (form.work.classMeetingDetail = "") : "";
|
|
}
|
|
);
|
|
const rules: FormRules = {
|
|
"baseInfo.school": [{ required: true, message: "请选择学校", trigger: "change" }],
|
|
"baseInfo.gradeLevel": [{ required: true, message: "请选择年级", trigger: "change" }],
|
|
"baseInfo.date": [{ required: true, message: "请选择赴校时间", trigger: "change" }],
|
|
"baseInfo.people": [
|
|
{ required: true, message: "请选择赴校人员", trigger: "change" },
|
|
{
|
|
type: "array",
|
|
min: 1,
|
|
message: "请至少选择一名赴校人员",
|
|
trigger: "change",
|
|
},
|
|
],
|
|
};
|
|
|
|
const feedbackGroups = [
|
|
{ key: "leaders", name: "学校领导班子" },
|
|
{ key: "classroom", name: "双师课堂" },
|
|
{ key: "equipment", name: "设备" },
|
|
{ key: "students", name: "学生" },
|
|
{ key: "others", name: "其他" },
|
|
] as { key: FeedbackKey; name: string }[];
|
|
|
|
function addProblem(key: FeedbackKey) {
|
|
form.feedback[key].push({ id: uid(), text: "" });
|
|
}
|
|
|
|
function removeProblem(key: FeedbackKey, index: number) {
|
|
form.feedback[key].splice(index, 1);
|
|
}
|
|
|
|
// 新增:反馈问题非空校验
|
|
const feedbackGroupNameMap: Record<FeedbackKey, string> = {
|
|
leaders: "学校领导班子",
|
|
classroom: "双师课堂",
|
|
equipment: "设备",
|
|
students: "学生",
|
|
others: "其他",
|
|
};
|
|
function validateFeedbackNotEmpty() {
|
|
for (const g of feedbackGroups) {
|
|
const items = form.feedback[g.key] || [];
|
|
if (items.length === 0) continue; // 允许为 0
|
|
for (const it of items) {
|
|
if (!it.text || !it.text.trim()) {
|
|
ElMessage.error(`${feedbackGroupNameMap[g.key]} 的问题内容不能为空`);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const submitting = ref(false);
|
|
|
|
function onCancel() {
|
|
dialogVisible.value = false;
|
|
formRef.value.resetFields();
|
|
}
|
|
/**
|
|
* 把表单数据处理成接口需要的结构
|
|
* @param data
|
|
*/
|
|
const handleFeedback = (data: any) => {
|
|
const processData = (items: any[], questionType: number) => {
|
|
return items.map((item, idx) => ({
|
|
question: item.text,
|
|
questionType,
|
|
sort: (idx + 1).toString(),
|
|
}));
|
|
};
|
|
|
|
let handledData = [];
|
|
|
|
if (data.leaders.length > 0) handledData.push(...processData(data.leaders, 1));
|
|
if (data.classroom.length > 0) handledData.push(...processData(data.classroom, 10));
|
|
if (data.equipment.length > 0) handledData.push(...processData(data.equipment, 15));
|
|
if (data.students.length > 0) handledData.push(...processData(data.students, 20));
|
|
if (data.others.length > 0) handledData.push(...processData(data.others, 999));
|
|
|
|
return handledData;
|
|
};
|
|
let editParams = {
|
|
id: 0,
|
|
schoolId: 0,
|
|
schoolName: "string",
|
|
grade: "string",
|
|
gradeYear: 0,
|
|
gradeLevel: "string",
|
|
// 赴校人员
|
|
schoolBusinessUser: ["string"],
|
|
// 赴校时间
|
|
startTime: "2025-08-19T07:20:29.292Z",
|
|
// 备注
|
|
remark: "string",
|
|
// 反馈问题
|
|
feedbackQuestions: [
|
|
{
|
|
// 问题类型
|
|
questionType: 1,
|
|
// 排序
|
|
sort: "string",
|
|
// 问题描述
|
|
question: "string",
|
|
// 解决情况
|
|
solution: "string",
|
|
// 解决时间
|
|
endTime: "2025-08-19T07:20:29.292Z",
|
|
},
|
|
],
|
|
// 解决方案记录
|
|
solutionRecord: {
|
|
// 解决方案
|
|
solution: "string",
|
|
// 完结情况
|
|
endRecord: "string",
|
|
// 完结时间
|
|
endRecordTime: "string",
|
|
record: [
|
|
{
|
|
// 执行记录
|
|
executionRecords: "string",
|
|
// 执行时间
|
|
executionTime: "2025-08-19T07:20:29.292Z",
|
|
},
|
|
],
|
|
},
|
|
// 座谈情况
|
|
discussion: "string",
|
|
// 班会情况
|
|
classMeeting: "string",
|
|
};
|
|
async function onSubmit() {
|
|
if (!formRef.value) return;
|
|
await formRef.value.validate((valid) => {
|
|
if (!valid) return;
|
|
// 新增:校验反馈问题不为空
|
|
if (!validateFeedbackNotEmpty()) return;
|
|
submitting.value = true;
|
|
console.log("Submit payload:", form);
|
|
// enum FeedbackQuestionTypeEnum {
|
|
// 学校领导班子 = 1,
|
|
// 双师课堂 = 10,
|
|
// 设备 = 15,
|
|
// 学生 = 20,
|
|
// 其他 = 999
|
|
// }
|
|
let reqParams = {
|
|
id: 0, //id传0代表新增
|
|
schoolId: form.baseInfo.school,
|
|
schoolName: schoolOptions.value.find((i) => i.value == form.baseInfo.school).label,
|
|
// 固定传空字符串
|
|
gradeLevel: form.baseInfo.gradeLevel,
|
|
gradeYear: form.baseInfo.gradeYear,
|
|
schoolBusinessUser: form.baseInfo.people,
|
|
startTime: form.baseInfo.date,
|
|
endTime: form.baseInfo.endTime,
|
|
isDiscussion: form.work.talk,
|
|
discussion: form.work.talkDetail,
|
|
isClassMeeting: form.work.classMeeting,
|
|
classMeeting: form.work.classMeetingDetail,
|
|
feedbackQuestions: handleFeedback(form.feedback),
|
|
};
|
|
// return;
|
|
console.log("提交数据", reqParams);
|
|
addOrEditApi(reqParams)
|
|
.then((res) => {
|
|
if (res.code === 200) {
|
|
ElMessage.success("提交成功");
|
|
dialogVisible.value = false;
|
|
resetForm();
|
|
formRef.value.resetFields();
|
|
emit("handleReset");
|
|
}
|
|
})
|
|
.finally(() => {
|
|
submitting.value = false;
|
|
});
|
|
|
|
// }, 600);
|
|
});
|
|
}
|
|
|
|
function resetForm() {
|
|
form.baseInfo.school = undefined;
|
|
form.baseInfo.gradeLevel = undefined;
|
|
form.baseInfo.date = undefined;
|
|
form.baseInfo.people = [];
|
|
form.work.talk = false;
|
|
form.work.talkDetail = "";
|
|
form.work.classMeeting = false;
|
|
form.work.classMeetingDetail = "";
|
|
(Object.keys(form.feedback) as FeedbackKey[]).forEach((k) => {
|
|
form.feedback[k] = [];
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.feedback-group {
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.feedback-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin: 6px 0;
|
|
}
|
|
|
|
.group-title {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.feedback-item {
|
|
display: flex;
|
|
gap: 8px;
|
|
align-items: center;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.feedback-empty {
|
|
margin: 4px 0 8px;
|
|
font-size: 13px;
|
|
color: #999;
|
|
}
|
|
|
|
:deep(.el-dialog__body) {
|
|
max-height: 70vh;
|
|
overflow-y: auto;
|
|
}
|
|
</style>
|