界面样式调整

master
zzy 2026-04-25 14:20:16 +08:00
parent 1b8c1bc0ef
commit 9e579d589b
15 changed files with 1058 additions and 597 deletions

2
.env
View File

@ -1,5 +1,5 @@
# 标题
VITE_APP_TITLE=智慧小区管理后
VITE_APP_TITLE=智慧小区
# 项目本地运行端口号
VITE_PORT=80

View File

@ -100,7 +100,8 @@ $prefix-cls: #{$elNamespace}-breadcrumb;
color: var(--top-header-text-color);
&:hover {
color: var(--el-color-primary);
color: #fff;
opacity: 0.8;
}
}
}
@ -110,7 +111,8 @@ $prefix-cls: #{$elNamespace}-breadcrumb;
color: var(--top-header-text-color);
&:hover {
color: var(--el-color-primary);
color: #fff;
opacity: 0.8;
}
}
}
@ -119,10 +121,10 @@ $prefix-cls: #{$elNamespace}-breadcrumb;
.#{$prefix-cls}__inner {
display: flex;
align-items: center;
color: var(--el-text-color-placeholder);
color: rgba(255, 255, 255, 0.65);
&:hover {
color: var(--el-text-color-placeholder);
color: rgba(255, 255, 255, 0.65);
}
}
}

View File

@ -66,10 +66,12 @@ watch(
]"
to="/"
>
<!-- <img-->
<!-- class="h-[calc(var(&#45;&#45;logo-height)-10px)] w-[calc(var(&#45;&#45;logo-height)-10px)]"-->
<!-- src="@/assets/imgs/logo.png"-->
<!-- />-->
<div class="flex items-center justify-center w-[40px] h-[40px] rounded-md bg-white/10">
<svg viewBox="0 0 1024 1024" width="28" height="28" fill="white">
<path d="M512 64L128 256v512l384 192 384-192V256L512 64zm0 72l304 152v448L512 888 208 736V288L512 136z"/>
<path d="M288 512h128l64-160 96 288 64-128h128" stroke="white" stroke-width="40" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div
v-if="show"
:class="[

View File

@ -57,13 +57,13 @@ export default defineComponent({
class={[
prefixCls,
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between',
'dark:bg-[var(--el-bg-color)]'
'bg-[#1677ff] text-white'
]}
>
{layout.value !== 'top' ? (
<div class="h-full flex items-center">
{hamburger.value && layout.value !== 'cutMenu' ? (
<Collapse class="custom-hover" color="var(--top-header-text-color)"></Collapse>
<Collapse class="custom-hover" color="#fff"></Collapse>
) : undefined}
{breadcrumb.value ? <Breadcrumb class="lt-md:hidden"></Breadcrumb> : undefined}
</div>
@ -71,20 +71,20 @@ export default defineComponent({
<div class="h-full flex items-center">
{hasTenantVisitPermission.value ? <TenantVisit /> : undefined}
{screenfull.value ? (
<Screenfull class="custom-hover" color="var(--top-header-text-color)"></Screenfull>
<Screenfull class="custom-hover" color="#fff"></Screenfull>
) : undefined}
{search.value ? <RouterSearch isModal={false} color="var(--top-header-text-color)"/> : undefined}
{search.value ? <RouterSearch isModal={false} color="#fff"/> : undefined}
{size.value ? (
<SizeDropdown class="custom-hover" color="var(--top-header-text-color)"></SizeDropdown>
<SizeDropdown class="custom-hover" color="#fff"></SizeDropdown>
) : undefined}
{locale.value ? (
<LocaleDropdown
class="custom-hover"
color="var(--top-header-text-color)"
color="#fff"
></LocaleDropdown>
) : undefined}
{message.value ? (
<Message class="custom-hover" color="var(--top-header-text-color)"></Message>
<Message class="custom-hover" color="#fff"></Message>
) : undefined}
<UserInfo></UserInfo>
</div>
@ -99,5 +99,20 @@ $prefix-cls: #{$namespace}-tool-header;
.#{$prefix-cls} {
transition: left var(--transition-time-02);
.custom-hover {
cursor: pointer;
transition: all 0.3s;
border-radius: 4px;
padding: 4px 8px;
&:hover {
background-color: rgba(255, 255, 255, 0.2);
}
}
:deep(.layout-border__right) {
border-right: none !important;
}
}
</style>

View File

@ -41,14 +41,14 @@ export const useRenderLayout = () => {
<>
<div
class={[
'absolute top-0 left-0 h-full layout-border__right',
'absolute top-0 left-0 h-full',
{ '!fixed z-3000': mobile.value }
]}
>
{logo.value ? (
<Logo
class={[
'bg-[var(--left-menu-bg-color)] relative',
'bg-[#1677ff] relative',
{
'!pl-0': mobile.value && collapse.value,
'w-[var(--left-menu-min-width)]': appStore.getCollapse,
@ -99,7 +99,7 @@ export const useRenderLayout = () => {
>
<ToolHeader
class={[
'bg-[var(--top-header-bg-color)]',
'bg-[#1677ff]',
{
'layout-border__bottom': !tagsView.value
}

View File

@ -5,31 +5,31 @@
--left-menu-min-width: 64px;
--left-menu-bg-color: #001529;
--left-menu-bg-color: #ffffff !important;
--left-menu-bg-light-color: #0f2438;
--left-menu-bg-light-color: #f5f7fa !important;
--left-menu-bg-active-color: var(--el-color-primary);
--left-menu-bg-active-color: #e6f7ff !important;
--left-menu-text-color: #bfcbd9;
--left-menu-text-color: #333333 !important;
--left-menu-text-active-color: #fff;
--left-menu-text-active-color: #1677ff !important;
--left-menu-collapse-bg-active-color: var(--el-color-primary);
--left-menu-collapse-bg-active-color: #1677ff !important;
/* left menu end */
/* logo start */
--logo-height: 50px;
--logo-height: 70px;
--logo-title-text-color: #fff;
/* logo end */
/* header start */
--top-header-bg-color: '#fff';
--top-header-bg-color: #1677ff !important;
--top-header-text-color: 'inherit';
--top-header-text-color: #fff !important;
--top-header-hover-color: #f6f6f6;
--top-header-hover-color: rgba(255, 255, 255, 0.2);
--top-tool-height: var(--logo-height);

View File

@ -1,6 +1,7 @@
<template>
<div>
<el-card shadow="never">
<div class="home-container">
<!-- 欢迎区域 -->
<el-card shadow="never" class="welcome-card">
<el-skeleton :loading="loading" animated>
<el-row :gutter="16" justify="space-between">
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
@ -10,10 +11,10 @@
</el-avatar>
<div>
<div class="text-20px">
{{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }}
你好 {{ username }} 祝你开心每一天!
</div>
<div class="mt-10px text-14px text-gray-500">
{{ t('workplace.toady') }}20 - 32
今日晴20 - 32
</div>
</div>
</div>
@ -21,7 +22,7 @@
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
<div class="h-70px flex items-center justify-end lt-sm:mt-10px">
<div class="px-8px text-right">
<div class="mb-16px text-14px text-gray-400">{{ t('workplace.project') }}</div>
<div class="mb-16px text-14px text-gray-400">项目数</div>
<CountTo
class="text-20px"
:start-val="0"
@ -31,7 +32,7 @@
</div>
<el-divider direction="vertical" />
<div class="px-8px text-right">
<div class="mb-16px text-14px text-gray-400">{{ t('workplace.toDo') }}</div>
<div class="mb-16px text-14px text-gray-400">待办</div>
<CountTo
class="text-20px"
:start-val="0"
@ -41,7 +42,7 @@
</div>
<el-divider direction="vertical" border-style="dashed" />
<div class="px-8px text-right">
<div class="mb-16px text-14px text-gray-400">{{ t('workplace.access') }}</div>
<div class="mb-16px text-14px text-gray-400">项目访问</div>
<CountTo
class="text-20px"
:start-val="0"
@ -54,21 +55,17 @@
</el-row>
</el-skeleton>
</el-card>
</div>
<!-- 主要内容区域 -->
<el-row class="mt-8px" :gutter="8" justify="space-between">
<el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px">
<!-- 小区项目列表 -->
<el-card shadow="never">
<template #header>
<div class="h-3 flex justify-between">
<span>{{ t('workplace.project') }}</span>
<el-link
type="primary"
:underline="false"
href="https://github.com/yudaocode"
target="_blank"
>
{{ t('action.more') }}
<span>项目数</span>
<el-link type="primary" :underline="false" @click="handleMoreClick">
更多
</el-link>
</div>
</template>
@ -86,7 +83,7 @@
<el-card
shadow="hover"
class="mr-5px mt-5px cursor-pointer"
@click="handleProjectClick(item.message)"
@click="handleProjectClick(item)"
>
<div class="flex items-center">
<Icon
@ -97,9 +94,9 @@
/>
<span class="text-16px">{{ item.name }}</span>
</div>
<div class="mt-12px text-12px text-gray-400">{{ t(item.message) }}</div>
<div class="mt-12px text-12px text-gray-400">{{ item.description }}</div>
<div class="mt-12px flex justify-between text-12px text-gray-400">
<span>{{ item.personal }}</span>
<span>{{ item.location }}</span>
<span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>
</div>
</el-card>
@ -108,6 +105,7 @@
</el-skeleton>
</el-card>
<!-- 图表区域 -->
<el-card shadow="never" class="mt-8px">
<el-skeleton :loading="loading" animated>
<el-row :gutter="20" justify="space-between">
@ -129,11 +127,14 @@
</el-skeleton>
</el-card>
</el-col>
<!-- 右侧区域 -->
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">
<!-- 快捷入口 -->
<el-card shadow="never">
<template #header>
<div class="h-3 flex justify-between">
<span>{{ t('workplace.shortcutOperation') }}</span>
<span>快捷入口</span>
</div>
</template>
<el-skeleton :loading="loading" animated>
@ -149,58 +150,61 @@
</el-row>
</el-skeleton>
</el-card>
<!-- 通知公告 -->
<el-card shadow="never" class="mt-8px">
<template #header>
<div class="h-3 flex justify-between">
<span>{{ t('workplace.notice') }}</span>
<el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>
<span>通知公告</span>
<el-link type="primary" :underline="false" @click="handleNoticeMoreClick"></el-link>
</div>
</template>
<el-skeleton :loading="loading" animated>
<div v-for="(item, index) in notice" :key="`dynamics-${index}`">
<div class="flex items-center">
<div class="flex items-start">
<el-avatar :src="avatar" :size="35" class="mr-16px">
<img src="@/assets/imgs/avatar.gif" alt="" />
</el-avatar>
<div>
<div class="flex-1">
<div class="text-14px">
<Highlight :keys="item.keys.map((v) => t(v))">
{{ item.type }} : {{ item.title }}
</Highlight>
<span class="text-gray-800">{{ item.type }}</span>
<span class="text-gray-600">{{ item.title }}</span>
</div>
<div class="mt-16px text-12px text-gray-400">
<div class="mt-8px text-12px text-gray-400">
{{ formatTime(item.date, 'yyyy-MM-dd') }}
</div>
</div>
</div>
<el-divider />
<el-divider v-if="index < notice.length - 1" />
</div>
</el-skeleton>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import { set } from 'lodash-es'
import { EChartsOption } from 'echarts'
import { formatTime } from '@/utils'
import { useUserStore } from '@/store/modules/user'
// import { useWatermark } from '@/hooks/web/useWatermark'
import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
import { pieOptions, barOptions } from './echarts-data'
import { useRouter } from 'vue-router'
import { CommunityApi, Community } from '@/api/community/community'
import { NoticeApi, Notice as NoticeInfo } from '@/api/community/notice'
defineOptions({ name: 'Index' })
const { t } = useI18n()
const router = useRouter()
const userStore = useUserStore()
// const { setWatermark } = useWatermark()
const loading = ref(true)
const avatar = userStore.getUser.avatar
const username = userStore.getUser.nickname
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
//
let totalSate = reactive<WorkplaceTotal>({
project: 0,
@ -209,100 +213,57 @@ let totalSate = reactive<WorkplaceTotal>({
})
const getCount = async () => {
const data = {
project: 40,
access: 2340,
todo: 10
try {
const data = await CommunityApi.getCommunitySimpleList()
totalSate.project = data.length
totalSate.access = 2340
totalSate.todo = 10
} catch (error) {
console.error('获取小区数量失败:', error)
}
totalSate = Object.assign(totalSate, data)
}
//
//
let projects = reactive<Project[]>([])
const getProject = async () => {
const data = [
{
name: 'ruoyi-vue-pro',
icon: 'simple-icons:springboot',
message: 'github.com/YunaiV/ruoyi-vue-pro',
personal: 'Spring Boot 单体架构',
time: new Date('2025-01-02'),
color: '#6DB33F'
},
{
name: 'yudao-ui-admin-vue3',
icon: 'ep:element-plus',
message: 'github.com/yudaocode/yudao-ui-admin-vue3',
personal: 'Vue3 + element-plus 管理后台',
time: new Date('2025-02-03'),
try {
const data = await CommunityApi.getCommunityPage({
pageNo: 1,
pageSize: 100
})
projects = data.list.map((item: Community) => ({
name: item.communityName || '',
icon: 'ep:house',
description: item.streetName || item.districtName || '智慧社区',
location: item.communityAddress || '',
time: new Date(),
color: '#409EFF'
},
{
name: 'yudao-ui-mall-uniapp',
icon: 'icon-park-outline:mall-bag',
message: 'github.com/yudaocode/yudao-ui-mall-uniapp',
personal: 'Vue3 + uniapp 商城手机端',
time: new Date('2025-03-04'),
color: '#ff4d4f'
},
{
name: 'yudao-cloud',
icon: 'material-symbols:cloud-outline',
message: 'github.com/YunaiV/yudao-cloud',
personal: 'Spring Cloud 微服务架构',
time: new Date('2025-04-05'),
color: '#1890ff'
},
{
name: 'yudao-ui-admin-vben',
icon: 'devicon:antdesign',
message: 'github.com/yudaocode/yudao-ui-admin-vben',
personal: 'Vue3 + vben5(antd) 管理后台',
time: new Date('2025-05-06'),
color: '#e18525'
},
{
name: 'yudao-ui-admin-uniapp',
icon: 'ant-design:mobile',
message: 'github.com/yudaocode/yudao-ui-admin-uniapp',
personal: 'Vue3 + uniapp 管理手机端',
time: new Date('2025-06-01'),
color: '#2979ff'
}))
} catch (error) {
console.error('获取小区列表失败:', error)
}
]
projects = Object.assign(projects, data)
}
//
let notice = reactive<Notice[]>([])
const getNotice = async () => {
const data = [
{
title: '系统支持 JDK 8/17/21Vue 2/3',
type: '技术兼容性',
keys: ['JDK', 'Vue'],
date: new Date()
},
{
title: '后端提供 Spring Boot 2.7/3.2 + Cloud 双架构',
type: '架构灵活性',
keys: ['Boot', 'Cloud'],
date: new Date()
},
{
title: '全部开源,个人与企业可 100% 直接使用,无需授权',
type: '开源免授权',
keys: ['无需授权'],
date: new Date()
},
{
title: '国内使用最广泛的快速开发平台,远超 10w+ 企业使用',
type: '广泛企业认可',
keys: ['最广泛', '10w+'],
date: new Date()
try {
const data = await NoticeApi.getNoticePage({
pageNo: 1,
pageSize: 4,
status: 1
})
notice = data.list.map((item: NoticeInfo) => ({
title: item.title || '',
type: item.publisher || '系统通知',
keys: [item.title || ''],
date: new Date(item.createTime || '')
}))
} catch (error) {
console.error('获取通知公告失败:', error)
}
]
notice = Object.assign(notice, data)
}
//
@ -311,87 +272,88 @@ let shortcut = reactive<Shortcut[]>([])
const getShortcut = async () => {
const data = [
{
name: '首页',
icon: 'ion:home-outline',
url: '/',
color: '#1fdaca'
name: '社区动态',
icon: 'ep:document',
url: '/operation/post',
color: '#1677ff'
},
{
name: '商城中心',
icon: 'ep:shop',
url: '/mall/home',
name: '通知公告',
icon: 'ep:bell',
url: '/operation/notice',
color: '#ff6b6b'
},
{
name: 'AI 大模型',
icon: 'tabler:ai',
url: '/ai/chat',
name: '知识课堂',
icon: 'ep:reading',
url: '/operation/knowledge-class',
color: '#7c3aed'
},
{
name: 'ERP 系统',
icon: 'simple-icons:erpnext',
url: '/erp/home',
name: '小区活动',
icon: 'ep:calendar',
url: '/operation/activity',
color: '#3fb27f'
},
{
name: 'CRM 系统',
icon: 'simple-icons:civicrm',
url: '/crm/backlog',
name: '小区管理',
icon: 'ep:office-building',
url: '/system/community',
color: '#4daf1bc9'
},
{
name: 'IoT 物联网',
icon: 'fa-solid:hdd',
url: '/iot/home',
name: 'Banner管理',
icon: 'ep:picture',
url: '/system/banner',
color: '#1a73e8'
}
]
shortcut = Object.assign(shortcut, data)
}
//
// 访
const getUserAccessSource = async () => {
const data = [
{ value: 335, name: 'analysis.directAccess' },
{ value: 310, name: 'analysis.mailMarketing' },
{ value: 234, name: 'analysis.allianceAdvertising' },
{ value: 135, name: 'analysis.videoAdvertising' },
{ value: 1548, name: 'analysis.searchEngines' }
{ value: 335, name: '直接访问' },
{ value: 310, name: '邮件营销' },
{ value: 234, name: '联盟广告' },
{ value: 135, name: '视频广告' },
{ value: 1548, name: '搜索引擎' }
]
set(
pieOptionsData,
'legend.data',
data.map((v) => t(v.name))
data.map((v) => v.name)
)
pieOptionsData!.series![0].data = data.map((v) => {
return {
name: t(v.name),
name: v.name,
value: v.value
}
})
}
const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
//
const getWeeklyUserActivity = async () => {
const data = [
{ value: 13253, name: 'analysis.monday' },
{ value: 34235, name: 'analysis.tuesday' },
{ value: 26321, name: 'analysis.wednesday' },
{ value: 12340, name: 'analysis.thursday' },
{ value: 24643, name: 'analysis.friday' },
{ value: 1322, name: 'analysis.saturday' },
{ value: 1324, name: 'analysis.sunday' }
{ value: 13253, name: '周一' },
{ value: 34235, name: '周二' },
{ value: 26321, name: '周三' },
{ value: 12340, name: '周四' },
{ value: 24643, name: '周五' },
{ value: 1322, name: '周六' },
{ value: 1324, name: '周日' }
]
set(
barOptionsData,
'xAxis.data',
data.map((v) => t(v.name))
data.map((v) => v.name)
)
set(barOptionsData, 'series', [
{
name: t('analysis.activeQuantity'),
name: '活跃用户',
data: data.map((v) => v.value),
type: 'bar'
}
@ -410,13 +372,34 @@ const getAllApi = async () => {
loading.value = false
}
const handleProjectClick = (message: string) => {
window.open(`https://${message}`, '_blank')
const handleProjectClick = (item: Project) => {
// TODO:
console.log('点击小区:', item.name)
}
const handleShortcutClick = (url: string) => {
router.push(url)
}
const handleMoreClick = () => {
router.push('/system/community')
}
const handleNoticeMoreClick = () => {
router.push('/operation/notice')
}
getAllApi()
</script>
<style lang="scss" scoped>
.home-container {
padding: 0;
}
.welcome-card {
:deep(.el-card__body) {
padding: 20px;
}
}
</style>

View File

@ -1,107 +1,462 @@
<template>
<div
:class="prefixCls"
class="relative h-[100%] lt-md:px-10px lt-sm:px-10px lt-xl:px-10px lt-xl:px-10px"
>
<div class="relative mx-auto h-full flex">
<div
:class="`${prefixCls}__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px lt-xl:hidden overflow-x-hidden overflow-y-auto`"
>
<!-- 左上角的 logo + 系统标题 -->
<div class="relative flex items-center text-white">
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
</div>
<!-- 左边的背景图 + 欢迎语 -->
<div class="h-[calc(100%-60px)] flex items-center justify-center">
<TransitionGroup
appear
enter-active-class="animate__animated animate__bounceInLeft"
tag="div"
>
<img key="1" alt="" class="w-350px" src="@/assets/svgs/login-box-bg.svg" />
<div key="2" class="text-3xl text-white">{{ t('login.welcome') }}</div>
<div key="3" class="mt-5 text-14px font-normal text-white">
{{ t('login.message') }}
</div>
</TransitionGroup>
<div :class="prefixCls" class="login-container">
<div class="login-content">
<!-- 登录卡片 -->
<div class="login-card">
<!-- Logo 图标 -->
<div class="login-logo">
<div class="logo-icon">
<svg viewBox="0 0 1024 1024" width="60" height="60">
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372S306.6 140 512 140s372 166.6 372 372-166.6 372-372 372z"
fill="#1677ff"
/>
<path
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
fill="#1677ff"
/>
</svg>
</div>
</div>
<div
class="relative flex-1 p-30px dark:bg-[var(--login-bg-color)] lt-sm:p-10px overflow-x-hidden overflow-y-auto"
<!-- 标题 -->
<h2 class="login-title">智慧小区云平台</h2>
<!-- 登录表单 -->
<el-form
ref="formLogin"
:model="loginData.loginForm"
:rules="LoginRules"
class="login-form"
size="large"
>
<!-- 右上角的主题语言选择 -->
<div
class="flex items-center justify-between at-2xl:justify-end at-xl:justify-end"
style="color: var(--el-text-color-primary);"
<el-form-item prop="username">
<el-input
v-model="loginData.loginForm.username"
placeholder="请输入用户名称"
:prefix-icon="iconAvatar"
@blur="handleUsernameBlur"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginData.loginForm.password"
placeholder="请输入登录密码"
:prefix-icon="iconLock"
show-password
type="password"
@keyup.enter="getCode()"
@blur="handlePasswordBlur"
/>
</el-form-item>
<!-- 租户选择 -->
<el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantId">
<el-select
ref="tenantSelectRef"
v-model="loginData.loginForm.tenantId"
placeholder="请选择租户"
:prefix-icon="iconHouse"
style="width: 100%"
:disabled="tenantList.length === 0"
>
<div class="flex items-center at-2xl:hidden at-xl:hidden">
<span class="text-20px font-bold" >{{ underlineToHump(appStore.getTitle) }}</span>
<el-option
v-for="tenant in tenantList"
:key="tenant.tenantId"
:label="tenant.tenantName"
:value="tenant.tenantId"
/>
</el-select>
</el-form-item>
<!-- 记住密码 -->
<div class="login-options">
<el-checkbox v-model="loginData.loginForm.rememberMe">
记住密码
</el-checkbox>
</div>
<div class="flex items-center justify-end space-x-10px h-48px">
<!-- 登录按钮 -->
<el-form-item>
<el-button
:loading="loginLoading"
type="primary"
class="login-button"
@click="getCode()"
>
登录
</el-button>
</el-form-item>
</el-form>
</div>
<!-- 右侧插图 -->
<div class="login-illustration">
<img src="@/assets/svgs/login-box-bg.svg" alt="illustration" />
</div>
</div>
<!-- 主题和语言切换 -->
<div class="login-tools">
<ThemeSwitch />
<LocaleDropdown />
</div>
</div>
<!-- 右边的登录界面 -->
<Transition appear enter-active-class="animate__animated animate__bounceInRight">
<div
class="m-auto h-[calc(100%-60px)] w-[100%] flex items-center at-2xl:max-w-500px at-lg:max-w-500px at-md:max-w-500px at-xl:max-w-500px"
>
<!-- 账号登录 -->
<LoginForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
<!-- 手机登录 -->
<MobileForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
<!-- 二维码登录 -->
<QrCodeForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
<!-- 注册 -->
<RegisterForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
<!-- 三方登录 -->
<SSOLoginVue class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
<!-- 忘记密码 -->
<ForgetPasswordForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
</div>
</Transition>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { underlineToHump } from '@/utils'
import { useDesign } from '@/hooks/web/useDesign'
import { useAppStore } from '@/store/modules/app'
import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm } from './components'
import { useIcon } from '@/hooks/web/useIcon'
import * as authUtil from '@/utils/auth'
import { usePermissionStore } from '@/store/modules/permission'
import * as LoginApi from '@/api/login'
import { ElLoading } from 'element-plus'
defineOptions({ name: 'Login' })
const { t } = useI18n()
const message = useMessage()
const appStore = useAppStore()
const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('login')
const iconHouse = useIcon({ icon: 'ep:house' })
const iconAvatar = useIcon({ icon: 'ep:avatar' })
const iconLock = useIcon({ icon: 'ep:lock' })
const formLogin = ref()
const loginLoading = ref(false)
const captchaType = ref('blockPuzzle')
const tenantList = ref<LoginApi.TenantInfo[]>([])
const tenantSelectRef = ref()
const isFetchingTenants = ref(false)
const LoginRules = {
username: [required],
password: [required],
tenantId: [
{
required: true,
message: '请选择租户',
trigger: 'change'
}
]
}
const loginData = reactive({
captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE,
tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE,
loginForm: {
tenantId: undefined as number | undefined,
username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME || '',
password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD || '',
captchaVerification: '',
rememberMe: true
}
})
const verify = ref()
const loading = ref()
const { push } = useRouter()
const permissionStore = usePermissionStore()
//
const handleUsernameBlur = async () => {
if (loginData.tenantEnable !== 'true') {
return
}
await fetchTenantList()
}
//
const handlePasswordBlur = async () => {
if (loginData.tenantEnable !== 'true') {
return
}
await fetchTenantList()
}
//
const fetchTenantList = async () => {
const username = loginData.loginForm.username?.trim()
const password = loginData.loginForm.password?.trim()
if (!username || !password) {
return
}
if (isFetchingTenants.value) {
return
}
isFetchingTenants.value = true
try {
const res = await LoginApi.getUserTenantList({
username,
password
})
if (!res || !res.tenants || res.tenants.length === 0) {
message.error('无权限访问该系统')
tenantList.value = []
loginData.loginForm.tenantId = undefined
return
}
tenantList.value = res.tenants
if (res.tenants.length === 1) {
loginData.loginForm.tenantId = res.tenants[0].tenantId
} else {
loginData.loginForm.tenantId = undefined
}
} catch (error) {
console.error('获取租户列表失败:', error)
tenantList.value = []
loginData.loginForm.tenantId = undefined
} finally {
isFetchingTenants.value = false
}
}
//
const getCode = async () => {
if (loginData.tenantEnable === 'true' && tenantList.value.length === 0) {
const username = loginData.loginForm.username?.trim()
const password = loginData.loginForm.password?.trim()
if (!username || !password) {
message.error('请输入用户名和密码')
return
}
await fetchTenantList()
if (tenantList.value.length === 0) {
return
}
if (tenantList.value.length === 1) {
loginData.loginForm.tenantId = tenantList.value[0].tenantId
continueLogin()
} else {
if (tenantSelectRef.value) {
tenantSelectRef.value.visible = true
}
message.info('请选择要登录的租户')
}
} else if (loginData.tenantEnable === 'true' && tenantList.value.length > 0) {
if (!loginData.loginForm.tenantId) {
message.error('请选择租户')
return
}
continueLogin()
} else {
continueLogin()
}
}
const continueLogin = () => {
if (loginData.captchaEnable === 'false') {
handleLogin({})
} else {
verify.value?.show()
}
}
const setTenantId = () => {
if (loginData.loginForm.tenantId) {
authUtil.setTenantId(loginData.loginForm.tenantId)
}
}
const getLoginFormCache = () => {
const loginForm = authUtil.getLoginForm()
if (loginForm) {
loginData.loginForm = {
...loginData.loginForm,
username: loginForm.username ? loginForm.username : loginData.loginForm.username,
password: loginForm.password ? loginForm.password : loginData.loginForm.password,
rememberMe: loginForm.rememberMe
}
}
}
const getTenantByWebsite = async () => {
if (loginData.tenantEnable === 'true') {
const website = location.host
const res = await LoginApi.getTenantByWebsite(website)
if (res) {
authUtil.setTenantId(res.id)
}
}
}
const handleLogin = async (params: any) => {
loginLoading.value = true
try {
setTenantId()
await formLogin.value.validate()
const loginDataLoginForm = { ...loginData.loginForm }
loginDataLoginForm.captchaVerification = params.captchaVerification
const res = await LoginApi.login(loginDataLoginForm)
if (!res) {
return
}
loading.value = ElLoading.service({
lock: true,
text: '正在加载系统中...',
background: 'rgba(0, 0, 0, 0.7)'
})
if (loginDataLoginForm.rememberMe) {
authUtil.setLoginForm(loginDataLoginForm)
} else {
authUtil.removeLoginForm()
}
authUtil.setToken(res)
await push({ path: '/' })
} finally {
loginLoading.value = false
loading.value?.close()
}
}
onMounted(() => {
getLoginFormCache()
getTenantByWebsite()
})
</script>
<style lang="scss" scoped>
$prefix-cls: #{$namespace}-login;
.#{$prefix-cls} {
overflow: auto;
&__left {
&::before {
position: absolute;
top: 0;
left: 0;
z-index: -1;
.login-container {
position: relative;
width: 100%;
height: 100%;
background-image: url('@/assets/svgs/login-bg.svg');
background-position: center;
background-repeat: no-repeat;
content: '';
height: 100vh;
background: #1677ff;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.login-content {
display: flex;
align-items: center;
justify-content: center;
gap: 100px;
max-width: 1200px;
width: 100%;
padding: 0 40px;
}
.login-card {
background: #ffffff;
border-radius: 8px;
padding: 40px;
width: 380px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.login-logo {
display: flex;
justify-content: center;
margin-bottom: 16px;
.logo-icon {
width: 60px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
}
}
.login-title {
text-align: center;
font-size: 24px;
font-weight: 600;
color: #1677ff;
margin: 0 0 30px 0;
}
.login-form {
:deep(.el-input__wrapper) {
border-radius: 4px;
}
:deep(.el-select .el-input__wrapper) {
border-radius: 4px;
}
}
.login-options {
margin-bottom: 20px;
:deep(.el-checkbox__label) {
color: #1677ff;
font-size: 14px;
}
}
.login-button {
width: 100%;
height: 44px;
font-size: 16px;
background: #1677ff;
border: none;
border-radius: 4px;
&:hover {
background: #4096ff;
}
}
.login-illustration {
flex-shrink: 0;
img {
width: 500px;
height: auto;
}
}
.login-tools {
position: absolute;
top: 20px;
right: 20px;
display: flex;
gap: 12px;
align-items: center;
:deep(svg) {
fill: #ffffff;
}
}
@media (max-width: 1200px) {
.login-illustration {
display: none;
}
.login-content {
justify-content: center;
}
}
@media (max-width: 480px) {
.login-card {
width: 100%;
padding: 30px 20px;
}
.login-content {
padding: 0 20px;
}
}
</style>

View File

@ -33,30 +33,31 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 查询
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['system:dept:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
</el-button>
<el-button type="danger" plain @click="toggleExpandAll">
<el-button type="primary" plain @click="toggleExpandAll">
<Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
</el-button>
<el-button
type="danger"
plain
:disabled="checkedIds.length === 0"
@click="handleDeleteBatch"
v-hasPermi="['system:dept:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
</el-form-item>
</el-form>
</div>
</ContentWrap>
<!-- 列表 -->
@ -68,16 +69,31 @@
:default-expand-all="isExpandAll"
v-if="refreshTable"
@selection-change="handleRowCheckboxChange"
:header-cell-style="{
background: '#1890ff',
color: '#ffffff',
textAlign: 'center',
fontWeight: 'normal',
fontSize: '14px',
borderColor: '#1890ff'
}"
:cell-style="{
textAlign: 'center',
fontSize: '14px',
color: '#333333',
borderColor: '#ebeef5'
}"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="部门名称" />
<el-table-column prop="leader" label="负责人">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column prop="name" label="部门名称" min-width="150" />
<el-table-column prop="leader" label="负责人" width="120">
<template #default="scope">
{{ userList.find((user) => user.id === scope.row.leaderUserId)?.nickname }}
</template>
</el-table-column>
<el-table-column prop="sort" label="排序" />
<el-table-column prop="status" label="状态">
<el-table-column prop="sort" label="排序" width="80" />
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
@ -89,7 +105,7 @@
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center">
<el-table-column label="操作" align="center" width="120px" fixed="right">
<template #default="scope">
<el-button
link
@ -97,7 +113,7 @@
@click="openForm('update', scope.row.id)"
v-hasPermi="['system:dept:update']"
>
修改
编辑
</el-button>
<el-button
link

View File

@ -37,18 +37,29 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 查询
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['system:dict:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
</el-button>
<el-button
type="success"
type="primary"
plain
@click="handleExport"
:loading="exportLoading"
@ -56,35 +67,46 @@
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
<el-button
type="danger"
plain
:disabled="checkedIds.length === 0"
@click="handleDeleteBatch"
v-hasPermi="['system:dict:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
</el-form-item>
</el-form>
</div>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange">
<el-table-column type="selection" width="55" />
<el-table-column label="字典编码" align="center" prop="id" />
<el-table-column label="字典标签" align="center" prop="label" />
<el-table-column label="字典键值" align="center" prop="value" />
<el-table-column label="字典排序" align="center" prop="sort" />
<el-table-column label="状态" align="center" prop="status">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleRowCheckboxChange"
:header-cell-style="{
background: '#1890ff',
color: '#ffffff',
textAlign: 'center',
fontWeight: 'normal',
fontSize: '14px',
borderColor: '#1890ff'
}"
:cell-style="{
textAlign: 'center',
fontSize: '14px',
color: '#333333',
borderColor: '#ebeef5'
}"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column label="字典编码" align="center" prop="id" width="100" />
<el-table-column label="字典标签" align="center" prop="label" min-width="120" />
<el-table-column label="字典键值" align="center" prop="value" width="120" />
<el-table-column label="字典排序" align="center" prop="sort" width="100" />
<el-table-column label="状态" align="center" prop="status" width="80">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="颜色类型" align="center" prop="colorType" />
<el-table-column label="CSS Class" align="center" prop="cssClass" />
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
<el-table-column label="颜色类型" align="center" prop="colorType" width="100" />
<el-table-column label="CSS Class" align="center" prop="cssClass" width="120" />
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip min-width="150" />
<el-table-column
label="创建时间"
align="center"
@ -92,7 +114,7 @@
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center">
<el-table-column label="操作" align="center" width="120px" fixed="right">
<template #default="scope">
<el-button
link
@ -100,7 +122,7 @@
@click="openForm('update', scope.row.id)"
v-hasPermi="['system:dict:update']"
>
修改
编辑
</el-button>
<el-button
link

View File

@ -53,60 +53,73 @@
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
搜索
<el-button type="primary" @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" /> 查询
</el-button>
<el-button @click="resetQuery">
<Icon class="mr-5px" icon="ep:refresh" />
重置
<Icon class="mr-5px" icon="ep:refresh" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button
v-hasPermi="['system:dict:create']"
plain
type="primary"
@click="openForm('create')"
>
<Icon class="mr-5px" icon="ep:plus" />
新增
<Icon class="mr-5px" icon="ep:plus" /> 新建
</el-button>
<el-button
v-hasPermi="['system:dict:export']"
:loading="exportLoading"
plain
type="success"
type="primary"
@click="handleExport"
>
<Icon class="mr-5px" icon="ep:download" />
导出
<Icon class="mr-5px" icon="ep:download" /> 导出
</el-button>
<el-button
v-hasPermi="['system:dict:delete']"
:disabled="checkedIds.length === 0"
plain
type="danger"
@click="handleDeleteBatch"
>
<Icon class="mr-5px" icon="ep:delete" />
批量删除
</el-button>
</el-form-item>
</el-form>
</div>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange">
<el-table-column type="selection" width="55" />
<el-table-column align="center" label="字典编号" prop="id" />
<el-table-column align="center" label="字典名称" prop="name" show-overflow-tooltip />
<el-table-column align="center" label="字典类型" prop="type" width="300" />
<el-table-column align="center" label="状态" prop="status">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleRowCheckboxChange"
:header-cell-style="{
background: '#1890ff',
color: '#ffffff',
textAlign: 'center',
fontWeight: 'normal',
fontSize: '14px',
borderColor: '#1890ff'
}"
:cell-style="{
textAlign: 'center',
fontSize: '14px',
color: '#333333',
borderColor: '#ebeef5'
}"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column align="center" label="字典编号" prop="id" width="100" />
<el-table-column align="center" label="字典名称" prop="name" show-overflow-tooltip min-width="150" />
<el-table-column align="center" label="字典类型" prop="type" width="200" />
<el-table-column align="center" label="状态" prop="status" width="80">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column align="center" label="备注" prop="remark" />
<el-table-column align="center" label="备注" prop="remark" min-width="150" />
<el-table-column
:formatter="dateFormatter"
align="center"
@ -114,7 +127,7 @@
prop="createTime"
width="180"
/>
<el-table-column align="center" label="操作">
<el-table-column align="center" label="操作" width="180px" fixed="right">
<template #default="scope">
<el-button
v-hasPermi="['system:dict:update']"
@ -122,7 +135,7 @@
type="primary"
@click="openForm('update', scope.row.id)"
>
修改
编辑
</el-button>
<router-link :to="'/dict/type/data/' + scope.row.type">
<el-button link type="primary">数据</el-button>

View File

@ -33,33 +33,34 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
搜索
<el-button type="primary" @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" /> 查询
</el-button>
<el-button @click="resetQuery">
<Icon class="mr-5px" icon="ep:refresh" />
重置
<Icon class="mr-5px" icon="ep:refresh" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button
v-hasPermi="['system:menu:create']"
plain
type="primary"
@click="openForm('create')"
>
<Icon class="mr-5px" icon="ep:plus" />
新增
<Icon class="mr-5px" icon="ep:plus" /> 新建
</el-button>
<el-button plain type="danger" @click="toggleExpandAll">
<Icon class="mr-5px" icon="ep:sort" />
展开/折叠
<el-button plain type="primary" @click="toggleExpandAll">
<Icon class="mr-5px" icon="ep:sort" /> 展开/折叠
</el-button>
<el-button plain @click="refreshMenu">
<Icon class="mr-5px" icon="ep:refresh" />
刷新菜单缓存
<el-button plain type="primary" @click="refreshMenu">
<Icon class="mr-5px" icon="ep:refresh" /> 刷新菜单缓存
</el-button>
</el-form-item>
</el-form>
</div>
</ContentWrap>
<!-- 列表 -->

View File

@ -37,18 +37,29 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 查询
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['system:post:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
</el-button>
<el-button
type="success"
type="primary"
plain
@click="handleExport"
:loading="exportLoading"
@ -56,29 +67,40 @@
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
<el-button
type="danger"
plain
:disabled="checkedIds.length === 0"
@click="handleDeleteBatch"
v-hasPermi="['system:post:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
</el-form-item>
</el-form>
</div>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange">
<el-table-column type="selection" width="55" />
<el-table-column label="岗位编号" align="center" prop="id" />
<el-table-column label="岗位名称" align="center" prop="name" />
<el-table-column label="岗位编码" align="center" prop="code" />
<el-table-column label="岗位顺序" align="center" prop="sort" />
<el-table-column label="岗位备注" align="center" prop="remark" />
<el-table-column label="状态" align="center" prop="status">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleRowCheckboxChange"
:header-cell-style="{
background: '#1890ff',
color: '#ffffff',
textAlign: 'center',
fontWeight: 'normal',
fontSize: '14px',
borderColor: '#1890ff'
}"
:cell-style="{
textAlign: 'center',
fontSize: '14px',
color: '#333333',
borderColor: '#ebeef5'
}"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column label="岗位编号" align="center" prop="id" width="100" />
<el-table-column label="岗位名称" align="center" prop="name" min-width="120" />
<el-table-column label="岗位编码" align="center" prop="code" width="120" />
<el-table-column label="岗位顺序" align="center" prop="sort" width="100" />
<el-table-column label="岗位备注" align="center" prop="remark" min-width="150" />
<el-table-column label="状态" align="center" prop="status" width="80">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
@ -90,7 +112,7 @@
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center">
<el-table-column label="操作" align="center" width="120px" fixed="right">
<template #default="scope">
<el-button
link

View File

@ -48,62 +48,75 @@
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
搜索
<el-button type="primary" @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" /> 查询
</el-button>
<el-button @click="resetQuery">
<Icon class="mr-5px" icon="ep:refresh" />
重置
<Icon class="mr-5px" icon="ep:refresh" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button
v-hasPermi="['system:role:create']"
plain
type="primary"
@click="openForm('create')"
>
<Icon class="mr-5px" icon="ep:plus" />
新增
<Icon class="mr-5px" icon="ep:plus" /> 新建
</el-button>
<el-button
v-hasPermi="['system:role:export']"
:loading="exportLoading"
plain
type="success"
type="primary"
@click="handleExport"
>
<Icon class="mr-5px" icon="ep:download" />
导出
<Icon class="mr-5px" icon="ep:download" /> 导出
</el-button>
<el-button
v-hasPermi="['system:role:delete']"
:disabled="checkedIds.length === 0"
plain
type="danger"
@click="handleDeleteBatch"
>
<Icon class="mr-5px" icon="ep:delete" />
批量删除
</el-button>
</el-form-item>
</el-form>
</div>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange">
<el-table-column type="selection" width="55" />
<el-table-column align="center" label="角色编号" prop="id" />
<el-table-column align="center" label="角色名称" prop="name" />
<el-table-column label="角色类型" align="center" prop="type">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleRowCheckboxChange"
:header-cell-style="{
background: '#1890ff',
color: '#ffffff',
textAlign: 'center',
fontWeight: 'normal',
fontSize: '14px',
borderColor: '#1890ff'
}"
:cell-style="{
textAlign: 'center',
fontSize: '14px',
color: '#333333',
borderColor: '#ebeef5'
}"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column align="center" label="角色编号" prop="id" width="100" />
<el-table-column align="center" label="角色名称" prop="name" min-width="120" />
<el-table-column label="角色类型" align="center" prop="type" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_ROLE_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column align="center" label="角色标识" prop="code" />
<el-table-column align="center" label="显示顺序" prop="sort" />
<el-table-column align="center" label="备注" prop="remark" />
<el-table-column align="center" label="状态" prop="status">
<el-table-column align="center" label="角色标识" prop="code" width="120" />
<el-table-column align="center" label="显示顺序" prop="sort" width="100" />
<el-table-column align="center" label="备注" prop="remark" min-width="120" />
<el-table-column align="center" label="状态" prop="status" width="80">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
@ -115,7 +128,7 @@
prop="createTime"
width="180"
/>
<el-table-column :width="300" align="center" label="操作">
<el-table-column label="操作" align="center" min-width="200px" fixed="right">
<template #default="scope">
<el-button
v-hasPermi="['system:role:update']"
@ -128,8 +141,6 @@
<el-button
v-hasPermi="['system:permission:assign-role-menu']"
link
preIcon="ep:basketball"
title="菜单权限"
type="primary"
@click="openAssignMenuForm(scope.row)"
>
@ -138,8 +149,6 @@
<el-button
v-hasPermi="['system:permission:assign-role-data-scope']"
link
preIcon="ep:coin"
title="数据权限"
type="primary"
@click="openDataPermissionForm(scope.row)"
>

View File

@ -38,35 +38,56 @@
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 查询
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['system:tenant-package:create']"
>
<Icon icon="ep:plus" class="mr-5px" />
新增
<Icon icon="ep:plus" class="mr-5px" /> 新建
</el-button>
<el-button
type="danger"
plain
:disabled="checkedIds.length === 0"
@click="handleDeleteBatch"
v-hasPermi="['system:tenant-package:delete']"
>
<Icon icon="ep:delete" class="mr-5px" />
批量删除
</el-button>
</el-form-item>
</el-form>
</div>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange">
<el-table-column type="selection" width="55" />
<el-table
row-key="id"
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleRowCheckboxChange"
:header-cell-style="{
background: '#1890ff',
color: '#ffffff',
textAlign: 'center',
fontWeight: 'normal',
fontSize: '14px',
borderColor: '#1890ff'
}"
:cell-style="{
textAlign: 'center',
fontSize: '14px',
color: '#333333',
borderColor: '#ebeef5'
}"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column label="套餐编号" align="center" prop="id" width="120" />
<el-table-column label="套餐名" align="center" prop="name" />
<el-table-column label="状态" align="center" prop="status" width="100">
@ -82,7 +103,7 @@
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" min-width="120px" fixed="right">
<template #default="scope">
<el-button
link
@ -90,7 +111,7 @@
@click="openForm('update', scope.row.id)"
v-hasPermi="['system:tenant-package:update']"
>
修改
编辑
</el-button>
<el-button
link