Browse Source

首页页面实现

dev-V1.0.6
wangmingyong@163.com 2 weeks ago
parent
commit
78221c86c7
  1. 1
      zdxt-web-client/zdxt-admin-plus-ui/index.html
  2. 8
      zdxt-web-client/zdxt-admin-plus-ui/src/layout/components/AppMain.vue
  3. 508
      zdxt-web-client/zdxt-admin-plus-ui/src/layout/components/Navbar.vue
  4. 70
      zdxt-web-client/zdxt-admin-plus-ui/src/layout/index.vue
  5. 1920
      zdxt-web-client/zdxt-admin-plus-ui/src/views/home/index.vue
  6. 23
      zdxt-web-client/zdxt-admin-plus-ui/src/views/supervision/statistical/utils/chartOptions.ts

1
zdxt-web-client/zdxt-admin-plus-ui/index.html

@ -6,6 +6,7 @@
<meta name="renderer" content="webkit" /> <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/statistical/font-awesome/css/font-awesome.min.css" />
<title>%VITE_APP_TITLE%</title> <title>%VITE_APP_TITLE%</title>
<!--[if lt IE 11 <!--[if lt IE 11
]><script> ]><script>

8
zdxt-web-client/zdxt-admin-plus-ui/src/layout/components/AppMain.vue

@ -53,26 +53,22 @@ function addIframe() {
<style lang="scss" scoped> <style lang="scss" scoped>
.app-main { .app-main {
/* navbar 50px 已由 main-container 的 padding-top 处理 */ height: calc(100vh - 50px);
min-height: calc(100vh - 50px);
width: 100%; width: 100%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
.fixed-header + .app-main { .fixed-header + .app-main {
/* fixed-header 现仅含 tags-view,无 tags-view 时为空,无需额外 padding */
padding-top: 0; padding-top: 0;
} }
.hasTagsView { .hasTagsView {
.app-main { .app-main {
/* 84 = navbar 50 + tags-view 34 */ height: calc(100vh - 84px);
min-height: calc(100vh - 84px);
} }
.fixed-header + .app-main { .fixed-header + .app-main {
/* tags-view 34px 固定在顶部,需让出空间 */
padding-top: 34px; padding-top: 34px;
} }
} }

508
zdxt-web-client/zdxt-admin-plus-ui/src/layout/components/Navbar.vue

@ -1,103 +1,45 @@
<template> <template>
<div class="navbar"> <div class="dashboard-navbar">
<div class="flex align-center"> <div class="navbar-left">
<div class="logo">执法监督码 执法监督</div> <div class="hamburger-btn" @click="toggleSideBar">
<hamburger v-if="!permissionStore.iframeMode" id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" <i class="fa fa-bars"></i>
@toggle-click="toggleSideBar" /> </div>
<div class="system-title">
<span class="title-main">执法监督码</span>
<span class="title-dot">·</span>
<span class="title-sub">执法监督</span>
</div>
</div> </div>
<div class="navbar-right">
<!-- <breadcrumb v-if="!settingsStore.topNav && !permissionStore.iframeMode" id="breadcrumb-container" class="breadcrumb-container" /> --> <div class="system-tabs">
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" /> <div
v-for="item in permissionStore.visibleSystemCodeOptions"
<div class="right-menu flex align-center"> :key="item.value"
<template v-if="appStore.device !== 'mobile'"> class="system-tab"
<div class="system-tabs"> :class="{ 'is-active': item.value === currentSystemCode }"
<div @click="handleSystemCodeChange(item.value)"
v-for="item in permissionStore.visibleSystemCodeOptions" >
:key="item.value" <div class="nav-icon">
class="system-tab"
:class="{ 'is-active': item.value === currentSystemCode }"
@click="handleSystemCodeChange(item.value)"
>
<el-icon><component :is="item.icon" /></el-icon> <el-icon><component :is="item.icon" /></el-icon>
<span>{{ item.label }}</span>
</div> </div>
<div class="nav-label">{{ item.label }}</div>
</div> </div>
</div>
<!-- <el-select <div class="user-info">
v-if="userId === 1 && tenantEnabled" <div class="user-avatar">
v-model="companyName" <img :src="userStore.avatar" alt="avatar" />
class="min-w-244px" </div>
clearable <div class="user-detail">
filterable <div class="username">{{ userStore.nickname || 'admin' }}</div>
reserve-keyword <div class="user-org">深圳市司法局</div>
:placeholder="proxy.$t('navbar.selectTenant')" </div>
@change="dynamicTenantEvent" <el-dropdown trigger="click" @command="handleCommand">
@clear="dynamicClearEvent" <i class="fa fa-caret-down user-caret"></i>
>
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
</el-select>-->
<!-- <search-menu ref="searchMenuRef" />
<el-tooltip content="搜索" effect="dark" placement="bottom">
<div class="right-menu-item hover-effect" @click="openSearchMenu">
<svg-icon class-name="search-icon" icon-class="search" />
</div>
</el-tooltip>-->
<!-- 消息 -->
<!-- <el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
<div>
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
<template #reference>
<el-badge :value="newNotice > 0 ? newNotice : ''" :max="99">
<div class="right-menu-item hover-effect" style="display: block"><svg-icon icon-class="message" /></div>
</el-badge>
</template>
<template #default>
<notice></notice>
</template>
</el-popover>
</div>
</el-tooltip>
<el-tooltip content="Github" effect="dark" placement="bottom">
<ruo-yi-git id="zdxt-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="proxy.$t('navbar.document')" effect="dark" placement="bottom">
<ruo-yi-doc id="zdxt-doc" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="proxy.$t('navbar.full')" effect="dark" placement="bottom">
<screenfull id="screenfull" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="proxy.$t('navbar.language')" effect="dark" placement="bottom">
<lang-select id="lang-select" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip :content="proxy.$t('navbar.layoutSize')" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>-->
</template>
<div class="avatar-container">
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
<div class="avatar-wrapper">
<img :src="userStore.avatar" class="user-avatar" />
<el-icon><caret-bottom /></el-icon>
</div>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<router-link v-if="!dynamic" to="/user/profile"> <el-dropdown-item command="logout">退出登录</el-dropdown-item>
<el-dropdown-item>{{ proxy.$t('navbar.personalCenter') }}</el-dropdown-item>
</router-link>
<el-dropdown-item v-if="settingsStore.showSettings" command="setLayout">
<span>{{ proxy.$t('navbar.layoutSetting') }}</span>
</el-dropdown-item>
<el-dropdown-item divided command="logout">
<span>{{ proxy.$t('navbar.logout') }}</span>
</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@ -107,135 +49,119 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import SearchMenu from './TopBar/search.vue'; import { ref, watch } from 'vue';
import { usePermissionStore } from '@/store/modules/permission';
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import { useSettingsStore } from '@/store/modules/settings'; import { usePermissionStore } from '@/store/modules/permission';
import { useNoticeStore } from '@/store/modules/notice'; import { ElMessageBox } from 'element-plus';
import { getTenantList } from '@/api/login'; import type { ElMessageBoxOptions } from 'element-plus/es/components/message-box/src/message-box.type';
import { dynamicClear, dynamicTenant } from '@/api/system/tenant';
import { TenantVO } from '@/api/types';
import notice from './notice/index.vue';
import router from '@/router'; import router from '@/router';
import { ElMessageBoxOptions } from 'element-plus/es/components/message-box/src/message-box.type';
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore(); const userStore = useUserStore();
const settingsStore = useSettingsStore();
const permissionStore = usePermissionStore(); const permissionStore = usePermissionStore();
const noticeStore = storeToRefs(useNoticeStore());
const newNotice = ref(<number>0);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userId = ref(userStore.userId);
const companyName = ref(undefined);
const tenantList = ref<TenantVO[]>([]);
//
const dynamic = ref(false);
//
const tenantEnabled = ref(true);
//
const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
//
const currentSystemCode = ref(permissionStore.currentSystemCode); const currentSystemCode = ref(permissionStore.currentSystemCode);
watch(() => permissionStore.currentSystemCode, (val) => { watch(
currentSystemCode.value = val; () => permissionStore.currentSystemCode,
}); (val) => {
currentSystemCode.value = val;
}
);
const toggleSideBar = () => {
appStore.toggleSideBar(false);
};
/** 切换菜单组 */
const handleSystemCodeChange = async (systemCode: string) => { const handleSystemCodeChange = async (systemCode: string) => {
currentSystemCode.value = systemCode; currentSystemCode.value = systemCode;
await permissionStore.switchSystemCode(systemCode); await permissionStore.switchSystemCode(systemCode);
}; };
const openSearchMenu = () => { const handleCommand = async (command: string) => {
searchMenuRef.value?.openSearch(); if (command === 'logout') {
}; await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
// cancelButtonText: '取消',
const dynamicTenantEvent = async (tenantId: string) => { type: 'warning'
if (companyName.value != null && companyName.value !== '') { } as ElMessageBoxOptions);
await dynamicTenant(tenantId); await userStore.logout();
dynamic.value = true; router.replace({ path: '/login' });
await proxy?.$router.push('/');
await proxy?.$tab.closeAllPage();
await proxy?.$tab.refreshPage();
} }
}; };
</script>
const dynamicClearEvent = async () => { <style lang="scss" scoped>
await dynamicClear(); .dashboard-navbar {
dynamic.value = false; height: 50px;
await proxy?.$router.push('/'); background: linear-gradient(180deg, #0c3d8f 0%, #0a2e72 100%);
await proxy?.$tab.closeAllPage(); display: flex;
await proxy?.$tab.refreshPage(); align-items: center;
}; justify-content: space-between;
padding: 0 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
position: relative;
z-index: 1000;
}
.navbar-left {
display: flex;
align-items: center;
gap: 20px;
}
/** 租户列表 */ .hamburger-btn {
const initTenantList = async () => { width: 32px;
const { data } = await getTenantList(true); height: 32px;
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled; display: flex;
if (tenantEnabled.value) { align-items: center;
tenantList.value = data.voList; justify-content: center;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
i {
color: rgba(255, 255, 255, 0.9);
font-size: 18px;
} }
};
defineExpose({ &:hover {
initTenantList background: rgba(255, 255, 255, 0.1);
}); }
}
const toggleSideBar = () => { .system-title {
appStore.toggleSideBar(false); display: flex;
}; align-items: baseline;
gap: 2px;
}
const logout = async () => { .title-main {
await ElMessageBox.confirm('确定注销并退出系统吗?', '提示', { font-size: 20px;
confirmButtonText: '确定', font-weight: 600;
cancelButtonText: '取消', color: #fff;
type: 'warning' letter-spacing: 2px;
} as ElMessageBoxOptions); text-shadow: 0 0 10px rgba(64, 180, 255, 0.5);
await userStore.logout(); }
proxy?.$tab.closeAllPage();
router.replace({
path: '/login',
query: {
redirect: encodeURIComponent(router.currentRoute.value.fullPath || '/')
}
});
};
const emits = defineEmits(['setLayout']); .title-dot {
const setLayout = () => { font-size: 18px;
emits('setLayout'); color: rgba(255, 255, 255, 0.7);
}; margin: 0 2px;
// Command key }
const commandMap: { [key: string]: any } = {
setLayout,
logout
};
const handleCommand = (command: string) => {
//
if (commandMap[command]) {
commandMap[command]();
}
};
//
watch(
() => noticeStore.state.value.notices,
(newVal) => {
newNotice.value = newVal.filter((item: any) => !item.read).length;
},
{ deep: true }
);
</script>
<style lang="scss" scoped> .title-sub {
:deep(.el-badge__content.is-fixed) { font-size: 18px;
top: 12px; font-weight: 500;
color: rgba(255, 255, 255, 0.9);
letter-spacing: 2px;
}
.navbar-right {
display: flex;
align-items: center;
gap: 8px;
} }
.system-tabs { .system-tabs {
@ -247,139 +173,117 @@ watch(
.system-tab { .system-tab {
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
gap: 5px; justify-content: center;
height: 32px; width: 64px;
padding: 0 14px; height: 44px;
border-radius: 4px; border-radius: 6px;
font-size: 13px;
color: #5a5e66;
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.25s ease;
white-space: nowrap; position: relative;
&:hover { &:hover {
color: #1e6bb8; background: rgba(255, 255, 255, 0.12);
background: rgba(58, 174, 251, 0.08);
.nav-icon .el-icon {
color: rgba(255, 255, 255, 0.9);
}
.nav-label {
color: rgba(255, 255, 255, 0.9);
}
} }
&.is-active { &.is-active {
background: rgba(58, 174, 251, 0.12); background: rgba(64, 160, 255, 0.25);
color: #1e6bb8; box-shadow: inset 0 -2px 0 #40a0ff;
.el-icon { .nav-icon .el-icon {
color: #1e6bb8; color: #fff;
} }
}
.el-icon { .nav-label {
font-size: 16px; color: #fff;
color: #5a5e66; }
transition: color 0.2s;
} }
} }
.flex { .nav-icon {
width: 24px;
height: 24px;
display: flex; display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1px;
.el-icon {
font-size: 16px;
color: rgba(255, 255, 255, 0.75);
transition: color 0.25s;
}
} }
.align-center { .nav-label {
align-items: center; font-size: 12px;
color: rgba(255, 255, 255, 0.7);
white-space: nowrap;
transition: color 0.25s;
} }
.navbar { .user-info {
height: 50px;
overflow: hidden;
position: relative;
//background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
display: flex; display: flex;
justify-content: space-between; align-items: center;
.logo { gap: 10px;
font-size: 18px; margin-left: 16px;
color: #5a5e66; padding: 4px 12px 4px 4px;
font-weight: bold; border-radius: 24px;
margin-left: 20px; background: rgba(255, 255, 255, 0.08);
} cursor: pointer;
.hamburger-container { transition: background 0.2s;
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.breadcrumb-container { &:hover {
float: left; background: rgba(255, 255, 255, 0.15);
} }
}
.topmenu-container { .user-avatar {
position: absolute; width: 34px;
left: 50px; height: 34px;
} border-radius: 50%;
overflow: hidden;
border: 2px solid rgba(64, 160, 255, 0.6);
box-shadow: 0 0 8px rgba(64, 160, 255, 0.3);
.errLog-container { img {
display: inline-block; width: 100%;
vertical-align: top; height: 100%;
object-fit: cover;
display: block;
} }
}
.right-menu { .user-detail {
float: right; display: flex;
height: 100%; flex-direction: column;
line-height: 50px; line-height: 1.2;
display: flex; }
&:focus { .username {
outline: none; font-size: 14px;
} font-weight: 500;
color: #fff;
}
.right-menu-item { .user-org {
display: inline-block; font-size: 11px;
padding: 0 8px; color: rgba(255, 255, 255, 0.65);
height: 100%; margin-top: 2px;
font-size: 18px; }
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
}
.avatar-container { .user-caret {
margin-right: 40px; color: rgba(255, 255, 255, 0.6);
font-size: 12px;
.avatar-wrapper { margin-left: 4px;
margin-top: 5px;
position: relative;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
margin-top: 10px;
}
i {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
} }
</style> </style>

70
zdxt-web-client/zdxt-admin-plus-ui/src/layout/index.vue

@ -3,11 +3,11 @@
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<!-- iframe 全屏模式隐藏侧边栏标签栏路由内容只保留导航栏 + iframe --> <!-- iframe 全屏模式隐藏侧边栏标签栏路由内容只保留导航栏 + iframe -->
<template v-if="permissionStore.iframeMode"> <template v-if="permissionStore.iframeMode">
<div class="main-container iframe-mode" style="margin-left: 0;"> <div class="main-container iframe-mode" :class="{ 'dashboard-mode': isDashboardRoute }" style="margin-left: 0;">
<div :class="{ 'fixed-header': fixedHeader }" style="width: 100%;"> <div :class="{ 'fixed-header': fixedHeader }" style="width: 100%;">
<navbar ref="navbarRef" @set-layout="setLayout" /> <navbar ref="navbarRef" />
</div> </div>
<section class="iframe-main"> <section class="iframe-main" :class="{ 'iframe-main-full': isDashboardRoute }">
<iframe v-if="permissionStore.iframeUrl" :src="permissionStore.iframeUrl" class="iframe-full" frameborder="0" /> <iframe v-if="permissionStore.iframeUrl" :src="permissionStore.iframeUrl" class="iframe-full" frameborder="0" />
<router-view v-else class="iframe-full-page" /> <router-view v-else class="iframe-full-page" />
</section> </section>
@ -18,7 +18,7 @@
<template v-else> <template v-else>
<!-- 顶部头部整行 --> <!-- 顶部头部整行 -->
<div class="top-header"> <div class="top-header">
<navbar ref="navbarRef" @set-layout="setLayout" /> <navbar ref="navbarRef" />
</div> </div>
<!-- 下方左侧边栏 + 右内容 --> <!-- 下方左侧边栏 + 右内容 -->
<side-bar v-if="!sidebar.hide" class="sidebar-container" /> <side-bar v-if="!sidebar.hide" class="sidebar-container" />
@ -76,9 +76,12 @@ watchEffect(() => {
const navbarRef = ref<InstanceType<typeof Navbar>>(); const navbarRef = ref<InstanceType<typeof Navbar>>();
const settingRef = ref<InstanceType<typeof Settings>>(); const settingRef = ref<InstanceType<typeof Settings>>();
const isDashboardRoute = computed(() => {
return permissionStore.fullscreenRoute === router.currentRoute.value.path && !permissionStore.iframeUrl;
});
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
navbarRef.value?.initTenantList();
if (permissionStore.iframeMode && permissionStore.fullscreenRoute && router.currentRoute.value.path !== permissionStore.fullscreenRoute) { if (permissionStore.iframeMode && permissionStore.fullscreenRoute && router.currentRoute.value.path !== permissionStore.fullscreenRoute) {
router.replace(permissionStore.fullscreenRoute); router.replace(permissionStore.fullscreenRoute);
} }
@ -175,12 +178,23 @@ const setLayout = () => {
} }
} }
.iframe-mode.dashboard-mode {
}
.iframe-mode.dashboard-mode .iframe-main {
}
.iframe-main { .iframe-main {
width: 100%; width: 100%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
.iframe-main-full {
height: calc(100vh - 50px);
overflow: hidden;
}
.fixed-header + .iframe-main { .fixed-header + .iframe-main {
padding-top: 50px; padding-top: 50px;
} }
@ -198,47 +212,17 @@ const setLayout = () => {
overflow: auto; overflow: auto;
} }
.iframe-mode .navbar { .iframe-mode .dashboard-navbar {
background: linear-gradient(180deg, #0d1d3a 0%, #0a1628 100%); background: linear-gradient(180deg, #0c3d8f 0%, #0a2e72 100%);
border-bottom: 1px solid rgba(58, 174, 251, 0.2); border-bottom: 1px solid rgba(64, 160, 255, 0.2);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.iframe-mode .navbar .right-menu-item,
.iframe-mode .navbar .breadcrumb-container,
.iframe-mode .navbar .topmenu-container {
color: rgba(255, 255, 255, 0.85);
}
.iframe-mode .navbar .right-menu-item:hover,
.iframe-mode .navbar .avatar-wrapper:hover {
background: rgba(58, 174, 251, 0.15);
} }
.iframe-mode .navbar .user-avatar { .iframe-mode .dashboard-navbar .nav-item:hover {
border: 2px solid rgba(58, 174, 251, 0.4); background: rgba(255, 255, 255, 0.12);
} }
.iframe-mode .navbar .system-tab { .iframe-mode .dashboard-navbar .user-info:hover {
color: rgba(255, 255, 255, 0.75); background: rgba(255, 255, 255, 0.15);
.el-icon {
color: rgba(255, 255, 255, 0.6);
}
&:hover {
color: #fff;
background: rgba(255, 255, 255, 0.08);
}
&.is-active {
background: rgba(58, 174, 251, 0.25);
color: #fff;
box-shadow: 0 0 12px rgba(58, 174, 251, 0.3);
.el-icon {
color: #3aaefb;
}
}
} }
</style> </style>

1920
zdxt-web-client/zdxt-admin-plus-ui/src/views/home/index.vue

File diff suppressed because it is too large

23
zdxt-web-client/zdxt-admin-plus-ui/src/views/supervision/statistical/utils/chartOptions.ts

@ -15,7 +15,14 @@ export function getSmartMaxAndInterval(data1: number[], data2: number[], maxSpli
return { max: interval * maxSplits, interval }; return { max: interval * maxSplits, interval };
} }
const ADMIN_PIE_COLORS = ['#2d6fcf', '#4fa0a8', '#5e9acc', '#b29f60', '#af5172', '#8a61d2', '#6f2c9b', '#9d7173', '#887456', '#9eac71'];
const NON_ADMIN_PIE_COLORS = ['#7bb06c', '#489d61', '#4e97a6', '#3953d4', '#4e3ec5', '#6f2c9b', '#9d7173', '#887456', '#9eac71', '#8e5aac'];
export function buildAdminPieOption(data: { value: number; name: string }[]): EChartsOption { export function buildAdminPieOption(data: { value: number; name: string }[]): EChartsOption {
const coloredData = data.map((item, index) => ({
...item,
itemStyle: { color: ADMIN_PIE_COLORS[index % ADMIN_PIE_COLORS.length] }
}));
return { return {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
@ -32,14 +39,13 @@ export function buildAdminPieOption(data: { value: number; name: string }[]): EC
itemHeight: 6.5, itemHeight: 6.5,
itemGap: 15 itemGap: 15
}, },
color: ADMIN_PIE_COLORS,
series: [ series: [
{ {
name: '行政执法类别数量及占比', name: '行政执法类别数量及占比',
type: 'pie', type: 'pie',
color: ['#2d6fcf', '#4fa0a8', '#5e9acc', '#b29f60', '#af5172', '#8a61d2', '#6f2c9b', '#9d7173', '#887456', '#9eac71'],
radius: [52, 72], radius: [52, 72],
center: ['50%', '50%'], center: ['50%', '50%'],
padAngle: 2,
itemStyle: { borderRadius: 1 }, itemStyle: { borderRadius: 1 },
label: { label: {
show: true, show: true,
@ -51,13 +57,17 @@ export function buildAdminPieOption(data: { value: number; name: string }[]): EC
} }
}, },
labelLine: { show: true, length: 20, length2: 5, smooth: 0 }, labelLine: { show: true, length: 20, length2: 5, smooth: 0 },
data data: coloredData
} }
] ]
}; };
} }
export function buildNonAdminPieOption(data: { value: number; name: string }[]): EChartsOption { export function buildNonAdminPieOption(data: { value: number; name: string }[]): EChartsOption {
const coloredData = data.map((item, index) => ({
...item,
itemStyle: { color: NON_ADMIN_PIE_COLORS[index % NON_ADMIN_PIE_COLORS.length] }
}));
return { return {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
@ -74,14 +84,13 @@ export function buildNonAdminPieOption(data: { value: number; name: string }[]):
itemHeight: 6.5, itemHeight: 6.5,
itemGap: 15 itemGap: 15
}, },
color: NON_ADMIN_PIE_COLORS,
series: [ series: [
{ {
name: '非行政执法类别数量及占比', name: '非行政执法类别数量及占比',
type: 'pie', type: 'pie',
color: ['#7bb06c', '#489d61', '#4e97a6', '#3953d4', '#4e3ec5', '#6f2c9b', '#9d7173', '#887456', '#9eac71', '#8e5aac'],
radius: [52, 72], radius: [52, 72],
center: ['50%', '40%'], center: ['50%', '40%'],
padAngle: 2,
itemStyle: { borderRadius: 1 }, itemStyle: { borderRadius: 1 },
label: { label: {
show: true, show: true,
@ -92,8 +101,8 @@ export function buildNonAdminPieOption(data: { value: number; name: string }[]):
d: { color: '#3aaefb', fontSize: 12 } d: { color: '#3aaefb', fontSize: 12 }
} }
}, },
labelLine: { show: true, length: 20, length2: 5, smooth: 0 }, labelLine: { show: true, length: 20, length2: 5, smooth: 0 ,maxSurfaceAngle: 80 },
data data: coloredData
} }
] ]
}; };

Loading…
Cancel
Save