界面样式调整

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 VITE_PORT=80

View File

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

View File

@ -66,10 +66,12 @@ watch(
]" ]"
to="/" to="/"
> >
<!-- <img--> <div class="flex items-center justify-center w-[40px] h-[40px] rounded-md bg-white/10">
<!-- class="h-[calc(var(&#45;&#45;logo-height)-10px)] w-[calc(var(&#45;&#45;logo-height)-10px)]"--> <svg viewBox="0 0 1024 1024" width="28" height="28" fill="white">
<!-- src="@/assets/imgs/logo.png"--> <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 <div
v-if="show" v-if="show"
:class="[ :class="[

View File

@ -57,13 +57,13 @@ export default defineComponent({
class={[ class={[
prefixCls, prefixCls,
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between', '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' ? ( {layout.value !== 'top' ? (
<div class="h-full flex items-center"> <div class="h-full flex items-center">
{hamburger.value && layout.value !== 'cutMenu' ? ( {hamburger.value && layout.value !== 'cutMenu' ? (
<Collapse class="custom-hover" color="var(--top-header-text-color)"></Collapse> <Collapse class="custom-hover" color="#fff"></Collapse>
) : undefined} ) : undefined}
{breadcrumb.value ? <Breadcrumb class="lt-md:hidden"></Breadcrumb> : undefined} {breadcrumb.value ? <Breadcrumb class="lt-md:hidden"></Breadcrumb> : undefined}
</div> </div>
@ -71,20 +71,20 @@ export default defineComponent({
<div class="h-full flex items-center"> <div class="h-full flex items-center">
{hasTenantVisitPermission.value ? <TenantVisit /> : undefined} {hasTenantVisitPermission.value ? <TenantVisit /> : undefined}
{screenfull.value ? ( {screenfull.value ? (
<Screenfull class="custom-hover" color="var(--top-header-text-color)"></Screenfull> <Screenfull class="custom-hover" color="#fff"></Screenfull>
) : undefined} ) : undefined}
{search.value ? <RouterSearch isModal={false} color="var(--top-header-text-color)"/> : undefined} {search.value ? <RouterSearch isModal={false} color="#fff"/> : undefined}
{size.value ? ( {size.value ? (
<SizeDropdown class="custom-hover" color="var(--top-header-text-color)"></SizeDropdown> <SizeDropdown class="custom-hover" color="#fff"></SizeDropdown>
) : undefined} ) : undefined}
{locale.value ? ( {locale.value ? (
<LocaleDropdown <LocaleDropdown
class="custom-hover" class="custom-hover"
color="var(--top-header-text-color)" color="#fff"
></LocaleDropdown> ></LocaleDropdown>
) : undefined} ) : undefined}
{message.value ? ( {message.value ? (
<Message class="custom-hover" color="var(--top-header-text-color)"></Message> <Message class="custom-hover" color="#fff"></Message>
) : undefined} ) : undefined}
<UserInfo></UserInfo> <UserInfo></UserInfo>
</div> </div>
@ -99,5 +99,20 @@ $prefix-cls: #{$namespace}-tool-header;
.#{$prefix-cls} { .#{$prefix-cls} {
transition: left var(--transition-time-02); 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> </style>

View File

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

View File

@ -5,31 +5,31 @@
--left-menu-min-width: 64px; --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 */ /* left menu end */
/* logo start */ /* logo start */
--logo-height: 50px; --logo-height: 70px;
--logo-title-text-color: #fff; --logo-title-text-color: #fff;
/* logo end */ /* logo end */
/* header start */ /* 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); --top-tool-height: var(--logo-height);

View File

@ -1,6 +1,7 @@
<template> <template>
<div> <div class="home-container">
<el-card shadow="never"> <!-- 欢迎区域 -->
<el-card shadow="never" class="welcome-card">
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<el-row :gutter="16" justify="space-between"> <el-row :gutter="16" justify="space-between">
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
@ -10,10 +11,10 @@
</el-avatar> </el-avatar>
<div> <div>
<div class="text-20px"> <div class="text-20px">
{{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }} 你好 {{ username }} 祝你开心每一天!
</div> </div>
<div class="mt-10px text-14px text-gray-500"> <div class="mt-10px text-14px text-gray-500">
{{ t('workplace.toady') }}20 - 32 今日晴20 - 32
</div> </div>
</div> </div>
</div> </div>
@ -21,7 +22,7 @@
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24"> <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="h-70px flex items-center justify-end lt-sm:mt-10px">
<div class="px-8px text-right"> <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 <CountTo
class="text-20px" class="text-20px"
:start-val="0" :start-val="0"
@ -31,7 +32,7 @@
</div> </div>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<div class="px-8px text-right"> <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 <CountTo
class="text-20px" class="text-20px"
:start-val="0" :start-val="0"
@ -41,7 +42,7 @@
</div> </div>
<el-divider direction="vertical" border-style="dashed" /> <el-divider direction="vertical" border-style="dashed" />
<div class="px-8px text-right"> <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 <CountTo
class="text-20px" class="text-20px"
:start-val="0" :start-val="0"
@ -54,21 +55,17 @@
</el-row> </el-row>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</div>
<!-- 主要内容区域 -->
<el-row class="mt-8px" :gutter="8" justify="space-between"> <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-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px">
<!-- 小区项目列表 -->
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header>
<div class="h-3 flex justify-between"> <div class="h-3 flex justify-between">
<span>{{ t('workplace.project') }}</span> <span>项目数</span>
<el-link <el-link type="primary" :underline="false" @click="handleMoreClick">
type="primary" 更多
:underline="false"
href="https://github.com/yudaocode"
target="_blank"
>
{{ t('action.more') }}
</el-link> </el-link>
</div> </div>
</template> </template>
@ -86,7 +83,7 @@
<el-card <el-card
shadow="hover" shadow="hover"
class="mr-5px mt-5px cursor-pointer" class="mr-5px mt-5px cursor-pointer"
@click="handleProjectClick(item.message)" @click="handleProjectClick(item)"
> >
<div class="flex items-center"> <div class="flex items-center">
<Icon <Icon
@ -97,9 +94,9 @@
/> />
<span class="text-16px">{{ item.name }}</span> <span class="text-16px">{{ item.name }}</span>
</div> </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"> <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> <span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>
</div> </div>
</el-card> </el-card>
@ -108,6 +105,7 @@
</el-skeleton> </el-skeleton>
</el-card> </el-card>
<!-- 图表区域 -->
<el-card shadow="never" class="mt-8px"> <el-card shadow="never" class="mt-8px">
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<el-row :gutter="20" justify="space-between"> <el-row :gutter="20" justify="space-between">
@ -129,11 +127,14 @@
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
<!-- 右侧区域 -->
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px"> <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">
<!-- 快捷入口 -->
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header>
<div class="h-3 flex justify-between"> <div class="h-3 flex justify-between">
<span>{{ t('workplace.shortcutOperation') }}</span> <span>快捷入口</span>
</div> </div>
</template> </template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
@ -149,58 +150,61 @@
</el-row> </el-row>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
<!-- 通知公告 -->
<el-card shadow="never" class="mt-8px"> <el-card shadow="never" class="mt-8px">
<template #header> <template #header>
<div class="h-3 flex justify-between"> <div class="h-3 flex justify-between">
<span>{{ t('workplace.notice') }}</span> <span>通知公告</span>
<el-link type="primary" :underline="false">{{ t('action.more') }}</el-link> <el-link type="primary" :underline="false" @click="handleNoticeMoreClick"></el-link>
</div> </div>
</template> </template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<div v-for="(item, index) in notice" :key="`dynamics-${index}`"> <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"> <el-avatar :src="avatar" :size="35" class="mr-16px">
<img src="@/assets/imgs/avatar.gif" alt="" /> <img src="@/assets/imgs/avatar.gif" alt="" />
</el-avatar> </el-avatar>
<div> <div class="flex-1">
<div class="text-14px"> <div class="text-14px">
<Highlight :keys="item.keys.map((v) => t(v))"> <span class="text-gray-800">{{ item.type }}</span>
{{ item.type }} : {{ item.title }} <span class="text-gray-600">{{ item.title }}</span>
</Highlight>
</div> </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') }} {{ formatTime(item.date, 'yyyy-MM-dd') }}
</div> </div>
</div> </div>
</div> </div>
<el-divider /> <el-divider v-if="index < notice.length - 1" />
</div> </div>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { set } from 'lodash-es' import { set } from 'lodash-es'
import { EChartsOption } from 'echarts' import { EChartsOption } from 'echarts'
import { formatTime } from '@/utils' import { formatTime } from '@/utils'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
// import { useWatermark } from '@/hooks/web/useWatermark'
import type { WorkplaceTotal, Project, Notice, Shortcut } from './types' import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
import { pieOptions, barOptions } from './echarts-data' import { pieOptions, barOptions } from './echarts-data'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { CommunityApi, Community } from '@/api/community/community'
import { NoticeApi, Notice as NoticeInfo } from '@/api/community/notice'
defineOptions({ name: 'Index' }) defineOptions({ name: 'Index' })
const { t } = useI18n() const { t } = useI18n()
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
// const { setWatermark } = useWatermark()
const loading = ref(true) const loading = ref(true)
const avatar = userStore.getUser.avatar const avatar = userStore.getUser.avatar
const username = userStore.getUser.nickname const username = userStore.getUser.nickname
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
// //
let totalSate = reactive<WorkplaceTotal>({ let totalSate = reactive<WorkplaceTotal>({
project: 0, project: 0,
@ -209,100 +213,57 @@ let totalSate = reactive<WorkplaceTotal>({
}) })
const getCount = async () => { const getCount = async () => {
const data = { try {
project: 40, const data = await CommunityApi.getCommunitySimpleList()
access: 2340, totalSate.project = data.length
todo: 10 totalSate.access = 2340
totalSate.todo = 10
} catch (error) {
console.error('获取小区数量失败:', error)
} }
totalSate = Object.assign(totalSate, data)
} }
// //
let projects = reactive<Project[]>([]) let projects = reactive<Project[]>([])
const getProject = async () => { const getProject = async () => {
const data = [ try {
{ const data = await CommunityApi.getCommunityPage({
name: 'ruoyi-vue-pro', pageNo: 1,
icon: 'simple-icons:springboot', pageSize: 100
message: 'github.com/YunaiV/ruoyi-vue-pro', })
personal: 'Spring Boot 单体架构',
time: new Date('2025-01-02'), projects = data.list.map((item: Community) => ({
color: '#6DB33F' name: item.communityName || '',
}, icon: 'ep:house',
{ description: item.streetName || item.districtName || '智慧社区',
name: 'yudao-ui-admin-vue3', location: item.communityAddress || '',
icon: 'ep:element-plus', time: new Date(),
message: 'github.com/yudaocode/yudao-ui-admin-vue3',
personal: 'Vue3 + element-plus 管理后台',
time: new Date('2025-02-03'),
color: '#409EFF' color: '#409EFF'
}, }))
{ } catch (error) {
name: 'yudao-ui-mall-uniapp', console.error('获取小区列表失败:', error)
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'
} }
]
projects = Object.assign(projects, data)
} }
// //
let notice = reactive<Notice[]>([]) let notice = reactive<Notice[]>([])
const getNotice = async () => { const getNotice = async () => {
const data = [ try {
{ const data = await NoticeApi.getNoticePage({
title: '系统支持 JDK 8/17/21Vue 2/3', pageNo: 1,
type: '技术兼容性', pageSize: 4,
keys: ['JDK', 'Vue'], status: 1
date: new Date() })
},
{ notice = data.list.map((item: NoticeInfo) => ({
title: '后端提供 Spring Boot 2.7/3.2 + Cloud 双架构', title: item.title || '',
type: '架构灵活性', type: item.publisher || '系统通知',
keys: ['Boot', 'Cloud'], keys: [item.title || ''],
date: new Date() date: new Date(item.createTime || '')
}, }))
{ } catch (error) {
title: '全部开源,个人与企业可 100% 直接使用,无需授权', console.error('获取通知公告失败:', error)
type: '开源免授权',
keys: ['无需授权'],
date: new Date()
},
{
title: '国内使用最广泛的快速开发平台,远超 10w+ 企业使用',
type: '广泛企业认可',
keys: ['最广泛', '10w+'],
date: new Date()
} }
]
notice = Object.assign(notice, data)
} }
// //
@ -311,87 +272,88 @@ let shortcut = reactive<Shortcut[]>([])
const getShortcut = async () => { const getShortcut = async () => {
const data = [ const data = [
{ {
name: '首页', name: '社区动态',
icon: 'ion:home-outline', icon: 'ep:document',
url: '/', url: '/operation/post',
color: '#1fdaca' color: '#1677ff'
}, },
{ {
name: '商城中心', name: '通知公告',
icon: 'ep:shop', icon: 'ep:bell',
url: '/mall/home', url: '/operation/notice',
color: '#ff6b6b' color: '#ff6b6b'
}, },
{ {
name: 'AI 大模型', name: '知识课堂',
icon: 'tabler:ai', icon: 'ep:reading',
url: '/ai/chat', url: '/operation/knowledge-class',
color: '#7c3aed' color: '#7c3aed'
}, },
{ {
name: 'ERP 系统', name: '小区活动',
icon: 'simple-icons:erpnext', icon: 'ep:calendar',
url: '/erp/home', url: '/operation/activity',
color: '#3fb27f' color: '#3fb27f'
}, },
{ {
name: 'CRM 系统', name: '小区管理',
icon: 'simple-icons:civicrm', icon: 'ep:office-building',
url: '/crm/backlog', url: '/system/community',
color: '#4daf1bc9' color: '#4daf1bc9'
}, },
{ {
name: 'IoT 物联网', name: 'Banner管理',
icon: 'fa-solid:hdd', icon: 'ep:picture',
url: '/iot/home', url: '/system/banner',
color: '#1a73e8' color: '#1a73e8'
} }
] ]
shortcut = Object.assign(shortcut, data) shortcut = Object.assign(shortcut, data)
} }
// // 访
const getUserAccessSource = async () => { const getUserAccessSource = async () => {
const data = [ const data = [
{ value: 335, name: 'analysis.directAccess' }, { value: 335, name: '直接访问' },
{ value: 310, name: 'analysis.mailMarketing' }, { value: 310, name: '邮件营销' },
{ value: 234, name: 'analysis.allianceAdvertising' }, { value: 234, name: '联盟广告' },
{ value: 135, name: 'analysis.videoAdvertising' }, { value: 135, name: '视频广告' },
{ value: 1548, name: 'analysis.searchEngines' } { value: 1548, name: '搜索引擎' }
] ]
set( set(
pieOptionsData, pieOptionsData,
'legend.data', 'legend.data',
data.map((v) => t(v.name)) data.map((v) => v.name)
) )
pieOptionsData!.series![0].data = data.map((v) => { pieOptionsData!.series![0].data = data.map((v) => {
return { return {
name: t(v.name), name: v.name,
value: v.value value: v.value
} }
}) })
} }
const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
// //
const getWeeklyUserActivity = async () => { const getWeeklyUserActivity = async () => {
const data = [ const data = [
{ value: 13253, name: 'analysis.monday' }, { value: 13253, name: '周一' },
{ value: 34235, name: 'analysis.tuesday' }, { value: 34235, name: '周二' },
{ value: 26321, name: 'analysis.wednesday' }, { value: 26321, name: '周三' },
{ value: 12340, name: 'analysis.thursday' }, { value: 12340, name: '周四' },
{ value: 24643, name: 'analysis.friday' }, { value: 24643, name: '周五' },
{ value: 1322, name: 'analysis.saturday' }, { value: 1322, name: '周六' },
{ value: 1324, name: 'analysis.sunday' } { value: 1324, name: '周日' }
] ]
set( set(
barOptionsData, barOptionsData,
'xAxis.data', 'xAxis.data',
data.map((v) => t(v.name)) data.map((v) => v.name)
) )
set(barOptionsData, 'series', [ set(barOptionsData, 'series', [
{ {
name: t('analysis.activeQuantity'), name: '活跃用户',
data: data.map((v) => v.value), data: data.map((v) => v.value),
type: 'bar' type: 'bar'
} }
@ -410,13 +372,34 @@ const getAllApi = async () => {
loading.value = false loading.value = false
} }
const handleProjectClick = (message: string) => { const handleProjectClick = (item: Project) => {
window.open(`https://${message}`, '_blank') // TODO:
console.log('点击小区:', item.name)
} }
const handleShortcutClick = (url: string) => { const handleShortcutClick = (url: string) => {
router.push(url) router.push(url)
} }
const handleMoreClick = () => {
router.push('/system/community')
}
const handleNoticeMoreClick = () => {
router.push('/operation/notice')
}
getAllApi() getAllApi()
</script> </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> <template>
<div <div :class="prefixCls" class="login-container">
:class="prefixCls" <div class="login-content">
class="relative h-[100%] lt-md:px-10px lt-sm:px-10px lt-xl:px-10px lt-xl:px-10px" <!-- 登录卡片 -->
> <div class="login-card">
<div class="relative mx-auto h-full flex"> <!-- Logo 图标 -->
<div <div class="login-logo">
:class="`${prefixCls}__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px lt-xl:hidden overflow-x-hidden overflow-y-auto`" <div class="logo-icon">
> <svg viewBox="0 0 1024 1024" width="60" height="60">
<!-- 左上角的 logo + 系统标题 --> <path
<div class="relative flex items-center text-white"> 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"
<span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span> fill="#1677ff"
</div> />
<!-- 左边的背景图 + 欢迎语 --> <path
<div class="h-[calc(100%-60px)] flex items-center justify-center"> 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"
<TransitionGroup fill="#1677ff"
appear />
enter-active-class="animate__animated animate__bounceInLeft" </svg>
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> </div>
</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"
> >
<!-- 右上角的主题语言选择 --> <el-form-item prop="username">
<div <el-input
class="flex items-center justify-between at-2xl:justify-end at-xl:justify-end" v-model="loginData.loginForm.username"
style="color: var(--el-text-color-primary);" 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"> <el-option
<span class="text-20px font-bold" >{{ underlineToHump(appStore.getTitle) }}</span> 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>
<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 /> <ThemeSwitch />
<LocaleDropdown /> <LocaleDropdown />
</div> </div>
</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> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { underlineToHump } from '@/utils' import { underlineToHump } from '@/utils'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { ThemeSwitch } from '@/layout/components/ThemeSwitch' import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
import { LocaleDropdown } from '@/layout/components/LocaleDropdown' import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
import { useIcon } from '@/hooks/web/useIcon'
import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm } from './components' 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' }) defineOptions({ name: 'Login' })
const { t } = useI18n() const { t } = useI18n()
const message = useMessage()
const appStore = useAppStore() const appStore = useAppStore()
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('login') 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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$prefix-cls: #{$namespace}-login; .login-container {
position: relative;
.#{$prefix-cls} {
overflow: auto;
&__left {
&::before {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%; width: 100%;
height: 100%; height: 100vh;
background-image: url('@/assets/svgs/login-bg.svg'); background: #1677ff;
background-position: center; display: flex;
background-repeat: no-repeat; align-items: center;
content: ''; 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> </style>

View File

@ -33,30 +33,31 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button type="primary" @click="handleQuery">
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> <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 <el-button
type="primary" type="primary"
plain plain
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['system:dept:create']" v-hasPermi="['system:dept:create']"
> >
<Icon icon="ep:plus" class="mr-5px" /> 新增 <Icon icon="ep:plus" class="mr-5px" />
</el-button> </el-button>
<el-button type="danger" plain @click="toggleExpandAll"> <el-button type="primary" plain @click="toggleExpandAll">
<Icon icon="ep:sort" class="mr-5px" /> 展开/折叠 <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
</el-button> </el-button>
<el-button </div>
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>
</ContentWrap> </ContentWrap>
<!-- 列表 --> <!-- 列表 -->
@ -68,16 +69,31 @@
:default-expand-all="isExpandAll" :default-expand-all="isExpandAll"
v-if="refreshTable" v-if="refreshTable"
@selection-change="handleRowCheckboxChange" @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 type="selection" width="55" align="center" />
<el-table-column prop="name" label="部门名称" /> <el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column prop="leader" label="负责人"> <el-table-column prop="name" label="部门名称" min-width="150" />
<el-table-column prop="leader" label="负责人" width="120">
<template #default="scope"> <template #default="scope">
{{ userList.find((user) => user.id === scope.row.leaderUserId)?.nickname }} {{ userList.find((user) => user.id === scope.row.leaderUserId)?.nickname }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="sort" label="排序" /> <el-table-column prop="sort" label="排序" width="80" />
<el-table-column prop="status" label="状态"> <el-table-column prop="status" label="状态" width="80">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template> </template>
@ -89,7 +105,7 @@
width="180" width="180"
:formatter="dateFormatter" :formatter="dateFormatter"
/> />
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center" width="120px" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
@ -97,7 +113,7 @@
@click="openForm('update', scope.row.id)" @click="openForm('update', scope.row.id)"
v-hasPermi="['system:dept:update']" v-hasPermi="['system:dept:update']"
> >
修改 编辑
</el-button> </el-button>
<el-button <el-button
link link

View File

@ -37,18 +37,29 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button type="primary" @click="handleQuery">
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> <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 <el-button
type="primary" type="primary"
plain plain
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['system:dict:create']" v-hasPermi="['system:dict:create']"
> >
<Icon icon="ep:plus" class="mr-5px" /> 新增 <Icon icon="ep:plus" class="mr-5px" />
</el-button> </el-button>
<el-button <el-button
type="success" type="primary"
plain plain
@click="handleExport" @click="handleExport"
:loading="exportLoading" :loading="exportLoading"
@ -56,35 +67,46 @@
> >
<Icon icon="ep:download" class="mr-5px" /> 导出 <Icon icon="ep:download" class="mr-5px" /> 导出
</el-button> </el-button>
<el-button </div>
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>
</ContentWrap> </ContentWrap>
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange"> <el-table
<el-table-column type="selection" width="55" /> v-loading="loading"
<el-table-column label="字典编码" align="center" prop="id" /> :data="list"
<el-table-column label="字典标签" align="center" prop="label" /> :stripe="true"
<el-table-column label="字典键值" align="center" prop="value" /> :show-overflow-tooltip="true"
<el-table-column label="字典排序" align="center" prop="sort" /> @selection-change="handleRowCheckboxChange"
<el-table-column label="状态" align="center" prop="status"> :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"> <template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="颜色类型" align="center" prop="colorType" /> <el-table-column label="颜色类型" align="center" prop="colorType" width="100" />
<el-table-column label="CSS Class" align="center" prop="cssClass" /> <el-table-column label="CSS Class" align="center" prop="cssClass" width="120" />
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip /> <el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip min-width="150" />
<el-table-column <el-table-column
label="创建时间" label="创建时间"
align="center" align="center"
@ -92,7 +114,7 @@
width="180" width="180"
:formatter="dateFormatter" :formatter="dateFormatter"
/> />
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center" width="120px" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
@ -100,7 +122,7 @@
@click="openForm('update', scope.row.id)" @click="openForm('update', scope.row.id)"
v-hasPermi="['system:dict:update']" v-hasPermi="['system:dict:update']"
> >
修改 编辑
</el-button> </el-button>
<el-button <el-button
link link

View File

@ -53,60 +53,73 @@
/> />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"> <el-button type="primary" @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" /> <Icon class="mr-5px" icon="ep:search" /> 查询
搜索
</el-button> </el-button>
<el-button @click="resetQuery"> <el-button @click="resetQuery">
<Icon class="mr-5px" icon="ep:refresh" /> <Icon class="mr-5px" icon="ep:refresh" /> 重置
重置
</el-button> </el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 操作按钮栏 -->
<ContentWrap>
<div class="mb-15px">
<el-button <el-button
v-hasPermi="['system:dict:create']" v-hasPermi="['system:dict:create']"
plain plain
type="primary" type="primary"
@click="openForm('create')" @click="openForm('create')"
> >
<Icon class="mr-5px" icon="ep:plus" /> <Icon class="mr-5px" icon="ep:plus" /> 新建
新增
</el-button> </el-button>
<el-button <el-button
v-hasPermi="['system:dict:export']" v-hasPermi="['system:dict:export']"
:loading="exportLoading" :loading="exportLoading"
plain plain
type="success" type="primary"
@click="handleExport" @click="handleExport"
> >
<Icon class="mr-5px" icon="ep:download" /> <Icon class="mr-5px" icon="ep:download" /> 导出
导出
</el-button> </el-button>
<el-button </div>
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>
</ContentWrap> </ContentWrap>
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange"> <el-table
<el-table-column type="selection" width="55" /> v-loading="loading"
<el-table-column align="center" label="字典编号" prop="id" /> :data="list"
<el-table-column align="center" label="字典名称" prop="name" show-overflow-tooltip /> :stripe="true"
<el-table-column align="center" label="字典类型" prop="type" width="300" /> :show-overflow-tooltip="true"
<el-table-column align="center" label="状态" prop="status"> @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"> <template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template> </template>
</el-table-column> </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 <el-table-column
:formatter="dateFormatter" :formatter="dateFormatter"
align="center" align="center"
@ -114,7 +127,7 @@
prop="createTime" prop="createTime"
width="180" width="180"
/> />
<el-table-column align="center" label="操作"> <el-table-column align="center" label="操作" width="180px" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button <el-button
v-hasPermi="['system:dict:update']" v-hasPermi="['system:dict:update']"
@ -122,7 +135,7 @@
type="primary" type="primary"
@click="openForm('update', scope.row.id)" @click="openForm('update', scope.row.id)"
> >
修改 编辑
</el-button> </el-button>
<router-link :to="'/dict/type/data/' + scope.row.type"> <router-link :to="'/dict/type/data/' + scope.row.type">
<el-button link type="primary">数据</el-button> <el-button link type="primary">数据</el-button>

View File

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

View File

@ -37,18 +37,29 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button type="primary" @click="handleQuery">
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> <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 <el-button
type="primary" type="primary"
plain plain
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['system:post:create']" v-hasPermi="['system:post:create']"
> >
<Icon icon="ep:plus" class="mr-5px" /> 新增 <Icon icon="ep:plus" class="mr-5px" />
</el-button> </el-button>
<el-button <el-button
type="success" type="primary"
plain plain
@click="handleExport" @click="handleExport"
:loading="exportLoading" :loading="exportLoading"
@ -56,29 +67,40 @@
> >
<Icon icon="ep:download" class="mr-5px" /> 导出 <Icon icon="ep:download" class="mr-5px" /> 导出
</el-button> </el-button>
<el-button </div>
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>
</ContentWrap> </ContentWrap>
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange"> <el-table
<el-table-column type="selection" width="55" /> v-loading="loading"
<el-table-column label="岗位编号" align="center" prop="id" /> :data="list"
<el-table-column label="岗位名称" align="center" prop="name" /> :stripe="true"
<el-table-column label="岗位编码" align="center" prop="code" /> :show-overflow-tooltip="true"
<el-table-column label="岗位顺序" align="center" prop="sort" /> @selection-change="handleRowCheckboxChange"
<el-table-column label="岗位备注" align="center" prop="remark" /> :header-cell-style="{
<el-table-column label="状态" align="center" prop="status"> 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"> <template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template> </template>
@ -90,7 +112,7 @@
width="180" width="180"
:formatter="dateFormatter" :formatter="dateFormatter"
/> />
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center" width="120px" fixed="right">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link

View File

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

View File

@ -38,35 +38,56 @@
/> />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button type="primary" @click="handleQuery">
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> <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 <el-button
type="primary" type="primary"
plain plain
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['system:tenant-package: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>
<el-button </div>
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>
</ContentWrap> </ContentWrap>
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-table v-loading="loading" :data="list" @selection-change="handleRowCheckboxChange"> <el-table
<el-table-column type="selection" width="55" /> 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="id" width="120" />
<el-table-column label="套餐名" align="center" prop="name" /> <el-table-column label="套餐名" align="center" prop="name" />
<el-table-column label="状态" align="center" prop="status" width="100"> <el-table-column label="状态" align="center" prop="status" width="100">
@ -82,7 +103,7 @@
width="180" width="180"
:formatter="dateFormatter" :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"> <template #default="scope">
<el-button <el-button
link link
@ -90,7 +111,7 @@
@click="openForm('update', scope.row.id)" @click="openForm('update', scope.row.id)"
v-hasPermi="['system:tenant-package:update']" v-hasPermi="['system:tenant-package:update']"
> >
修改 编辑
</el-button> </el-button>
<el-button <el-button
link link