[重大更新] 整体主题样式重写 改为卡片式布局 样式更企业化

This commit is contained in:
疯狂的狮子Li
2026-03-17 12:35:56 +08:00
parent b83755e626
commit 833dfa67fc
70 changed files with 5250 additions and 1568 deletions
+69 -52
View File
@@ -1,57 +1,60 @@
<template>
<div class="p-2">
<div class="panel">
<h4 class="panel-title">基本信息</h4>
<el-form :model="form" :inline="true">
<el-row :gutter="10">
<el-col :span="2.5">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled />
</el-form-item>
</el-col>
<el-col :span="2.5">
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div class="panel">
<h4 class="panel-title">角色信息</h4>
<div>
<el-table
ref="tableRef"
v-loading="loading"
border
:row-key="getRowKey"
:data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
@row-click="clickRow"
@selection-change="handleSelectionChange"
>
<el-table-column label="序号" width="55" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column>
<el-table-column label="角色编号" align="center" prop="roleId" />
<el-table-column label="角色名称" align="center" prop="roleName" />
<el-table-column label="权限字符" align="center" prop="roleKey" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" />
<div style="text-align: center; margin-left: -120px; margin-top: 30px">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
<div class="p-2 page-shell auth-role-page">
<el-card shadow="hover" class="search-panel auth-role-info">
<template #header>
<div class="panel-heading">
<div><h3>基本信息</h3></div>
</div>
<div></div>
</div>
</div>
</template>
<el-form :model="form" :inline="true" class="query-form auth-role-form">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled />
</el-form-item>
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-form>
</el-card>
<el-card shadow="hover" class="table-panel">
<template #header>
<div class="toolbar-shell">
<div class="table-heading">
<h3>角色信息</h3>
</div>
<div class="toolbar-actions">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
</div>
</template>
<el-table
ref="tableRef"
v-loading="loading"
border
class="data-table"
:row-key="getRowKey"
:data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
@row-click="clickRow"
@selection-change="handleSelectionChange"
>
<el-table-column label="序号" width="55" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column>
<el-table-column label="角色编号" align="center" prop="roleId" />
<el-table-column label="角色名称" align="center" prop="roleName" />
<el-table-column label="权限字符" align="center" prop="roleKey" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" />
</el-card>
</div>
</template>
@@ -144,3 +147,17 @@ onMounted(() => {
getList();
});
</script>
<style lang="scss" scoped>
.auth-role-form :deep(.el-form-item) {
margin-bottom: 0;
}
.auth-role-form :deep(.el-input) {
width: 220px;
}
.auth-role-info :deep(.el-card__body) {
padding-top: 14px !important;
}
</style>
+73 -24
View File
@@ -1,13 +1,21 @@
<template>
<div class="p-2">
<el-row :gutter="20">
<div class="page-shell system-user-page">
<el-row :gutter="20" class="content-grid">
<!-- 部门树 -->
<el-col :lg="4" :xs="24" style="">
<el-card shadow="hover">
<el-col :lg="5" :xs="24">
<el-card shadow="hover" class="side-panel">
<template #header>
<div class="panel-heading">
<div>
<span class="panel-kicker">Department Filter</span>
<h3>部门结构</h3>
</div>
</div>
</template>
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
<el-tree
ref="deptTreeRef"
class="mt-2"
class="mt-2 dept-tree"
node-key="id"
:data="deptOptions"
:props="{ label: 'label', children: 'children' } as any"
@@ -19,11 +27,18 @@
/>
</el-card>
</el-col>
<el-col :lg="20" :xs="24">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-col :lg="19" :xs="24" class="content-main">
<div class="search-wrap">
<el-card shadow="hover" class="search-panel" :class="{ 'is-collapsed': !showSearch }">
<template #header>
<div class="panel-heading search-panel-toggle" @click.stop="showSearch = !showSearch">
<div>
<span class="panel-kicker">Search Filters</span>
<h3>筛选条件</h3>
</div>
</div>
</template>
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
@@ -57,25 +72,23 @@
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="hover">
<el-card shadow="hover" class="table-panel">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<div class="toolbar-shell">
<div class="table-heading">
<span class="panel-kicker">User Dataset</span>
<h3>用户列表</h3>
<p> {{ total }} 条记录支持部门筛选状态切换导入导出和角色分配</p>
</div>
<div class="toolbar-actions">
<el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-dropdown class="mt-[1px]">
<el-button plain type="info">
更多
@@ -90,12 +103,12 @@
</el-dropdown-menu>
</template>
</el-dropdown>
</el-col>
<right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
</el-row>
<right-toolbar v-model:show-search="showSearch" :columns="columns" :search="false" @query-table="getList"></right-toolbar>
</div>
</div>
</template>
<el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange">
<el-table v-loading="loading" border class="data-table" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
@@ -677,3 +690,39 @@ async function handleDeptChange(value: number | string) {
form.value.postIds = [];
}
</script>
<style lang="scss" scoped>
.page-shell {
display: flex;
flex-direction: column;
}
.content-grid {
margin: 0 !important;
}
.content-main {
display: flex;
flex-direction: column;
gap: 12px;
}
.dept-tree {
padding-top: 6px;
}
.data-table {
:deep(.el-button.is-link) {
width: 32px;
height: 32px;
border-radius: 10px;
background: rgba(53, 109, 255, 0.08);
}
}
@media (max-width: 900px) {
.toolbar-shell {
align-items: flex-start;
}
}
</style>
+130 -23
View File
@@ -1,54 +1,76 @@
<template>
<div class="p-2">
<el-row :gutter="20">
<div class="p-2 page-shell profile-page">
<el-row :gutter="20" class="profile-grid">
<el-col :span="6" :xs="24">
<el-card class="box-card">
<el-card shadow="hover" class="side-panel profile-summary-card">
<template #header>
<div class="clearfix">
<span>个人信息</span>
<div class="panel-heading">
<div><h3>个人信息</h3></div>
</div>
</template>
<div>
<div class="text-center">
<div class="profile-summary">
<div class="text-center profile-avatar">
<userAvatar />
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">
<svg-icon icon-class="user" />用户名称
<div class="pull-right">{{ state.user.userName }}</div>
<div class="profile-item-label">
<svg-icon icon-class="user" />
<span>用户名称</span>
</div>
<span class="profile-item-value">{{ state.user.userName || '-' }}</span>
</li>
<li class="list-group-item">
<svg-icon icon-class="phone" />手机号码
<div class="pull-right">{{ state.user.phonenumber }}</div>
<div class="profile-item-label">
<svg-icon icon-class="phone" />
<span>手机号码</span>
</div>
<span class="profile-item-value">{{ state.user.phonenumber || '-' }}</span>
</li>
<li class="list-group-item">
<svg-icon icon-class="email" />用户邮箱
<div class="pull-right">{{ state.user.email }}</div>
<div class="profile-item-label">
<svg-icon icon-class="email" />
<span>用户邮箱</span>
</div>
<span class="profile-item-value">{{ state.user.email || '-' }}</span>
</li>
<li class="list-group-item">
<svg-icon icon-class="tree" />所属部门
<div v-if="state.user.deptName" class="pull-right">{{ state.user.deptName }} / {{ state.postGroup }}</div>
<div class="profile-item-label">
<svg-icon icon-class="tree" />
<span>所属部门</span>
</div>
<span v-if="state.user.deptName" class="profile-item-value">{{ state.user.deptName }} / {{ state.postGroup }}</span>
<span v-else class="profile-item-value">-</span>
</li>
<li class="list-group-item">
<svg-icon icon-class="peoples" />所属角色
<div class="pull-right">{{ state.roleGroup }}</div>
<div class="profile-item-label">
<svg-icon icon-class="peoples" />
<span>所属角色</span>
</div>
<span class="profile-item-value">{{ state.roleGroup || '-' }}</span>
</li>
<li class="list-group-item">
<svg-icon icon-class="date" />创建日期
<div class="pull-right">{{ state.user.createTime }}</div>
<div class="profile-item-label">
<svg-icon icon-class="date" />
<span>创建日期</span>
</div>
<span class="profile-item-value">{{ state.user.createTime || '-' }}</span>
</li>
</ul>
</div>
</el-card>
</el-col>
<el-col :span="18" :xs="24">
<el-card>
<el-card shadow="hover" class="table-panel profile-main-card">
<template #header>
<div class="clearfix">
<span>基本资料</span>
<div class="toolbar-shell">
<div class="table-heading">
<h3>个人设置</h3>
<p>维护个人资料密码第三方应用和在线设备</p>
</div>
</div>
</template>
<el-tabs v-model="activeTab">
<el-tabs v-model="activeTab" class="profile-tabs">
<el-tab-pane label="基本资料" name="userinfo">
<userInfo :user="userForm" />
</el-tab-pane>
@@ -120,3 +142,88 @@ onMounted(() => {
getOnlines();
});
</script>
<style lang="scss" scoped>
.profile-grid {
row-gap: 12px;
}
.profile-summary-card,
.profile-main-card {
height: 100%;
}
.profile-summary {
display: flex;
flex-direction: column;
gap: 18px;
}
.profile-avatar {
margin-bottom: 4px;
}
.profile-item-label {
display: inline-flex;
align-items: center;
gap: 8px;
font-weight: 600;
}
.profile-item-value {
max-width: 58%;
text-align: right;
color: var(--el-text-color-secondary);
word-break: break-word;
}
.profile-summary :deep(.list-group-item) {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 12px 0;
}
.profile-tabs :deep(.el-tabs__header) {
margin-bottom: 18px;
}
.profile-tabs :deep(.el-tabs__nav-wrap::after),
.profile-tabs :deep(.el-tabs__active-bar) {
display: none;
}
.profile-tabs :deep(.el-tabs__nav) {
gap: 8px;
}
.profile-tabs :deep(.el-tabs__item) {
display: inline-flex;
align-items: center;
justify-content: center;
height: 36px;
min-width: 88px;
padding: 0 16px;
border-radius: 10px;
color: var(--el-text-color-regular);
}
.profile-tabs :deep(.el-tabs__item:nth-child(2)),
.profile-tabs :deep(.el-tabs__item.is-top:first-child),
.profile-tabs :deep(.el-tabs__item.is-top:last-child) {
padding-left: 16px;
padding-right: 16px;
}
.profile-tabs :deep(.el-tabs__item.is-active) {
background: rgba(53, 109, 255, 0.1);
color: var(--el-color-primary);
}
@media (max-width: 768px) {
.profile-item-value {
max-width: 50%;
}
}
</style>
@@ -1,6 +1,6 @@
<template>
<div>
<el-table :data="devices" border style="width: 100%; height: 100%; font-size: 14px">
<div class="profile-table-wrap">
<el-table :data="devices" border class="data-table profile-device-table">
<el-table-column label="设备类型" align="center">
<template #default="scope">
<dict-tag :options="sys_device_type" :value="scope.row.deviceType" />
@@ -52,6 +52,12 @@ const handldDelOnline = (row: any) => {
proxy?.$modal.msgError(res.msg);
}
})
.catch(() => {});
.catch(() => {});
};
</script>
<style lang="scss" scoped>
.profile-table-wrap {
width: 100%;
}
</style>
+22 -3
View File
@@ -1,5 +1,5 @@
<template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px" class="profile-form">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item>
@@ -9,9 +9,9 @@
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
</el-form-item>
<el-form-item>
<el-form-item class="profile-form__actions">
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
<el-button @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>
@@ -71,3 +71,22 @@ const close = () => {
proxy?.$tab.closePage();
};
</script>
<style lang="scss" scoped>
.profile-form {
max-width: 520px;
}
.profile-form :deep(.el-input__wrapper) {
border-radius: 12px;
}
.profile-form :deep(.el-button) {
border-radius: 10px;
}
.profile-form__actions :deep(.el-form-item__content) {
display: flex;
gap: 8px;
}
</style>
+87 -35
View File
@@ -1,6 +1,6 @@
<template>
<div>
<el-table :data="auths" border style="width: 100%; height: 100%; font-size: 14px">
<div class="profile-auth">
<el-table :data="auths" border class="data-table profile-auth-table">
<el-table-column label="序号" width="50" type="index" />
<el-table-column label="绑定账号平台" width="140" align="center" prop="source" show-overflow-tooltip />
<el-table-column label="头像" width="120" align="center" prop="avatar">
@@ -12,43 +12,48 @@
<el-table-column label="绑定时间" width="180" align="center" prop="createTime" />
<el-table-column label="操作" width="80" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button size="small" type="text" @click="unlockAuth(scope.row)">解绑</el-button>
<el-tooltip content="解绑" placement="top">
<el-button link type="primary" icon="CircleClose" @click="unlockAuth(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<div id="git-user-binding">
<h4 class="provider-desc">你可以绑定以下第三方帐号</h4>
<div id="authlist" class="user-bind">
<div class="provider-section">
<div class="provider-heading">
<h4 class="provider-desc">可绑定的第三方应用</h4>
<p>点击下方平台完成账号绑定</p>
</div>
<div class="user-bind">
<a class="third-app" href="#" title="使用 微信 账号授权登录" @click="authUrl('wechat')">
<div class="git-other-login-icon">
<div class="third-app__icon">
<svg-icon icon-class="wechat" />
</div>
<span class="app-name">WeiXin</span>
<span class="app-name">微信</span>
</a>
<a class="third-app" href="#" title="使用 MaxKey 账号授权登录" @click="authUrl('maxkey')">
<div class="git-other-login-icon">
<div class="third-app__icon">
<svg-icon icon-class="maxkey" />
</div>
<span class="app-name">MaxKey</span>
</a>
<a class="third-app" href="#" title="使用 TopIam 账号授权登录" @click="authUrl('topiam')">
<div class="git-other-login-icon">
<div class="third-app__icon">
<svg-icon icon-class="topiam" />
</div>
<span class="app-name">TopIam</span>
</a>
<a class="third-app" href="#" title="使用 Gitee 账号授权登录" @click="authUrl('gitee')">
<div class="git-other-login-icon">
<div class="third-app__icon">
<svg-icon icon-class="gitee" />
</div>
<span class="app-name">Gitee</span>
</a>
<a class="third-app" href="#" title="使用 GitHub 账号授权登录" @click="authUrl('github')">
<div class="git-other-login-icon">
<div class="third-app__icon">
<svg-icon icon-class="github" />
</div>
<span class="app-name">Github</span>
<span class="app-name">GitHub</span>
</a>
</div>
</div>
@@ -94,44 +99,77 @@ const authUrl = (source: string) => {
</script>
<style lang="scss" scoped>
.user-bind .third-app {
display: -webkit-box;
display: -ms-flexbox;
.profile-auth {
display: flex;
flex-direction: column;
gap: 18px;
}
.profile-auth-table {
width: 100%;
}
.provider-section {
display: flex;
flex-direction: column;
gap: 14px;
}
.provider-heading p {
margin: 6px 0 0;
color: var(--el-text-color-secondary);
}
.user-bind .third-app {
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
min-width: 80px;
float: left;
justify-content: center;
gap: 8px;
min-height: 84px;
padding: 12px 10px;
border: 1px solid var(--app-surface-border);
border-radius: 12px;
background: rgba(248, 250, 252, 0.82);
transition:
transform 0.2s ease,
border-color 0.2s ease,
box-shadow 0.2s ease;
}
.user-bind {
font-size: 1rem;
text-align: start;
height: 50px;
margin-top: 10px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(96px, 108px));
gap: 10px;
justify-content: start;
}
.git-other-login-icon > img {
height: 32px;
.third-app:hover {
transform: translateY(-1px);
border-color: rgba(53, 109, 255, 0.3);
box-shadow: var(--app-shadow-sm);
}
.third-app__icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 10px;
background: rgba(53, 109, 255, 0.08);
font-size: 18px;
}
a {
text-decoration: none;
cursor: pointer;
color: #005980;
color: inherit;
}
.provider-desc {
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Liberation Sans',
'PingFang SC', 'Microsoft YaHei', 'Hiragino Sans GB', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti', SimHei, SimSun,
'WenQuanYi Zen Hei Sharp', sans-serif;
font-size: 1.071rem;
margin: 0;
font-size: 16px;
}
td > img {
@@ -141,4 +179,18 @@ td > img {
border-radius: 50%;
margin-right: 5px;
}
.app-name {
font-weight: 600;
font-size: 13px;
line-height: 1.2;
text-align: center;
word-break: break-word;
}
:global(html.dark) {
.user-bind .third-app {
background: rgba(15, 23, 42, 0.64);
}
}
</style>
+26 -1
View File
@@ -159,7 +159,18 @@ const closeDialog = () => {
.user-info-head {
position: relative;
display: inline-block;
width: 120px;
height: 120px;
cursor: pointer;
}
.user-info-head :deep(.img-circle) {
width: 120px;
height: 120px;
object-fit: cover;
border-radius: 50%;
border: 4px solid rgba(255, 255, 255, 0.92);
box-shadow: var(--app-shadow-sm);
}
.user-info-head:hover:after {
@@ -176,7 +187,21 @@ const closeDialog = () => {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
line-height: 110px;
line-height: 120px;
border-radius: 50%;
}
.avatar-upload-preview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
border-radius: 18px;
background: rgba(248, 250, 252, 0.9);
}
.avatar-upload-preview img {
max-width: 100%;
}
</style>
+26 -3
View File
@@ -1,5 +1,5 @@
<template>
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px" class="profile-form">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="userForm.nickName" maxlength="30" />
</el-form-item>
@@ -15,9 +15,9 @@
<el-radio value="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-form-item class="profile-form__actions">
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
<el-button @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>
@@ -67,3 +67,26 @@ const close = () => {
proxy?.$tab.closePage();
};
</script>
<style lang="scss" scoped>
.profile-form {
max-width: 520px;
}
.profile-form :deep(.el-input__wrapper) {
border-radius: 12px;
}
.profile-form :deep(.el-radio-group) {
gap: 16px;
}
.profile-form :deep(.el-button) {
border-radius: 10px;
}
.profile-form__actions :deep(.el-form-item__content) {
display: flex;
gap: 8px;
}
</style>