|
|
<template>
|
|
|
<div class="school-admin-workbench">
|
|
|
<section class="admin-hero">
|
|
|
<div class="admin-badge">Platform Admin / Schools</div>
|
|
|
<h1 class="admin-title">学校管理</h1>
|
|
|
<p class="admin-subtitle">平台超管维护学校基础档案,学校管理员账号和本校业务数据会绑定到这里。</p>
|
|
|
</section>
|
|
|
|
|
|
<section class="admin-panel">
|
|
|
<div class="toolbar">
|
|
|
<el-input v-model="query.schoolName" clearable placeholder="学校名称" class="filter-input" @keyup.enter="load" />
|
|
|
<el-button type="primary" @click="load">查询</el-button>
|
|
|
<el-button @click="reset">重置</el-button>
|
|
|
<el-button type="success" @click="openCreate">新增</el-button>
|
|
|
</div>
|
|
|
|
|
|
<el-table v-loading="loading" :data="rows" border>
|
|
|
<el-table-column label="学校名称" prop="schoolName" min-width="180" />
|
|
|
<el-table-column label="学校层次" prop="schoolGrade" min-width="120" />
|
|
|
<el-table-column label="省份" prop="schoolProvince" width="110" />
|
|
|
<el-table-column label="城市" prop="schoolCity" width="110" />
|
|
|
<el-table-column label="联系人" prop="schoolContacts" min-width="120" />
|
|
|
<el-table-column label="联系电话" prop="schoolContactsMobile" min-width="140" />
|
|
|
<el-table-column label="联系邮箱" prop="schoolContactsEmail" min-width="180" />
|
|
|
<el-table-column label="操作" width="160" fixed="right">
|
|
|
<template #default="{ row }">
|
|
|
<el-button link type="primary" @click="openEdit(row)">编辑</el-button>
|
|
|
<el-button link type="danger" @click="remove(row)">删除</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
<el-pagination
|
|
|
class="pager"
|
|
|
layout="total, prev, pager, next, sizes"
|
|
|
:total="total"
|
|
|
v-model:current-page="query.index"
|
|
|
v-model:page-size="query.size"
|
|
|
@current-change="load"
|
|
|
@size-change="handleSizeChange"
|
|
|
/>
|
|
|
|
|
|
<el-dialog
|
|
|
v-model="dialogVisible"
|
|
|
:title="editingId ? '编辑学校' : '新增学校'"
|
|
|
width="680px"
|
|
|
align-center
|
|
|
append-to-body
|
|
|
custom-class="admin-edit-dialog platform-admin-dialog platform-school-dialog"
|
|
|
>
|
|
|
<el-form :model="form" label-width="98px">
|
|
|
<el-form-item label="学校名称">
|
|
|
<el-input v-model="form.schoolName" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="学校层次">
|
|
|
<el-input v-model="form.schoolGrade" placeholder="如:本科、专科、双一流" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="省份/城市">
|
|
|
<div class="form-inline">
|
|
|
<el-select v-model="form.schoolProvince" filterable placeholder="请选择省份" @change="handleProvinceChange">
|
|
|
<el-option v-for="item in chinaRegions" :key="item.province" :label="item.province" :value="item.province" />
|
|
|
</el-select>
|
|
|
<el-select v-model="form.schoolCity" filterable placeholder="请选择城市" :disabled="!form.schoolProvince">
|
|
|
<el-option v-for="city in cityOptions" :key="city" :label="city" :value="city" />
|
|
|
</el-select>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="联系人">
|
|
|
<el-input v-model="form.schoolContacts" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="联系电话">
|
|
|
<el-input v-model="form.schoolContactsMobile" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="联系邮箱">
|
|
|
<el-input v-model="form.schoolContactsEmail" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="学校Logo">
|
|
|
<ImageUpload v-model="form.schoolLogo" class="school-logo-upload" :limit="1" :file-size="2" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="组织模式">
|
|
|
<el-select v-model="productConfig.organizationMode" :disabled="!editingId" style="width: 100%" @change="applyOrganizationPreset">
|
|
|
<el-option label="标准学校:行政班 + 教学班" value="ADMIN_CLASS_ENABLED" />
|
|
|
<el-option label="教师教学班维护名单" value="TEACHING_CLASS_ONLY" />
|
|
|
<el-option label="自定义配置(由下方开关形成)" value="CUSTOM" disabled />
|
|
|
</el-select>
|
|
|
<div class="config-hint">选择预设会同步更新下方开关;已有组织数据会保留,关闭开关仅隐藏菜单和阻止新增编辑。</div>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="院系管理">
|
|
|
<el-switch v-model="productConfig.facultyManagementEnabled" :disabled="!editingId" @change="handleFacultyManagementChange" />
|
|
|
<span class="config-hint">关闭后会同时关闭专业管理和行政班管理。</span>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="专业管理">
|
|
|
<el-switch v-model="productConfig.majorManagementEnabled" :disabled="!editingId || !productConfig.facultyManagementEnabled" @change="handleMajorManagementChange" />
|
|
|
<span class="config-hint">需先启用院系管理;关闭后会同时关闭行政班管理。</span>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="行政班管理">
|
|
|
<el-switch v-model="productConfig.adminClassManagementEnabled" :disabled="!editingId || !productConfig.facultyManagementEnabled || !productConfig.majorManagementEnabled" @change="syncOrganizationModeFromSwitches" />
|
|
|
<span class="config-hint">关闭后班级管理仅保留教学班,教师维护学生名单。</span>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<template #footer>
|
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
|
<el-button type="primary" @click="submit">保存</el-button>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
</section>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import "@/views/schoolAdmin/admin-theme.scss";
|
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
import { addPlatformSchool, deletePlatformSchool, getPlatformSchools, updatePlatformSchool } from "@/api/platformAdmin";
|
|
|
import { getPlatformSchoolProductConfig, updatePlatformSchoolProductConfig } from "@/api/schoolProductConfig";
|
|
|
import { chinaRegions } from "@/utils/chinaRegions";
|
|
|
|
|
|
const query = reactive({ index: 1, size: 10, schoolName: "" });
|
|
|
const rows = ref([]);
|
|
|
const total = ref(0);
|
|
|
const loading = ref(false);
|
|
|
const dialogVisible = ref(false);
|
|
|
const editingId = ref("");
|
|
|
const form = ref({});
|
|
|
const defaultProductConfig = () => ({
|
|
|
organizationMode: "ADMIN_CLASS_ENABLED",
|
|
|
studentRosterOwner: "SCHOOL_ADMIN",
|
|
|
facultyManagementEnabled: true,
|
|
|
majorManagementEnabled: true,
|
|
|
adminClassManagementEnabled: true,
|
|
|
});
|
|
|
const productConfig = ref(defaultProductConfig());
|
|
|
const cityOptions = computed(() => chinaRegions.find((item) => item.province === form.value.schoolProvince)?.cities || []);
|
|
|
|
|
|
const load = async (options = {}) => {
|
|
|
const { showLoading = true } = options;
|
|
|
if (showLoading) {
|
|
|
loading.value = true;
|
|
|
}
|
|
|
try {
|
|
|
const res = await getPlatformSchools(query);
|
|
|
rows.value = res.data?.list || [];
|
|
|
total.value = res.data?.total || 0;
|
|
|
} finally {
|
|
|
if (showLoading) {
|
|
|
loading.value = false;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const reset = () => {
|
|
|
query.index = 1;
|
|
|
query.schoolName = "";
|
|
|
load();
|
|
|
};
|
|
|
|
|
|
const handleSizeChange = () => {
|
|
|
query.index = 1;
|
|
|
load();
|
|
|
};
|
|
|
|
|
|
const openCreate = () => {
|
|
|
editingId.value = "";
|
|
|
form.value = {
|
|
|
schoolName: "",
|
|
|
schoolGrade: "",
|
|
|
schoolProvince: "",
|
|
|
schoolCity: "",
|
|
|
schoolContacts: "",
|
|
|
schoolContactsMobile: "",
|
|
|
schoolContactsEmail: "",
|
|
|
schoolLogo: "",
|
|
|
};
|
|
|
productConfig.value = defaultProductConfig();
|
|
|
dialogVisible.value = true;
|
|
|
};
|
|
|
|
|
|
const openEdit = async (row) => {
|
|
|
editingId.value = row.schoolId;
|
|
|
form.value = { ...row };
|
|
|
const res = await getPlatformSchoolProductConfig(row.schoolId);
|
|
|
productConfig.value = normalizeProductConfig(res.data);
|
|
|
dialogVisible.value = true;
|
|
|
};
|
|
|
|
|
|
const handleProvinceChange = () => {
|
|
|
form.value.schoolCity = "";
|
|
|
};
|
|
|
|
|
|
const normalizeProductConfig = (config) => {
|
|
|
const current = config || defaultProductConfig();
|
|
|
const legacyAdminEnabled = current.organizationMode !== "TEACHING_CLASS_ONLY";
|
|
|
return {
|
|
|
...current,
|
|
|
facultyManagementEnabled: current.facultyManagementEnabled ?? legacyAdminEnabled,
|
|
|
majorManagementEnabled: current.majorManagementEnabled ?? legacyAdminEnabled,
|
|
|
adminClassManagementEnabled: current.adminClassManagementEnabled ?? legacyAdminEnabled,
|
|
|
};
|
|
|
};
|
|
|
|
|
|
const applyOrganizationPreset = (organizationMode) => {
|
|
|
if (organizationMode === "ADMIN_CLASS_ENABLED") {
|
|
|
productConfig.value = { ...productConfig.value, ...defaultProductConfig() };
|
|
|
return;
|
|
|
}
|
|
|
if (organizationMode === "TEACHING_CLASS_ONLY") {
|
|
|
productConfig.value = {
|
|
|
...productConfig.value,
|
|
|
organizationMode: "TEACHING_CLASS_ONLY",
|
|
|
studentRosterOwner: "TEACHER",
|
|
|
facultyManagementEnabled: false,
|
|
|
majorManagementEnabled: false,
|
|
|
adminClassManagementEnabled: false,
|
|
|
};
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const handleFacultyManagementChange = (enabled) => {
|
|
|
if (!enabled) {
|
|
|
productConfig.value.majorManagementEnabled = false;
|
|
|
productConfig.value.adminClassManagementEnabled = false;
|
|
|
}
|
|
|
syncOrganizationModeFromSwitches();
|
|
|
};
|
|
|
|
|
|
const handleMajorManagementChange = (enabled) => {
|
|
|
if (!enabled) {
|
|
|
productConfig.value.adminClassManagementEnabled = false;
|
|
|
}
|
|
|
syncOrganizationModeFromSwitches();
|
|
|
};
|
|
|
|
|
|
const syncOrganizationModeFromSwitches = () => {
|
|
|
const { facultyManagementEnabled, majorManagementEnabled, adminClassManagementEnabled } = productConfig.value;
|
|
|
if (facultyManagementEnabled && majorManagementEnabled && adminClassManagementEnabled) {
|
|
|
productConfig.value.organizationMode = "ADMIN_CLASS_ENABLED";
|
|
|
productConfig.value.studentRosterOwner = "SCHOOL_ADMIN";
|
|
|
} else if (!facultyManagementEnabled && !majorManagementEnabled && !adminClassManagementEnabled) {
|
|
|
productConfig.value.organizationMode = "TEACHING_CLASS_ONLY";
|
|
|
productConfig.value.studentRosterOwner = "TEACHER";
|
|
|
} else {
|
|
|
productConfig.value.organizationMode = "CUSTOM";
|
|
|
productConfig.value.studentRosterOwner = "TEACHER";
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const buildSchoolPayload = () => ({
|
|
|
schoolName: form.value.schoolName,
|
|
|
schoolGrade: form.value.schoolGrade,
|
|
|
schoolProvince: form.value.schoolProvince,
|
|
|
schoolCity: form.value.schoolCity,
|
|
|
schoolContacts: form.value.schoolContacts,
|
|
|
schoolContactsMobile: form.value.schoolContactsMobile,
|
|
|
schoolContactsEmail: form.value.schoolContactsEmail,
|
|
|
schoolLogo: form.value.schoolLogo,
|
|
|
});
|
|
|
|
|
|
const submit = async () => {
|
|
|
const payload = buildSchoolPayload();
|
|
|
if (editingId.value) {
|
|
|
await updatePlatformSchoolProductConfig(editingId.value, {
|
|
|
organizationMode: productConfig.value.organizationMode,
|
|
|
studentRosterOwner: productConfig.value.studentRosterOwner,
|
|
|
facultyManagementEnabled: productConfig.value.facultyManagementEnabled,
|
|
|
majorManagementEnabled: productConfig.value.majorManagementEnabled,
|
|
|
adminClassManagementEnabled: productConfig.value.adminClassManagementEnabled,
|
|
|
});
|
|
|
await updatePlatformSchool(editingId.value, payload);
|
|
|
} else {
|
|
|
await addPlatformSchool(payload);
|
|
|
}
|
|
|
ElMessage.success("保存成功");
|
|
|
dialogVisible.value = false;
|
|
|
load({ showLoading: false });
|
|
|
};
|
|
|
|
|
|
const remove = async (row) => {
|
|
|
await ElMessageBox.confirm("确认删除该学校?学校下存在业务数据时后端会拒绝删除。", "提示", { type: "warning" });
|
|
|
await deletePlatformSchool(row.schoolId);
|
|
|
ElMessage.success("删除成功");
|
|
|
load({ showLoading: false });
|
|
|
};
|
|
|
|
|
|
onMounted(load);
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
.form-inline {
|
|
|
display: grid;
|
|
|
width: 100%;
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
.school-logo-upload {
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.school-logo-upload :deep(.el-upload-list--picture-card .el-upload-list__item),
|
|
|
.school-logo-upload :deep(.el-upload--picture-card) {
|
|
|
width: 96px;
|
|
|
height: 96px;
|
|
|
}
|
|
|
|
|
|
.config-hint {
|
|
|
color: #7a8499;
|
|
|
font-size: 12px;
|
|
|
line-height: 1.6;
|
|
|
margin-top: 6px;
|
|
|
}
|
|
|
|
|
|
@media (max-width: 640px) {
|
|
|
.form-inline {
|
|
|
grid-template-columns: 1fr;
|
|
|
}
|
|
|
}
|
|
|
</style>
|