Merge branch 'main' of http://git.tensent.cn/molong/vueadmin
This commit is contained in:
@@ -9,41 +9,28 @@
|
||||
</template>
|
||||
|
||||
<div class="search-form">
|
||||
<a-form :model="searchForm" layout="inline">
|
||||
<a-form-item label="用户名">
|
||||
<a-input v-model:value="searchForm.username" placeholder="请输入用户名" />
|
||||
</a-form-item>
|
||||
<a-form-item label="状态">
|
||||
<a-select v-model:value="searchForm.status" placeholder="请选择状态" style="width: 120px">
|
||||
<a-select-option value="">全部</a-select-option>
|
||||
<a-select-option :value="1">正常</a-select-option>
|
||||
<a-select-option :value="0">禁用</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleSearch">查询</a-button>
|
||||
<a-button @click="handleReset">重置</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<sc-form :form-items="formItems" :initial-values="searchForm" :show-actions="true" submit-text="查询"
|
||||
reset-text="重置" @finish="handleSearch" @reset="handleReset" layout="inline" />
|
||||
</div>
|
||||
|
||||
<a-table :columns="columns" :data-source="dataSource" :loading="loading" :pagination="pagination">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">
|
||||
<a-tag :color="record.status === 1 ? 'green' : 'red'">
|
||||
{{ record.status === 1 ? '正常' : '禁用' }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-button type="link" size="small" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button type="link" size="small" danger @click="handleDelete(record)">删除</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<sc-table :columns="columns" :data-source="dataSource" :loading="loading" :pagination="pagination"
|
||||
:show-action-column="true" :action-column="{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
}">
|
||||
<template #status="{ record }">
|
||||
<a-tag :color="record.status === 1 ? 'green' : 'red'">
|
||||
{{ record.status === 1 ? '正常' : '禁用' }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</a-table>
|
||||
<template #action="{ record }">
|
||||
<a-space>
|
||||
<a-button type="link" size="small" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button type="link" size="small" danger @click="handleDelete(record)">删除</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</sc-table>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -52,45 +39,66 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { PlusOutlined } from '@ant-design/icons-vue'
|
||||
import ScTable from '@/components/scTable/index.vue'
|
||||
import ScForm from '@/components/scForm/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
width: 80
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
dataIndex: 'username',
|
||||
key: 'username'
|
||||
key: 'username',
|
||||
},
|
||||
{
|
||||
title: '昵称',
|
||||
dataIndex: 'nickname',
|
||||
key: 'nickname'
|
||||
key: 'nickname',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 100
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime'
|
||||
key: 'createTime',
|
||||
},
|
||||
]
|
||||
|
||||
// 搜索表单配置
|
||||
const formItems = [
|
||||
{
|
||||
field: 'username',
|
||||
label: '用户名',
|
||||
type: 'input',
|
||||
placeholder: '请输入用户名',
|
||||
allowClear: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150
|
||||
}
|
||||
field: 'status',
|
||||
label: '状态',
|
||||
type: 'select',
|
||||
placeholder: '请选择状态',
|
||||
options: [
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '正常', value: 1 },
|
||||
{ label: '禁用', value: 0 },
|
||||
],
|
||||
allowClear: true,
|
||||
style: 'width: 120px',
|
||||
},
|
||||
]
|
||||
|
||||
const searchForm = ref({
|
||||
username: '',
|
||||
status: ''
|
||||
status: '',
|
||||
})
|
||||
|
||||
const dataSource = ref([])
|
||||
@@ -100,7 +108,7 @@ const pagination = ref({
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showTotal: (total) => `共 ${total} 条`
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
@@ -110,15 +118,15 @@ const mockData = [
|
||||
username: 'admin',
|
||||
nickname: '管理员',
|
||||
status: 1,
|
||||
createTime: '2024-01-01 10:00:00'
|
||||
createTime: '2024-01-01 10:00:00',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: 'user',
|
||||
nickname: '普通用户',
|
||||
status: 1,
|
||||
createTime: '2024-01-02 10:00:00'
|
||||
}
|
||||
createTime: '2024-01-02 10:00:00',
|
||||
},
|
||||
]
|
||||
|
||||
const loadData = () => {
|
||||
@@ -138,7 +146,7 @@ const handleSearch = () => {
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
username: '',
|
||||
status: ''
|
||||
status: '',
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<scForm :form-items="formItems" :initial-values="initialValues" :loading="loading" @finish="handleFinish"
|
||||
@reset="handleReset" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import scForm from '@/components/scForm/index.vue'
|
||||
|
||||
const props = defineProps({
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update'])
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
// 表单初始值
|
||||
const initialValues = computed(() => ({
|
||||
username: props.userInfo.username || '',
|
||||
nickname: props.userInfo.nickname || '',
|
||||
phone: props.userInfo.phone || '',
|
||||
email: props.userInfo.email || '',
|
||||
gender: props.userInfo.gender || 0,
|
||||
birthday: props.userInfo.birthday || null,
|
||||
bio: props.userInfo.bio || '',
|
||||
}))
|
||||
|
||||
// 表单项配置
|
||||
const formItems = [
|
||||
{
|
||||
field: 'username',
|
||||
label: '用户名',
|
||||
type: 'input',
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
field: 'nickname',
|
||||
label: '昵称',
|
||||
type: 'input',
|
||||
required: true,
|
||||
rules: [
|
||||
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
||||
{ min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '手机号',
|
||||
type: 'input',
|
||||
rules: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }],
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
label: '邮箱',
|
||||
type: 'input',
|
||||
rules: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }],
|
||||
},
|
||||
{
|
||||
field: 'gender',
|
||||
label: '性别',
|
||||
type: 'radio',
|
||||
options: [
|
||||
{ label: '男', value: 1 },
|
||||
{ label: '女', value: 2 },
|
||||
{ label: '保密', value: 0 },
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'birthday',
|
||||
label: '生日',
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
field: 'bio',
|
||||
label: '个人简介',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
maxLength: 200,
|
||||
showCount: true,
|
||||
},
|
||||
]
|
||||
|
||||
// 表单提交
|
||||
const handleFinish = (values) => {
|
||||
loading.value = true
|
||||
// 模拟接口请求
|
||||
setTimeout(() => {
|
||||
emit('update', values)
|
||||
message.success('保存成功')
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
message.info('已重置')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<scForm :form-items="formItems" :initial-values="initialValues" :loading="loading" submit-text="修改密码"
|
||||
@finish="handleFinish" @reset="handleReset" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import scForm from '@/components/scForm/index.vue'
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
// 表单初始值
|
||||
const initialValues = {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
}
|
||||
|
||||
// 表单项配置
|
||||
const formItems = [
|
||||
{
|
||||
field: 'oldPassword',
|
||||
label: '原密码',
|
||||
type: 'password',
|
||||
required: true,
|
||||
rules: [{ required: true, message: '请输入原密码', trigger: 'blur' }],
|
||||
},
|
||||
{
|
||||
field: 'newPassword',
|
||||
label: '新密码',
|
||||
type: 'password',
|
||||
required: true,
|
||||
rules: [
|
||||
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '密码长度在 6 到 20 个字符', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'confirmPassword',
|
||||
label: '确认密码',
|
||||
type: 'password',
|
||||
required: true,
|
||||
rules: [
|
||||
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (value !== initialValues.newPassword) {
|
||||
return Promise.reject('两次输入的密码不一致')
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
// 表单提交
|
||||
const handleFinish = (values) => {
|
||||
loading.value = true
|
||||
// 模拟接口请求
|
||||
setTimeout(() => {
|
||||
message.success('密码修改成功,请重新登录')
|
||||
emit('success')
|
||||
handleReset()
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
initialValues.oldPassword = ''
|
||||
initialValues.newPassword = ''
|
||||
initialValues.confirmPassword = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div class="profile-info">
|
||||
<div class="avatar-wrapper">
|
||||
<a-avatar :size="100" :src="userInfo.avatar" @click="handleAvatarClick">
|
||||
{{ userInfo.nickname?.charAt(0) }}
|
||||
</a-avatar>
|
||||
</div>
|
||||
<div class="user-name">{{ userInfo.nickname || userInfo.username }}</div>
|
||||
<a-tag :color="userInfo.status === 1 ? 'green' : 'red'">
|
||||
{{ userInfo.status === 1 ? '正常' : '禁用' }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['avatar-click'])
|
||||
|
||||
const handleAvatarClick = () => {
|
||||
emit('avatar-click')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.profile-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px 0;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
color: #fff;
|
||||
|
||||
.avatar-wrapper {
|
||||
margin-bottom: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
.ant-avatar {
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(255, 255, 255, 0.6);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ant-tag {
|
||||
margin: 0;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<a-list :data-source="securityList" item-layout="horizontal">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
<a-list-item-meta>
|
||||
<template #title>
|
||||
{{ item.title }}
|
||||
</template>
|
||||
<template #description>
|
||||
{{ item.description }}
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<template #actions>
|
||||
<a-button type="primary" size="small" @click="handleAction(item.action)">
|
||||
{{ item.buttonText }}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
const emit = defineEmits(['change-password'])
|
||||
|
||||
const securityList = ref([
|
||||
{
|
||||
title: '登录密码',
|
||||
description: '用于登录系统的密码,建议定期更换',
|
||||
buttonText: '修改',
|
||||
action: 'password',
|
||||
},
|
||||
{
|
||||
title: '手机验证',
|
||||
description: '用于接收重要通知和安全验证',
|
||||
buttonText: '已绑定',
|
||||
action: 'phone',
|
||||
},
|
||||
{
|
||||
title: '邮箱验证',
|
||||
description: '用于接收重要通知和账号找回',
|
||||
buttonText: '已绑定',
|
||||
action: 'email',
|
||||
},
|
||||
{
|
||||
title: '登录设备',
|
||||
description: '查看和管理已登录的设备',
|
||||
buttonText: '查看',
|
||||
action: 'device',
|
||||
},
|
||||
])
|
||||
|
||||
const handleAction = (action) => {
|
||||
switch (action) {
|
||||
case 'password':
|
||||
emit('change-password')
|
||||
break
|
||||
case 'phone':
|
||||
message.info('手机绑定功能开发中')
|
||||
break
|
||||
case 'email':
|
||||
message.info('邮箱绑定功能开发中')
|
||||
break
|
||||
case 'device':
|
||||
message.info('登录设备管理功能开发中')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.ant-list-item) {
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
:deep(.ant-list-item:last-child) {
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div class="ucenter">
|
||||
<a-card>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="6">
|
||||
<ProfileInfo :user-info="userInfo" @avatar-click="showAvatarModal = true" />
|
||||
<a-menu v-model:selectedKeys="selectedKeys" mode="inline" class="menu">
|
||||
<a-menu-item key="basic">
|
||||
<UserOutlined />
|
||||
基本信息
|
||||
</a-menu-item>
|
||||
<a-menu-item key="password">
|
||||
<LockOutlined />
|
||||
修改密码
|
||||
</a-menu-item>
|
||||
<a-menu-item key="security">
|
||||
<SafetyOutlined />
|
||||
账号安全
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-col>
|
||||
<a-col :span="18">
|
||||
<div class="content-wrapper">
|
||||
<BasicInfo v-if="selectedKeys[0] === 'basic'" :user-info="userInfo"
|
||||
@update="handleUpdateUserInfo" />
|
||||
<Password v-else-if="selectedKeys[0] === 'password'" @success="handlePasswordSuccess" />
|
||||
<Security v-else-if="selectedKeys[0] === 'security'" @change-password="handleChangePassword" />
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
|
||||
<!-- 头像上传弹窗 -->
|
||||
<a-modal v-model:open="showAvatarModal" title="更换头像" :confirm-loading="loading" @ok="handleAvatarUpload"
|
||||
@cancel="showAvatarModal = false">
|
||||
<div class="avatar-upload">
|
||||
<a-upload list-type="picture-card" :max-count="1" :before-upload="beforeUpload"
|
||||
@change="handleAvatarChange" :file-list="avatarFileList">
|
||||
<div v-if="avatarFileList.length === 0">
|
||||
<PlusOutlined />
|
||||
<div class="ant-upload-text">上传头像</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<div class="upload-tip">
|
||||
<a-typography-text type="secondary"> 支持 JPG、PNG 格式,文件大小不超过 2MB </a-typography-text>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { PlusOutlined, UserOutlined, LockOutlined, SafetyOutlined } from '@ant-design/icons-vue'
|
||||
import dayjs from 'dayjs'
|
||||
import ProfileInfo from './components/ProfileInfo.vue'
|
||||
import BasicInfo from './components/BasicInfo.vue'
|
||||
import Password from './components/Password.vue'
|
||||
import Security from './components/Security.vue'
|
||||
|
||||
// 用户信息
|
||||
const userInfo = ref({
|
||||
username: '',
|
||||
nickname: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
avatar: '',
|
||||
status: 1,
|
||||
gender: 0,
|
||||
birthday: null,
|
||||
bio: '',
|
||||
})
|
||||
|
||||
// 选中的菜单
|
||||
const selectedKeys = ref(['basic'])
|
||||
|
||||
// 头像上传
|
||||
const showAvatarModal = ref(false)
|
||||
const avatarFileList = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
// 初始化用户信息
|
||||
const initUserInfo = () => {
|
||||
// 模拟用户数据
|
||||
const mockUserInfo = {
|
||||
username: 'admin',
|
||||
nickname: '管理员',
|
||||
phone: '13800138000',
|
||||
email: 'admin@example.com',
|
||||
avatar: '',
|
||||
status: 1,
|
||||
gender: 1,
|
||||
birthday: dayjs('1990-01-01'),
|
||||
bio: '热爱编程,专注于前端开发技术。',
|
||||
}
|
||||
userInfo.value = { ...mockUserInfo }
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
const handleUpdateUserInfo = (data) => {
|
||||
Object.assign(userInfo.value, data)
|
||||
}
|
||||
|
||||
// 密码修改成功
|
||||
const handlePasswordSuccess = () => {
|
||||
// 密码修改成功后的处理
|
||||
}
|
||||
|
||||
// 切换到密码修改页面
|
||||
const handleChangePassword = () => {
|
||||
selectedKeys.value = ['password']
|
||||
}
|
||||
|
||||
// 头像上传前校验
|
||||
const beforeUpload = (file) => {
|
||||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
|
||||
if (!isJpgOrPng) {
|
||||
message.error('只能上传 JPG/PNG 格式的文件!')
|
||||
return false
|
||||
}
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
message.error('图片大小不能超过 2MB!')
|
||||
return false
|
||||
}
|
||||
return false // 阻止自动上传
|
||||
}
|
||||
|
||||
// 头像文件变化
|
||||
const handleAvatarChange = ({ fileList }) => {
|
||||
avatarFileList.value = fileList
|
||||
}
|
||||
|
||||
// 上传头像
|
||||
const handleAvatarUpload = () => {
|
||||
if (avatarFileList.value.length === 0) {
|
||||
message.warning('请先选择头像')
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
// 模拟上传
|
||||
setTimeout(() => {
|
||||
const file = avatarFileList.value[0]
|
||||
userInfo.value.avatar = URL.createObjectURL(file.originFileObj)
|
||||
message.success('头像更新成功')
|
||||
showAvatarModal.value = false
|
||||
avatarFileList.value = []
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initUserInfo()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.ucenter {
|
||||
.content-wrapper {
|
||||
padding: 24px;
|
||||
background: #fafafa;
|
||||
border-radius: 8px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.menu {
|
||||
margin-top: 16px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
||||
.ant-menu-item {
|
||||
border-radius: 6px;
|
||||
margin: 4px 0;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
&.ant-menu-item-selected {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
|
||||
&::after {
|
||||
border-right-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-upload {
|
||||
.upload-tip {
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-card-head-title) {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user