feat(settings): 五个 pane 对接真实数据(零新接口)——profile 读 store、改密登出流程、头像直传、logo/wallpaper 管理列表
- profile:姓名/工号(暂以登录账号展示,接口无独立工号字段)/部门/手机/邮箱改读 store.userInfo(无值显示 -),保存按钮占位 disabled(接口待 UserBase 支持本人自助修改,拍板搁置);头像行 v-real-img 真实图 - password:非空/一致性/不同旧密码/长度校验 + BaseApi.updatePassword,成功提示后 1500ms 登出跳 CAS(确认登出流程照抄 UserInfoModal L162-183,不自创) - avatar:Upload 直传移植 UserInfoModal(action=/api/avatarUpload、accept/format/max-size 20480/with-credentials/网关头/成功写 store.profilePicture 照抄);预设色块保留、「使用默认头像」disabled 占位 - logo:getSchLogoManageList 管理列表(不带 schId,按登录人归属校返回;超管按机构切换走 sys pane)+ 直传 /api/logoUpload + deleteLogoById + 「保存设置」走 saveSchLogo(schId 后端按登录人推断) - wallpaper:getSchWallpaperManageList + 直传 + deleteWallById + 「应用壁纸」采用 checkWallpaper 个人壁纸语义(与 Header 壁纸弹窗现状一致,执行报告写明;校级默认壁纸保存接口不存在,不发明新语义) - BaseApi 补 saveSchLogo 封装(复用已有后端接口);sidebar/statset/sys/backend/noperm 五个不动 pane 模板 diff 为空;navGroups/ADMIN_PANES 权限结构未动
This commit is contained in:
@@ -172,6 +172,15 @@ class Base extends Abstract {
|
||||
return this.postRequest({ url, data: { oldPassword, password } });
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存校级 LOGO(schId 后端按登录人推断:主学校→归属组→0 平台默认)
|
||||
* @memberof Basic
|
||||
*/
|
||||
saveSchLogo(logoUrl: string) {
|
||||
const url = path + "/saveSchLogo";
|
||||
return this.postRequest({ url, params: { logoUrl } });
|
||||
}
|
||||
|
||||
savUserRole(info: any) {
|
||||
const url = path + "/user/savUserRole";
|
||||
return this.postRequest({ url, data: info as any });
|
||||
|
||||
+272
-68
@@ -49,28 +49,29 @@
|
||||
<div class="form-row">
|
||||
<span class="lb">头像</span>
|
||||
<div class="ctl">
|
||||
<div class="avatar-now avatar-sm">张</div>
|
||||
<img class="avatar-img avatar-img-sm" :src="requireImg('user-avatar-default.png')"
|
||||
v-real-img="store.userInfo.profilePicture" alt="" />
|
||||
<button class="btn ghost sm" @click="setPane('avatar')">更换头像</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<span class="lb">姓名</span>
|
||||
<div class="ctl">
|
||||
<input class="inp" value="张明" disabled />
|
||||
<input class="inp" :value="profileView.name" disabled />
|
||||
<span class="hint">由学校统一维护</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<span class="lb">工号</span>
|
||||
<div class="ctl">
|
||||
<input class="inp" value="T20240315" disabled />
|
||||
<input class="inp" :value="profileView.account" disabled />
|
||||
<span class="hint">由学校统一维护</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<span class="lb">所属部门</span>
|
||||
<div class="ctl">
|
||||
<input class="inp" value="教务处 / 教研组" disabled />
|
||||
<input class="inp" :value="profileView.deptName" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@@ -87,7 +88,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane-foot">
|
||||
<button class="btn primary">保存修改</button>
|
||||
<!-- 保存占位:接口待 UserBase 支持本人自助修改,本轮不做(拍板结论) -->
|
||||
<button class="btn primary" disabled title="接口待 UserBase 支持本人自助修改,本轮暂不可用">保存修改</button>
|
||||
<button class="btn plain" @click="resetProfileForm">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -120,7 +122,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane-foot">
|
||||
<button class="btn primary">确认修改</button>
|
||||
<button class="btn primary" :disabled="passwordSubmitting" @click="onUpdatePassword">确认修改</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -134,13 +136,22 @@
|
||||
<h4>当前头像</h4>
|
||||
<div class="avatar-pad">
|
||||
<div class="avatar-box">
|
||||
<div class="avatar-now">张</div>
|
||||
<img class="avatar-img" :src="requireImg('user-avatar-default.png')"
|
||||
v-real-img="store.userInfo.profilePicture" alt="" />
|
||||
<div class="avatar-ops">
|
||||
<div class="avatar-btns">
|
||||
<button class="btn primary sm">上传新头像</button>
|
||||
<button class="btn plain sm">使用默认头像</button>
|
||||
<!-- 直传逻辑移植 UserInfoModal:action/headers/校验/成功回调照抄 -->
|
||||
<Upload :on-success="uploadAvatarSuccess" :on-exceeded-size="onAvatarSizeExceeded"
|
||||
:on-format-error="onAvatarFormatError" :show-upload-list="false"
|
||||
:action="$conf.serviceHost + '/api/avatarUpload'"
|
||||
accept=".jpg,.jpeg,.png,.gif,.webp" :format="['jpg', 'jpeg', 'png', 'gif', 'webp']"
|
||||
:max-size="20480" :with-credentials="true" :headers="uploadHeaders">
|
||||
<button class="btn primary sm">上传新头像</button>
|
||||
</Upload>
|
||||
<!-- 存储方案本轮不做(拍板),保持占位 -->
|
||||
<button class="btn plain sm" disabled title="存储方案本轮不做">使用默认头像</button>
|
||||
</div>
|
||||
<span class="tip">上传后立即生效,全站同步展示。</span>
|
||||
<span class="tip">上传后立即生效,全站同步展示。支持 JPG / PNG / GIF / WebP,≤ 20MB。</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,25 +181,31 @@
|
||||
<div class="sec-card">
|
||||
<h4>当前 LOGO</h4>
|
||||
<div class="logo-grid">
|
||||
<div v-if="logoManageList.length === 0" class="logo-empty">暂无 LOGO,请先上传</div>
|
||||
<div
|
||||
v-for="(l, i) in logoList"
|
||||
:key="i"
|
||||
:class="['logo-item', { sel: logoSel === i }]"
|
||||
@click="logoSel = i"
|
||||
v-for="l in logoManageList"
|
||||
:key="l.id"
|
||||
:class="['logo-item', { sel: logoSelUrl === l.url }]"
|
||||
@click="logoSelUrl = l.url"
|
||||
>
|
||||
<span class="mk">{{ l.marks }}</span>{{ l.name }}
|
||||
<img :src="l.url" alt="" />
|
||||
<i v-if="l.isEdit" class="del" title="删除" @click.stop="onDeleteLogo(l)">×</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row form-row--last form-row--top">
|
||||
<span class="lb">上传 LOGO</span>
|
||||
<div class="ctl">
|
||||
<button class="btn ghost sm">选择文件</button>
|
||||
<Upload :on-success="onLogoUploaded" :show-upload-list="false" :action="logoUploadAction"
|
||||
accept="image/jpeg, image/jpg, image/png, image/gif, image/webp"
|
||||
:with-credentials="true" :headers="uploadHeaders">
|
||||
<button class="btn ghost sm">选择文件</button>
|
||||
</Upload>
|
||||
<span class="hint">建议 PNG 透明底,高度 ≥ 64px,≤ 1MB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane-foot">
|
||||
<button class="btn primary">保存设置</button>
|
||||
<button class="btn primary" :disabled="logoSaving" @click="onSaveLogo">保存设置</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -201,24 +218,33 @@
|
||||
<div class="sec-card">
|
||||
<h4>系统壁纸</h4>
|
||||
<div class="wall-grid">
|
||||
<div v-if="wallpaperManageList.length === 0" class="logo-empty">暂无壁纸,请先上传</div>
|
||||
<div
|
||||
v-for="(w, i) in wallpaperList"
|
||||
:key="i"
|
||||
:class="['wall-item', { sel: wallSel === i }]"
|
||||
:style="{ background: w }"
|
||||
@click="wallSel = i"
|
||||
v-for="w in wallpaperManageList"
|
||||
:key="w.id"
|
||||
:class="['wall-item', { sel: wallSelUrl === w.url }]"
|
||||
:style="{ background: 'center / cover no-repeat url(' + w.url + ')' }"
|
||||
@click="wallSelUrl = w.url"
|
||||
>
|
||||
<i v-if="w.isEdit" class="del" title="删除" @click.stop="onDeleteWallpaper(w)">×</i>
|
||||
<i class="tick">✓</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row form-row--last form-row--top">
|
||||
<span class="lb">上传壁纸</span>
|
||||
<div class="ctl">
|
||||
<button class="btn ghost sm">选择文件</button>
|
||||
<Upload :on-success="onWallpaperUploaded" :show-upload-list="false" :action="wallpaperUploadAction"
|
||||
accept="image/jpeg, image/jpg, image/png" :with-credentials="true" :headers="uploadHeaders">
|
||||
<button class="btn ghost sm">选择文件</button>
|
||||
</Upload>
|
||||
<span class="hint">建议 1920×1080 以上,≤ 5MB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane-foot">
|
||||
<!-- 保存语义=设为我的壁纸(checkWallpaper,与 Header 壁纸弹窗一致) -->
|
||||
<button class="btn primary" :disabled="wallApplying" @click="onApplyWallpaper">应用壁纸</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 边栏设置(管理员) -->
|
||||
@@ -291,11 +317,22 @@ import { ref, reactive, computed, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useDefaultStore } from "@/store";
|
||||
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
|
||||
import { requireImg } from "@/utils/hook/useImg";
|
||||
import SysSetting from "@/views/SysSetting.vue";
|
||||
import BaseApi from "@/api/BaseApi";
|
||||
import SysSettingApi from "@/api/SysSettingApi";
|
||||
import UserSettingApi from "@/api/UserSettingApi";
|
||||
import Utils from "@/utils";
|
||||
import { Message } from "view-ui-plus";
|
||||
|
||||
/**
|
||||
* 设置中心(/settings):左 216px 分组导航卡 + 右内容卡(B 方案左右双卡)。
|
||||
* 本轮只做导航壳 + pane 切换 + 背景层,各 pane 内表单均为占位(接口对接属下一轮)。
|
||||
* 五个 pane 已对接真实数据(设置对接 2026-09-30,零新接口):
|
||||
* profile 读 store.userInfo(保存占位——接口待 UserBase 支持本人自助修改,本轮不做);
|
||||
* password 走 updatePassword + 确认登出流程(照抄 UserInfoModal);
|
||||
* avatar 移植 UserInfoModal 直传上传(预设色块/「使用默认头像」保持占位);
|
||||
* logo/wallpaper 管理列表 + 直传 + 删除照抄 SysSetting.vue,LOGO 保存走 saveSchLogo(schId 后端按登录人推断),
|
||||
* 「应用壁纸」采用 checkWallpaper 个人壁纸语义(与 Header 壁纸弹窗一致,执行报告已写明)。
|
||||
*/
|
||||
|
||||
const route = useRoute();
|
||||
@@ -366,13 +403,91 @@ const navGroups = computed(() => {
|
||||
return isAdmin.value ? groups : groups.filter(g => !g.adminOnly);
|
||||
});
|
||||
|
||||
/* ===== 以下均为 pane 占位数据(真实表单/接口对接属下一轮) ===== */
|
||||
const profileForm = reactive({ mobile: "138****8899", email: "zhangming@school.edu.cn" });
|
||||
/* ===== profile:读 store.userInfo(真实展示;保存占位) ===== */
|
||||
const profileForm = reactive({ mobile: "", email: "" });
|
||||
/** userInfo 派生展示(手机/邮箱编辑值初始同源;工号暂以登录账号展示——接口未提供独立工号字段) */
|
||||
const profileView = computed(() => {
|
||||
const u: any = store.userInfo || {};
|
||||
return {
|
||||
name: u.name || "-",
|
||||
account: u.account || "-",
|
||||
deptName: u.deptName || u.dept || "-",
|
||||
phone: u.phone || "",
|
||||
email: u.email || "",
|
||||
};
|
||||
});
|
||||
watch(
|
||||
() => store.userInfo,
|
||||
() => {
|
||||
profileForm.mobile = profileView.value.phone;
|
||||
profileForm.email = profileView.value.email;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
function resetProfileForm() {
|
||||
profileForm.mobile = "138****8899";
|
||||
profileForm.email = "zhangming@school.edu.cn";
|
||||
profileForm.mobile = profileView.value.phone;
|
||||
profileForm.email = profileView.value.email;
|
||||
}
|
||||
/** 保存占位:接口待 UserBase 支持本人自助修改,本轮不做(拍板结论) */
|
||||
|
||||
/* ===== password:updatePassword + 确认登出(流程照抄 UserInfoModal) ===== */
|
||||
const passwordForm = reactive({ old: "", next: "", confirm: "" });
|
||||
const passwordSubmitting = ref(false);
|
||||
async function onUpdatePassword() {
|
||||
if (!passwordForm.old || !passwordForm.next) {
|
||||
Message.warning("请填写原密码与新密码");
|
||||
return;
|
||||
}
|
||||
if (passwordForm.next !== passwordForm.confirm) {
|
||||
Message.warning("两次输入的新密码不一致");
|
||||
return;
|
||||
}
|
||||
if (passwordForm.next === passwordForm.old) {
|
||||
Message.warning("新密码不能与旧密码一致");
|
||||
return;
|
||||
}
|
||||
if (passwordForm.next.length < 8) {
|
||||
Message.warning("密码长度不能小于8位");
|
||||
return;
|
||||
}
|
||||
if (passwordSubmitting.value) return;
|
||||
passwordSubmitting.value = true;
|
||||
try {
|
||||
await BaseApi.updatePassword(passwordForm.old, passwordForm.next);
|
||||
Message.success("操作成功!");
|
||||
// 改密后旧会话失效,引导重新登录(照抄 UserInfoModal 确认登出流程)
|
||||
setTimeout(logout, 1500);
|
||||
} catch (error) {
|
||||
Message.error("操作失败:" + error);
|
||||
} finally {
|
||||
passwordSubmitting.value = false;
|
||||
}
|
||||
}
|
||||
function logout() {
|
||||
let url = window.location.href;
|
||||
url = "/logout?service=" + url;
|
||||
url = $conf.ssoHost + url;
|
||||
if (!!window.top) window.top.location.href = url;
|
||||
else window.location.href = url;
|
||||
}
|
||||
|
||||
/* ===== avatar:移植 UserInfoModal 直传上传(预设色块/「使用默认头像」保持占位) ===== */
|
||||
// Upload 组件直传不经 axios 封装,需手动补网关校验头(照抄 UserInfoModal)
|
||||
const uploadHeaders = { yschapirequest: 1, yschreferer: Utils.strToHexCharCode(window.location.href) };
|
||||
function uploadAvatarSuccess(response: any) {
|
||||
if (response.code == 0 && response.data && response.data.url) {
|
||||
store.userInfo.profilePicture = response.data.url;
|
||||
Message.success("头像更新成功!");
|
||||
} else {
|
||||
Message.error("头像更新失败:" + (response.msg || "未知错误"));
|
||||
}
|
||||
}
|
||||
function onAvatarSizeExceeded() {
|
||||
Message.error("图片大小不能超过20MB!");
|
||||
}
|
||||
function onAvatarFormatError() {
|
||||
Message.error("仅支持 jpg/jpeg/png/gif/webp 格式图片!");
|
||||
}
|
||||
|
||||
const avatarPresets = [
|
||||
"linear-gradient(135deg,#5979ea,#7d9bf5)",
|
||||
@@ -381,24 +496,97 @@ const avatarPresets = [
|
||||
"linear-gradient(135deg,#e8684a,#f1957e)",
|
||||
"linear-gradient(135deg,#8a7ce0,#b3a8f0)",
|
||||
];
|
||||
const avatarLetters = ["张", "A", "B", "C", "D"];
|
||||
const avatarLetters = computed(() => {
|
||||
const name = String(store.userInfo?.name || "A").trim();
|
||||
return [name.charAt(0) || "A", "A", "B", "C", "D"];
|
||||
});
|
||||
const avatarSel = ref(0);
|
||||
|
||||
const logoList = [
|
||||
{ name: "智慧校园平台", marks: "🎓" },
|
||||
{ name: "云海教育", marks: "📘" },
|
||||
{ name: "第一中学", marks: "🏫" },
|
||||
];
|
||||
const logoSel = ref(0);
|
||||
/* ===== logo / wallpaper:管理列表 + 直传 + 删除(照抄 SysSetting.vue 管理语义) ===== */
|
||||
const logoManageList = ref<any[]>([]);
|
||||
const wallpaperManageList = ref<any[]>([]);
|
||||
const logoSelUrl = ref<string>("");
|
||||
const wallSelUrl = ref<string>("");
|
||||
/** 直传端点(本 pane 无机构树,超管按机构切换请用「系统设置」pane;不带 schId 即落到登录人归属校) */
|
||||
const logoUploadAction = $conf.serviceHost + "/api/logoUpload";
|
||||
const wallpaperUploadAction = $conf.serviceHost + "/api/wallpaperUpload";
|
||||
|
||||
const wallpaperList = [
|
||||
"linear-gradient(135deg,#cfe0ea,#d9e0d2)",
|
||||
"linear-gradient(135deg,#e6e2d6,#c9d4c0)",
|
||||
"linear-gradient(135deg,#bfd4e8,#a8bdd6)",
|
||||
"linear-gradient(135deg,#f0e2d0,#e0cdb8)",
|
||||
"linear-gradient(135deg,#d6e0f0,#c0cde6)",
|
||||
];
|
||||
const wallSel = ref(0);
|
||||
async function loadManageLists() {
|
||||
// 本 pane 无机构树:不带 schId,列表按登录人归属校返回(超管按机构切换请用「系统设置」pane)
|
||||
const [walls, logos] = await Promise.all([
|
||||
SysSettingApi.getSchWallpaperManageList(),
|
||||
SysSettingApi.getSchLogoManageList(),
|
||||
]);
|
||||
wallpaperManageList.value = walls || [];
|
||||
logoManageList.value = logos || [];
|
||||
}
|
||||
|
||||
function onLogoUploaded() {
|
||||
loadManageLists();
|
||||
}
|
||||
function onWallpaperUploaded() {
|
||||
loadManageLists();
|
||||
}
|
||||
async function onDeleteLogo(item: any) {
|
||||
await SysSettingApi.deleteLogoById(item.id);
|
||||
Message.success("删除成功");
|
||||
loadManageLists();
|
||||
}
|
||||
async function onDeleteWallpaper(item: any) {
|
||||
await SysSettingApi.deleteWallById(item.id);
|
||||
Message.success("删除成功");
|
||||
loadManageLists();
|
||||
}
|
||||
|
||||
/** LOGO 保存:选中项写入学校级配置(schId 后端按登录人推断:主学校→归属组→0 平台默认) */
|
||||
const logoSaving = ref(false);
|
||||
async function onSaveLogo() {
|
||||
if (!logoSelUrl.value) {
|
||||
Message.warning("请先选择一个 LOGO");
|
||||
return;
|
||||
}
|
||||
if (logoSaving.value) return;
|
||||
logoSaving.value = true;
|
||||
try {
|
||||
await BaseApi.saveSchLogo(logoSelUrl.value);
|
||||
Message.success("保存成功,全站 LOGO 生效");
|
||||
} catch (error) {
|
||||
Message.error("操作失败:" + error);
|
||||
} finally {
|
||||
logoSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 应用壁纸:采用 checkWallpaper 个人壁纸语义(与 Header 壁纸弹窗现状一致,见执行报告) */
|
||||
const wallApplying = ref(false);
|
||||
async function onApplyWallpaper() {
|
||||
if (!wallSelUrl.value) {
|
||||
Message.warning("请先选择一张壁纸");
|
||||
return;
|
||||
}
|
||||
if (wallApplying.value) return;
|
||||
wallApplying.value = true;
|
||||
try {
|
||||
await UserSettingApi.checkWallpaper(store.getCurSchId, wallSelUrl.value);
|
||||
const userSetting = store.curUserSettingInfo;
|
||||
if (!!userSetting) {
|
||||
userSetting.wallpaperUrl = wallSelUrl.value;
|
||||
store.setCurUserSettingsInfo(userSetting);
|
||||
}
|
||||
Message.success("壁纸已应用");
|
||||
} catch (error) {
|
||||
Message.error("操作失败:" + error);
|
||||
} finally {
|
||||
wallApplying.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 首次切到 logo / wallpaper pane 时懒加载管理列表
|
||||
watch(curPane, pane => {
|
||||
if ((pane === "logo" || pane === "wallpaper") && isAdmin.value && logoManageList.value.length === 0 && wallpaperManageList.value.length === 0) {
|
||||
loadManageLists();
|
||||
}
|
||||
});
|
||||
|
||||
const sidebarItems = ref([
|
||||
{ name: "通知公告", on: true },
|
||||
@@ -672,23 +860,16 @@ function openBackend() {
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
.avatar-now {
|
||||
.avatar-img {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #5979ea, #7d9bf5);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 14px rgba(89, 121, 234, 0.3);
|
||||
&.avatar-sm {
|
||||
&.avatar-img-sm {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.avatar-ops {
|
||||
@@ -698,6 +879,7 @@ function openBackend() {
|
||||
.avatar-btns {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
.tip {
|
||||
font-size: 12px;
|
||||
@@ -786,6 +968,12 @@ function openBackend() {
|
||||
gap: 12px;
|
||||
padding: 14px 0 4px;
|
||||
}
|
||||
.logo-empty {
|
||||
grid-column: 1 / -1;
|
||||
padding: 18px 0 8px;
|
||||
color: #b3b3b3;
|
||||
font-size: 13px;
|
||||
}
|
||||
.logo-item {
|
||||
height: 72px;
|
||||
border-radius: 6px;
|
||||
@@ -796,10 +984,13 @@ function openBackend() {
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.18s;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #3f5fd4;
|
||||
gap: 8px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
img {
|
||||
max-width: 86%;
|
||||
max-height: 82%;
|
||||
object-fit: contain;
|
||||
}
|
||||
&:hover {
|
||||
border-color: #5979ea;
|
||||
background: #eef2ff;
|
||||
@@ -808,17 +999,30 @@ function openBackend() {
|
||||
border-color: #5979ea;
|
||||
box-shadow: 0 0 0 3px rgba(89, 121, 234, 0.18);
|
||||
}
|
||||
.mk {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 7px;
|
||||
background: linear-gradient(135deg, #5979ea, #7d9bf5);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.wall-item {
|
||||
position: relative;
|
||||
}
|
||||
.del {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
z-index: 2;
|
||||
}
|
||||
.logo-item:hover .del,
|
||||
.wall-item:hover .del {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 边栏设置:拖拽示意列表 */
|
||||
|
||||
Reference in New Issue
Block a user