用户验收反馈三处: 1. 左侧锚点导航不固定——根因 .base-wrap-main .main-container 的 legacy overflow:hidden 使 sticky 相对不滚动的隐藏滚动盒定位失效(实测滚动 600px 导航 top=-387);本页运行时改写为 visible、离开还原,修复后滚动 800px 导航稳定停在 top:72px。窄屏(≤1080)导航转横排胶囊。 2. 皮肤颜色参数竖排长蛇(真实主题 12 个色参数 = 12 行)——ThemeParamForm 重排:color 参数转 150px 起步 auto-fill 色卡网格(宽屏一行 4~5 张, 色卡含取色器+名称+HEX),select/image/text 转两列行式;非法值红框提示。 3. 「换肤/改参数保存后门户立即生效」提示框样式突兀且与按钮拥挤——移除 皮肤区内联 form-hint,并入卡片 footer 的 card-hint(与基本信息卡一致)。 整页配套:分区卡 10px 圆角+柔和阴影+品牌竖条标题、锚点导航品牌指示条、 footer hint 自适应换行。 mock THEMES 补 poly-blue/agri-forest/jade-normal 三套新皮肤条目。 vitest 147/147 绿;vite build 通过。
This commit is contained in:
@@ -131,6 +131,48 @@ const THEMES: MockTheme[] = [
|
|||||||
{ key: "accent", cssVar: "--cz-accent", label: "点缀青绿", type: "color", defaultValue: "#2b9c8f" },
|
{ key: "accent", cssVar: "--cz-accent", label: "点缀青绿", type: "color", defaultValue: "#2b9c8f" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "poly-blue",
|
||||||
|
title: "理工蓝(poly-blue)",
|
||||||
|
description: "深宝蓝+活力橙的理工院校风:受众品牌行 + 白底吸顶导航 + 双栏要闻 + 日期方块 + 快捷通道宫格(参考浙江理工大学官网)。",
|
||||||
|
version: "1.0.0",
|
||||||
|
author: "yunhai",
|
||||||
|
bannerSize: "1920x560",
|
||||||
|
screenshotUrl: "/api/theme/poly-blue/asset/screenshot.png",
|
||||||
|
params: [
|
||||||
|
{ key: "primary", cssVar: "--pb-primary", label: "主色", type: "color", defaultValue: "#0558A5" },
|
||||||
|
{ key: "primaryDark", cssVar: "--pb-primary-dark", label: "主色加深", type: "color", defaultValue: "#124489" },
|
||||||
|
{ key: "accent", cssVar: "--pb-accent", label: "活力橙", type: "color", defaultValue: "#FF7B00" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "agri-forest",
|
||||||
|
title: "农林绿(agri-forest)",
|
||||||
|
description: "墨绿+麦穗金的农林院校风:白页头 + 墨绿通栏导航 + SVG 图标栏目标题 + 日期方块 + 专题缩略卡(参考信阳农林学院官网)。",
|
||||||
|
version: "1.0.0",
|
||||||
|
author: "yunhai",
|
||||||
|
bannerSize: "1920x560",
|
||||||
|
screenshotUrl: "/api/theme/agri-forest/asset/screenshot.png",
|
||||||
|
params: [
|
||||||
|
{ key: "primary", cssVar: "--af-primary", label: "主色", type: "color", defaultValue: "#1C6E19" },
|
||||||
|
{ key: "primaryDark", cssVar: "--af-primary-dark", label: "主色加深", type: "color", defaultValue: "#14510F" },
|
||||||
|
{ key: "accent", cssVar: "--af-accent", label: "麦穗金", type: "color", defaultValue: "#C8A45C" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "jade-normal",
|
||||||
|
title: "师大青(jade-normal)",
|
||||||
|
description: "翡翠青+暖橙点缀的师范院校风:橙色日期徽标 + 快捷通道图标宫格 + 融媒行(参考信阳师范大学官网)。",
|
||||||
|
version: "1.0.0",
|
||||||
|
author: "yunhai",
|
||||||
|
bannerSize: "1920x560",
|
||||||
|
screenshotUrl: "/api/theme/jade-normal/asset/screenshot.png",
|
||||||
|
params: [
|
||||||
|
{ key: "primary", cssVar: "--jn-primary", label: "主色", type: "color", defaultValue: "#008D3F" },
|
||||||
|
{ key: "primaryDark", cssVar: "--jn-primary-dark", label: "主色加深", type: "color", defaultValue: "#04682E" },
|
||||||
|
{ key: "accent", cssVar: "--jn-accent", label: "暖橙", type: "color", defaultValue: "#F18D00" },
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function themeByName(name: string): MockTheme | undefined {
|
function themeByName(name: string): MockTheme | undefined {
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import { effectiveValue, invalidParamKeys, FormModelValue } from "@/utils/themeP
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 主题参数微调表单(方案 §6.3):按 theme.json params schema 动态生成。
|
* 主题参数微调表单(方案 §6.3):按 theme.json params schema 动态生成。
|
||||||
* color→ColorPicker、select→Select、image→Input(手填 /cms/upload/ 路径,走附件上传后回填)、
|
* 2026-09-20 布局重排(用户反馈"颜色设置竖着太长"):
|
||||||
* text→Input。父级 v-model 绑定 FormModelValue(声明过的 key,值已兜底为默认)。
|
* - color 参数 → 色卡网格(横排自动换行,auto-fill 150px;真实主题 12 个色参数不再拉出 12 行长蛇);
|
||||||
|
* - select/image/text → 两列行式(label + 控件同行);
|
||||||
|
* - 非法值红框 + 行内提示;父级 v-model 绑定 FormModelValue(声明过的 key,值已兜底为默认)。
|
||||||
*/
|
*/
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
theme?: ThemeVo;
|
theme?: ThemeVo;
|
||||||
@@ -19,6 +21,8 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const themeName = computed(() => props.theme?.title || props.theme?.name || "");
|
const themeName = computed(() => props.theme?.title || props.theme?.name || "");
|
||||||
const params = computed(() => props.theme?.params || []);
|
const params = computed(() => props.theme?.params || []);
|
||||||
|
const colorParams = computed(() => params.value.filter(p => p.type === "color"));
|
||||||
|
const otherParams = computed(() => params.value.filter(p => p.type !== "color"));
|
||||||
const badKeys = computed(() =>
|
const badKeys = computed(() =>
|
||||||
props.theme ? invalidParamKeys(props.theme, props.modelValue) : []
|
props.theme ? invalidParamKeys(props.theme, props.modelValue) : []
|
||||||
);
|
);
|
||||||
@@ -38,71 +42,186 @@ function isBad(key: string): boolean {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="!theme" class="empty-tip">请先选择皮肤包</div>
|
<div v-if="!theme" class="empty-tip">请先选择皮肤包</div>
|
||||||
<Form v-else :label-width="90" class="theme-param-form">
|
<div v-else class="theme-param-form">
|
||||||
<div class="param-head">
|
<div class="param-head">
|
||||||
参数微调 · {{ themeName }}
|
<span class="param-head-title">参数微调 · {{ themeName }}</span>
|
||||||
<span v-if="badKeys.length" class="param-warn">
|
<span v-if="badKeys.length" class="param-warn">
|
||||||
有 {{ badKeys.length }} 个非法值未生效(将回退皮肤默认)
|
{{ badKeys.length }} 个非法值未生效(保存时将回退皮肤默认)
|
||||||
</span>
|
</span>
|
||||||
|
<span class="param-head-tip">点击色卡可修改;保存后门户立即生效</span>
|
||||||
</div>
|
</div>
|
||||||
<FormItem v-for="p in params" :key="p.key" :label="p.label">
|
|
||||||
<!-- color:色板 -->
|
<!-- color:色卡网格(横排) -->
|
||||||
<ColorPicker
|
<div v-if="colorParams.length" class="param-grid">
|
||||||
v-if="p.type === 'color'"
|
<div
|
||||||
:model-value="displayValue(p.key)"
|
v-for="p in colorParams"
|
||||||
recommend
|
:key="p.key"
|
||||||
@on-change="(c: string) => setValue(p.key, c)"
|
class="param-chip"
|
||||||
/>
|
:class="{ bad: isBad(p.key) }"
|
||||||
<!-- select:下拉 -->
|
:title="p.key"
|
||||||
<Select
|
|
||||||
v-else-if="p.type === 'select'"
|
|
||||||
:model-value="displayValue(p.key)"
|
|
||||||
style="width: 260px"
|
|
||||||
@on-change="(v: string) => setValue(p.key, v)"
|
|
||||||
>
|
>
|
||||||
<Option v-for="o in p.options" :key="o.value" :value="o.value">{{ o.label }}</Option>
|
<ColorPicker
|
||||||
</Select>
|
:model-value="displayValue(p.key)"
|
||||||
<!-- image:附件路径(上传后回填 /cms/upload/**) -->
|
recommend
|
||||||
<Input
|
@on-change="(c: string) => setValue(p.key, c)"
|
||||||
v-else-if="p.type === 'image'"
|
/>
|
||||||
:model-value="displayValue(p.key)"
|
<span class="chip-name">{{ p.label }}</span>
|
||||||
placeholder="/cms/upload/cms/... (仅接受 /cms/upload/** 路径)"
|
<span class="chip-hex">{{ displayValue(p.key) }}</span>
|
||||||
style="width: 320px"
|
</div>
|
||||||
@on-change="(v: string) => setValue(p.key, v)"
|
</div>
|
||||||
/>
|
|
||||||
<!-- text:短文本 -->
|
<!-- select / image / text:两列行式 -->
|
||||||
<Input
|
<div v-if="otherParams.length" class="param-rows">
|
||||||
v-else
|
<div v-for="p in otherParams" :key="p.key" class="param-row" :class="{ bad: isBad(p.key) }">
|
||||||
:model-value="displayValue(p.key)"
|
<label class="row-label">{{ p.label }}</label>
|
||||||
:maxlength="256"
|
<div class="row-control">
|
||||||
style="width: 320px"
|
<Select
|
||||||
@on-change="(v: string) => setValue(p.key, v)"
|
v-if="p.type === 'select'"
|
||||||
/>
|
:model-value="displayValue(p.key)"
|
||||||
<span v-if="isBad(p.key)" class="bad-mark">当前值非法({{ p.type }} 类型校验失败)</span>
|
size="small"
|
||||||
</FormItem>
|
transfer
|
||||||
</Form>
|
@on-change="(v: string) => setValue(p.key, v)"
|
||||||
|
>
|
||||||
|
<Option v-for="o in p.options" :key="o.value" :value="o.value">{{ o.label }}</Option>
|
||||||
|
</Select>
|
||||||
|
<Input
|
||||||
|
v-else-if="p.type === 'image'"
|
||||||
|
:model-value="displayValue(p.key)"
|
||||||
|
size="small"
|
||||||
|
placeholder="/cms/upload/cms/... (仅接受 /cms/upload/** 路径)"
|
||||||
|
@on-change="(v: string) => setValue(p.key, v)"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
v-else
|
||||||
|
:model-value="displayValue(p.key)"
|
||||||
|
size="small"
|
||||||
|
:maxlength="256"
|
||||||
|
@on-change="(v: string) => setValue(p.key, v)"
|
||||||
|
/>
|
||||||
|
<span v-if="isBad(p.key)" class="bad-mark">非法值({{ p.type }} 校验失败)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.empty-tip {
|
.empty-tip {
|
||||||
color: #999;
|
color: #8a93a6;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
}
|
}
|
||||||
.param-head {
|
.theme-param-form {
|
||||||
font-size: 13px;
|
margin-top: 10px;
|
||||||
font-weight: 600;
|
|
||||||
color: #666;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
.param-warn {
|
.param-head {
|
||||||
color: #ed4014;
|
display: flex;
|
||||||
font-weight: 400;
|
align-items: baseline;
|
||||||
margin-left: 8px;
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
.param-head-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1e2635;
|
||||||
|
}
|
||||||
|
.param-head-tip {
|
||||||
|
color: #8a93a6;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.param-warn {
|
||||||
|
color: #e54d42;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* color 色卡网格:横排自动换行(150px 起步,宽屏一行 4~5 张) */
|
||||||
|
.param-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.param-chip {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: 1px solid #e9edf5;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fff;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
&:hover {
|
||||||
|
border-color: #b9c8f7;
|
||||||
|
box-shadow: 0 4px 12px -8px rgba(87, 122, 251, 0.45);
|
||||||
|
}
|
||||||
|
&.bad {
|
||||||
|
border-color: #e54d42;
|
||||||
|
}
|
||||||
|
.chip-name {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #1e2635;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.chip-hex {
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: Consolas, Menlo, monospace;
|
||||||
|
color: #8a93a6;
|
||||||
|
}
|
||||||
|
/* ColorPicker 触发器整条拉宽成色条 */
|
||||||
|
:deep(.ivu-color-picker) {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
:deep(.ivu-color-picker .ivu-input-wrapper) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
:deep(.ivu-color-picker .ivu-input) {
|
||||||
|
width: 100%;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select/image/text:两列行式 */
|
||||||
|
.param-rows {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
||||||
|
gap: 8px 18px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
.param-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
&.bad .row-label {
|
||||||
|
color: #e54d42;
|
||||||
|
}
|
||||||
|
.row-label {
|
||||||
|
flex: none;
|
||||||
|
width: 76px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #1e2635;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.row-control {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
.ivu-select,
|
||||||
|
.ivu-input-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.bad-mark {
|
.bad-mark {
|
||||||
color: #ed4014;
|
color: #e54d42;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-left: 8px;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -126,10 +126,32 @@ onMounted(async () => {
|
|||||||
basic.parentSiteId = lockParentId.value;
|
basic.parentSiteId = lockParentId.value;
|
||||||
}
|
}
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
patchAncestorOverflow();
|
||||||
nextTick(setupAnchorObserver);
|
nextTick(setupAnchorObserver);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => observer?.disconnect());
|
/**
|
||||||
|
* 左侧锚点导航 sticky 的生效前提:布局遗留的 .main-container 带 overflow:hidden
|
||||||
|
* (清浮动时代产物),sticky 会改为相对这个"自身不滚动的隐藏滚动盒"定位 → 表现为
|
||||||
|
* 跟随内容滚走(2026-09-20 实测滚动 600px 导航 top=-387)。本页内容为 flex/常规流,
|
||||||
|
* 不依赖该 overflow 裁剪浮动,故进入本页时运行时改写、离开时还原,零全局影响。
|
||||||
|
*/
|
||||||
|
let patchedContainer: HTMLElement | null = null;
|
||||||
|
function patchAncestorOverflow() {
|
||||||
|
const el = document.querySelector<HTMLElement>(".base-wrap-main .main-container");
|
||||||
|
if (el && getComputedStyle(el).overflow === "hidden") {
|
||||||
|
patchedContainer = el;
|
||||||
|
el.style.overflow = "visible";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
observer?.disconnect();
|
||||||
|
if (patchedContainer) {
|
||||||
|
patchedContainer.style.overflow = "";
|
||||||
|
patchedContainer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
async function loadSites() {
|
async function loadSites() {
|
||||||
sites.value = (await siteApi.list().send()) || [];
|
sites.value = (await siteApi.list().send()) || [];
|
||||||
@@ -458,7 +480,6 @@ watch(() => store.currentSchool?.schId, () => loadSites());
|
|||||||
<ThemePicker :themes="themes" :model-value="theme" @update:model-value="pickTheme" />
|
<ThemePicker :themes="themes" :model-value="theme" @update:model-value="pickTheme" />
|
||||||
<Button size="small" class="preview-btn" :disabled="!editTheme" @click="openPreview">预览本皮肤</Button>
|
<Button size="small" class="preview-btn" :disabled="!editTheme" @click="openPreview">预览本皮肤</Button>
|
||||||
<ThemeParamForm :theme="editTheme" v-model="themeParams" />
|
<ThemeParamForm :theme="editTheme" v-model="themeParams" />
|
||||||
<p class="form-hint">换肤/改参数保存后门户立即生效(缓存已自动失效)。</p>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- B3 自定义样式(config_json.custom_css,服务端黑名单强校验) -->
|
<!-- B3 自定义样式(config_json.custom_css,服务端黑名单强校验) -->
|
||||||
<Collapse class="css-collapse">
|
<Collapse class="css-collapse">
|
||||||
@@ -480,7 +501,7 @@ watch(() => store.currentSchool?.schId, () => loadSites());
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<Button type="primary" :loading="saving.theme" @click="saveTheme">仅保存皮肤与外观</Button>
|
<Button type="primary" :loading="saving.theme" @click="saveTheme">仅保存皮肤与外观</Button>
|
||||||
<span class="card-hint">仅保存本分区;其他分区未保存的修改仍在页面上,下次任一分区保存会一并带上</span>
|
<span class="card-hint">换肤/改参数保存后门户立即生效(缓存已自动失效);其他分区未保存的修改仍在页面上,下次任一分区保存会一并带上</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -603,32 +624,48 @@ watch(() => store.currentSchool?.schId, () => loadSites());
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
.ss-nav {
|
.ss-nav {
|
||||||
width: 180px;
|
width: 184px;
|
||||||
flex: none;
|
flex: none;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 84px;
|
top: 72px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 2px;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px solid #e9edf5;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 14px 30px -22px rgba(16, 24, 40, 0.4);
|
||||||
.ss-nav-item {
|
.ss-nav-item {
|
||||||
padding: 8px 12px;
|
position: relative;
|
||||||
border-radius: 6px;
|
padding: 8px 10px 8px 14px;
|
||||||
|
border-radius: 7px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #f0faff;
|
background: #f0f4ff;
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
background: #e8f4ff;
|
background: #eef2ff;
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 4px;
|
||||||
|
top: 10px;
|
||||||
|
bottom: 10px;
|
||||||
|
width: 3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #577afb;
|
||||||
|
}
|
||||||
.ss-nav-title {
|
.ss-nav-title {
|
||||||
color: #2d8cf0;
|
color: #4264e4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ss-nav-title {
|
.ss-nav-title {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #515a6e;
|
color: #1e2635;
|
||||||
}
|
}
|
||||||
.ss-nav-lock {
|
.ss-nav-lock {
|
||||||
color: #c5c8ce;
|
color: #c5c8ce;
|
||||||
@@ -636,12 +673,33 @@ watch(() => store.currentSchool?.schId, () => loadSites());
|
|||||||
}
|
}
|
||||||
.ss-nav-desc {
|
.ss-nav-desc {
|
||||||
display: block;
|
display: block;
|
||||||
color: #999;
|
color: #8a93a6;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@media (max-width: 1080px) {
|
||||||
|
.ss-layout {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.ss-nav {
|
||||||
|
position: static;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
.ss-nav-item {
|
||||||
|
flex: none;
|
||||||
|
.ss-nav-desc {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.active::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.ss-cards {
|
.ss-cards {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@@ -650,11 +708,12 @@ watch(() => store.currentSchool?.schId, () => loadSites());
|
|||||||
gap: 14px;
|
gap: 14px;
|
||||||
}
|
}
|
||||||
.setting-card {
|
.setting-card {
|
||||||
border: 1px solid #e8eaec;
|
border: 1px solid #e9edf5;
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 16px 18px;
|
padding: 18px 20px;
|
||||||
scroll-margin-top: 76px;
|
scroll-margin-top: 84px;
|
||||||
|
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
|
||||||
&.locked {
|
&.locked {
|
||||||
.card-body {
|
.card-body {
|
||||||
opacity: 0.55;
|
opacity: 0.55;
|
||||||
@@ -669,13 +728,25 @@ watch(() => store.currentSchool?.schId, () => loadSites());
|
|||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: 1px solid #f0f2f5;
|
border-bottom: 1px solid #f0f2f5;
|
||||||
.card-title {
|
.card-title {
|
||||||
|
position: relative;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #17233d;
|
color: #1e2635;
|
||||||
|
padding-left: 10px;
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 3px;
|
||||||
|
bottom: 3px;
|
||||||
|
width: 3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #577afb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.card-subtitle {
|
.card-subtitle {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #999;
|
color: #8a93a6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.card-footer {
|
.card-footer {
|
||||||
@@ -686,9 +757,11 @@ watch(() => store.currentSchool?.schId, () => loadSites());
|
|||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid #f0f2f5;
|
border-top: 1px solid #f0f2f5;
|
||||||
.card-hint {
|
.card-hint {
|
||||||
color: #999;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
color: #8a93a6;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.5;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ss-lock-tip {
|
.ss-lock-tip {
|
||||||
|
|||||||
Reference in New Issue
Block a user