feat(B1): 校级建站入口-新建院系子站(向导锁定本校主站)+学校信息服务端继承
- SiteManage: 新建按钮校级显示"新建院系子站";编辑弹窗校级隐藏schId/schName(payload留空服务端继承) - SiteWizard: lockParentId 锁定上级为本校主站禁改 - SchoolWorkbench: 副文案改自助创建口径 - vitest 24/24 绿 + build 成功
This commit is contained in:
@@ -198,7 +198,7 @@ onMounted(run);
|
||||
<div class="wb-body">
|
||||
<div class="wb-title">
|
||||
<h3>我的学校</h3>
|
||||
<p class="wb-sub">选择学校进入内容管理;学校与站点由平台管理员在「添加学校」中绑定创建。</p>
|
||||
<p class="wb-sub">选择学校进入内容管理;学校由平台管理员接入,院系子站可在「站点管理」自助创建。</p>
|
||||
</div>
|
||||
|
||||
<Spin v-if="loading" size="large" fix />
|
||||
|
||||
@@ -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<SiteVo[]>([]);
|
||||
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());
|
||||
<a href="javascript:void(0);" @click="goBackWorkbench">返回学校工作台</a>
|
||||
</Alert>
|
||||
</div>
|
||||
<div class="fix">
|
||||
<div class="fix" v-if="canCreateSite">
|
||||
<Button class="fl" type="primary" size="large" @click="openWizard">
|
||||
<Icon type="ios-add" />
|
||||
新建站点(向导)
|
||||
{{ isSchoolAdmin ? "新建院系子站" : "新建站点(向导)" }}
|
||||
</Button>
|
||||
</div>
|
||||
<Table :columns="columns" :data="rows" :height="tableHeight" :loading="loading" no-data-text="暂无站点" />
|
||||
@@ -303,15 +308,15 @@ watch(() => store.currentSchool?.schId, () => run());
|
||||
<Input v-model="form.name" :maxlength="128" placeholder="如 XX学校门户网站" />
|
||||
</FormItem>
|
||||
<FormItem label="上级站点">
|
||||
<Select v-model="form.parentSiteId" clearable placeholder="空=顶层校站点;选主站则为院系子站" style="width: 320px">
|
||||
<Select v-model="form.parentSiteId" :clearable="!isSchoolAdmin" placeholder="空=顶层校站点;选主站则为院系子站" style="width: 320px">
|
||||
<Option v-for="s in parentOptions" :key="s.id" :value="s.id">{{ s.name }}({{ s.code }})</Option>
|
||||
</Select>
|
||||
<p class="form-tip">院系子站挂在主站下,门户 header 右上出现"专业院系"下拉;层级固定两层。</p>
|
||||
<p class="form-tip">院系子站挂在主站下,门户 header 右上出现"专业院系"下拉;层级固定两层。{{ isSchoolAdmin ? "校级角色仅可在本校主站之间改挂。" : "" }}</p>
|
||||
</FormItem>
|
||||
<FormItem label="学校ID">
|
||||
<FormItem v-if="store.isSuperAdmin" label="学校ID">
|
||||
<InputNumber v-model="form.schId" :min="1" placeholder="UserBase sys_group.id" style="width: 200px" />
|
||||
</FormItem>
|
||||
<FormItem label="学校名称">
|
||||
<FormItem v-if="store.isSuperAdmin" label="学校名称">
|
||||
<Input v-model="form.schName" :maxlength="128" />
|
||||
</FormItem>
|
||||
<FormItem label="皮肤包">
|
||||
@@ -340,8 +345,8 @@ watch(() => store.currentSchool?.schId, () => run());
|
||||
<ThemePreviewFrame v-if="previewVisible && editTheme" :site-code="form.code" :theme="form.theme" :theme-params="editThemeParams" />
|
||||
</Modal>
|
||||
|
||||
<!-- 新建站点三步向导 -->
|
||||
<SiteWizard v-model:visible="wizardVisible" :sites="rows" @created="onWizardCreated" />
|
||||
<!-- 新建站点三步向导(B1:校级锁定为本校主站下建院系子站) -->
|
||||
<SiteWizard v-model:visible="wizardVisible" :sites="rows" :lock-parent-id="isSchoolAdmin ? store.currentSchool?.mainSiteId : undefined" @created="onWizardCreated" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -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<FormModelValue>({});
|
||||
|
||||
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() {
|
||||
<template>
|
||||
<Modal
|
||||
:model-value="visible"
|
||||
:title="`新建站点向导 · 第 ${step} / 3 步`"
|
||||
:title="`${props.lockParentId ? '新建院系子站' : '新建站点'}向导 · 第 ${step} / 3 步`"
|
||||
:mask-closable="false"
|
||||
width="980px"
|
||||
@update:model-value="emit('update:visible', $event)"
|
||||
@@ -200,18 +208,19 @@ async function createSite() {
|
||||
<Input v-model="form.name" :maxlength="128" placeholder="如 XX学校门户网站" style="width: 320px" />
|
||||
</FormItem>
|
||||
<FormItem label="上级站点">
|
||||
<Select v-model="form.parentSiteId" clearable placeholder="空=顶层校站点;选主站则为院系子站" style="width: 320px">
|
||||
<Select v-model="form.parentSiteId" :disabled="!!props.lockParentId" placeholder="空=顶层校站点;选主站则为院系子站" style="width: 320px">
|
||||
<Option v-for="s in parentOptions" :key="s.id" :value="s.id">{{ s.name }}({{ s.code }})</Option>
|
||||
</Select>
|
||||
<div v-if="props.lockParentId" class="pbu-tip">校级角色仅可在本校主站下创建院系子站,学校信息自动继承主站。</div>
|
||||
</FormItem>
|
||||
<FormItem label="学校ID">
|
||||
<FormItem v-if="!props.lockParentId" label="学校ID">
|
||||
<InputNumber v-model="form.schId" :min="1" placeholder="UserBase sys_group.id" style="width: 200px" />
|
||||
<!-- B-8:顶层站 schId 必填(校级角色按此匹配管理权限);院系子站留空自动继承主站 -->
|
||||
<div class="pbu-tip">
|
||||
顶层站点必填(否则建成即校级角色不可管理);选了上级站点的院系子站可留空,自动继承主站。
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="学校名称">
|
||||
<FormItem v-if="!props.lockParentId" label="学校名称">
|
||||
<Input v-model="form.schName" :maxlength="128" style="width: 320px" />
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
|
||||
Reference in New Issue
Block a user