diff --git a/src/views/cms/SchoolWorkbench.vue b/src/views/cms/SchoolWorkbench.vue index 3a2e098..d783d8d 100644 --- a/src/views/cms/SchoolWorkbench.vue +++ b/src/views/cms/SchoolWorkbench.vue @@ -198,7 +198,7 @@ onMounted(run);

我的学校

-

选择学校进入内容管理;学校与站点由平台管理员在「添加学校」中绑定创建。

+

选择学校进入内容管理;学校由平台管理员接入,院系子站可在「站点管理」自助创建。

diff --git a/src/views/cms/SiteManage.vue b/src/views/cms/SiteManage.vue index 6faefaa..c289777 100644 --- a/src/views/cms/SiteManage.vue +++ b/src/views/cms/SiteManage.vue @@ -32,6 +32,10 @@ const router = useRouter(); /** 超管全局视图(工作台入口带入 scope=all) */ const scopeAll = computed(() => route.query.scope === "all" && store.isSuperAdmin); +/** B1 建站权限拆分:校级(学校上下文内)可自助创建院系子站;超管向导行为不变 */ +const isSchoolAdmin = computed(() => !store.isSuperAdmin && !!store.currentSchool); +const canCreateSite = computed(() => store.isSuperAdmin || isSchoolAdmin.value); + const rows = ref([]); const loading = ref(false); const tableHeight = Utils.useTableHeight({ isOperat: true }); @@ -214,8 +218,9 @@ async function save() { id: form.id, code: form.code, parentSiteId: form.parentSiteId || 0, - schId: form.schId, - schName: form.schName || undefined, + // B1:校级角色隐藏学校信息字段,留空由服务端继承主站(防伪造通道) + schId: isSchoolAdmin.value ? undefined : form.schId, + schName: isSchoolAdmin.value ? undefined : form.schName || undefined, name: form.name, theme: form.theme || undefined, configJson: t ? mergeThemeParamsIntoConfigJson(form.configJson || "", t, themeParams) : form.configJson || undefined, @@ -285,10 +290,10 @@ watch(() => store.currentSchool?.schId, () => run()); 返回学校工作台
-
+
@@ -303,15 +308,15 @@ watch(() => store.currentSchool?.schId, () => run()); - -

院系子站挂在主站下,门户 header 右上出现"专业院系"下拉;层级固定两层。

+

院系子站挂在主站下,门户 header 右上出现"专业院系"下拉;层级固定两层。{{ isSchoolAdmin ? "校级角色仅可在本校主站之间改挂。" : "" }}

- + - + @@ -340,8 +345,8 @@ watch(() => store.currentSchool?.schId, () => run()); - - + + diff --git a/src/views/cms/SiteWizard.vue b/src/views/cms/SiteWizard.vue index a13087a..5d247b0 100644 --- a/src/views/cms/SiteWizard.vue +++ b/src/views/cms/SiteWizard.vue @@ -17,6 +17,8 @@ import SiteConfigForm from "@/views/cms/components/SiteConfigForm.vue"; const props = defineProps<{ visible: boolean; sites: SiteVo[]; + /** B1 建站权限拆分:校级锁定在本校主站下建院系子站(上级禁改、学校信息由服务端继承) */ + lockParentId?: number; }>(); const emit = defineEmits<{ @@ -51,7 +53,12 @@ const canPreview = computed(() => !!sourceSiteCode.value && !!themeName.value); const previewTick = ref(0); const previewParams = ref({}); -const parentOptions = computed(() => props.sites.filter(s => !s.parentSiteId)); +/** 锁定模式:上级仅本校主站;否则全部顶层站可选 */ +const parentOptions = computed(() => + props.lockParentId + ? props.sites.filter(s => s.id === props.lockParentId && !s.parentSiteId) + : props.sites.filter(s => !s.parentSiteId) +); function debouncePreview() { previewParams.value = { ...themeParams.value }; @@ -71,7 +78,7 @@ watch( async v => { if (!v) return; step.value = 1; - Object.assign(form, { code: "", parentSiteId: undefined, schId: undefined, schName: "", name: "", status: 1, configJson: "" }); + Object.assign(form, { code: "", parentSiteId: props.lockParentId, schId: undefined, schName: "", name: "", status: 1, configJson: "" }); sourceSiteCode.value = sourceSites.value[0]?.code || ""; if (!themes.value.length) await loadThemes(); themeName.value = "default"; @@ -128,8 +135,9 @@ async function createSite() { .save({ code: form.code, parentSiteId: form.parentSiteId || 0, - schId: form.schId, - schName: form.schName || undefined, + // B1:校级锁定模式学校信息留空,服务端校验后继承主站(防伪造) + schId: props.lockParentId ? undefined : form.schId, + schName: props.lockParentId ? undefined : form.schName || undefined, name: form.name, theme: themeName.value, configJson, @@ -148,7 +156,7 @@ async function createSite() {